From 89cf8ee8ec99825b015d48e7642a6956660c00f9 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Mon, 26 Sep 2022 17:11:31 +0200 Subject: [PATCH] Unit test for signout success --- .../devices/v2/DevicesViewModelTest.kt | 1 + .../overview/SessionOverviewViewModelTest.kt | 99 ++++++++++++++++++- 2 files changed, 96 insertions(+), 4 deletions(-) diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/DevicesViewModelTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/DevicesViewModelTest.kt index a1b6205a77..c8cfdc6d8a 100644 --- a/vector/src/test/java/im/vector/app/features/settings/devices/v2/DevicesViewModelTest.kt +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/DevicesViewModelTest.kt @@ -70,6 +70,7 @@ class DevicesViewModelTest { @Before fun setup() { + // Needed for internal usage of Flow.throttleFirst() inside the ViewModel mockkStatic(SystemClock::class) every { SystemClock.elapsedRealtime() } returns 1234 } diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModelTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModelTest.kt index b9fc027a63..cb84478f19 100644 --- a/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModelTest.kt +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModelTest.kt @@ -16,11 +16,13 @@ package im.vector.app.features.settings.devices.v2.overview +import android.os.SystemClock import com.airbnb.mvrx.Success import com.airbnb.mvrx.test.MvRxTestRule import im.vector.app.features.settings.devices.v2.DeviceFullInfo import im.vector.app.features.settings.devices.v2.RefreshDevicesUseCase import im.vector.app.features.settings.devices.v2.signout.InterceptSignoutFlowResponseUseCase +import im.vector.app.features.settings.devices.v2.signout.SignoutSessionResult import im.vector.app.features.settings.devices.v2.signout.SignoutSessionUseCase import im.vector.app.features.settings.devices.v2.verification.CheckIfCurrentSessionCanBeVerifiedUseCase import im.vector.app.test.fakes.FakeActiveSessionHolder @@ -32,12 +34,23 @@ import im.vector.app.test.testDispatcher import io.mockk.coEvery import io.mockk.coVerify import io.mockk.every +import io.mockk.just import io.mockk.mockk +import io.mockk.mockkStatic +import io.mockk.runs +import io.mockk.slot +import io.mockk.unmockkAll import io.mockk.verify import kotlinx.coroutines.flow.flowOf +import org.junit.After +import org.junit.Before import org.junit.Rule import org.junit.Test +import org.matrix.android.sdk.api.auth.UIABaseAuth +import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor +import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel +import kotlin.coroutines.Continuation private const val A_SESSION_ID_1 = "session-id-1" private const val A_SESSION_ID_2 = "session-id-2" @@ -71,10 +84,23 @@ class SessionOverviewViewModelTest { refreshDevicesUseCase = refreshDevicesUseCase, ) + @Before + fun setup() { + // Needed for internal usage of Flow.throttleFirst() inside the ViewModel + mockkStatic(SystemClock::class) + every { SystemClock.elapsedRealtime() } returns 1234 + + givenVerificationService() + } + + @After + fun tearDown() { + unmockkAll() + } + @Test fun `given the viewModel has been initialized then viewState is updated with session info and current session verification status`() { // Given - givenVerificationService() val deviceFullInfo = mockk() every { getDeviceFullInfoUseCase.execute(A_SESSION_ID_1) } returns flowOf(deviceFullInfo) givenCurrentSessionIsTrusted() @@ -99,7 +125,6 @@ class SessionOverviewViewModelTest { @Test fun `given current session can be verified when handling verify current session action then self verification event is posted`() { // Given - givenVerificationService() val deviceFullInfo = mockk() every { deviceFullInfo.isCurrentDevice } returns true every { getDeviceFullInfoUseCase.execute(A_SESSION_ID_1) } returns flowOf(deviceFullInfo) @@ -124,7 +149,6 @@ class SessionOverviewViewModelTest { @Test fun `given current session cannot be verified when handling verify current session action then reset secrets event is posted`() { // Given - givenVerificationService() val deviceFullInfo = mockk() every { deviceFullInfo.isCurrentDevice } returns true every { getDeviceFullInfoUseCase.execute(A_SESSION_ID_1) } returns flowOf(deviceFullInfo) @@ -149,7 +173,6 @@ class SessionOverviewViewModelTest { @Test fun `given another session when handling verify session action then verify session event is posted`() { // Given - givenVerificationService() val deviceFullInfo = mockk() every { deviceFullInfo.isCurrentDevice } returns false every { getDeviceFullInfoUseCase.execute(A_SESSION_ID_1) } returns flowOf(deviceFullInfo) @@ -167,6 +190,74 @@ class SessionOverviewViewModelTest { .finish() } + @Test + fun `given current session when handling signout action then confirmation event is posted`() { + // Given + val deviceFullInfo = mockk() + every { deviceFullInfo.isCurrentDevice } returns true + every { getDeviceFullInfoUseCase.execute(A_SESSION_ID_1) } returns flowOf(deviceFullInfo) + val signoutAction = SessionOverviewAction.SignoutSession + givenCurrentSessionIsTrusted() + + // When + val viewModel = createViewModel() + val viewModelTest = viewModel.test() + viewModel.handle(signoutAction) + + // Then + viewModelTest + .assertEvent { it is SessionOverviewViewEvent.ConfirmSignoutCurrentSession } + .finish() + } + + @Test + fun `given another session and no reAuth is needed when handling signout action then signout process is performed`() { + // Given + val deviceFullInfo = mockk() + every { deviceFullInfo.isCurrentDevice } returns false + every { getDeviceFullInfoUseCase.execute(A_SESSION_ID_1) } returns flowOf(deviceFullInfo) + givenSignoutSuccess(A_SESSION_ID_1) + every { refreshDevicesUseCase.execute() } just runs + val signoutAction = SessionOverviewAction.SignoutSession + givenCurrentSessionIsTrusted() + val expectedViewState = SessionOverviewViewState( + deviceId = A_SESSION_ID_1, + isCurrentSessionTrusted = true, + deviceInfo = Success(deviceFullInfo), + isLoading = false, + ) + + // When + val viewModel = createViewModel() + val viewModelTest = viewModel.test() + viewModel.handle(signoutAction) + + // Then + viewModelTest + .assertStatesChanges( + expectedViewState, + { copy(isLoading = true) }, + { copy(isLoading = false) } + ) + .assertEvent { it is SessionOverviewViewEvent.SignoutSuccess } + .finish() + verify { + refreshDevicesUseCase.execute() + } + } + + private fun givenSignoutSuccess(deviceId: String) { + val interceptor = slot() + val flowResponse = mockk() + val errorCode = "errorCode" + val promise = mockk>() + every { interceptSignoutFlowResponseUseCase.execute(flowResponse, errorCode, promise) } returns SignoutSessionResult.Completed + coEvery { signoutSessionUseCase.execute(deviceId, capture(interceptor)) } coAnswers { + secondArg().performStage(flowResponse, errorCode, promise) + Result.success(Unit) + } + } + private fun givenVerificationService(): FakeVerificationService { val fakeVerificationService = fakeActiveSessionHolder .fakeSession