Unit test for signout success

This commit is contained in:
Maxime NATUREL 2022-09-26 17:11:31 +02:00
parent da3d3308b4
commit 89cf8ee8ec
2 changed files with 96 additions and 4 deletions

View File

@ -70,6 +70,7 @@ class DevicesViewModelTest {
@Before @Before
fun setup() { fun setup() {
// Needed for internal usage of Flow<T>.throttleFirst() inside the ViewModel
mockkStatic(SystemClock::class) mockkStatic(SystemClock::class)
every { SystemClock.elapsedRealtime() } returns 1234 every { SystemClock.elapsedRealtime() } returns 1234
} }

View File

@ -16,11 +16,13 @@
package im.vector.app.features.settings.devices.v2.overview package im.vector.app.features.settings.devices.v2.overview
import android.os.SystemClock
import com.airbnb.mvrx.Success import com.airbnb.mvrx.Success
import com.airbnb.mvrx.test.MvRxTestRule import com.airbnb.mvrx.test.MvRxTestRule
import im.vector.app.features.settings.devices.v2.DeviceFullInfo 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.RefreshDevicesUseCase
import im.vector.app.features.settings.devices.v2.signout.InterceptSignoutFlowResponseUseCase 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.signout.SignoutSessionUseCase
import im.vector.app.features.settings.devices.v2.verification.CheckIfCurrentSessionCanBeVerifiedUseCase import im.vector.app.features.settings.devices.v2.verification.CheckIfCurrentSessionCanBeVerifiedUseCase
import im.vector.app.test.fakes.FakeActiveSessionHolder import im.vector.app.test.fakes.FakeActiveSessionHolder
@ -32,12 +34,23 @@ import im.vector.app.test.testDispatcher
import io.mockk.coEvery import io.mockk.coEvery
import io.mockk.coVerify import io.mockk.coVerify
import io.mockk.every import io.mockk.every
import io.mockk.just
import io.mockk.mockk 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 io.mockk.verify
import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOf
import org.junit.After
import org.junit.Before
import org.junit.Rule import org.junit.Rule
import org.junit.Test 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 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_1 = "session-id-1"
private const val A_SESSION_ID_2 = "session-id-2" private const val A_SESSION_ID_2 = "session-id-2"
@ -71,10 +84,23 @@ class SessionOverviewViewModelTest {
refreshDevicesUseCase = refreshDevicesUseCase, refreshDevicesUseCase = refreshDevicesUseCase,
) )
@Before
fun setup() {
// Needed for internal usage of Flow<T>.throttleFirst() inside the ViewModel
mockkStatic(SystemClock::class)
every { SystemClock.elapsedRealtime() } returns 1234
givenVerificationService()
}
@After
fun tearDown() {
unmockkAll()
}
@Test @Test
fun `given the viewModel has been initialized then viewState is updated with session info and current session verification status`() { fun `given the viewModel has been initialized then viewState is updated with session info and current session verification status`() {
// Given // Given
givenVerificationService()
val deviceFullInfo = mockk<DeviceFullInfo>() val deviceFullInfo = mockk<DeviceFullInfo>()
every { getDeviceFullInfoUseCase.execute(A_SESSION_ID_1) } returns flowOf(deviceFullInfo) every { getDeviceFullInfoUseCase.execute(A_SESSION_ID_1) } returns flowOf(deviceFullInfo)
givenCurrentSessionIsTrusted() givenCurrentSessionIsTrusted()
@ -99,7 +125,6 @@ class SessionOverviewViewModelTest {
@Test @Test
fun `given current session can be verified when handling verify current session action then self verification event is posted`() { fun `given current session can be verified when handling verify current session action then self verification event is posted`() {
// Given // Given
givenVerificationService()
val deviceFullInfo = mockk<DeviceFullInfo>() val deviceFullInfo = mockk<DeviceFullInfo>()
every { deviceFullInfo.isCurrentDevice } returns true every { deviceFullInfo.isCurrentDevice } returns true
every { getDeviceFullInfoUseCase.execute(A_SESSION_ID_1) } returns flowOf(deviceFullInfo) every { getDeviceFullInfoUseCase.execute(A_SESSION_ID_1) } returns flowOf(deviceFullInfo)
@ -124,7 +149,6 @@ class SessionOverviewViewModelTest {
@Test @Test
fun `given current session cannot be verified when handling verify current session action then reset secrets event is posted`() { fun `given current session cannot be verified when handling verify current session action then reset secrets event is posted`() {
// Given // Given
givenVerificationService()
val deviceFullInfo = mockk<DeviceFullInfo>() val deviceFullInfo = mockk<DeviceFullInfo>()
every { deviceFullInfo.isCurrentDevice } returns true every { deviceFullInfo.isCurrentDevice } returns true
every { getDeviceFullInfoUseCase.execute(A_SESSION_ID_1) } returns flowOf(deviceFullInfo) every { getDeviceFullInfoUseCase.execute(A_SESSION_ID_1) } returns flowOf(deviceFullInfo)
@ -149,7 +173,6 @@ class SessionOverviewViewModelTest {
@Test @Test
fun `given another session when handling verify session action then verify session event is posted`() { fun `given another session when handling verify session action then verify session event is posted`() {
// Given // Given
givenVerificationService()
val deviceFullInfo = mockk<DeviceFullInfo>() val deviceFullInfo = mockk<DeviceFullInfo>()
every { deviceFullInfo.isCurrentDevice } returns false every { deviceFullInfo.isCurrentDevice } returns false
every { getDeviceFullInfoUseCase.execute(A_SESSION_ID_1) } returns flowOf(deviceFullInfo) every { getDeviceFullInfoUseCase.execute(A_SESSION_ID_1) } returns flowOf(deviceFullInfo)
@ -167,6 +190,74 @@ class SessionOverviewViewModelTest {
.finish() .finish()
} }
@Test
fun `given current session when handling signout action then confirmation event is posted`() {
// Given
val deviceFullInfo = mockk<DeviceFullInfo>()
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<DeviceFullInfo>()
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<UserInteractiveAuthInterceptor>()
val flowResponse = mockk<RegistrationFlowResponse>()
val errorCode = "errorCode"
val promise = mockk<Continuation<UIABaseAuth>>()
every { interceptSignoutFlowResponseUseCase.execute(flowResponse, errorCode, promise) } returns SignoutSessionResult.Completed
coEvery { signoutSessionUseCase.execute(deviceId, capture(interceptor)) } coAnswers {
secondArg<UserInteractiveAuthInterceptor>().performStage(flowResponse, errorCode, promise)
Result.success(Unit)
}
}
private fun givenVerificationService(): FakeVerificationService { private fun givenVerificationService(): FakeVerificationService {
val fakeVerificationService = fakeActiveSessionHolder val fakeVerificationService = fakeActiveSessionHolder
.fakeSession .fakeSession