Checking if migration should be called after unlock, removing the force sync call when user should migrate on SyncManager and added a new Sync call on the MigrateToMyItemsVM

This commit is contained in:
Andre Rosado committed 2026-01-06 15:54:05 +00:00
1 parent 23737ef18e
commit cf711b656d
4 files changed
+52 -8

No files matched your search

@@ -406,6 +406,8 @@ class VaultSyncManagerImpl(
.onStart { mutableDecryptCipherListResultFlow.updateToPendingOrLoading() }
.map {
vaultLockManager.waitUntilUnlocked(userId = userId)
// Verify migration state after unlock with the cipher list from disk
vaultMigrationManager.verifyAndUpdateMigrationState(it)
vaultSdkSource
.decryptCipherListWithFailures(
userId = userId,
@@ -413,14 +415,6 @@ class VaultSyncManagerImpl(
)
.fold(
onSuccess = { result ->
// We need to be sure the data on device is updated
// before sending the user to the migration screen
if (vaultMigrationManager.shouldMigrateVault {
result.successes.any { it.organizationId == null }
}
) {
sync(forced = true)
}
DataState.Loaded(
result.copy(successes = result.successes.sortAlphabetically()),
)
@@ -9,6 +9,8 @@ import com.bitwarden.ui.util.Text
import com.bitwarden.ui.util.asText
import com.x8bit.bitwarden.data.platform.manager.event.OrganizationEventManager
import com.x8bit.bitwarden.data.platform.manager.model.OrganizationEvent
import com.x8bit.bitwarden.data.vault.manager.VaultMigrationManager
import com.x8bit.bitwarden.data.vault.manager.VaultSyncManager
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.launchIn
@@ -26,6 +28,8 @@ private const val KEY_STATE = "state"
@HiltViewModel
class MigrateToMyItemsViewModel @Inject constructor(
private val organizationEventManager: OrganizationEventManager,
val vaultMigrationManager: VaultMigrationManager,
val vaultSyncManager: VaultSyncManager,
savedStateHandle: SavedStateHandle,
) : BaseViewModel<MigrateToMyItemsState, MigrateToMyItemsEvent, MigrateToMyItemsAction>(
initialState = savedStateHandle[KEY_STATE] ?: run {
@@ -42,6 +46,11 @@ class MigrateToMyItemsViewModel @Inject constructor(
stateFlow
.onEach { savedStateHandle[KEY_STATE] = it }
.launchIn(viewModelScope)
viewModelScope.launch {
// We need to ensure we have the most recent data. No need to do anything
// RootNavViewModel will take care of navigating if needed
vaultSyncManager.syncForResult(forced = true)
}
}
override fun handleAction(action: MigrateToMyItemsAction) {
@@ -497,6 +497,41 @@ class VaultSyncManagerTest {
}
}
@Test
fun `vault unlock should trigger migration state verification with cipher list from disk`() =
runTest {
fakeAuthDiskSource.userState = MOCK_USER_STATE
val userId = "mockId-1"
val mockCipherList = listOf(createMockCipher(number = 1))
val mockEncryptedCipherList = mockCipherList.toEncryptedSdkCipherList()
val mockDecryptCipherListResult = createMockDecryptCipherListResult(number = 1)
val mutableCiphersStateFlow =
bufferedMutableSharedFlow<List<SyncResponseJson.Cipher>>(replay = 1)
setupVaultDiskSourceFlows(ciphersFlow = mutableCiphersStateFlow)
coEvery {
vaultSdkSource.decryptCipherListWithFailures(
userId = userId,
cipherList = mockEncryptedCipherList,
)
} returns mockDecryptCipherListResult.asSuccess()
vaultSyncManager
.decryptCipherListResultStateFlow
.test {
assertEquals(DataState.Loading, awaitItem())
mutableCiphersStateFlow.tryEmit(mockCipherList)
expectNoEvents()
setVaultToUnlocked(userId = userId)
assertEquals(DataState.Loaded(mockDecryptCipherListResult), awaitItem())
verify(exactly = 1) {
vaultMigrationManager.verifyAndUpdateMigrationState(mockCipherList)
}
}
}
@Suppress("MaxLineLength")
@Test
fun `collectionsStateFlow should emit decrypted list of collections when decryptCollectionList succeeds`() =
@@ -7,6 +7,8 @@ import com.bitwarden.ui.platform.resource.BitwardenString
import com.bitwarden.ui.util.asText
import com.x8bit.bitwarden.data.platform.manager.event.OrganizationEventManager
import com.x8bit.bitwarden.data.platform.manager.model.OrganizationEvent
import com.x8bit.bitwarden.data.vault.manager.VaultMigrationManager
import com.x8bit.bitwarden.data.vault.manager.VaultSyncManager
import io.mockk.every
import io.mockk.just
import io.mockk.mockk
@@ -26,6 +28,8 @@ class MigrateToMyItemsViewModelTest : BaseViewModelTest() {
private val mockOrganizationEventManager: OrganizationEventManager = mockk {
every { trackEvent(any()) } just runs
}
private val mockVaultMigrationManager: VaultMigrationManager = mockk(relaxed = true)
private val mockVaultSyncManager: VaultSyncManager = mockk(relaxed = true)
@BeforeEach
fun setup() {
@@ -176,6 +180,8 @@ class MigrateToMyItemsViewModelTest : BaseViewModelTest() {
)
return MigrateToMyItemsViewModel(
organizationEventManager = mockOrganizationEventManager,
vaultMigrationManager = mockVaultMigrationManager,
vaultSyncManager = mockVaultSyncManager,
savedStateHandle = savedStateHandle,
)
}