From a4a611778857e8367e10dea78b8bcc35694ba394 Mon Sep 17 00:00:00 2001 From: Greyson Parrelli Date: Mon, 29 Jun 2026 15:39:31 -0400 Subject: [PATCH] Improve remote restore test coverage in regV5. --- .../RemoteBackupRestoreViewModel.kt | 44 ++- .../RemoteBackupRestoreViewModelTest.kt | 316 ++++++++++++++++-- 2 files changed, 325 insertions(+), 35 deletions(-) diff --git a/feature/registration/src/main/java/org/signal/registration/screens/remotebackuprestore/RemoteBackupRestoreViewModel.kt b/feature/registration/src/main/java/org/signal/registration/screens/remotebackuprestore/RemoteBackupRestoreViewModel.kt index 25acc5806d..c223aa3e4a 100644 --- a/feature/registration/src/main/java/org/signal/registration/screens/remotebackuprestore/RemoteBackupRestoreViewModel.kt +++ b/feature/registration/src/main/java/org/signal/registration/screens/remotebackuprestore/RemoteBackupRestoreViewModel.kt @@ -81,6 +81,7 @@ class RemoteBackupRestoreViewModel( repository.restoreRemoteBackup(_state.value.aep).collect { progress -> when (progress) { is RemoteBackupRestoreProgress.Downloading -> { + Log.i(TAG, "[restoreBackup] Restoring...") _state.value = _state.value.copy( restoreState = RemoteBackupRestoreState.RestoreState.InProgress, restoreProgress = RemoteBackupRestoreState.RestoreProgress( @@ -91,6 +92,7 @@ class RemoteBackupRestoreViewModel( ) } is RemoteBackupRestoreProgress.Restoring -> { + Log.i(TAG, "[restoreBackup] Restoring...") _state.value = _state.value.copy( restoreState = RemoteBackupRestoreState.RestoreState.InProgress, restoreProgress = RemoteBackupRestoreState.RestoreProgress( @@ -101,6 +103,7 @@ class RemoteBackupRestoreViewModel( ) } is RemoteBackupRestoreProgress.Finalizing -> { + Log.i(TAG, "[restoreBackup] Finalizing...") _state.value = _state.value.copy( restoreState = RemoteBackupRestoreState.RestoreState.InProgress, restoreProgress = RemoteBackupRestoreState.RestoreProgress( @@ -111,7 +114,7 @@ class RemoteBackupRestoreViewModel( ) } is RemoteBackupRestoreProgress.Complete -> { - Log.i(TAG, "Remote restore completed successfully") + Log.i(TAG, "[restoreBackup] Remote restore completed successfully.") _state.value = _state.value.copy( restoreState = RemoteBackupRestoreState.RestoreState.Restored, restoreProgress = null @@ -121,35 +124,35 @@ class RemoteBackupRestoreViewModel( repository.finishRegistrationOrCreateProfile(parentEventEmitter) } is RemoteBackupRestoreProgress.NetworkError -> { - Log.w(TAG, "Remote restore failed with network error", progress.cause) + Log.w(TAG, "[restoreBackup] Remote restore failed with network error.", progress.cause) _state.value = _state.value.copy( restoreState = RemoteBackupRestoreState.RestoreState.NetworkFailure, restoreProgress = null ) } is RemoteBackupRestoreProgress.InvalidBackupVersion -> { - Log.w(TAG, "Remote restore failed: invalid backup version") + Log.w(TAG, "[restoreBackup] Remote restore failed: invalid backup version.") _state.value = _state.value.copy( restoreState = RemoteBackupRestoreState.RestoreState.InvalidBackupVersion, restoreProgress = null ) } is RemoteBackupRestoreProgress.PermanentSvrBFailure -> { - Log.w(TAG, "Remote restore failed: permanent SVR-B failure") + Log.w(TAG, "[restoreBackup] Remote restore failed: permanent SVRB failure.") _state.value = _state.value.copy( restoreState = RemoteBackupRestoreState.RestoreState.PermanentSvrBFailure, restoreProgress = null ) } is RemoteBackupRestoreProgress.Canceled -> { - Log.w(TAG, "Remote restore was canceled") + Log.w(TAG, "[restoreBackup] Remote restore was canceled.") _state.value = _state.value.copy( restoreState = RemoteBackupRestoreState.RestoreState.Failed, restoreProgress = null ) } is RemoteBackupRestoreProgress.GenericError -> { - Log.w(TAG, "Remote restore failed", progress.cause) + Log.w(TAG, "[restoreBackup] Remote restore failed.", progress.cause) _state.value = _state.value.copy( restoreState = RemoteBackupRestoreState.RestoreState.Failed, restoreProgress = null @@ -170,10 +173,9 @@ class RemoteBackupRestoreViewModel( when (result) { is RequestResult.Success -> { + Log.i(TAG, "[loadBackupInfo] Successfully fetched backup info.") val info = result.result -// parentEventEmitter(RegistrationFlowEvent) - val lastModifiedResult = withContext(ioDispatcher) { repository.getBackupFileLastModified(_state.value.aep, info) } @@ -193,15 +195,35 @@ class RemoteBackupRestoreViewModel( ) } is RequestResult.NonSuccess -> { - _state.value = when (result.error) { - is NetworkController.GetBackupInfoError.NoBackup -> _state.value.copy(loadState = RemoteBackupRestoreState.LoadState.NotFound) - else -> _state.value.copy(loadState = RemoteBackupRestoreState.LoadState.Failure) + _state.value = when (val error = result.error) { + is NetworkController.GetBackupInfoError.NoBackup -> { + Log.w(TAG, "[loadBackupInfo] No backup found.") + _state.value.copy(loadState = RemoteBackupRestoreState.LoadState.NotFound) + } + is NetworkController.GetBackupInfoError.BadArguments -> { + Log.w(TAG, "[loadBackupInfo] Failed with bad arguments. Body: ${error.body}") + _state.value.copy(loadState = RemoteBackupRestoreState.LoadState.Failure) + } + is NetworkController.GetBackupInfoError.BadAuthCredential -> { + Log.w(TAG, "[loadBackupInfo] Bad auth credential. Body: ${error.body}") + _state.value.copy(loadState = RemoteBackupRestoreState.LoadState.Failure) + } + is NetworkController.GetBackupInfoError.Forbidden -> { + Log.w(TAG, "[loadBackupInfo] Forbidden. Body: ${error.body}") + _state.value.copy(loadState = RemoteBackupRestoreState.LoadState.Failure) + } + is NetworkController.GetBackupInfoError.RateLimited -> { + Log.w(TAG, "[loadBackupInfo] Rate limited. Try again in: ${error.retryAfter}") + _state.value.copy(loadState = RemoteBackupRestoreState.LoadState.Failure) + } } } is RequestResult.RetryableNetworkError -> { + Log.w(TAG, "[loadBackupInfo] Hit network error.", result.networkError) _state.value = _state.value.copy(loadState = RemoteBackupRestoreState.LoadState.Failure) } is RequestResult.ApplicationError -> { + Log.w(TAG, "[loadBackupInfo] Hit unexpected error.", result.cause) _state.value = _state.value.copy(loadState = RemoteBackupRestoreState.LoadState.Failure) } } diff --git a/feature/registration/src/test/java/org/signal/registration/screens/remotebackuprestore/RemoteBackupRestoreViewModelTest.kt b/feature/registration/src/test/java/org/signal/registration/screens/remotebackuprestore/RemoteBackupRestoreViewModelTest.kt index eff88358fa..ab6324ab0b 100644 --- a/feature/registration/src/test/java/org/signal/registration/screens/remotebackuprestore/RemoteBackupRestoreViewModelTest.kt +++ b/feature/registration/src/test/java/org/signal/registration/screens/remotebackuprestore/RemoteBackupRestoreViewModelTest.kt @@ -18,6 +18,8 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.launch +import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.resetMain import kotlinx.coroutines.test.runTest @@ -31,6 +33,8 @@ import org.signal.registration.NetworkController import org.signal.registration.RegistrationFlowEvent import org.signal.registration.RegistrationRepository import org.signal.registration.RestoreDecision +import java.io.IOException +import kotlin.time.Duration.Companion.seconds @OptIn(ExperimentalCoroutinesApi::class) class RemoteBackupRestoreViewModelTest { @@ -72,7 +76,22 @@ class RemoteBackupRestoreViewModelTest { ) } - // ==================== BackupRestoreBackup Tests ==================== + /** Keeps the [WhileSubscribed] `state` flow hot and records every emission for assertions. */ + private fun TestScope.collectStatesOf(viewModel: RemoteBackupRestoreViewModel): List { + val states = mutableListOf() + backgroundScope.launch { viewModel.state.collect { states.add(it) } } + return states + } + + private fun backupInfo(usedSpace: Long? = 1024L) = NetworkController.GetBackupInfoResponse( + cdn = 3, + backupDir = "dir", + mediaDir = "media", + backupName = "backup", + usedSpace = usedSpace + ) + + // ==================== BackupRestoreBackup ==================== @Test fun `BackupRestoreBackup emits InProgress state and triggers restore`() = runTest(testDispatcher) { @@ -90,7 +109,7 @@ class RemoteBackupRestoreViewModelTest { coVerify { mockRepository.restoreRemoteBackup(aep) } } - // ==================== Cancel Tests ==================== + // ==================== Cancel ==================== @Test fun `Cancel emits NavigateBack`() = runTest(testDispatcher) { @@ -103,7 +122,30 @@ class RemoteBackupRestoreViewModelTest { assertThat(emittedParentEvents.first()).isEqualTo(RegistrationFlowEvent.NavigateBack) } - // ==================== DismissError Tests ==================== + // ==================== Retry ==================== + + @Test + fun `Retry reloads backup info and re-emits the current state`() = runTest(testDispatcher) { + val viewModel = createViewModel() + val states = collectStatesOf(viewModel) + val currentState = RemoteBackupRestoreState(aep = aep) + + viewModel.applyEvent(currentState, RemoteBackupRestoreScreenEvents.Retry, stateEmitter) + + coVerify(exactly = 2) { mockRepository.getRemoteBackupInfo(aep) } + assertThat(emittedStates).hasSize(1) + assertThat(states.last().loadAttempts).isEqualTo(2) + } + + @Test + fun `init records a single load attempt`() = runTest(testDispatcher) { + val viewModel = createViewModel() + val states = collectStatesOf(viewModel) + + assertThat(states.last().loadAttempts).isEqualTo(1) + } + + // ==================== DismissError ==================== @Test fun `DismissError resets restoreState to None and clears progress`() = runTest(testDispatcher) { @@ -125,17 +167,11 @@ class RemoteBackupRestoreViewModelTest { assertThat(emittedStates.last().restoreProgress).isNull() } - // ==================== loadBackupInfo Tests ==================== + // ==================== loadBackupInfo ==================== @Test fun `init with successful backup info invokes getRemoteBackupInfo and getBackupFileLastModified`() = runTest(testDispatcher) { - val info = NetworkController.GetBackupInfoResponse( - cdn = 3, - backupDir = "dir", - mediaDir = "media", - backupName = "backup", - usedSpace = 1024L - ) + val info = backupInfo() coEvery { mockRepository.getRemoteBackupInfo(any()) } returns RequestResult.Success(info) coEvery { mockRepository.getBackupFileLastModified(any(), any()) } returns RequestResult.Success(1234L) @@ -146,19 +182,172 @@ class RemoteBackupRestoreViewModelTest { } @Test - fun `init with NoBackup error invokes getRemoteBackupInfo`() = runTest(testDispatcher) { + fun `init with successful backup info moves to Loaded with size and time`() = runTest(testDispatcher) { + coEvery { mockRepository.getRemoteBackupInfo(any()) } returns RequestResult.Success(backupInfo(usedSpace = 2048L)) + coEvery { mockRepository.getBackupFileLastModified(any(), any()) } returns RequestResult.Success(99999L) + + val viewModel = createViewModel() + val states = collectStatesOf(viewModel) + + assertThat(states.last().loadState).isEqualTo(RemoteBackupRestoreState.LoadState.Loaded) + assertThat(states.last().backupSize).isEqualTo(2048L) + assertThat(states.last().backupTime).isEqualTo(99999L) + } + + @Test + fun `init with null usedSpace defaults backup size to zero`() = runTest(testDispatcher) { + coEvery { mockRepository.getRemoteBackupInfo(any()) } returns RequestResult.Success(backupInfo(usedSpace = null)) + coEvery { mockRepository.getBackupFileLastModified(any(), any()) } returns RequestResult.Success(1L) + + val viewModel = createViewModel() + val states = collectStatesOf(viewModel) + + assertThat(states.last().loadState).isEqualTo(RemoteBackupRestoreState.LoadState.Loaded) + assertThat(states.last().backupSize).isEqualTo(0L) + } + + @Test + fun `init with successful info but failed last-modified lookup uses sentinel backup time`() = runTest(testDispatcher) { + coEvery { mockRepository.getRemoteBackupInfo(any()) } returns RequestResult.Success(backupInfo()) + coEvery { mockRepository.getBackupFileLastModified(any(), any()) } returns + RequestResult.NonSuccess(NetworkController.GetBackupInfoError.NoBackup) + + val viewModel = createViewModel() + val states = collectStatesOf(viewModel) + + assertThat(states.last().loadState).isEqualTo(RemoteBackupRestoreState.LoadState.Loaded) + assertThat(states.last().backupTime).isEqualTo(-1L) + } + + @Test + fun `init with NoBackup moves to NotFound`() = runTest(testDispatcher) { coEvery { mockRepository.getRemoteBackupInfo(any()) } returns RequestResult.NonSuccess(NetworkController.GetBackupInfoError.NoBackup) - createViewModel() + val viewModel = createViewModel() + val states = collectStatesOf(viewModel) - coVerify { mockRepository.getRemoteBackupInfo(aep) } + assertThat(states.last().loadState).isEqualTo(RemoteBackupRestoreState.LoadState.NotFound) } - // ==================== Restore Progress Tests ==================== + @Test + fun `init with BadArguments moves to Failure`() = runTest(testDispatcher) { + coEvery { mockRepository.getRemoteBackupInfo(any()) } returns + RequestResult.NonSuccess(NetworkController.GetBackupInfoError.BadArguments()) + + val viewModel = createViewModel() + val states = collectStatesOf(viewModel) + + assertThat(states.last().loadState).isEqualTo(RemoteBackupRestoreState.LoadState.Failure) + } @Test - fun `BackupRestoreBackup Complete progress emits UserSuppliedAepVerified and hands off to finishRegistrationOrCreateProfile`() = runTest(testDispatcher) { + fun `init with BadAuthCredential moves to Failure`() = runTest(testDispatcher) { + coEvery { mockRepository.getRemoteBackupInfo(any()) } returns + RequestResult.NonSuccess(NetworkController.GetBackupInfoError.BadAuthCredential()) + + val viewModel = createViewModel() + val states = collectStatesOf(viewModel) + + assertThat(states.last().loadState).isEqualTo(RemoteBackupRestoreState.LoadState.Failure) + } + + @Test + fun `init with Forbidden moves to Failure`() = runTest(testDispatcher) { + coEvery { mockRepository.getRemoteBackupInfo(any()) } returns + RequestResult.NonSuccess(NetworkController.GetBackupInfoError.Forbidden()) + + val viewModel = createViewModel() + val states = collectStatesOf(viewModel) + + assertThat(states.last().loadState).isEqualTo(RemoteBackupRestoreState.LoadState.Failure) + } + + @Test + fun `init with RateLimited moves to Failure`() = runTest(testDispatcher) { + coEvery { mockRepository.getRemoteBackupInfo(any()) } returns + RequestResult.NonSuccess(NetworkController.GetBackupInfoError.RateLimited(30.seconds)) + + val viewModel = createViewModel() + val states = collectStatesOf(viewModel) + + assertThat(states.last().loadState).isEqualTo(RemoteBackupRestoreState.LoadState.Failure) + } + + @Test + fun `init with retryable network error moves to Failure`() = runTest(testDispatcher) { + coEvery { mockRepository.getRemoteBackupInfo(any()) } returns + RequestResult.RetryableNetworkError(IOException("Network error")) + + val viewModel = createViewModel() + val states = collectStatesOf(viewModel) + + assertThat(states.last().loadState).isEqualTo(RemoteBackupRestoreState.LoadState.Failure) + } + + @Test + fun `init with application error moves to Failure`() = runTest(testDispatcher) { + coEvery { mockRepository.getRemoteBackupInfo(any()) } returns + RequestResult.ApplicationError(RuntimeException("Unexpected")) + + val viewModel = createViewModel() + val states = collectStatesOf(viewModel) + + assertThat(states.last().loadState).isEqualTo(RemoteBackupRestoreState.LoadState.Failure) + } + + // ==================== Restore progress ==================== + + @Test + fun `Downloading progress maps to InProgress with download bytes`() = runTest(testDispatcher) { + every { mockRepository.restoreRemoteBackup(any()) } returns flowOf( + RemoteBackupRestoreProgress.Downloading(bytesDownloaded = 30, totalBytes = 100) + ) + val viewModel = createViewModel() + val states = collectStatesOf(viewModel) + + viewModel.applyEvent(RemoteBackupRestoreState(aep = aep), RemoteBackupRestoreScreenEvents.BackupRestoreBackup, stateEmitter) + + val last = states.last() + assertThat(last.restoreState).isEqualTo(RemoteBackupRestoreState.RestoreState.InProgress) + assertThat(last.restoreProgress?.phase).isEqualTo(RemoteBackupRestoreState.RestoreProgress.Phase.Downloading) + assertThat(last.restoreProgress?.bytesCompleted).isEqualTo(30L) + assertThat(last.restoreProgress?.totalBytes).isEqualTo(100L) + } + + @Test + fun `Restoring progress maps to InProgress with restore bytes`() = runTest(testDispatcher) { + every { mockRepository.restoreRemoteBackup(any()) } returns flowOf( + RemoteBackupRestoreProgress.Restoring(bytesRead = 75, totalBytes = 100) + ) + val viewModel = createViewModel() + val states = collectStatesOf(viewModel) + + viewModel.applyEvent(RemoteBackupRestoreState(aep = aep), RemoteBackupRestoreScreenEvents.BackupRestoreBackup, stateEmitter) + + val last = states.last() + assertThat(last.restoreState).isEqualTo(RemoteBackupRestoreState.RestoreState.InProgress) + assertThat(last.restoreProgress?.phase).isEqualTo(RemoteBackupRestoreState.RestoreProgress.Phase.Restoring) + assertThat(last.restoreProgress?.bytesCompleted).isEqualTo(75L) + } + + @Test + fun `Finalizing progress maps to InProgress with finalizing phase`() = runTest(testDispatcher) { + every { mockRepository.restoreRemoteBackup(any()) } returns flowOf( + RemoteBackupRestoreProgress.Finalizing + ) + val viewModel = createViewModel() + val states = collectStatesOf(viewModel) + + viewModel.applyEvent(RemoteBackupRestoreState(aep = aep), RemoteBackupRestoreScreenEvents.BackupRestoreBackup, stateEmitter) + + val last = states.last() + assertThat(last.restoreState).isEqualTo(RemoteBackupRestoreState.RestoreState.InProgress) + assertThat(last.restoreProgress?.phase).isEqualTo(RemoteBackupRestoreState.RestoreProgress.Phase.Finalizing) + } + + @Test + fun `Complete progress emits UserSuppliedAepVerified and hands off to finishRegistrationOrCreateProfile`() = runTest(testDispatcher) { every { mockRepository.restoreRemoteBackup(any()) } returns flowOf( RemoteBackupRestoreProgress.Complete ) @@ -179,21 +368,100 @@ class RemoteBackupRestoreViewModelTest { } @Test - fun `BackupRestoreBackup NetworkError progress triggers restore and emits no parent events`() = runTest(testDispatcher) { + fun `Complete progress moves restore state to Restored and clears progress`() = runTest(testDispatcher) { + every { mockRepository.restoreRemoteBackup(any()) } returns flowOf( + RemoteBackupRestoreProgress.Complete + ) + val viewModel = createViewModel() + val states = collectStatesOf(viewModel) + + viewModel.applyEvent(RemoteBackupRestoreState(aep = aep), RemoteBackupRestoreScreenEvents.BackupRestoreBackup, stateEmitter) + + assertThat(states.last().restoreState).isEqualTo(RemoteBackupRestoreState.RestoreState.Restored) + assertThat(states.last().restoreProgress).isNull() + } + + @Test + fun `NetworkError progress moves restore state to NetworkFailure and emits no parent events`() = runTest(testDispatcher) { every { mockRepository.restoreRemoteBackup(any()) } returns flowOf( RemoteBackupRestoreProgress.NetworkError() ) - val viewModel = createViewModel() - val initialState = RemoteBackupRestoreState(aep = aep) + val states = collectStatesOf(viewModel) - viewModel.applyEvent( - initialState, - RemoteBackupRestoreScreenEvents.BackupRestoreBackup, - stateEmitter - ) + viewModel.applyEvent(RemoteBackupRestoreState(aep = aep), RemoteBackupRestoreScreenEvents.BackupRestoreBackup, stateEmitter) coVerify { mockRepository.restoreRemoteBackup(aep) } + assertThat(states.last().restoreState).isEqualTo(RemoteBackupRestoreState.RestoreState.NetworkFailure) assertThat(emittedParentEvents).hasSize(0) } + + @Test + fun `InvalidBackupVersion progress moves restore state to InvalidBackupVersion`() = runTest(testDispatcher) { + every { mockRepository.restoreRemoteBackup(any()) } returns flowOf( + RemoteBackupRestoreProgress.InvalidBackupVersion + ) + val viewModel = createViewModel() + val states = collectStatesOf(viewModel) + + viewModel.applyEvent(RemoteBackupRestoreState(aep = aep), RemoteBackupRestoreScreenEvents.BackupRestoreBackup, stateEmitter) + + assertThat(states.last().restoreState).isEqualTo(RemoteBackupRestoreState.RestoreState.InvalidBackupVersion) + } + + @Test + fun `PermanentSvrBFailure progress moves restore state to PermanentSvrBFailure`() = runTest(testDispatcher) { + every { mockRepository.restoreRemoteBackup(any()) } returns flowOf( + RemoteBackupRestoreProgress.PermanentSvrBFailure + ) + val viewModel = createViewModel() + val states = collectStatesOf(viewModel) + + viewModel.applyEvent(RemoteBackupRestoreState(aep = aep), RemoteBackupRestoreScreenEvents.BackupRestoreBackup, stateEmitter) + + assertThat(states.last().restoreState).isEqualTo(RemoteBackupRestoreState.RestoreState.PermanentSvrBFailure) + } + + @Test + fun `Canceled progress moves restore state to Failed`() = runTest(testDispatcher) { + every { mockRepository.restoreRemoteBackup(any()) } returns flowOf( + RemoteBackupRestoreProgress.Canceled + ) + val viewModel = createViewModel() + val states = collectStatesOf(viewModel) + + viewModel.applyEvent(RemoteBackupRestoreState(aep = aep), RemoteBackupRestoreScreenEvents.BackupRestoreBackup, stateEmitter) + + assertThat(states.last().restoreState).isEqualTo(RemoteBackupRestoreState.RestoreState.Failed) + } + + @Test + fun `GenericError progress moves restore state to Failed`() = runTest(testDispatcher) { + every { mockRepository.restoreRemoteBackup(any()) } returns flowOf( + RemoteBackupRestoreProgress.GenericError() + ) + val viewModel = createViewModel() + val states = collectStatesOf(viewModel) + + viewModel.applyEvent(RemoteBackupRestoreState(aep = aep), RemoteBackupRestoreScreenEvents.BackupRestoreBackup, stateEmitter) + + assertThat(states.last().restoreState).isEqualTo(RemoteBackupRestoreState.RestoreState.Failed) + } + + @Test + fun `a multi-phase progress sequence ends in Restored`() = runTest(testDispatcher) { + every { mockRepository.restoreRemoteBackup(any()) } returns flowOf( + RemoteBackupRestoreProgress.Downloading(bytesDownloaded = 10, totalBytes = 100), + RemoteBackupRestoreProgress.Restoring(bytesRead = 60, totalBytes = 100), + RemoteBackupRestoreProgress.Finalizing, + RemoteBackupRestoreProgress.Complete + ) + val viewModel = createViewModel() + val states = collectStatesOf(viewModel) + + viewModel.applyEvent(RemoteBackupRestoreState(aep = aep), RemoteBackupRestoreScreenEvents.BackupRestoreBackup, stateEmitter) + + assertThat(states.last().restoreState).isEqualTo(RemoteBackupRestoreState.RestoreState.Restored) + coVerify { mockRepository.finishRegistrationOrCreateProfile(parentEventEmitter, any()) } + } }