diff --git a/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/outgoing/OutgoingVerificationStateMachine.kt b/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/outgoing/OutgoingVerificationStateMachine.kt index 7932ccc484..465fc20066 100644 --- a/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/outgoing/OutgoingVerificationStateMachine.kt +++ b/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/outgoing/OutgoingVerificationStateMachine.kt @@ -46,7 +46,7 @@ class OutgoingVerificationStateMachine( inState { onEnterEffect { event -> when (event.verificationRequest) { - is VerificationRequest.Outgoing.CurrentSession -> sessionVerificationService.requestCurrentSessionVerification() + is VerificationRequest.Outgoing.CurrentSession -> sessionVerificationService.requestDeviceVerification() is VerificationRequest.Outgoing.User -> sessionVerificationService.requestUserVerification(event.verificationRequest.userId) } } @@ -56,7 +56,7 @@ class OutgoingVerificationStateMachine( } inState { onEnterEffect { - sessionVerificationService.startVerification() + sessionVerificationService.startSasVerification() } } inState { diff --git a/features/verifysession/impl/src/test/kotlin/io/element/android/features/verifysession/impl/incoming/IncomingVerificationPresenterTest.kt b/features/verifysession/impl/src/test/kotlin/io/element/android/features/verifysession/impl/incoming/IncomingVerificationPresenterTest.kt index c9b9e25b74..a8d3802268 100644 --- a/features/verifysession/impl/src/test/kotlin/io/element/android/features/verifysession/impl/incoming/IncomingVerificationPresenterTest.kt +++ b/features/verifysession/impl/src/test/kotlin/io/element/android/features/verifysession/impl/incoming/IncomingVerificationPresenterTest.kt @@ -99,6 +99,7 @@ class IncomingVerificationPresenterTest { emojiState.eventSink(IncomingVerificationViewEvents.ConfirmVerification) val emojiWaitingItem = awaitItem() assertThat((emojiWaitingItem.step as IncomingVerificationState.Step.Verifying).isWaiting).isTrue() + advanceUntilIdle() approveVerificationLambda.assertions().isCalledOnce() // Remote confirm that the emojis match fakeSessionVerificationService.emitVerificationFlowState( @@ -161,6 +162,7 @@ class IncomingVerificationPresenterTest { emojiState.eventSink(IncomingVerificationViewEvents.DeclineVerification) val emojiWaitingItem = awaitItem() assertThat((emojiWaitingItem.step as IncomingVerificationState.Step.Verifying).isWaiting).isTrue() + advanceUntilIdle() declineVerificationLambda.assertions().isCalledOnce() // Remote confirm that there is a failure fakeSessionVerificationService.emitVerificationFlowState( @@ -260,6 +262,7 @@ class IncomingVerificationPresenterTest { emojiState.eventSink(IncomingVerificationViewEvents.GoBack) val emojiWaitingItem = awaitItem() assertThat((emojiWaitingItem.step as IncomingVerificationState.Step.Verifying).isWaiting).isTrue() + advanceUntilIdle() declineVerificationLambda.assertions().isCalledOnce() // Remote confirm that there is a failure fakeSessionVerificationService.emitVerificationFlowState( diff --git a/features/verifysession/impl/src/test/kotlin/io/element/android/features/verifysession/impl/outgoing/OutgoingVerificationPresenterTest.kt b/features/verifysession/impl/src/test/kotlin/io/element/android/features/verifysession/impl/outgoing/OutgoingVerificationPresenterTest.kt index f02f24c9ef..c6cbfca281 100644 --- a/features/verifysession/impl/src/test/kotlin/io/element/android/features/verifysession/impl/outgoing/OutgoingVerificationPresenterTest.kt +++ b/features/verifysession/impl/src/test/kotlin/io/element/android/features/verifysession/impl/outgoing/OutgoingVerificationPresenterTest.kt @@ -6,6 +6,8 @@ * Please see LICENSE files in the repository root for full details. */ +@file:Suppress("UnusedImports") + package io.element.android.features.verifysession.impl.outgoing import app.cash.turbine.ReceiveTurbine @@ -27,6 +29,8 @@ import io.element.android.tests.testutils.lambda.lambdaError import io.element.android.tests.testutils.lambda.lambdaRecorder import io.element.android.tests.testutils.test import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.advanceUntilIdle import kotlinx.coroutines.test.runTest import org.junit.Rule import org.junit.Test @@ -50,11 +54,11 @@ class OutgoingVerificationPresenterTest { @Test fun `present - Handles requestVerification for session verification`() = runTest { - val requestSessionVerificationRecorder = lambdaRecorder {} - val startVerificationRecorder = lambdaRecorder {} + val requestDeviceVerificationRecorder = lambdaRecorder {} + val startSasVerificationRecorder = lambdaRecorder {} val service = unverifiedSessionService( - requestSessionVerificationLambda = requestSessionVerificationRecorder, - startVerificationLambda = startVerificationRecorder, + requestDeviceVerificationLambda = requestDeviceVerificationRecorder, + startSasVerificationLambda = startSasVerificationRecorder, ) val presenter = createOutgoingVerificationPresenter( service = service, @@ -63,18 +67,18 @@ class OutgoingVerificationPresenterTest { presenter.test { requestVerificationAndAwaitVerifyingState(service) - requestSessionVerificationRecorder.assertions().isCalledOnce() - startVerificationRecorder.assertions().isCalledOnce() + requestDeviceVerificationRecorder.assertions().isCalledOnce() + startSasVerificationRecorder.assertions().isCalledOnce() } } @Test fun `present - Handles requestVerification for user verification`() = runTest { val requestUserVerificationRecorder = lambdaRecorder {} - val startVerificationRecorder = lambdaRecorder {} + val startSasVerificationRecorder = lambdaRecorder {} val service = unverifiedSessionService( requestUserVerificationLambda = requestUserVerificationRecorder, - startVerificationLambda = startVerificationRecorder, + startSasVerificationLambda = startSasVerificationRecorder, ) val presenter = createOutgoingVerificationPresenter( service = service, @@ -84,7 +88,7 @@ class OutgoingVerificationPresenterTest { requestVerificationAndAwaitVerifyingState(service) requestUserVerificationRecorder.assertions().isCalledOnce() - startVerificationRecorder.assertions().isCalledOnce() + startSasVerificationRecorder.assertions().isCalledOnce() } } @@ -106,8 +110,8 @@ class OutgoingVerificationPresenterTest { @Test fun `present - A failure when verifying cancels it`() = runTest { val service = unverifiedSessionService( - requestSessionVerificationLambda = { }, - startVerificationLambda = { }, + requestDeviceVerificationLambda = { }, + startSasVerificationLambda = { }, approveVerificationLambda = { }, ) val presenter = createOutgoingVerificationPresenter(service) @@ -125,7 +129,7 @@ class OutgoingVerificationPresenterTest { @Test fun `present - A fail when requesting verification resets the state to the canceled one`() = runTest { val service = unverifiedSessionService( - requestSessionVerificationLambda = { }, + requestDeviceVerificationLambda = { }, ) val presenter = createOutgoingVerificationPresenter(service) presenter.test { @@ -139,8 +143,8 @@ class OutgoingVerificationPresenterTest { @Test fun `present - Canceling the flow once it's verifying cancels it`() = runTest { val service = unverifiedSessionService( - requestSessionVerificationLambda = { }, - startVerificationLambda = { }, + requestDeviceVerificationLambda = { }, + startSasVerificationLambda = { }, cancelVerificationLambda = { }, ) val presenter = createOutgoingVerificationPresenter(service) @@ -154,8 +158,8 @@ class OutgoingVerificationPresenterTest { @Test fun `present - When verifying, if we receive another challenge we ignore it`() = runTest { val service = unverifiedSessionService( - requestSessionVerificationLambda = { }, - startVerificationLambda = { }, + requestDeviceVerificationLambda = { }, + startSasVerificationLambda = { }, ) val presenter = createOutgoingVerificationPresenter(service) presenter.test { @@ -168,8 +172,8 @@ class OutgoingVerificationPresenterTest { @Test fun `present - Go back after cancellation returns to initial state`() = runTest { val service = unverifiedSessionService( - requestSessionVerificationLambda = { }, - startVerificationLambda = { }, + requestDeviceVerificationLambda = { }, + startSasVerificationLambda = { }, ) val presenter = createOutgoingVerificationPresenter(service) presenter.test { @@ -189,8 +193,8 @@ class OutgoingVerificationPresenterTest { VerificationEmoji(number = 30) ) val service = unverifiedSessionService( - requestSessionVerificationLambda = { }, - startVerificationLambda = { }, + requestDeviceVerificationLambda = { }, + startSasVerificationLambda = { }, approveVerificationLambda = { }, ) val presenter = createOutgoingVerificationPresenter(service) @@ -215,8 +219,8 @@ class OutgoingVerificationPresenterTest { @Test fun `present - When verification is declined, the flow is canceled`() = runTest { val service = unverifiedSessionService( - requestSessionVerificationLambda = { }, - startVerificationLambda = { }, + requestDeviceVerificationLambda = { }, + startSasVerificationLambda = { }, declineVerificationLambda = { }, ) val presenter = createOutgoingVerificationPresenter(service) @@ -271,6 +275,7 @@ class OutgoingVerificationPresenterTest { } } + context(testScope: TestScope) private suspend fun ReceiveTurbine.requestVerificationAndAwaitVerifyingState( fakeService: FakeSessionVerificationService, sessionVerificationData: SessionVerificationData = SessionVerificationData.Emojis(emptyList()), @@ -278,6 +283,7 @@ class OutgoingVerificationPresenterTest { var state = awaitItem() assertThat(state.step).isEqualTo(Step.Initial) state.eventSink(OutgoingVerificationViewEvents.RequestVerification) + testScope.advanceUntilIdle() // Await for other device response: fakeService.emitVerificationFlowState(VerificationFlowState.DidAcceptVerificationRequest) state = awaitItem() @@ -286,6 +292,7 @@ class OutgoingVerificationPresenterTest { state = awaitItem() assertThat(state.step).isEqualTo(Step.Ready) state.eventSink(OutgoingVerificationViewEvents.StartSasVerification) + testScope.advanceUntilIdle() // Await for other device response (again): fakeService.emitVerificationFlowState(VerificationFlowState.DidStartSasVerification) state = awaitItem() @@ -297,30 +304,29 @@ class OutgoingVerificationPresenterTest { return state } - private suspend fun unverifiedSessionService( - requestSessionVerificationLambda: () -> Unit = { lambdaError() }, + private fun unverifiedSessionService( + requestDeviceVerificationLambda: () -> Unit = { lambdaError() }, requestUserVerificationLambda: (UserId) -> Unit = { lambdaError() }, cancelVerificationLambda: () -> Unit = { lambdaError() }, approveVerificationLambda: () -> Unit = { lambdaError() }, declineVerificationLambda: () -> Unit = { lambdaError() }, - startVerificationLambda: () -> Unit = { lambdaError() }, + startSasVerificationLambda: () -> Unit = { lambdaError() }, resetLambda: (Boolean) -> Unit = { }, acknowledgeVerificationRequestLambda: (VerificationRequest.Incoming) -> Unit = { lambdaError() }, acceptVerificationRequestLambda: () -> Unit = { lambdaError() }, ): FakeSessionVerificationService { return FakeSessionVerificationService( - requestCurrentSessionVerificationLambda = requestSessionVerificationLambda, + initialSessionVerifiedStatus = SessionVerifiedStatus.NotVerified, + requestDeviceVerificationLambda = requestDeviceVerificationLambda, requestUserVerificationLambda = requestUserVerificationLambda, cancelVerificationLambda = cancelVerificationLambda, approveVerificationLambda = approveVerificationLambda, declineVerificationLambda = declineVerificationLambda, - startVerificationLambda = startVerificationLambda, + startSasVerificationLambda = startSasVerificationLambda, resetLambda = resetLambda, acknowledgeVerificationRequestLambda = acknowledgeVerificationRequestLambda, acceptVerificationRequestLambda = acceptVerificationRequestLambda, - ).apply { - emitVerifiedStatus(SessionVerifiedStatus.NotVerified) - } + ) } } diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/verification/SessionVerificationService.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/verification/SessionVerificationService.kt index 4d2e786038..38a00d833d 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/verification/SessionVerificationService.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/verification/SessionVerificationService.kt @@ -33,7 +33,7 @@ interface SessionVerificationService { /** * Request verification of the current session. */ - suspend fun requestCurrentSessionVerification() + suspend fun requestDeviceVerification() /** * Request verification of the user with the given [userId]. @@ -56,9 +56,9 @@ interface SessionVerificationService { suspend fun declineVerification() /** - * Starts the verification of the unverified session from another device. + * Transition the current verification request into a SAS verification flow. */ - suspend fun startVerification() + suspend fun startSasVerification() /** * Returns the verification service state to the initial step. diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/verification/RustSessionVerificationService.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/verification/RustSessionVerificationService.kt index 7fb2935897..b2a13f5f1a 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/verification/RustSessionVerificationService.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/verification/RustSessionVerificationService.kt @@ -124,7 +124,7 @@ class RustSessionVerificationService( this.listener = listener } - override suspend fun requestCurrentSessionVerification() = tryOrFail { + override suspend fun requestDeviceVerification() = tryOrFail { ensureEncryptionIsInitialized() verificationController.requestDeviceVerification() currentVerificationRequest = VerificationRequest.Outgoing.CurrentSession @@ -146,7 +146,7 @@ class RustSessionVerificationService( override suspend fun declineVerification() = tryOrFail { verificationController.declineVerification() } - override suspend fun startVerification() = tryOrFail { + override suspend fun startSasVerification() = tryOrFail { verificationController.startSasVerification() } diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/verification/FakeSessionVerificationService.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/verification/FakeSessionVerificationService.kt index f4f12a435e..0aeeebf86d 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/verification/FakeSessionVerificationService.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/verification/FakeSessionVerificationService.kt @@ -22,12 +22,12 @@ import kotlinx.coroutines.flow.StateFlow class FakeSessionVerificationService( initialSessionVerifiedStatus: SessionVerifiedStatus = SessionVerifiedStatus.Unknown, - private val requestCurrentSessionVerificationLambda: () -> Unit = { lambdaError() }, + private val requestDeviceVerificationLambda: () -> Unit = { lambdaError() }, private val requestUserVerificationLambda: (UserId) -> Unit = { lambdaError() }, private val cancelVerificationLambda: () -> Unit = { lambdaError() }, private val approveVerificationLambda: () -> Unit = { lambdaError() }, private val declineVerificationLambda: () -> Unit = { lambdaError() }, - private val startVerificationLambda: () -> Unit = { lambdaError() }, + private val startSasVerificationLambda: () -> Unit = { lambdaError() }, private val resetLambda: (Boolean) -> Unit = { lambdaError() }, private val acknowledgeVerificationRequestLambda: (VerificationRequest.Incoming) -> Unit = { lambdaError() }, private val acceptVerificationRequestLambda: () -> Unit = { lambdaError() }, @@ -40,31 +40,31 @@ class FakeSessionVerificationService( override val sessionVerifiedStatus: StateFlow = _sessionVerifiedStatus override val needsSessionVerification: Flow = _needsSessionVerification - override suspend fun requestCurrentSessionVerification() { - requestCurrentSessionVerificationLambda() + override suspend fun requestDeviceVerification() = simulateLongTask { + requestDeviceVerificationLambda() } - override suspend fun requestUserVerification(userId: UserId) { + override suspend fun requestUserVerification(userId: UserId) = simulateLongTask { requestUserVerificationLambda(userId) } - override suspend fun cancelVerification() { + override suspend fun cancelVerification() = simulateLongTask { cancelVerificationLambda() } - override suspend fun approveVerification() { + override suspend fun approveVerification() = simulateLongTask { approveVerificationLambda() } - override suspend fun declineVerification() { + override suspend fun declineVerification() = simulateLongTask { declineVerificationLambda() } - override suspend fun startVerification() { - startVerificationLambda() + override suspend fun startSasVerification() = simulateLongTask { + startSasVerificationLambda() } - override suspend fun reset(cancelAnyPendingVerificationAttempt: Boolean) { + override suspend fun reset(cancelAnyPendingVerificationAttempt: Boolean) = simulateLongTask { resetLambda(cancelAnyPendingVerificationAttempt) } @@ -75,7 +75,7 @@ class FakeSessionVerificationService( this.listener = listener } - override suspend fun acknowledgeVerificationRequest(verificationRequest: VerificationRequest.Incoming) { + override suspend fun acknowledgeVerificationRequest(verificationRequest: VerificationRequest.Incoming) = simulateLongTask { acknowledgeVerificationRequestLambda(verificationRequest) }