diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/call/CallsScope.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/call/CallsScope.kt index 46da890c277..0bd7104704d 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/call/CallsScope.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/call/CallsScope.kt @@ -31,6 +31,7 @@ import com.wire.kalium.logic.data.id.CurrentClientIdProvider import com.wire.kalium.logic.feature.call.usecase.AnswerCallUseCase import com.wire.kalium.logic.feature.call.usecase.AnswerCallUseCaseImpl import com.wire.kalium.logic.feature.call.usecase.ConversationClientsInCallUpdater +import com.wire.kalium.logic.feature.call.usecase.EndCallResultListenerImpl import com.wire.kalium.logic.feature.call.usecase.EndCallOnConversationChangeUseCase import com.wire.kalium.logic.feature.call.usecase.EndCallOnConversationChangeUseCaseImpl import com.wire.kalium.logic.feature.call.usecase.EndCallUseCase @@ -48,6 +49,8 @@ import com.wire.kalium.logic.feature.call.usecase.IsLastCallClosedUseCase import com.wire.kalium.logic.feature.call.usecase.IsLastCallClosedUseCaseImpl import com.wire.kalium.logic.feature.call.usecase.MuteCallUseCase import com.wire.kalium.logic.feature.call.usecase.MuteCallUseCaseImpl +import com.wire.kalium.logic.feature.call.usecase.ObserveEndCallDueToConversationDegradationUseCase +import com.wire.kalium.logic.feature.call.usecase.ObserveEndCallDueToConversationDegradationUseCaseImpl import com.wire.kalium.logic.feature.call.usecase.ObserveEstablishedCallsUseCase import com.wire.kalium.logic.feature.call.usecase.ObserveEstablishedCallsUseCaseImpl import com.wire.kalium.logic.feature.call.usecase.ObserveOngoingCallsUseCase @@ -66,6 +69,7 @@ import com.wire.kalium.logic.feature.call.usecase.UpdateConversationClientsForCu import com.wire.kalium.logic.feature.call.usecase.UpdateVideoStateUseCase import com.wire.kalium.logic.featureFlags.KaliumConfigs import com.wire.kalium.logic.sync.SyncManager +import com.wire.kalium.util.KaliumDispatcher import com.wire.kalium.util.KaliumDispatcherImpl @Suppress("LongParameterList") @@ -81,7 +85,8 @@ class CallsScope internal constructor( private val currentClientIdProvider: CurrentClientIdProvider, private val userConfigRepository: UserConfigRepository, private val conversationClientsInCallUpdater: ConversationClientsInCallUpdater, - private val kaliumConfigs: KaliumConfigs + private val kaliumConfigs: KaliumConfigs, + internal val dispatcher: KaliumDispatcher = KaliumDispatcherImpl ) { val allCallsWithSortedParticipants: GetAllCallsWithSortedParticipantsUseCase @@ -109,13 +114,14 @@ class CallsScope internal constructor( callRepository = callRepository, ) - val startCall: StartCallUseCase get() = StartCallUseCase( - callManager = callManager, - syncManager = syncManager, - callRepository = callRepository, - answerCall = answerCall, - kaliumConfigs = kaliumConfigs - ) + val startCall: StartCallUseCase + get() = StartCallUseCase( + callManager = callManager, + syncManager = syncManager, + callRepository = callRepository, + answerCall = answerCall, + kaliumConfigs = kaliumConfigs + ) val answerCall: AnswerCallUseCase get() = AnswerCallUseCaseImpl( @@ -132,7 +138,8 @@ class CallsScope internal constructor( get() = EndCallOnConversationChangeUseCaseImpl( callRepository = callRepository, conversationRepository = conversationRepository, - endCallUseCase = endCall + endCallUseCase = endCall, + endCallListener = EndCallResultListenerImpl ) val updateConversationClientsForCurrentCallUseCase: UpdateConversationClientsForCurrentCallUseCase @@ -172,4 +179,7 @@ class CallsScope internal constructor( val requestVideoStreams: RequestVideoStreamsUseCase get() = RequestVideoStreamsUseCase(callManager, KaliumDispatcherImpl) val isEligibleToStartCall: IsEligibleToStartCallUseCase get() = IsEligibleToStartCallUseCaseImpl(userConfigRepository, callRepository) + + val observeEndCallDialog: ObserveEndCallDueToConversationDegradationUseCase + get() = ObserveEndCallDueToConversationDegradationUseCaseImpl(EndCallResultListenerImpl) } diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/call/usecase/EndCallOnConversationChangeUseCase.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/call/usecase/EndCallOnConversationChangeUseCase.kt index 2432a3b92da..033c401cfc2 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/call/usecase/EndCallOnConversationChangeUseCase.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/call/usecase/EndCallOnConversationChangeUseCase.kt @@ -1,14 +1,22 @@ package com.wire.kalium.logic.feature.call.usecase import com.wire.kalium.logic.data.call.CallRepository +import com.wire.kalium.logic.data.conversation.Conversation import com.wire.kalium.logic.data.conversation.ConversationDetails import com.wire.kalium.logic.data.conversation.ConversationRepository +import com.wire.kalium.logic.data.id.ConversationId import com.wire.kalium.logic.data.user.ConnectionState -import com.wire.kalium.logic.functional.fold +import com.wire.kalium.logic.functional.getOrElse +import com.wire.kalium.logic.functional.map +import com.wire.kalium.logic.functional.onlyRight import kotlinx.coroutines.flow.cancellable -import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.emptyFlow +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.merge +import kotlinx.coroutines.flow.scan /** * End call when conversation is deleted, user is not a member anymore or user is deleted. @@ -20,34 +28,76 @@ interface EndCallOnConversationChangeUseCase { internal class EndCallOnConversationChangeUseCaseImpl( private val callRepository: CallRepository, private val conversationRepository: ConversationRepository, - private val endCallUseCase: EndCallUseCase + private val endCallUseCase: EndCallUseCase, + private val endCallListener: EndCallResultListener ) : EndCallOnConversationChangeUseCase { override suspend operator fun invoke() { val callsFlow = callRepository.establishedCallsFlow().map { calls -> calls.map { it.conversationId } }.distinctUntilChanged().cancellable() - callsFlow.collectLatest { calls -> - if (calls.isNotEmpty()) { - conversationRepository.observeConversationDetailsById(calls.first()).cancellable().collect { conversationDetails -> - conversationDetails.fold({ - // conversation deleted - endCallUseCase(calls.first()) - }, { - if (it is ConversationDetails.Group) { - // Not a member anymore - if (!it.isSelfUserMember) { - endCallUseCase(calls.first()) - } - } else if (it is ConversationDetails.OneOne) { - // Member blocked or deleted - if (it.otherUser.deleted || it.otherUser.connectionStatus == ConnectionState.BLOCKED) { - endCallUseCase(calls.first()) - } - } - }) - } + callsFlow.flatMapLatest { calls -> + if (calls.isEmpty()) return@flatMapLatest emptyFlow() + + val currentCall = calls.first() + + merge( + finishCallBecauseOfMembershipChangesFlow(currentCall), + finishCallBecauseOfVerificationDegradedFlow(currentCall) + ) + }.collect { conversationId -> endCallUseCase(conversationId) } + } + + private suspend fun finishCallBecauseOfMembershipChangesFlow(conversationId: ConversationId) = + conversationRepository.observeConversationDetailsById(conversationId).cancellable() + .map { conversationDetails -> + conversationDetails.map { + // Member blocked or deleted + val isOtherUserBlockedOrDeleted = it is ConversationDetails.OneOne + && (it.otherUser.deleted || it.otherUser.connectionStatus == ConnectionState.BLOCKED) + // Not a member of group anymore + val isSelfRemovedFromGroup = it is ConversationDetails.Group && !it.isSelfUserMember + + isOtherUserBlockedOrDeleted || isSelfRemovedFromGroup + }.getOrElse(true) } - } + .filter { it } + .map { conversationId } + + /** + * @return [ConversationId] only when the conversation Proteus or MLS verification status was verified in past + * but became not verified -> means need to finish the call + */ + private suspend fun finishCallBecauseOfVerificationDegradedFlow(conversationId: ConversationId) = + conversationRepository.observeConversationDetailsById(conversationId) + .cancellable() + .onlyRight() + .map { + val isProteusVerified = it.conversation.proteusVerificationStatus == Conversation.VerificationStatus.VERIFIED + val isMLSVerified = it.conversation.mlsVerificationStatus == Conversation.VerificationStatus.VERIFIED + + isProteusVerified to isMLSVerified + } + .scan(ConversationVerificationStatuses()) { prevState, (isProteusVerified, isMLSVerified) -> + ConversationVerificationStatuses( + isProteusVerified = isProteusVerified, + wasProteusVerified = prevState.isProteusVerified, + isMLSVerified = isMLSVerified, + wasMLSVerified = prevState.isMLSVerified + ) + } + .filter { it.shouldFinishCall() } + .map { + endCallListener.onCallEndedBecauseOfVerificationDegraded(conversationId) + conversationId + } + + private data class ConversationVerificationStatuses( + val isProteusVerified: Boolean = false, + val wasProteusVerified: Boolean = false, + val isMLSVerified: Boolean = false, + val wasMLSVerified: Boolean = false + ) { + fun shouldFinishCall(): Boolean = (!isProteusVerified && wasProteusVerified) || (!isMLSVerified && wasMLSVerified) } } diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/call/usecase/EndCallResultListener.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/call/usecase/EndCallResultListener.kt new file mode 100644 index 00000000000..768c83877e9 --- /dev/null +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/call/usecase/EndCallResultListener.kt @@ -0,0 +1,41 @@ +/* + * Wire + * Copyright (C) 2023 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ +package com.wire.kalium.logic.feature.call.usecase + +import com.wire.kalium.logic.data.id.ConversationId +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableSharedFlow + +interface EndCallResultListener { + suspend fun observeCallEndedBecauseOfVerificationDegraded(): Flow + suspend fun onCallEndedBecauseOfVerificationDegraded(conversationId: ConversationId) +} + +/** + * This singleton allow us to queue event to show dialog informing user that call was ended because of verification degradation. + */ +object EndCallResultListenerImpl : EndCallResultListener { + + private val conversationCallEnded = MutableSharedFlow() + + override suspend fun observeCallEndedBecauseOfVerificationDegraded(): Flow = conversationCallEnded + + override suspend fun onCallEndedBecauseOfVerificationDegraded(conversationId: ConversationId) { + conversationCallEnded.emit(conversationId) + } +} diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/call/usecase/ObserveEndCallDueToConversationDegradationUseCase.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/call/usecase/ObserveEndCallDueToConversationDegradationUseCase.kt new file mode 100644 index 00000000000..9959fa2f72f --- /dev/null +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/call/usecase/ObserveEndCallDueToConversationDegradationUseCase.kt @@ -0,0 +1,38 @@ +/* + * Wire + * Copyright (C) 2023 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ +package com.wire.kalium.logic.feature.call.usecase + +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map + +/** + * The useCase for observing when the ongoing call was ended because of degradation of conversation verification status (Proteus or MLS) + */ +interface ObserveEndCallDueToConversationDegradationUseCase { + /** + * @return [Flow] that emits only when the call was ended because of degradation of conversation verification status (Proteus or MLS) + */ + suspend operator fun invoke(): Flow +} + +internal class ObserveEndCallDueToConversationDegradationUseCaseImpl( + private val endCallListener: EndCallResultListener +) : ObserveEndCallDueToConversationDegradationUseCase { + override suspend fun invoke(): Flow = + endCallListener.observeCallEndedBecauseOfVerificationDegraded().map { Unit } +} diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/call/usecase/EndCallOnConversationChangeUseCaseTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/call/usecase/EndCallOnConversationChangeUseCaseTest.kt index 7138942514c..c7af10ad288 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/call/usecase/EndCallOnConversationChangeUseCaseTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/call/usecase/EndCallOnConversationChangeUseCaseTest.kt @@ -1,10 +1,8 @@ package com.wire.kalium.logic.feature.call.usecase import com.wire.kalium.logic.StorageFailure -import com.wire.kalium.logic.data.call.CallRepository import com.wire.kalium.logic.data.conversation.Conversation import com.wire.kalium.logic.data.conversation.ConversationDetails -import com.wire.kalium.logic.data.conversation.ConversationRepository import com.wire.kalium.logic.data.conversation.LegalHoldStatus import com.wire.kalium.logic.data.conversation.MutedConversationStatus import com.wire.kalium.logic.data.id.ConversationId @@ -19,6 +17,10 @@ import com.wire.kalium.logic.data.user.type.UserType import com.wire.kalium.logic.data.call.Call import com.wire.kalium.logic.data.call.CallStatus import com.wire.kalium.logic.functional.Either +import com.wire.kalium.logic.util.arrangement.repository.CallRepositoryArrangement +import com.wire.kalium.logic.util.arrangement.repository.CallRepositoryArrangementImpl +import com.wire.kalium.logic.util.arrangement.repository.ConversationRepositoryArrangement +import com.wire.kalium.logic.util.arrangement.repository.ConversationRepositoryArrangementImpl import io.mockative.Mock import io.mockative.classOf import io.mockative.eq @@ -27,97 +29,158 @@ import io.mockative.mock import io.mockative.once import io.mockative.thenDoNothing import io.mockative.verify -import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.test.runTest -import kotlin.test.BeforeTest import kotlin.test.Test class EndCallOnConversationChangeUseCaseTest { - @Mock - private val callRepository = mock(classOf()) - - @Mock - private val conversationRepository = mock(classOf()) + @Test + fun givenAnEstablishedCall_whenConversationIsDeleted_thenEndTheCurrentCall() = runTest { + val (arrangement, endCallOnConversationChange) = arrange { + withObserveConversationDetailsByIdReturning(Either.Left(StorageFailure.DataNotFound)) + } - @Mock - private val endCall = mock(classOf()) + endCallOnConversationChange() - private lateinit var endCallOnConversationChange: EndCallOnConversationChangeUseCase + verify(arrangement.endCall) + .suspendFunction(arrangement.endCall::invoke) + .with(eq(conversationId)) + .wasInvoked(once) + } - @BeforeTest - fun setup() { - endCallOnConversationChange = EndCallOnConversationChangeUseCaseImpl( - callRepository = callRepository, - conversationRepository = conversationRepository, - endCallUseCase = endCall - ) + @Test + fun givenAnEstablishedCall_whenUserIsRemovedFromConversation_thenEndTheCurrentCall() = runTest { + val (arrangement, endCallOnConversationChange) = arrange { + withObserveConversationDetailsByIdReturning(Either.Right(groupConversationDetail)) + } - given(callRepository) - .suspendFunction(callRepository::establishedCallsFlow) - .whenInvoked() - .thenReturn(flowOf(listOf(call))) + endCallOnConversationChange() - given(endCall) - .suspendFunction(endCall::invoke) - .whenInvokedWith(eq(conversationId)) - .thenDoNothing() + verify(arrangement.endCall) + .suspendFunction(arrangement.endCall::invoke) + .with(eq(conversationId)) + .wasInvoked(once) } @Test - fun givenAnEstablishedCall_whenConversationIsDeleted_thenEndTheCurrentCall() = runTest { - - given(conversationRepository) - .suspendFunction(conversationRepository::observeConversationDetailsById) - .whenInvokedWith(eq(conversationId)) - .then { - flowOf(Either.Left(StorageFailure.DataNotFound)) - } + fun givenAnEstablishedCall_whenUserDeletesHisAccount_thenEndTheCurrentCall() = runTest { + val (arrangement, endCallOnConversationChange) = arrange { + withObserveConversationDetailsByIdReturning(Either.Right(oneOnOneConversationDetail)) + } endCallOnConversationChange() - verify(endCall) - .suspendFunction(endCall::invoke) + verify(arrangement.endCall) + .suspendFunction(arrangement.endCall::invoke) .with(eq(conversationId)) .wasInvoked(once) } @Test - fun givenAnEstablishedCall_whenUserIsRemovedFromConversation_thenEndTheCurrentCall() = runTest { - - given(conversationRepository) - .suspendFunction(conversationRepository::observeConversationDetailsById) - .whenInvokedWith(eq(conversationId)) - .then { - flowOf(Either.Right(groupConversationDetail)) - } + fun givenAnEstablishedCall_whenConversationProteusDegraded_thenEndTheCurrentCall() = runTest { + val verifiedConversation = oneOnOneConversationDetail.copy( + conversation = conversation.copy(proteusVerificationStatus = Conversation.VerificationStatus.VERIFIED), + otherUser = otherUser.copy(deleted = false) + ) + val value0 = Either.Right(verifiedConversation) + val value1 = + Either.Right( + verifiedConversation.copy( + conversation = conversation.copy(proteusVerificationStatus = Conversation.VerificationStatus.DEGRADED) + ) + ) + val (arrangement, endCallOnConversationChange) = arrange { + withObserveConversationDetailsByIdReturning(value0, value1) + } endCallOnConversationChange() - verify(endCall) - .suspendFunction(endCall::invoke) + verify(arrangement.endCall) + .suspendFunction(arrangement.endCall::invoke) .with(eq(conversationId)) .wasInvoked(once) } @Test - fun givenAnEstablishedCall_whenUserDeletesHisAccount_thenEndTheCurrentCall() = runTest { - given(conversationRepository) - .suspendFunction(conversationRepository::observeConversationDetailsById) - .whenInvokedWith(eq(conversationId)) - .then { - flowOf(Either.Right(oneOnOneConversationDetail)) - } + fun givenAnEstablishedCall_whenConversationMLSDegraded_thenEndTheCurrentCall() = runTest { + val verifiedConversation = oneOnOneConversationDetail.copy( + conversation = conversation.copy(mlsVerificationStatus = Conversation.VerificationStatus.VERIFIED), + otherUser = otherUser.copy(deleted = false) + ) + val value0 = Either.Right(verifiedConversation) + val value1 = + Either.Right( + verifiedConversation.copy( + conversation = conversation.copy(mlsVerificationStatus = Conversation.VerificationStatus.DEGRADED) + ) + ) + val (arrangement, endCallOnConversationChange) = arrange { + withObserveConversationDetailsByIdReturning(value0, value1) + } endCallOnConversationChange() - verify(endCall) - .suspendFunction(endCall::invoke) + verify(arrangement.endCall) + .suspendFunction(arrangement.endCall::invoke) .with(eq(conversationId)) .wasInvoked(once) } + @Test + fun givenAnEstablishedCallInVerifiedConversationAndUserIsOkay_thenCurrentCallIsNotEnded() = runTest { + val verifiedConversation = oneOnOneConversationDetail.copy( + conversation = conversation.copy(proteusVerificationStatus = Conversation.VerificationStatus.VERIFIED), + otherUser = otherUser.copy(deleted = false) + ) + val (arrangement, endCallOnConversationChange) = arrange { + withObserveConversationDetailsByIdReturning(Either.Right(verifiedConversation)) + } + + endCallOnConversationChange() + + verify(arrangement.endCall) + .suspendFunction(arrangement.endCall::invoke) + .with(eq(conversationId)) + .wasNotInvoked() + } + + private class Arrangement(private val block: Arrangement.() -> Unit) : + CallRepositoryArrangement by CallRepositoryArrangementImpl(), + ConversationRepositoryArrangement by ConversationRepositoryArrangementImpl() { + + @Mock + val endCall = mock(classOf()) + + @Mock + val endCallDialogManager = mock(classOf()) + + init { + given(endCall) + .suspendFunction(endCall::invoke) + .whenInvokedWith(eq(conversationId)) + .thenDoNothing() + given(endCallDialogManager) + .suspendFunction(endCallDialogManager::onCallEndedBecauseOfVerificationDegraded) + .whenInvokedWith(eq(conversationId)) + .thenDoNothing() + + withEstablishedCallsFlow(listOf(call)) + } + + fun arrange() = run { + block() + this@Arrangement to EndCallOnConversationChangeUseCaseImpl( + callRepository = callRepository, + conversationRepository = conversationRepository, + endCallUseCase = endCall, + endCallListener = endCallDialogManager + ) + } + } + companion object { + private fun arrange(configuration: Arrangement.() -> Unit) = Arrangement(configuration).arrange() + val conversationId = ConversationId("conversationId", "domainId") private val call = Call( conversationId = conversationId, diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/util/arrangement/repository/CallRepositoryArrangement.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/util/arrangement/repository/CallRepositoryArrangement.kt new file mode 100644 index 00000000000..1384385f42b --- /dev/null +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/util/arrangement/repository/CallRepositoryArrangement.kt @@ -0,0 +1,44 @@ +/* + * Wire + * Copyright (C) 2023 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ +package com.wire.kalium.logic.util.arrangement.repository + +import com.wire.kalium.logic.data.call.CallRepository +import com.wire.kalium.logic.data.call.Call +import io.mockative.Mock +import io.mockative.given +import io.mockative.mock +import kotlinx.coroutines.flow.flowOf + +internal interface CallRepositoryArrangement { + val callRepository: CallRepository + + fun withEstablishedCallsFlow(calls: List) +} + +internal open class CallRepositoryArrangementImpl : CallRepositoryArrangement { + + @Mock + override val callRepository: CallRepository = mock(CallRepository::class) + + override fun withEstablishedCallsFlow(calls: List) { + given(callRepository) + .suspendFunction(callRepository::establishedCallsFlow) + .whenInvoked() + .thenReturn(flowOf(calls)) + } +} diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/util/arrangement/repository/ConversationRepositoryArrangement.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/util/arrangement/repository/ConversationRepositoryArrangement.kt index 7dc51414426..e4a0bb9bf86 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/util/arrangement/repository/ConversationRepositoryArrangement.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/util/arrangement/repository/ConversationRepositoryArrangement.kt @@ -18,14 +18,14 @@ package com.wire.kalium.logic.util.arrangement.repository import com.wire.kalium.logic.CoreFailure +import com.wire.kalium.logic.StorageFailure import com.wire.kalium.logic.data.conversation.Conversation import com.wire.kalium.logic.data.conversation.ConversationDetails -import com.wire.kalium.logic.StorageFailure import com.wire.kalium.logic.data.conversation.ConversationRepository -import com.wire.kalium.logic.data.user.UserId -import com.wire.kalium.logic.framework.TestConversation import com.wire.kalium.logic.data.id.ConversationId import com.wire.kalium.logic.data.id.QualifiedID +import com.wire.kalium.logic.data.user.UserId +import com.wire.kalium.logic.framework.TestConversation import com.wire.kalium.logic.functional.Either import io.mockative.Mock import io.mockative.any @@ -61,7 +61,7 @@ internal interface ConversationRepositoryArrangement { fun withFetchConversation(result: Either) fun withObserveOneToOneConversationWithOtherUserReturning(result: Either) - fun withObserveConversationDetailsByIdReturning(result: Either) + fun withObserveConversationDetailsByIdReturning(vararg results: Either) fun withGetConversationIdsReturning(result: Either>) @@ -217,11 +217,11 @@ internal open class ConversationRepositoryArrangementImpl : ConversationReposito .thenReturn(flowOf(result)) } - override fun withObserveConversationDetailsByIdReturning(result: Either) { + override fun withObserveConversationDetailsByIdReturning(vararg results: Either) { given(conversationRepository) .suspendFunction(conversationRepository::observeConversationDetailsById) .whenInvokedWith(any()) - .thenReturn(flowOf(result)) + .thenReturn(flowOf(*results)) } override fun withGetConversationIdsReturning(result: Either>) {