From 02c8eb02c5b56beb96731e4bff06a7878932dba8 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 2 Sep 2024 09:05:13 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20End=20SFT=20oneOnOne=20call=20on=20prot?= =?UTF-8?q?eus=20protocol=20(WPB-7153)=20=F0=9F=8D=92=20=F0=9F=8D=92=20(#2?= =?UTF-8?q?948)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Commit with unresolved merge conflicts * chore: resolve conflicts * chore: resolve conflicts * chore: resolve conflicts * chore: resolve conflicts --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Oussama Hassine --- .../call/scenario/OnParticipantListChanged.kt | 33 +++--- .../kalium/logic/data/call/MLSCallHelper.kt | 17 ++- .../logic/data/call/MLSCallHelperTest.kt | 105 ++++++++---------- 3 files changed, 79 insertions(+), 76 deletions(-) diff --git a/logic/src/commonJvmAndroid/kotlin/com/wire/kalium/logic/feature/call/scenario/OnParticipantListChanged.kt b/logic/src/commonJvmAndroid/kotlin/com/wire/kalium/logic/feature/call/scenario/OnParticipantListChanged.kt index 4412357a6d..6fb7ce39c4 100644 --- a/logic/src/commonJvmAndroid/kotlin/com/wire/kalium/logic/feature/call/scenario/OnParticipantListChanged.kt +++ b/logic/src/commonJvmAndroid/kotlin/com/wire/kalium/logic/feature/call/scenario/OnParticipantListChanged.kt @@ -40,7 +40,6 @@ import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch import kotlinx.serialization.json.Json -// TODO: add tests for this class @Suppress("LongParameterList") class OnParticipantListChanged internal constructor( private val callRepository: CallRepository, @@ -60,25 +59,29 @@ class OnParticipantListChanged internal constructor( callingScope.launch { val participants = mutableListOf() - val conversationIdWithDomain = qualifiedIdMapper.fromStringToQualifiedID(remoteConversationId) + val conversationIdWithDomain = + qualifiedIdMapper.fromStringToQualifiedID(remoteConversationId) participantsChange.members.map { member -> participants.add(participantMapper.fromCallMemberToParticipantMinimized(member)) } - val callProtocol = callRepository.currentCallProtocol(conversationIdWithDomain) - val currentCall = callRepository.establishedCallsFlow().first().firstOrNull() - currentCall?.let { - val shouldEndSFTOneOnOneCall = mlsCallHelper.shouldEndSFTOneOnOneCall( - conversationId = conversationIdWithDomain, - callProtocol = callProtocol, - conversationType = it.conversationType, - newCallParticipants = participants, - previousCallParticipants = it.participants - ) - if (shouldEndSFTOneOnOneCall) { - kaliumLogger.i("[onParticipantChanged] - Ending MLS call due to participant leaving") - endCall(conversationIdWithDomain) + if (userConfigRepository.shouldUseSFTForOneOnOneCalls().getOrElse(false)) { + val callProtocol = callRepository.currentCallProtocol(conversationIdWithDomain) + + val currentCall = callRepository.establishedCallsFlow().first().firstOrNull() + currentCall?.let { + val shouldEndSFTOneOnOneCall = mlsCallHelper.shouldEndSFTOneOnOneCall( + conversationId = conversationIdWithDomain, + callProtocol = callProtocol, + conversationType = it.conversationType, + newCallParticipants = participants, + previousCallParticipants = it.participants + ) + if (shouldEndSFTOneOnOneCall) { + kaliumLogger.i("[onParticipantChanged] - Ending SFT one on one call due to participant leaving") + endCall(conversationIdWithDomain) + } } } diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/call/MLSCallHelper.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/call/MLSCallHelper.kt index 82e2515b09..131478e166 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/call/MLSCallHelper.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/call/MLSCallHelper.kt @@ -80,12 +80,18 @@ class MLSCallHelperImpl( conversationType: Conversation.Type, newCallParticipants: List, previousCallParticipants: List - ) = callProtocol is Conversation.ProtocolInfo.MLS && - userConfigRepository.shouldUseSFTForOneOnOneCalls().getOrElse(false) && + ): Boolean { + return if (callProtocol is Conversation.ProtocolInfo.Proteus) { conversationType == Conversation.Type.ONE_ON_ONE && - newCallParticipants.size == TWO_PARTICIPANTS && - previousCallParticipants.size == TWO_PARTICIPANTS && - previousCallParticipants[1].hasEstablishedAudio && !newCallParticipants[1].hasEstablishedAudio + newCallParticipants.size == ONE_PARTICIPANTS && + previousCallParticipants.size == TWO_PARTICIPANTS + } else { + conversationType == Conversation.Type.ONE_ON_ONE && + newCallParticipants.size == TWO_PARTICIPANTS && + previousCallParticipants.size == TWO_PARTICIPANTS && + previousCallParticipants[1].hasEstablishedAudio && !newCallParticipants[1].hasEstablishedAudio + } + } override suspend fun handleCallTermination( conversationId: ConversationId, @@ -119,5 +125,6 @@ class MLSCallHelperImpl( companion object { const val TWO_PARTICIPANTS = 2 + const val ONE_PARTICIPANTS = 1 } } diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/call/MLSCallHelperTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/call/MLSCallHelperTest.kt index b3ece1e8b5..880e39526e 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/call/MLSCallHelperTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/call/MLSCallHelperTest.kt @@ -47,44 +47,34 @@ import kotlin.test.assertTrue class MLSCallHelperTest { @Test - fun givenMlsConferenceCall_whenShouldEndSFTOneOnOneCallIsCalled_thenReturnCorrectValue() = + fun givenMlsProtocol_whenShouldEndSFTOneOnOneCallIsCalled_thenReturnCorrectValue() = runTest { val (_, mLSCallHelper) = Arrangement() .withShouldUseSFTForOneOnOneCallsReturning(Either.Right(true)) .arrange() - // Proteus protocol - val shouldEndSFTOneOnOneCall1 = mLSCallHelper.shouldEndSFTOneOnOneCall( - conversationId = conversationId, - callProtocol = Conversation.ProtocolInfo.Proteus, - conversationType = Conversation.Type.ONE_ON_ONE, - newCallParticipants = listOf(participantMinimized1, participantMinimized2), - previousCallParticipants = listOf(participant1, participant2) - ) - assertFalse { shouldEndSFTOneOnOneCall1 } - // one participant in the call - val shouldEndSFTOneOnOneCall2 = mLSCallHelper.shouldEndSFTOneOnOneCall( + val shouldEndSFTOneOnOneCall1 = mLSCallHelper.shouldEndSFTOneOnOneCall( conversationId = conversationId, callProtocol = CONVERSATION_MLS_PROTOCOL_INFO, conversationType = Conversation.Type.ONE_ON_ONE, newCallParticipants = listOf(participantMinimized1), previousCallParticipants = listOf(participant1) ) - assertFalse { shouldEndSFTOneOnOneCall2 } + assertFalse { shouldEndSFTOneOnOneCall1 } - // Audi not lost for the second participant - val shouldEndSFTOneOnOneCall3 = mLSCallHelper.shouldEndSFTOneOnOneCall( + // Audio not lost for the second participant + val shouldEndSFTOneOnOneCall2 = mLSCallHelper.shouldEndSFTOneOnOneCall( conversationId = conversationId, callProtocol = CONVERSATION_MLS_PROTOCOL_INFO, conversationType = Conversation.Type.GROUP, newCallParticipants = listOf(participantMinimized1, participantMinimized2), previousCallParticipants = listOf(participant1, participant2) ) - assertFalse { shouldEndSFTOneOnOneCall3 } + assertFalse { shouldEndSFTOneOnOneCall2 } // Audio lost for the second participant - val shouldEndSFTOneOnOneCall4 = mLSCallHelper.shouldEndSFTOneOnOneCall( + val shouldEndSFTOneOnOneCall3 = mLSCallHelper.shouldEndSFTOneOnOneCall( conversationId = conversationId, callProtocol = CONVERSATION_MLS_PROTOCOL_INFO, conversationType = Conversation.Type.ONE_ON_ONE, @@ -94,24 +84,36 @@ class MLSCallHelperTest { participantMinimized2.copy(hasEstablishedAudio = false) ) ) - assertTrue { shouldEndSFTOneOnOneCall4 } + assertTrue { shouldEndSFTOneOnOneCall3 } + } - val (_, mLSCallHelper2) = Arrangement() - .withShouldUseSFTForOneOnOneCallsReturning(Either.Left(StorageFailure.DataNotFound)) + @Test + fun givenProteusProtocol_whenShouldEndSFTOneOnOneCallIsCalled_thenReturnCorrectValue() = + runTest { + + val (_, mLSCallHelper) = Arrangement() + .withShouldUseSFTForOneOnOneCallsReturning(Either.Right(true)) .arrange() - // ShouldUseSFTForOneOnOneCalls user config is not found - val shouldEndSFTOneOnOneCall5 = mLSCallHelper2.shouldEndSFTOneOnOneCall( + // participants list has 2 items for the new list and the previous list + val shouldEndSFTOneOnOneCall1 = mLSCallHelper.shouldEndSFTOneOnOneCall( conversationId = conversationId, - callProtocol = CONVERSATION_MLS_PROTOCOL_INFO, + callProtocol = Conversation.ProtocolInfo.Proteus, conversationType = Conversation.Type.ONE_ON_ONE, - previousCallParticipants = listOf(participant1, participant2), - newCallParticipants = listOf( - participantMinimized1, - participantMinimized2.copy(hasEstablishedAudio = false) - ) + newCallParticipants = listOf(participantMinimized1, participantMinimized2), + previousCallParticipants = listOf(participant1, participant2) ) - assertFalse { shouldEndSFTOneOnOneCall5 } + assertFalse { shouldEndSFTOneOnOneCall1 } + + // new participants list has 1 participant + val shouldEndSFTOneOnOneCall2 = mLSCallHelper.shouldEndSFTOneOnOneCall( + conversationId = conversationId, + callProtocol = Conversation.ProtocolInfo.Proteus, + conversationType = Conversation.Type.ONE_ON_ONE, + newCallParticipants = listOf(participantMinimized1), + previousCallParticipants = listOf(participant1, participant2) + ) + assertTrue { shouldEndSFTOneOnOneCall2 } } @Test @@ -129,7 +131,7 @@ class MLSCallHelperTest { coVerify { arrangement.subconversationRepository.deleteRemoteSubConversation(any(), any(), any()) - }.wasInvoked(once) + }.wasInvoked(exactly = once) } @Test @@ -149,11 +151,7 @@ class MLSCallHelperTest { mLSCallHelper.handleCallTermination(conversationId, Conversation.Type.ONE_ON_ONE) coVerify { - arrangement.subconversationRepository.deleteRemoteSubConversation( - eq(conversationId), - any(), - any() - ) + arrangement.subconversationRepository.deleteRemoteSubConversation(any(), any(), any()) }.wasNotInvoked() } @@ -167,8 +165,8 @@ class MLSCallHelperTest { mLSCallHelper.handleCallTermination(conversationId, Conversation.Type.GROUP) coVerify { - arrangement.callRepository.leaveMlsConference(eq(conversationId)) - }.wasInvoked(once) + arrangement.callRepository.leaveMlsConference(any()) + }.wasInvoked(exactly = once) } @Test @@ -182,7 +180,7 @@ class MLSCallHelperTest { coVerify { arrangement.callRepository.leaveMlsConference(eq(conversationId)) - }.wasInvoked(once) + }.wasInvoked(exactly = once) } private class Arrangement { @@ -206,18 +204,13 @@ class MLSCallHelperTest { fun withShouldUseSFTForOneOnOneCallsReturning(result: Either) = apply { - every { - userConfigRepository.shouldUseSFTForOneOnOneCalls() - }.returns(result) + every { userConfigRepository.shouldUseSFTForOneOnOneCalls() }.returns(result) } suspend fun withFetchRemoteSubConversationDetailsReturning(result: Either) = apply { coEvery { - subconversationRepository.fetchRemoteSubConversationDetails( - conversationId, - CALL_SUBCONVERSATION_ID - ) + subconversationRepository.fetchRemoteSubConversationDetails(eq(conversationId), eq(CALL_SUBCONVERSATION_ID)) }.returns(result) } @@ -238,32 +231,32 @@ class MLSCallHelperTest { Instant.parse("2021-03-30T15:36:00.000Z"), cipherSuite = CipherSuite.MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519 ) - val participantMinimized1 = ParticipantMinimized( + val participant1 = Participant( id = QualifiedID("participantId", "participantDomain"), - userId = QualifiedID("participantId", "participantDomain"), clientId = "abcd", + name = "name", isMuted = true, + isSpeaking = false, isCameraOn = false, + avatarAssetId = null, isSharingScreen = false, - hasEstablishedAudio = true + hasEstablishedAudio = true, + accentId = 0 ) - val participantMinimized2 = participantMinimized1.copy( + val participant2 = participant1.copy( id = QualifiedID("participantId2", "participantDomain2"), clientId = "efgh" ) - val participant1 = Participant( + val participantMinimized1 = ParticipantMinimized( id = QualifiedID("participantId", "participantDomain"), + userId = QualifiedID("participantId", "participantDomain"), clientId = "abcd", - name = "name", isMuted = true, - isSpeaking = false, isCameraOn = false, - avatarAssetId = null, isSharingScreen = false, - hasEstablishedAudio = true, - accentId = 0 + hasEstablishedAudio = true ) - val participant2 = participant1.copy( + val participantMinimized2 = participantMinimized1.copy( id = QualifiedID("participantId2", "participantDomain2"), clientId = "efgh" )