From 5d8bc31717d6435edf117f7a697a0d7c2319bbb4 Mon Sep 17 00:00:00 2001 From: kakiba <97882386+kotto5@users.noreply.github.com> Date: Tue, 23 Jan 2024 11:05:51 +0900 Subject: [PATCH] invite-deny event (#226) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [backend] Add deny-pong event handler to ChatGateway * [backend] [test] mute する長さと、それを待つための setTimeout の長さに依存関係を作った (muteTime) --- backend/src/chat/chat.gateway.ts | 23 ++++++ backend/test/chat-gateway.e2e-spec.ts | 105 +++++++++++++++++++++----- 2 files changed, 111 insertions(+), 17 deletions(-) diff --git a/backend/src/chat/chat.gateway.ts b/backend/src/chat/chat.gateway.ts index a5015958..76fccf93 100644 --- a/backend/src/chat/chat.gateway.ts +++ b/backend/src/chat/chat.gateway.ts @@ -121,6 +121,29 @@ export class ChatGateway { } } + @SubscribeMessage('deny-pong') + handleDenyPong( + @MessageBody() data: { userId: number }, + @ConnectedSocket() client: Socket, + ) { + const deniedUserWsId = this.chatService.getWsFromUserId(data.userId)?.id; + if (!deniedUserWsId) { + return; + } else { + if ( + this.chatService.getInvite(data.userId) !== + this.chatService.getUserId(client) + ) { + this.server + .to(client.id) + .emit('error-pong', 'No pending invite found.'); + return; + } + this.server.to(deniedUserWsId).emit('deny-pong'); + this.chatService.removeInvite(data.userId); + } + } + @OnEvent('room.leave', { async: true }) async handleLeave(event: RoomLeftEvent) { this.server.in(event.roomId.toString()).emit('leave', event); diff --git a/backend/test/chat-gateway.e2e-spec.ts b/backend/test/chat-gateway.e2e-spec.ts index 0e71084d..8dc26087 100644 --- a/backend/test/chat-gateway.e2e-spec.ts +++ b/backend/test/chat-gateway.e2e-spec.ts @@ -31,6 +31,7 @@ describe('ChatGateway and ChatController (e2e)', () => { kickedUser1, bannedUser1, mutedUser1; + const waitTime = 500; beforeAll(async () => { //app = await initializeApp(); @@ -307,7 +308,7 @@ describe('ChatGateway and ChatController (e2e)', () => { ws1.off('message'); ws2.off('message'); done(); - }, 3000); + }, waitTime); }); it('user1 and user2 block blockedUser2', async () => { @@ -339,7 +340,7 @@ describe('ChatGateway and ChatController (e2e)', () => { ws1.off('message'); ws2.off('message'); done(); - }, 3000); + }, waitTime); }); it('user1 should get all messages except from blockedUser1 and blockedUser2 in the room', async () => { @@ -558,7 +559,7 @@ describe('ChatGateway and ChatController (e2e)', () => { ws1.off('message'); ws2.off('message'); done(); - }, 3000); + }, waitTime); }); it('user1 should get all messages except from kickedUser1 in the room', async () => { @@ -647,7 +648,7 @@ describe('ChatGateway and ChatController (e2e)', () => { expect(mockMessage).not.toBeCalled(); ws5.off('message'); done(); - }, 3000); + }, waitTime); }); }); @@ -678,7 +679,7 @@ describe('ChatGateway and ChatController (e2e)', () => { ws1.off('message'); ws2.off('message'); done(); - }, 3000); + }, waitTime); }); it('user1 should get all messages except from bannedUser1 in the room', async () => { @@ -777,7 +778,7 @@ describe('ChatGateway and ChatController (e2e)', () => { expect(mockMessage).not.toBeCalled(); ws6.off('message'); done(); - }, 3000); + }, waitTime); }); }); }); @@ -809,9 +810,11 @@ describe('ChatGateway and ChatController (e2e)', () => { await app.enterRoom(room.id, mutedUser1.accessToken).expect(201); }); + const muteTime = 1; + it('user1 mutes mutedUser1', async () => { await app - .muteUser(room.id, mutedUser1.id, user1.accessToken, 3) + .muteUser(room.id, mutedUser1.id, user1.accessToken, muteTime) .expect(200); }); @@ -851,12 +854,12 @@ describe('ChatGateway and ChatController (e2e)', () => { ws5.off('message'); ws6.off('message'); done(); - }, 3000); + }, waitTime); }); let ctx6: Promise; it('setup promises to recv messages from mutedUser1 after the duration', async () => { - await new Promise((r) => setTimeout(r, 4000)); + await new Promise((r) => setTimeout(r, muteTime * 1000)); // Wait for mute duration const expected: MessageEntity = { user: { id: mutedUser1.id, @@ -940,7 +943,7 @@ describe('ChatGateway and ChatController (e2e)', () => { ws5.off('message'); ws6.off('message'); done(); - }, 3000); + }, waitTime); }); it('user1 unmutes mutedUser1', async () => { @@ -1106,7 +1109,7 @@ describe('ChatGateway and ChatController (e2e)', () => { setTimeout(() => { expect(mockCallback).not.toBeCalled(); resolve(); - }, 1000), + }, waitTime), )); }); // TODO: block してるuser から invite されるケース @@ -1145,7 +1148,7 @@ describe('ChatGateway and ChatController (e2e)', () => { setTimeout(async () => { expect(mockCallback).not.toHaveBeenCalled(); resolve(); - }, 500), + }, waitTime), )); }); describe('invite -> cancel -> invite', () => { @@ -1174,7 +1177,7 @@ describe('ChatGateway and ChatController (e2e)', () => { setTimeout(() => { expect(mockCallback).toHaveBeenCalledTimes(2); resolve(); - }, 1000), + }, waitTime), )); }); }); @@ -1227,7 +1230,7 @@ describe('ChatGateway and ChatController (e2e)', () => { setTimeout(() => { expect(mockCallback1).not.toBeCalled(); resolve(); - }, 1000), + }, waitTime), )); }); describe('failure case', () => { @@ -1258,7 +1261,7 @@ describe('ChatGateway and ChatController (e2e)', () => { expect(mockCallback1).not.toHaveBeenCalled(); expect(mockCallback2).not.toHaveBeenCalled(); resolve(); - }, 1000), + }, waitTime), )); }); describe('invite -> cancel -> approve: dose not match', () => { @@ -1287,7 +1290,7 @@ describe('ChatGateway and ChatController (e2e)', () => { listener.ws.emit('approve-pong', { userId: data.userId, }); - }, 100); + }, waitTime); }); }); it('user should not receive match message from canceled invite user', () => @@ -1296,7 +1299,75 @@ describe('ChatGateway and ChatController (e2e)', () => { expect(mockToMatchByEmitter).not.toHaveBeenCalled(); expect(mockToMatchByListener).not.toHaveBeenCalled(); resolve(); - }, 1000), + }, waitTime), + )); + }); + }); + describe('deny invite', () => { + describe('success case', () => { + const mockCallback1 = jest.fn(); + const mockCallback2 = jest.fn(); + let ctxToDeny: Promise; + + beforeAll(() => { + const inviter = userAndSockets[0]; + const invitee = userAndSockets[1]; + const notInvited1 = userAndSockets[2]; + + notInvited1.ws.on('invite-pong', mockCallback1); + notInvited1.ws.on('deny-pong', mockCallback1); + + const promiseToInvite = new Promise((resolve) => + invitee.ws.on('invite-pong', (data) => resolve(data)), + ); + inviter.ws.emit('invite-pong', { + userId: invitee.user.id, + }); + ctxToDeny = new Promise((resolve) => + inviter.ws.on('deny-pong', (data) => resolve(data)), + ); + return promiseToInvite.then((data) => { + invitee.ws.emit('deny-pong', { + userId: data.userId, + }); + }); + }); + it('invite user should receive an error', () => ctxToDeny); + it('unrelated user should not receive any messages', () => + new Promise((resolve) => + setTimeout(() => { + expect(mockCallback1).not.toHaveBeenCalled(); + expect(mockCallback2).not.toHaveBeenCalled(); + resolve(); + }, waitTime), + )); + }); + describe('failure case', () => { + const mockCallback1 = jest.fn(); + const mockCallback2 = jest.fn(); + let errorCtx: Promise; + + beforeAll(() => { + const emitter = userAndSockets[0]; + const listener = userAndSockets[1]; + + listener.ws.on('error-pong', mockCallback2); + emitter.ws.emit('deny-pong', { + userId: listener.user.id, + }); + errorCtx = new Promise((resolve) => + emitter.ws.on('error-pong', (data) => resolve(data)), + ); + }); + it('should receive an error when denying without an existing invite', () => + errorCtx); + it('user should not receive deny message from not invite user', () => + new Promise((resolve) => + setTimeout(() => { + expect(mockCallback1).not.toHaveBeenCalled(); + expect(mockCallback2).not.toHaveBeenCalled(); + resolve(); + }, waitTime), )); }); });