From 5b7d9da5e3a744eba6d246532580155e76a12641 Mon Sep 17 00:00:00 2001 From: PatrykBuniX Date: Wed, 11 Oct 2023 13:19:55 +0200 Subject: [PATCH 1/2] runfix: leave mls conversation --- src/script/conversation/ConversationRepository.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/script/conversation/ConversationRepository.ts b/src/script/conversation/ConversationRepository.ts index 29777e49441..359c3d30997 100644 --- a/src/script/conversation/ConversationRepository.ts +++ b/src/script/conversation/ConversationRepository.ts @@ -1742,9 +1742,13 @@ export class ConversationRepository { */ public async leaveConversation(conversation: Conversation, {localOnly = false} = {}) { const userQualifiedId = this.userState.self().qualifiedId; - return localOnly - ? this.removeMembersLocally(conversation, [userQualifiedId]) - : this.removeMembers(conversation, [userQualifiedId]); + + if (localOnly) { + return this.removeMembersLocally(conversation, [userQualifiedId]); + } + + const events = await this.removeMembersFromConversation(conversation, [userQualifiedId]); + await this.eventRepository.injectEvents(events, EventRepository.SOURCE.BACKEND_RESPONSE); } /** From 6c93d8dd325a069dc6aeb0512c94e7e0cd5d6f0d Mon Sep 17 00:00:00 2001 From: PatrykBuniX Date: Wed, 11 Oct 2023 13:34:15 +0200 Subject: [PATCH 2/2] test: remove/leave conversation --- src/__mocks__/@wireapp/core.ts | 2 + .../ConversationRepository.test.ts | 108 +++++++++++++++++- 2 files changed, 109 insertions(+), 1 deletion(-) diff --git a/src/__mocks__/@wireapp/core.ts b/src/__mocks__/@wireapp/core.ts index 560cb162c5e..019c155509f 100644 --- a/src/__mocks__/@wireapp/core.ts +++ b/src/__mocks__/@wireapp/core.ts @@ -59,6 +59,8 @@ export class Account extends EventEmitter { messageTimer: { setConversationLevelTimer: jest.fn(), }, + removeUsersFromMLSConversation: jest.fn(), + removeUserFromConversation: jest.fn(), }, client: { diff --git a/src/script/conversation/ConversationRepository.test.ts b/src/script/conversation/ConversationRepository.test.ts index 5de905b0e1d..71ddfe523a5 100644 --- a/src/script/conversation/ConversationRepository.test.ts +++ b/src/script/conversation/ConversationRepository.test.ts @@ -29,7 +29,12 @@ import { } from '@wireapp/api-client/lib/conversation'; import {RECEIPT_MODE} from '@wireapp/api-client/lib/conversation/data'; import {ConversationProtocol} from '@wireapp/api-client/lib/conversation/NewConversation'; -import {ConversationCreateEvent, ConversationMemberJoinEvent, CONVERSATION_EVENT} from '@wireapp/api-client/lib/event/'; +import { + ConversationMemberLeaveEvent, + ConversationCreateEvent, + ConversationMemberJoinEvent, + CONVERSATION_EVENT, +} from '@wireapp/api-client/lib/event/'; import {QualifiedId} from '@wireapp/api-client/lib/user'; import {amplify} from 'amplify'; import {StatusCodes as HTTP_STATUS} from 'http-status-codes'; @@ -1540,4 +1545,105 @@ describe('ConversationRepository', () => { expect(conversationRepo['refreshAllConversationsUnavailableParticipants']).toHaveBeenCalled(); }); }); + + describe('removeMembers', () => { + it.each([ConversationProtocol.PROTEUS, ConversationProtocol.MIXED])( + 'should remove member from %s conversation', + async protocol => { + const conversationRepository = await testFactory.exposeConversationActors(); + + const conversation = _generateConversation({protocol}); + + const selfUser = generateUser(); + conversation.selfUser(selfUser); + + const user1 = generateUser(); + const user2 = generateUser(); + + conversation.participating_user_ets([user1, user2]); + + const coreConversationService = container.resolve(Core).service!.conversation; + + jest.spyOn(conversationRepository['eventRepository'], 'injectEvent').mockImplementation(jest.fn()); + + await conversationRepository.removeMembers(conversation, [user1.qualifiedId]); + + expect(coreConversationService.removeUserFromConversation).toHaveBeenCalledWith( + conversation.qualifiedId, + user1.qualifiedId, + ); + }, + ); + + it('should remove member from mls conversation', async () => { + const conversationRepository = await testFactory.exposeConversationActors(); + + const conversation = _generateConversation({protocol: ConversationProtocol.MLS}); + + const selfUser = generateUser(); + conversation.selfUser(selfUser); + + const user1 = generateUser(); + const user2 = generateUser(); + + conversation.participating_user_ets([user1, user2]); + + const coreConversationService = container.resolve(Core).service!.conversation; + + jest.spyOn(conversationRepository['eventRepository'], 'injectEvent').mockImplementation(jest.fn()); + + const mockedMemberLeaveEvent: ConversationMemberLeaveEvent = { + conversation: conversation.id, + data: {qualified_user_ids: [], user_ids: []}, + from: '', + time: '', + type: CONVERSATION_EVENT.MEMBER_LEAVE, + }; + jest + .spyOn(coreConversationService, 'removeUsersFromMLSConversation') + .mockResolvedValueOnce({events: [mockedMemberLeaveEvent], conversation: {} as BackendConversation}); + await conversationRepository.removeMembers(conversation, [user1.qualifiedId]); + + expect(coreConversationService.removeUsersFromMLSConversation).toHaveBeenCalledWith({ + conversationId: conversation.qualifiedId, + qualifiedUserIds: [user1.qualifiedId], + groupId: conversation.groupId, + }); + expect(conversationRepository['eventRepository'].injectEvent).toHaveBeenCalled(); + }); + }); + + describe('leaveConversation', () => { + afterEach(() => { + jest.clearAllMocks(); + }); + + it.each([ConversationProtocol.PROTEUS, ConversationProtocol.MIXED, ConversationProtocol.MLS])( + 'should leave %s conversation', + async protocol => { + const conversationRepository = await testFactory.exposeConversationActors(); + + const conversation = _generateConversation({protocol}); + + const selfUser = generateUser(); + conversation.selfUser(selfUser); + + spyOn(conversationRepository['userState'], 'self').and.returnValue(selfUser); + + conversation.participating_user_ets([generateUser(), generateUser()]); + + const coreConversationService = container.resolve(Core).service!.conversation; + + jest.spyOn(conversationRepository['eventRepository'], 'injectEvent').mockImplementation(jest.fn()); + + await conversationRepository.leaveConversation(conversation); + + expect(coreConversationService.removeUserFromConversation).toHaveBeenCalledWith( + conversation.qualifiedId, + selfUser.qualifiedId, + ); + expect(conversationRepository['eventRepository'].injectEvent).toHaveBeenCalled(); + }, + ); + }); });