|
|
|
@ -18,14 +18,13 @@ package io.element.android.features.verifysession.impl
@@ -18,14 +18,13 @@ package io.element.android.features.verifysession.impl
|
|
|
|
|
|
|
|
|
|
import app.cash.molecule.RecompositionClock |
|
|
|
|
import app.cash.molecule.moleculeFlow |
|
|
|
|
import app.cash.turbine.Event |
|
|
|
|
import app.cash.turbine.ReceiveTurbine |
|
|
|
|
import app.cash.turbine.test |
|
|
|
|
import com.google.common.truth.Truth.assertThat |
|
|
|
|
import io.element.android.features.verifysession.impl.VerifySelfSessionState.VerificationStep as VerificationStep |
|
|
|
|
import io.element.android.features.verifysession.impl.VerifySelfSessionState.VerificationStep |
|
|
|
|
import io.element.android.libraries.architecture.Async |
|
|
|
|
import io.element.android.libraries.matrix.api.verification.VerificationFlowState |
|
|
|
|
import io.element.android.libraries.matrix.api.verification.VerificationEmoji |
|
|
|
|
import io.element.android.libraries.matrix.api.verification.VerificationFlowState |
|
|
|
|
import io.element.android.libraries.matrix.test.verification.FakeSessionVerificationService |
|
|
|
|
import kotlinx.coroutines.ExperimentalCoroutinesApi |
|
|
|
|
import kotlinx.coroutines.test.runTest |
|
|
|
@ -36,8 +35,7 @@ class VerifySelfSessionPresenterTests {
@@ -36,8 +35,7 @@ class VerifySelfSessionPresenterTests {
|
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
fun `present - Initial state is received`() = runTest { |
|
|
|
|
val service = FakeSessionVerificationService() |
|
|
|
|
val presenter = VerifySelfSessionPresenter(service) |
|
|
|
|
val presenter = createPresenter() |
|
|
|
|
moleculeFlow(RecompositionClock.Immediate) { |
|
|
|
|
presenter.present() |
|
|
|
|
}.test { |
|
|
|
@ -48,30 +46,18 @@ class VerifySelfSessionPresenterTests {
@@ -48,30 +46,18 @@ class VerifySelfSessionPresenterTests {
|
|
|
|
|
@Test |
|
|
|
|
fun `present - Handles requestVerification`() = runTest { |
|
|
|
|
val service = FakeSessionVerificationService() |
|
|
|
|
val presenter = VerifySelfSessionPresenter(service) |
|
|
|
|
val presenter = createPresenter(service) |
|
|
|
|
moleculeFlow(RecompositionClock.Immediate) { |
|
|
|
|
presenter.present() |
|
|
|
|
}.test { |
|
|
|
|
val initialState = awaitItem() |
|
|
|
|
assertThat(initialState.verificationFlowStep).isEqualTo(VerificationStep.Initial) |
|
|
|
|
val eventSink = initialState.eventSink |
|
|
|
|
eventSink(VerifySelfSessionViewEvents.RequestVerification) |
|
|
|
|
// Await for other device response: |
|
|
|
|
assertThat(awaitItem().verificationFlowStep).isEqualTo(VerificationStep.AwaitingOtherDeviceResponse) |
|
|
|
|
// Await for the state to be Ready |
|
|
|
|
assertThat(awaitItem().verificationFlowStep).isEqualTo(VerificationStep.Ready) |
|
|
|
|
// Await for other device response (again): |
|
|
|
|
assertThat(awaitItem().verificationFlowStep).isEqualTo(VerificationStep.AwaitingOtherDeviceResponse) |
|
|
|
|
// Finally, ChallengeReceived: |
|
|
|
|
val verifyingState = awaitItem() |
|
|
|
|
assertThat(verifyingState.verificationFlowStep).isInstanceOf(VerificationStep.Verifying::class.java) |
|
|
|
|
requestVerificationAndAwaitVerifyingState(service) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
fun `present - Handles startSasVerification`() = runTest { |
|
|
|
|
val service = FakeSessionVerificationService() |
|
|
|
|
val presenter = VerifySelfSessionPresenter(service) |
|
|
|
|
val presenter = createPresenter(service) |
|
|
|
|
moleculeFlow(RecompositionClock.Immediate) { |
|
|
|
|
presenter.present() |
|
|
|
|
}.test { |
|
|
|
@ -82,6 +68,7 @@ class VerifySelfSessionPresenterTests {
@@ -82,6 +68,7 @@ class VerifySelfSessionPresenterTests {
|
|
|
|
|
// Await for other device response: |
|
|
|
|
assertThat(awaitItem().verificationFlowStep).isEqualTo(VerificationStep.AwaitingOtherDeviceResponse) |
|
|
|
|
// ChallengeReceived: |
|
|
|
|
service.triggerReceiveVerificationData() |
|
|
|
|
val verifyingState = awaitItem() |
|
|
|
|
assertThat(verifyingState.verificationFlowStep).isInstanceOf(VerificationStep.Verifying::class.java) |
|
|
|
|
} |
|
|
|
@ -89,8 +76,7 @@ class VerifySelfSessionPresenterTests {
@@ -89,8 +76,7 @@ class VerifySelfSessionPresenterTests {
|
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
fun `present - Cancelation on initial state does nothing`() = runTest { |
|
|
|
|
val service = FakeSessionVerificationService() |
|
|
|
|
val presenter = VerifySelfSessionPresenter(service) |
|
|
|
|
val presenter = createPresenter() |
|
|
|
|
moleculeFlow(RecompositionClock.Immediate) { |
|
|
|
|
presenter.present() |
|
|
|
|
}.test { |
|
|
|
@ -105,65 +91,43 @@ class VerifySelfSessionPresenterTests {
@@ -105,65 +91,43 @@ class VerifySelfSessionPresenterTests {
|
|
|
|
|
@Test |
|
|
|
|
fun `present - A fail in the flow cancels it`() = runTest { |
|
|
|
|
val service = FakeSessionVerificationService() |
|
|
|
|
val presenter = VerifySelfSessionPresenter(service) |
|
|
|
|
val presenter = createPresenter(service) |
|
|
|
|
moleculeFlow(RecompositionClock.Immediate) { |
|
|
|
|
presenter.present() |
|
|
|
|
}.test { |
|
|
|
|
val initialState = awaitItem() |
|
|
|
|
assertThat(initialState.verificationFlowStep).isEqualTo(VerificationStep.Initial) |
|
|
|
|
val eventSink = initialState.eventSink |
|
|
|
|
eventSink(VerifySelfSessionViewEvents.RequestVerification) |
|
|
|
|
|
|
|
|
|
val verifyingState = awaitChallengeReceivedState() |
|
|
|
|
assertThat(verifyingState.verificationFlowStep).isInstanceOf(VerificationStep.Verifying::class.java) |
|
|
|
|
|
|
|
|
|
val state = requestVerificationAndAwaitVerifyingState(service) |
|
|
|
|
service.shouldFail = true |
|
|
|
|
eventSink(VerifySelfSessionViewEvents.ConfirmVerification) |
|
|
|
|
|
|
|
|
|
val remainingEvents = cancelAndConsumeRemainingEvents().mapNotNull { (it as? Event.Item<VerifySelfSessionState>)?.value } |
|
|
|
|
assertThat(remainingEvents.last().verificationFlowStep).isEqualTo(VerificationStep.Canceled) |
|
|
|
|
state.eventSink(VerifySelfSessionViewEvents.ConfirmVerification) |
|
|
|
|
// Cancelling |
|
|
|
|
assertThat(awaitItem().verificationFlowStep).isInstanceOf(VerificationStep.Verifying::class.java) |
|
|
|
|
// Cancelled |
|
|
|
|
assertThat(awaitItem().verificationFlowStep).isEqualTo(VerificationStep.Canceled) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
fun `present - Canceling the flow once it's verifying cancels it`() = runTest { |
|
|
|
|
val service = FakeSessionVerificationService() |
|
|
|
|
val presenter = VerifySelfSessionPresenter(service) |
|
|
|
|
val presenter = createPresenter(service) |
|
|
|
|
moleculeFlow(RecompositionClock.Immediate) { |
|
|
|
|
presenter.present() |
|
|
|
|
}.test { |
|
|
|
|
val initialState = awaitItem() |
|
|
|
|
assertThat(initialState.verificationFlowStep).isEqualTo(VerificationStep.Initial) |
|
|
|
|
val eventSink = initialState.eventSink |
|
|
|
|
eventSink(VerifySelfSessionViewEvents.RequestVerification) |
|
|
|
|
|
|
|
|
|
val verifyingState = awaitChallengeReceivedState() |
|
|
|
|
assertThat(verifyingState.verificationFlowStep).isInstanceOf(VerificationStep.Verifying::class.java) |
|
|
|
|
|
|
|
|
|
eventSink(VerifySelfSessionViewEvents.CancelAndClose) |
|
|
|
|
|
|
|
|
|
val remainingEvents = cancelAndConsumeRemainingEvents().mapNotNull { (it as? Event.Item<VerifySelfSessionState>)?.value } |
|
|
|
|
assertThat(remainingEvents.last().verificationFlowStep).isEqualTo(VerificationStep.Canceled) |
|
|
|
|
val state = requestVerificationAndAwaitVerifyingState(service) |
|
|
|
|
state.eventSink(VerifySelfSessionViewEvents.CancelAndClose) |
|
|
|
|
assertThat(awaitItem().verificationFlowStep).isEqualTo(VerificationStep.AwaitingOtherDeviceResponse) |
|
|
|
|
assertThat(awaitItem().verificationFlowStep).isEqualTo(VerificationStep.Canceled) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
fun `present - When verifying, if we receive another challenge we ignore it`() = runTest { |
|
|
|
|
val service = FakeSessionVerificationService() |
|
|
|
|
val presenter = VerifySelfSessionPresenter(service) |
|
|
|
|
val presenter = createPresenter(service) |
|
|
|
|
moleculeFlow(RecompositionClock.Immediate) { |
|
|
|
|
presenter.present() |
|
|
|
|
}.test { |
|
|
|
|
val initialState = awaitItem() |
|
|
|
|
assertThat(initialState.verificationFlowStep).isEqualTo(VerificationStep.Initial) |
|
|
|
|
val eventSink = initialState.eventSink |
|
|
|
|
eventSink(VerifySelfSessionViewEvents.RequestVerification) |
|
|
|
|
|
|
|
|
|
val verifyingState = awaitChallengeReceivedState() |
|
|
|
|
assertThat(verifyingState.verificationFlowStep).isInstanceOf(VerificationStep.Verifying::class.java) |
|
|
|
|
|
|
|
|
|
requestVerificationAndAwaitVerifyingState(service) |
|
|
|
|
service.givenVerificationFlowState(VerificationFlowState.ReceivedVerificationData(emptyList())) |
|
|
|
|
|
|
|
|
|
ensureAllEventsConsumed() |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -171,21 +135,14 @@ class VerifySelfSessionPresenterTests {
@@ -171,21 +135,14 @@ class VerifySelfSessionPresenterTests {
|
|
|
|
|
@Test |
|
|
|
|
fun `present - Restart after cancelation returns to requesting verification`() = runTest { |
|
|
|
|
val service = FakeSessionVerificationService() |
|
|
|
|
val presenter = VerifySelfSessionPresenter(service) |
|
|
|
|
val presenter = createPresenter(service) |
|
|
|
|
moleculeFlow(RecompositionClock.Immediate) { |
|
|
|
|
presenter.present() |
|
|
|
|
}.test { |
|
|
|
|
val initialState = awaitItem() |
|
|
|
|
assertThat(initialState.verificationFlowStep).isEqualTo(VerificationStep.Initial) |
|
|
|
|
val eventSink = initialState.eventSink |
|
|
|
|
|
|
|
|
|
eventSink(VerifySelfSessionViewEvents.RequestVerification) |
|
|
|
|
assertThat(awaitChallengeReceivedState().verificationFlowStep).isEqualTo(VerificationStep.Verifying(emptyList(), Async.Uninitialized)) |
|
|
|
|
|
|
|
|
|
val state = requestVerificationAndAwaitVerifyingState(service) |
|
|
|
|
service.givenVerificationFlowState(VerificationFlowState.Canceled) |
|
|
|
|
assertThat(awaitItem().verificationFlowStep).isEqualTo(VerificationStep.Canceled) |
|
|
|
|
|
|
|
|
|
eventSink(VerifySelfSessionViewEvents.Restart) |
|
|
|
|
state.eventSink(VerifySelfSessionViewEvents.Restart) |
|
|
|
|
// Went back to requesting verification |
|
|
|
|
assertThat(awaitItem().verificationFlowStep).isEqualTo(VerificationStep.AwaitingOtherDeviceResponse) |
|
|
|
|
cancelAndIgnoreRemainingEvents() |
|
|
|
@ -200,18 +157,12 @@ class VerifySelfSessionPresenterTests {
@@ -200,18 +157,12 @@ class VerifySelfSessionPresenterTests {
|
|
|
|
|
val service = FakeSessionVerificationService().apply { |
|
|
|
|
givenEmojiList(emojis) |
|
|
|
|
} |
|
|
|
|
val presenter = VerifySelfSessionPresenter(service) |
|
|
|
|
val presenter = createPresenter(service) |
|
|
|
|
moleculeFlow(RecompositionClock.Immediate) { |
|
|
|
|
presenter.present() |
|
|
|
|
}.test { |
|
|
|
|
val initialState = awaitItem() |
|
|
|
|
assertThat(initialState.verificationFlowStep).isEqualTo(VerificationStep.Initial) |
|
|
|
|
val eventSink = initialState.eventSink |
|
|
|
|
|
|
|
|
|
eventSink(VerifySelfSessionViewEvents.RequestVerification) |
|
|
|
|
assertThat(awaitChallengeReceivedState().verificationFlowStep).isEqualTo(VerificationStep.Verifying(emojis, Async.Uninitialized)) |
|
|
|
|
|
|
|
|
|
eventSink(VerifySelfSessionViewEvents.ConfirmVerification) |
|
|
|
|
val state = requestVerificationAndAwaitVerifyingState(service) |
|
|
|
|
state.eventSink(VerifySelfSessionViewEvents.ConfirmVerification) |
|
|
|
|
assertThat(awaitItem().verificationFlowStep).isEqualTo(VerificationStep.Verifying(emojis, Async.Loading())) |
|
|
|
|
assertThat(awaitItem().verificationFlowStep).isEqualTo(VerificationStep.Completed) |
|
|
|
|
} |
|
|
|
@ -220,28 +171,41 @@ class VerifySelfSessionPresenterTests {
@@ -220,28 +171,41 @@ class VerifySelfSessionPresenterTests {
|
|
|
|
|
@Test |
|
|
|
|
fun `present - When verification is declined, the flow is canceled`() = runTest { |
|
|
|
|
val service = FakeSessionVerificationService() |
|
|
|
|
val presenter = VerifySelfSessionPresenter(service) |
|
|
|
|
val presenter = createPresenter(service) |
|
|
|
|
moleculeFlow(RecompositionClock.Immediate) { |
|
|
|
|
presenter.present() |
|
|
|
|
}.test { |
|
|
|
|
val initialState = awaitItem() |
|
|
|
|
assertThat(initialState.verificationFlowStep).isEqualTo(VerificationStep.Initial) |
|
|
|
|
val eventSink = initialState.eventSink |
|
|
|
|
|
|
|
|
|
eventSink(VerifySelfSessionViewEvents.RequestVerification) |
|
|
|
|
|
|
|
|
|
assertThat(awaitChallengeReceivedState().verificationFlowStep).isEqualTo(VerificationStep.Verifying(emptyList(), Async.Uninitialized)) |
|
|
|
|
eventSink(VerifySelfSessionViewEvents.DeclineVerification) |
|
|
|
|
|
|
|
|
|
val state = requestVerificationAndAwaitVerifyingState(service) |
|
|
|
|
state.eventSink(VerifySelfSessionViewEvents.DeclineVerification) |
|
|
|
|
assertThat(awaitItem().verificationFlowStep).isEqualTo(VerificationStep.Verifying(emptyList(), Async.Loading())) |
|
|
|
|
assertThat(awaitItem().verificationFlowStep).isEqualTo(VerificationStep.Canceled) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private suspend fun ReceiveTurbine<VerifySelfSessionState>.awaitChallengeReceivedState(): VerifySelfSessionState { |
|
|
|
|
// Skip 'waiting for response', 'ready' and 'starting verification' state |
|
|
|
|
skipItems(3) |
|
|
|
|
// Received challenge |
|
|
|
|
return awaitItem() |
|
|
|
|
private suspend fun ReceiveTurbine<VerifySelfSessionState>.requestVerificationAndAwaitVerifyingState( |
|
|
|
|
fakeService: FakeSessionVerificationService |
|
|
|
|
): VerifySelfSessionState { |
|
|
|
|
var state = awaitItem() |
|
|
|
|
assertThat(state.verificationFlowStep).isEqualTo(VerificationStep.Initial) |
|
|
|
|
state.eventSink(VerifySelfSessionViewEvents.RequestVerification) |
|
|
|
|
// Await for other device response: |
|
|
|
|
state = awaitItem() |
|
|
|
|
assertThat(state.verificationFlowStep).isEqualTo(VerificationStep.AwaitingOtherDeviceResponse) |
|
|
|
|
// Await for the state to be Ready |
|
|
|
|
state = awaitItem() |
|
|
|
|
assertThat(state.verificationFlowStep).isEqualTo(VerificationStep.Ready) |
|
|
|
|
state.eventSink(VerifySelfSessionViewEvents.StartSasVerification) |
|
|
|
|
// Await for other device response (again): |
|
|
|
|
state = awaitItem() |
|
|
|
|
assertThat(state.verificationFlowStep).isEqualTo(VerificationStep.AwaitingOtherDeviceResponse) |
|
|
|
|
fakeService.triggerReceiveVerificationData() |
|
|
|
|
// Finally, ChallengeReceived: |
|
|
|
|
state = awaitItem() |
|
|
|
|
assertThat(state.verificationFlowStep).isInstanceOf(VerificationStep.Verifying::class.java) |
|
|
|
|
return state |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private fun createPresenter(service: FakeSessionVerificationService = FakeSessionVerificationService()): VerifySelfSessionPresenter { |
|
|
|
|
return VerifySelfSessionPresenter(service, VerifySelfSessionStateMachine(service)) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|