From 51e519909d86e91c99f4639d79de750ba399d40a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20=C5=BBerko?= Date: Tue, 3 Dec 2024 12:15:07 +0100 Subject: [PATCH 1/7] fix merge conflicts --- .../wire/android/ui/home/AppSyncViewModel.kt | 68 +++++++-- .../android/ui/home/AppSyncViewModelTest.kt | 130 ++++++++++++++++++ 2 files changed, 184 insertions(+), 14 deletions(-) create mode 100644 app/src/test/kotlin/com/wire/android/ui/home/AppSyncViewModelTest.kt diff --git a/app/src/main/kotlin/com/wire/android/ui/home/AppSyncViewModel.kt b/app/src/main/kotlin/com/wire/android/ui/home/AppSyncViewModel.kt index 79b2a2cbfb9..be27db10d08 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/AppSyncViewModel.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/AppSyncViewModel.kt @@ -17,33 +17,73 @@ */ package com.wire.android.ui.home -import androidx.lifecycle.SavedStateHandle +import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.wire.android.navigation.SavedStateViewModel -import com.wire.kalium.logic.feature.e2ei.CertificateRevocationListCheckWorker +import com.wire.android.appLogger +import com.wire.kalium.logic.feature.e2ei.CheckCrlRevocationListUseCase import com.wire.kalium.logic.feature.e2ei.usecase.ObserveCertificateRevocationForSelfClientUseCase import com.wire.kalium.logic.feature.featureConfig.FeatureFlagsSyncWorker +import com.wire.kalium.logic.feature.server.UpdateApiVersionsUseCase import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.Job +import kotlinx.coroutines.joinAll import kotlinx.coroutines.launch +import kotlinx.datetime.Clock +import kotlinx.datetime.Instant import javax.inject.Inject +import kotlin.time.Duration +import kotlin.time.Duration.Companion.minutes @HiltViewModel class AppSyncViewModel @Inject constructor( - override val savedStateHandle: SavedStateHandle, - private val certificateRevocationListCheckWorker: CertificateRevocationListCheckWorker, + private val syncCertificateRevocationListUseCase: CheckCrlRevocationListUseCase, private val observeCertificateRevocationForSelfClient: ObserveCertificateRevocationForSelfClientUseCase, - private val featureFlagsSyncWorker: FeatureFlagsSyncWorker -) : SavedStateViewModel(savedStateHandle) { + private val featureFlagsSyncWorker: FeatureFlagsSyncWorker, + private val updateApiVersions: UpdateApiVersionsUseCase +) : ViewModel() { + + private val minIntervalBetweenPulls: Duration = MIN_INTERVAL_BETWEEN_PULLS + + private var lastPullInstant: Instant? = null + private var syncDataJob: Job? = null fun startSyncingAppConfig() { - viewModelScope.launch { - certificateRevocationListCheckWorker.execute() - } - viewModelScope.launch { - observeCertificateRevocationForSelfClient.invoke() + if (isSyncing()) return + + val now = Clock.System.now() + if (isPullTooRecent(now)) return + + lastPullInstant = now + syncDataJob = viewModelScope.launch { + runSyncTasks() } - viewModelScope.launch { - featureFlagsSyncWorker.execute() + } + + private fun isSyncing(): Boolean { + return syncDataJob?.isActive == true + } + + private fun isPullTooRecent(now: Instant): Boolean { + return lastPullInstant?.let { lastPull -> + lastPull + minIntervalBetweenPulls > now + } ?: false + } + + @Suppress("TooGenericExceptionCaught") + private suspend fun runSyncTasks() { + try { + listOf( + viewModelScope.launch { syncCertificateRevocationListUseCase(false) }, + viewModelScope.launch { featureFlagsSyncWorker.execute() }, + viewModelScope.launch { observeCertificateRevocationForSelfClient.invoke() }, + viewModelScope.launch { updateApiVersions() }, + ).joinAll() + } catch (e: Exception) { + appLogger.e("Error while syncing app config", e) } } + + companion object { + val MIN_INTERVAL_BETWEEN_PULLS = 60.minutes + } } diff --git a/app/src/test/kotlin/com/wire/android/ui/home/AppSyncViewModelTest.kt b/app/src/test/kotlin/com/wire/android/ui/home/AppSyncViewModelTest.kt new file mode 100644 index 00000000000..531731fc301 --- /dev/null +++ b/app/src/test/kotlin/com/wire/android/ui/home/AppSyncViewModelTest.kt @@ -0,0 +1,130 @@ +/* + * Wire + * Copyright (C) 2024 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ +package com.wire.android.ui.home + +import com.wire.android.config.CoroutineTestExtension +import com.wire.kalium.logic.feature.e2ei.SyncCertificateRevocationListUseCase +import com.wire.kalium.logic.feature.e2ei.usecase.ObserveCertificateRevocationForSelfClientUseCase +import com.wire.kalium.logic.feature.featureConfig.FeatureFlagsSyncWorker +import com.wire.kalium.logic.feature.server.UpdateApiVersionsUseCase +import io.mockk.MockKAnnotations +import io.mockk.coEvery +import io.mockk.coVerify +import io.mockk.impl.annotations.MockK +import kotlinx.coroutines.InternalCoroutinesApi +import kotlinx.coroutines.delay +import kotlinx.coroutines.test.advanceUntilIdle +import kotlinx.coroutines.test.runTest +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(CoroutineTestExtension::class) +class AppSyncViewModelTest { + @Test + fun `when startSyncingAppConfig is called then it should call the use case`() = runTest { + val (arrangement, viewModel) = Arrangement().arrange { + withObserveCertificateRevocationForSelfClient() + withFeatureFlagsSyncWorker() + withSyncCertificateRevocationListUseCase() + withUpdateApiVersions() + } + + viewModel.startSyncingAppConfig() + advanceUntilIdle() + + coVerify { arrangement.observeCertificateRevocationForSelfClient.invoke() } + coVerify { arrangement.syncCertificateRevocationListUseCase.invoke() } + coVerify { arrangement.featureFlagsSyncWorker.execute() } + coVerify { arrangement.updateApiVersions() } + } + + @Test + fun `when startSyncingAppConfig is called multiple times then it should call the use case with delay`() = runTest { + val (arrangement, viewModel) = Arrangement().arrange { + withObserveCertificateRevocationForSelfClient(1000) + withFeatureFlagsSyncWorker(1000) + withSyncCertificateRevocationListUseCase(1000) + withUpdateApiVersions(1000) + } + + viewModel.startSyncingAppConfig() + viewModel.startSyncingAppConfig() + viewModel.startSyncingAppConfig() + advanceUntilIdle() + + coVerify(exactly = 1) { arrangement.observeCertificateRevocationForSelfClient.invoke() } + coVerify(exactly = 1) { arrangement.syncCertificateRevocationListUseCase.invoke() } + coVerify(exactly = 1) { arrangement.featureFlagsSyncWorker.execute() } + coVerify(exactly = 1) { arrangement.updateApiVersions() } + } + + private class Arrangement { + + @MockK + lateinit var syncCertificateRevocationListUseCase: SyncCertificateRevocationListUseCase + + @MockK + lateinit var observeCertificateRevocationForSelfClient: ObserveCertificateRevocationForSelfClientUseCase + + @MockK + lateinit var featureFlagsSyncWorker: FeatureFlagsSyncWorker + + @MockK + lateinit var updateApiVersions: UpdateApiVersionsUseCase + + init { + MockKAnnotations.init(this) + } + + private val viewModel = AppSyncViewModel( + syncCertificateRevocationListUseCase, + observeCertificateRevocationForSelfClient, + featureFlagsSyncWorker, + updateApiVersions + ) + + @OptIn(InternalCoroutinesApi::class) + fun withObserveCertificateRevocationForSelfClient(delayMs: Long = 0) { + coEvery { observeCertificateRevocationForSelfClient.invoke() } coAnswers { + delay(delayMs) + } + } + + fun withSyncCertificateRevocationListUseCase(delayMs: Long = 0) { + coEvery { syncCertificateRevocationListUseCase.invoke() } coAnswers { + delay(delayMs) + } + } + + fun withFeatureFlagsSyncWorker(delayMs: Long = 0) { + coEvery { featureFlagsSyncWorker.execute() } coAnswers { + delay(delayMs) + } + } + + fun withUpdateApiVersions(delayMs: Long = 0) { + coEvery { updateApiVersions() } coAnswers { + delay(delayMs) + } + } + + fun arrange(block: Arrangement.() -> Unit) = apply(block).let { + this to viewModel + } + } +} From 90b3f15f79c0c782a656c93ebd54dcb6c157d9d4 Mon Sep 17 00:00:00 2001 From: Mohamad Jaara Date: Tue, 7 Jan 2025 14:18:13 +0100 Subject: [PATCH 2/7] add changes for the crl revocation check --- .../main/kotlin/com/wire/android/ui/home/AppSyncViewModel.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/kotlin/com/wire/android/ui/home/AppSyncViewModel.kt b/app/src/main/kotlin/com/wire/android/ui/home/AppSyncViewModel.kt index be27db10d08..60e950a45e2 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/AppSyncViewModel.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/AppSyncViewModel.kt @@ -20,6 +20,7 @@ package com.wire.android.ui.home import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.wire.android.appLogger +import com.wire.kalium.logic.feature.e2ei.CertificateRevocationListCheckWorker import com.wire.kalium.logic.feature.e2ei.CheckCrlRevocationListUseCase import com.wire.kalium.logic.feature.e2ei.usecase.ObserveCertificateRevocationForSelfClientUseCase import com.wire.kalium.logic.feature.featureConfig.FeatureFlagsSyncWorker @@ -36,7 +37,7 @@ import kotlin.time.Duration.Companion.minutes @HiltViewModel class AppSyncViewModel @Inject constructor( - private val syncCertificateRevocationListUseCase: CheckCrlRevocationListUseCase, + private val syncCertificateRevocationListUseCase: CertificateRevocationListCheckWorker, private val observeCertificateRevocationForSelfClient: ObserveCertificateRevocationForSelfClientUseCase, private val featureFlagsSyncWorker: FeatureFlagsSyncWorker, private val updateApiVersions: UpdateApiVersionsUseCase From 4bbdc9b4b2b8aaeb592b0bb14c8d88fd0a60e352 Mon Sep 17 00:00:00 2001 From: Mohamad Jaara Date: Tue, 7 Jan 2025 14:18:34 +0100 Subject: [PATCH 3/7] update kalium --- kalium | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kalium b/kalium index c5c24685027..c5c0ef16709 160000 --- a/kalium +++ b/kalium @@ -1 +1 @@ -Subproject commit c5c24685027a629022cabe70750ff62d7edc48ff +Subproject commit c5c0ef16709873222a1eeee4e4f49734c9f2df46 From 0644277b42628f07bf8b926f0ddd97cc3ec1a687 Mon Sep 17 00:00:00 2001 From: Mohamad Jaara Date: Tue, 7 Jan 2025 14:32:15 +0100 Subject: [PATCH 4/7] detekt --- kalium | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kalium b/kalium index c5c0ef16709..6e254463125 160000 --- a/kalium +++ b/kalium @@ -1 +1 @@ -Subproject commit c5c0ef16709873222a1eeee4e4f49734c9f2df46 +Subproject commit 6e2544631257b1da4740a814e63c2ebe2cacf6ab From 990d86d5e819bfad0e32dcd84eaa5474e206aa1d Mon Sep 17 00:00:00 2001 From: Mohamad Jaara Date: Tue, 7 Jan 2025 15:24:28 +0100 Subject: [PATCH 5/7] fix dependencies --- .../kotlin/com/wire/android/di/accountScoped/UserModule.kt | 6 +++--- .../kotlin/com/wire/android/ui/home/AppSyncViewModel.kt | 5 +++-- kalium | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/app/src/main/kotlin/com/wire/android/di/accountScoped/UserModule.kt b/app/src/main/kotlin/com/wire/android/di/accountScoped/UserModule.kt index 3fa653b074f..3d4a174eae2 100644 --- a/app/src/main/kotlin/com/wire/android/di/accountScoped/UserModule.kt +++ b/app/src/main/kotlin/com/wire/android/di/accountScoped/UserModule.kt @@ -26,7 +26,7 @@ import com.wire.kalium.logic.feature.asset.GetAssetSizeLimitUseCase import com.wire.kalium.logic.feature.asset.GetAvatarAssetUseCase import com.wire.kalium.logic.feature.client.FinalizeMLSClientAfterE2EIEnrollment import com.wire.kalium.logic.feature.conversation.GetAllContactsNotInConversationUseCase -import com.wire.kalium.logic.feature.e2ei.CertificateRevocationListCheckWorker +import com.wire.kalium.logic.feature.e2ei.SyncCertificateRevocationListUseCase import com.wire.kalium.logic.feature.e2ei.usecase.GetMLSClientIdentityUseCase import com.wire.kalium.logic.feature.e2ei.usecase.GetMembersE2EICertificateStatusesUseCase import com.wire.kalium.logic.feature.e2ei.usecase.IsOtherUserE2EIVerifiedUseCase @@ -232,8 +232,8 @@ class UserModule { @ViewModelScoped @Provides - fun provideCertificateRevocationListCheckWorker(userScope: UserScope): CertificateRevocationListCheckWorker = - userScope.certificateRevocationListCheckWorker + fun provideCertificateRevocationListCheckWorker(userScope: UserScope): SyncCertificateRevocationListUseCase = + userScope.syncCertificateRevocationListUseCase @ViewModelScoped @Provides diff --git a/app/src/main/kotlin/com/wire/android/ui/home/AppSyncViewModel.kt b/app/src/main/kotlin/com/wire/android/ui/home/AppSyncViewModel.kt index 60e950a45e2..c076c7744ff 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/AppSyncViewModel.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/AppSyncViewModel.kt @@ -22,6 +22,7 @@ import androidx.lifecycle.viewModelScope import com.wire.android.appLogger import com.wire.kalium.logic.feature.e2ei.CertificateRevocationListCheckWorker import com.wire.kalium.logic.feature.e2ei.CheckCrlRevocationListUseCase +import com.wire.kalium.logic.feature.e2ei.SyncCertificateRevocationListUseCase import com.wire.kalium.logic.feature.e2ei.usecase.ObserveCertificateRevocationForSelfClientUseCase import com.wire.kalium.logic.feature.featureConfig.FeatureFlagsSyncWorker import com.wire.kalium.logic.feature.server.UpdateApiVersionsUseCase @@ -37,7 +38,7 @@ import kotlin.time.Duration.Companion.minutes @HiltViewModel class AppSyncViewModel @Inject constructor( - private val syncCertificateRevocationListUseCase: CertificateRevocationListCheckWorker, + private val syncCertificateRevocationListUseCase: SyncCertificateRevocationListUseCase, private val observeCertificateRevocationForSelfClient: ObserveCertificateRevocationForSelfClientUseCase, private val featureFlagsSyncWorker: FeatureFlagsSyncWorker, private val updateApiVersions: UpdateApiVersionsUseCase @@ -74,7 +75,7 @@ class AppSyncViewModel @Inject constructor( private suspend fun runSyncTasks() { try { listOf( - viewModelScope.launch { syncCertificateRevocationListUseCase(false) }, + viewModelScope.launch { syncCertificateRevocationListUseCase() }, viewModelScope.launch { featureFlagsSyncWorker.execute() }, viewModelScope.launch { observeCertificateRevocationForSelfClient.invoke() }, viewModelScope.launch { updateApiVersions() }, diff --git a/kalium b/kalium index 6e254463125..9bc8774a7b6 160000 --- a/kalium +++ b/kalium @@ -1 +1 @@ -Subproject commit 6e2544631257b1da4740a814e63c2ebe2cacf6ab +Subproject commit 9bc8774a7b6aa63704c9c5d56ca8a73c1acebe76 From 5eba8b53c6e11c5c0622bae25cdd262b269a5c7e Mon Sep 17 00:00:00 2001 From: Mohamad Jaara Date: Tue, 7 Jan 2025 15:32:42 +0100 Subject: [PATCH 6/7] fix dependencies --- .../main/kotlin/com/wire/android/ui/home/AppSyncViewModel.kt | 2 -- .../main/kotlin/com/wire/android/ui/home/HomeViewModel.kt | 5 ----- kalium | 2 +- 3 files changed, 1 insertion(+), 8 deletions(-) diff --git a/app/src/main/kotlin/com/wire/android/ui/home/AppSyncViewModel.kt b/app/src/main/kotlin/com/wire/android/ui/home/AppSyncViewModel.kt index c076c7744ff..cf9839278b4 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/AppSyncViewModel.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/AppSyncViewModel.kt @@ -20,8 +20,6 @@ package com.wire.android.ui.home import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.wire.android.appLogger -import com.wire.kalium.logic.feature.e2ei.CertificateRevocationListCheckWorker -import com.wire.kalium.logic.feature.e2ei.CheckCrlRevocationListUseCase import com.wire.kalium.logic.feature.e2ei.SyncCertificateRevocationListUseCase import com.wire.kalium.logic.feature.e2ei.usecase.ObserveCertificateRevocationForSelfClientUseCase import com.wire.kalium.logic.feature.featureConfig.FeatureFlagsSyncWorker diff --git a/app/src/main/kotlin/com/wire/android/ui/home/HomeViewModel.kt b/app/src/main/kotlin/com/wire/android/ui/home/HomeViewModel.kt index f810fec27eb..71f9347f382 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/HomeViewModel.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/HomeViewModel.kt @@ -29,7 +29,6 @@ import com.wire.android.model.ImageAsset.UserAvatarAsset import com.wire.android.navigation.SavedStateViewModel import com.wire.android.util.ui.WireSessionImageLoader import com.wire.kalium.logic.feature.client.NeedsToRegisterClientUseCase -import com.wire.kalium.logic.feature.e2ei.CertificateRevocationListCheckWorker import com.wire.kalium.logic.feature.user.GetSelfUserUseCase import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.first @@ -45,7 +44,6 @@ class HomeViewModel @Inject constructor( private val needsToRegisterClient: NeedsToRegisterClientUseCase, private val wireSessionImageLoader: WireSessionImageLoader, private val shouldTriggerMigrationForUser: ShouldTriggerMigrationForUserUserCase, - private val certificateRevocationListCheckWorker: CertificateRevocationListCheckWorker ) : SavedStateViewModel(savedStateHandle) { var homeState by mutableStateOf(HomeState()) @@ -53,9 +51,6 @@ class HomeViewModel @Inject constructor( init { loadUserAvatar() - viewModelScope.launch { - certificateRevocationListCheckWorker.execute() - } } fun checkRequirements(onRequirement: (HomeRequirement) -> Unit) { diff --git a/kalium b/kalium index 9bc8774a7b6..bf7f4965c89 160000 --- a/kalium +++ b/kalium @@ -1 +1 @@ -Subproject commit 9bc8774a7b6aa63704c9c5d56ca8a73c1acebe76 +Subproject commit bf7f4965c896abcde01234f008e6b93c209faa27 From 0444fb232850ef9f296fef4373f3d30e953d5ad4 Mon Sep 17 00:00:00 2001 From: Mohamad Jaara Date: Tue, 7 Jan 2025 17:20:30 +0100 Subject: [PATCH 7/7] fix tests --- kalium | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kalium b/kalium index bf7f4965c89..df62e267723 160000 --- a/kalium +++ b/kalium @@ -1 +1 @@ -Subproject commit bf7f4965c896abcde01234f008e6b93c209faa27 +Subproject commit df62e267723c403c4ba44ea13cf0648b4269fa9e