Skip to content
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
9 changes: 9 additions & 0 deletions feature/orchestrator/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

<application>

<activity
Expand Down Expand Up @@ -80,6 +81,14 @@
</intent-filter>
</activity>

<receiver
android:name=".receivers.CacheResetReceiver"
android:exported="false">
<intent-filter>
<action android:name="android.intent.action.ACTION_MY_PACKAGE_REPLACED" />
</intent-filter>
</receiver>

</application>

</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.simprints.feature.orchestrator.receivers

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import com.simprints.core.ExcludedFromGeneratedTestCoverageReports
import com.simprints.core.SessionCoroutineScope
import com.simprints.feature.orchestrator.cache.OrchestratorCache
import com.simprints.infra.events.session.SessionEventRepository
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import javax.inject.Inject

/**
* Cached step structure might change between SID versions therefore caches should be cleared to avoid unmarshalling exceptions.
* Since we do not support cross-version sessions, any ongoing scopes should be closed as well.
*/
@ExcludedFromGeneratedTestCoverageReports("Platform glue code")
@AndroidEntryPoint
internal class CacheResetReceiver : BroadcastReceiver() {
@Inject
@SessionCoroutineScope
lateinit var externalScope: CoroutineScope

@Inject
lateinit var sessionEventRepository: SessionEventRepository

@Inject
lateinit var orchestratorCache: OrchestratorCache

override fun onReceive(
context: Context,
intent: Intent,
) {
if (Intent.ACTION_MY_PACKAGE_REPLACED == intent.action) {
orchestratorCache.clearCache()
externalScope.launch { sessionEventRepository.closeCurrentSession() }
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,15 @@ internal class ResetLocalRecordsIfConfigChangedUseCase @Inject constructor(
}
}

//
private fun hasPartitionTypeChanged(
oldConfig: ProjectConfiguration,
newConfig: ProjectConfiguration,
) = (oldConfig.synchronization.down.commCare != newConfig.synchronization.down.commCare) ||
(oldConfig.synchronization.down.simprints != newConfig.synchronization.down.simprints) ||
(oldConfig.synchronization.down.simprints?.partitionType != newConfig.synchronization.down.simprints?.partitionType)
// This also covers simprints changing from/to null since the partition will always be present if simprints is
(
oldConfig.synchronization.down.simprints
?.partitionType != newConfig.synchronization.down.simprints
?.partitionType
)
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.simprints.infra.sync.config.usecase

import com.simprints.core.domain.tokenization.asTokenizableEncrypted
import com.simprints.infra.config.store.models.DownSynchronizationConfiguration
import com.simprints.infra.config.store.models.Frequency
import com.simprints.infra.enrolment.records.repository.EnrolmentRecordRepository
import com.simprints.infra.eventsync.EventSyncManager
import com.simprints.infra.sync.SyncOrchestrator
Expand Down Expand Up @@ -106,14 +108,15 @@ class ResetLocalRecordsIfConfigChangedUseCaseTest {
simprints = synchronizationConfiguration.down.simprints?.copy(
partitionType = DownSynchronizationConfiguration.PartitionType.PROJECT,
),
commCare = null,
),
),
),
projectConfiguration.copy(
synchronization = synchronizationConfiguration.copy(
down = synchronizationConfiguration.down.copy(
simprints = null,
commCare = DownSynchronizationConfiguration.CommCareDownSynchronizationConfiguration
commCare = DownSynchronizationConfiguration.CommCareDownSynchronizationConfiguration,
),
),
),
Expand All @@ -134,7 +137,7 @@ class ResetLocalRecordsIfConfigChangedUseCaseTest {
synchronization = synchronizationConfiguration.copy(
down = synchronizationConfiguration.down.copy(
simprints = null,
commCare = DownSynchronizationConfiguration.CommCareDownSynchronizationConfiguration
commCare = DownSynchronizationConfiguration.CommCareDownSynchronizationConfiguration,
),
),
),
Expand All @@ -144,6 +147,7 @@ class ResetLocalRecordsIfConfigChangedUseCaseTest {
simprints = synchronizationConfiguration.down.simprints?.copy(
partitionType = DownSynchronizationConfiguration.PartitionType.PROJECT,
),
commCare = null,
),
),
),
Expand All @@ -156,4 +160,159 @@ class ResetLocalRecordsIfConfigChangedUseCaseTest {
enrolmentRecordRepository.deleteAll()
}
}

@Test
fun `should reset local records when sync partition changes`() = runTest {
useCase(
projectConfiguration.copy(
synchronization = synchronizationConfiguration.copy(
down = synchronizationConfiguration.down.copy(
simprints = synchronizationConfiguration.down.simprints?.copy(
partitionType = DownSynchronizationConfiguration.PartitionType.PROJECT,
),
commCare = null,
),
),
),
projectConfiguration.copy(
synchronization = synchronizationConfiguration.copy(
down = synchronizationConfiguration.down.copy(
simprints = null,
commCare = null,
),
),
),
)

coVerify {
syncOrchestrator.cancelEventSync()
syncOrchestrator.rescheduleEventSync()
eventSyncManager.resetDownSyncInfo()
enrolmentRecordRepository.deleteAll()
}
}

@Test
fun `should not reset local records when sync frequency changes`() = runTest {
useCase(
projectConfiguration.copy(
synchronization = synchronizationConfiguration.copy(
down = synchronizationConfiguration.down.copy(
simprints = synchronizationConfiguration.down.simprints?.copy(
frequency = Frequency.ONLY_PERIODICALLY_UP_SYNC,
),
),
),
),
projectConfiguration.copy(
synchronization = synchronizationConfiguration.copy(
down = synchronizationConfiguration.down.copy(
simprints = synchronizationConfiguration.down.simprints?.copy(
frequency = Frequency.PERIODICALLY,
),
),
),
),
)

coVerify(exactly = 0) {
syncOrchestrator.cancelEventSync()
syncOrchestrator.rescheduleEventSync()
eventSyncManager.resetDownSyncInfo()
enrolmentRecordRepository.deleteAll()
}
}

@Test
fun `should not reset local records when sync modules changes`() = runTest {
useCase(
projectConfiguration.copy(
synchronization = synchronizationConfiguration.copy(
down = synchronizationConfiguration.down.copy(
simprints = synchronizationConfiguration.down.simprints?.copy(
moduleOptions = listOf("One".asTokenizableEncrypted(), "Two".asTokenizableEncrypted()),
),
),
),
),
projectConfiguration.copy(
synchronization = synchronizationConfiguration.copy(
down = synchronizationConfiguration.down.copy(
simprints = synchronizationConfiguration.down.simprints?.copy(
moduleOptions = listOf("Three".asTokenizableEncrypted()),
),
),
),
),
)

coVerify(exactly = 0) {
syncOrchestrator.cancelEventSync()
syncOrchestrator.rescheduleEventSync()
eventSyncManager.resetDownSyncInfo()
enrolmentRecordRepository.deleteAll()
}
}

@Test
fun `should not reset local records when sync max age changes`() = runTest {
useCase(
projectConfiguration.copy(
synchronization = synchronizationConfiguration.copy(
down = synchronizationConfiguration.down.copy(
simprints = synchronizationConfiguration.down.simprints?.copy(
maxAge = "PT24H",
),
),
),
),
projectConfiguration.copy(
synchronization = synchronizationConfiguration.copy(
down = synchronizationConfiguration.down.copy(
simprints = synchronizationConfiguration.down.simprints?.copy(
maxAge = "PT12H",
),
),
),
),
)

coVerify(exactly = 0) {
syncOrchestrator.cancelEventSync()
syncOrchestrator.rescheduleEventSync()
eventSyncManager.resetDownSyncInfo()
enrolmentRecordRepository.deleteAll()
}
}

@Test
fun `should not reset local records when sync module count changes`() = runTest {
useCase(
projectConfiguration.copy(
synchronization = synchronizationConfiguration.copy(
down = synchronizationConfiguration.down.copy(
simprints = synchronizationConfiguration.down.simprints?.copy(
maxNbOfModules = 2,
),
),
),
),
projectConfiguration.copy(
synchronization = synchronizationConfiguration.copy(
down = synchronizationConfiguration.down.copy(
simprints = synchronizationConfiguration.down.simprints?.copy(
maxNbOfModules = 5,
),
),
),
),
)

coVerify(exactly = 0) {
syncOrchestrator.cancelEventSync()
syncOrchestrator.rescheduleEventSync()
eventSyncManager.resetDownSyncInfo()
enrolmentRecordRepository.deleteAll()
}
}
}