From a20ae68d20079538f62d51fbab2b0926a9f69432 Mon Sep 17 00:00:00 2001 From: Sergejs Luhmirins Date: Wed, 9 Jul 2025 12:36:12 +0300 Subject: [PATCH] Update sync configuration to the new structure --- build-logic/build_properties.gradle.kts | 3 +- .../dashboard/main/sync/SyncViewModel.kt | 10 +- .../settings/about/AboutViewModel.kt | 2 +- .../settings/syncinfo/SyncInfoViewModel.kt | 4 +- .../repository/ModuleRepositoryImpl.kt | 11 +- .../dashboard/main/sync/SyncViewModelTest.kt | 9 +- .../settings/about/AboutViewModelTest.kt | 10 +- .../syncinfo/SyncInfoViewModelTest.kt | 16 +-- .../repository/ModuleRepositoryImplTest.kt | 4 +- .../usecases/ExtractCrashKeysUseCase.kt | 3 +- .../usecases/StartBackgroundSyncUseCase.kt | 8 +- .../usecases/ExtractCrashKeysUseCaseTest.kt | 12 +- .../StartBackgroundSyncUseCaseTest.kt | 30 +++-- .../usecase/ShouldSuggestSyncUseCase.kt | 1 + .../usecase/ShouldSuggestSyncUseCaseTest.kt | 6 +- .../config/store/ConfigRepositoryImpl.kt | 24 ++-- .../infra/config/store/ConfigStoreModule.kt | 3 + .../store/local/ConfigLocalDataSourceImpl.kt | 14 ++- ...ojectConfigSimprintsSyncConfigMigration.kt | 68 +++++++++++ .../migrations/models/OldProjectConfig.kt | 31 +++-- .../DownSynchronizationConfiguration.kt | 27 +++-- .../config/store/local/models/Frequency.kt | 17 +++ .../models/SynchronizationConfiguration.kt | 17 --- .../models/UpSynchronizationConfiguration.kt | 8 +- .../DownSynchronizationConfiguration.kt | 13 +- .../infra/config/store/models/Frequency.kt | 7 ++ .../store/models/ProjectConfiguration.kt | 3 +- .../models/SynchronizationConfiguration.kt | 9 +- .../models/UpSynchronizationConfiguration.kt | 1 + .../models/ApiSynchronizationConfiguration.kt | 36 ++++-- .../src/main/proto/project_config.proto | 30 ++++- .../ProjectConfigSharedPrefsMigrationTest.kt | 87 ++++++++------ ...figSimprintsDownSyncConfigMigrationTest.kt | 112 ++++++++++++++++++ .../SynchronizationConfigurationTest.kt | 42 +++---- .../store/models/ProjectConfigurationTest.kt | 17 +-- .../ApiSynchronizationConfigurationTest.kt | 38 +++--- .../infra/config/store/testtools/Models.kt | 51 +++++--- .../infra/eventsync/EventSyncManagerImpl.kt | 2 +- .../sync/down/EventDownSyncWorkersBuilder.kt | 2 +- .../sync/master/EventSyncMasterWorker.kt | 4 +- .../infra/eventsync/EventSyncManagerTest.kt | 5 +- .../down/EventDownSyncWorkersBuilderTest.kt | 10 +- .../sync/master/EventSyncMasterWorkerTest.kt | 28 ++--- .../sync/up/EventUpSyncWorkersBuilderTest.kt | 6 +- ...ResetLocalRecordsIfConfigChangedUseCase.kt | 2 +- .../infra/sync/config/testtools/Models.kt | 32 +++-- ...tLocalRecordsIfConfigChangedUseCaseTest.kt | 16 ++- 47 files changed, 583 insertions(+), 308 deletions(-) create mode 100644 infra/config-store/src/main/java/com/simprints/infra/config/store/local/migrations/ProjectConfigSimprintsSyncConfigMigration.kt create mode 100644 infra/config-store/src/main/java/com/simprints/infra/config/store/local/models/Frequency.kt create mode 100644 infra/config-store/src/main/java/com/simprints/infra/config/store/models/Frequency.kt create mode 100644 infra/config-store/src/test/java/com/simprints/infra/config/store/local/migrations/ProjectConfigSimprintsDownSyncConfigMigrationTest.kt diff --git a/build-logic/build_properties.gradle.kts b/build-logic/build_properties.gradle.kts index 78d9ccc235..1f50152ac9 100644 --- a/build-logic/build_properties.gradle.kts +++ b/build-logic/build_properties.gradle.kts @@ -17,8 +17,9 @@ extra.apply { * Dev version >= 2024.2.2 is required for float quality thresholds * Dev version >= 2024.3.0 is required to receive configuration ID * Dev version >= 2025.2.0 is required to support enrolment record updates and SimFace configuration + * Dev version >= 2025.3.0 is required to receive smaples and structured down sync configuration */ - set("VERSION_NAME", "2025.2.0") + set("VERSION_NAME", "2025.3.0") /** * Build type. The version code describes which build type was used for the build. diff --git a/feature/dashboard/src/main/java/com/simprints/feature/dashboard/main/sync/SyncViewModel.kt b/feature/dashboard/src/main/java/com/simprints/feature/dashboard/main/sync/SyncViewModel.kt index 93e207d2ff..7308272799 100644 --- a/feature/dashboard/src/main/java/com/simprints/feature/dashboard/main/sync/SyncViewModel.kt +++ b/feature/dashboard/src/main/java/com/simprints/feature/dashboard/main/sync/SyncViewModel.kt @@ -29,8 +29,8 @@ import com.simprints.feature.login.LoginContract import com.simprints.feature.login.LoginResult import com.simprints.infra.authstore.AuthStore import com.simprints.infra.config.store.models.DownSynchronizationConfiguration +import com.simprints.infra.config.store.models.Frequency import com.simprints.infra.config.store.models.ProjectState -import com.simprints.infra.config.store.models.SynchronizationConfiguration import com.simprints.infra.config.store.models.canSyncDataToSimprints import com.simprints.infra.config.store.models.isEventDownSyncAllowed import com.simprints.infra.config.sync.ConfigManager @@ -262,14 +262,16 @@ internal class SyncViewModel @Inject constructor( private suspend fun isModuleSelectionRequired() = isDownSyncAllowed() && isSelectedModulesEmpty() && isModuleSync() - private suspend fun isDownSyncAllowed() = configManager.getProjectConfiguration().synchronization.frequency != - SynchronizationConfiguration.Frequency.ONLY_PERIODICALLY_UP_SYNC + private suspend fun isDownSyncAllowed() = configManager + .getProjectConfiguration() + .synchronization.down.simprints.frequency != + Frequency.ONLY_PERIODICALLY_UP_SYNC private suspend fun isSelectedModulesEmpty() = configManager.getDeviceConfiguration().selectedModules.isEmpty() private suspend fun isModuleSync() = configManager .getProjectConfiguration() - .synchronization.down.partitionType == DownSynchronizationConfiguration.PartitionType.MODULE + .synchronization.down.simprints.partitionType == DownSynchronizationConfiguration.PartitionType.MODULE private fun isConnected() = connectivityTracker.observeIsConnected().value ?: true } diff --git a/feature/dashboard/src/main/java/com/simprints/feature/dashboard/settings/about/AboutViewModel.kt b/feature/dashboard/src/main/java/com/simprints/feature/dashboard/settings/about/AboutViewModel.kt index 63d43cb55c..51b37c1487 100644 --- a/feature/dashboard/src/main/java/com/simprints/feature/dashboard/settings/about/AboutViewModel.kt +++ b/feature/dashboard/src/main/java/com/simprints/feature/dashboard/settings/about/AboutViewModel.kt @@ -85,7 +85,7 @@ internal class AboutViewModel @Inject constructor( private fun load() = viewModelScope.launch { val configuration = configManager.getProjectConfiguration() val syncAndSearchConfig = SyncAndSearchConfig( - configuration.synchronization.down.partitionType.name, + configuration.synchronization.down.simprints.partitionType.name, configuration.identification.poolType.name, ) _syncAndSearchConfig.postValue(syncAndSearchConfig) diff --git a/feature/dashboard/src/main/java/com/simprints/feature/dashboard/settings/syncinfo/SyncInfoViewModel.kt b/feature/dashboard/src/main/java/com/simprints/feature/dashboard/settings/syncinfo/SyncInfoViewModel.kt index 1b2325ea5d..f14deef261 100644 --- a/feature/dashboard/src/main/java/com/simprints/feature/dashboard/settings/syncinfo/SyncInfoViewModel.kt +++ b/feature/dashboard/src/main/java/com/simprints/feature/dashboard/settings/syncinfo/SyncInfoViewModel.kt @@ -198,10 +198,10 @@ internal class SyncInfoViewModel @Inject constructor( } == true private fun isModuleSync(syncConfiguration: DownSynchronizationConfiguration) = - syncConfiguration.partitionType == DownSynchronizationConfiguration.PartitionType.MODULE + syncConfiguration.simprints.partitionType == DownSynchronizationConfiguration.PartitionType.MODULE fun isModuleSyncAndModuleIdOptionsNotEmpty(synchronizationConfiguration: SynchronizationConfiguration) = - synchronizationConfiguration.down.let { it.moduleOptions.isNotEmpty() && isModuleSync(it) } + synchronizationConfiguration.down.let { it.simprints.moduleOptions.isNotEmpty() && isModuleSync(it) } private suspend fun getRecordsInLocal(projectId: String): Int = enrolmentRecordRepository.count(SubjectQuery(projectId = projectId)) diff --git a/feature/dashboard/src/main/java/com/simprints/feature/dashboard/settings/syncinfo/moduleselection/repository/ModuleRepositoryImpl.kt b/feature/dashboard/src/main/java/com/simprints/feature/dashboard/settings/syncinfo/moduleselection/repository/ModuleRepositoryImpl.kt index 7563f041ed..c81231aa09 100644 --- a/feature/dashboard/src/main/java/com/simprints/feature/dashboard/settings/syncinfo/moduleselection/repository/ModuleRepositoryImpl.kt +++ b/feature/dashboard/src/main/java/com/simprints/feature/dashboard/settings/syncinfo/moduleselection/repository/ModuleRepositoryImpl.kt @@ -16,9 +16,12 @@ internal class ModuleRepositoryImpl @Inject constructor( private val enrolmentRecordRepository: EnrolmentRecordRepository, private val eventSyncManager: EventSyncManager, ) : ModuleRepository { - override suspend fun getModules(): List = configManager.getProjectConfiguration().synchronization.down.moduleOptions.map { - Module(it, isModuleSelected(it.value)) - } + override suspend fun getModules(): List = configManager + .getProjectConfiguration() + .synchronization.down.simprints.moduleOptions + .map { + Module(it, isModuleSelected(it.value)) + } override suspend fun saveModules(modules: List) { setSelectedModules(modules.filter { it.isSelected }) @@ -27,7 +30,7 @@ internal class ModuleRepositoryImpl @Inject constructor( override suspend fun getMaxNumberOfModules(): Int = configManager .getProjectConfiguration() - .synchronization.down.maxNbOfModules + .synchronization.down.simprints.maxNbOfModules private suspend fun isModuleSelected(moduleName: String): Boolean = configManager .getDeviceConfiguration() diff --git a/feature/dashboard/src/test/java/com/simprints/feature/dashboard/main/sync/SyncViewModelTest.kt b/feature/dashboard/src/test/java/com/simprints/feature/dashboard/main/sync/SyncViewModelTest.kt index e143e70416..5d803bb14f 100644 --- a/feature/dashboard/src/test/java/com/simprints/feature/dashboard/main/sync/SyncViewModelTest.kt +++ b/feature/dashboard/src/test/java/com/simprints/feature/dashboard/main/sync/SyncViewModelTest.kt @@ -22,8 +22,8 @@ import com.simprints.feature.login.LoginResult import com.simprints.infra.authstore.AuthStore import com.simprints.infra.config.store.models.DeviceConfiguration import com.simprints.infra.config.store.models.DownSynchronizationConfiguration +import com.simprints.infra.config.store.models.Frequency import com.simprints.infra.config.store.models.ProjectState -import com.simprints.infra.config.store.models.SynchronizationConfiguration import com.simprints.infra.config.store.models.UpSynchronizationConfiguration import com.simprints.infra.config.store.models.UpSynchronizationConfiguration.SimprintsUpSynchronizationConfiguration import com.simprints.infra.config.store.models.UpSynchronizationConfiguration.UpSynchronizationKind.ALL @@ -103,10 +103,11 @@ internal class SyncViewModelTest { every { up.simprints } returns SimprintsUpSynchronizationConfiguration( kind = ALL, batchSizes = UpSynchronizationConfiguration.UpSyncBatchSizes.default(), - false, + imagesRequireUnmeteredConnection = false, + frequency = Frequency.PERIODICALLY_AND_ON_SESSION_START, ) - every { frequency } returns SynchronizationConfiguration.Frequency.PERIODICALLY_AND_ON_SESSION_START - every { down.partitionType } returns DownSynchronizationConfiguration.PartitionType.MODULE + every { down.simprints.frequency } returns Frequency.PERIODICALLY_AND_ON_SESSION_START + every { down.simprints.partitionType } returns DownSynchronizationConfiguration.PartitionType.MODULE } every { timeHelper.readableBetweenNowAndTime(any()) } returns DATE every { authStore.signedInProjectId } returns "projectId" diff --git a/feature/dashboard/src/test/java/com/simprints/feature/dashboard/settings/about/AboutViewModelTest.kt b/feature/dashboard/src/test/java/com/simprints/feature/dashboard/settings/about/AboutViewModelTest.kt index 8fd01ffb9b..8c6cf98b7b 100644 --- a/feature/dashboard/src/test/java/com/simprints/feature/dashboard/settings/about/AboutViewModelTest.kt +++ b/feature/dashboard/src/test/java/com/simprints/feature/dashboard/settings/about/AboutViewModelTest.kt @@ -180,14 +180,8 @@ class AboutViewModelTest { every { poolType } returns POOL_TYPE } every { synchronization } returns mockk { - every { down } returns mockk { - every { partitionType } returns PARTITION_TYPE - } - every { up } returns mockk { - every { simprints } returns mockk { - every { kind } returns upSyncKind - } - } + every { down.simprints.partitionType } returns PARTITION_TYPE + every { up.simprints.kind } returns upSyncKind } } diff --git a/feature/dashboard/src/test/java/com/simprints/feature/dashboard/settings/syncinfo/SyncInfoViewModelTest.kt b/feature/dashboard/src/test/java/com/simprints/feature/dashboard/settings/syncinfo/SyncInfoViewModelTest.kt index a49f77c8a2..66e317a3f8 100644 --- a/feature/dashboard/src/test/java/com/simprints/feature/dashboard/settings/syncinfo/SyncInfoViewModelTest.kt +++ b/feature/dashboard/src/test/java/com/simprints/feature/dashboard/settings/syncinfo/SyncInfoViewModelTest.kt @@ -2,13 +2,14 @@ package com.simprints.feature.dashboard.settings.syncinfo import androidx.arch.core.executor.testing.InstantTaskExecutorRule import androidx.lifecycle.MutableLiveData -import com.google.common.truth.Truth.assertThat +import com.google.common.truth.Truth.* import com.simprints.core.domain.tokenization.asTokenizableEncrypted import com.simprints.core.domain.tokenization.asTokenizableRaw import com.simprints.feature.dashboard.settings.syncinfo.modulecount.ModuleCount import com.simprints.feature.login.LoginResult import com.simprints.infra.authstore.AuthStore import com.simprints.infra.config.store.models.DownSynchronizationConfiguration +import com.simprints.infra.config.store.models.Frequency import com.simprints.infra.config.store.models.Project import com.simprints.infra.config.store.models.ProjectConfiguration import com.simprints.infra.config.store.models.SynchronizationConfiguration @@ -30,13 +31,8 @@ import com.simprints.infra.sync.SyncOrchestrator import com.simprints.testtools.common.coroutines.TestCoroutineRule import com.simprints.testtools.common.livedata.getOrAwaitValue import com.simprints.testtools.common.livedata.getOrAwaitValues -import io.mockk.MockKAnnotations -import io.mockk.coEvery -import io.mockk.coVerify -import io.mockk.every +import io.mockk.* import io.mockk.impl.annotations.MockK -import io.mockk.mockk -import io.mockk.verify import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.test.runTest import org.junit.Before @@ -507,13 +503,13 @@ class SyncInfoViewModelTest { partitionType: DownSynchronizationConfiguration.PartitionType, modules: List = emptyList(), ) = mockk { - every { frequency }.returns(SynchronizationConfiguration.Frequency.PERIODICALLY) - every { down }.returns( - DownSynchronizationConfiguration( + every { down.simprints }.returns( + DownSynchronizationConfiguration.SimprintsDownSynchronizationConfiguration( partitionType = partitionType, moduleOptions = modules.map(String::asTokenizableRaw), maxNbOfModules = 0, maxAge = "PT24H", + frequency = Frequency.PERIODICALLY, ), ) } diff --git a/feature/dashboard/src/test/java/com/simprints/feature/dashboard/settings/syncinfo/moduleselection/repository/ModuleRepositoryImplTest.kt b/feature/dashboard/src/test/java/com/simprints/feature/dashboard/settings/syncinfo/moduleselection/repository/ModuleRepositoryImplTest.kt index 603f856a72..f140d3cb9c 100644 --- a/feature/dashboard/src/test/java/com/simprints/feature/dashboard/settings/syncinfo/moduleselection/repository/ModuleRepositoryImplTest.kt +++ b/feature/dashboard/src/test/java/com/simprints/feature/dashboard/settings/syncinfo/moduleselection/repository/ModuleRepositoryImplTest.kt @@ -46,7 +46,7 @@ class ModuleRepositoryImplTest { every { projectConfiguration.synchronization.down } returns downSynchronizationConfiguration coEvery { configManager.getProjectConfiguration() } returns projectConfiguration - every { downSynchronizationConfiguration.moduleOptions } returns listOf("a", "b", "c", "d").map(String::asTokenizableRaw) + every { downSynchronizationConfiguration.simprints.moduleOptions } returns listOf("a", "b", "c", "d").map(String::asTokenizableRaw) coEvery { configManager.getDeviceConfiguration() } returns DeviceConfiguration("", listOf("b", "c").map(TokenizableString::Tokenized), "") @@ -130,7 +130,7 @@ class ModuleRepositoryImplTest { @Test fun shouldFetchMaxNumberOfModulesFromRemoteConfig() = runTest { - every { downSynchronizationConfiguration.maxNbOfModules } returns 10 + every { downSynchronizationConfiguration.simprints.maxNbOfModules } returns 10 assertThat(repository.getMaxNumberOfModules()).isEqualTo(10) } diff --git a/feature/login-check/src/main/java/com/simprints/feature/logincheck/usecases/ExtractCrashKeysUseCase.kt b/feature/login-check/src/main/java/com/simprints/feature/logincheck/usecases/ExtractCrashKeysUseCase.kt index f7421db18c..d1ead10268 100644 --- a/feature/login-check/src/main/java/com/simprints/feature/logincheck/usecases/ExtractCrashKeysUseCase.kt +++ b/feature/login-check/src/main/java/com/simprints/feature/logincheck/usecases/ExtractCrashKeysUseCase.kt @@ -19,7 +19,8 @@ internal class ExtractCrashKeysUseCase @Inject constructor( Simber.setUserProperty(CrashReportingCustomKeys.MODULE_IDS, deviceConfiguration.selectedModules.toString()) Simber.setUserProperty( CrashReportingCustomKeys.SUBJECTS_DOWN_SYNC_TRIGGERS, - projectConfiguration.synchronization.frequency.toString(), + projectConfiguration.synchronization.down.simprints.frequency + .toString(), ) } } diff --git a/feature/login-check/src/main/java/com/simprints/feature/logincheck/usecases/StartBackgroundSyncUseCase.kt b/feature/login-check/src/main/java/com/simprints/feature/logincheck/usecases/StartBackgroundSyncUseCase.kt index 0e6a13503d..5e98cdb812 100644 --- a/feature/login-check/src/main/java/com/simprints/feature/logincheck/usecases/StartBackgroundSyncUseCase.kt +++ b/feature/login-check/src/main/java/com/simprints/feature/logincheck/usecases/StartBackgroundSyncUseCase.kt @@ -1,6 +1,6 @@ package com.simprints.feature.logincheck.usecases -import com.simprints.infra.config.store.models.SynchronizationConfiguration +import com.simprints.infra.config.store.models.Frequency import com.simprints.infra.config.sync.ConfigManager import com.simprints.infra.sync.SyncOrchestrator import javax.inject.Inject @@ -10,10 +10,12 @@ internal class StartBackgroundSyncUseCase @Inject constructor( private val configManager: ConfigManager, ) { suspend operator fun invoke() { - val frequency = configManager.getProjectConfiguration().synchronization.frequency + val frequency = configManager + .getProjectConfiguration() + .synchronization.down.simprints.frequency syncOrchestrator.scheduleBackgroundWork( - withDelay = frequency != SynchronizationConfiguration.Frequency.PERIODICALLY_AND_ON_SESSION_START, + withDelay = frequency != Frequency.PERIODICALLY_AND_ON_SESSION_START, ) } } diff --git a/feature/login-check/src/test/java/com/simprints/feature/logincheck/usecases/ExtractCrashKeysUseCaseTest.kt b/feature/login-check/src/test/java/com/simprints/feature/logincheck/usecases/ExtractCrashKeysUseCaseTest.kt index c7cd2aa3a3..2411a5a4c9 100644 --- a/feature/login-check/src/test/java/com/simprints/feature/logincheck/usecases/ExtractCrashKeysUseCaseTest.kt +++ b/feature/login-check/src/test/java/com/simprints/feature/logincheck/usecases/ExtractCrashKeysUseCaseTest.kt @@ -2,17 +2,11 @@ package com.simprints.feature.logincheck.usecases import com.simprints.core.domain.tokenization.asTokenizableRaw import com.simprints.infra.authstore.AuthStore -import com.simprints.infra.config.store.models.SynchronizationConfiguration +import com.simprints.infra.config.store.models.Frequency import com.simprints.infra.config.sync.ConfigManager import com.simprints.infra.logging.Simber -import io.mockk.MockKAnnotations -import io.mockk.coEvery -import io.mockk.every +import io.mockk.* import io.mockk.impl.annotations.MockK -import io.mockk.mockk -import io.mockk.mockkObject -import io.mockk.unmockkObject -import io.mockk.verify import kotlinx.coroutines.test.runTest import org.junit.After import org.junit.Before @@ -43,7 +37,7 @@ class ExtractCrashKeysUseCaseTest { @Test fun `Sets values to Simber`() = runTest { coEvery { configManager.getProjectConfiguration() } returns mockk { - every { synchronization.frequency } returns SynchronizationConfiguration.Frequency.PERIODICALLY + every { synchronization.down.simprints.frequency } returns Frequency.PERIODICALLY } coEvery { configManager.getDeviceConfiguration() } returns mockk { every { selectedModules } returns listOf( diff --git a/feature/login-check/src/test/java/com/simprints/feature/logincheck/usecases/StartBackgroundSyncUseCaseTest.kt b/feature/login-check/src/test/java/com/simprints/feature/logincheck/usecases/StartBackgroundSyncUseCaseTest.kt index b23f046c8c..72558ece45 100644 --- a/feature/login-check/src/test/java/com/simprints/feature/logincheck/usecases/StartBackgroundSyncUseCaseTest.kt +++ b/feature/login-check/src/test/java/com/simprints/feature/logincheck/usecases/StartBackgroundSyncUseCaseTest.kt @@ -1,11 +1,9 @@ package com.simprints.feature.logincheck.usecases -import com.simprints.infra.config.store.models.SynchronizationConfiguration +import com.simprints.infra.config.store.models.Frequency import com.simprints.infra.config.sync.ConfigManager import com.simprints.infra.sync.SyncOrchestrator -import io.mockk.MockKAnnotations -import io.mockk.coEvery -import io.mockk.coVerify +import io.mockk.* import io.mockk.impl.annotations.MockK import kotlinx.coroutines.test.runTest import org.junit.Before @@ -32,8 +30,12 @@ class StartBackgroundSyncUseCaseTest { @Test fun `Schedules all syncs when called`() = runTest { - coEvery { configManager.getProjectConfiguration().synchronization.frequency } returns - SynchronizationConfiguration.Frequency.PERIODICALLY + coEvery { + configManager + .getProjectConfiguration() + .synchronization.down.simprints.frequency + } returns + Frequency.PERIODICALLY useCase.invoke() @@ -42,8 +44,12 @@ class StartBackgroundSyncUseCaseTest { @Test fun `Starts event sync on start if required`() = runTest { - coEvery { configManager.getProjectConfiguration().synchronization.frequency } returns - SynchronizationConfiguration.Frequency.PERIODICALLY_AND_ON_SESSION_START + coEvery { + configManager + .getProjectConfiguration() + .synchronization.down.simprints.frequency + } returns + Frequency.PERIODICALLY_AND_ON_SESSION_START useCase.invoke() @@ -52,8 +58,12 @@ class StartBackgroundSyncUseCaseTest { @Test fun `Does not start event sync on start if not required`() = runTest { - coEvery { configManager.getProjectConfiguration().synchronization.frequency } returns - SynchronizationConfiguration.Frequency.PERIODICALLY + coEvery { + configManager + .getProjectConfiguration() + .synchronization.down.simprints.frequency + } returns + Frequency.PERIODICALLY useCase.invoke() diff --git a/feature/validate-subject-pool/src/main/java/com/simprints/feature/validatepool/usecase/ShouldSuggestSyncUseCase.kt b/feature/validate-subject-pool/src/main/java/com/simprints/feature/validatepool/usecase/ShouldSuggestSyncUseCase.kt index bf937b5815..1999485d11 100644 --- a/feature/validate-subject-pool/src/main/java/com/simprints/feature/validatepool/usecase/ShouldSuggestSyncUseCase.kt +++ b/feature/validate-subject-pool/src/main/java/com/simprints/feature/validatepool/usecase/ShouldSuggestSyncUseCase.kt @@ -18,6 +18,7 @@ internal class ShouldSuggestSyncUseCase @Inject constructor( .getProjectConfiguration() .synchronization .down + .simprints .maxAge .let(Duration.Companion::parse) .inWholeMilliseconds diff --git a/feature/validate-subject-pool/src/test/java/com/simprints/feature/validatepool/usecase/ShouldSuggestSyncUseCaseTest.kt b/feature/validate-subject-pool/src/test/java/com/simprints/feature/validatepool/usecase/ShouldSuggestSyncUseCaseTest.kt index 69cfac3400..790466780a 100644 --- a/feature/validate-subject-pool/src/test/java/com/simprints/feature/validatepool/usecase/ShouldSuggestSyncUseCaseTest.kt +++ b/feature/validate-subject-pool/src/test/java/com/simprints/feature/validatepool/usecase/ShouldSuggestSyncUseCaseTest.kt @@ -45,7 +45,7 @@ class ShouldSuggestSyncUseCaseTest { coEvery { configRepository .getProjectConfiguration() - .synchronization.down.maxAge + .synchronization.down.simprints.maxAge } returns "PT24H" assertThat(usecase()).isTrue() @@ -58,7 +58,7 @@ class ShouldSuggestSyncUseCaseTest { coEvery { configRepository .getProjectConfiguration() - .synchronization.down.maxAge + .synchronization.down.simprints.maxAge } returns "24h0m0s" assertThat(usecase()).isTrue() @@ -71,7 +71,7 @@ class ShouldSuggestSyncUseCaseTest { coEvery { configRepository .getProjectConfiguration() - .synchronization.down.maxAge + .synchronization.down.simprints.maxAge } returns "PT24H" assertThat(usecase()).isFalse() diff --git a/infra/config-store/src/main/java/com/simprints/infra/config/store/ConfigRepositoryImpl.kt b/infra/config-store/src/main/java/com/simprints/infra/config/store/ConfigRepositoryImpl.kt index 1ffc910197..f21dc8b214 100644 --- a/infra/config-store/src/main/java/com/simprints/infra/config/store/ConfigRepositoryImpl.kt +++ b/infra/config-store/src/main/java/com/simprints/infra/config/store/ConfigRepositoryImpl.kt @@ -99,17 +99,19 @@ internal class ConfigRepositoryImpl @Inject constructor( return config.copy( synchronization = config.synchronization.copy( down = config.synchronization.down.copy( - moduleOptions = config.synchronization.down.moduleOptions.map { moduleId -> - when (moduleId) { - is TokenizableString.Raw -> tokenizationProcessor.encrypt( - decrypted = moduleId, - tokenKeyType = TokenKeyType.ModuleId, - project = project, - ) - - is TokenizableString.Tokenized -> moduleId - } - }, + simprints = config.synchronization.down.simprints.copy( + moduleOptions = config.synchronization.down.simprints.moduleOptions.map { moduleId -> + when (moduleId) { + is TokenizableString.Raw -> tokenizationProcessor.encrypt( + decrypted = moduleId, + tokenKeyType = TokenKeyType.ModuleId, + project = project, + ) + + is TokenizableString.Tokenized -> moduleId + } + }, + ), ), ), ) diff --git a/infra/config-store/src/main/java/com/simprints/infra/config/store/ConfigStoreModule.kt b/infra/config-store/src/main/java/com/simprints/infra/config/store/ConfigStoreModule.kt index 66bd506c38..e15475be78 100644 --- a/infra/config-store/src/main/java/com/simprints/infra/config/store/ConfigStoreModule.kt +++ b/infra/config-store/src/main/java/com/simprints/infra/config/store/ConfigStoreModule.kt @@ -16,6 +16,7 @@ import com.simprints.infra.config.store.local.migrations.ProjectConfigMatchingMo import com.simprints.infra.config.store.local.migrations.ProjectConfigQualityThresholdMigration import com.simprints.infra.config.store.local.migrations.ProjectConfigSampleUploadMigration import com.simprints.infra.config.store.local.migrations.ProjectConfigSharedPrefsMigration +import com.simprints.infra.config.store.local.migrations.ProjectConfigSimprintsSyncConfigMigration import com.simprints.infra.config.store.local.migrations.ProjectRealmMigration import com.simprints.infra.config.store.local.models.ProtoDeviceConfiguration import com.simprints.infra.config.store.local.models.ProtoProject @@ -78,6 +79,7 @@ object DataStoreModule { projectConfigMatchingModalitiesMigration: ProjectConfigMatchingModalitiesMigration, projectConfigFaceEmptyVersionMigration: ProjectConfigFaceEmptyVersionMigration, projectConfigSampleUploadMigration: ProjectConfigSampleUploadMigration, + projectConfigDownSyncConfigMigration: ProjectConfigSimprintsSyncConfigMigration, ): DataStore = DataStoreFactory.create( serializer = ProjectConfigurationSerializer, produceFile = { appContext.dataStoreFile(PROJECT_CONFIG_DATA_STORE_FILE_NAME) }, @@ -91,6 +93,7 @@ object DataStoreModule { projectConfigMatchingModalitiesMigration, projectConfigFaceEmptyVersionMigration, projectConfigSampleUploadMigration, + projectConfigDownSyncConfigMigration, ), ) diff --git a/infra/config-store/src/main/java/com/simprints/infra/config/store/local/ConfigLocalDataSourceImpl.kt b/infra/config-store/src/main/java/com/simprints/infra/config/store/local/ConfigLocalDataSourceImpl.kt index 13cce83684..633ab8e1f3 100644 --- a/infra/config-store/src/main/java/com/simprints/infra/config/store/local/ConfigLocalDataSourceImpl.kt +++ b/infra/config-store/src/main/java/com/simprints/infra/config/store/local/ConfigLocalDataSourceImpl.kt @@ -16,6 +16,7 @@ import com.simprints.infra.config.store.models.DownSynchronizationConfiguration import com.simprints.infra.config.store.models.DownSynchronizationConfiguration.Companion.DEFAULT_DOWN_SYNC_MAX_AGE import com.simprints.infra.config.store.models.Finger import com.simprints.infra.config.store.models.FingerprintConfiguration +import com.simprints.infra.config.store.models.Frequency import com.simprints.infra.config.store.models.GeneralConfiguration import com.simprints.infra.config.store.models.IdentificationConfiguration import com.simprints.infra.config.store.models.Project @@ -212,22 +213,25 @@ internal class ConfigLocalDataSourceImpl @Inject constructor( poolType = IdentificationConfiguration.PoolType.USER, ), synchronization = SynchronizationConfiguration( - frequency = SynchronizationConfiguration.Frequency.PERIODICALLY, up = UpSynchronizationConfiguration( simprints = UpSynchronizationConfiguration.SimprintsUpSynchronizationConfiguration( kind = UpSynchronizationConfiguration.UpSynchronizationKind.NONE, batchSizes = UpSynchronizationConfiguration.UpSyncBatchSizes.default(), imagesRequireUnmeteredConnection = false, + frequency = Frequency.PERIODICALLY, ), coSync = UpSynchronizationConfiguration.CoSyncUpSynchronizationConfiguration( kind = UpSynchronizationConfiguration.UpSynchronizationKind.NONE, ), ), down = DownSynchronizationConfiguration( - partitionType = DownSynchronizationConfiguration.PartitionType.USER, - maxNbOfModules = 6, - moduleOptions = listOf(), - maxAge = DEFAULT_DOWN_SYNC_MAX_AGE, + simprints = DownSynchronizationConfiguration.SimprintsDownSynchronizationConfiguration( + partitionType = DownSynchronizationConfiguration.PartitionType.USER, + maxNbOfModules = 6, + moduleOptions = listOf(), + maxAge = DEFAULT_DOWN_SYNC_MAX_AGE, + frequency = Frequency.PERIODICALLY, + ), ), samples = SampleSynchronizationConfiguration( signedUrlBatchSize = 1, diff --git a/infra/config-store/src/main/java/com/simprints/infra/config/store/local/migrations/ProjectConfigSimprintsSyncConfigMigration.kt b/infra/config-store/src/main/java/com/simprints/infra/config/store/local/migrations/ProjectConfigSimprintsSyncConfigMigration.kt new file mode 100644 index 0000000000..51f27ca0e3 --- /dev/null +++ b/infra/config-store/src/main/java/com/simprints/infra/config/store/local/migrations/ProjectConfigSimprintsSyncConfigMigration.kt @@ -0,0 +1,68 @@ +package com.simprints.infra.config.store.local.migrations + +import androidx.datastore.core.DataMigration +import com.simprints.infra.config.store.local.models.ProtoDownSynchronizationConfiguration +import com.simprints.infra.config.store.local.models.ProtoProjectConfiguration +import com.simprints.infra.config.store.local.models.ProtoSyncFrequency +import com.simprints.infra.logging.LoggingConstants.CrashReportTag.MIGRATION +import com.simprints.infra.logging.Simber +import javax.inject.Inject + +/** + * Can be removed once all the devices have been updated to 2025.3.0 + */ +class ProjectConfigSimprintsSyncConfigMigration @Inject constructor() : DataMigration { + override suspend fun cleanUp() { + Simber.i("Migration of project configuration simprints sync is done", tag = MIGRATION) + } + + override suspend fun shouldMigrate(currentData: ProtoProjectConfiguration) = with(currentData) { + !synchronization.down.hasSimprints() + } + + override suspend fun migrate(currentData: ProtoProjectConfiguration): ProtoProjectConfiguration { + Simber.i("Start migration of project configuration simprints sync", tag = MIGRATION) + + val currentSyncFrequency = ProtoSyncFrequency.forNumber(currentData.synchronization.frequency.number) + + val currentDownSyncConfig = currentData.synchronization.down + val newDownSyncConfig = currentDownSyncConfig + .toBuilder() + .setSimprints( + ProtoDownSynchronizationConfiguration.ProtoSimprintsDownSynchronizationConfiguration + .newBuilder() + .setPartitionType(currentDownSyncConfig.partitionType) + .setMaxNbOfModules(currentDownSyncConfig.maxNbOfModules) + .addAllModuleOptions(currentDownSyncConfig.moduleOptionsList) + .setIsTokenized(currentDownSyncConfig.isTokenized) + .setMaxAge(currentDownSyncConfig.maxAge) + .setFrequency(currentSyncFrequency) + .build(), + ).clearPartitionType() + .clearMaxNbOfModules() + .clearModuleOptions() + .clearIsTokenized() + .clearMaxAge() + .build() + + val newUpSyncConfig = currentData.synchronization.up + .toBuilder() + .setSimprints( + currentData.synchronization.up.simprints + .toBuilder() + .setFrequency(currentSyncFrequency) + .build(), + ).build() + + return currentData + .toBuilder() + .setSynchronization( + currentData.synchronization + .toBuilder() + .setDown(newDownSyncConfig) + .setUp(newUpSyncConfig) + .clearFrequency() // Moved to simprints blocks + .build(), + ).build() + } +} diff --git a/infra/config-store/src/main/java/com/simprints/infra/config/store/local/migrations/models/OldProjectConfig.kt b/infra/config-store/src/main/java/com/simprints/infra/config/store/local/migrations/models/OldProjectConfig.kt index bfac5a83e1..0a8d422c44 100644 --- a/infra/config-store/src/main/java/com/simprints/infra/config/store/local/migrations/models/OldProjectConfig.kt +++ b/infra/config-store/src/main/java/com/simprints/infra/config/store/local/migrations/models/OldProjectConfig.kt @@ -10,6 +10,7 @@ import com.simprints.infra.config.store.models.DownSynchronizationConfiguration import com.simprints.infra.config.store.models.FaceConfiguration import com.simprints.infra.config.store.models.Finger import com.simprints.infra.config.store.models.FingerprintConfiguration +import com.simprints.infra.config.store.models.Frequency import com.simprints.infra.config.store.models.GeneralConfiguration import com.simprints.infra.config.store.models.IdentificationConfiguration import com.simprints.infra.config.store.models.ProjectConfiguration @@ -207,12 +208,6 @@ internal data class OldProjectConfig( ) private fun synchronizationConfiguration(): SynchronizationConfiguration = SynchronizationConfiguration( - frequency = when (downSyncSetting) { - "OFF" -> SynchronizationConfiguration.Frequency.ONLY_PERIODICALLY_UP_SYNC - "ON" -> SynchronizationConfiguration.Frequency.PERIODICALLY - "EXTRA" -> SynchronizationConfiguration.Frequency.PERIODICALLY_AND_ON_SESSION_START - else -> SynchronizationConfiguration.Frequency.PERIODICALLY - }, up = UpSynchronizationConfiguration( simprints = UpSynchronizationConfiguration.SimprintsUpSynchronizationConfiguration( kind = if (simprintsSync == null) { @@ -233,6 +228,12 @@ internal data class OldProjectConfig( sampleUpSyncs = 1, ), imagesRequireUnmeteredConnection = false, + frequency = when (downSyncSetting) { + "OFF" -> Frequency.ONLY_PERIODICALLY_UP_SYNC + "ON" -> Frequency.PERIODICALLY + "EXTRA" -> Frequency.PERIODICALLY_AND_ON_SESSION_START + else -> Frequency.PERIODICALLY + }, ), coSync = UpSynchronizationConfiguration.CoSyncUpSynchronizationConfiguration( kind = if (coSync == null) { @@ -249,12 +250,20 @@ internal data class OldProjectConfig( ), ), down = DownSynchronizationConfiguration( - partitionType = DownSynchronizationConfiguration.PartitionType.valueOf( - if (syncGroup == "GLOBAL") "PROJECT" else syncGroup, + simprints = DownSynchronizationConfiguration.SimprintsDownSynchronizationConfiguration( + partitionType = DownSynchronizationConfiguration.PartitionType.valueOf( + if (syncGroup == "GLOBAL") "PROJECT" else syncGroup, + ), + maxNbOfModules = maxNbOfModules.toInt(), + moduleOptions = moduleIdOptions.split("|").map(String::asTokenizableRaw), + maxAge = DownSynchronizationConfiguration.DEFAULT_DOWN_SYNC_MAX_AGE, + frequency = when (downSyncSetting) { + "OFF" -> Frequency.ONLY_PERIODICALLY_UP_SYNC + "ON" -> Frequency.PERIODICALLY + "EXTRA" -> Frequency.PERIODICALLY_AND_ON_SESSION_START + else -> Frequency.PERIODICALLY + }, ), - maxNbOfModules = maxNbOfModules.toInt(), - moduleOptions = moduleIdOptions.split("|").map(String::asTokenizableRaw), - maxAge = DownSynchronizationConfiguration.DEFAULT_DOWN_SYNC_MAX_AGE, ), samples = SampleSynchronizationConfiguration( signedUrlBatchSize = 5, diff --git a/infra/config-store/src/main/java/com/simprints/infra/config/store/local/models/DownSynchronizationConfiguration.kt b/infra/config-store/src/main/java/com/simprints/infra/config/store/local/models/DownSynchronizationConfiguration.kt index 5eda60d2eb..e09fffc5bd 100644 --- a/infra/config-store/src/main/java/com/simprints/infra/config/store/local/models/DownSynchronizationConfiguration.kt +++ b/infra/config-store/src/main/java/com/simprints/infra/config/store/local/models/DownSynchronizationConfiguration.kt @@ -5,17 +5,25 @@ import com.simprints.core.domain.tokenization.asTokenizableEncrypted import com.simprints.core.domain.tokenization.asTokenizableRaw import com.simprints.core.domain.tokenization.values import com.simprints.infra.config.store.exceptions.InvalidProtobufEnumException +import com.simprints.infra.config.store.local.models.ProtoDownSynchronizationConfiguration.ProtoSimprintsDownSynchronizationConfiguration import com.simprints.infra.config.store.models.DownSynchronizationConfiguration +import com.simprints.infra.config.store.models.DownSynchronizationConfiguration.SimprintsDownSynchronizationConfiguration -internal fun DownSynchronizationConfiguration.toProto(): ProtoDownSynchronizationConfiguration { +internal fun DownSynchronizationConfiguration.toProto(): ProtoDownSynchronizationConfiguration = ProtoDownSynchronizationConfiguration + .newBuilder() + .setSimprints(simprints.toProto()) + .build() + +internal fun SimprintsDownSynchronizationConfiguration.toProto(): ProtoSimprintsDownSynchronizationConfiguration { val isTokenized = moduleOptions.any { it is TokenizableString.Tokenized } - return ProtoDownSynchronizationConfiguration + return ProtoSimprintsDownSynchronizationConfiguration .newBuilder() .setPartitionType(partitionType.toProto()) .setMaxNbOfModules(maxNbOfModules) .addAllModuleOptions(moduleOptions.values()) .setIsTokenized(isTokenized) .setMaxAge(maxAge) + .setFrequency(frequency.toProto()) .build() } @@ -25,13 +33,18 @@ internal fun DownSynchronizationConfiguration.PartitionType.toProto(): ProtoDown DownSynchronizationConfiguration.PartitionType.USER -> ProtoDownSynchronizationConfiguration.PartitionType.USER } -internal fun ProtoDownSynchronizationConfiguration.toDomain(): DownSynchronizationConfiguration = DownSynchronizationConfiguration( - partitionType.toDomain(), - maxNbOfModules, - moduleOptionsList.map { +internal fun ProtoDownSynchronizationConfiguration.toDomain() = DownSynchronizationConfiguration( + simprints = simprints.toDomain(), +) + +internal fun ProtoSimprintsDownSynchronizationConfiguration.toDomain() = SimprintsDownSynchronizationConfiguration( + partitionType = partitionType.toDomain(), + maxNbOfModules = maxNbOfModules, + moduleOptions = moduleOptionsList.map { if (isTokenized) it.asTokenizableEncrypted() else it.asTokenizableRaw() }, - maxAge, + maxAge = maxAge, + frequency = frequency.toDomain(), ) internal fun ProtoDownSynchronizationConfiguration.PartitionType.toDomain(): DownSynchronizationConfiguration.PartitionType = when (this) { diff --git a/infra/config-store/src/main/java/com/simprints/infra/config/store/local/models/Frequency.kt b/infra/config-store/src/main/java/com/simprints/infra/config/store/local/models/Frequency.kt new file mode 100644 index 0000000000..14ff656c60 --- /dev/null +++ b/infra/config-store/src/main/java/com/simprints/infra/config/store/local/models/Frequency.kt @@ -0,0 +1,17 @@ +package com.simprints.infra.config.store.local.models + +import com.simprints.infra.config.store.exceptions.InvalidProtobufEnumException +import com.simprints.infra.config.store.models.Frequency + +internal fun Frequency.toProto(): ProtoSyncFrequency = when (this) { + Frequency.ONLY_PERIODICALLY_UP_SYNC -> ProtoSyncFrequency.ONLY_PERIODICALLY_UP_SYNC + Frequency.PERIODICALLY -> ProtoSyncFrequency.PERIODICALLY + Frequency.PERIODICALLY_AND_ON_SESSION_START -> ProtoSyncFrequency.PERIODICALLY_AND_ON_SESSION_START +} + +internal fun ProtoSyncFrequency.toDomain(): Frequency = when (this) { + ProtoSyncFrequency.ONLY_PERIODICALLY_UP_SYNC -> Frequency.ONLY_PERIODICALLY_UP_SYNC + ProtoSyncFrequency.PERIODICALLY -> Frequency.PERIODICALLY + ProtoSyncFrequency.PERIODICALLY_AND_ON_SESSION_START -> Frequency.PERIODICALLY_AND_ON_SESSION_START + ProtoSyncFrequency.UNRECOGNIZED -> throw InvalidProtobufEnumException("invalid Frequency $name") +} diff --git a/infra/config-store/src/main/java/com/simprints/infra/config/store/local/models/SynchronizationConfiguration.kt b/infra/config-store/src/main/java/com/simprints/infra/config/store/local/models/SynchronizationConfiguration.kt index a65ee68208..c58604d1de 100644 --- a/infra/config-store/src/main/java/com/simprints/infra/config/store/local/models/SynchronizationConfiguration.kt +++ b/infra/config-store/src/main/java/com/simprints/infra/config/store/local/models/SynchronizationConfiguration.kt @@ -1,33 +1,16 @@ package com.simprints.infra.config.store.local.models -import com.simprints.infra.config.store.exceptions.InvalidProtobufEnumException -import com.simprints.infra.config.store.local.models.ProtoSynchronizationConfiguration.Frequency import com.simprints.infra.config.store.models.SynchronizationConfiguration internal fun SynchronizationConfiguration.toProto(): ProtoSynchronizationConfiguration = ProtoSynchronizationConfiguration .newBuilder() - .setFrequency(frequency.toProto()) .setDown(down.toProto()) .setUp(up.toProto()) .setSamples(samples.toProto()) .build() -internal fun SynchronizationConfiguration.Frequency.toProto(): Frequency = when (this) { - SynchronizationConfiguration.Frequency.ONLY_PERIODICALLY_UP_SYNC -> Frequency.ONLY_PERIODICALLY_UP_SYNC - SynchronizationConfiguration.Frequency.PERIODICALLY -> Frequency.PERIODICALLY - SynchronizationConfiguration.Frequency.PERIODICALLY_AND_ON_SESSION_START -> Frequency.PERIODICALLY_AND_ON_SESSION_START -} - internal fun ProtoSynchronizationConfiguration.toDomain(): SynchronizationConfiguration = SynchronizationConfiguration( - frequency = frequency.toDomain(), up = up.toDomain(), down = down.toDomain(), samples = samples.toDomain(), ) - -internal fun Frequency.toDomain(): SynchronizationConfiguration.Frequency = when (this) { - Frequency.ONLY_PERIODICALLY_UP_SYNC -> SynchronizationConfiguration.Frequency.ONLY_PERIODICALLY_UP_SYNC - Frequency.PERIODICALLY -> SynchronizationConfiguration.Frequency.PERIODICALLY - Frequency.PERIODICALLY_AND_ON_SESSION_START -> SynchronizationConfiguration.Frequency.PERIODICALLY_AND_ON_SESSION_START - Frequency.UNRECOGNIZED -> throw InvalidProtobufEnumException("invalid Frequency $name") -} diff --git a/infra/config-store/src/main/java/com/simprints/infra/config/store/local/models/UpSynchronizationConfiguration.kt b/infra/config-store/src/main/java/com/simprints/infra/config/store/local/models/UpSynchronizationConfiguration.kt index ffcb4d0ab2..0350c7b904 100644 --- a/infra/config-store/src/main/java/com/simprints/infra/config/store/local/models/UpSynchronizationConfiguration.kt +++ b/infra/config-store/src/main/java/com/simprints/infra/config/store/local/models/UpSynchronizationConfiguration.kt @@ -17,6 +17,7 @@ internal fun UpSynchronizationConfiguration.SimprintsUpSynchronizationConfigurat .setKind(kind.toProto()) .setBatchSizes(batchSizes.toProto()) .setImagesRequireUnmeteredConnection(imagesRequireUnmeteredConnection) + .setFrequency(frequency.toProto()) .build() internal fun UpSynchronizationConfiguration.CoSyncUpSynchronizationConfiguration.toProto() = @@ -52,9 +53,10 @@ internal fun ProtoUpSynchronizationConfiguration.toDomain() = UpSynchronizationC internal fun ProtoUpSynchronizationConfiguration.SimprintsUpSynchronizationConfiguration.toDomain() = UpSynchronizationConfiguration.SimprintsUpSynchronizationConfiguration( - kind.toDomain(), - batchSizes.toDomain(), - imagesRequireUnmeteredConnection, + kind = kind.toDomain(), + batchSizes = batchSizes.toDomain(), + imagesRequireUnmeteredConnection = imagesRequireUnmeteredConnection, + frequency = frequency.toDomain(), ) internal fun ProtoUpSynchronizationConfiguration.CoSyncUpSynchronizationConfiguration.toDomain() = diff --git a/infra/config-store/src/main/java/com/simprints/infra/config/store/models/DownSynchronizationConfiguration.kt b/infra/config-store/src/main/java/com/simprints/infra/config/store/models/DownSynchronizationConfiguration.kt index 69e21d3a1a..1f6581d506 100644 --- a/infra/config-store/src/main/java/com/simprints/infra/config/store/models/DownSynchronizationConfiguration.kt +++ b/infra/config-store/src/main/java/com/simprints/infra/config/store/models/DownSynchronizationConfiguration.kt @@ -4,11 +4,16 @@ import com.simprints.core.domain.common.Partitioning import com.simprints.core.domain.tokenization.TokenizableString data class DownSynchronizationConfiguration( - val partitionType: PartitionType, - val maxNbOfModules: Int, - val moduleOptions: List, - val maxAge: String, + val simprints: SimprintsDownSynchronizationConfiguration, ) { + data class SimprintsDownSynchronizationConfiguration( + val partitionType: PartitionType, + val maxNbOfModules: Int, + val moduleOptions: List, + val maxAge: String, + val frequency: Frequency, + ) + enum class PartitionType { PROJECT, MODULE, diff --git a/infra/config-store/src/main/java/com/simprints/infra/config/store/models/Frequency.kt b/infra/config-store/src/main/java/com/simprints/infra/config/store/models/Frequency.kt new file mode 100644 index 0000000000..3076282e0e --- /dev/null +++ b/infra/config-store/src/main/java/com/simprints/infra/config/store/models/Frequency.kt @@ -0,0 +1,7 @@ +package com.simprints.infra.config.store.models + +enum class Frequency { + ONLY_PERIODICALLY_UP_SYNC, + PERIODICALLY, + PERIODICALLY_AND_ON_SESSION_START, +} diff --git a/infra/config-store/src/main/java/com/simprints/infra/config/store/models/ProjectConfiguration.kt b/infra/config-store/src/main/java/com/simprints/infra/config/store/models/ProjectConfiguration.kt index 013d009102..de6e8d9aaf 100644 --- a/infra/config-store/src/main/java/com/simprints/infra/config/store/models/ProjectConfiguration.kt +++ b/infra/config-store/src/main/java/com/simprints/infra/config/store/models/ProjectConfiguration.kt @@ -37,8 +37,7 @@ fun ProjectConfiguration.canSyncBiometricDataToSimprints(): Boolean = fun ProjectConfiguration.canSyncAnalyticsDataToSimprints(): Boolean = synchronization.up.simprints.kind == UpSynchronizationConfiguration.UpSynchronizationKind.ONLY_ANALYTICS -fun ProjectConfiguration.isEventDownSyncAllowed(): Boolean = - synchronization.frequency != SynchronizationConfiguration.Frequency.ONLY_PERIODICALLY_UP_SYNC +fun ProjectConfiguration.isEventDownSyncAllowed(): Boolean = synchronization.down.simprints.frequency != Frequency.ONLY_PERIODICALLY_UP_SYNC fun ProjectConfiguration.imagesUploadRequiresUnmeteredConnection(): Boolean = synchronization.up.simprints.imagesRequireUnmeteredConnection diff --git a/infra/config-store/src/main/java/com/simprints/infra/config/store/models/SynchronizationConfiguration.kt b/infra/config-store/src/main/java/com/simprints/infra/config/store/models/SynchronizationConfiguration.kt index f1b7787954..267b3c09f2 100644 --- a/infra/config-store/src/main/java/com/simprints/infra/config/store/models/SynchronizationConfiguration.kt +++ b/infra/config-store/src/main/java/com/simprints/infra/config/store/models/SynchronizationConfiguration.kt @@ -1,14 +1,7 @@ package com.simprints.infra.config.store.models data class SynchronizationConfiguration( - val frequency: Frequency, val up: UpSynchronizationConfiguration, val down: DownSynchronizationConfiguration, val samples: SampleSynchronizationConfiguration, -) { - enum class Frequency { - ONLY_PERIODICALLY_UP_SYNC, - PERIODICALLY, - PERIODICALLY_AND_ON_SESSION_START, - } -} +) diff --git a/infra/config-store/src/main/java/com/simprints/infra/config/store/models/UpSynchronizationConfiguration.kt b/infra/config-store/src/main/java/com/simprints/infra/config/store/models/UpSynchronizationConfiguration.kt index 3abd619e10..f737f445ce 100644 --- a/infra/config-store/src/main/java/com/simprints/infra/config/store/models/UpSynchronizationConfiguration.kt +++ b/infra/config-store/src/main/java/com/simprints/infra/config/store/models/UpSynchronizationConfiguration.kt @@ -8,6 +8,7 @@ data class UpSynchronizationConfiguration( val kind: UpSynchronizationKind, val batchSizes: UpSyncBatchSizes, val imagesRequireUnmeteredConnection: Boolean, + val frequency: Frequency, ) data class CoSyncUpSynchronizationConfiguration( diff --git a/infra/config-store/src/main/java/com/simprints/infra/config/store/remote/models/ApiSynchronizationConfiguration.kt b/infra/config-store/src/main/java/com/simprints/infra/config/store/remote/models/ApiSynchronizationConfiguration.kt index f7be642a23..dc1720cfbf 100644 --- a/infra/config-store/src/main/java/com/simprints/infra/config/store/remote/models/ApiSynchronizationConfiguration.kt +++ b/infra/config-store/src/main/java/com/simprints/infra/config/store/remote/models/ApiSynchronizationConfiguration.kt @@ -4,35 +4,34 @@ import androidx.annotation.Keep import com.simprints.core.domain.tokenization.asTokenizableEncrypted import com.simprints.infra.config.store.models.DownSynchronizationConfiguration import com.simprints.infra.config.store.models.DownSynchronizationConfiguration.Companion.DEFAULT_DOWN_SYNC_MAX_AGE +import com.simprints.infra.config.store.models.Frequency import com.simprints.infra.config.store.models.SampleSynchronizationConfiguration import com.simprints.infra.config.store.models.SynchronizationConfiguration import com.simprints.infra.config.store.models.UpSynchronizationConfiguration @Keep internal data class ApiSynchronizationConfiguration( - val frequency: Frequency, val up: ApiUpSynchronizationConfiguration, val down: ApiDownSynchronizationConfiguration, val sample: ApiSampleSynchronizationConfiguration, ) { fun toDomain(): SynchronizationConfiguration = SynchronizationConfiguration( - frequency = frequency.toDomain(), up = up.toDomain(), down = down.toDomain(), samples = sample.toDomain(), ) @Keep - enum class Frequency { + enum class ApiSynchronizationFrequency { ONLY_PERIODICALLY_UP_SYNC, PERIODICALLY, PERIODICALLY_AND_ON_SESSION_START, ; - fun toDomain(): SynchronizationConfiguration.Frequency = when (this) { - ONLY_PERIODICALLY_UP_SYNC -> SynchronizationConfiguration.Frequency.ONLY_PERIODICALLY_UP_SYNC - PERIODICALLY -> SynchronizationConfiguration.Frequency.PERIODICALLY - PERIODICALLY_AND_ON_SESSION_START -> SynchronizationConfiguration.Frequency.PERIODICALLY_AND_ON_SESSION_START + fun toDomain(): Frequency = when (this) { + ONLY_PERIODICALLY_UP_SYNC -> Frequency.ONLY_PERIODICALLY_UP_SYNC + PERIODICALLY -> Frequency.PERIODICALLY + PERIODICALLY_AND_ON_SESSION_START -> Frequency.PERIODICALLY_AND_ON_SESSION_START } } @@ -51,6 +50,7 @@ internal data class ApiSynchronizationConfiguration( val kind: UpSynchronizationKind, val batchSizes: ApiUpSyncBatchSizes?, val imagesRequireUnmeteredConnection: Boolean?, + val frequency: ApiSynchronizationFrequency, ) { fun toDomain(): UpSynchronizationConfiguration.SimprintsUpSynchronizationConfiguration = UpSynchronizationConfiguration.SimprintsUpSynchronizationConfiguration( @@ -58,6 +58,7 @@ internal data class ApiSynchronizationConfiguration( batchSizes = batchSizes?.toDomain() ?: UpSynchronizationConfiguration.UpSyncBatchSizes.default(), imagesRequireUnmeteredConnection = imagesRequireUnmeteredConnection ?: false, + frequency = frequency.toDomain(), ) } @@ -99,16 +100,27 @@ internal data class ApiSynchronizationConfiguration( @Keep data class ApiDownSynchronizationConfiguration( + val simprints: ApiSimprintsDownSynchronizationConfiguration, + ) { + fun toDomain(): DownSynchronizationConfiguration = DownSynchronizationConfiguration( + simprints.toDomain(), + ) + } + + @Keep + data class ApiSimprintsDownSynchronizationConfiguration( val partitionType: PartitionType, val maxNbOfModules: Int, val moduleOptions: List?, val maxAge: String?, + val frequency: ApiSynchronizationFrequency, ) { - fun toDomain(): DownSynchronizationConfiguration = DownSynchronizationConfiguration( - partitionType.toDomain(), - maxNbOfModules, - moduleOptions?.map(String::asTokenizableEncrypted) ?: emptyList(), - maxAge ?: DEFAULT_DOWN_SYNC_MAX_AGE, + fun toDomain() = DownSynchronizationConfiguration.SimprintsDownSynchronizationConfiguration( + partitionType = partitionType.toDomain(), + maxNbOfModules = maxNbOfModules, + moduleOptions = moduleOptions?.map(String::asTokenizableEncrypted) ?: emptyList(), + maxAge = maxAge ?: DEFAULT_DOWN_SYNC_MAX_AGE, + frequency = frequency.toDomain(), ) @Keep diff --git a/infra/config-store/src/main/proto/project_config.proto b/infra/config-store/src/main/proto/project_config.proto index ac0c1faa4d..b03ea409ce 100644 --- a/infra/config-store/src/main/proto/project_config.proto +++ b/infra/config-store/src/main/proto/project_config.proto @@ -189,11 +189,12 @@ message ProtoIdentificationConfiguration { } message ProtoSynchronizationConfiguration { - Frequency frequency = 1; + Frequency frequency = 1; // TODO: remove this field after migration to 2025.3.0 ProtoUpSynchronizationConfiguration up = 2; ProtoDownSynchronizationConfiguration down = 3; ProtoSampleSynchronizationConfiguration samples = 4; + // TODO: remove this field after migration to 2025.3.0 enum Frequency { ONLY_PERIODICALLY_UP_SYNC = 0; PERIODICALLY = 1; @@ -201,12 +202,28 @@ message ProtoSynchronizationConfiguration { } } +enum ProtoSyncFrequency { + ONLY_PERIODICALLY_UP_SYNC = 0; + PERIODICALLY = 1; + PERIODICALLY_AND_ON_SESSION_START = 2; +} + message ProtoDownSynchronizationConfiguration { - PartitionType partition_type = 1; - int32 max_nb_of_modules = 2; - repeated string module_options = 3; - bool is_tokenized = 4; - string max_age = 5; + PartitionType partition_type = 1; // TODO: remove this field after migration to 2025.3.0 + int32 max_nb_of_modules = 2; // TODO: remove this field after migration to 2025.3.0 + repeated string module_options = 3; // TODO: remove this field after migration to 2025.3.0 + bool is_tokenized = 4; // TODO: remove this field after migration to 2025.3.0 + string max_age = 5; // TODO: remove this field after migration to 2025.3.0 + ProtoSimprintsDownSynchronizationConfiguration simprints = 6; + + message ProtoSimprintsDownSynchronizationConfiguration { + PartitionType partition_type = 1; + int32 max_nb_of_modules = 2; + repeated string module_options = 3; + bool is_tokenized = 4; + string max_age = 5; + ProtoSyncFrequency frequency = 6; + } enum PartitionType { PROJECT = 0; @@ -223,6 +240,7 @@ message ProtoUpSynchronizationConfiguration { UpSynchronizationKind kind = 1; ProtoUpSyncBatchSizes batchSizes = 2; bool imagesRequireUnmeteredConnection = 3; + ProtoSyncFrequency frequency = 4; } message CoSyncUpSynchronizationConfiguration { diff --git a/infra/config-store/src/test/java/com/simprints/infra/config/store/local/migrations/ProjectConfigSharedPrefsMigrationTest.kt b/infra/config-store/src/test/java/com/simprints/infra/config/store/local/migrations/ProjectConfigSharedPrefsMigrationTest.kt index ed61ed1d44..1d8bb19c1c 100644 --- a/infra/config-store/src/test/java/com/simprints/infra/config/store/local/migrations/ProjectConfigSharedPrefsMigrationTest.kt +++ b/infra/config-store/src/test/java/com/simprints/infra/config/store/local/migrations/ProjectConfigSharedPrefsMigrationTest.kt @@ -2,8 +2,8 @@ package com.simprints.infra.config.store.local.migrations import android.content.Context import android.content.SharedPreferences -import androidx.test.ext.junit.runners.AndroidJUnit4 -import com.google.common.truth.Truth.assertThat +import androidx.test.ext.junit.runners.* +import com.google.common.truth.Truth.* import com.simprints.core.tools.json.JsonHelper import com.simprints.infra.authstore.AuthStore import com.simprints.infra.config.store.local.migrations.ProjectConfigSharedPrefsMigration.Companion.ALL_KEYS @@ -20,6 +20,7 @@ import com.simprints.infra.config.store.local.models.ProtoGeneralConfiguration import com.simprints.infra.config.store.local.models.ProtoIdentificationConfiguration import com.simprints.infra.config.store.local.models.ProtoProjectConfiguration import com.simprints.infra.config.store.local.models.ProtoSampleSynchronizationConfiguration +import com.simprints.infra.config.store.local.models.ProtoSyncFrequency import com.simprints.infra.config.store.local.models.ProtoSynchronizationConfiguration import com.simprints.infra.config.store.local.models.ProtoUpSyncBatchSizes import com.simprints.infra.config.store.local.models.ProtoUpSynchronizationConfiguration @@ -27,11 +28,7 @@ import com.simprints.infra.config.store.local.models.ProtoVero1Configuration import com.simprints.infra.config.store.local.models.ProtoVero2Configuration import com.simprints.infra.config.store.testtools.protoProjectConfiguration import com.simprints.testtools.common.syntax.assertThrows -import io.mockk.every -import io.mockk.mockk -import io.mockk.mockkObject -import io.mockk.unmockkAll -import io.mockk.verify +import io.mockk.* import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test @@ -526,7 +523,6 @@ class ProjectConfigSharedPrefsMigrationTest { private val PROTO_SYNCHRONIZATION_CONFIGURATION = ProtoSynchronizationConfiguration .newBuilder() - .setFrequency(ProtoSynchronizationConfiguration.Frequency.PERIODICALLY) .setUp( ProtoUpSynchronizationConfiguration .newBuilder() @@ -542,7 +538,8 @@ class ProjectConfigSharedPrefsMigrationTest { .setEventDownSyncs(1) .setSampleUpSyncs(1) .build(), - ).build(), + ).setFrequency(ProtoSyncFrequency.PERIODICALLY) + .build(), ).setCoSync( ProtoUpSynchronizationConfiguration.CoSyncUpSynchronizationConfiguration .newBuilder() @@ -552,11 +549,16 @@ class ProjectConfigSharedPrefsMigrationTest { ).setDown( ProtoDownSynchronizationConfiguration .newBuilder() - .setPartitionType(ProtoDownSynchronizationConfiguration.PartitionType.PROJECT) - .setMaxNbOfModules(5) - .addAllModuleOptions(listOf("module1", "module2")) - .setMaxAge("PT24H") - .build(), + .setSimprints( + ProtoDownSynchronizationConfiguration.ProtoSimprintsDownSynchronizationConfiguration + .newBuilder() + .setPartitionType(ProtoDownSynchronizationConfiguration.PartitionType.PROJECT) + .setMaxNbOfModules(5) + .addAllModuleOptions(listOf("module1", "module2")) + .setMaxAge("PT24H") + .setFrequency(ProtoSyncFrequency.PERIODICALLY) + .build(), + ).build(), ).setSamples( ProtoSampleSynchronizationConfiguration.newBuilder().setSignedUrlBatchSize(5).build(), ).build() @@ -564,7 +566,6 @@ class ProjectConfigSharedPrefsMigrationTest { private val PROTO_SYNCHRONIZATION_CONFIGURATION_NON_NULL_VALUES = ProtoSynchronizationConfiguration .newBuilder() - .setFrequency(ProtoSynchronizationConfiguration.Frequency.PERIODICALLY) .setUp( ProtoUpSynchronizationConfiguration .newBuilder() @@ -580,7 +581,8 @@ class ProjectConfigSharedPrefsMigrationTest { .setEventDownSyncs(1) .setSampleUpSyncs(1) .build(), - ).build(), + ).setFrequency(ProtoSyncFrequency.PERIODICALLY) + .build(), ).setCoSync( ProtoUpSynchronizationConfiguration.CoSyncUpSynchronizationConfiguration .newBuilder() @@ -590,11 +592,16 @@ class ProjectConfigSharedPrefsMigrationTest { ).setDown( ProtoDownSynchronizationConfiguration .newBuilder() - .setPartitionType(ProtoDownSynchronizationConfiguration.PartitionType.PROJECT) - .setMaxNbOfModules(5) - .addAllModuleOptions(listOf("module1", "module2")) - .setMaxAge("PT24H") - .build(), + .setSimprints( + ProtoDownSynchronizationConfiguration.ProtoSimprintsDownSynchronizationConfiguration + .newBuilder() + .setPartitionType(ProtoDownSynchronizationConfiguration.PartitionType.PROJECT) + .setMaxNbOfModules(5) + .addAllModuleOptions(listOf("module1", "module2")) + .setMaxAge("PT24H") + .setFrequency(ProtoSyncFrequency.PERIODICALLY) + .build(), + ).build(), ).setSamples( ProtoSampleSynchronizationConfiguration.newBuilder().setSignedUrlBatchSize(5).build(), ).build() @@ -602,7 +609,6 @@ class ProjectConfigSharedPrefsMigrationTest { private val PROTO_SYNCHRONIZATION_CONFIGURATION_EMPTY_VALUES = ProtoSynchronizationConfiguration .newBuilder() - .setFrequency(ProtoSynchronizationConfiguration.Frequency.PERIODICALLY) .setUp( ProtoUpSynchronizationConfiguration .newBuilder() @@ -618,7 +624,8 @@ class ProjectConfigSharedPrefsMigrationTest { .setEventDownSyncs(1) .setSampleUpSyncs(1) .build(), - ).build(), + ).setFrequency(ProtoSyncFrequency.PERIODICALLY) + .build(), ).setCoSync( ProtoUpSynchronizationConfiguration.CoSyncUpSynchronizationConfiguration .newBuilder() @@ -628,11 +635,16 @@ class ProjectConfigSharedPrefsMigrationTest { ).setDown( ProtoDownSynchronizationConfiguration .newBuilder() - .setPartitionType(ProtoDownSynchronizationConfiguration.PartitionType.PROJECT) - .setMaxNbOfModules(5) - .addAllModuleOptions(listOf("module1", "module2")) - .setMaxAge("PT24H") - .build(), + .setSimprints( + ProtoDownSynchronizationConfiguration.ProtoSimprintsDownSynchronizationConfiguration + .newBuilder() + .setPartitionType(ProtoDownSynchronizationConfiguration.PartitionType.PROJECT) + .setMaxNbOfModules(5) + .addAllModuleOptions(listOf("module1", "module2")) + .setMaxAge("PT24H") + .setFrequency(ProtoSyncFrequency.PERIODICALLY) + .build(), + ).build(), ).setSamples( ProtoSampleSynchronizationConfiguration.newBuilder().setSignedUrlBatchSize(5).build(), ).build() @@ -640,7 +652,6 @@ class ProjectConfigSharedPrefsMigrationTest { private val PROTO_SYNCHRONIZATION_CONFIGURATION_NULL_VALUES = ProtoSynchronizationConfiguration .newBuilder() - .setFrequency(ProtoSynchronizationConfiguration.Frequency.PERIODICALLY) .setUp( ProtoUpSynchronizationConfiguration .newBuilder() @@ -656,7 +667,8 @@ class ProjectConfigSharedPrefsMigrationTest { .setEventDownSyncs(1) .setSampleUpSyncs(1) .build(), - ).build(), + ).setFrequency(ProtoSyncFrequency.PERIODICALLY) + .build(), ).setCoSync( ProtoUpSynchronizationConfiguration.CoSyncUpSynchronizationConfiguration .newBuilder() @@ -666,11 +678,16 @@ class ProjectConfigSharedPrefsMigrationTest { ).setDown( ProtoDownSynchronizationConfiguration .newBuilder() - .setPartitionType(ProtoDownSynchronizationConfiguration.PartitionType.PROJECT) - .setMaxNbOfModules(5) - .addAllModuleOptions(listOf("module1", "module2")) - .setMaxAge("PT24H") - .build(), + .setSimprints( + ProtoDownSynchronizationConfiguration.ProtoSimprintsDownSynchronizationConfiguration + .newBuilder() + .setPartitionType(ProtoDownSynchronizationConfiguration.PartitionType.PROJECT) + .setMaxNbOfModules(5) + .addAllModuleOptions(listOf("module1", "module2")) + .setMaxAge("PT24H") + .setFrequency(ProtoSyncFrequency.PERIODICALLY) + .build(), + ).build(), ).setSamples( ProtoSampleSynchronizationConfiguration.newBuilder().setSignedUrlBatchSize(5).build(), ).build() diff --git a/infra/config-store/src/test/java/com/simprints/infra/config/store/local/migrations/ProjectConfigSimprintsDownSyncConfigMigrationTest.kt b/infra/config-store/src/test/java/com/simprints/infra/config/store/local/migrations/ProjectConfigSimprintsDownSyncConfigMigrationTest.kt new file mode 100644 index 0000000000..b825023242 --- /dev/null +++ b/infra/config-store/src/test/java/com/simprints/infra/config/store/local/migrations/ProjectConfigSimprintsDownSyncConfigMigrationTest.kt @@ -0,0 +1,112 @@ +package com.simprints.infra.config.store.local.migrations + +import com.google.common.truth.Truth.* +import com.simprints.infra.config.store.local.models.ProtoDownSynchronizationConfiguration +import com.simprints.infra.config.store.local.models.ProtoProjectConfiguration +import com.simprints.infra.config.store.local.models.ProtoSyncFrequency +import com.simprints.infra.config.store.local.models.ProtoSynchronizationConfiguration +import kotlinx.coroutines.test.runTest +import org.junit.Test + +class ProjectConfigSimprintsDownSyncConfigMigrationTest { + @Test + fun `should not migrate if has down sync simprints object`() = runTest { + val currentData = ProtoProjectConfiguration + .newBuilder() + .setSynchronization( + ProtoSynchronizationConfiguration + .newBuilder() + .setDown( + ProtoDownSynchronizationConfiguration + .newBuilder() + .setSimprints( + ProtoDownSynchronizationConfiguration.ProtoSimprintsDownSynchronizationConfiguration + .newBuilder() + .build(), + ).build(), + ), + ).build() + assertThat(ProjectConfigSimprintsSyncConfigMigration().shouldMigrate(currentData)).isFalse() + } + + @Test + fun `should migrate if no down sync simprints object`() = runTest { + val currentData = ProtoProjectConfiguration + .newBuilder() + .setSynchronization( + ProtoSynchronizationConfiguration + .newBuilder() + .setDown( + ProtoDownSynchronizationConfiguration + .newBuilder() + .clearSimprints() + .build(), + ), + ).build() + assertThat(ProjectConfigSimprintsSyncConfigMigration().shouldMigrate(currentData)).isTrue() + } + + @Test + fun `migration moves old down sync values into simprints object`() = runTest { + val currentData = ProtoProjectConfiguration + .newBuilder() + .setSynchronization( + ProtoSynchronizationConfiguration + .newBuilder() + .setDown( + ProtoDownSynchronizationConfiguration + .newBuilder() + .clearSimprints() + .setMaxAge("PT24H") + .setMaxNbOfModules(7) + .setPartitionType(ProtoDownSynchronizationConfiguration.PartitionType.MODULE) + .addAllModuleOptions(listOf("module1", "module2")) + .build(), + ), + ).build() + val result = ProjectConfigSimprintsSyncConfigMigration().migrate(currentData) + + // Old fields are cleared + assertThat(result.synchronization.down.maxAge).isEmpty() + assertThat(result.synchronization.down.maxNbOfModules).isEqualTo(0) + assertThat(result.synchronization.down.moduleOptionsCount).isEqualTo(0) + assertThat(result.synchronization.down.partitionType).isNotEqualTo(ProtoDownSynchronizationConfiguration.PartitionType.MODULE) + // Data is in the nested fields now + assertThat(result.synchronization.down.hasSimprints()).isTrue() + assertThat(result.synchronization.down.simprints.maxAge).isEqualTo("PT24H") + assertThat(result.synchronization.down.simprints.maxNbOfModules).isEqualTo(7) + assertThat(result.synchronization.down.simprints.moduleOptionsCount).isEqualTo(2) + assertThat( + result.synchronization.down.simprints.partitionType, + ).isEqualTo(ProtoDownSynchronizationConfiguration.PartitionType.MODULE) + } + + @Test + fun `migration moves frequency values into both simprints objects`() = runTest { + val currentData = ProtoProjectConfiguration + .newBuilder() + .setSynchronization( + ProtoSynchronizationConfiguration + .newBuilder() + .setFrequency(ProtoSynchronizationConfiguration.Frequency.PERIODICALLY_AND_ON_SESSION_START) + .setDown( + ProtoDownSynchronizationConfiguration + .newBuilder() + .clearSimprints() + .setMaxAge("PT24H") + .setMaxNbOfModules(7) + .setPartitionType(ProtoDownSynchronizationConfiguration.PartitionType.MODULE) + .addAllModuleOptions(listOf("module1", "module2")) + .build(), + ), + ).build() + val result = ProjectConfigSimprintsSyncConfigMigration().migrate(currentData) + + // Old fields are cleared + assertThat( + result.synchronization.frequency, + ).isNotEqualTo(ProtoSynchronizationConfiguration.Frequency.PERIODICALLY_AND_ON_SESSION_START) + assertThat(result.synchronization.down.simprints.frequency).isEqualTo(ProtoSyncFrequency.PERIODICALLY_AND_ON_SESSION_START) + assertThat(result.synchronization.up.simprints.frequency).isEqualTo(ProtoSyncFrequency.PERIODICALLY_AND_ON_SESSION_START) + } +} diff --git a/infra/config-store/src/test/java/com/simprints/infra/config/store/local/models/SynchronizationConfigurationTest.kt b/infra/config-store/src/test/java/com/simprints/infra/config/store/local/models/SynchronizationConfigurationTest.kt index 6d9c739654..df96fd280b 100644 --- a/infra/config-store/src/test/java/com/simprints/infra/config/store/local/models/SynchronizationConfigurationTest.kt +++ b/infra/config-store/src/test/java/com/simprints/infra/config/store/local/models/SynchronizationConfigurationTest.kt @@ -1,8 +1,10 @@ package com.simprints.infra.config.store.local.models -import com.google.common.truth.Truth.assertThat +import com.google.common.truth.Truth.* +import com.simprints.infra.config.store.local.models.ProtoDownSynchronizationConfiguration.PartitionType +import com.simprints.infra.config.store.local.models.ProtoUpSynchronizationConfiguration.UpSynchronizationKind import com.simprints.infra.config.store.models.DownSynchronizationConfiguration -import com.simprints.infra.config.store.models.SynchronizationConfiguration +import com.simprints.infra.config.store.models.Frequency import com.simprints.infra.config.store.models.UpSynchronizationConfiguration import com.simprints.infra.config.store.testtools.protoSynchronizationConfiguration import com.simprints.infra.config.store.testtools.synchronizationConfiguration @@ -22,11 +24,9 @@ class SynchronizationConfigurationTest { @Test fun `should map correctly the Frequency enums`() { val mapping = mapOf( - ProtoSynchronizationConfiguration.Frequency.ONLY_PERIODICALLY_UP_SYNC to - SynchronizationConfiguration.Frequency.ONLY_PERIODICALLY_UP_SYNC, - ProtoSynchronizationConfiguration.Frequency.PERIODICALLY to SynchronizationConfiguration.Frequency.PERIODICALLY, - ProtoSynchronizationConfiguration.Frequency.PERIODICALLY_AND_ON_SESSION_START to - SynchronizationConfiguration.Frequency.PERIODICALLY_AND_ON_SESSION_START, + ProtoSyncFrequency.ONLY_PERIODICALLY_UP_SYNC to Frequency.ONLY_PERIODICALLY_UP_SYNC, + ProtoSyncFrequency.PERIODICALLY to Frequency.PERIODICALLY, + ProtoSyncFrequency.PERIODICALLY_AND_ON_SESSION_START to Frequency.PERIODICALLY_AND_ON_SESSION_START, ) mapping.forEach { @@ -38,18 +38,10 @@ class SynchronizationConfigurationTest { @Test fun `should map correctly the UpSynchronizationKind enums`() { val mapping = mapOf( - ProtoUpSynchronizationConfiguration.UpSynchronizationKind.NONE - to - UpSynchronizationConfiguration.UpSynchronizationKind.NONE, - ProtoUpSynchronizationConfiguration.UpSynchronizationKind.ALL - to - UpSynchronizationConfiguration.UpSynchronizationKind.ALL, - ProtoUpSynchronizationConfiguration.UpSynchronizationKind.ONLY_ANALYTICS - to - UpSynchronizationConfiguration.UpSynchronizationKind.ONLY_ANALYTICS, - ProtoUpSynchronizationConfiguration.UpSynchronizationKind.ONLY_BIOMETRICS - to - UpSynchronizationConfiguration.UpSynchronizationKind.ONLY_BIOMETRICS, + UpSynchronizationKind.NONE to UpSynchronizationConfiguration.UpSynchronizationKind.NONE, + UpSynchronizationKind.ALL to UpSynchronizationConfiguration.UpSynchronizationKind.ALL, + UpSynchronizationKind.ONLY_ANALYTICS to UpSynchronizationConfiguration.UpSynchronizationKind.ONLY_ANALYTICS, + UpSynchronizationKind.ONLY_BIOMETRICS to UpSynchronizationConfiguration.UpSynchronizationKind.ONLY_BIOMETRICS, ) mapping.forEach { @@ -61,15 +53,9 @@ class SynchronizationConfigurationTest { @Test fun `should map correctly the PartitionType enums`() { val mapping = mapOf( - ProtoDownSynchronizationConfiguration.PartitionType.PROJECT - to - DownSynchronizationConfiguration.PartitionType.PROJECT, - ProtoDownSynchronizationConfiguration.PartitionType.MODULE - to - DownSynchronizationConfiguration.PartitionType.MODULE, - ProtoDownSynchronizationConfiguration.PartitionType.USER - to - DownSynchronizationConfiguration.PartitionType.USER, + PartitionType.PROJECT to DownSynchronizationConfiguration.PartitionType.PROJECT, + PartitionType.MODULE to DownSynchronizationConfiguration.PartitionType.MODULE, + PartitionType.USER to DownSynchronizationConfiguration.PartitionType.USER, ) mapping.forEach { diff --git a/infra/config-store/src/test/java/com/simprints/infra/config/store/models/ProjectConfigurationTest.kt b/infra/config-store/src/test/java/com/simprints/infra/config/store/models/ProjectConfigurationTest.kt index b5d1fddc5d..7deecd49d8 100644 --- a/infra/config-store/src/test/java/com/simprints/infra/config/store/models/ProjectConfigurationTest.kt +++ b/infra/config-store/src/test/java/com/simprints/infra/config/store/models/ProjectConfigurationTest.kt @@ -1,9 +1,6 @@ package com.simprints.infra.config.store.models import com.google.common.truth.Truth.assertThat -import com.simprints.infra.config.store.models.SynchronizationConfiguration.Frequency.ONLY_PERIODICALLY_UP_SYNC -import com.simprints.infra.config.store.models.SynchronizationConfiguration.Frequency.PERIODICALLY -import com.simprints.infra.config.store.models.SynchronizationConfiguration.Frequency.PERIODICALLY_AND_ON_SESSION_START import com.simprints.infra.config.store.models.UpSynchronizationConfiguration.CoSyncUpSynchronizationConfiguration import com.simprints.infra.config.store.models.UpSynchronizationConfiguration.SimprintsUpSynchronizationConfiguration import com.simprints.infra.config.store.models.UpSynchronizationConfiguration.UpSynchronizationKind.ALL @@ -14,6 +11,7 @@ import com.simprints.infra.config.store.testtools.faceConfiguration import com.simprints.infra.config.store.testtools.faceSdkConfiguration import com.simprints.infra.config.store.testtools.fingerprintConfiguration import com.simprints.infra.config.store.testtools.projectConfiguration +import com.simprints.infra.config.store.testtools.simprintsDownSyncConfigurationConfiguration import com.simprints.infra.config.store.testtools.simprintsUpSyncConfigurationConfiguration import com.simprints.infra.config.store.testtools.synchronizationConfiguration import org.junit.Test @@ -174,6 +172,7 @@ class ProjectConfigurationTest { kind = it.key, batchSizes = UpSynchronizationConfiguration.UpSyncBatchSizes.default(), imagesRequireUnmeteredConnection = false, + frequency = Frequency.PERIODICALLY, ), ), ), @@ -208,15 +207,19 @@ class ProjectConfigurationTest { @Test fun `isEventDownSyncAllowed should return the correct value`() { val values = mapOf( - ONLY_PERIODICALLY_UP_SYNC to false, - PERIODICALLY to true, - PERIODICALLY_AND_ON_SESSION_START to true, + Frequency.ONLY_PERIODICALLY_UP_SYNC to false, + Frequency.PERIODICALLY to true, + Frequency.PERIODICALLY_AND_ON_SESSION_START to true, ) values.forEach { val config = projectConfiguration.copy( synchronization = synchronizationConfiguration.copy( - frequency = it.key, + down = synchronizationConfiguration.down.copy( + simprints = simprintsDownSyncConfigurationConfiguration.copy( + frequency = it.key, + ), + ), ), ) assertThat(config.isEventDownSyncAllowed()).isEqualTo(it.value) diff --git a/infra/config-store/src/test/java/com/simprints/infra/config/store/remote/models/ApiSynchronizationConfigurationTest.kt b/infra/config-store/src/test/java/com/simprints/infra/config/store/remote/models/ApiSynchronizationConfigurationTest.kt index d933a275fc..5e6c719640 100644 --- a/infra/config-store/src/test/java/com/simprints/infra/config/store/remote/models/ApiSynchronizationConfigurationTest.kt +++ b/infra/config-store/src/test/java/com/simprints/infra/config/store/remote/models/ApiSynchronizationConfigurationTest.kt @@ -1,9 +1,10 @@ package com.simprints.infra.config.store.remote.models -import com.google.common.truth.Truth.assertThat +import com.google.common.truth.Truth.* import com.simprints.infra.config.store.models.DownSynchronizationConfiguration -import com.simprints.infra.config.store.models.SynchronizationConfiguration +import com.simprints.infra.config.store.models.Frequency import com.simprints.infra.config.store.models.UpSynchronizationConfiguration +import com.simprints.infra.config.store.remote.models.ApiSynchronizationConfiguration.ApiSimprintsDownSynchronizationConfiguration import com.simprints.infra.config.store.testtools.apiSynchronizationConfiguration import com.simprints.infra.config.store.testtools.synchronizationConfiguration import org.junit.Test @@ -19,11 +20,10 @@ class ApiSynchronizationConfigurationTest { @Test fun `should map correctly the Frequency enums`() { val mapping = mapOf( - ApiSynchronizationConfiguration.Frequency.ONLY_PERIODICALLY_UP_SYNC to - SynchronizationConfiguration.Frequency.ONLY_PERIODICALLY_UP_SYNC, - ApiSynchronizationConfiguration.Frequency.PERIODICALLY to SynchronizationConfiguration.Frequency.PERIODICALLY, - ApiSynchronizationConfiguration.Frequency.PERIODICALLY_AND_ON_SESSION_START to - SynchronizationConfiguration.Frequency.PERIODICALLY_AND_ON_SESSION_START, + ApiSynchronizationConfiguration.ApiSynchronizationFrequency.ONLY_PERIODICALLY_UP_SYNC to Frequency.ONLY_PERIODICALLY_UP_SYNC, + ApiSynchronizationConfiguration.ApiSynchronizationFrequency.PERIODICALLY to Frequency.PERIODICALLY, + ApiSynchronizationConfiguration.ApiSynchronizationFrequency.PERIODICALLY_AND_ON_SESSION_START to + Frequency.PERIODICALLY_AND_ON_SESSION_START, ) mapping.forEach { @@ -35,17 +35,13 @@ class ApiSynchronizationConfigurationTest { fun `should map correctly the UpSynchronizationKind enums`() { val mapping = mapOf( ApiSynchronizationConfiguration.ApiUpSynchronizationConfiguration.UpSynchronizationKind.NONE - to - UpSynchronizationConfiguration.UpSynchronizationKind.NONE, + to UpSynchronizationConfiguration.UpSynchronizationKind.NONE, ApiSynchronizationConfiguration.ApiUpSynchronizationConfiguration.UpSynchronizationKind.ALL - to - UpSynchronizationConfiguration.UpSynchronizationKind.ALL, + to UpSynchronizationConfiguration.UpSynchronizationKind.ALL, ApiSynchronizationConfiguration.ApiUpSynchronizationConfiguration.UpSynchronizationKind.ONLY_ANALYTICS - to - UpSynchronizationConfiguration.UpSynchronizationKind.ONLY_ANALYTICS, + to UpSynchronizationConfiguration.UpSynchronizationKind.ONLY_ANALYTICS, ApiSynchronizationConfiguration.ApiUpSynchronizationConfiguration.UpSynchronizationKind.ONLY_BIOMETRICS - to - UpSynchronizationConfiguration.UpSynchronizationKind.ONLY_BIOMETRICS, + to UpSynchronizationConfiguration.UpSynchronizationKind.ONLY_BIOMETRICS, ) mapping.forEach { @@ -56,15 +52,9 @@ class ApiSynchronizationConfigurationTest { @Test fun `should map correctly the PartitionType enums`() { val mapping = mapOf( - ApiSynchronizationConfiguration.ApiDownSynchronizationConfiguration.PartitionType.PROJECT - to - DownSynchronizationConfiguration.PartitionType.PROJECT, - ApiSynchronizationConfiguration.ApiDownSynchronizationConfiguration.PartitionType.MODULE - to - DownSynchronizationConfiguration.PartitionType.MODULE, - ApiSynchronizationConfiguration.ApiDownSynchronizationConfiguration.PartitionType.USER - to - DownSynchronizationConfiguration.PartitionType.USER, + ApiSimprintsDownSynchronizationConfiguration.PartitionType.PROJECT to DownSynchronizationConfiguration.PartitionType.PROJECT, + ApiSimprintsDownSynchronizationConfiguration.PartitionType.MODULE to DownSynchronizationConfiguration.PartitionType.MODULE, + ApiSimprintsDownSynchronizationConfiguration.PartitionType.USER to DownSynchronizationConfiguration.PartitionType.USER, ) mapping.forEach { diff --git a/infra/config-store/src/test/java/com/simprints/infra/config/store/testtools/Models.kt b/infra/config-store/src/test/java/com/simprints/infra/config/store/testtools/Models.kt index b0d38aa809..229040bc55 100644 --- a/infra/config-store/src/test/java/com/simprints/infra/config/store/testtools/Models.kt +++ b/infra/config-store/src/test/java/com/simprints/infra/config/store/testtools/Models.kt @@ -15,6 +15,7 @@ import com.simprints.infra.config.store.local.models.ProtoIdentificationConfigur import com.simprints.infra.config.store.local.models.ProtoProject import com.simprints.infra.config.store.local.models.ProtoProjectConfiguration import com.simprints.infra.config.store.local.models.ProtoSampleSynchronizationConfiguration +import com.simprints.infra.config.store.local.models.ProtoSyncFrequency import com.simprints.infra.config.store.local.models.ProtoSynchronizationConfiguration import com.simprints.infra.config.store.local.models.ProtoUpSyncBatchSizes import com.simprints.infra.config.store.local.models.ProtoUpSynchronizationConfiguration @@ -30,6 +31,7 @@ import com.simprints.infra.config.store.models.FaceConfiguration import com.simprints.infra.config.store.models.FaceConfiguration.FaceSdkConfiguration import com.simprints.infra.config.store.models.Finger import com.simprints.infra.config.store.models.FingerprintConfiguration +import com.simprints.infra.config.store.models.Frequency import com.simprints.infra.config.store.models.GeneralConfiguration import com.simprints.infra.config.store.models.IdentificationConfiguration import com.simprints.infra.config.store.models.MaxCaptureAttempts @@ -338,7 +340,6 @@ internal val protoIdentificationConfiguration = ProtoIdentificationConfiguration .build() internal val apiSynchronizationConfiguration = ApiSynchronizationConfiguration( - frequency = ApiSynchronizationConfiguration.Frequency.PERIODICALLY, up = ApiSynchronizationConfiguration.ApiUpSynchronizationConfiguration( simprints = ApiSynchronizationConfiguration.ApiUpSynchronizationConfiguration.ApiSimprintsUpSynchronizationConfiguration( kind = ApiSynchronizationConfiguration.ApiUpSynchronizationConfiguration.UpSynchronizationKind.ALL, @@ -349,16 +350,20 @@ internal val apiSynchronizationConfiguration = ApiSynchronizationConfiguration( sampleUpSyncs = 4, ), imagesRequireUnmeteredConnection = false, + frequency = ApiSynchronizationConfiguration.ApiSynchronizationFrequency.PERIODICALLY, ), coSync = ApiSynchronizationConfiguration.ApiUpSynchronizationConfiguration.ApiCoSyncUpSynchronizationConfiguration( kind = ApiSynchronizationConfiguration.ApiUpSynchronizationConfiguration.UpSynchronizationKind.NONE, ), ), down = ApiSynchronizationConfiguration.ApiDownSynchronizationConfiguration( - partitionType = ApiSynchronizationConfiguration.ApiDownSynchronizationConfiguration.PartitionType.PROJECT, - maxNbOfModules = 1, - moduleOptions = listOf("module1"), - maxAge = "PT24H", + simprints = ApiSynchronizationConfiguration.ApiSimprintsDownSynchronizationConfiguration( + partitionType = ApiSynchronizationConfiguration.ApiSimprintsDownSynchronizationConfiguration.PartitionType.PROJECT, + maxNbOfModules = 1, + moduleOptions = listOf("module1"), + maxAge = "PT24H", + frequency = ApiSynchronizationConfiguration.ApiSynchronizationFrequency.PERIODICALLY, + ), ), sample = ApiSynchronizationConfiguration.ApiSampleSynchronizationConfiguration( signedUrlBatchSize = 5, @@ -374,10 +379,18 @@ internal val simprintsUpSyncConfigurationConfiguration = UpSynchronizationConfig sampleUpSyncs = 4, ), imagesRequireUnmeteredConnection = false, + frequency = Frequency.PERIODICALLY, +) + +internal val simprintsDownSyncConfigurationConfiguration = DownSynchronizationConfiguration.SimprintsDownSynchronizationConfiguration( + partitionType = DownSynchronizationConfiguration.PartitionType.PROJECT, + maxNbOfModules = 1, + moduleOptions = listOf("module1".asTokenizableEncrypted()), + maxAge = "PT24H", + frequency = Frequency.PERIODICALLY, ) internal val synchronizationConfiguration = SynchronizationConfiguration( - frequency = SynchronizationConfiguration.Frequency.PERIODICALLY, up = UpSynchronizationConfiguration( simprints = simprintsUpSyncConfigurationConfiguration, coSync = UpSynchronizationConfiguration.CoSyncUpSynchronizationConfiguration( @@ -385,10 +398,7 @@ internal val synchronizationConfiguration = SynchronizationConfiguration( ), ), down = DownSynchronizationConfiguration( - partitionType = DownSynchronizationConfiguration.PartitionType.PROJECT, - maxNbOfModules = 1, - moduleOptions = listOf("module1".asTokenizableEncrypted()), - maxAge = "PT24H", + simprints = simprintsDownSyncConfigurationConfiguration, ), samples = SampleSynchronizationConfiguration( signedUrlBatchSize = 5, @@ -397,7 +407,6 @@ internal val synchronizationConfiguration = SynchronizationConfiguration( internal val protoSynchronizationConfiguration = ProtoSynchronizationConfiguration .newBuilder() - .setFrequency(ProtoSynchronizationConfiguration.Frequency.PERIODICALLY) .setUp( ProtoUpSynchronizationConfiguration .newBuilder() @@ -413,7 +422,8 @@ internal val protoSynchronizationConfiguration = ProtoSynchronizationConfigurati .setEventDownSyncs(3) .setSampleUpSyncs(4) .build(), - ).build(), + ).setFrequency(ProtoSyncFrequency.PERIODICALLY) + .build(), ).setCoSync( ProtoUpSynchronizationConfiguration.CoSyncUpSynchronizationConfiguration .newBuilder() @@ -423,12 +433,17 @@ internal val protoSynchronizationConfiguration = ProtoSynchronizationConfigurati ).setDown( ProtoDownSynchronizationConfiguration .newBuilder() - .setPartitionType(ProtoDownSynchronizationConfiguration.PartitionType.PROJECT) - .setMaxNbOfModules(1) - .setIsTokenized(true) - .addModuleOptions("module1") - .setMaxAge("PT24H") - .build(), + .setSimprints( + ProtoDownSynchronizationConfiguration.ProtoSimprintsDownSynchronizationConfiguration + .newBuilder() + .setPartitionType(ProtoDownSynchronizationConfiguration.PartitionType.PROJECT) + .setMaxNbOfModules(1) + .setIsTokenized(true) + .addModuleOptions("module1") + .setMaxAge("PT24H") + .setFrequency(ProtoSyncFrequency.PERIODICALLY) + .build(), + ).build(), ).setSamples( ProtoSampleSynchronizationConfiguration .newBuilder() diff --git a/infra/event-sync/src/main/java/com/simprints/infra/eventsync/EventSyncManagerImpl.kt b/infra/event-sync/src/main/java/com/simprints/infra/eventsync/EventSyncManagerImpl.kt index ffbcaffcf1..e3ea7842bd 100644 --- a/infra/event-sync/src/main/java/com/simprints/infra/eventsync/EventSyncManagerImpl.kt +++ b/infra/event-sync/src/main/java/com/simprints/infra/eventsync/EventSyncManagerImpl.kt @@ -75,7 +75,7 @@ internal class EventSyncManagerImpl @Inject constructor( val downSyncScope = downSyncScopeRepository.getDownSyncScope( modes = getProjectModes(projectConfig), selectedModuleIDs = deviceConfig.selectedModules.values(), - syncPartitioning = projectConfig.synchronization.down.partitionType + syncPartitioning = projectConfig.synchronization.down.simprints.partitionType .toDomain(), ) diff --git a/infra/event-sync/src/main/java/com/simprints/infra/eventsync/sync/down/EventDownSyncWorkersBuilder.kt b/infra/event-sync/src/main/java/com/simprints/infra/eventsync/sync/down/EventDownSyncWorkersBuilder.kt index 498d24532d..487e8da526 100644 --- a/infra/event-sync/src/main/java/com/simprints/infra/eventsync/sync/down/EventDownSyncWorkersBuilder.kt +++ b/infra/event-sync/src/main/java/com/simprints/infra/eventsync/sync/down/EventDownSyncWorkersBuilder.kt @@ -39,7 +39,7 @@ internal class EventDownSyncWorkersBuilder @Inject constructor( val downSyncScope = downSyncScopeRepository.getDownSyncScope( modes = projectConfiguration.general.modalities.map { it.toMode() }, selectedModuleIDs = deviceConfiguration.selectedModules.values(), - syncPartitioning = projectConfiguration.synchronization.down.partitionType + syncPartitioning = projectConfiguration.synchronization.down.simprints.partitionType .toDomain(), ) diff --git a/infra/event-sync/src/main/java/com/simprints/infra/eventsync/sync/master/EventSyncMasterWorker.kt b/infra/event-sync/src/main/java/com/simprints/infra/eventsync/sync/master/EventSyncMasterWorker.kt index baaece80f7..ca0529b29f 100644 --- a/infra/event-sync/src/main/java/com/simprints/infra/eventsync/sync/master/EventSyncMasterWorker.kt +++ b/infra/event-sync/src/main/java/com/simprints/infra/eventsync/sync/master/EventSyncMasterWorker.kt @@ -10,9 +10,9 @@ import androidx.work.workDataOf import com.simprints.core.DispatcherBG import com.simprints.core.tools.time.TimeHelper import com.simprints.core.workers.SimCoroutineWorker +import com.simprints.infra.config.store.models.Frequency import com.simprints.infra.config.store.models.ProjectConfiguration import com.simprints.infra.config.store.models.ProjectState -import com.simprints.infra.config.store.models.SynchronizationConfiguration import com.simprints.infra.config.store.models.canSyncDataToSimprints import com.simprints.infra.config.store.models.isEventDownSyncAllowed import com.simprints.infra.config.sync.ConfigManager @@ -146,7 +146,7 @@ class EventSyncMasterWorker @AssistedInject internal constructor( configManager.getProject(configuration.projectId).state == ProjectState.PROJECT_PAUSED val isDownSyncConfigEnabled = - configuration.synchronization.frequency != SynchronizationConfiguration.Frequency.ONLY_PERIODICALLY_UP_SYNC + configuration.synchronization.down.simprints.frequency != Frequency.ONLY_PERIODICALLY_UP_SYNC return !isProjectPaused && isDownSyncConfigEnabled } diff --git a/infra/event-sync/src/test/java/com/simprints/infra/eventsync/EventSyncManagerTest.kt b/infra/event-sync/src/test/java/com/simprints/infra/eventsync/EventSyncManagerTest.kt index 776c8c9105..27c8b429ff 100644 --- a/infra/event-sync/src/test/java/com/simprints/infra/eventsync/EventSyncManagerTest.kt +++ b/infra/event-sync/src/test/java/com/simprints/infra/eventsync/EventSyncManagerTest.kt @@ -84,7 +84,10 @@ internal class EventSyncManagerTest { every { timeHelper.now() } returns Timestamp(1) coEvery { configRepository.getProjectConfiguration() } returns mockk { every { general.modalities } returns listOf() - every { synchronization.down.partitionType.toDomain() } returns Partitioning.MODULE + every { + synchronization.down.simprints.partitionType + .toDomain() + } returns Partitioning.MODULE } eventSyncManagerImpl = EventSyncManagerImpl( diff --git a/infra/event-sync/src/test/java/com/simprints/infra/eventsync/sync/down/EventDownSyncWorkersBuilderTest.kt b/infra/event-sync/src/test/java/com/simprints/infra/eventsync/sync/down/EventDownSyncWorkersBuilderTest.kt index e0a4d323e4..a9af39c804 100644 --- a/infra/event-sync/src/test/java/com/simprints/infra/eventsync/sync/down/EventDownSyncWorkersBuilderTest.kt +++ b/infra/event-sync/src/test/java/com/simprints/infra/eventsync/sync/down/EventDownSyncWorkersBuilderTest.kt @@ -78,7 +78,7 @@ class EventDownSyncWorkersBuilderTest { @Test fun builder_forProjectDownSync_shouldReturnTheRightWorkers() = runTest { every { generalConfiguration.modalities } returns listOf(GeneralConfiguration.Modality.FINGERPRINT) - every { downSyncConfiguration.partitionType } returns DownSynchronizationConfiguration.PartitionType.PROJECT + every { downSyncConfiguration.simprints.partitionType } returns DownSynchronizationConfiguration.PartitionType.PROJECT coEvery { eventDownSyncScopeRepository.getDownSyncScope( modes = listOf(Modes.FINGERPRINT), @@ -97,7 +97,7 @@ class EventDownSyncWorkersBuilderTest { @Test fun builder_forUserDownSync_shouldReturnTheRightWorkers() = runTest { every { generalConfiguration.modalities } returns listOf(GeneralConfiguration.Modality.FINGERPRINT) - every { downSyncConfiguration.partitionType } returns DownSynchronizationConfiguration.PartitionType.USER + every { downSyncConfiguration.simprints.partitionType } returns DownSynchronizationConfiguration.PartitionType.USER coEvery { eventDownSyncScopeRepository.getDownSyncScope( modes = listOf(Modes.FINGERPRINT), @@ -115,7 +115,7 @@ class EventDownSyncWorkersBuilderTest { @Test fun builder_forModuleDownSync_shouldReturnTheRightWorkers() = runTest { every { generalConfiguration.modalities } returns listOf(GeneralConfiguration.Modality.FINGERPRINT) - every { downSyncConfiguration.partitionType } returns DownSynchronizationConfiguration.PartitionType.MODULE + every { downSyncConfiguration.simprints.partitionType } returns DownSynchronizationConfiguration.PartitionType.MODULE coEvery { eventDownSyncScopeRepository.getDownSyncScope( modes = listOf(Modes.FINGERPRINT), @@ -133,7 +133,7 @@ class EventDownSyncWorkersBuilderTest { @Test fun builder_periodicDownSyncWorkers_shouldHaveTheRightTags() = runTest { every { generalConfiguration.modalities } returns listOf(GeneralConfiguration.Modality.FACE) - every { downSyncConfiguration.partitionType } returns DownSynchronizationConfiguration.PartitionType.PROJECT + every { downSyncConfiguration.simprints.partitionType } returns DownSynchronizationConfiguration.PartitionType.PROJECT coEvery { eventDownSyncScopeRepository.getDownSyncScope( modes = listOf(Modes.FACE), @@ -152,7 +152,7 @@ class EventDownSyncWorkersBuilderTest { @Test fun builder_oneTimeDownSyncWorkers_shouldHaveTheRightTags() = runTest { every { generalConfiguration.modalities } returns listOf(GeneralConfiguration.Modality.FINGERPRINT) - every { downSyncConfiguration.partitionType } returns DownSynchronizationConfiguration.PartitionType.PROJECT + every { downSyncConfiguration.simprints.partitionType } returns DownSynchronizationConfiguration.PartitionType.PROJECT coEvery { eventDownSyncScopeRepository.getDownSyncScope( modes = listOf(Modes.FINGERPRINT), diff --git a/infra/event-sync/src/test/java/com/simprints/infra/eventsync/sync/master/EventSyncMasterWorkerTest.kt b/infra/event-sync/src/test/java/com/simprints/infra/eventsync/sync/master/EventSyncMasterWorkerTest.kt index c612024286..c90bb951be 100644 --- a/infra/event-sync/src/test/java/com/simprints/infra/eventsync/sync/master/EventSyncMasterWorkerTest.kt +++ b/infra/event-sync/src/test/java/com/simprints/infra/eventsync/sync/master/EventSyncMasterWorkerTest.kt @@ -1,8 +1,8 @@ package com.simprints.infra.eventsync.sync.master import android.content.Context -import androidx.test.core.app.ApplicationProvider.getApplicationContext -import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.core.app.ApplicationProvider.* +import androidx.test.ext.junit.runners.* import androidx.work.Configuration import androidx.work.ListenableWorker import androidx.work.ListenableWorker.Result.Success @@ -12,13 +12,14 @@ import androidx.work.WorkInfo import androidx.work.WorkManager import androidx.work.testing.WorkManagerTestInitHelper import androidx.work.workDataOf -import com.google.common.truth.Truth.assertThat +import com.google.common.truth.Truth.* import com.simprints.core.tools.time.TimeHelper +import com.simprints.infra.config.store.models.Frequency +import com.simprints.infra.config.store.models.Frequency.ONLY_PERIODICALLY_UP_SYNC +import com.simprints.infra.config.store.models.Frequency.PERIODICALLY import com.simprints.infra.config.store.models.ProjectConfiguration import com.simprints.infra.config.store.models.ProjectState import com.simprints.infra.config.store.models.SynchronizationConfiguration -import com.simprints.infra.config.store.models.SynchronizationConfiguration.Frequency.ONLY_PERIODICALLY_UP_SYNC -import com.simprints.infra.config.store.models.SynchronizationConfiguration.Frequency.PERIODICALLY import com.simprints.infra.config.store.models.UpSynchronizationConfiguration.SimprintsUpSynchronizationConfiguration import com.simprints.infra.config.store.models.UpSynchronizationConfiguration.UpSynchronizationKind.ALL import com.simprints.infra.config.store.models.UpSynchronizationConfiguration.UpSynchronizationKind.NONE @@ -34,16 +35,9 @@ import com.simprints.infra.eventsync.sync.up.EventUpSyncWorkersBuilder import com.simprints.infra.security.SecurityManager import com.simprints.infra.security.exceptions.RootedDeviceException import com.simprints.testtools.common.coroutines.TestCoroutineRule -import io.mockk.MockKAnnotations -import io.mockk.coEvery -import io.mockk.coVerify -import io.mockk.every +import io.mockk.* +import io.mockk.impl.annotations.* import io.mockk.impl.annotations.MockK -import io.mockk.impl.annotations.RelaxedMockK -import io.mockk.mockk -import io.mockk.mockkObject -import io.mockk.spyk -import io.mockk.verify import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Rule @@ -312,13 +306,13 @@ internal class EventSyncMasterWorkerTest { private suspend fun getIsEventDownSyncAllowedResult( projectState: ProjectState, - syncConfig: SynchronizationConfiguration.Frequency, + syncConfig: Frequency, ): ListenableWorker.Result { coEvery { configManager.getProject(any()).state } returns projectState coEvery { configManager.getProjectConfiguration() } returns mockk { every { projectId } returns "projectId" every { synchronization } returns mockk { - every { frequency } returns syncConfig + every { down.simprints.frequency } returns syncConfig every { up.simprints.kind } returns NONE } } @@ -338,7 +332,7 @@ internal class EventSyncMasterWorkerTest { } private fun canDownSync(should: Boolean) { - every { synchronizationConfiguration.frequency } returns if (should) PERIODICALLY else ONLY_PERIODICALLY_UP_SYNC + every { synchronizationConfiguration.down.simprints.frequency } returns if (should) PERIODICALLY else ONLY_PERIODICALLY_UP_SYNC } private fun canUpSync(should: Boolean) { diff --git a/infra/event-sync/src/test/java/com/simprints/infra/eventsync/sync/up/EventUpSyncWorkersBuilderTest.kt b/infra/event-sync/src/test/java/com/simprints/infra/eventsync/sync/up/EventUpSyncWorkersBuilderTest.kt index 3256452bba..c794b4d08c 100644 --- a/infra/event-sync/src/test/java/com/simprints/infra/eventsync/sync/up/EventUpSyncWorkersBuilderTest.kt +++ b/infra/event-sync/src/test/java/com/simprints/infra/eventsync/sync/up/EventUpSyncWorkersBuilderTest.kt @@ -47,7 +47,7 @@ class EventUpSyncWorkersBuilderTest { @Test fun builder_forProjectUpSync_shouldReturnTheRightWorkers() = runTest { every { generalConfiguration.modalities } returns listOf(GeneralConfiguration.Modality.FINGERPRINT) - every { downSyncConfiguration.partitionType } returns DownSynchronizationConfiguration.PartitionType.PROJECT + every { downSyncConfiguration.simprints.partitionType } returns DownSynchronizationConfiguration.PartitionType.PROJECT coEvery { eventUpSyncScopeRepository.getUpSyncScope() } returns SampleSyncScopes.projectUpSyncScope @@ -62,7 +62,7 @@ class EventUpSyncWorkersBuilderTest { @Test fun builder_periodicUpSyncWorkers_shouldHaveTheRightTags() = runTest { every { generalConfiguration.modalities } returns listOf(GeneralConfiguration.Modality.FACE) - every { downSyncConfiguration.partitionType } returns DownSynchronizationConfiguration.PartitionType.PROJECT + every { downSyncConfiguration.simprints.partitionType } returns DownSynchronizationConfiguration.PartitionType.PROJECT coEvery { eventUpSyncScopeRepository.getUpSyncScope() } returns SampleSyncScopes.projectUpSyncScope @@ -78,7 +78,7 @@ class EventUpSyncWorkersBuilderTest { @Test fun builder_oneTimeDownSyncWorkers_shouldHaveTheRightTags() = runTest { every { generalConfiguration.modalities } returns listOf(GeneralConfiguration.Modality.FINGERPRINT) - every { downSyncConfiguration.partitionType } returns DownSynchronizationConfiguration.PartitionType.PROJECT + every { downSyncConfiguration.simprints.partitionType } returns DownSynchronizationConfiguration.PartitionType.PROJECT coEvery { eventUpSyncScopeRepository.getUpSyncScope() } returns SampleSyncScopes.projectUpSyncScope diff --git a/infra/sync/src/main/java/com/simprints/infra/sync/config/usecase/ResetLocalRecordsIfConfigChangedUseCase.kt b/infra/sync/src/main/java/com/simprints/infra/sync/config/usecase/ResetLocalRecordsIfConfigChangedUseCase.kt index 5931e471ad..abc8f7fef8 100644 --- a/infra/sync/src/main/java/com/simprints/infra/sync/config/usecase/ResetLocalRecordsIfConfigChangedUseCase.kt +++ b/infra/sync/src/main/java/com/simprints/infra/sync/config/usecase/ResetLocalRecordsIfConfigChangedUseCase.kt @@ -26,5 +26,5 @@ internal class ResetLocalRecordsIfConfigChangedUseCase @Inject constructor( private fun hasPartitionTypeChanged( oldConfig: ProjectConfiguration, newConfig: ProjectConfiguration, - ) = oldConfig.synchronization.down.partitionType != newConfig.synchronization.down.partitionType + ) = oldConfig.synchronization.down.simprints.partitionType != newConfig.synchronization.down.simprints.partitionType } diff --git a/infra/sync/src/test/java/com/simprints/infra/sync/config/testtools/Models.kt b/infra/sync/src/test/java/com/simprints/infra/sync/config/testtools/Models.kt index a0a228f623..aa055eb0b9 100644 --- a/infra/sync/src/test/java/com/simprints/infra/sync/config/testtools/Models.kt +++ b/infra/sync/src/test/java/com/simprints/infra/sync/config/testtools/Models.kt @@ -8,6 +8,7 @@ import com.simprints.infra.config.store.models.DownSynchronizationConfiguration import com.simprints.infra.config.store.models.FaceConfiguration import com.simprints.infra.config.store.models.Finger import com.simprints.infra.config.store.models.FingerprintConfiguration +import com.simprints.infra.config.store.models.Frequency import com.simprints.infra.config.store.models.GeneralConfiguration import com.simprints.infra.config.store.models.IdentificationConfiguration import com.simprints.infra.config.store.models.MaxCaptureAttempts @@ -99,26 +100,31 @@ internal val consentConfiguration = ConsentConfiguration( ) internal val simprintsUpSyncConfigurationConfiguration = UpSynchronizationConfiguration.SimprintsUpSynchronizationConfiguration( - UpSynchronizationConfiguration.UpSynchronizationKind.ALL, - UpSynchronizationConfiguration.UpSyncBatchSizes.default(), - false, + kind = UpSynchronizationConfiguration.UpSynchronizationKind.ALL, + batchSizes = UpSynchronizationConfiguration.UpSyncBatchSizes.default(), + imagesRequireUnmeteredConnection = false, + frequency = Frequency.PERIODICALLY, +) + +internal val simprintsDownSyncConfigurationConfiguration = DownSynchronizationConfiguration.SimprintsDownSynchronizationConfiguration( + partitionType = DownSynchronizationConfiguration.PartitionType.PROJECT, + maxNbOfModules = 1, + moduleOptions = listOf("module1".asTokenizableEncrypted()), + maxAge = "PT24H", + frequency = Frequency.PERIODICALLY, ) internal val synchronizationConfiguration = SynchronizationConfiguration( - SynchronizationConfiguration.Frequency.PERIODICALLY, - UpSynchronizationConfiguration( - simprintsUpSyncConfigurationConfiguration, - UpSynchronizationConfiguration.CoSyncUpSynchronizationConfiguration( + up = UpSynchronizationConfiguration( + simprints = simprintsUpSyncConfigurationConfiguration, + coSync = UpSynchronizationConfiguration.CoSyncUpSynchronizationConfiguration( UpSynchronizationConfiguration.UpSynchronizationKind.NONE, ), ), - DownSynchronizationConfiguration( - DownSynchronizationConfiguration.PartitionType.PROJECT, - 1, - listOf("module1".asTokenizableEncrypted()), - "PT24H", + down = DownSynchronizationConfiguration( + simprints = simprintsDownSyncConfigurationConfiguration, ), - SampleSynchronizationConfiguration(3), + samples = SampleSynchronizationConfiguration(3), ) internal val identificationConfiguration = diff --git a/infra/sync/src/test/java/com/simprints/infra/sync/config/usecase/ResetLocalRecordsIfConfigChangedUseCaseTest.kt b/infra/sync/src/test/java/com/simprints/infra/sync/config/usecase/ResetLocalRecordsIfConfigChangedUseCaseTest.kt index 4c84ddcf7f..0f5886fe86 100644 --- a/infra/sync/src/test/java/com/simprints/infra/sync/config/usecase/ResetLocalRecordsIfConfigChangedUseCaseTest.kt +++ b/infra/sync/src/test/java/com/simprints/infra/sync/config/usecase/ResetLocalRecordsIfConfigChangedUseCaseTest.kt @@ -41,14 +41,18 @@ class ResetLocalRecordsIfConfigChangedUseCaseTest { projectConfiguration.copy( synchronization = synchronizationConfiguration.copy( down = synchronizationConfiguration.down.copy( - partitionType = DownSynchronizationConfiguration.PartitionType.MODULE, + simprints = synchronizationConfiguration.down.simprints.copy( + partitionType = DownSynchronizationConfiguration.PartitionType.MODULE, + ), ), ), ), projectConfiguration.copy( synchronization = synchronizationConfiguration.copy( down = synchronizationConfiguration.down.copy( - partitionType = DownSynchronizationConfiguration.PartitionType.MODULE, + simprints = synchronizationConfiguration.down.simprints.copy( + partitionType = DownSynchronizationConfiguration.PartitionType.MODULE, + ), ), ), ), @@ -68,14 +72,18 @@ class ResetLocalRecordsIfConfigChangedUseCaseTest { projectConfiguration.copy( synchronization = synchronizationConfiguration.copy( down = synchronizationConfiguration.down.copy( - partitionType = DownSynchronizationConfiguration.PartitionType.PROJECT, + simprints = synchronizationConfiguration.down.simprints.copy( + partitionType = DownSynchronizationConfiguration.PartitionType.PROJECT, + ), ), ), ), projectConfiguration.copy( synchronization = synchronizationConfiguration.copy( down = synchronizationConfiguration.down.copy( - partitionType = DownSynchronizationConfiguration.PartitionType.MODULE, + simprints = synchronizationConfiguration.down.simprints.copy( + partitionType = DownSynchronizationConfiguration.PartitionType.MODULE, + ), ), ), ),