Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ANDROAPP-5701] Perform sync in local network #3591

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading