Skip to content

Commit

Permalink
[ANDROAPP-5701] Perform sync in local network (#3591)
Browse files Browse the repository at this point in the history
* Perform sync in local network

Signed-off-by: Pablo <[email protected]>

* Perform sync in local network

Signed-off-by: Pablo <[email protected]>

---------

Signed-off-by: Pablo <[email protected]>
Co-authored-by: Pablo <[email protected]>
  • Loading branch information
andresmr and Balcan authored Apr 30, 2024
1 parent 6c1abab commit 9f93352
Show file tree
Hide file tree
Showing 13 changed files with 118 additions and 67 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,12 @@ import org.dhis2.usescases.searchTrackEntity.SearchTEActivity
import org.dhis2.usescases.searchte.robot.searchTeiRobot
import org.dhis2.usescases.teidashboard.robot.eventRobot
import org.dhis2.usescases.teidashboard.robot.teiDashboardRobot
import org.junit.Ignore
import org.hisp.dhis.android.core.mockwebserver.ResponseController.GET
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import syncFlowRobot
import java.util.UUID
import org.dhis2.usescases.eventsWithoutRegistration.eventCapture.EventCaptureActivity

@RunWith(AndroidJUnit4::class)
class SyncFlowTest : BaseTest() {
Expand All @@ -48,12 +47,15 @@ class SyncFlowTest : BaseTest() {

override fun setUp() {
super.setUp()
setupMockServer()
workInfoStatusLiveData =
ApplicationProvider.getApplicationContext<AppTest>().mutableWorkInfoStatuses
}

@Test
fun shouldShowErrorWhenTEISyncFails() {
mockWebServerRobot.addResponse(GET, "/api/system/ping", API_PING_RESPONSE_OK)

val teiName = "Lars"
val teiLastName = "Overland"

Expand Down Expand Up @@ -95,6 +97,8 @@ class SyncFlowTest : BaseTest() {

@Test
fun shouldSuccessfullySyncSavedEvent() {
mockWebServerRobot.addResponse(GET, "/api/system/ping", API_PING_RESPONSE_OK)

prepareMalariaEventIntentAndLaunchActivity(ruleEventWithoutRegistration)

eventWithoutRegistrationRobot(composeTestRule) {
Expand All @@ -118,6 +122,8 @@ class SyncFlowTest : BaseTest() {

@Test
fun shouldShowErrorWhenSyncEventFails() {
mockWebServerRobot.addResponse(GET, "/api/system/ping", API_PING_RESPONSE_OK)

prepareMalariaEventIntentAndLaunchActivity(ruleEventWithoutRegistration)

eventWithoutRegistrationRobot(composeTestRule) {
Expand All @@ -141,6 +147,8 @@ class SyncFlowTest : BaseTest() {

@Test
fun shouldSuccessfullySyncSavedDataSet() {
mockWebServerRobot.addResponse(GET, "/api/system/ping", API_PING_RESPONSE_OK)

prepareFacilityDataSetIntentAndLaunchActivity(ruleDataSet)

dataSetRobot {
Expand Down Expand Up @@ -223,5 +231,6 @@ class SyncFlowTest : BaseTest() {

companion object {
const val LAB_MONITORING_EVENT_DATE = "28/6/2020"
const val API_PING_RESPONSE_OK = "mocks/systeminfo/ping.txt"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,6 @@ class MockedWorkManagerController(private val workInfoStatuses: LiveData<List<Wo

}

override fun syncDataForWorkers(
metadataWorkerTag: String,
dataWorkerTag: String,
workName: String
) {

}

override fun syncMetaDataForWorker(metadataWorkerTag: String, workName: String) {
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ fun enrollmentRobot(enrollmentRobot: EnrollmentRobot.() -> Unit) {
class EnrollmentRobot : BaseRobot() {

fun clickOnAProgramForEnrollment(composeTestRule: ComposeTestRule, program: String) {
composeTestRule.onNodeWithTag(PROGRAM_TO_ENROLL.format(program))
composeTestRule.onNodeWithTag(PROGRAM_TO_ENROLL.format(program), useUnmergedTree = true)
.performClick()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,19 +60,22 @@ class GranularSyncModule(
view,
repository,
schedulerProvider,
object : DispatcherProvider {
override fun io() = Dispatchers.IO

override fun computation() = Dispatchers.Default

override fun ui() = Dispatchers.Main
},
provideDispatchers(),
syncContext,
workManagerController,
smsSyncProvider,
)
}

@Provides
fun provideDispatchers() = object : DispatcherProvider {
override fun io() = Dispatchers.IO

override fun computation() = Dispatchers.Default

override fun ui() = Dispatchers.Main
}

@Provides
fun granularSyncRepository(
d2: D2,
Expand All @@ -87,6 +90,7 @@ class GranularSyncModule(
dhisProgramUtils,
periodUtils,
resourceManager,
provideDispatchers(),
)

@Provides
Expand Down
1 change: 1 addition & 0 deletions app/src/dhisUITesting/assets/mocks/systeminfo/ping.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pong
Original file line number Diff line number Diff line change
Expand Up @@ -80,13 +80,15 @@ class GranularSyncModule(
periodUtils: DhisPeriodUtils,
preferenceProvider: PreferenceProvider,
resourceManager: ResourceManager,
dispatcherProvider: DispatcherProvider,
): GranularSyncRepository = GranularSyncRepository(
d2,
syncContext,
preferenceProvider,
dhisProgramUtils,
periodUtils,
resourceManager,
dispatcherProvider,
)

@Provides
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ import androidx.work.WorkInfo
interface WorkManagerController {

fun syncDataForWorker(workerItem: WorkerItem)
fun syncDataForWorkers(metadataWorkerTag: String, dataWorkerTag: String, workName: String)
fun syncMetaDataForWorker(metadataWorkerTag: String, workName: String)
fun syncDataForWorker(metadataWorkerTag: String, workName: String)
fun beginUniqueWork(workerItem: WorkerItem)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,7 @@ package org.dhis2.data.service.workManager

import androidx.lifecycle.LiveData
import androidx.lifecycle.MediatorLiveData
import androidx.work.Constraints
import androidx.work.ExistingWorkPolicy
import androidx.work.NetworkType
import androidx.work.OneTimeWorkRequest
import androidx.work.PeriodicWorkRequest
import androidx.work.WorkInfo
Expand All @@ -56,38 +54,10 @@ class WorkManagerControllerImpl(private val workManager: WorkManager) : WorkMana
}
}

override fun syncDataForWorkers(
metadataWorkerTag: String,
dataWorkerTag: String,
workName: String,
) {
val workerOneBuilder = OneTimeWorkRequest.Builder(SyncMetadataWorker::class.java)
workerOneBuilder
.addTag(metadataWorkerTag)
.setConstraints(
Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build(),
)

val workerTwoBuilder = OneTimeWorkRequest.Builder(SyncDataWorker::class.java)
workerTwoBuilder
.addTag(dataWorkerTag)
.setConstraints(
Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build(),
)

workManager
.beginUniqueWork(workName, ExistingWorkPolicy.KEEP, workerOneBuilder.build())
.then(workerTwoBuilder.build())
.enqueue()
}

override fun syncMetaDataForWorker(metadataWorkerTag: String, workName: String) {
val workerOneBuilder = OneTimeWorkRequest.Builder(SyncMetadataWorker::class.java)
workerOneBuilder
.addTag(metadataWorkerTag)
.setConstraints(
Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build(),
)

workManager
.beginUniqueWork(workName, ExistingWorkPolicy.KEEP, workerOneBuilder.build())
Expand All @@ -98,9 +68,6 @@ class WorkManagerControllerImpl(private val workManager: WorkManager) : WorkMana
val workerTwoBuilder = OneTimeWorkRequest.Builder(SyncDataWorker::class.java)
workerTwoBuilder
.addTag(dataWorkerTag)
.setConstraints(
Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build(),
)

workManager
.beginUniqueWork(workName, ExistingWorkPolicy.KEEP, workerTwoBuilder.build())
Expand Down Expand Up @@ -163,9 +130,6 @@ class WorkManagerControllerImpl(private val workManager: WorkManager) : WorkMana

syncBuilder.apply {
addTag(workerItem.workerName)
setConstraints(
Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build(),
)
workerItem.delayInSeconds?.let {
setInitialDelay(it, TimeUnit.SECONDS)
}
Expand Down Expand Up @@ -218,9 +182,6 @@ class WorkManagerControllerImpl(private val workManager: WorkManager) : WorkMana

syncBuilder.apply {
addTag(workerItem.workerName)
setConstraints(
Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build(),
)
workerItem.data?.let {
setInputData(it)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ class GranularSyncPresenter(
workerName = workerName()
}

private val _serverAvailability = MutableLiveData<Boolean>()
val serverAvailability: LiveData<Boolean> = _serverAvailability

private fun loadSyncInfo(forcedState: State? = null) {
viewModelScope.launch(dispatcher.io()) {
val syncState = async {
Expand Down Expand Up @@ -424,4 +427,15 @@ class GranularSyncPresenter(
}
}
}

fun checkServerAvailability() {
viewModelScope.launch {
try {
repository.checkServerAvailability()
_serverAvailability.value = true
} catch (error: RuntimeException) {
_serverAvailability.value = false
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.dhis2.utils.granularsync

import io.reactivex.Single
import kotlinx.coroutines.withContext
import org.dhis2.R
import org.dhis2.commons.bindings.categoryOptionCombo
import org.dhis2.commons.bindings.countEventImportConflicts
Expand Down Expand Up @@ -41,6 +42,7 @@ import org.dhis2.commons.sync.ConflictType
import org.dhis2.commons.sync.SyncContext
import org.dhis2.commons.sync.SyncStatusItem
import org.dhis2.commons.sync.SyncStatusType
import org.dhis2.commons.viewmodel.DispatcherProvider
import org.dhis2.data.dhislogic.DhisProgramUtils
import org.hisp.dhis.android.core.D2
import org.hisp.dhis.android.core.common.State
Expand All @@ -57,6 +59,7 @@ class GranularSyncRepository(
private val dhisProgramUtils: DhisProgramUtils,
private val periodUtils: DhisPeriodUtils,
private val resourceManager: ResourceManager,
private val dispatcher: DispatcherProvider,
) {

fun getUiState(forcedState: State? = null): SyncUiState {
Expand Down Expand Up @@ -554,7 +557,7 @@ class GranularSyncRepository(

val teiMainAttribute = tei.let {
d2.teiMainAttributes(it.uid(), programUid)
} ?: emptyList()
}

val label = teiMainAttribute.firstOrNull()?.let { (attributeName, value) ->
"$attributeName: $value"
Expand Down Expand Up @@ -980,6 +983,10 @@ class GranularSyncRepository(
.map { it.displayName() }
}
}

suspend fun checkServerAvailability() = withContext(dispatcher.io()) {
d2.systemInfoModule().ping().blockingGet()
}
}

fun List<SyncStatusItem>.sortedByState(): List<SyncStatusItem> {
Expand Down
18 changes: 11 additions & 7 deletions app/src/main/java/org/dhis2/utils/granularsync/SyncStatusDialog.kt
Original file line number Diff line number Diff line change
Expand Up @@ -181,14 +181,18 @@ class SyncStatusDialog : BottomSheetDialogFragment(), GranularSyncContracts.View
}

private fun onSyncClick() {
when {
networkUtils.isOnline() -> syncGranular()
viewModel.canSendSMS() &&
viewModel.isSMSEnabled(context?.showSMS() == true) -> syncSms()

!networkUtils.isOnline() &&
!viewModel.isSMSEnabled(context?.showSMS() == true) -> showSnackbar()
viewModel.serverAvailability.observe(viewLifecycleOwner) { isAvailable ->
val canSendSMS = viewModel.canSendSMS()
val isSMSEnabled = viewModel.isSMSEnabled(context?.showSMS() == true)

when {
isAvailable -> syncGranular()
canSendSMS && isSMSEnabled -> syncSms()
else -> showSnackbar()
}
}

viewModel.checkServerAvailability()
}

private fun showSnackbar() {
Expand Down
Loading

0 comments on commit 9f93352

Please sign in to comment.