Moving UI auth interceptor into use case

This commit is contained in:
Maxime NATUREL 2022-11-07 16:52:41 +01:00
parent 45050e8216
commit 6d2620815c
16 changed files with 132 additions and 363 deletions

View file

@ -27,20 +27,16 @@ import im.vector.app.core.di.hiltMavericksViewModelFactory
import im.vector.app.features.auth.PendingAuthHandler import im.vector.app.features.auth.PendingAuthHandler
import im.vector.app.features.settings.devices.v2.filter.DeviceManagerFilterType import im.vector.app.features.settings.devices.v2.filter.DeviceManagerFilterType
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.SignoutSessionsReAuthNeeded
import im.vector.app.features.settings.devices.v2.signout.SignoutSessionsUseCase import im.vector.app.features.settings.devices.v2.signout.SignoutSessionsUseCase
import im.vector.app.features.settings.devices.v2.verification.CheckIfCurrentSessionCanBeVerifiedUseCase import im.vector.app.features.settings.devices.v2.verification.CheckIfCurrentSessionCanBeVerifiedUseCase
import im.vector.app.features.settings.devices.v2.verification.GetCurrentSessionCrossSigningInfoUseCase import im.vector.app.features.settings.devices.v2.verification.GetCurrentSessionCrossSigningInfoUseCase
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
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.extensions.orFalse import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.session.uia.DefaultBaseAuth import org.matrix.android.sdk.api.session.uia.DefaultBaseAuth
import timber.log.Timber import timber.log.Timber
import kotlin.coroutines.Continuation
class DevicesViewModel @AssistedInject constructor( class DevicesViewModel @AssistedInject constructor(
@Assisted initialState: DevicesViewState, @Assisted initialState: DevicesViewState,
@ -141,16 +137,14 @@ class DevicesViewModel @AssistedInject constructor(
if (deviceIds.isEmpty()) { if (deviceIds.isEmpty()) {
return@launch return@launch
} }
val signoutResult = signout(deviceIds) val result = signout(deviceIds)
setLoading(false) setLoading(false)
if (signoutResult.isSuccess) { val error = result.exceptionOrNull()
if (error == null) {
onSignoutSuccess() onSignoutSuccess()
} else { } else {
when (val failure = signoutResult.exceptionOrNull()) { onSignoutFailure(error)
null -> onSignoutSuccess()
else -> onSignoutFailure(failure)
}
} }
} }
} }
@ -162,16 +156,9 @@ class DevicesViewModel @AssistedInject constructor(
.orEmpty() .orEmpty()
} }
private suspend fun signout(deviceIds: List<String>) = signoutSessionsUseCase.execute(deviceIds, object : UserInteractiveAuthInterceptor { private suspend fun signout(deviceIds: List<String>) = signoutSessionsUseCase.execute(deviceIds, this::onReAuthNeeded)
override fun performStage(flowResponse: RegistrationFlowResponse, errCode: String?, promise: Continuation<UIABaseAuth>) {
when (val result = interceptSignoutFlowResponseUseCase.execute(flowResponse, errCode, promise)) {
is SignoutSessionResult.ReAuthNeeded -> onReAuthNeeded(result)
is SignoutSessionResult.Completed -> Unit
}
}
})
private fun onReAuthNeeded(reAuthNeeded: SignoutSessionResult.ReAuthNeeded) { private fun onReAuthNeeded(reAuthNeeded: SignoutSessionsReAuthNeeded) {
Timber.d("onReAuthNeeded") Timber.d("onReAuthNeeded")
pendingAuthHandler.pendingAuth = DefaultBaseAuth(session = reAuthNeeded.flowResponse.session) pendingAuthHandler.pendingAuth = DefaultBaseAuth(session = reAuthNeeded.flowResponse.session)
pendingAuthHandler.uiaContinuation = reAuthNeeded.uiaContinuation pendingAuthHandler.uiaContinuation = reAuthNeeded.uiaContinuation

View file

@ -29,24 +29,18 @@ import im.vector.app.features.settings.devices.v2.GetDeviceFullInfoListUseCase
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.VectorSessionsListViewModel import im.vector.app.features.settings.devices.v2.VectorSessionsListViewModel
import im.vector.app.features.settings.devices.v2.filter.DeviceManagerFilterType import im.vector.app.features.settings.devices.v2.filter.DeviceManagerFilterType
import im.vector.app.features.settings.devices.v2.signout.InterceptSignoutFlowResponseUseCase import im.vector.app.features.settings.devices.v2.signout.SignoutSessionsReAuthNeeded
import im.vector.app.features.settings.devices.v2.signout.SignoutSessionResult
import im.vector.app.features.settings.devices.v2.signout.SignoutSessionsUseCase import im.vector.app.features.settings.devices.v2.signout.SignoutSessionsUseCase
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
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.uia.DefaultBaseAuth import org.matrix.android.sdk.api.session.uia.DefaultBaseAuth
import timber.log.Timber import timber.log.Timber
import kotlin.coroutines.Continuation
class OtherSessionsViewModel @AssistedInject constructor( class OtherSessionsViewModel @AssistedInject constructor(
@Assisted private val initialState: OtherSessionsViewState, @Assisted private val initialState: OtherSessionsViewState,
activeSessionHolder: ActiveSessionHolder, activeSessionHolder: ActiveSessionHolder,
private val getDeviceFullInfoListUseCase: GetDeviceFullInfoListUseCase, private val getDeviceFullInfoListUseCase: GetDeviceFullInfoListUseCase,
private val signoutSessionsUseCase: SignoutSessionsUseCase, private val signoutSessionsUseCase: SignoutSessionsUseCase,
private val interceptSignoutFlowResponseUseCase: InterceptSignoutFlowResponseUseCase,
private val pendingAuthHandler: PendingAuthHandler, private val pendingAuthHandler: PendingAuthHandler,
refreshDevicesUseCase: RefreshDevicesUseCase refreshDevicesUseCase: RefreshDevicesUseCase
) : VectorSessionsListViewModel<OtherSessionsViewState, OtherSessionsAction, OtherSessionsViewEvents>( ) : VectorSessionsListViewModel<OtherSessionsViewState, OtherSessionsAction, OtherSessionsViewEvents>(
@ -168,16 +162,14 @@ class OtherSessionsViewModel @AssistedInject constructor(
if (deviceIds.isEmpty()) { if (deviceIds.isEmpty()) {
return@launch return@launch
} }
val signoutResult = signout(deviceIds) val result = signout(deviceIds)
setLoading(false) setLoading(false)
if (signoutResult.isSuccess) { val error = result.exceptionOrNull()
if (error == null) {
onSignoutSuccess() onSignoutSuccess()
} else { } else {
when (val failure = signoutResult.exceptionOrNull()) { onSignoutFailure(error)
null -> onSignoutSuccess()
else -> onSignoutFailure(failure)
}
} }
} }
} }
@ -190,16 +182,9 @@ class OtherSessionsViewModel @AssistedInject constructor(
}.mapNotNull { it.deviceInfo.deviceId } }.mapNotNull { it.deviceInfo.deviceId }
} }
private suspend fun signout(deviceIds: List<String>) = signoutSessionsUseCase.execute(deviceIds, object : UserInteractiveAuthInterceptor { private suspend fun signout(deviceIds: List<String>) = signoutSessionsUseCase.execute(deviceIds, this::onReAuthNeeded)
override fun performStage(flowResponse: RegistrationFlowResponse, errCode: String?, promise: Continuation<UIABaseAuth>) {
when (val result = interceptSignoutFlowResponseUseCase.execute(flowResponse, errCode, promise)) {
is SignoutSessionResult.ReAuthNeeded -> onReAuthNeeded(result)
is SignoutSessionResult.Completed -> Unit
}
}
})
private fun onReAuthNeeded(reAuthNeeded: SignoutSessionResult.ReAuthNeeded) { private fun onReAuthNeeded(reAuthNeeded: SignoutSessionsReAuthNeeded) {
Timber.d("onReAuthNeeded") Timber.d("onReAuthNeeded")
pendingAuthHandler.pendingAuth = DefaultBaseAuth(session = reAuthNeeded.flowResponse.session) pendingAuthHandler.pendingAuth = DefaultBaseAuth(session = reAuthNeeded.flowResponse.session)
pendingAuthHandler.uiaContinuation = reAuthNeeded.uiaContinuation pendingAuthHandler.uiaContinuation = reAuthNeeded.uiaContinuation

View file

@ -30,28 +30,24 @@ import im.vector.app.features.settings.devices.v2.VectorSessionsListViewModel
import im.vector.app.features.settings.devices.v2.notification.GetNotificationsStatusUseCase import im.vector.app.features.settings.devices.v2.notification.GetNotificationsStatusUseCase
import im.vector.app.features.settings.devices.v2.notification.TogglePushNotificationUseCase import im.vector.app.features.settings.devices.v2.notification.TogglePushNotificationUseCase
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.SignoutSessionsReAuthNeeded
import im.vector.app.features.settings.devices.v2.signout.SignoutSessionUseCase import im.vector.app.features.settings.devices.v2.signout.SignoutSessionsUseCase
import im.vector.app.features.settings.devices.v2.verification.CheckIfCurrentSessionCanBeVerifiedUseCase import im.vector.app.features.settings.devices.v2.verification.CheckIfCurrentSessionCanBeVerifiedUseCase
import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
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.extensions.orFalse import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel
import org.matrix.android.sdk.api.session.uia.DefaultBaseAuth import org.matrix.android.sdk.api.session.uia.DefaultBaseAuth
import timber.log.Timber import timber.log.Timber
import kotlin.coroutines.Continuation
class SessionOverviewViewModel @AssistedInject constructor( class SessionOverviewViewModel @AssistedInject constructor(
@Assisted val initialState: SessionOverviewViewState, @Assisted val initialState: SessionOverviewViewState,
private val getDeviceFullInfoUseCase: GetDeviceFullInfoUseCase, private val getDeviceFullInfoUseCase: GetDeviceFullInfoUseCase,
private val checkIfCurrentSessionCanBeVerifiedUseCase: CheckIfCurrentSessionCanBeVerifiedUseCase, private val checkIfCurrentSessionCanBeVerifiedUseCase: CheckIfCurrentSessionCanBeVerifiedUseCase,
private val signoutSessionUseCase: SignoutSessionUseCase, private val signoutSessionsUseCase: SignoutSessionsUseCase,
private val interceptSignoutFlowResponseUseCase: InterceptSignoutFlowResponseUseCase, private val interceptSignoutFlowResponseUseCase: InterceptSignoutFlowResponseUseCase,
private val pendingAuthHandler: PendingAuthHandler, private val pendingAuthHandler: PendingAuthHandler,
private val activeSessionHolder: ActiveSessionHolder, private val activeSessionHolder: ActiveSessionHolder,
@ -149,30 +145,21 @@ class SessionOverviewViewModel @AssistedInject constructor(
private fun handleSignoutOtherSession(deviceId: String) { private fun handleSignoutOtherSession(deviceId: String) {
viewModelScope.launch { viewModelScope.launch {
setLoading(true) setLoading(true)
val signoutResult = signout(deviceId) val result = signout(deviceId)
setLoading(false) setLoading(false)
if (signoutResult.isSuccess) { val error = result.exceptionOrNull()
if (error == null) {
onSignoutSuccess() onSignoutSuccess()
} else { } else {
when (val failure = signoutResult.exceptionOrNull()) { onSignoutFailure(error)
null -> onSignoutSuccess()
else -> onSignoutFailure(failure)
}
} }
} }
} }
private suspend fun signout(deviceId: String) = signoutSessionUseCase.execute(deviceId, object : UserInteractiveAuthInterceptor { private suspend fun signout(deviceId: String) = signoutSessionsUseCase.execute(listOf(deviceId), this::onReAuthNeeded)
override fun performStage(flowResponse: RegistrationFlowResponse, errCode: String?, promise: Continuation<UIABaseAuth>) {
when (val result = interceptSignoutFlowResponseUseCase.execute(flowResponse, errCode, promise)) {
is SignoutSessionResult.ReAuthNeeded -> onReAuthNeeded(result)
is SignoutSessionResult.Completed -> Unit
}
}
})
private fun onReAuthNeeded(reAuthNeeded: SignoutSessionResult.ReAuthNeeded) { private fun onReAuthNeeded(reAuthNeeded: SignoutSessionsReAuthNeeded) {
Timber.d("onReAuthNeeded") Timber.d("onReAuthNeeded")
pendingAuthHandler.pendingAuth = DefaultBaseAuth(session = reAuthNeeded.flowResponse.session) pendingAuthHandler.pendingAuth = DefaultBaseAuth(session = reAuthNeeded.flowResponse.session)
pendingAuthHandler.uiaContinuation = reAuthNeeded.uiaContinuation pendingAuthHandler.uiaContinuation = reAuthNeeded.uiaContinuation

View file

@ -37,17 +37,16 @@ class InterceptSignoutFlowResponseUseCase @Inject constructor(
flowResponse: RegistrationFlowResponse, flowResponse: RegistrationFlowResponse,
errCode: String?, errCode: String?,
promise: Continuation<UIABaseAuth> promise: Continuation<UIABaseAuth>
): SignoutSessionResult { ): SignoutSessionsReAuthNeeded? {
return if (flowResponse.nextUncompletedStage() == LoginFlowTypes.PASSWORD && reAuthHelper.data != null && errCode == null) { return if (flowResponse.nextUncompletedStage() == LoginFlowTypes.PASSWORD && reAuthHelper.data != null && errCode == null) {
UserPasswordAuth( UserPasswordAuth(
session = null, session = null,
user = activeSessionHolder.getActiveSession().myUserId, user = activeSessionHolder.getActiveSession().myUserId,
password = reAuthHelper.data password = reAuthHelper.data
).let { promise.resume(it) } ).let { promise.resume(it) }
null
SignoutSessionResult.Completed
} else { } else {
SignoutSessionResult.ReAuthNeeded( SignoutSessionsReAuthNeeded(
pendingAuth = DefaultBaseAuth(session = flowResponse.session), pendingAuth = DefaultBaseAuth(session = flowResponse.session),
uiaContinuation = promise, uiaContinuation = promise,
flowResponse = flowResponse, flowResponse = flowResponse,

View file

@ -1,42 +0,0 @@
/*
* Copyright (c) 2022 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.app.features.settings.devices.v2.signout
import im.vector.app.core.di.ActiveSessionHolder
import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor
import org.matrix.android.sdk.api.util.awaitCallback
import javax.inject.Inject
/**
* Use case to signout a single session.
*/
class SignoutSessionUseCase @Inject constructor(
private val activeSessionHolder: ActiveSessionHolder,
) {
suspend fun execute(deviceId: String, userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor): Result<Unit> {
return deleteDevice(deviceId, userInteractiveAuthInterceptor)
}
private suspend fun deleteDevice(deviceId: String, userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor) = runCatching {
awaitCallback { matrixCallback ->
activeSessionHolder.getActiveSession()
.cryptoService()
.deleteDevice(deviceId, userInteractiveAuthInterceptor, matrixCallback)
}
}
}

View file

@ -20,13 +20,9 @@ import org.matrix.android.sdk.api.auth.UIABaseAuth
import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse
import kotlin.coroutines.Continuation import kotlin.coroutines.Continuation
sealed class SignoutSessionResult { data class SignoutSessionsReAuthNeeded(
data class ReAuthNeeded( val pendingAuth: UIABaseAuth,
val pendingAuth: UIABaseAuth, val uiaContinuation: Continuation<UIABaseAuth>,
val uiaContinuation: Continuation<UIABaseAuth>, val flowResponse: RegistrationFlowResponse,
val flowResponse: RegistrationFlowResponse, val errCode: String?
val errCode: String? )
) : SignoutSessionResult()
object Completed : SignoutSessionResult()
}

View file

@ -16,27 +16,42 @@
package im.vector.app.features.settings.devices.v2.signout package im.vector.app.features.settings.devices.v2.signout
import androidx.annotation.Size
import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.di.ActiveSessionHolder
import org.matrix.android.sdk.api.auth.UIABaseAuth
import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor
import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse
import org.matrix.android.sdk.api.util.awaitCallback import org.matrix.android.sdk.api.util.awaitCallback
import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
import kotlin.coroutines.Continuation
/**
* Use case to signout several sessions.
*/
class SignoutSessionsUseCase @Inject constructor( class SignoutSessionsUseCase @Inject constructor(
private val activeSessionHolder: ActiveSessionHolder, private val activeSessionHolder: ActiveSessionHolder,
private val interceptSignoutFlowResponseUseCase: InterceptSignoutFlowResponseUseCase,
) { ) {
suspend fun execute(deviceIds: List<String>, userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor): Result<Unit> { suspend fun execute(
return deleteDevices(deviceIds, userInteractiveAuthInterceptor) @Size(min = 1) deviceIds: List<String>,
onReAuthNeeded: (SignoutSessionsReAuthNeeded) -> Unit,
): Result<Unit> = runCatching {
Timber.d("start execute with ${deviceIds.size} deviceIds")
val authInterceptor = object : UserInteractiveAuthInterceptor {
override fun performStage(flowResponse: RegistrationFlowResponse, errCode: String?, promise: Continuation<UIABaseAuth>) {
val result = interceptSignoutFlowResponseUseCase.execute(flowResponse, errCode, promise)
result?.let(onReAuthNeeded)
}
}
deleteDevices(deviceIds, authInterceptor)
Timber.d("end execute")
} }
private suspend fun deleteDevices(deviceIds: List<String>, userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor) = runCatching { private suspend fun deleteDevices(deviceIds: List<String>, userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor) =
awaitCallback { matrixCallback -> awaitCallback { matrixCallback ->
activeSessionHolder.getActiveSession() activeSessionHolder.getActiveSession()
.cryptoService() .cryptoService()
.deleteDevices(deviceIds, userInteractiveAuthInterceptor, matrixCallback) .deleteDevices(deviceIds, userInteractiveAuthInterceptor, matrixCallback)
} }
}
} }

View file

@ -228,7 +228,7 @@ class DevicesViewModelTest {
// Given // Given
val expectedViewState = givenInitialViewState(deviceId1 = A_DEVICE_ID_1, deviceId2 = A_CURRENT_DEVICE_ID) val expectedViewState = givenInitialViewState(deviceId1 = A_DEVICE_ID_1, deviceId2 = A_CURRENT_DEVICE_ID)
// signout all devices except the current device // signout all devices except the current device
fakeSignoutSessionsUseCase.givenSignoutSuccess(listOf(A_DEVICE_ID_1), fakeInterceptSignoutFlowResponseUseCase) fakeSignoutSessionsUseCase.givenSignoutSuccess(listOf(A_DEVICE_ID_1))
// When // When
val viewModel = createViewModel() val viewModel = createViewModel()
@ -275,7 +275,7 @@ class DevicesViewModelTest {
@Test @Test
fun `given reAuth is needed during multiSignout when handling multiSignout action then requestReAuth is sent and pending auth is stored`() { fun `given reAuth is needed during multiSignout when handling multiSignout action then requestReAuth is sent and pending auth is stored`() {
// Given // Given
val reAuthNeeded = fakeSignoutSessionsUseCase.givenSignoutReAuthNeeded(listOf(A_DEVICE_ID_1, A_DEVICE_ID_2), fakeInterceptSignoutFlowResponseUseCase) val reAuthNeeded = fakeSignoutSessionsUseCase.givenSignoutReAuthNeeded(listOf(A_DEVICE_ID_1, A_DEVICE_ID_2))
val expectedPendingAuth = DefaultBaseAuth(session = reAuthNeeded.flowResponse.session) val expectedPendingAuth = DefaultBaseAuth(session = reAuthNeeded.flowResponse.session)
val expectedReAuthEvent = DevicesViewEvent.RequestReAuth(reAuthNeeded.flowResponse, reAuthNeeded.errCode) val expectedReAuthEvent = DevicesViewEvent.RequestReAuth(reAuthNeeded.flowResponse, reAuthNeeded.errCode)

View file

@ -23,7 +23,6 @@ import im.vector.app.features.settings.devices.v2.DeviceFullInfo
import im.vector.app.features.settings.devices.v2.GetDeviceFullInfoListUseCase import im.vector.app.features.settings.devices.v2.GetDeviceFullInfoListUseCase
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.filter.DeviceManagerFilterType import im.vector.app.features.settings.devices.v2.filter.DeviceManagerFilterType
import im.vector.app.features.settings.devices.v2.signout.InterceptSignoutFlowResponseUseCase
import im.vector.app.test.fakes.FakeActiveSessionHolder import im.vector.app.test.fakes.FakeActiveSessionHolder
import im.vector.app.test.fakes.FakePendingAuthHandler import im.vector.app.test.fakes.FakePendingAuthHandler
import im.vector.app.test.fakes.FakeSignoutSessionsUseCase import im.vector.app.test.fakes.FakeSignoutSessionsUseCase
@ -66,7 +65,6 @@ class OtherSessionsViewModelTest {
private val fakeGetDeviceFullInfoListUseCase = mockk<GetDeviceFullInfoListUseCase>() private val fakeGetDeviceFullInfoListUseCase = mockk<GetDeviceFullInfoListUseCase>()
private val fakeRefreshDevicesUseCase = mockk<RefreshDevicesUseCase>(relaxed = true) private val fakeRefreshDevicesUseCase = mockk<RefreshDevicesUseCase>(relaxed = true)
private val fakeSignoutSessionsUseCase = FakeSignoutSessionsUseCase() private val fakeSignoutSessionsUseCase = FakeSignoutSessionsUseCase()
private val fakeInterceptSignoutFlowResponseUseCase = mockk<InterceptSignoutFlowResponseUseCase>()
private val fakePendingAuthHandler = FakePendingAuthHandler() private val fakePendingAuthHandler = FakePendingAuthHandler()
private fun createViewModel(viewState: OtherSessionsViewState = OtherSessionsViewState(defaultArgs)) = private fun createViewModel(viewState: OtherSessionsViewState = OtherSessionsViewState(defaultArgs)) =
@ -75,7 +73,6 @@ class OtherSessionsViewModelTest {
activeSessionHolder = fakeActiveSessionHolder.instance, activeSessionHolder = fakeActiveSessionHolder.instance,
getDeviceFullInfoListUseCase = fakeGetDeviceFullInfoListUseCase, getDeviceFullInfoListUseCase = fakeGetDeviceFullInfoListUseCase,
signoutSessionsUseCase = fakeSignoutSessionsUseCase.instance, signoutSessionsUseCase = fakeSignoutSessionsUseCase.instance,
interceptSignoutFlowResponseUseCase = fakeInterceptSignoutFlowResponseUseCase,
pendingAuthHandler = fakePendingAuthHandler.instance, pendingAuthHandler = fakePendingAuthHandler.instance,
refreshDevicesUseCase = fakeRefreshDevicesUseCase, refreshDevicesUseCase = fakeRefreshDevicesUseCase,
) )
@ -321,7 +318,7 @@ class OtherSessionsViewModelTest {
val devices: List<DeviceFullInfo> = listOf(deviceFullInfo1, deviceFullInfo2) val devices: List<DeviceFullInfo> = listOf(deviceFullInfo1, deviceFullInfo2)
givenGetDeviceFullInfoListReturns(filterType = defaultArgs.defaultFilter, devices) givenGetDeviceFullInfoListReturns(filterType = defaultArgs.defaultFilter, devices)
// signout only selected devices // signout only selected devices
fakeSignoutSessionsUseCase.givenSignoutSuccess(listOf(A_DEVICE_ID_2), fakeInterceptSignoutFlowResponseUseCase) fakeSignoutSessionsUseCase.givenSignoutSuccess(listOf(A_DEVICE_ID_2))
val expectedViewState = OtherSessionsViewState( val expectedViewState = OtherSessionsViewState(
devices = Success(listOf(deviceFullInfo1, deviceFullInfo2)), devices = Success(listOf(deviceFullInfo1, deviceFullInfo2)),
currentFilter = defaultArgs.defaultFilter, currentFilter = defaultArgs.defaultFilter,
@ -357,7 +354,7 @@ class OtherSessionsViewModelTest {
val devices: List<DeviceFullInfo> = listOf(deviceFullInfo1, deviceFullInfo2) val devices: List<DeviceFullInfo> = listOf(deviceFullInfo1, deviceFullInfo2)
givenGetDeviceFullInfoListReturns(filterType = defaultArgs.defaultFilter, devices) givenGetDeviceFullInfoListReturns(filterType = defaultArgs.defaultFilter, devices)
// signout all devices // signout all devices
fakeSignoutSessionsUseCase.givenSignoutSuccess(listOf(A_DEVICE_ID_1, A_DEVICE_ID_2), fakeInterceptSignoutFlowResponseUseCase) fakeSignoutSessionsUseCase.givenSignoutSuccess(listOf(A_DEVICE_ID_1, A_DEVICE_ID_2))
val expectedViewState = OtherSessionsViewState( val expectedViewState = OtherSessionsViewState(
devices = Success(listOf(deviceFullInfo1, deviceFullInfo2)), devices = Success(listOf(deviceFullInfo1, deviceFullInfo2)),
currentFilter = defaultArgs.defaultFilter, currentFilter = defaultArgs.defaultFilter,
@ -422,7 +419,7 @@ class OtherSessionsViewModelTest {
val deviceFullInfo2 = aDeviceFullInfo(A_DEVICE_ID_2, isSelected = true) val deviceFullInfo2 = aDeviceFullInfo(A_DEVICE_ID_2, isSelected = true)
val devices: List<DeviceFullInfo> = listOf(deviceFullInfo1, deviceFullInfo2) val devices: List<DeviceFullInfo> = listOf(deviceFullInfo1, deviceFullInfo2)
givenGetDeviceFullInfoListReturns(filterType = defaultArgs.defaultFilter, devices) givenGetDeviceFullInfoListReturns(filterType = defaultArgs.defaultFilter, devices)
val reAuthNeeded = fakeSignoutSessionsUseCase.givenSignoutReAuthNeeded(listOf(A_DEVICE_ID_1, A_DEVICE_ID_2), fakeInterceptSignoutFlowResponseUseCase) val reAuthNeeded = fakeSignoutSessionsUseCase.givenSignoutReAuthNeeded(listOf(A_DEVICE_ID_1, A_DEVICE_ID_2))
val expectedPendingAuth = DefaultBaseAuth(session = reAuthNeeded.flowResponse.session) val expectedPendingAuth = DefaultBaseAuth(session = reAuthNeeded.flowResponse.session)
val expectedReAuthEvent = OtherSessionsViewEvents.RequestReAuth(reAuthNeeded.flowResponse, reAuthNeeded.errCode) val expectedReAuthEvent = OtherSessionsViewEvents.RequestReAuth(reAuthNeeded.flowResponse, reAuthNeeded.errCode)

View file

@ -28,7 +28,7 @@ import im.vector.app.features.settings.devices.v2.signout.InterceptSignoutFlowRe
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
import im.vector.app.test.fakes.FakePendingAuthHandler import im.vector.app.test.fakes.FakePendingAuthHandler
import im.vector.app.test.fakes.FakeSignoutSessionUseCase import im.vector.app.test.fakes.FakeSignoutSessionsUseCase
import im.vector.app.test.fakes.FakeTogglePushNotificationUseCase import im.vector.app.test.fakes.FakeTogglePushNotificationUseCase
import im.vector.app.test.fakes.FakeVerificationService import im.vector.app.test.fakes.FakeVerificationService
import im.vector.app.test.test import im.vector.app.test.test
@ -70,7 +70,7 @@ class SessionOverviewViewModelTest {
private val getDeviceFullInfoUseCase = mockk<GetDeviceFullInfoUseCase>(relaxed = true) private val getDeviceFullInfoUseCase = mockk<GetDeviceFullInfoUseCase>(relaxed = true)
private val fakeActiveSessionHolder = FakeActiveSessionHolder() private val fakeActiveSessionHolder = FakeActiveSessionHolder()
private val checkIfCurrentSessionCanBeVerifiedUseCase = mockk<CheckIfCurrentSessionCanBeVerifiedUseCase>() private val checkIfCurrentSessionCanBeVerifiedUseCase = mockk<CheckIfCurrentSessionCanBeVerifiedUseCase>()
private val fakeSignoutSessionUseCase = FakeSignoutSessionUseCase() private val fakeSignoutSessionsUseCase = FakeSignoutSessionsUseCase()
private val interceptSignoutFlowResponseUseCase = mockk<InterceptSignoutFlowResponseUseCase>() private val interceptSignoutFlowResponseUseCase = mockk<InterceptSignoutFlowResponseUseCase>()
private val fakePendingAuthHandler = FakePendingAuthHandler() private val fakePendingAuthHandler = FakePendingAuthHandler()
private val refreshDevicesUseCase = mockk<RefreshDevicesUseCase>(relaxed = true) private val refreshDevicesUseCase = mockk<RefreshDevicesUseCase>(relaxed = true)
@ -82,7 +82,7 @@ class SessionOverviewViewModelTest {
initialState = SessionOverviewViewState(args), initialState = SessionOverviewViewState(args),
getDeviceFullInfoUseCase = getDeviceFullInfoUseCase, getDeviceFullInfoUseCase = getDeviceFullInfoUseCase,
checkIfCurrentSessionCanBeVerifiedUseCase = checkIfCurrentSessionCanBeVerifiedUseCase, checkIfCurrentSessionCanBeVerifiedUseCase = checkIfCurrentSessionCanBeVerifiedUseCase,
signoutSessionUseCase = fakeSignoutSessionUseCase.instance, signoutSessionsUseCase = fakeSignoutSessionsUseCase.instance,
interceptSignoutFlowResponseUseCase = interceptSignoutFlowResponseUseCase, interceptSignoutFlowResponseUseCase = interceptSignoutFlowResponseUseCase,
pendingAuthHandler = fakePendingAuthHandler.instance, pendingAuthHandler = fakePendingAuthHandler.instance,
activeSessionHolder = fakeActiveSessionHolder.instance, activeSessionHolder = fakeActiveSessionHolder.instance,
@ -248,7 +248,7 @@ class SessionOverviewViewModelTest {
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)
fakeSignoutSessionUseCase.givenSignoutSuccess(A_SESSION_ID_1, interceptSignoutFlowResponseUseCase) fakeSignoutSessionsUseCase.givenSignoutSuccess(listOf(A_SESSION_ID_1))
val signoutAction = SessionOverviewAction.SignoutOtherSession val signoutAction = SessionOverviewAction.SignoutOtherSession
givenCurrentSessionIsTrusted() givenCurrentSessionIsTrusted()
val expectedViewState = SessionOverviewViewState( val expectedViewState = SessionOverviewViewState(
@ -285,7 +285,7 @@ class SessionOverviewViewModelTest {
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)
val error = Exception() val error = Exception()
fakeSignoutSessionUseCase.givenSignoutError(A_SESSION_ID_1, error) fakeSignoutSessionsUseCase.givenSignoutError(listOf(A_SESSION_ID_1), error)
val signoutAction = SessionOverviewAction.SignoutOtherSession val signoutAction = SessionOverviewAction.SignoutOtherSession
givenCurrentSessionIsTrusted() givenCurrentSessionIsTrusted()
val expectedViewState = SessionOverviewViewState( val expectedViewState = SessionOverviewViewState(
@ -318,7 +318,7 @@ class SessionOverviewViewModelTest {
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)
val reAuthNeeded = fakeSignoutSessionUseCase.givenSignoutReAuthNeeded(A_SESSION_ID_1, interceptSignoutFlowResponseUseCase) val reAuthNeeded = fakeSignoutSessionsUseCase.givenSignoutReAuthNeeded(listOf(A_SESSION_ID_1))
val signoutAction = SessionOverviewAction.SignoutOtherSession val signoutAction = SessionOverviewAction.SignoutOtherSession
givenCurrentSessionIsTrusted() givenCurrentSessionIsTrusted()
val expectedPendingAuth = DefaultBaseAuth(session = reAuthNeeded.flowResponse.session) val expectedPendingAuth = DefaultBaseAuth(session = reAuthNeeded.flowResponse.session)

View file

@ -24,8 +24,8 @@ import io.mockk.mockk
import io.mockk.mockkStatic import io.mockk.mockkStatic
import io.mockk.runs import io.mockk.runs
import io.mockk.unmockkAll import io.mockk.unmockkAll
import org.amshove.kluent.shouldBe
import org.amshove.kluent.shouldBeEqualTo import org.amshove.kluent.shouldBeEqualTo
import org.amshove.kluent.shouldBeInstanceOf
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
@ -63,7 +63,7 @@ class InterceptSignoutFlowResponseUseCaseTest {
} }
@Test @Test
fun `given no error and a stored password and a next stage as password when intercepting then promise is resumed and success is returned`() { fun `given no error and a stored password and a next stage as password when intercepting then promise is resumed and null is returned`() {
// Given // Given
val registrationFlowResponse = givenNextUncompletedStage(LoginFlowTypes.PASSWORD, A_SESSION_ID) val registrationFlowResponse = givenNextUncompletedStage(LoginFlowTypes.PASSWORD, A_SESSION_ID)
fakeReAuthHelper.givenStoredPassword(A_PASSWORD) fakeReAuthHelper.givenStoredPassword(A_PASSWORD)
@ -84,7 +84,7 @@ class InterceptSignoutFlowResponseUseCaseTest {
) )
// Then // Then
result shouldBeInstanceOf (SignoutSessionResult.Completed::class) result shouldBe null
every { every {
promise.resume(expectedAuth) promise.resume(expectedAuth)
} }
@ -97,7 +97,7 @@ class InterceptSignoutFlowResponseUseCaseTest {
fakeReAuthHelper.givenStoredPassword(A_PASSWORD) fakeReAuthHelper.givenStoredPassword(A_PASSWORD)
val errorCode = AN_ERROR_CODE val errorCode = AN_ERROR_CODE
val promise = mockk<Continuation<UIABaseAuth>>() val promise = mockk<Continuation<UIABaseAuth>>()
val expectedResult = SignoutSessionResult.ReAuthNeeded( val expectedResult = SignoutSessionsReAuthNeeded(
pendingAuth = DefaultBaseAuth(session = A_SESSION_ID), pendingAuth = DefaultBaseAuth(session = A_SESSION_ID),
uiaContinuation = promise, uiaContinuation = promise,
flowResponse = registrationFlowResponse, flowResponse = registrationFlowResponse,
@ -122,7 +122,7 @@ class InterceptSignoutFlowResponseUseCaseTest {
fakeReAuthHelper.givenStoredPassword(A_PASSWORD) fakeReAuthHelper.givenStoredPassword(A_PASSWORD)
val errorCode: String? = null val errorCode: String? = null
val promise = mockk<Continuation<UIABaseAuth>>() val promise = mockk<Continuation<UIABaseAuth>>()
val expectedResult = SignoutSessionResult.ReAuthNeeded( val expectedResult = SignoutSessionsReAuthNeeded(
pendingAuth = DefaultBaseAuth(session = A_SESSION_ID), pendingAuth = DefaultBaseAuth(session = A_SESSION_ID),
uiaContinuation = promise, uiaContinuation = promise,
flowResponse = registrationFlowResponse, flowResponse = registrationFlowResponse,
@ -147,7 +147,7 @@ class InterceptSignoutFlowResponseUseCaseTest {
fakeReAuthHelper.givenStoredPassword(null) fakeReAuthHelper.givenStoredPassword(null)
val errorCode: String? = null val errorCode: String? = null
val promise = mockk<Continuation<UIABaseAuth>>() val promise = mockk<Continuation<UIABaseAuth>>()
val expectedResult = SignoutSessionResult.ReAuthNeeded( val expectedResult = SignoutSessionsReAuthNeeded(
pendingAuth = DefaultBaseAuth(session = A_SESSION_ID), pendingAuth = DefaultBaseAuth(session = A_SESSION_ID),
uiaContinuation = promise, uiaContinuation = promise,
flowResponse = registrationFlowResponse, flowResponse = registrationFlowResponse,

View file

@ -1,79 +0,0 @@
/*
* Copyright (c) 2022 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.app.features.settings.devices.v2.signout
import im.vector.app.test.fakes.FakeActiveSessionHolder
import io.mockk.every
import io.mockk.mockk
import kotlinx.coroutines.test.runTest
import org.amshove.kluent.shouldBe
import org.junit.Test
import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor
private const val A_DEVICE_ID = "device-id"
class SignoutSessionUseCaseTest {
private val fakeActiveSessionHolder = FakeActiveSessionHolder()
private val signoutSessionUseCase = SignoutSessionUseCase(
activeSessionHolder = fakeActiveSessionHolder.instance
)
@Test
fun `given a device id when signing out with success then success result is returned`() = runTest {
// Given
val interceptor = givenAuthInterceptor()
fakeActiveSessionHolder.fakeSession
.fakeCryptoService
.givenDeleteDeviceSucceeds(A_DEVICE_ID)
// When
val result = signoutSessionUseCase.execute(A_DEVICE_ID, interceptor)
// Then
result.isSuccess shouldBe true
every {
fakeActiveSessionHolder.fakeSession
.fakeCryptoService
.deleteDevice(A_DEVICE_ID, interceptor, any())
}
}
@Test
fun `given a device id when signing out with error then failure result is returned`() = runTest {
// Given
val interceptor = givenAuthInterceptor()
val error = mockk<Exception>()
fakeActiveSessionHolder.fakeSession
.fakeCryptoService
.givenDeleteDeviceFailsWithError(A_DEVICE_ID, error)
// When
val result = signoutSessionUseCase.execute(A_DEVICE_ID, interceptor)
// Then
result.isFailure shouldBe true
every {
fakeActiveSessionHolder.fakeSession
.fakeCryptoService
.deleteDevice(A_DEVICE_ID, interceptor, any())
}
}
private fun givenAuthInterceptor() = mockk<UserInteractiveAuthInterceptor>()
}

View file

@ -19,10 +19,10 @@ package im.vector.app.features.settings.devices.v2.signout
import im.vector.app.test.fakes.FakeActiveSessionHolder import im.vector.app.test.fakes.FakeActiveSessionHolder
import io.mockk.every import io.mockk.every
import io.mockk.mockk import io.mockk.mockk
import io.mockk.verify
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.amshove.kluent.shouldBe import org.amshove.kluent.shouldBe
import org.junit.Test import org.junit.Test
import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor
private const val A_DEVICE_ID_1 = "device-id-1" private const val A_DEVICE_ID_1 = "device-id-1"
private const val A_DEVICE_ID_2 = "device-id-2" private const val A_DEVICE_ID_2 = "device-id-2"
@ -30,36 +30,38 @@ private const val A_DEVICE_ID_2 = "device-id-2"
class SignoutSessionsUseCaseTest { class SignoutSessionsUseCaseTest {
private val fakeActiveSessionHolder = FakeActiveSessionHolder() private val fakeActiveSessionHolder = FakeActiveSessionHolder()
private val fakeInterceptSignoutFlowResponseUseCase = mockk<InterceptSignoutFlowResponseUseCase>()
private val signoutSessionsUseCase = SignoutSessionsUseCase( private val signoutSessionsUseCase = SignoutSessionsUseCase(
activeSessionHolder = fakeActiveSessionHolder.instance activeSessionHolder = fakeActiveSessionHolder.instance,
interceptSignoutFlowResponseUseCase = fakeInterceptSignoutFlowResponseUseCase,
) )
@Test @Test
fun `given a list of device ids when signing out with success then success result is returned`() = runTest { fun `given a list of device ids when signing out with success then success result is returned`() = runTest {
// Given // Given
val interceptor = givenAuthInterceptor() val callback = givenOnReAuthCallback()
val deviceIds = listOf(A_DEVICE_ID_1, A_DEVICE_ID_2) val deviceIds = listOf(A_DEVICE_ID_1, A_DEVICE_ID_2)
fakeActiveSessionHolder.fakeSession fakeActiveSessionHolder.fakeSession
.fakeCryptoService .fakeCryptoService
.givenDeleteDevicesSucceeds(deviceIds) .givenDeleteDevicesSucceeds(deviceIds)
// When // When
val result = signoutSessionsUseCase.execute(deviceIds, interceptor) val result = signoutSessionsUseCase.execute(deviceIds, callback)
// Then // Then
result.isSuccess shouldBe true result.isSuccess shouldBe true
every { verify {
fakeActiveSessionHolder.fakeSession fakeActiveSessionHolder.fakeSession
.fakeCryptoService .fakeCryptoService
.deleteDevices(deviceIds, interceptor, any()) .deleteDevices(deviceIds, any(), any())
} }
} }
@Test @Test
fun `given a list of device ids when signing out with error then failure result is returned`() = runTest { fun `given a list of device ids when signing out with error then failure result is returned`() = runTest {
// Given // Given
val interceptor = givenAuthInterceptor() val interceptor = givenOnReAuthCallback()
val deviceIds = listOf(A_DEVICE_ID_1, A_DEVICE_ID_2) val deviceIds = listOf(A_DEVICE_ID_1, A_DEVICE_ID_2)
val error = mockk<Exception>() val error = mockk<Exception>()
fakeActiveSessionHolder.fakeSession fakeActiveSessionHolder.fakeSession
@ -71,12 +73,41 @@ class SignoutSessionsUseCaseTest {
// Then // Then
result.isFailure shouldBe true result.isFailure shouldBe true
every { verify {
fakeActiveSessionHolder.fakeSession fakeActiveSessionHolder.fakeSession
.fakeCryptoService .fakeCryptoService
.deleteDevices(deviceIds, interceptor, any()) .deleteDevices(deviceIds, any(), any())
} }
} }
private fun givenAuthInterceptor() = mockk<UserInteractiveAuthInterceptor>() @Test
fun `given a list of device ids when signing out with reAuth needed then callback is called`() = runTest {
// Given
val callback = givenOnReAuthCallback()
val deviceIds = listOf(A_DEVICE_ID_1, A_DEVICE_ID_2)
fakeActiveSessionHolder.fakeSession
.fakeCryptoService
.givenDeleteDevicesNeedsUIAuth(deviceIds)
val reAuthNeeded = SignoutSessionsReAuthNeeded(
pendingAuth = mockk(),
uiaContinuation = mockk(),
flowResponse = mockk(),
errCode = "errorCode"
)
every { fakeInterceptSignoutFlowResponseUseCase.execute(any(), any(), any()) } returns reAuthNeeded
// When
val result = signoutSessionsUseCase.execute(deviceIds, callback)
// Then
result.isSuccess shouldBe true
verify {
fakeActiveSessionHolder.fakeSession
.fakeCryptoService
.deleteDevices(deviceIds, any(), any())
callback(reAuthNeeded)
}
}
private fun givenOnReAuthCallback(): (SignoutSessionsReAuthNeeded) -> Unit = {}
} }

View file

@ -22,6 +22,7 @@ import io.mockk.every
import io.mockk.mockk import io.mockk.mockk
import io.mockk.slot import io.mockk.slot
import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor
import org.matrix.android.sdk.api.session.crypto.CryptoService import org.matrix.android.sdk.api.session.crypto.CryptoService
import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo
@ -70,30 +71,21 @@ class FakeCryptoService(
} }
} }
fun givenDeleteDeviceSucceeds(deviceId: String) { fun givenDeleteDevicesSucceeds(deviceIds: List<String>) {
val matrixCallback = slot<MatrixCallback<Unit>>() every { deleteDevices(deviceIds, any(), any()) } answers {
every { deleteDevice(deviceId, any(), capture(matrixCallback)) } answers {
thirdArg<MatrixCallback<Unit>>().onSuccess(Unit) thirdArg<MatrixCallback<Unit>>().onSuccess(Unit)
} }
} }
fun givenDeleteDeviceFailsWithError(deviceId: String, error: Exception) { fun givenDeleteDevicesNeedsUIAuth(deviceIds: List<String>) {
val matrixCallback = slot<MatrixCallback<Unit>>() every { deleteDevices(deviceIds, any(), any()) } answers {
every { deleteDevice(deviceId, any(), capture(matrixCallback)) } answers { secondArg<UserInteractiveAuthInterceptor>().performStage(mockk(), "", mockk())
thirdArg<MatrixCallback<Unit>>().onFailure(error)
}
}
fun givenDeleteDevicesSucceeds(deviceIds: List<String>) {
val matrixCallback = slot<MatrixCallback<Unit>>()
every { deleteDevices(deviceIds, any(), capture(matrixCallback)) } answers {
thirdArg<MatrixCallback<Unit>>().onSuccess(Unit) thirdArg<MatrixCallback<Unit>>().onSuccess(Unit)
} }
} }
fun givenDeleteDevicesFailsWithError(deviceIds: List<String>, error: Exception) { fun givenDeleteDevicesFailsWithError(deviceIds: List<String>, error: Exception) {
val matrixCallback = slot<MatrixCallback<Unit>>() every { deleteDevices(deviceIds, any(), any()) } answers {
every { deleteDevices(deviceIds, any(), capture(matrixCallback)) } answers {
thirdArg<MatrixCallback<Unit>>().onFailure(error) thirdArg<MatrixCallback<Unit>>().onFailure(error)
} }
} }

View file

@ -1,77 +0,0 @@
/*
* Copyright (c) 2022 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.app.test.fakes
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 io.mockk.coEvery
import io.mockk.every
import io.mockk.mockk
import io.mockk.slot
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 kotlin.coroutines.Continuation
class FakeSignoutSessionUseCase {
val instance = mockk<SignoutSessionUseCase>()
fun givenSignoutSuccess(
deviceId: String,
interceptSignoutFlowResponseUseCase: InterceptSignoutFlowResponseUseCase,
) {
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 { instance.execute(deviceId, capture(interceptor)) } coAnswers {
secondArg<UserInteractiveAuthInterceptor>().performStage(flowResponse, errorCode, promise)
Result.success(Unit)
}
}
fun givenSignoutReAuthNeeded(
deviceId: String,
interceptSignoutFlowResponseUseCase: InterceptSignoutFlowResponseUseCase,
): SignoutSessionResult.ReAuthNeeded {
val interceptor = slot<UserInteractiveAuthInterceptor>()
val flowResponse = mockk<RegistrationFlowResponse>()
every { flowResponse.session } returns "a-session-id"
val errorCode = "errorCode"
val promise = mockk<Continuation<UIABaseAuth>>()
val reAuthNeeded = SignoutSessionResult.ReAuthNeeded(
pendingAuth = mockk(),
uiaContinuation = promise,
flowResponse = flowResponse,
errCode = errorCode,
)
every { interceptSignoutFlowResponseUseCase.execute(flowResponse, errorCode, promise) } returns reAuthNeeded
coEvery { instance.execute(deviceId, capture(interceptor)) } coAnswers {
secondArg<UserInteractiveAuthInterceptor>().performStage(flowResponse, errorCode, promise)
Result.success(Unit)
}
return reAuthNeeded
}
fun givenSignoutError(deviceId: String, error: Throwable) {
coEvery { instance.execute(deviceId, any()) } returns Result.failure(error)
}
}

View file

@ -16,55 +16,33 @@
package im.vector.app.test.fakes package im.vector.app.test.fakes
import im.vector.app.features.settings.devices.v2.signout.InterceptSignoutFlowResponseUseCase import im.vector.app.features.settings.devices.v2.signout.SignoutSessionsReAuthNeeded
import im.vector.app.features.settings.devices.v2.signout.SignoutSessionResult
import im.vector.app.features.settings.devices.v2.signout.SignoutSessionsUseCase import im.vector.app.features.settings.devices.v2.signout.SignoutSessionsUseCase
import io.mockk.coEvery import io.mockk.coEvery
import io.mockk.every import io.mockk.every
import io.mockk.mockk import io.mockk.mockk
import io.mockk.slot
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.auth.registration.RegistrationFlowResponse
import kotlin.coroutines.Continuation
class FakeSignoutSessionsUseCase { class FakeSignoutSessionsUseCase {
val instance = mockk<SignoutSessionsUseCase>() val instance = mockk<SignoutSessionsUseCase>()
fun givenSignoutSuccess( fun givenSignoutSuccess(deviceIds: List<String>) {
deviceIds: List<String>, coEvery { instance.execute(deviceIds, any()) } returns Result.success(Unit)
interceptSignoutFlowResponseUseCase: InterceptSignoutFlowResponseUseCase,
) {
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 { instance.execute(deviceIds, capture(interceptor)) } coAnswers {
secondArg<UserInteractiveAuthInterceptor>().performStage(flowResponse, errorCode, promise)
Result.success(Unit)
}
} }
fun givenSignoutReAuthNeeded( fun givenSignoutReAuthNeeded(deviceIds: List<String>): SignoutSessionsReAuthNeeded {
deviceIds: List<String>,
interceptSignoutFlowResponseUseCase: InterceptSignoutFlowResponseUseCase,
): SignoutSessionResult.ReAuthNeeded {
val interceptor = slot<UserInteractiveAuthInterceptor>()
val flowResponse = mockk<RegistrationFlowResponse>() val flowResponse = mockk<RegistrationFlowResponse>()
every { flowResponse.session } returns "a-session-id" every { flowResponse.session } returns "a-session-id"
val errorCode = "errorCode" val errorCode = "errorCode"
val promise = mockk<Continuation<UIABaseAuth>>() val reAuthNeeded = SignoutSessionsReAuthNeeded(
val reAuthNeeded = SignoutSessionResult.ReAuthNeeded(
pendingAuth = mockk(), pendingAuth = mockk(),
uiaContinuation = promise, uiaContinuation = mockk(),
flowResponse = flowResponse, flowResponse = flowResponse,
errCode = errorCode, errCode = errorCode,
) )
every { interceptSignoutFlowResponseUseCase.execute(flowResponse, errorCode, promise) } returns reAuthNeeded coEvery { instance.execute(deviceIds, any()) } coAnswers {
coEvery { instance.execute(deviceIds, capture(interceptor)) } coAnswers { secondArg<(SignoutSessionsReAuthNeeded) -> Unit>().invoke(reAuthNeeded)
secondArg<UserInteractiveAuthInterceptor>().performStage(flowResponse, errorCode, promise)
Result.success(Unit) Result.success(Unit)
} }