From 4271d6abc5a8c0a289f555d6c11d87ed26bbd08b Mon Sep 17 00:00:00 2001 From: Carlos Santos <4a.santos@gmail.com> Date: Mon, 28 Apr 2025 11:55:51 +0200 Subject: [PATCH] test: Add integration tests for deleting recordings and validation checks --- .../api/recordings/delete-recording.test.ts | 148 ++++++++++++++++++ backend/tests/utils/helpers.ts | 10 ++ 2 files changed, 158 insertions(+) create mode 100644 backend/tests/integration/api/recordings/delete-recording.test.ts diff --git a/backend/tests/integration/api/recordings/delete-recording.test.ts b/backend/tests/integration/api/recordings/delete-recording.test.ts new file mode 100644 index 0000000..879db8d --- /dev/null +++ b/backend/tests/integration/api/recordings/delete-recording.test.ts @@ -0,0 +1,148 @@ +import { afterAll, beforeAll, beforeEach, describe, expect, it } from '@jest/globals'; +import { container } from '../../../../src/config'; +import { MeetStorageService } from '../../../../src/services'; +import { expectValidationError, expectValidStartRecordingResponse } from '../../../utils/assertion-helpers'; +import { + deleteAllRecordings, + deleteAllRooms, + deleteRecording, + startRecording, + startTestServer, + stopAllRecordings, + stopRecording +} from '../../../utils/helpers'; +import { setupMultiRecordingsTestContext } from '../../../utils/test-scenarios'; +import { MeetRoom } from '../../../../src/typings/ce'; + +describe('Recording API Tests', () => { + beforeAll(() => { + startTestServer(); + }); + + describe('Delete Recording Tests', () => { + let room: MeetRoom, recordingId: string, moderatorCookie: string; + + beforeEach(async () => { + const testContext = await setupMultiRecordingsTestContext(1, 1, 1, '0s'); + const roomData = testContext.getRoomByIndex(0)!; + + ({ room, recordingId = '', moderatorCookie } = roomData); + }); + + afterAll(async () => { + await stopAllRecordings(moderatorCookie); + await Promise.all([deleteAllRecordings(), deleteAllRooms()]); + }); + + it('should delete a recording successfully', async () => { + // Delete the recording + const deleteResponse = await deleteRecording(recordingId); + expect(deleteResponse.status).toBe(204); + + // Verify that the recording is deleted + const getResponse = await deleteRecording(recordingId); + expect(getResponse.status).toBe(404); + }); + + it('should delete room metadata when deleting the last recording', async () => { + const meetStorageService = container.get(MeetStorageService); + // Create two recordings in the same room + + // Check that the room metadata exists after starting the first recording + let roomMetadata = await meetStorageService.getArchivedRoomMetadata(room.roomId); + expect(roomMetadata).toBeDefined(); + expect(roomMetadata!.moderatorRoomUrl).toContain(room.roomId); + expect(roomMetadata!.publisherRoomUrl).toContain(room.roomId); + + // Generate a new recording + const response = await startRecording(room.roomId, moderatorCookie); + console.log('Start recording response:', response.body); + expectValidStartRecordingResponse(response, room.roomId); + const secondRecordingId = response.body.recordingId; + await stopRecording(secondRecordingId, moderatorCookie); + + // Check that the room metadata still exists after deleteing the first recording + let deleteResponse = await deleteRecording(recordingId!); + expect(deleteResponse.status).toBe(204); + + roomMetadata = await meetStorageService.getArchivedRoomMetadata(room.roomId); + + expect(roomMetadata).toBeDefined(); + expect(roomMetadata!.moderatorRoomUrl).toContain(room.roomId); + expect(roomMetadata!.publisherRoomUrl).toContain(room.roomId); + + // Delete the second recording + deleteResponse = await deleteRecording(secondRecordingId!); + expect(deleteResponse.status).toBe(204); + + // Verify that the room metadata is deleted after deleting the last recording + roomMetadata = await meetStorageService.getArchivedRoomMetadata(room.roomId); + expect(roomMetadata).toBe(null); + }); + }); + + describe('Delete Recording Validation', () => { + let room: MeetRoom, recordingId: string, moderatorCookie: string; + beforeAll(async () => { + await deleteAllRecordings(); + const testContext = await setupMultiRecordingsTestContext(1, 1, 1, '0s'); + const roomData = testContext.getRoomByIndex(0)!; + + ({ room, recordingId = '', moderatorCookie } = roomData); + }); + + afterAll(async () => { + await stopAllRecordings(moderatorCookie); + await Promise.all([deleteAllRecordings(), deleteAllRooms()]); + }); + it('should fail when recordingId has incorrect format', async () => { + const response = await deleteRecording('incorrect-format'); + expectValidationError(response, 'recordingId', 'does not follow the expected format'); + }); + + it('should fail when recordingId has less than 3 parts', async () => { + const response = await deleteRecording('part1--part2'); + expectValidationError(response, 'recordingId', 'does not follow the expected format'); + }); + + it('should fail when recordingId first part is empty', async () => { + const response = await deleteRecording('--EG_12345--uid'); + expectValidationError(response, 'recordingId', 'does not follow the expected format'); + }); + + it('should fail when recordingId second part does not start with EG_', async () => { + const response = await deleteRecording(`${room.roomId}--INVALID--uid`); + expectValidationError(response, 'recordingId', 'does not follow the expected format'); + }); + + it('should fail when recordingId second part is too short', async () => { + const response = await deleteRecording(`${room.roomId}--EG_--uid`); + expectValidationError(response, 'recordingId', 'does not follow the expected format'); + }); + + it('should fail when recordingId third part is empty', async () => { + const response = await deleteRecording(`${room.roomId}--EG_12345--`); + expectValidationError(response, 'recordingId', 'does not follow the expected format'); + }); + + it('should sanitize recordingId before validation', async () => { + const response = await deleteRecording(` ${recordingId} `); + expect(response.status).toBe(204); + expect(response.body).toStrictEqual({}); + }); + + it('should return 409 when attempting to delete an active recording', async () => { + const testContext = await setupMultiRecordingsTestContext(1, 1, 0, '0s'); + const { recordingId: activeRecordingId = '', moderatorCookie } = testContext.rooms[0]; + + // Attempt to delete the active recording + let deleteResponse = await deleteRecording(activeRecordingId); + expect(deleteResponse.status).toBe(409); + + await stopRecording(activeRecordingId, moderatorCookie); + // Attempt to delete the recording again + deleteResponse = await deleteRecording(activeRecordingId); + expect(deleteResponse.status).toBe(204); + }); + }); +}); diff --git a/backend/tests/utils/helpers.ts b/backend/tests/utils/helpers.ts index fcef7b7..fe981e1 100644 --- a/backend/tests/utils/helpers.ts +++ b/backend/tests/utils/helpers.ts @@ -364,6 +364,16 @@ export const getRecording = async (recordingId: string) => { .set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_API_KEY); }; +export const deleteRecording = async (recordingId: string) => { + if (!app) { + throw new Error('App instance is not defined'); + } + + return await request(app) + .delete(`${INTERNAL_CONFIG.API_BASE_PATH_V1}/recordings/${recordingId}`) + .set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_API_KEY); +} + export const stopAllRecordings = async (moderatorCookie: string) => { if (!app) { throw new Error('App instance is not defined');