Iterate on sessionVerificationService.sessionVerifiedStatus and fix tests.

This commit is contained in:
Benoit Marty 2024-06-18 11:01:36 +02:00
parent f09b77f72f
commit bc30aee359
3 changed files with 80 additions and 56 deletions

View file

@ -41,7 +41,8 @@ import io.element.android.libraries.matrix.api.verification.SessionVerifiedStatu
import io.element.android.libraries.push.api.PushService import io.element.android.libraries.push.api.PushService
import io.element.android.libraries.pushproviders.api.RegistrationFailure import io.element.android.libraries.pushproviders.api.RegistrationFailure
import io.element.android.services.analytics.api.AnalyticsService import io.element.android.services.analytics.api.AnalyticsService
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
@ -59,21 +60,24 @@ class LoggedInPresenter @Inject constructor(
@Composable @Composable
override fun present(): LoggedInState { override fun present(): LoggedInState {
val coroutineScope = rememberCoroutineScope() val coroutineScope = rememberCoroutineScope()
val isVerified by remember {
sessionVerificationService.sessionVerifiedStatus.map { it == SessionVerifiedStatus.Verified }
}.collectAsState(initial = false)
val ignoreRegistrationError by remember { val ignoreRegistrationError by remember {
pushService.ignoreRegistrationError(matrixClient.sessionId) pushService.ignoreRegistrationError(matrixClient.sessionId)
}.collectAsState(initial = false) }.collectAsState(initial = false)
val pusherRegistrationState = remember<MutableState<AsyncData<Unit>>> { mutableStateOf(AsyncData.Uninitialized) } val pusherRegistrationState = remember<MutableState<AsyncData<Unit>>> { mutableStateOf(AsyncData.Uninitialized) }
if (isVerified) { LaunchedEffect(Unit) {
LaunchedEffect(Unit) { sessionVerificationService.sessionVerifiedStatus
ensurePusherIsRegistered(pusherRegistrationState) .onEach { sessionVerifiedStatus ->
} when (sessionVerifiedStatus) {
} else { SessionVerifiedStatus.Unknown -> Unit
LaunchedEffect(Unit) { SessionVerifiedStatus.Verified -> {
pusherRegistrationState.value = AsyncData.Failure(PusherRegistrationFailure.AccountNotVerified()) ensurePusherIsRegistered(pusherRegistrationState)
} }
SessionVerifiedStatus.NotVerified -> {
pusherRegistrationState.value = AsyncData.Failure(PusherRegistrationFailure.AccountNotVerified())
}
}
}
.launchIn(this)
} }
val syncIndicator by matrixClient.roomListService.syncIndicator.collectAsState() val syncIndicator by matrixClient.roomListService.syncIndicator.collectAsState()
val networkStatus by networkMonitor.connectivity.collectAsState() val networkStatus by networkMonitor.connectivity.collectAsState()
@ -116,7 +120,7 @@ class LoggedInPresenter @Inject constructor(
Timber.tag(pusherTag.value).d("Register with the first available push provider with at least one distributor") Timber.tag(pusherTag.value).d("Register with the first available push provider with at least one distributor")
val pushProvider = pushService.getAvailablePushProviders() val pushProvider = pushService.getAvailablePushProviders()
.firstOrNull { it.getDistributors().isNotEmpty() } .firstOrNull { it.getDistributors().isNotEmpty() }
// Else fallback to the first available push provider (the list should never be empty) // Else fallback to the first available push provider (the list should never be empty)
?: pushService.getAvailablePushProviders().firstOrNull() ?: pushService.getAvailablePushProviders().firstOrNull()
?: return Unit ?: return Unit
.also { Timber.tag(pusherTag.value).w("No push providers available") } .also { Timber.tag(pusherTag.value).w("No push providers available") }

View file

@ -18,6 +18,7 @@ package io.element.android.appnav.loggedin
import app.cash.molecule.RecompositionMode import app.cash.molecule.RecompositionMode
import app.cash.molecule.moleculeFlow import app.cash.molecule.moleculeFlow
import app.cash.turbine.ReceiveTurbine
import app.cash.turbine.test import app.cash.turbine.test
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import im.vector.app.features.analytics.plan.CryptoSessionStateChange import im.vector.app.features.analytics.plan.CryptoSessionStateChange
@ -25,12 +26,14 @@ import im.vector.app.features.analytics.plan.UserProperties
import io.element.android.features.networkmonitor.api.NetworkStatus import io.element.android.features.networkmonitor.api.NetworkStatus
import io.element.android.features.networkmonitor.test.FakeNetworkMonitor import io.element.android.features.networkmonitor.test.FakeNetworkMonitor
import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.core.SessionId
import io.element.android.libraries.matrix.api.encryption.EncryptionService import io.element.android.libraries.matrix.api.encryption.EncryptionService
import io.element.android.libraries.matrix.api.encryption.RecoveryState import io.element.android.libraries.matrix.api.encryption.RecoveryState
import io.element.android.libraries.matrix.api.roomlist.RoomListService import io.element.android.libraries.matrix.api.roomlist.RoomListService
import io.element.android.libraries.matrix.api.verification.SessionVerificationService import io.element.android.libraries.matrix.api.verification.SessionVerificationService
import io.element.android.libraries.matrix.api.verification.SessionVerifiedStatus import io.element.android.libraries.matrix.api.verification.SessionVerifiedStatus
import io.element.android.libraries.matrix.test.AN_EXCEPTION import io.element.android.libraries.matrix.test.AN_EXCEPTION
import io.element.android.libraries.matrix.test.A_SESSION_ID
import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.matrix.test.FakeMatrixClient
import io.element.android.libraries.matrix.test.encryption.FakeEncryptionService import io.element.android.libraries.matrix.test.encryption.FakeEncryptionService
import io.element.android.libraries.matrix.test.roomlist.FakeRoomListService import io.element.android.libraries.matrix.test.roomlist.FakeRoomListService
@ -66,7 +69,6 @@ class LoggedInPresenterTest {
assertThat(initialState.showSyncSpinner).isFalse() assertThat(initialState.showSyncSpinner).isFalse()
assertThat(initialState.pusherRegistrationState.isUninitialized()).isTrue() assertThat(initialState.pusherRegistrationState.isUninitialized()).isTrue()
assertThat(initialState.ignoreRegistrationError).isFalse() assertThat(initialState.ignoreRegistrationError).isFalse()
skipItems(1)
} }
} }
@ -106,16 +108,12 @@ class LoggedInPresenterTest {
encryptionService.emitRecoveryState(RecoveryState.UNKNOWN) encryptionService.emitRecoveryState(RecoveryState.UNKNOWN)
encryptionService.emitRecoveryState(RecoveryState.INCOMPLETE) encryptionService.emitRecoveryState(RecoveryState.INCOMPLETE)
verificationService.emitVerifiedStatus(SessionVerifiedStatus.Verified) verificationService.emitVerifiedStatus(SessionVerifiedStatus.Verified)
skipItems(4)
skipItems(6)
assertThat(analyticsService.capturedEvents.size).isEqualTo(1) assertThat(analyticsService.capturedEvents.size).isEqualTo(1)
assertThat(analyticsService.capturedEvents[0]).isInstanceOf(CryptoSessionStateChange::class.java) assertThat(analyticsService.capturedEvents[0]).isInstanceOf(CryptoSessionStateChange::class.java)
assertThat(analyticsService.capturedUserProperties.size).isEqualTo(1) assertThat(analyticsService.capturedUserProperties.size).isEqualTo(1)
assertThat(analyticsService.capturedUserProperties[0].recoveryState).isEqualTo(UserProperties.RecoveryState.Incomplete) assertThat(analyticsService.capturedUserProperties[0].recoveryState).isEqualTo(UserProperties.RecoveryState.Incomplete)
assertThat(analyticsService.capturedUserProperties[0].verificationState).isEqualTo(UserProperties.VerificationState.Verified) assertThat(analyticsService.capturedUserProperties[0].verificationState).isEqualTo(UserProperties.VerificationState.Verified)
// ensure a sync status change does not trigger a new capture // ensure a sync status change does not trigger a new capture
roomListService.postSyncIndicator(RoomListService.SyncIndicator.Show) roomListService.postSyncIndicator(RoomListService.SyncIndicator.Show)
skipItems(1) skipItems(1)
@ -129,12 +127,17 @@ class LoggedInPresenterTest {
Result.success(Unit) Result.success(Unit)
} }
val pushService = createFakePushService(registerWithLambda = lambda) val pushService = createFakePushService(registerWithLambda = lambda)
val presenter = createLoggedInPresenter(pushService = pushService) val verificationService = FakeSessionVerificationService(
initialSessionVerifiedStatus = SessionVerifiedStatus.NotVerified
)
val presenter = createLoggedInPresenter(
pushService = pushService,
sessionVerificationService = verificationService,
)
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
presenter.present() presenter.present()
}.test { }.test {
skipItems(1) val finalState = awaitFirstItem()
val finalState = awaitItem()
assertThat(finalState.pusherRegistrationState.errorOrNull()) assertThat(finalState.pusherRegistrationState.errorOrNull())
.isInstanceOf(PusherRegistrationFailure.AccountNotVerified::class.java) .isInstanceOf(PusherRegistrationFailure.AccountNotVerified::class.java)
lambda.assertions() lambda.assertions()
@ -147,8 +150,9 @@ class LoggedInPresenterTest {
val lambda = lambdaRecorder<MatrixClient, PushProvider, Distributor, Result<Unit>> { _, _, _ -> val lambda = lambdaRecorder<MatrixClient, PushProvider, Distributor, Result<Unit>> { _, _, _ ->
Result.success(Unit) Result.success(Unit)
} }
val sessionVerificationService = FakeSessionVerificationService() val sessionVerificationService = FakeSessionVerificationService(
sessionVerificationService.givenVerifiedStatus(SessionVerifiedStatus.Verified) initialSessionVerifiedStatus = SessionVerifiedStatus.Verified
)
val pushService = createFakePushService( val pushService = createFakePushService(
registerWithLambda = lambda, registerWithLambda = lambda,
) )
@ -159,8 +163,7 @@ class LoggedInPresenterTest {
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
presenter.present() presenter.present()
}.test { }.test {
skipItems(2) val finalState = awaitFirstItem()
val finalState = awaitItem()
assertThat(finalState.pusherRegistrationState.isSuccess()).isTrue() assertThat(finalState.pusherRegistrationState.isSuccess()).isTrue()
lambda.assertions() lambda.assertions()
.isCalledOnce() .isCalledOnce()
@ -180,8 +183,9 @@ class LoggedInPresenterTest {
val lambda = lambdaRecorder<MatrixClient, PushProvider, Distributor, Result<Unit>> { _, _, _ -> val lambda = lambdaRecorder<MatrixClient, PushProvider, Distributor, Result<Unit>> { _, _, _ ->
Result.failure(AN_EXCEPTION) Result.failure(AN_EXCEPTION)
} }
val sessionVerificationService = FakeSessionVerificationService() val sessionVerificationService = FakeSessionVerificationService(
sessionVerificationService.givenVerifiedStatus(SessionVerifiedStatus.Verified) initialSessionVerifiedStatus = SessionVerifiedStatus.Verified
)
val pushService = createFakePushService( val pushService = createFakePushService(
registerWithLambda = lambda, registerWithLambda = lambda,
) )
@ -192,8 +196,7 @@ class LoggedInPresenterTest {
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
presenter.present() presenter.present()
}.test { }.test {
skipItems(2) val finalState = awaitFirstItem()
val finalState = awaitItem()
assertThat(finalState.pusherRegistrationState.isFailure()).isTrue() assertThat(finalState.pusherRegistrationState.isFailure()).isTrue()
lambda.assertions() lambda.assertions()
.isCalledOnce() .isCalledOnce()
@ -213,8 +216,9 @@ class LoggedInPresenterTest {
val lambda = lambdaRecorder<MatrixClient, PushProvider, Distributor, Result<Unit>> { _, _, _ -> val lambda = lambdaRecorder<MatrixClient, PushProvider, Distributor, Result<Unit>> { _, _, _ ->
Result.success(Unit) Result.success(Unit)
} }
val sessionVerificationService = FakeSessionVerificationService() val sessionVerificationService = FakeSessionVerificationService(
sessionVerificationService.givenVerifiedStatus(SessionVerifiedStatus.Verified) initialSessionVerifiedStatus = SessionVerifiedStatus.Verified
)
val distributor = Distributor("aDistributorValue1", "aDistributorName1") val distributor = Distributor("aDistributorValue1", "aDistributorName1")
val pushProvider = FakePushProvider( val pushProvider = FakePushProvider(
index = 0, index = 0,
@ -237,8 +241,7 @@ class LoggedInPresenterTest {
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
presenter.present() presenter.present()
}.test { }.test {
skipItems(2) val finalState = awaitFirstItem()
val finalState = awaitItem()
assertThat(finalState.pusherRegistrationState.isSuccess()).isTrue() assertThat(finalState.pusherRegistrationState.isSuccess()).isTrue()
lambda.assertions() lambda.assertions()
.isCalledOnce() .isCalledOnce()
@ -258,8 +261,9 @@ class LoggedInPresenterTest {
val lambda = lambdaRecorder<MatrixClient, PushProvider, Distributor, Result<Unit>> { _, _, _ -> val lambda = lambdaRecorder<MatrixClient, PushProvider, Distributor, Result<Unit>> { _, _, _ ->
Result.success(Unit) Result.success(Unit)
} }
val sessionVerificationService = FakeSessionVerificationService() val sessionVerificationService = FakeSessionVerificationService(
sessionVerificationService.givenVerifiedStatus(SessionVerifiedStatus.Verified) initialSessionVerifiedStatus = SessionVerifiedStatus.Verified
)
val pushProvider = FakePushProvider( val pushProvider = FakePushProvider(
index = 0, index = 0,
name = "aFakePushProvider0", name = "aFakePushProvider0",
@ -281,8 +285,7 @@ class LoggedInPresenterTest {
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
presenter.present() presenter.present()
}.test { }.test {
skipItems(2) val finalState = awaitFirstItem()
val finalState = awaitItem()
assertThat(finalState.pusherRegistrationState.isSuccess()).isTrue() assertThat(finalState.pusherRegistrationState.isSuccess()).isTrue()
lambda.assertions() lambda.assertions()
.isCalledOnce() .isCalledOnce()
@ -302,8 +305,9 @@ class LoggedInPresenterTest {
val lambda = lambdaRecorder<MatrixClient, PushProvider, Distributor, Result<Unit>> { _, _, _ -> val lambda = lambdaRecorder<MatrixClient, PushProvider, Distributor, Result<Unit>> { _, _, _ ->
Result.success(Unit) Result.success(Unit)
} }
val sessionVerificationService = FakeSessionVerificationService() val sessionVerificationService = FakeSessionVerificationService(
sessionVerificationService.givenVerifiedStatus(SessionVerifiedStatus.Verified) initialSessionVerifiedStatus = SessionVerifiedStatus.Verified
)
val pushProvider = FakePushProvider( val pushProvider = FakePushProvider(
index = 0, index = 0,
name = "aFakePushProvider0", name = "aFakePushProvider0",
@ -321,8 +325,7 @@ class LoggedInPresenterTest {
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
presenter.present() presenter.present()
}.test { }.test {
skipItems(2) val finalState = awaitFirstItem()
val finalState = awaitItem()
assertThat(finalState.pusherRegistrationState.errorOrNull()) assertThat(finalState.pusherRegistrationState.errorOrNull())
.isInstanceOf(PusherRegistrationFailure.NoDistributorsAvailable::class.java) .isInstanceOf(PusherRegistrationFailure.NoDistributorsAvailable::class.java)
lambda.assertions() lambda.assertions()
@ -335,12 +338,13 @@ class LoggedInPresenterTest {
val lambda = lambdaRecorder<MatrixClient, PushProvider, Distributor, Result<Unit>> { _, _, _ -> val lambda = lambdaRecorder<MatrixClient, PushProvider, Distributor, Result<Unit>> { _, _, _ ->
Result.success(Unit) Result.success(Unit)
} }
val sessionVerificationService = FakeSessionVerificationService() val sessionVerificationService = FakeSessionVerificationService(SessionVerifiedStatus.Verified)
sessionVerificationService.givenVerifiedStatus(SessionVerifiedStatus.Verified) val setIgnoreRegistrationErrorLambda = lambdaRecorder<SessionId, Boolean, Unit> { _, _ -> }
val pushService = createFakePushService( val pushService = createFakePushService(
pushProvider0 = null, pushProvider0 = null,
pushProvider1 = null, pushProvider1 = null,
registerWithLambda = lambda, registerWithLambda = lambda,
setIgnoreRegistrationErrorLambda = setIgnoreRegistrationErrorLambda,
) )
val presenter = createLoggedInPresenter( val presenter = createLoggedInPresenter(
pushService = pushService, pushService = pushService,
@ -349,8 +353,7 @@ class LoggedInPresenterTest {
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
presenter.present() presenter.present()
}.test { }.test {
skipItems(2) val finalState = awaitFirstItem()
val finalState = awaitItem()
assertThat(finalState.pusherRegistrationState.errorOrNull()) assertThat(finalState.pusherRegistrationState.errorOrNull())
.isInstanceOf(PusherRegistrationFailure.NoProvidersAvailable::class.java) .isInstanceOf(PusherRegistrationFailure.NoProvidersAvailable::class.java)
lambda.assertions() lambda.assertions()
@ -358,6 +361,14 @@ class LoggedInPresenterTest {
// Reset the error and do not show again // Reset the error and do not show again
finalState.eventSink(LoggedInEvents.CloseErrorDialog(doNotShowAgain = true)) finalState.eventSink(LoggedInEvents.CloseErrorDialog(doNotShowAgain = true))
skipItems(1) skipItems(1)
setIgnoreRegistrationErrorLambda.assertions()
.isCalledOnce()
.with(
// SessionId
value(A_SESSION_ID),
// Ignore
value(true),
)
val lastState = awaitItem() val lastState = awaitItem()
assertThat(lastState.pusherRegistrationState.isUninitialized()).isTrue() assertThat(lastState.pusherRegistrationState.isUninitialized()).isTrue()
assertThat(lastState.ignoreRegistrationError).isTrue() assertThat(lastState.ignoreRegistrationError).isTrue()
@ -370,8 +381,9 @@ class LoggedInPresenterTest {
Result.success(Unit) Result.success(Unit)
} }
val selectPushProviderLambda = lambdaRecorder<MatrixClient, PushProvider, Unit> { _, _ -> } val selectPushProviderLambda = lambdaRecorder<MatrixClient, PushProvider, Unit> { _, _ -> }
val sessionVerificationService = FakeSessionVerificationService() val sessionVerificationService = FakeSessionVerificationService(
sessionVerificationService.givenVerifiedStatus(SessionVerifiedStatus.Verified) initialSessionVerifiedStatus = SessionVerifiedStatus.Verified
)
val pushProvider = FakePushProvider( val pushProvider = FakePushProvider(
index = 0, index = 0,
name = "aFakePushProvider", name = "aFakePushProvider",
@ -390,8 +402,7 @@ class LoggedInPresenterTest {
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
presenter.present() presenter.present()
}.test { }.test {
skipItems(2) val finalState = awaitFirstItem()
val finalState = awaitItem()
assertThat(finalState.pusherRegistrationState.errorOrNull()) assertThat(finalState.pusherRegistrationState.errorOrNull())
.isInstanceOf(PusherRegistrationFailure.NoDistributorsAvailable::class.java) .isInstanceOf(PusherRegistrationFailure.NoDistributorsAvailable::class.java)
lambda.assertions() lambda.assertions()
@ -416,8 +427,9 @@ class LoggedInPresenterTest {
val lambda = lambdaRecorder<MatrixClient, PushProvider, Distributor, Result<Unit>> { _, _, _ -> val lambda = lambdaRecorder<MatrixClient, PushProvider, Distributor, Result<Unit>> { _, _, _ ->
Result.success(Unit) Result.success(Unit)
} }
val sessionVerificationService = FakeSessionVerificationService() val sessionVerificationService = FakeSessionVerificationService(
sessionVerificationService.givenVerifiedStatus(SessionVerifiedStatus.Verified) initialSessionVerifiedStatus = SessionVerifiedStatus.Verified
)
val pushProvider0 = FakePushProvider( val pushProvider0 = FakePushProvider(
index = 0, index = 0,
name = "aFakePushProvider0", name = "aFakePushProvider0",
@ -441,8 +453,7 @@ class LoggedInPresenterTest {
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
presenter.present() presenter.present()
}.test { }.test {
skipItems(2) val finalState = awaitFirstItem()
val finalState = awaitItem()
assertThat(finalState.pusherRegistrationState.isSuccess()).isTrue() assertThat(finalState.pusherRegistrationState.isSuccess()).isTrue()
lambda.assertions().isCalledOnce() lambda.assertions().isCalledOnce()
.with( .with(
@ -474,15 +485,22 @@ class LoggedInPresenterTest {
}, },
selectPushProviderLambda: (MatrixClient, PushProvider) -> Unit = { _, _ -> lambdaError() }, selectPushProviderLambda: (MatrixClient, PushProvider) -> Unit = { _, _ -> lambdaError() },
currentPushProvider: () -> PushProvider? = { null }, currentPushProvider: () -> PushProvider? = { null },
setIgnoreRegistrationErrorLambda: (SessionId, Boolean) -> Unit = { _, _ -> lambdaError() },
): PushService { ): PushService {
return FakePushService( return FakePushService(
availablePushProviders = listOfNotNull(pushProvider0, pushProvider1), availablePushProviders = listOfNotNull(pushProvider0, pushProvider1),
registerWithLambda = registerWithLambda, registerWithLambda = registerWithLambda,
currentPushProvider = currentPushProvider, currentPushProvider = currentPushProvider,
selectPushProviderLambda = selectPushProviderLambda, selectPushProviderLambda = selectPushProviderLambda,
setIgnoreRegistrationErrorLambda = setIgnoreRegistrationErrorLambda,
) )
} }
private suspend fun <T> ReceiveTurbine<T>.awaitFirstItem(): T {
skipItems(1)
return awaitItem()
}
private fun createLoggedInPresenter( private fun createLoggedInPresenter(
roomListService: RoomListService = FakeRoomListService(), roomListService: RoomListService = FakeRoomListService(),
networkStatus: NetworkStatus = NetworkStatus.Offline, networkStatus: NetworkStatus = NetworkStatus.Offline,

View file

@ -24,8 +24,10 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
class FakeSessionVerificationService : SessionVerificationService { class FakeSessionVerificationService(
private val _sessionVerifiedStatus = MutableStateFlow<SessionVerifiedStatus>(SessionVerifiedStatus.Unknown) initialSessionVerifiedStatus: SessionVerifiedStatus = SessionVerifiedStatus.Unknown,
) : SessionVerificationService {
private val _sessionVerifiedStatus = MutableStateFlow(initialSessionVerifiedStatus)
private var _verificationFlowState = MutableStateFlow<VerificationFlowState>(VerificationFlowState.Initial) private var _verificationFlowState = MutableStateFlow<VerificationFlowState>(VerificationFlowState.Initial)
private var _needsSessionVerification = MutableStateFlow(true) private var _needsSessionVerification = MutableStateFlow(true)
var shouldFail = false var shouldFail = false