tests: update tests to reflect code changes and add test cases for update room status endpoint
This commit is contained in:
parent
1dd8cc3238
commit
2bea178e76
@ -3,11 +3,16 @@ import { container } from '../../src/config/dependency-injector.config';
|
|||||||
import INTERNAL_CONFIG from '../../src/config/internal-config';
|
import INTERNAL_CONFIG from '../../src/config/internal-config';
|
||||||
import { TokenService } from '../../src/services';
|
import { TokenService } from '../../src/services';
|
||||||
import {
|
import {
|
||||||
|
MeetingEndAction,
|
||||||
MeetRecordingAccess,
|
MeetRecordingAccess,
|
||||||
MeetRecordingInfo,
|
MeetRecordingInfo,
|
||||||
MeetRecordingStatus,
|
MeetRecordingStatus,
|
||||||
MeetRoom,
|
MeetRoom,
|
||||||
|
MeetRoomAutoDeletionPolicy,
|
||||||
|
MeetRoomDeletionPolicyWithMeeting,
|
||||||
|
MeetRoomDeletionPolicyWithRecordings,
|
||||||
MeetRoomPreferences,
|
MeetRoomPreferences,
|
||||||
|
MeetRoomStatus,
|
||||||
ParticipantPermissions,
|
ParticipantPermissions,
|
||||||
ParticipantRole
|
ParticipantRole
|
||||||
} from '../../src/typings/ce';
|
} from '../../src/typings/ce';
|
||||||
@ -91,7 +96,7 @@ export const expectSuccessRoomResponse = (
|
|||||||
preferences?: MeetRoomPreferences
|
preferences?: MeetRoomPreferences
|
||||||
) => {
|
) => {
|
||||||
expect(response.status).toBe(200);
|
expect(response.status).toBe(200);
|
||||||
expectValidRoom(response.body, roomName, autoDeletionDate, preferences);
|
expectValidRoom(response.body, roomName, preferences, autoDeletionDate);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const expectSuccessRoomPreferencesResponse = (response: any, preferences: MeetRoomPreferences) => {
|
export const expectSuccessRoomPreferencesResponse = (response: any, preferences: MeetRoomPreferences) => {
|
||||||
@ -103,9 +108,11 @@ export const expectSuccessRoomPreferencesResponse = (response: any, preferences:
|
|||||||
export const expectValidRoom = (
|
export const expectValidRoom = (
|
||||||
room: MeetRoom,
|
room: MeetRoom,
|
||||||
name: string,
|
name: string,
|
||||||
autoDeletionDate?: number,
|
|
||||||
preferences?: MeetRoomPreferences,
|
preferences?: MeetRoomPreferences,
|
||||||
markedForDeletion?: boolean
|
autoDeletionDate?: number,
|
||||||
|
autoDeletionPolicy?: MeetRoomAutoDeletionPolicy,
|
||||||
|
status?: MeetRoomStatus,
|
||||||
|
meetingEndAction?: MeetingEndAction
|
||||||
) => {
|
) => {
|
||||||
expect(room).toBeDefined();
|
expect(room).toBeDefined();
|
||||||
|
|
||||||
@ -123,6 +130,16 @@ export const expectValidRoom = (
|
|||||||
expect(room.autoDeletionDate).toBeUndefined();
|
expect(room.autoDeletionDate).toBeUndefined();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (autoDeletionPolicy !== undefined) {
|
||||||
|
expect(room.autoDeletionPolicy).toBeDefined();
|
||||||
|
expect(room.autoDeletionPolicy).toEqual(autoDeletionPolicy);
|
||||||
|
} else {
|
||||||
|
expect(room.autoDeletionPolicy).toEqual({
|
||||||
|
withMeeting: MeetRoomDeletionPolicyWithMeeting.WHEN_MEETING_ENDS,
|
||||||
|
withRecordings: MeetRoomDeletionPolicyWithRecordings.CLOSE
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
expect(room.preferences).toBeDefined();
|
expect(room.preferences).toBeDefined();
|
||||||
|
|
||||||
if (preferences !== undefined) {
|
if (preferences !== undefined) {
|
||||||
@ -143,11 +160,10 @@ export const expectValidRoom = (
|
|||||||
expect(room.moderatorUrl).toContain(room.roomId);
|
expect(room.moderatorUrl).toContain(room.roomId);
|
||||||
expect(room.speakerUrl).toContain(room.roomId);
|
expect(room.speakerUrl).toContain(room.roomId);
|
||||||
|
|
||||||
if (markedForDeletion !== undefined) {
|
expect(room.status).toBeDefined();
|
||||||
expect(room.autoDeletionDate).toBeDefined();
|
expect(room.status).toEqual(status || MeetRoomStatus.OPEN);
|
||||||
|
expect(room.meetingEndAction).toBeDefined();
|
||||||
expect(room.markedForDeletion).toBe(markedForDeletion ?? false);
|
expect(room.meetingEndAction).toEqual(meetingEndAction || MeetingEndAction.NONE);
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const expectValidRecording = (
|
export const expectValidRecording = (
|
||||||
|
|||||||
@ -22,6 +22,8 @@ import {
|
|||||||
MeetRecordingInfo,
|
MeetRecordingInfo,
|
||||||
MeetRecordingStatus,
|
MeetRecordingStatus,
|
||||||
MeetRoom,
|
MeetRoom,
|
||||||
|
MeetRoomDeletionPolicyWithMeeting,
|
||||||
|
MeetRoomDeletionPolicyWithRecordings,
|
||||||
MeetRoomOptions,
|
MeetRoomOptions,
|
||||||
ParticipantRole,
|
ParticipantRole,
|
||||||
WebhookPreferences
|
WebhookPreferences
|
||||||
@ -244,20 +246,18 @@ export const getRoom = async (roomId: string, fields?: string, cookie?: string,
|
|||||||
export const getRoomPreferences = async (roomId: string) => {
|
export const getRoomPreferences = async (roomId: string) => {
|
||||||
checkAppIsRunning();
|
checkAppIsRunning();
|
||||||
|
|
||||||
const adminCookie = await loginUser();
|
|
||||||
return await request(app)
|
return await request(app)
|
||||||
.get(`${INTERNAL_CONFIG.API_BASE_PATH_V1}/rooms/${roomId}/preferences`)
|
.get(`${INTERNAL_CONFIG.API_BASE_PATH_V1}/rooms/${roomId}/preferences`)
|
||||||
.set('Cookie', adminCookie)
|
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY)
|
||||||
.send();
|
.send();
|
||||||
};
|
};
|
||||||
|
|
||||||
export const updateRoomPreferences = async (roomId: string, preferences: any) => {
|
export const updateRoomPreferences = async (roomId: string, preferences: any) => {
|
||||||
checkAppIsRunning();
|
checkAppIsRunning();
|
||||||
|
|
||||||
const adminCookie = await loginUser();
|
|
||||||
return await request(app)
|
return await request(app)
|
||||||
.put(`${INTERNAL_CONFIG.API_BASE_PATH_V1}/rooms/${roomId}/preferences`)
|
.put(`${INTERNAL_CONFIG.API_BASE_PATH_V1}/rooms/${roomId}/preferences`)
|
||||||
.set('Cookie', adminCookie)
|
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY)
|
||||||
.send({ preferences });
|
.send({ preferences });
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -277,6 +277,15 @@ export const updateRecordingAccessPreferencesInRoom = async (roomId: string, rec
|
|||||||
expect(response.status).toBe(200);
|
expect(response.status).toBe(200);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const updateRoomStatus = async (roomId: string, status: string) => {
|
||||||
|
checkAppIsRunning();
|
||||||
|
|
||||||
|
return await request(app)
|
||||||
|
.put(`${INTERNAL_CONFIG.API_BASE_PATH_V1}/rooms/${roomId}/status`)
|
||||||
|
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY)
|
||||||
|
.send({ status });
|
||||||
|
};
|
||||||
|
|
||||||
export const deleteRoom = async (roomId: string, query: Record<string, any> = {}) => {
|
export const deleteRoom = async (roomId: string, query: Record<string, any> = {}) => {
|
||||||
checkAppIsRunning();
|
checkAppIsRunning();
|
||||||
|
|
||||||
@ -288,13 +297,17 @@ export const deleteRoom = async (roomId: string, query: Record<string, any> = {}
|
|||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const bulkDeleteRooms = async (roomIds: any[], force?: any) => {
|
export const bulkDeleteRooms = async (
|
||||||
|
roomIds: any[],
|
||||||
|
withMeeting?: string,
|
||||||
|
withRecordings?: string
|
||||||
|
) => {
|
||||||
checkAppIsRunning();
|
checkAppIsRunning();
|
||||||
|
|
||||||
const result = await request(app)
|
const result = await request(app)
|
||||||
.delete(`${INTERNAL_CONFIG.API_BASE_PATH_V1}/rooms`)
|
.delete(`${INTERNAL_CONFIG.API_BASE_PATH_V1}/rooms`)
|
||||||
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY)
|
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY)
|
||||||
.query({ roomIds: roomIds.join(','), force });
|
.query({ roomIds: roomIds.join(','), withMeeting, withRecordings });
|
||||||
await sleep('1s');
|
await sleep('1s');
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
@ -305,11 +318,8 @@ export const deleteAllRooms = async () => {
|
|||||||
let nextPageToken: string | undefined;
|
let nextPageToken: string | undefined;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
const response: any = await request(app)
|
const response = await getRooms({ fields: 'roomId', maxItems: 100, nextPageToken });
|
||||||
.get(`${INTERNAL_CONFIG.API_BASE_PATH_V1}/rooms`)
|
expect(response.status).toBe(200);
|
||||||
.query({ fields: 'roomId', maxItems: 100, nextPageToken })
|
|
||||||
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY)
|
|
||||||
.expect(200);
|
|
||||||
|
|
||||||
nextPageToken = response.body.pagination?.nextPageToken ?? undefined;
|
nextPageToken = response.body.pagination?.nextPageToken ?? undefined;
|
||||||
const roomIds = response.body.rooms.map((room: { roomId: string }) => room.roomId);
|
const roomIds = response.body.rooms.map((room: { roomId: string }) => room.roomId);
|
||||||
@ -318,13 +328,12 @@ export const deleteAllRooms = async () => {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
await request(app)
|
await bulkDeleteRooms(
|
||||||
.delete(`${INTERNAL_CONFIG.API_BASE_PATH_V1}/rooms`)
|
roomIds,
|
||||||
.query({ roomIds: roomIds.join(','), force: true })
|
MeetRoomDeletionPolicyWithMeeting.FORCE,
|
||||||
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY);
|
MeetRoomDeletionPolicyWithRecordings.FORCE
|
||||||
|
);
|
||||||
} while (nextPageToken);
|
} while (nextPageToken);
|
||||||
|
|
||||||
await sleep('1s');
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -339,6 +348,7 @@ export const runRoomGarbageCollector = async () => {
|
|||||||
|
|
||||||
const roomService = container.get(RoomService);
|
const roomService = container.get(RoomService);
|
||||||
await (roomService as any)['deleteExpiredRooms']();
|
await (roomService as any)['deleteExpiredRooms']();
|
||||||
|
await sleep('1s');
|
||||||
};
|
};
|
||||||
|
|
||||||
export const runReleaseActiveRecordingLock = async (roomId: string) => {
|
export const runReleaseActiveRecordingLock = async (roomId: string) => {
|
||||||
@ -547,7 +557,7 @@ export const updateParticipant = async (
|
|||||||
return response;
|
return response;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const deleteParticipant = async (roomId: string, participantIdentity: string, moderatorCookie: string) => {
|
export const kickParticipant = async (roomId: string, participantIdentity: string, moderatorCookie: string) => {
|
||||||
checkAppIsRunning();
|
checkAppIsRunning();
|
||||||
|
|
||||||
const response = await request(app)
|
const response = await request(app)
|
||||||
|
|||||||
@ -71,8 +71,8 @@ describe('Meetings API Tests', () => {
|
|||||||
|
|
||||||
it('should fail with 404 if the room does not exist', async () => {
|
it('should fail with 404 if the room does not exist', async () => {
|
||||||
// Delete the room to ensure it does not exist
|
// Delete the room to ensure it does not exist
|
||||||
let response = await deleteRoom(roomData.room.roomId, { force: true });
|
let response = await deleteRoom(roomData.room.roomId, { withMeeting: 'force' });
|
||||||
expect(response.status).toBe(204);
|
expect(response.status).toBe(200);
|
||||||
|
|
||||||
response = await endMeeting(roomData.room.roomId, roomData.moderatorCookie);
|
response = await endMeeting(roomData.room.roomId, roomData.moderatorCookie);
|
||||||
expect(response.status).toBe(404);
|
expect(response.status).toBe(404);
|
||||||
|
|||||||
@ -4,9 +4,9 @@ import { OpenViduMeetError } from '../../../../src/models/error.model.js';
|
|||||||
import { LiveKitService } from '../../../../src/services/index.js';
|
import { LiveKitService } from '../../../../src/services/index.js';
|
||||||
import {
|
import {
|
||||||
deleteAllRooms,
|
deleteAllRooms,
|
||||||
deleteParticipant,
|
|
||||||
deleteRoom,
|
deleteRoom,
|
||||||
disconnectFakeParticipants,
|
disconnectFakeParticipants,
|
||||||
|
kickParticipant,
|
||||||
startTestServer
|
startTestServer
|
||||||
} from '../../../helpers/request-helpers.js';
|
} from '../../../helpers/request-helpers.js';
|
||||||
import { RoomData, setupSingleRoom } from '../../../helpers/test-scenarios.js';
|
import { RoomData, setupSingleRoom } from '../../../helpers/test-scenarios.js';
|
||||||
@ -27,19 +27,19 @@ describe('Meetings API Tests', () => {
|
|||||||
await deleteAllRooms();
|
await deleteAllRooms();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Delete Participant Tests', () => {
|
describe('Kick Participant Tests', () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
roomData = await setupSingleRoom(true);
|
roomData = await setupSingleRoom(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should remove participant from LiveKit room', async () => {
|
it('should kick participant from LiveKit room', async () => {
|
||||||
// Check if participant exists before deletion
|
// Check if participant exists before deletion
|
||||||
const participant = await livekitService.getParticipant(roomData.room.roomId, participantIdentity);
|
const participant = await livekitService.getParticipant(roomData.room.roomId, participantIdentity);
|
||||||
expect(participant).toBeDefined();
|
expect(participant).toBeDefined();
|
||||||
expect(participant.identity).toBe(participantIdentity);
|
expect(participant.identity).toBe(participantIdentity);
|
||||||
|
|
||||||
// Delete the participant
|
// Delete the participant
|
||||||
const response = await deleteParticipant(roomData.room.roomId, participantIdentity, roomData.moderatorCookie);
|
const response = await kickParticipant(roomData.room.roomId, participantIdentity, roomData.moderatorCookie);
|
||||||
expect(response.status).toBe(200);
|
expect(response.status).toBe(200);
|
||||||
|
|
||||||
// Check if the participant has been removed from LiveKit
|
// Check if the participant has been removed from LiveKit
|
||||||
@ -51,7 +51,7 @@ describe('Meetings API Tests', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should fail with 404 if participant does not exist', async () => {
|
it('should fail with 404 if participant does not exist', async () => {
|
||||||
const response = await deleteParticipant(
|
const response = await kickParticipant(
|
||||||
roomData.room.roomId,
|
roomData.room.roomId,
|
||||||
'NON_EXISTENT_PARTICIPANT',
|
'NON_EXISTENT_PARTICIPANT',
|
||||||
roomData.moderatorCookie
|
roomData.moderatorCookie
|
||||||
@ -62,10 +62,10 @@ describe('Meetings API Tests', () => {
|
|||||||
|
|
||||||
it('should fail with 404 if room does not exist', async () => {
|
it('should fail with 404 if room does not exist', async () => {
|
||||||
// Delete the room to ensure it does not exist
|
// Delete the room to ensure it does not exist
|
||||||
let response = await deleteRoom(roomData.room.roomId, { force: true });
|
let response = await deleteRoom(roomData.room.roomId, { withMeeting: 'force' });
|
||||||
expect(response.status).toBe(204);
|
expect(response.status).toBe(200);
|
||||||
|
|
||||||
response = await deleteParticipant(roomData.room.roomId, participantIdentity, roomData.moderatorCookie);
|
response = await kickParticipant(roomData.room.roomId, participantIdentity, roomData.moderatorCookie);
|
||||||
expect(response.status).toBe(404);
|
expect(response.status).toBe(404);
|
||||||
expect(response.body.error).toBe('Room Error');
|
expect(response.body.error).toBe('Room Error');
|
||||||
});
|
});
|
||||||
@ -141,8 +141,8 @@ describe('Meetings API Tests', () => {
|
|||||||
|
|
||||||
it('should fail with 404 if room does not exist', async () => {
|
it('should fail with 404 if room does not exist', async () => {
|
||||||
// Delete the room to ensure it does not exist
|
// Delete the room to ensure it does not exist
|
||||||
let response = await deleteRoom(roomData.room.roomId, { force: true });
|
let response = await deleteRoom(roomData.room.roomId, { withMeeting: 'force' });
|
||||||
expect(response.status).toBe(204);
|
expect(response.status).toBe(200);
|
||||||
|
|
||||||
response = await updateParticipant(
|
response = await updateParticipant(
|
||||||
roomData.room.roomId,
|
roomData.room.roomId,
|
||||||
|
|||||||
@ -4,9 +4,11 @@ import { expectValidationError, expectValidParticipantTokenResponse } from '../.
|
|||||||
import {
|
import {
|
||||||
deleteAllRooms,
|
deleteAllRooms,
|
||||||
disconnectFakeParticipants,
|
disconnectFakeParticipants,
|
||||||
|
endMeeting,
|
||||||
generateParticipantToken,
|
generateParticipantToken,
|
||||||
generateParticipantTokenCookie,
|
generateParticipantTokenCookie,
|
||||||
startTestServer
|
startTestServer,
|
||||||
|
updateRoomStatus
|
||||||
} from '../../../helpers/request-helpers.js';
|
} from '../../../helpers/request-helpers.js';
|
||||||
import { RoomData, setupSingleRoom } from '../../../helpers/test-scenarios.js';
|
import { RoomData, setupSingleRoom } from '../../../helpers/test-scenarios.js';
|
||||||
|
|
||||||
@ -125,6 +127,17 @@ describe('Participant API Tests', () => {
|
|||||||
roomData = await setupSingleRoom();
|
roomData = await setupSingleRoom();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should fail with 409 when room is closed', async () => {
|
||||||
|
await endMeeting(roomData.room.roomId, roomData.moderatorCookie);
|
||||||
|
await updateRoomStatus(roomData.room.roomId, 'closed');
|
||||||
|
const response = await generateParticipantToken({
|
||||||
|
roomId: roomData.room.roomId,
|
||||||
|
secret: roomData.moderatorSecret,
|
||||||
|
participantName
|
||||||
|
});
|
||||||
|
expect(response.status).toBe(409);
|
||||||
|
});
|
||||||
|
|
||||||
it('should fail with 404 when room does not exist', async () => {
|
it('should fail with 404 when room does not exist', async () => {
|
||||||
const response = await generateParticipantToken({
|
const response = await generateParticipantToken({
|
||||||
roomId: 'non_existent_room',
|
roomId: 'non_existent_room',
|
||||||
|
|||||||
@ -30,7 +30,7 @@ describe('Recording API Tests', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('Bulk Delete Recording Tests', () => {
|
describe('Bulk Delete Recording Tests', () => {
|
||||||
it('should return 200 when mixed valid and non-existent IDs are provided', async () => {
|
it('should return 400 when mixed valid and non-existent IDs are provided', async () => {
|
||||||
const testContext = await setupMultiRecordingsTestContext(3, 3, 3);
|
const testContext = await setupMultiRecordingsTestContext(3, 3, 3);
|
||||||
const recordingIds = testContext.rooms.map((room) => room.recordingId);
|
const recordingIds = testContext.rooms.map((room) => room.recordingId);
|
||||||
const nonExistentIds = ['nonExistent--EG_000--1234', 'nonExistent--EG_111--5678'];
|
const nonExistentIds = ['nonExistent--EG_000--1234', 'nonExistent--EG_111--5678'];
|
||||||
@ -38,10 +38,11 @@ describe('Recording API Tests', () => {
|
|||||||
|
|
||||||
const deleteResponse = await bulkDeleteRecordings(mixedIds);
|
const deleteResponse = await bulkDeleteRecordings(mixedIds);
|
||||||
|
|
||||||
expect(deleteResponse.status).toBe(200);
|
expect(deleteResponse.status).toBe(400);
|
||||||
expect(deleteResponse.body).toEqual({
|
expect(deleteResponse.body).toEqual({
|
||||||
|
message: expect.stringContaining('could not be deleted'),
|
||||||
deleted: expect.arrayContaining(recordingIds),
|
deleted: expect.arrayContaining(recordingIds),
|
||||||
notDeleted: expect.arrayContaining(
|
failed: expect.arrayContaining(
|
||||||
nonExistentIds.map((id) => ({
|
nonExistentIds.map((id) => ({
|
||||||
recordingId: id,
|
recordingId: id,
|
||||||
error: expect.stringContaining(`Recording '${id}' not found`)
|
error: expect.stringContaining(`Recording '${id}' not found`)
|
||||||
@ -50,7 +51,7 @@ describe('Recording API Tests', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return 200 with mixed results when some recordings are in active state', async () => {
|
it('should return 400 with mixed results when some recordings are in active state', async () => {
|
||||||
const testContext = await setupMultiRecordingsTestContext(3, 3, 2);
|
const testContext = await setupMultiRecordingsTestContext(3, 3, 2);
|
||||||
const activeRecordingRoom = testContext.getLastRoom();
|
const activeRecordingRoom = testContext.getLastRoom();
|
||||||
const recordingIds = testContext.rooms
|
const recordingIds = testContext.rooms
|
||||||
@ -60,10 +61,11 @@ describe('Recording API Tests', () => {
|
|||||||
const activeRecordingId = activeRecordingRoom?.recordingId;
|
const activeRecordingId = activeRecordingRoom?.recordingId;
|
||||||
let deleteResponse = await bulkDeleteRecordings([...recordingIds, activeRecordingId]);
|
let deleteResponse = await bulkDeleteRecordings([...recordingIds, activeRecordingId]);
|
||||||
|
|
||||||
expect(deleteResponse.status).toBe(200);
|
expect(deleteResponse.status).toBe(400);
|
||||||
expect(deleteResponse.body).toEqual({
|
expect(deleteResponse.body).toEqual({
|
||||||
|
message: expect.stringContaining('could not be deleted'),
|
||||||
deleted: expect.arrayContaining(recordingIds),
|
deleted: expect.arrayContaining(recordingIds),
|
||||||
notDeleted: [
|
failed: [
|
||||||
{
|
{
|
||||||
recordingId: activeRecordingId,
|
recordingId: activeRecordingId,
|
||||||
error: expect.stringContaining(`Recording '${activeRecordingId}' is not stopped yet`)
|
error: expect.stringContaining(`Recording '${activeRecordingId}' is not stopped yet`)
|
||||||
@ -75,18 +77,22 @@ describe('Recording API Tests', () => {
|
|||||||
|
|
||||||
deleteResponse = await bulkDeleteRecordings([activeRecordingId]);
|
deleteResponse = await bulkDeleteRecordings([activeRecordingId]);
|
||||||
|
|
||||||
expect(deleteResponse.status).toBe(204);
|
expect(deleteResponse.status).toBe(200);
|
||||||
expect(deleteResponse.body).toStrictEqual({});
|
expect(deleteResponse.body).toEqual({
|
||||||
|
message: expect.stringContaining('All recordings deleted successfully'),
|
||||||
|
deleted: expect.arrayContaining([activeRecordingId])
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not delete any recordings and return 200', async () => {
|
it('should not delete any recordings and return 400', async () => {
|
||||||
const testContext = await setupMultiRecordingsTestContext(2, 2, 0);
|
const testContext = await setupMultiRecordingsTestContext(2, 2, 0);
|
||||||
const recordingIds = testContext.rooms.map((room) => room.recordingId);
|
const recordingIds = testContext.rooms.map((room) => room.recordingId);
|
||||||
const deleteResponse = await bulkDeleteRecordings(recordingIds);
|
const deleteResponse = await bulkDeleteRecordings(recordingIds);
|
||||||
expect(deleteResponse.status).toBe(200);
|
expect(deleteResponse.status).toBe(400);
|
||||||
expect(deleteResponse.body).toEqual({
|
expect(deleteResponse.body).toEqual({
|
||||||
|
message: expect.stringContaining('could not be deleted'),
|
||||||
deleted: [],
|
deleted: [],
|
||||||
notDeleted: expect.arrayContaining(
|
failed: expect.arrayContaining(
|
||||||
recordingIds.map((id) => ({
|
recordingIds.map((id) => ({
|
||||||
recordingId: id,
|
recordingId: id,
|
||||||
error: expect.stringContaining(`Recording '${id}' is not stopped yet`)
|
error: expect.stringContaining(`Recording '${id}' is not stopped yet`)
|
||||||
@ -101,12 +107,12 @@ describe('Recording API Tests', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should delete all recordings and return 204 when all operations succeed', async () => {
|
it('should delete all recordings and return 200 when all operations succeed', async () => {
|
||||||
const response = await setupMultiRecordingsTestContext(5, 5, 5);
|
const response = await setupMultiRecordingsTestContext(5, 5, 5);
|
||||||
const recordingIds = response.rooms.map((room) => room.recordingId);
|
const recordingIds = response.rooms.map((room) => room.recordingId);
|
||||||
const deleteResponse = await bulkDeleteRecordings(recordingIds);
|
const deleteResponse = await bulkDeleteRecordings(recordingIds);
|
||||||
|
|
||||||
expect(deleteResponse.status).toBe(204);
|
expect(deleteResponse.status).toBe(200);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should only delete recordings belonging to the room when using a recording token', async () => {
|
it('should only delete recordings belonging to the room when using a recording token', async () => {
|
||||||
@ -125,10 +131,11 @@ describe('Recording API Tests', () => {
|
|||||||
// Intenta eliminar ambas grabaciones usando el token de la primera sala
|
// Intenta eliminar ambas grabaciones usando el token de la primera sala
|
||||||
const deleteResponse = await bulkDeleteRecordings([recordingId, otherRecordingId], recordingCookie);
|
const deleteResponse = await bulkDeleteRecordings([recordingId, otherRecordingId], recordingCookie);
|
||||||
|
|
||||||
expect(deleteResponse.status).toBe(200);
|
expect(deleteResponse.status).toBe(400);
|
||||||
expect(deleteResponse.body).toEqual({
|
expect(deleteResponse.body).toEqual({
|
||||||
|
message: expect.stringContaining('could not be deleted'),
|
||||||
deleted: [recordingId],
|
deleted: [recordingId],
|
||||||
notDeleted: [
|
failed: [
|
||||||
{
|
{
|
||||||
recordingId: otherRecordingId,
|
recordingId: otherRecordingId,
|
||||||
error: expect.stringContaining(
|
error: expect.stringContaining(
|
||||||
@ -144,7 +151,7 @@ describe('Recording API Tests', () => {
|
|||||||
const recordingIds = response.rooms.map((room) => room.recordingId);
|
const recordingIds = response.rooms.map((room) => room.recordingId);
|
||||||
const deleteResponse = await bulkDeleteRecordings(recordingIds);
|
const deleteResponse = await bulkDeleteRecordings(recordingIds);
|
||||||
|
|
||||||
expect(deleteResponse.status).toBe(204);
|
expect(deleteResponse.status).toBe(200);
|
||||||
|
|
||||||
const storageService = container.get(MeetStorageService);
|
const storageService = container.get(MeetStorageService);
|
||||||
|
|
||||||
@ -159,8 +166,7 @@ describe('Recording API Tests', () => {
|
|||||||
const recordingId = testContext.rooms[0].recordingId;
|
const recordingId = testContext.rooms[0].recordingId;
|
||||||
const deleteResponse = await bulkDeleteRecordings([recordingId]);
|
const deleteResponse = await bulkDeleteRecordings([recordingId]);
|
||||||
|
|
||||||
expect(deleteResponse.status).toBe(204);
|
expect(deleteResponse.status).toBe(200);
|
||||||
expect(deleteResponse.body).toStrictEqual({});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle duplicate recording IDs by treating them as a single delete', async () => {
|
it('should handle duplicate recording IDs by treating them as a single delete', async () => {
|
||||||
@ -168,8 +174,7 @@ describe('Recording API Tests', () => {
|
|||||||
const recordingId = testContext.getRoomByIndex(0)!.recordingId;
|
const recordingId = testContext.getRoomByIndex(0)!.recordingId;
|
||||||
const deleteResponse = await bulkDeleteRecordings([recordingId, recordingId]);
|
const deleteResponse = await bulkDeleteRecordings([recordingId, recordingId]);
|
||||||
|
|
||||||
expect(deleteResponse.status).toBe(204);
|
expect(deleteResponse.status).toBe(200);
|
||||||
expect(deleteResponse.body).toStrictEqual({});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should delete room metadata when deleting the last recording', async () => {
|
it('should delete room metadata when deleting the last recording', async () => {
|
||||||
@ -197,7 +202,7 @@ describe('Recording API Tests', () => {
|
|||||||
await stopRecording(secondRecordingId, moderatorCookie);
|
await stopRecording(secondRecordingId, moderatorCookie);
|
||||||
// Delete first recording - room metadata should remain
|
// Delete first recording - room metadata should remain
|
||||||
const bulkResponse = await bulkDeleteRecordings([firstRecordingId, secondRecordingId]);
|
const bulkResponse = await bulkDeleteRecordings([firstRecordingId, secondRecordingId]);
|
||||||
expect(bulkResponse.status).toBe(204);
|
expect(bulkResponse.status).toBe(200);
|
||||||
|
|
||||||
// // Verify second recording still exists
|
// // Verify second recording still exists
|
||||||
// const secondRecordingResponse = await getRecording(secondRecordingId);
|
// const secondRecordingResponse = await getRecording(secondRecordingId);
|
||||||
|
|||||||
@ -44,7 +44,7 @@ describe('Recording API Tests', () => {
|
|||||||
it('should delete a recording successfully', async () => {
|
it('should delete a recording successfully', async () => {
|
||||||
// Delete the recording
|
// Delete the recording
|
||||||
const deleteResponse = await deleteRecording(recordingId);
|
const deleteResponse = await deleteRecording(recordingId);
|
||||||
expect(deleteResponse.status).toBe(204);
|
expect(deleteResponse.status).toBe(200);
|
||||||
|
|
||||||
// Verify that the recording is deleted
|
// Verify that the recording is deleted
|
||||||
const getResponse = await deleteRecording(recordingId);
|
const getResponse = await deleteRecording(recordingId);
|
||||||
@ -61,7 +61,7 @@ describe('Recording API Tests', () => {
|
|||||||
|
|
||||||
// Check that the room metadata still exists after deleteing the first recording
|
// Check that the room metadata still exists after deleteing the first recording
|
||||||
const deleteResponse = await deleteRecording(recordingId!);
|
const deleteResponse = await deleteRecording(recordingId!);
|
||||||
expect(deleteResponse.status).toBe(204);
|
expect(deleteResponse.status).toBe(200);
|
||||||
|
|
||||||
recSecrets = await storageService.getAccessRecordingSecrets(recordingId);
|
recSecrets = await storageService.getAccessRecordingSecrets(recordingId);
|
||||||
expect(recSecrets).toBe(null);
|
expect(recSecrets).toBe(null);
|
||||||
@ -85,7 +85,7 @@ describe('Recording API Tests', () => {
|
|||||||
|
|
||||||
// Check that the room metadata still exists after deleteing the first recording
|
// Check that the room metadata still exists after deleteing the first recording
|
||||||
let deleteResponse = await deleteRecording(recordingId!);
|
let deleteResponse = await deleteRecording(recordingId!);
|
||||||
expect(deleteResponse.status).toBe(204);
|
expect(deleteResponse.status).toBe(200);
|
||||||
|
|
||||||
roomMetadata = await meetStorageService.getArchivedRoomMetadata(room.roomId);
|
roomMetadata = await meetStorageService.getArchivedRoomMetadata(room.roomId);
|
||||||
|
|
||||||
@ -95,7 +95,7 @@ describe('Recording API Tests', () => {
|
|||||||
|
|
||||||
// Delete the second recording
|
// Delete the second recording
|
||||||
deleteResponse = await deleteRecording(secondRecordingId!);
|
deleteResponse = await deleteRecording(secondRecordingId!);
|
||||||
expect(deleteResponse.status).toBe(204);
|
expect(deleteResponse.status).toBe(200);
|
||||||
|
|
||||||
// Verify that the room metadata is deleted after deleting the last recording
|
// Verify that the room metadata is deleted after deleting the last recording
|
||||||
roomMetadata = await meetStorageService.getArchivedRoomMetadata(room.roomId);
|
roomMetadata = await meetStorageService.getArchivedRoomMetadata(room.roomId);
|
||||||
@ -149,8 +149,7 @@ describe('Recording API Tests', () => {
|
|||||||
|
|
||||||
it('should sanitize recordingId before validation', async () => {
|
it('should sanitize recordingId before validation', async () => {
|
||||||
const response = await deleteRecording(` ${recordingId} `);
|
const response = await deleteRecording(` ${recordingId} `);
|
||||||
expect(response.status).toBe(204);
|
expect(response.status).toBe(200);
|
||||||
expect(response.body).toStrictEqual({});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return 409 when attempting to delete an active recording', async () => {
|
it('should return 409 when attempting to delete an active recording', async () => {
|
||||||
@ -164,7 +163,7 @@ describe('Recording API Tests', () => {
|
|||||||
await stopRecording(activeRecordingId, moderatorCookie);
|
await stopRecording(activeRecordingId, moderatorCookie);
|
||||||
// Attempt to delete the recording again
|
// Attempt to delete the recording again
|
||||||
deleteResponse = await deleteRecording(activeRecordingId);
|
deleteResponse = await deleteRecording(activeRecordingId);
|
||||||
expect(deleteResponse.status).toBe(204);
|
expect(deleteResponse.status).toBe(200);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -434,7 +434,7 @@ describe('Recording API Race Conditions Tests', () => {
|
|||||||
streamResponse.status === 'fulfilled' &&
|
streamResponse.status === 'fulfilled' &&
|
||||||
(streamResponse.value.status === 200 || streamResponse.value.status === 206);
|
(streamResponse.value.status === 200 || streamResponse.value.status === 206);
|
||||||
|
|
||||||
const deleteSuccessful = deleteResponse.status === 'fulfilled' && deleteResponse.value.status === 204;
|
const deleteSuccessful = deleteResponse.status === 'fulfilled' && deleteResponse.value.status === 200;
|
||||||
|
|
||||||
console.log(`Stream successful: ${streamSuccessful}, Delete successful: ${deleteSuccessful}`);
|
console.log(`Stream successful: ${streamSuccessful}, Delete successful: ${deleteSuccessful}`);
|
||||||
|
|
||||||
@ -485,8 +485,7 @@ describe('Recording API Race Conditions Tests', () => {
|
|||||||
// Both operations should complete successfully
|
// Both operations should complete successfully
|
||||||
const [bulkDeleteResult, newRecordingResult] = await Promise.all([bulkDeletePromise, startNewRecordingPromise]);
|
const [bulkDeleteResult, newRecordingResult] = await Promise.all([bulkDeletePromise, startNewRecordingPromise]);
|
||||||
|
|
||||||
expect(bulkDeleteResult.status).toBe(204);
|
expect(bulkDeleteResult.status).toBe(200);
|
||||||
expect(bulkDeleteResult.body).toEqual({});
|
|
||||||
|
|
||||||
// Check that the new recording started successfully
|
// Check that the new recording started successfully
|
||||||
expectValidStartRecordingResponse(newRecordingResult, room3.room.roomId, room3.room.roomName);
|
expectValidStartRecordingResponse(newRecordingResult, room3.room.roomId, room3.room.roomName);
|
||||||
|
|||||||
@ -1,224 +1,150 @@
|
|||||||
import { afterEach, beforeAll, describe, expect, it } from '@jest/globals';
|
import { afterAll, beforeAll, describe, expect, it } from '@jest/globals';
|
||||||
|
import {
|
||||||
|
MeetingEndAction,
|
||||||
|
MeetRoom,
|
||||||
|
MeetRoomDeletionErrorCode,
|
||||||
|
MeetRoomDeletionPolicyWithMeeting,
|
||||||
|
MeetRoomDeletionPolicyWithRecordings,
|
||||||
|
MeetRoomDeletionSuccessCode,
|
||||||
|
MeetRoomStatus
|
||||||
|
} from '../../../../src/typings/ce/room.js';
|
||||||
|
import { expectValidRoom } from '../../../helpers/assertion-helpers.js';
|
||||||
import {
|
import {
|
||||||
bulkDeleteRooms,
|
bulkDeleteRooms,
|
||||||
createRoom,
|
createRoom,
|
||||||
|
deleteAllRecordings,
|
||||||
deleteAllRooms,
|
deleteAllRooms,
|
||||||
disconnectFakeParticipants,
|
disconnectFakeParticipants,
|
||||||
|
endMeeting,
|
||||||
getRoom,
|
getRoom,
|
||||||
joinFakeParticipant,
|
|
||||||
sleep,
|
|
||||||
startTestServer
|
startTestServer
|
||||||
} from '../../../helpers/request-helpers.js';
|
} from '../../../helpers/request-helpers.js';
|
||||||
|
import { setupSingleRoom, setupSingleRoomWithRecording } from '../../../helpers/test-scenarios.js';
|
||||||
|
|
||||||
describe('Room API Tests', () => {
|
describe('Room API Tests', () => {
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
startTestServer();
|
startTestServer();
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(async () => {
|
afterAll(async () => {
|
||||||
// Remove all rooms created
|
|
||||||
await disconnectFakeParticipants();
|
await disconnectFakeParticipants();
|
||||||
await deleteAllRooms();
|
await deleteAllRooms();
|
||||||
|
await deleteAllRecordings();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Bulk Delete Room Tests', () => {
|
describe('Bulk Delete Room Tests', () => {
|
||||||
it('should return 204 when room does not exist (idempotent deletion)', async () => {
|
it('should return 200 when all rooms are processed for deletion successfully', async () => {
|
||||||
// The roomId will be transformed to string
|
const { roomId } = await createRoom();
|
||||||
const response = await bulkDeleteRooms([{ invalid: 'format' }], true);
|
|
||||||
|
|
||||||
expect(response.status).toBe(204);
|
|
||||||
expect(response.body).toStrictEqual({});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should delete room (204) with invalid force parameter when no participants exist', async () => {
|
|
||||||
const { roomId } = await createRoom({ roomName: 'test-invalid-force' });
|
|
||||||
|
|
||||||
const response = await bulkDeleteRooms([roomId]);
|
const response = await bulkDeleteRooms([roomId]);
|
||||||
|
expect(response.status).toBe(200);
|
||||||
//The bulk operation for only one room should be the same as deleting the room
|
expect(response.body).toEqual({
|
||||||
expect(response.status).toBe(204);
|
message: 'All rooms successfully processed for deletion',
|
||||||
expect(response.body).toStrictEqual({});
|
successful: expect.arrayContaining([
|
||||||
|
{
|
||||||
|
roomId,
|
||||||
|
successCode: MeetRoomDeletionSuccessCode.ROOM_DELETED,
|
||||||
|
message: expect.any(String)
|
||||||
|
}
|
||||||
|
])
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should mark room for deletion (202) with invalid force parameter when participants exist', async () => {
|
it('should return 400 when some rooms fail to process for deletion', async () => {
|
||||||
const { roomId } = await createRoom({ roomName: 'test-invalid-force' });
|
const room1 = await createRoom();
|
||||||
|
const { room: room2 } = await setupSingleRoom(true);
|
||||||
|
|
||||||
await joinFakeParticipant(roomId, 'test-participant-1');
|
const response = await bulkDeleteRooms([room1.roomId, room2.roomId]);
|
||||||
|
expect(response.status).toBe(400);
|
||||||
const response = await bulkDeleteRooms([roomId]);
|
expect(response.body).toEqual({
|
||||||
|
message: '1 room(s) failed to process while deleting',
|
||||||
//The bulk operation for only one room should be the same as deleting the room
|
successful: expect.arrayContaining([
|
||||||
expect(response.status).toBe(202);
|
{
|
||||||
expect(response.body.message).toContain('marked for deletion');
|
roomId: room1.roomId,
|
||||||
|
successCode: MeetRoomDeletionSuccessCode.ROOM_DELETED,
|
||||||
|
message: expect.any(String)
|
||||||
|
}
|
||||||
|
]),
|
||||||
|
failed: expect.arrayContaining([
|
||||||
|
{
|
||||||
|
roomId: room2.roomId,
|
||||||
|
error: MeetRoomDeletionErrorCode.ROOM_HAS_ACTIVE_MEETING,
|
||||||
|
message: expect.any(String)
|
||||||
|
}
|
||||||
|
])
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should delete room (204) with force=true parameter when no participants exist', async () => {
|
it('should return 400 when all rooms fail to process for deletion', async () => {
|
||||||
const { roomId } = await createRoom({ roomName: 'test-force' });
|
const { room } = await setupSingleRoom(true);
|
||||||
|
|
||||||
const response = await bulkDeleteRooms([roomId], true);
|
const response = await bulkDeleteRooms([room.roomId]);
|
||||||
|
expect(response.status).toBe(400);
|
||||||
//The bulk operation for only one room should be the same as deleting the room
|
expect(response.body).toEqual({
|
||||||
expect(response.status).toBe(204);
|
message: '1 room(s) failed to process while deleting',
|
||||||
expect(response.body).toStrictEqual({});
|
successful: [],
|
||||||
});
|
failed: expect.arrayContaining([
|
||||||
|
{
|
||||||
it('should delete room (204) with force=true parameter when participants exist', async () => {
|
roomId: room.roomId,
|
||||||
const { roomId } = await createRoom({ roomName: 'test-force' });
|
error: MeetRoomDeletionErrorCode.ROOM_HAS_ACTIVE_MEETING,
|
||||||
|
message: expect.any(String)
|
||||||
await joinFakeParticipant(roomId, 'test-participant-1');
|
}
|
||||||
|
])
|
||||||
const response = await bulkDeleteRooms([roomId], true);
|
});
|
||||||
|
|
||||||
//The bulk operation for only one room should be the same as deleting the room
|
|
||||||
expect(response.status).toBe(204);
|
|
||||||
expect(response.body).toStrictEqual({});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should successfully delete the room requesting the same roomId multiple times', async () => {
|
it('should successfully delete the room requesting the same roomId multiple times', async () => {
|
||||||
const { roomId } = await createRoom({ roomName: 'test-duplicate' });
|
const { roomId } = await createRoom();
|
||||||
|
|
||||||
const response = await bulkDeleteRooms([roomId, roomId, roomId], true);
|
const response = await bulkDeleteRooms([roomId, roomId, roomId]);
|
||||||
|
expect(response.status).toBe(200);
|
||||||
expect(response.status).toBe(204);
|
expect(response.body).toEqual({
|
||||||
expect(response.body).toStrictEqual({});
|
message: 'All rooms successfully processed for deletion',
|
||||||
|
successful: expect.arrayContaining([
|
||||||
|
{
|
||||||
|
roomId,
|
||||||
|
successCode: MeetRoomDeletionSuccessCode.ROOM_DELETED,
|
||||||
|
message: expect.any(String)
|
||||||
|
}
|
||||||
|
])
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should successfully delete valid roomIds while ignoring invalid ones', async () => {
|
it('should successfully delete valid roomIds while ignoring invalid ones', async () => {
|
||||||
const { roomId } = await createRoom({ roomName: 'test-invalid-force' });
|
const { roomId } = await createRoom();
|
||||||
|
|
||||||
const response = await bulkDeleteRooms([roomId, '!!@##$']);
|
const response = await bulkDeleteRooms([roomId, '!!@##$']);
|
||||||
|
|
||||||
expect(response.status).toBe(204);
|
|
||||||
expect(response.body).toStrictEqual({});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should successfully delete multiple rooms with valid roomIds', async () => {
|
|
||||||
// Create test rooms
|
|
||||||
const [room1, room2] = await Promise.all([
|
|
||||||
createRoom({ roomName: 'test-bulk-1' }),
|
|
||||||
createRoom({ roomName: 'test-bulk-2' })
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Delete both rooms
|
|
||||||
const response = await bulkDeleteRooms([room1.roomId, room2.roomId]);
|
|
||||||
|
|
||||||
expect(response.status).toBe(204);
|
|
||||||
expect(response.body).toStrictEqual({});
|
|
||||||
|
|
||||||
// Verify that the rooms are deleted
|
|
||||||
const getRoom1 = await getRoom(room1.roomId);
|
|
||||||
const getRoom2 = await getRoom(room2.roomId);
|
|
||||||
expect(getRoom1.status).toBe(404);
|
|
||||||
expect(getRoom2.status).toBe(404);
|
|
||||||
expect(getRoom1.body.message).toContain(`'${room1.roomId}' does not exist`);
|
|
||||||
expect(getRoom2.body.message).toContain(`'${room2.roomId}' does not exist`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should successfully marked for deletion multiple rooms with valid roomIds', async () => {
|
|
||||||
// Create test rooms
|
|
||||||
const [room1, room2] = await Promise.all([
|
|
||||||
createRoom({ roomName: 'test-bulk-1' }),
|
|
||||||
createRoom({ roomName: 'test-bulk-2' })
|
|
||||||
]);
|
|
||||||
|
|
||||||
await Promise.all([
|
|
||||||
joinFakeParticipant(room1.roomId, 'test-participant-1'),
|
|
||||||
joinFakeParticipant(room2.roomId, 'test-participant-2')
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Delete both rooms
|
|
||||||
const response = await bulkDeleteRooms([room1.roomId, room2.roomId]);
|
|
||||||
|
|
||||||
expect(response.status).toBe(202);
|
|
||||||
|
|
||||||
expect(response.body.message).toContain(`Rooms '${room1.roomId}, ${room2.roomId}' marked for deletion`);
|
|
||||||
expect(response.body.deleted).toBeUndefined();
|
|
||||||
|
|
||||||
// Verify that the rooms are marked for deletion
|
|
||||||
const getRoom1 = await getRoom(room1.roomId);
|
|
||||||
const getRoom2 = await getRoom(room2.roomId);
|
|
||||||
expect(getRoom1.status).toBe(200);
|
|
||||||
expect(getRoom2.status).toBe(200);
|
|
||||||
expect(getRoom1.body.roomId).toBe(room1.roomId);
|
|
||||||
expect(getRoom2.body.roomId).toBe(room2.roomId);
|
|
||||||
expect(getRoom1.body.markedForDeletion).toBe(true);
|
|
||||||
expect(getRoom2.body.markedForDeletion).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should sanitize roomIds before deleting', async () => {
|
|
||||||
// Create a test room
|
|
||||||
const { roomId } = await createRoom({ roomName: 'test-sanitize' });
|
|
||||||
|
|
||||||
const response = await bulkDeleteRooms([roomId + '!!@##$']);
|
|
||||||
expect(response.status).toBe(204);
|
|
||||||
expect(response.body).toStrictEqual({});
|
|
||||||
const deletedRoom = await getRoom(roomId);
|
|
||||||
expect(deletedRoom.status).toBe(404);
|
|
||||||
expect(deletedRoom.body.message).toContain(`'${roomId}' does not exist`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should delete rooms when force=true and participants exist', async () => {
|
|
||||||
// Create test rooms
|
|
||||||
const [room1, room2] = await Promise.all([
|
|
||||||
createRoom({ roomName: 'test-bulk-1' }),
|
|
||||||
createRoom({ roomName: 'test-bulk-2' })
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Join a participant to the rooms
|
|
||||||
await Promise.all([
|
|
||||||
joinFakeParticipant(room1.roomId, 'test-participant-1'),
|
|
||||||
joinFakeParticipant(room2.roomId, 'test-participant-2')
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Attempt to delete the rooms with force=false
|
|
||||||
const response = await bulkDeleteRooms([room1.roomId, room2.roomId], true);
|
|
||||||
|
|
||||||
expect(response.status).toBe(204);
|
|
||||||
expect(response.body).toStrictEqual({});
|
|
||||||
|
|
||||||
// Verify that the rooms are deleted
|
|
||||||
await sleep('1s'); // Wait a bit for the meetings to be closed and the rooms deleted
|
|
||||||
const deletedRoom1 = await getRoom(room1.roomId);
|
|
||||||
const deletedRoom2 = await getRoom(room2.roomId);
|
|
||||||
expect(deletedRoom1.status).toBe(404);
|
|
||||||
expect(deletedRoom1.body.message).toContain(`'${room1.roomId}' does not exist`);
|
|
||||||
expect(deletedRoom2.status).toBe(404);
|
|
||||||
expect(deletedRoom2.body.message).toContain(`'${room2.roomId}' does not exist`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return mixed results (200) when some rooms are deleted and others marked for deletion', async () => {
|
|
||||||
// Create rooms
|
|
||||||
const room1 = await createRoom({ roomName: 'empty-room' });
|
|
||||||
const room2 = await createRoom({ roomName: 'occupied-room' });
|
|
||||||
|
|
||||||
// Add participant to only one room
|
|
||||||
await joinFakeParticipant(room2.roomId, 'test-participant');
|
|
||||||
|
|
||||||
// Delete both rooms (without force)
|
|
||||||
const response = await bulkDeleteRooms([room1.roomId, room2.roomId], false);
|
|
||||||
|
|
||||||
// Should return 200 with mixed results
|
|
||||||
expect(response.status).toBe(200);
|
expect(response.status).toBe(200);
|
||||||
expect(response.body.deleted).toHaveLength(1);
|
expect(response.body).toEqual({
|
||||||
expect(response.body.deleted).toContain(room1.roomId);
|
message: 'All rooms successfully processed for deletion',
|
||||||
expect(response.body.markedForDeletion).toHaveLength(1);
|
successful: expect.arrayContaining([
|
||||||
expect(response.body.markedForDeletion).toContain(room2.roomId);
|
{
|
||||||
|
roomId,
|
||||||
// Verify deletion state
|
successCode: MeetRoomDeletionSuccessCode.ROOM_DELETED,
|
||||||
const getRoom1 = await getRoom(room1.roomId);
|
message: expect.any(String)
|
||||||
const getRoom2 = await getRoom(room2.roomId);
|
}
|
||||||
expect(getRoom1.status).toBe(404);
|
])
|
||||||
expect(getRoom2.status).toBe(200);
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle a large number of room IDs', async () => {
|
it('should handle a large number of room IDs', async () => {
|
||||||
// Create 20+ rooms and test deletion
|
// Create 20 rooms
|
||||||
const rooms = await Promise.all(
|
const rooms = await Promise.all(
|
||||||
Array.from({ length: 20 }, (_, i) => createRoom({ roomName: `bulk-${i}` }))
|
Array.from({ length: 20 }, (_, i) => createRoom({ roomName: `bulk-${i}` }))
|
||||||
);
|
);
|
||||||
|
|
||||||
const response = await bulkDeleteRooms(rooms.map((r) => r.roomId));
|
const response = await bulkDeleteRooms(rooms.map((r) => r.roomId));
|
||||||
expect(response.status).toBe(204);
|
expect(response.status).toBe(200);
|
||||||
|
expect(response.body).toEqual({
|
||||||
|
message: 'All rooms successfully processed for deletion',
|
||||||
|
successful: expect.arrayContaining(
|
||||||
|
rooms.map((room) => ({
|
||||||
|
roomId: room.roomId,
|
||||||
|
successCode: MeetRoomDeletionSuccessCode.ROOM_DELETED,
|
||||||
|
message: expect.any(String)
|
||||||
|
}))
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
// Verify all rooms are deleted
|
// Verify all rooms are deleted
|
||||||
for (const room of rooms) {
|
for (const room of rooms) {
|
||||||
@ -227,39 +153,98 @@ describe('Room API Tests', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle a large number of room IDs with mixed valid and invalid IDs', async () => {
|
it('should handle deletion when specifying withMeeting and withRecordings parameters', async () => {
|
||||||
// Create 20+ rooms and test deletion
|
const [room1, { room: room2 }, { room: room3 }, { room: room4, moderatorCookie }] = await Promise.all([
|
||||||
const rooms = await Promise.all(
|
createRoom(), // Room without active meeting or recordings
|
||||||
Array.from({ length: 20 }, (_, i) => createRoom({ roomName: `bulk-${i}` }))
|
setupSingleRoom(true), // Room with active meeting
|
||||||
);
|
setupSingleRoomWithRecording(true), // Room with active meeting and recordings
|
||||||
|
setupSingleRoomWithRecording(true) // Room with recordings
|
||||||
await joinFakeParticipant(rooms[0].roomId, 'test-participant-1');
|
|
||||||
|
|
||||||
const response = await bulkDeleteRooms([
|
|
||||||
...rooms.map((r) => r.roomId),
|
|
||||||
'!!@##$',
|
|
||||||
',,,,',
|
|
||||||
'room-1',
|
|
||||||
'room-2'
|
|
||||||
]);
|
]);
|
||||||
|
await endMeeting(room4.roomId, moderatorCookie);
|
||||||
|
const fakeRoomId = 'fakeRoomId'; // Non-existing room
|
||||||
|
|
||||||
expect(response.status).toBe(200);
|
const response = await bulkDeleteRooms(
|
||||||
|
[room1.roomId, room2.roomId, room3.roomId, room4.roomId, fakeRoomId],
|
||||||
|
MeetRoomDeletionPolicyWithMeeting.WHEN_MEETING_ENDS,
|
||||||
|
MeetRoomDeletionPolicyWithRecordings.CLOSE
|
||||||
|
);
|
||||||
|
expect(response.status).toBe(400);
|
||||||
|
expect(response.body).toEqual({
|
||||||
|
message: '1 room(s) failed to process while deleting',
|
||||||
|
successful: expect.arrayContaining([
|
||||||
|
{
|
||||||
|
roomId: room1.roomId,
|
||||||
|
successCode: MeetRoomDeletionSuccessCode.ROOM_DELETED,
|
||||||
|
message: expect.any(String)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
roomId: room2.roomId,
|
||||||
|
successCode: MeetRoomDeletionSuccessCode.ROOM_WITH_ACTIVE_MEETING_SCHEDULED_TO_BE_DELETED,
|
||||||
|
message: expect.any(String),
|
||||||
|
room: expect.any(Object)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
roomId: room3.roomId,
|
||||||
|
successCode: MeetRoomDeletionSuccessCode.ROOM_WITH_ACTIVE_MEETING_SCHEDULED_TO_BE_CLOSED,
|
||||||
|
message: expect.any(String),
|
||||||
|
room: expect.any(Object)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
roomId: room4.roomId,
|
||||||
|
successCode: MeetRoomDeletionSuccessCode.ROOM_CLOSED,
|
||||||
|
message: expect.any(String),
|
||||||
|
room: expect.any(Object)
|
||||||
|
}
|
||||||
|
]),
|
||||||
|
failed: expect.arrayContaining([
|
||||||
|
{
|
||||||
|
roomId: fakeRoomId,
|
||||||
|
error: 'Room Error',
|
||||||
|
message: expect.stringContaining('does not exist')
|
||||||
|
}
|
||||||
|
])
|
||||||
|
});
|
||||||
|
|
||||||
// Verify all valid rooms are deleted
|
// Check successful rooms properties
|
||||||
for (const room of rooms) {
|
const successfulRoom2 = response.body.successful.find(
|
||||||
if (room.roomId === rooms[0].roomId) {
|
(s: { roomId: string; successCode: MeetRoomDeletionSuccessCode; message: string; room?: MeetRoom }) =>
|
||||||
continue; // Skip the room with a participant
|
s.room?.roomId === room2.roomId
|
||||||
}
|
);
|
||||||
|
expectValidRoom(
|
||||||
const getResponse = await getRoom(room.roomId);
|
successfulRoom2.room,
|
||||||
expect(getResponse.status).toBe(404);
|
successfulRoom2.room.roomName,
|
||||||
}
|
undefined,
|
||||||
|
undefined,
|
||||||
// Verify the room with a participant is marked for deletion
|
undefined,
|
||||||
const getResponse = await getRoom(rooms[0].roomId);
|
MeetRoomStatus.ACTIVE_MEETING,
|
||||||
expect(getResponse.status).toBe(200);
|
MeetingEndAction.DELETE
|
||||||
expect(getResponse.body.markedForDeletion).toBe(true);
|
);
|
||||||
expect(getResponse.body.roomId).toBe(rooms[0].roomId);
|
const successfulRoom3 = response.body.successful.find(
|
||||||
|
(r: { roomId: string; successCode: MeetRoomDeletionSuccessCode; message: string; room?: MeetRoom }) =>
|
||||||
|
r.room?.roomId === room3.roomId
|
||||||
|
);
|
||||||
|
expectValidRoom(
|
||||||
|
successfulRoom3.room,
|
||||||
|
successfulRoom3.room.roomName,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
MeetRoomStatus.ACTIVE_MEETING,
|
||||||
|
MeetingEndAction.CLOSE
|
||||||
|
);
|
||||||
|
const successfulRoom4 = response.body.successful.find(
|
||||||
|
(r: { roomId: string; successCode: MeetRoomDeletionSuccessCode; message: string; room?: MeetRoom }) =>
|
||||||
|
r.room?.roomId === room4.roomId
|
||||||
|
);
|
||||||
|
expectValidRoom(
|
||||||
|
successfulRoom4.room,
|
||||||
|
successfulRoom4.room.roomName,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
MeetRoomStatus.CLOSED,
|
||||||
|
MeetingEndAction.NONE
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -293,5 +278,21 @@ describe('Room API Tests', () => {
|
|||||||
'At least one valid roomId is required after sanitization'
|
'At least one valid roomId is required after sanitization'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should fail when withMeeting parameter is invalid', async () => {
|
||||||
|
const response = await bulkDeleteRooms(['testRoom'], 'invalid_value');
|
||||||
|
|
||||||
|
expect(response.status).toBe(422);
|
||||||
|
expect(response.body.error).toContain('Unprocessable Entity');
|
||||||
|
expect(JSON.stringify(response.body.details)).toContain('Invalid enum value');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fail when withRecordings parameter is invalid', async () => {
|
||||||
|
const response = await bulkDeleteRooms(['testRoom'], 'force', 'invalid_value');
|
||||||
|
|
||||||
|
expect(response.status).toBe(422);
|
||||||
|
expect(response.body.error).toContain('Unprocessable Entity');
|
||||||
|
expect(JSON.stringify(response.body.details)).toContain('Invalid enum value');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -3,7 +3,11 @@ import { Express } from 'express';
|
|||||||
import ms from 'ms';
|
import ms from 'ms';
|
||||||
import request from 'supertest';
|
import request from 'supertest';
|
||||||
import INTERNAL_CONFIG from '../../../../src/config/internal-config.js';
|
import INTERNAL_CONFIG from '../../../../src/config/internal-config.js';
|
||||||
import { MeetRecordingAccess } from '../../../../src/typings/ce/index.js';
|
import {
|
||||||
|
MeetRecordingAccess,
|
||||||
|
MeetRoomDeletionPolicyWithMeeting,
|
||||||
|
MeetRoomDeletionPolicyWithRecordings
|
||||||
|
} from '../../../../src/typings/ce/index.js';
|
||||||
import { expectValidRoom } from '../../../helpers/assertion-helpers.js';
|
import { expectValidRoom } from '../../../helpers/assertion-helpers.js';
|
||||||
import { createRoom, deleteAllRooms, loginUser, startTestServer } from '../../../helpers/request-helpers.js';
|
import { createRoom, deleteAllRooms, loginUser, startTestServer } from '../../../helpers/request-helpers.js';
|
||||||
|
|
||||||
@ -25,6 +29,11 @@ describe('Room API Tests', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('Room Creation Tests', () => {
|
describe('Room Creation Tests', () => {
|
||||||
|
it('Should create a room with default name when roomName is omitted', async () => {
|
||||||
|
const room = await createRoom();
|
||||||
|
expectValidRoom(room, 'Room');
|
||||||
|
});
|
||||||
|
|
||||||
it('Should create a room without autoDeletionDate (default behavior)', async () => {
|
it('Should create a room without autoDeletionDate (default behavior)', async () => {
|
||||||
const room = await createRoom({
|
const room = await createRoom({
|
||||||
roomName: ' Test Room '
|
roomName: ' Test Room '
|
||||||
@ -38,13 +47,17 @@ describe('Room API Tests', () => {
|
|||||||
roomName: ' .,-------}{¡$#<+My Room *123 '
|
roomName: ' .,-------}{¡$#<+My Room *123 '
|
||||||
});
|
});
|
||||||
|
|
||||||
expectValidRoom(room, 'My Room 123', validAutoDeletionDate);
|
expectValidRoom(room, 'My Room 123', undefined, validAutoDeletionDate);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should create a room when sending full valid payload', async () => {
|
it('Should create a room when sending full valid payload', async () => {
|
||||||
const payload = {
|
const payload = {
|
||||||
roomName: ' =Example Room&/ ',
|
roomName: ' =Example Room&/ ',
|
||||||
autoDeletionDate: validAutoDeletionDate,
|
autoDeletionDate: validAutoDeletionDate,
|
||||||
|
autoDeletionPolicy: {
|
||||||
|
withMeeting: MeetRoomDeletionPolicyWithMeeting.FORCE,
|
||||||
|
withRecordings: MeetRoomDeletionPolicyWithRecordings.FORCE
|
||||||
|
},
|
||||||
preferences: {
|
preferences: {
|
||||||
recordingPreferences: {
|
recordingPreferences: {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
@ -57,7 +70,13 @@ describe('Room API Tests', () => {
|
|||||||
|
|
||||||
const room = await createRoom(payload);
|
const room = await createRoom(payload);
|
||||||
|
|
||||||
expectValidRoom(room, 'Example Room', validAutoDeletionDate, payload.preferences);
|
expectValidRoom(
|
||||||
|
room,
|
||||||
|
'Example Room',
|
||||||
|
payload.preferences,
|
||||||
|
validAutoDeletionDate,
|
||||||
|
payload.autoDeletionPolicy
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -122,6 +141,63 @@ describe('Room API Tests', () => {
|
|||||||
expect(JSON.stringify(response.body.details)).toContain('Expected number');
|
expect(JSON.stringify(response.body.details)).toContain('Expected number');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should fail when autoDeletionPolicy is not an object (string provided)', async () => {
|
||||||
|
const payload = {
|
||||||
|
roomName: 'TestRoom',
|
||||||
|
autoDeletionDate: validAutoDeletionDate,
|
||||||
|
autoDeletionPolicy: 'invalid-policy'
|
||||||
|
};
|
||||||
|
|
||||||
|
const response = await request(app).post(ROOMS_PATH).set('Cookie', adminCookie).send(payload).expect(422);
|
||||||
|
|
||||||
|
expect(JSON.stringify(response.body.details)).toContain('Expected object');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fail when autoDeletionPolicy has invalid structure', async () => {
|
||||||
|
const payload = {
|
||||||
|
roomName: 'TestRoom',
|
||||||
|
autoDeletionDate: validAutoDeletionDate,
|
||||||
|
autoDeletionPolicy: {
|
||||||
|
withMeeting: 'invalid-value',
|
||||||
|
withRecordings: MeetRoomDeletionPolicyWithRecordings.CLOSE
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const response = await request(app).post(ROOMS_PATH).set('Cookie', adminCookie).send(payload).expect(422);
|
||||||
|
|
||||||
|
expect(JSON.stringify(response.body.details)).toContain('Invalid enum value');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fail when autoDeletionPolicy.withMeeting has FAIL policy', async () => {
|
||||||
|
const payload = {
|
||||||
|
roomName: 'TestRoom',
|
||||||
|
autoDeletionDate: validAutoDeletionDate,
|
||||||
|
autoDeletionPolicy: {
|
||||||
|
withMeeting: MeetRoomDeletionPolicyWithMeeting.FAIL,
|
||||||
|
withRecordings: MeetRoomDeletionPolicyWithRecordings.CLOSE
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const response = await request(app).post(ROOMS_PATH).set('Cookie', adminCookie).send(payload).expect(422);
|
||||||
|
|
||||||
|
expect(JSON.stringify(response.body.details)).toContain('FAIL policy is not allowed for withMeeting auto-deletion policy');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fail when autoDeletionPolicy.withRecordings has FAIL policy', async () => {
|
||||||
|
const payload = {
|
||||||
|
roomName: 'TestRoom',
|
||||||
|
autoDeletionDate: validAutoDeletionDate,
|
||||||
|
autoDeletionPolicy: {
|
||||||
|
withMeeting: MeetRoomDeletionPolicyWithMeeting.WHEN_MEETING_ENDS,
|
||||||
|
withRecordings: MeetRoomDeletionPolicyWithRecordings.FAIL
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const response = await request(app).post(ROOMS_PATH).set('Cookie', adminCookie).send(payload).expect(422);
|
||||||
|
|
||||||
|
expect(JSON.stringify(response.body.details)).toContain('FAIL policy is not allowed for withRecordings auto-deletion policy');
|
||||||
|
});
|
||||||
|
|
||||||
it('should fail when roomName is not a string (number provided)', async () => {
|
it('should fail when roomName is not a string (number provided)', async () => {
|
||||||
const payload = {
|
const payload = {
|
||||||
roomName: 12345,
|
roomName: 12345,
|
||||||
|
|||||||
@ -1,209 +1,342 @@
|
|||||||
import { afterEach, beforeAll, describe, expect, it } from '@jest/globals';
|
import { afterAll, beforeAll, beforeEach, describe, expect, it } from '@jest/globals';
|
||||||
import ms from 'ms';
|
import {
|
||||||
import { expectValidRoom } from '../../../helpers/assertion-helpers.js';
|
MeetingEndAction,
|
||||||
|
MeetRoomDeletionErrorCode,
|
||||||
|
MeetRoomDeletionPolicyWithMeeting,
|
||||||
|
MeetRoomDeletionPolicyWithRecordings,
|
||||||
|
MeetRoomDeletionSuccessCode,
|
||||||
|
MeetRoomStatus
|
||||||
|
} from '../../../../src/typings/ce/room.js';
|
||||||
|
import { expectSuccessListRecordingResponse, expectValidRoom } from '../../../helpers/assertion-helpers.js';
|
||||||
import {
|
import {
|
||||||
createRoom,
|
createRoom,
|
||||||
|
deleteAllRecordings,
|
||||||
deleteAllRooms,
|
deleteAllRooms,
|
||||||
deleteRoom,
|
deleteRoom,
|
||||||
disconnectFakeParticipants,
|
disconnectFakeParticipants,
|
||||||
|
endMeeting,
|
||||||
|
getAllRecordings,
|
||||||
getRoom,
|
getRoom,
|
||||||
joinFakeParticipant,
|
|
||||||
sleep,
|
|
||||||
startTestServer
|
startTestServer
|
||||||
} from '../../../helpers/request-helpers.js';
|
} from '../../../helpers/request-helpers.js';
|
||||||
import { RoomService } from '../../../../src/services/room.service.js';
|
import { setupSingleRoom, setupSingleRoomWithRecording } from '../../../helpers/test-scenarios.js';
|
||||||
import { container } from '../../../../src/config/dependency-injector.config.js';
|
|
||||||
import { setInternalConfig } from '../../../../src/config/internal-config.js';
|
|
||||||
|
|
||||||
describe('Room API Tests', () => {
|
describe('Room API Tests', () => {
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
startTestServer();
|
startTestServer();
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(async () => {
|
afterAll(async () => {
|
||||||
// Remove all rooms created
|
// Remove all rooms created
|
||||||
await disconnectFakeParticipants();
|
await disconnectFakeParticipants();
|
||||||
await deleteAllRooms();
|
await deleteAllRooms();
|
||||||
|
await deleteAllRecordings();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Delete Room Tests', () => {
|
describe('Delete Room Tests', () => {
|
||||||
it('should return 204 when room does not exist (idempotent deletion)', async () => {
|
describe('without active meeting or recordings', () => {
|
||||||
const response = await deleteRoom('non-existent-room-id');
|
it('should return 200 with successCode=room_deleted', async () => {
|
||||||
|
const { roomId } = await createRoom();
|
||||||
|
|
||||||
expect(response.status).toBe(204);
|
const response = await deleteRoom(roomId);
|
||||||
});
|
expect(response.status).toBe(200);
|
||||||
|
expect(response.body).toHaveProperty('successCode', MeetRoomDeletionSuccessCode.ROOM_DELETED);
|
||||||
|
|
||||||
it('should default to force=false when force parameter is invalid', async () => {
|
// Check room is deleted
|
||||||
// Create a room first
|
const getResponse = await getRoom(roomId);
|
||||||
const { roomId } = await createRoom({
|
expect(getResponse.status).toBe(404);
|
||||||
roomName: 'test-room'
|
|
||||||
});
|
});
|
||||||
const response = await deleteRoom(roomId, { force: 'not-a-boolean' });
|
|
||||||
|
|
||||||
expect(response.status).toBe(204);
|
|
||||||
// Verify it's deleted
|
|
||||||
const getResponse = await getRoom(roomId);
|
|
||||||
expect(getResponse.status).toBe(404);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should mark room for deletion when participants exist and force parameter is invalid', async () => {
|
describe('with active meeting but no recordings', () => {
|
||||||
// Create a room first
|
let roomId: string;
|
||||||
const { roomId } = await createRoom({
|
let roomName: string;
|
||||||
roomName: 'test-room'
|
let moderatorCookie: string;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
// Create a room with an active meeting
|
||||||
|
const { room, moderatorCookie: cookie } = await setupSingleRoom(true);
|
||||||
|
roomId = room.roomId;
|
||||||
|
roomName = room.roomName;
|
||||||
|
moderatorCookie = cookie;
|
||||||
});
|
});
|
||||||
|
|
||||||
await joinFakeParticipant(roomId, 'test-participant');
|
it('should return 200 with successCode=room_with_active_meeting_deleted when withMeeting=force', async () => {
|
||||||
|
const response = await deleteRoom(roomId, {
|
||||||
|
withMeeting: MeetRoomDeletionPolicyWithMeeting.FORCE
|
||||||
|
});
|
||||||
|
expect(response.status).toBe(200);
|
||||||
|
expect(response.body).toHaveProperty(
|
||||||
|
'successCode',
|
||||||
|
MeetRoomDeletionSuccessCode.ROOM_WITH_ACTIVE_MEETING_DELETED
|
||||||
|
);
|
||||||
|
|
||||||
// The force parameter is not a boolean so it should be defined as false
|
// Check room is deleted
|
||||||
// and the room should be marked for deletion
|
const getResponse = await getRoom(roomId);
|
||||||
const response = await deleteRoom(roomId, { force: 'not-a-boolean' });
|
expect(getResponse.status).toBe(404);
|
||||||
|
|
||||||
// Check operation accepted
|
|
||||||
expect(response.status).toBe(202);
|
|
||||||
|
|
||||||
// The room should be marked for deletion
|
|
||||||
const roomResponse = await getRoom(roomId);
|
|
||||||
expect(roomResponse.body).toBeDefined();
|
|
||||||
expect(roomResponse.body.roomId).toBe(roomId);
|
|
||||||
expect(roomResponse.body.markedForDeletion).toBeDefined();
|
|
||||||
expect(roomResponse.body.markedForDeletion).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should delete an empty room completely (204)', async () => {
|
|
||||||
const { roomId } = await createRoom({ roomName: 'test-room' });
|
|
||||||
|
|
||||||
const response = await deleteRoom(roomId);
|
|
||||||
|
|
||||||
expect(response.status).toBe(204);
|
|
||||||
|
|
||||||
// Try to retrieve the room again
|
|
||||||
const responseAfterDelete = await getRoom(roomId);
|
|
||||||
expect(responseAfterDelete.status).toBe(404);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should sanitize roomId with spaces and special characters before deletion', async () => {
|
|
||||||
// Create a room first
|
|
||||||
const createdRoom = await createRoom({
|
|
||||||
roomName: 'test-mixed'
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add some spaces and special chars to the valid roomId
|
it('should return 202 with successCode=room_with_active_meeting_scheduled_to_be_deleted when withMeeting=when_meeting_ends', async () => {
|
||||||
const modifiedId = ` ${createdRoom.roomId}!@# `;
|
const response = await deleteRoom(roomId, {
|
||||||
const response = await deleteRoom(modifiedId);
|
withMeeting: MeetRoomDeletionPolicyWithMeeting.WHEN_MEETING_ENDS
|
||||||
|
});
|
||||||
|
expect(response.status).toBe(202);
|
||||||
|
expect(response.body).toHaveProperty(
|
||||||
|
'successCode',
|
||||||
|
MeetRoomDeletionSuccessCode.ROOM_WITH_ACTIVE_MEETING_SCHEDULED_TO_BE_DELETED
|
||||||
|
);
|
||||||
|
expectValidRoom(
|
||||||
|
response.body.room,
|
||||||
|
roomName,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
MeetRoomStatus.ACTIVE_MEETING,
|
||||||
|
MeetingEndAction.DELETE
|
||||||
|
);
|
||||||
|
|
||||||
// The validation should sanitize the ID and successfully delete
|
// End meeting and check the room is deleted
|
||||||
expect(response.status).toBe(204);
|
await endMeeting(roomId, moderatorCookie);
|
||||||
|
const getResponse = await getRoom(roomId);
|
||||||
// Verify it's deleted
|
expect(getResponse.status).toBe(404);
|
||||||
const getResponse = await getRoom(createdRoom.roomId);
|
|
||||||
expect(getResponse.status).toBe(404);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should handle explicit force=true for room with no participants', async () => {
|
|
||||||
const createdRoom = await createRoom({
|
|
||||||
roomName: 'test-room'
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const response = await deleteRoom(createdRoom.roomId, { force: true });
|
it('should return 409 with error=room_has_active_meeting when withMeeting=fail', async () => {
|
||||||
|
const response = await deleteRoom(roomId, { withMeeting: MeetRoomDeletionPolicyWithMeeting.FAIL });
|
||||||
expect(response.status).toBe(204);
|
expect(response.status).toBe(409);
|
||||||
|
expect(response.body).toHaveProperty('error', MeetRoomDeletionErrorCode.ROOM_HAS_ACTIVE_MEETING);
|
||||||
// Try to retrieve the room again
|
});
|
||||||
const responseAfterDelete = await getRoom(createdRoom.roomId);
|
|
||||||
expect(responseAfterDelete.status).toBe(404);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should mark room for deletion (202) when participants exist and force=false', async () => {
|
describe('with recordings but no active meeting', () => {
|
||||||
const autoDeletionDate = Date.now() + ms('5h');
|
let roomId: string;
|
||||||
const { roomId } = await createRoom({
|
let roomName: string;
|
||||||
roomName: 'test-room',
|
|
||||||
autoDeletionDate
|
beforeEach(async () => {
|
||||||
|
// Create a room with recordings and end the meeting
|
||||||
|
const { room, moderatorCookie } = await setupSingleRoomWithRecording(true);
|
||||||
|
roomId = room.roomId;
|
||||||
|
roomName = room.roomName;
|
||||||
|
await endMeeting(roomId, moderatorCookie);
|
||||||
});
|
});
|
||||||
|
|
||||||
await joinFakeParticipant(roomId, 'test-participant');
|
it('should return 200 with successCode=room_and_recordings_deleted when withRecording=force', async () => {
|
||||||
|
const response = await deleteRoom(roomId, {
|
||||||
|
withRecordings: MeetRoomDeletionPolicyWithRecordings.FORCE
|
||||||
|
});
|
||||||
|
expect(response.status).toBe(200);
|
||||||
|
expect(response.body).toHaveProperty(
|
||||||
|
'successCode',
|
||||||
|
MeetRoomDeletionSuccessCode.ROOM_AND_RECORDINGS_DELETED
|
||||||
|
);
|
||||||
|
|
||||||
const response = await deleteRoom(roomId, { force: false });
|
// Check the room and recordings are deleted
|
||||||
|
const roomResponse = await getRoom(roomId);
|
||||||
expect(response.status).toBe(202);
|
expect(roomResponse.status).toBe(404);
|
||||||
|
const recordingsResponse = await getAllRecordings({ roomId, maxItems: 1 });
|
||||||
const roomResponse = await getRoom(roomId);
|
expectSuccessListRecordingResponse(recordingsResponse, 0, false, false, 1);
|
||||||
expectValidRoom(roomResponse.body, 'test-room', autoDeletionDate, undefined, true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should delete a room marked for deletion when the webhook room_finished is received', async () => {
|
|
||||||
const autoDeletionDate = Date.now() + ms('5h');
|
|
||||||
const { roomId } = await createRoom({
|
|
||||||
roomName: 'test-room',
|
|
||||||
autoDeletionDate
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const roomService = container.get(RoomService);
|
it('should return 200 with successCode=room_closed when withRecording=close', async () => {
|
||||||
// Set MEETING_DEPARTURE_TIMEOUT to 1s to force the room to be closed immediately
|
const response = await deleteRoom(roomId, {
|
||||||
setInternalConfig({
|
withRecordings: MeetRoomDeletionPolicyWithRecordings.CLOSE
|
||||||
MEETING_DEPARTURE_TIMEOUT: '1s'
|
});
|
||||||
});
|
expect(response.status).toBe(200);
|
||||||
// Create livekit room with custom departure timeout
|
expect(response.body).toHaveProperty('successCode', MeetRoomDeletionSuccessCode.ROOM_CLOSED);
|
||||||
// This is needed to trigger the room_finished event
|
|
||||||
await roomService.createLivekitRoom(roomId);
|
|
||||||
|
|
||||||
// Join a participant to the room
|
// Check that the room is closed and recordings are not deleted
|
||||||
await joinFakeParticipant(roomId, 'test-participant');
|
expectValidRoom(
|
||||||
|
response.body.room,
|
||||||
|
roomName,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
MeetRoomStatus.CLOSED,
|
||||||
|
MeetingEndAction.NONE
|
||||||
|
);
|
||||||
|
|
||||||
const response = await deleteRoom(roomId, { force: false });
|
const recordingsResponse = await getAllRecordings({ roomId, maxItems: 1 });
|
||||||
|
expectSuccessListRecordingResponse(recordingsResponse, 1, false, false, 1);
|
||||||
expect(response.status).toBe(202);
|
|
||||||
|
|
||||||
const roomResponse = await getRoom(roomId);
|
|
||||||
expectValidRoom(roomResponse.body, 'test-room', autoDeletionDate, undefined, true);
|
|
||||||
|
|
||||||
await disconnectFakeParticipants();
|
|
||||||
|
|
||||||
// Wait for room deletion
|
|
||||||
await sleep('2s');
|
|
||||||
const responseAfterDelete = await getRoom(roomId);
|
|
||||||
expect(responseAfterDelete.status).toBe(404);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should force delete (204) room with active participants when force=true', async () => {
|
|
||||||
const { roomId } = await createRoom({
|
|
||||||
roomName: 'test-room'
|
|
||||||
});
|
});
|
||||||
|
|
||||||
await joinFakeParticipant(roomId, 'test-participant');
|
it('should return 409 with error=room_has_recordings when withRecording=fail', async () => {
|
||||||
|
const response = await deleteRoom(roomId, {
|
||||||
const response = await deleteRoom(roomId, { force: true });
|
withRecordings: MeetRoomDeletionPolicyWithRecordings.FAIL
|
||||||
|
});
|
||||||
expect(response.status).toBe(204);
|
expect(response.status).toBe(409);
|
||||||
|
expect(response.body).toHaveProperty('error', MeetRoomDeletionErrorCode.ROOM_HAS_RECORDINGS);
|
||||||
// Try to retrieve the room again
|
});
|
||||||
await sleep('1s'); // Wait a bit for the meeting to be closed and the room deleted
|
|
||||||
const responseAfterDelete = await getRoom(roomId);
|
|
||||||
expect(responseAfterDelete.status).toBe(404);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should successfully delete a room already marked for deletion', async () => {
|
describe('with active meeting and recordings', () => {
|
||||||
const { roomId } = await createRoom({ roomName: 'test-marked' });
|
let roomId: string;
|
||||||
|
let roomName: string;
|
||||||
|
let moderatorCookie: string;
|
||||||
|
|
||||||
// First mark it for deletion
|
beforeEach(async () => {
|
||||||
await joinFakeParticipant(roomId, 'test-participant');
|
// Create a room with recordings, keep the meeting active
|
||||||
|
const { room, moderatorCookie: cookie } = await setupSingleRoomWithRecording(true);
|
||||||
|
roomId = room.roomId;
|
||||||
|
roomName = room.roomName;
|
||||||
|
moderatorCookie = cookie;
|
||||||
|
});
|
||||||
|
|
||||||
await deleteRoom(roomId, { force: false });
|
it('should return 200 with successCode=room_with_active_meeting_and_recordings_deleted when withMeeting=force and withRecording=force', async () => {
|
||||||
|
const response = await deleteRoom(roomId, {
|
||||||
|
withMeeting: MeetRoomDeletionPolicyWithMeeting.FORCE,
|
||||||
|
withRecordings: MeetRoomDeletionPolicyWithRecordings.FORCE
|
||||||
|
});
|
||||||
|
expect(response.status).toBe(200);
|
||||||
|
expect(response.body).toHaveProperty(
|
||||||
|
'successCode',
|
||||||
|
MeetRoomDeletionSuccessCode.ROOM_WITH_ACTIVE_MEETING_AND_RECORDINGS_DELETED
|
||||||
|
);
|
||||||
|
|
||||||
// Then try to delete it again
|
// Check the room and recordings are deleted
|
||||||
const response = await deleteRoom(roomId, { force: true });
|
const roomResponse = await getRoom(roomId);
|
||||||
expect(response.status).toBe(204);
|
expect(roomResponse.status).toBe(404);
|
||||||
});
|
const recordingsResponse = await getAllRecordings({ roomId, maxItems: 1 });
|
||||||
|
expectSuccessListRecordingResponse(recordingsResponse, 0, false, false, 1);
|
||||||
|
});
|
||||||
|
|
||||||
it('should handle repeated deletion of the same room gracefully', async () => {
|
it('should return 200 with successCode=room_with_active_meeting_closed when withMeeting=force and withRecording=close', async () => {
|
||||||
const { roomId } = await createRoom({ roomName: 'test-idempotent' });
|
const response = await deleteRoom(roomId, {
|
||||||
|
withMeeting: MeetRoomDeletionPolicyWithMeeting.FORCE,
|
||||||
|
withRecordings: MeetRoomDeletionPolicyWithRecordings.CLOSE
|
||||||
|
});
|
||||||
|
expect(response.status).toBe(200);
|
||||||
|
expect(response.body).toHaveProperty(
|
||||||
|
'successCode',
|
||||||
|
MeetRoomDeletionSuccessCode.ROOM_WITH_ACTIVE_MEETING_CLOSED
|
||||||
|
);
|
||||||
|
expectValidRoom(
|
||||||
|
response.body.room,
|
||||||
|
roomName,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
MeetRoomStatus.ACTIVE_MEETING,
|
||||||
|
MeetingEndAction.CLOSE
|
||||||
|
);
|
||||||
|
|
||||||
// Delete first time
|
// Check that the room is closed and recordings are not deleted
|
||||||
const response1 = await deleteRoom(roomId);
|
const roomResponse = await getRoom(roomId);
|
||||||
expect(response1.status).toBe(204);
|
expect(roomResponse.status).toBe(200);
|
||||||
|
expectValidRoom(
|
||||||
|
roomResponse.body,
|
||||||
|
roomName,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
MeetRoomStatus.CLOSED,
|
||||||
|
MeetingEndAction.NONE
|
||||||
|
);
|
||||||
|
|
||||||
// Delete second time - should still return 204 (no error)
|
const recordingsResponse = await getAllRecordings({ roomId, maxItems: 1 });
|
||||||
const response2 = await deleteRoom(roomId);
|
expectSuccessListRecordingResponse(recordingsResponse, 1, false, false, 1);
|
||||||
expect(response2.status).toBe(204);
|
});
|
||||||
|
|
||||||
|
it('should return 409 with error=room_with_active_meeting_has_recordings when withMeeting=force and withRecording=fail', async () => {
|
||||||
|
const response = await deleteRoom(roomId, {
|
||||||
|
withMeeting: MeetRoomDeletionPolicyWithMeeting.FORCE,
|
||||||
|
withRecordings: MeetRoomDeletionPolicyWithRecordings.FAIL
|
||||||
|
});
|
||||||
|
expect(response.status).toBe(409);
|
||||||
|
expect(response.body).toHaveProperty(
|
||||||
|
'error',
|
||||||
|
MeetRoomDeletionErrorCode.ROOM_WITH_ACTIVE_MEETING_HAS_RECORDINGS
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return 202 with successCode=room_with_active_meeting_and_recordings_scheduled_to_be_deleted when withMeeting=when_meeting_ends and withRecording=force', async () => {
|
||||||
|
const response = await deleteRoom(roomId, {
|
||||||
|
withMeeting: MeetRoomDeletionPolicyWithMeeting.WHEN_MEETING_ENDS,
|
||||||
|
withRecordings: MeetRoomDeletionPolicyWithRecordings.FORCE
|
||||||
|
});
|
||||||
|
expect(response.status).toBe(202);
|
||||||
|
expect(response.body).toHaveProperty(
|
||||||
|
'successCode',
|
||||||
|
MeetRoomDeletionSuccessCode.ROOM_WITH_ACTIVE_MEETING_AND_RECORDINGS_SCHEDULED_TO_BE_DELETED
|
||||||
|
);
|
||||||
|
expectValidRoom(
|
||||||
|
response.body.room,
|
||||||
|
roomName,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
MeetRoomStatus.ACTIVE_MEETING,
|
||||||
|
MeetingEndAction.DELETE
|
||||||
|
);
|
||||||
|
|
||||||
|
// End meeting and check the room and recordings are deleted
|
||||||
|
await endMeeting(roomId, moderatorCookie);
|
||||||
|
const roomResponse = await getRoom(roomId);
|
||||||
|
expect(roomResponse.status).toBe(404);
|
||||||
|
const recordingsResponse = await getAllRecordings({ roomId, maxItems: 1 });
|
||||||
|
expectSuccessListRecordingResponse(recordingsResponse, 0, false, false, 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return 202 with successCode=room_with_active_meeting_scheduled_to_be_closed when withMeeting=when_meeting_ends and withRecording=close', async () => {
|
||||||
|
const response = await deleteRoom(roomId, {
|
||||||
|
withMeeting: MeetRoomDeletionPolicyWithMeeting.WHEN_MEETING_ENDS,
|
||||||
|
withRecordings: MeetRoomDeletionPolicyWithRecordings.CLOSE
|
||||||
|
});
|
||||||
|
expect(response.status).toBe(202);
|
||||||
|
expect(response.body).toHaveProperty(
|
||||||
|
'successCode',
|
||||||
|
MeetRoomDeletionSuccessCode.ROOM_WITH_ACTIVE_MEETING_SCHEDULED_TO_BE_CLOSED
|
||||||
|
);
|
||||||
|
expectValidRoom(
|
||||||
|
response.body.room,
|
||||||
|
roomName,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
MeetRoomStatus.ACTIVE_MEETING,
|
||||||
|
MeetingEndAction.CLOSE
|
||||||
|
);
|
||||||
|
|
||||||
|
// End meeting and check that the room is closed and recordings are not deleted
|
||||||
|
await endMeeting(roomId, moderatorCookie);
|
||||||
|
const roomResponse = await getRoom(roomId);
|
||||||
|
expect(roomResponse.status).toBe(200);
|
||||||
|
expectValidRoom(
|
||||||
|
roomResponse.body,
|
||||||
|
roomName,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
MeetRoomStatus.CLOSED,
|
||||||
|
MeetingEndAction.NONE
|
||||||
|
);
|
||||||
|
|
||||||
|
const recordingsResponse = await getAllRecordings({ roomId, maxItems: 1 });
|
||||||
|
expectSuccessListRecordingResponse(recordingsResponse, 1, false, false, 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return 409 with error=room_with_active_meeting_has_recordings_cannot_schedule_deletion when withMeeting=when_meeting_ends and withRecording=fail', async () => {
|
||||||
|
const response = await deleteRoom(roomId, {
|
||||||
|
withMeeting: MeetRoomDeletionPolicyWithMeeting.WHEN_MEETING_ENDS,
|
||||||
|
withRecordings: MeetRoomDeletionPolicyWithRecordings.FAIL
|
||||||
|
});
|
||||||
|
expect(response.status).toBe(409);
|
||||||
|
expect(response.body).toHaveProperty(
|
||||||
|
'error',
|
||||||
|
MeetRoomDeletionErrorCode.ROOM_WITH_ACTIVE_MEETING_HAS_RECORDINGS_CANNOT_SCHEDULE_DELETION
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return 409 with error=room_with_recordings_has_active_meeting when withMeeting=fail', async () => {
|
||||||
|
const response = await deleteRoom(roomId, {
|
||||||
|
withMeeting: MeetRoomDeletionPolicyWithMeeting.FAIL,
|
||||||
|
withRecordings: MeetRoomDeletionPolicyWithRecordings.FORCE
|
||||||
|
});
|
||||||
|
expect(response.status).toBe(409);
|
||||||
|
expect(response.body).toHaveProperty(
|
||||||
|
'error',
|
||||||
|
MeetRoomDeletionErrorCode.ROOM_WITH_RECORDINGS_HAS_ACTIVE_MEETING
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -217,12 +350,20 @@ describe('Room API Tests', () => {
|
|||||||
expect(JSON.stringify(response.body.details)).toContain('roomId cannot be empty after sanitization');
|
expect(JSON.stringify(response.body.details)).toContain('roomId cannot be empty after sanitization');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should fail when force parameter is a number instead of boolean', async () => {
|
it('should fail when withMeeting parameter is invalid', async () => {
|
||||||
const response = await deleteRoom('testRoom', { force: { value: 123 } });
|
const response = await deleteRoom('testRoom', { withMeeting: 'invalid_value' });
|
||||||
|
|
||||||
expect(response.status).toBe(422);
|
expect(response.status).toBe(422);
|
||||||
expect(response.body.error).toContain('Unprocessable Entity');
|
expect(response.body.error).toContain('Unprocessable Entity');
|
||||||
expect(JSON.stringify(response.body.details)).toContain('Expected boolean, received object');
|
expect(JSON.stringify(response.body.details)).toContain('Invalid enum value');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fail when withRecordings parameter is invalid', async () => {
|
||||||
|
const response = await deleteRoom('testRoom', { withRecordings: 'invalid_value' });
|
||||||
|
|
||||||
|
expect(response.status).toBe(422);
|
||||||
|
expect(response.body.error).toContain('Unprocessable Entity');
|
||||||
|
expect(JSON.stringify(response.body.details)).toContain('Invalid enum value');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,19 +1,25 @@
|
|||||||
import { afterEach, beforeAll, describe, expect, it } from '@jest/globals';
|
import { afterAll, beforeAll, describe, expect, it } from '@jest/globals';
|
||||||
import ms from 'ms';
|
import ms from 'ms';
|
||||||
import { setInternalConfig } from '../../../../src/config/internal-config.js';
|
import { setInternalConfig } from '../../../../src/config/internal-config.js';
|
||||||
|
import { MeetRoomHelper } from '../../../../src/helpers/room.helper.js';
|
||||||
|
import {
|
||||||
|
MeetRoomDeletionPolicyWithMeeting,
|
||||||
|
MeetRoomDeletionPolicyWithRecordings
|
||||||
|
} from '../../../../src/typings/ce/room.js';
|
||||||
import {
|
import {
|
||||||
createRoom,
|
createRoom,
|
||||||
|
deleteAllRecordings,
|
||||||
deleteAllRooms,
|
deleteAllRooms,
|
||||||
disconnectFakeParticipants,
|
disconnectFakeParticipants,
|
||||||
|
endMeeting,
|
||||||
|
generateParticipantTokenCookie,
|
||||||
getRoom,
|
getRoom,
|
||||||
getRooms,
|
|
||||||
joinFakeParticipant,
|
joinFakeParticipant,
|
||||||
runRoomGarbageCollector,
|
runRoomGarbageCollector,
|
||||||
sleep,
|
sleep,
|
||||||
|
startRecording,
|
||||||
startTestServer
|
startTestServer
|
||||||
} from '../../../helpers/request-helpers.js';
|
} from '../../../helpers/request-helpers.js';
|
||||||
import { container } from '../../../../src/config/dependency-injector.config.js';
|
|
||||||
import { RoomService } from '../../../../src/services/room.service.js';
|
|
||||||
|
|
||||||
describe('Room Garbage Collector Tests', () => {
|
describe('Room Garbage Collector Tests', () => {
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
@ -23,13 +29,14 @@ describe('Room Garbage Collector Tests', () => {
|
|||||||
startTestServer();
|
startTestServer();
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(async () => {
|
afterAll(async () => {
|
||||||
// Remove all rooms created
|
// Remove all rooms created
|
||||||
await disconnectFakeParticipants();
|
await disconnectFakeParticipants();
|
||||||
await deleteAllRooms();
|
await deleteAllRooms();
|
||||||
|
await deleteAllRecordings();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should delete a room with a past auto-deletion date if no participant is present', async () => {
|
it('should delete a room with a past auto-deletion date if no active meeting', async () => {
|
||||||
const createdRoom = await createRoom({
|
const createdRoom = await createRoom({
|
||||||
roomName: 'test-gc',
|
roomName: 'test-gc',
|
||||||
autoDeletionDate: Date.now() + ms('1s')
|
autoDeletionDate: Date.now() + ms('1s')
|
||||||
@ -48,20 +55,20 @@ describe('Room Garbage Collector Tests', () => {
|
|||||||
expect(response.status).toBe(404);
|
expect(response.status).toBe(404);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should mark room for deletion but not delete when expiration date has passed and participants exist', async () => {
|
it('should schedule room to be deleted when expiration date has passed and there is a active meeting', async () => {
|
||||||
const createdRoom = await createRoom({
|
const createdRoom = await createRoom({
|
||||||
roomName: 'test-gc-participants',
|
roomName: 'test-gc-participants',
|
||||||
autoDeletionDate: Date.now() + ms('1s')
|
autoDeletionDate: Date.now() + ms('1s')
|
||||||
});
|
});
|
||||||
|
|
||||||
await joinFakeParticipant(createdRoom.roomId, 'test-participant');
|
await joinFakeParticipant(createdRoom.roomId, 'test-participant');
|
||||||
|
|
||||||
await runRoomGarbageCollector();
|
await runRoomGarbageCollector();
|
||||||
|
|
||||||
// The room should not be deleted but marked for deletion
|
// The room should not be deleted but scheduled for deletion
|
||||||
const response = await getRoom(createdRoom.roomId);
|
const response = await getRoom(createdRoom.roomId);
|
||||||
expect(response.status).toBe(200);
|
expect(response.status).toBe(200);
|
||||||
expect(response.body.markedForDeletion).toBe(true);
|
expect(response.body).toHaveProperty('status', 'active_meeting');
|
||||||
|
expect(response.body).toHaveProperty('meetingEndAction', 'delete');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not touch a room with a future auto-deletion date', async () => {
|
it('should not touch a room with a future auto-deletion date', async () => {
|
||||||
@ -74,45 +81,32 @@ describe('Room Garbage Collector Tests', () => {
|
|||||||
|
|
||||||
const response = await getRoom(createdRoom.roomId);
|
const response = await getRoom(createdRoom.roomId);
|
||||||
expect(response.status).toBe(200);
|
expect(response.status).toBe(200);
|
||||||
expect(response.body.markedForDeletion).toBeFalsy();
|
expect(response.body).toHaveProperty('status', 'open');
|
||||||
|
expect(response.body).toHaveProperty('meetingEndAction', 'none');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should delete a room after the last participant leaves when it was marked for deletion', async () => {
|
it('should delete a room scheduled for deletion when the the meeting ends', async () => {
|
||||||
const { roomId } = await createRoom({
|
const room = await createRoom({
|
||||||
roomName: 'test-gc-lifecycle',
|
roomName: 'test-gc-lifecycle',
|
||||||
autoDeletionDate: Date.now() + ms('1s')
|
autoDeletionDate: Date.now() + ms('1s')
|
||||||
});
|
});
|
||||||
|
await joinFakeParticipant(room.roomId, 'test-participant');
|
||||||
|
|
||||||
const roomService = container.get(RoomService);
|
|
||||||
// Set MEETING_DEPARTURE_TIMEOUT to 1s to force the room to be closed immediately
|
|
||||||
setInternalConfig({
|
|
||||||
MEETING_DEPARTURE_TIMEOUT: '1s'
|
|
||||||
});
|
|
||||||
// Create livekit room with custom departure timeout
|
|
||||||
// This is needed to trigger the room_finished event
|
|
||||||
await roomService.createLivekitRoom(roomId);
|
|
||||||
|
|
||||||
await joinFakeParticipant(roomId, 'test-participant');
|
|
||||||
|
|
||||||
// Wait for the auto-deletion date to pass
|
|
||||||
await sleep('1s');
|
|
||||||
|
|
||||||
// Should mark the room for deletion but not delete it yet
|
|
||||||
await runRoomGarbageCollector();
|
await runRoomGarbageCollector();
|
||||||
|
|
||||||
let response = await getRoom(roomId);
|
// The room should not be deleted but scheduled for deletion
|
||||||
|
let response = await getRoom(room.roomId);
|
||||||
expect(response.status).toBe(200);
|
expect(response.status).toBe(200);
|
||||||
expect(response.body.markedForDeletion).toBe(true);
|
expect(response.body).toHaveProperty('status', 'active_meeting');
|
||||||
expect(response.body.autoDeletionDate).toBeTruthy();
|
expect(response.body).toHaveProperty('meetingEndAction', 'delete');
|
||||||
expect(response.body.autoDeletionDate).toBeLessThan(Date.now());
|
|
||||||
|
|
||||||
await disconnectFakeParticipants();
|
// End the meeting
|
||||||
|
const { moderatorSecret } = MeetRoomHelper.extractSecretsFromRoom(room);
|
||||||
// Wait to receive webhook room_finished
|
const moderatorCookie = await generateParticipantTokenCookie(room.roomId, moderatorSecret, 'moderator');
|
||||||
await sleep('1s');
|
await endMeeting(room.roomId, moderatorCookie);
|
||||||
|
|
||||||
// Verify that the room is deleted
|
// Verify that the room is deleted
|
||||||
response = await getRoom(roomId);
|
response = await getRoom(room.roomId);
|
||||||
expect(response.status).toBe(404);
|
expect(response.status).toBe(404);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -123,14 +117,10 @@ describe('Room Garbage Collector Tests', () => {
|
|||||||
|
|
||||||
await runRoomGarbageCollector();
|
await runRoomGarbageCollector();
|
||||||
|
|
||||||
let response = await getRoom(createdRoom.roomId);
|
const response = await getRoom(createdRoom.roomId);
|
||||||
expect(response.status).toBe(200);
|
expect(response.status).toBe(200);
|
||||||
|
expect(response.body).toHaveProperty('status', 'open');
|
||||||
await runRoomGarbageCollector();
|
expect(response.body).toHaveProperty('meetingEndAction', 'none');
|
||||||
response = await getRoom(createdRoom.roomId);
|
|
||||||
expect(response.status).toBe(200);
|
|
||||||
expect(response.body.markedForDeletion).toBeFalsy();
|
|
||||||
expect(response.body.autoDeletionDate).toBeFalsy();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle multiple expired rooms in one batch', async () => {
|
it('should handle multiple expired rooms in one batch', async () => {
|
||||||
@ -161,11 +151,48 @@ describe('Room Garbage Collector Tests', () => {
|
|||||||
expect(response.status).toBe(200); // Should still exist
|
expect(response.status).toBe(200); // Should still exist
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const response = await getRooms();
|
it('should handle expired rooms correctly when specifying autoDeletionPolicy', async () => {
|
||||||
const { body } = response;
|
// Create both rooms in parallel
|
||||||
|
const [room1, room2] = await Promise.all([
|
||||||
|
createRoom({
|
||||||
|
roomName: 'test-gc-policy-1',
|
||||||
|
autoDeletionDate: Date.now() + ms('1s'),
|
||||||
|
autoDeletionPolicy: {
|
||||||
|
withMeeting: MeetRoomDeletionPolicyWithMeeting.FORCE,
|
||||||
|
withRecordings: MeetRoomDeletionPolicyWithRecordings.CLOSE
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
createRoom({
|
||||||
|
roomName: 'test-gc-policy-2',
|
||||||
|
autoDeletionDate: Date.now() + ms('1s'),
|
||||||
|
autoDeletionPolicy: {
|
||||||
|
withMeeting: MeetRoomDeletionPolicyWithMeeting.WHEN_MEETING_ENDS,
|
||||||
|
withRecordings: MeetRoomDeletionPolicyWithRecordings.FORCE
|
||||||
|
}
|
||||||
|
})
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Join participants
|
||||||
|
await joinFakeParticipant(room1.roomId, 'participant1');
|
||||||
|
await joinFakeParticipant(room2.roomId, 'participant2');
|
||||||
|
|
||||||
|
// Start recording
|
||||||
|
const { moderatorSecret } = MeetRoomHelper.extractSecretsFromRoom(room1);
|
||||||
|
const moderatorCookie = await generateParticipantTokenCookie(room1.roomId, moderatorSecret, 'moderator');
|
||||||
|
await startRecording(room1.roomId, moderatorCookie);
|
||||||
|
|
||||||
|
await runRoomGarbageCollector();
|
||||||
|
|
||||||
|
const response = await getRoom(room1.roomId);
|
||||||
expect(response.status).toBe(200);
|
expect(response.status).toBe(200);
|
||||||
expect(body.rooms.length).toBe(2); // Only 2 rooms should remain
|
expect(response.body).toHaveProperty('status', 'closed');
|
||||||
|
expect(response.body).toHaveProperty('meetingEndAction', 'none');
|
||||||
|
|
||||||
|
const response2 = await getRoom(room2.roomId);
|
||||||
|
expect(response2.status).toBe(200);
|
||||||
|
expect(response2.body).toHaveProperty('status', 'active_meeting');
|
||||||
|
expect(response2.body).toHaveProperty('meetingEndAction', 'delete');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -82,7 +82,7 @@ describe('Room API Tests', () => {
|
|||||||
|
|
||||||
expectSuccessRoomsResponse(response, 3, 3, true, true);
|
expectSuccessRoomsResponse(response, 3, 3, true, true);
|
||||||
rooms.forEach((room: MeetRoom, i: number) => {
|
rooms.forEach((room: MeetRoom, i: number) => {
|
||||||
expectValidRoom(room, `test-room-${i}`, validAutoDeletionDate);
|
expectValidRoom(room, `test-room-${i}`, undefined, validAutoDeletionDate);
|
||||||
});
|
});
|
||||||
|
|
||||||
const nextPageToken = pagination.nextPageToken;
|
const nextPageToken = pagination.nextPageToken;
|
||||||
@ -90,7 +90,7 @@ describe('Room API Tests', () => {
|
|||||||
({ pagination, rooms } = response.body);
|
({ pagination, rooms } = response.body);
|
||||||
expectSuccessRoomsResponse(response, 3, 3, false, false);
|
expectSuccessRoomsResponse(response, 3, 3, false, false);
|
||||||
rooms.forEach((room: MeetRoom, i: number) => {
|
rooms.forEach((room: MeetRoom, i: number) => {
|
||||||
expectValidRoom(room, `test-room-${i + 3}`, validAutoDeletionDate);
|
expectValidRoom(room, `test-room-${i + 3}`, undefined, validAutoDeletionDate);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -21,7 +21,7 @@ describe('Room API Tests', () => {
|
|||||||
await deleteAllRooms();
|
await deleteAllRooms();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Update Room Tests', () => {
|
describe('Update Room Preferences Tests', () => {
|
||||||
let frontendEventService: FrontendEventService;
|
let frontendEventService: FrontendEventService;
|
||||||
|
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
@ -113,7 +113,7 @@ describe('Room API Tests', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Update Room Validation failures', () => {
|
describe('Update Room Preferences Validation failures', () => {
|
||||||
it('should fail when preferences have incorrect structure', async () => {
|
it('should fail when preferences have incorrect structure', async () => {
|
||||||
const { roomId } = await createRoom({
|
const { roomId } = await createRoom({
|
||||||
roomName: 'validation-test'
|
roomName: 'validation-test'
|
||||||
103
backend/tests/integration/api/rooms/update-room-status.test.ts
Normal file
103
backend/tests/integration/api/rooms/update-room-status.test.ts
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
import { afterEach, beforeAll, describe, expect, it } from '@jest/globals';
|
||||||
|
import {
|
||||||
|
createRoom,
|
||||||
|
deleteAllRooms,
|
||||||
|
disconnectFakeParticipants,
|
||||||
|
endMeeting,
|
||||||
|
getRoom,
|
||||||
|
startTestServer,
|
||||||
|
updateRoomStatus
|
||||||
|
} from '../../../helpers/request-helpers.js';
|
||||||
|
import { setupSingleRoom } from '../../../helpers/test-scenarios.js';
|
||||||
|
|
||||||
|
describe('Room API Tests', () => {
|
||||||
|
beforeAll(() => {
|
||||||
|
startTestServer();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
await disconnectFakeParticipants();
|
||||||
|
await deleteAllRooms();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Update Room Status Tests', () => {
|
||||||
|
it('should successfully update room status to open', async () => {
|
||||||
|
const createdRoom = await createRoom({
|
||||||
|
roomName: 'update-test'
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update the room status
|
||||||
|
const response = await updateRoomStatus(createdRoom.roomId, 'open');
|
||||||
|
expect(response.status).toBe(200);
|
||||||
|
expect(response.body).toHaveProperty('message');
|
||||||
|
|
||||||
|
// Verify with a get request
|
||||||
|
const getResponse = await getRoom(createdRoom.roomId);
|
||||||
|
expect(getResponse.status).toBe(200);
|
||||||
|
expect(getResponse.body.status).toEqual('open');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should successfully update room status to closed', async () => {
|
||||||
|
const createdRoom = await createRoom({
|
||||||
|
roomName: 'update-test'
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update the room status
|
||||||
|
const response = await updateRoomStatus(createdRoom.roomId, 'closed');
|
||||||
|
expect(response.status).toBe(200);
|
||||||
|
expect(response.body).toHaveProperty('message');
|
||||||
|
|
||||||
|
// Verify with a get request
|
||||||
|
const getResponse = await getRoom(createdRoom.roomId);
|
||||||
|
expect(getResponse.status).toBe(200);
|
||||||
|
expect(getResponse.body.status).toEqual('closed');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should schedule room to be closed when meeting ends if there is an active meeting', async () => {
|
||||||
|
const roomData = await setupSingleRoom(true);
|
||||||
|
|
||||||
|
// Update the room status
|
||||||
|
const response = await updateRoomStatus(roomData.room.roomId, 'closed');
|
||||||
|
expect(response.status).toBe(202);
|
||||||
|
expect(response.body).toHaveProperty('message');
|
||||||
|
|
||||||
|
// Verify with a get request
|
||||||
|
let getResponse = await getRoom(roomData.room.roomId);
|
||||||
|
expect(getResponse.status).toBe(200);
|
||||||
|
expect(getResponse.body.status).toEqual('active_meeting');
|
||||||
|
expect(getResponse.body.meetingEndAction).toEqual('close');
|
||||||
|
|
||||||
|
// End meeting and verify closed status
|
||||||
|
await endMeeting(roomData.room.roomId, roomData.moderatorCookie);
|
||||||
|
|
||||||
|
getResponse = await getRoom(roomData.room.roomId);
|
||||||
|
expect(getResponse.status).toBe(200);
|
||||||
|
expect(getResponse.body.status).toEqual('closed');
|
||||||
|
expect(getResponse.body.meetingEndAction).toEqual('none');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fail with 404 when updating non-existent room', async () => {
|
||||||
|
const nonExistentRoomId = 'non-existent-room';
|
||||||
|
|
||||||
|
const response = await updateRoomStatus(nonExistentRoomId, 'closed');
|
||||||
|
|
||||||
|
expect(response.status).toBe(404);
|
||||||
|
expect(response.body.message).toContain(`'${nonExistentRoomId}' does not exist`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Update Room Status Validation failures', () => {
|
||||||
|
it('should fail when status is invalid', async () => {
|
||||||
|
const { roomId } = await createRoom({
|
||||||
|
roomName: 'validation-test'
|
||||||
|
});
|
||||||
|
|
||||||
|
// Invalid status
|
||||||
|
const response = await updateRoomStatus(roomId, 'invalid_status');
|
||||||
|
|
||||||
|
expect(response.status).toBe(422);
|
||||||
|
expect(response.body.error).toContain('Unprocessable Entity');
|
||||||
|
expect(JSON.stringify(response.body.details)).toContain('Invalid enum value');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -27,7 +27,6 @@ describe('Authentication API Tests', () => {
|
|||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
expect(response.body).toHaveProperty('message');
|
expect(response.body).toHaveProperty('message');
|
||||||
expect(response.body.message).toBe('Login succeeded');
|
|
||||||
|
|
||||||
// Check for access token and refresh token cookies
|
// Check for access token and refresh token cookies
|
||||||
expect(response.headers['set-cookie']).toBeDefined();
|
expect(response.headers['set-cookie']).toBeDefined();
|
||||||
@ -144,7 +143,6 @@ describe('Authentication API Tests', () => {
|
|||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
expect(response.body).toHaveProperty('message');
|
expect(response.body).toHaveProperty('message');
|
||||||
expect(response.body.message).toBe('Token refreshed');
|
|
||||||
|
|
||||||
// Check for new access token cookie
|
// Check for new access token cookie
|
||||||
const newCookies = response.headers['set-cookie'] as unknown as string[];
|
const newCookies = response.headers['set-cookie'] as unknown as string[];
|
||||||
@ -235,7 +233,7 @@ describe('Authentication API Tests', () => {
|
|||||||
|
|
||||||
it('should delete all API keys', async () => {
|
it('should delete all API keys', async () => {
|
||||||
const apiKey = await generateApiKey();
|
const apiKey = await generateApiKey();
|
||||||
await request(app).delete(`${AUTH_PATH}/api-keys`).set('Cookie', adminCookie).expect(204);
|
await request(app).delete(`${AUTH_PATH}/api-keys`).set('Cookie', adminCookie).expect(200);
|
||||||
|
|
||||||
// Confirm deletion
|
// Confirm deletion
|
||||||
const getResponse = await getApiKeys();
|
const getResponse = await getApiKeys();
|
||||||
|
|||||||
@ -141,7 +141,7 @@ describe('Meeting API Security Tests', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Delete Participant from Meeting Tests', () => {
|
describe('Kick Participant from Meeting Tests', () => {
|
||||||
const PARTICIPANT_IDENTITY = 'TEST_PARTICIPANT';
|
const PARTICIPANT_IDENTITY = 'TEST_PARTICIPANT';
|
||||||
|
|
||||||
it('should fail when request includes API key', async () => {
|
it('should fail when request includes API key', async () => {
|
||||||
|
|||||||
@ -428,7 +428,7 @@ describe('Recording API Security Tests', () => {
|
|||||||
/*
|
/*
|
||||||
Use a simulated recording ID matching the API's expected format.
|
Use a simulated recording ID matching the API's expected format.
|
||||||
This allows testing the delete endpoint logic without deleting a real recording.
|
This allows testing the delete endpoint logic without deleting a real recording.
|
||||||
As a result, all successful delete tests will expect a 404 Not Found response.
|
As a result, all successful delete tests will expect a 400 response with failed recordings.
|
||||||
*/
|
*/
|
||||||
fakeRecordingId = `${roomData.room.roomId}--EG_xxx--uid`;
|
fakeRecordingId = `${roomData.room.roomId}--EG_xxx--uid`;
|
||||||
});
|
});
|
||||||
@ -438,7 +438,7 @@ describe('Recording API Security Tests', () => {
|
|||||||
.delete(RECORDINGS_PATH)
|
.delete(RECORDINGS_PATH)
|
||||||
.query({ recordingIds: fakeRecordingId })
|
.query({ recordingIds: fakeRecordingId })
|
||||||
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY);
|
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY);
|
||||||
expect(response.status).toBe(200);
|
expect(response.status).toBe(400);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should succeed when user is authenticated as admin', async () => {
|
it('should succeed when user is authenticated as admin', async () => {
|
||||||
@ -446,7 +446,7 @@ describe('Recording API Security Tests', () => {
|
|||||||
.delete(RECORDINGS_PATH)
|
.delete(RECORDINGS_PATH)
|
||||||
.query({ recordingIds: fakeRecordingId })
|
.query({ recordingIds: fakeRecordingId })
|
||||||
.set('Cookie', adminCookie);
|
.set('Cookie', adminCookie);
|
||||||
expect(response.status).toBe(200);
|
expect(response.status).toBe(400);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should fail when recording access is admin-moderator-speaker and participant is speaker', async () => {
|
it('should fail when recording access is admin-moderator-speaker and participant is speaker', async () => {
|
||||||
@ -480,7 +480,7 @@ describe('Recording API Security Tests', () => {
|
|||||||
.delete(RECORDINGS_PATH)
|
.delete(RECORDINGS_PATH)
|
||||||
.query({ recordingIds: fakeRecordingId })
|
.query({ recordingIds: fakeRecordingId })
|
||||||
.set('Cookie', recordingCookie);
|
.set('Cookie', recordingCookie);
|
||||||
expect(response.status).toBe(200);
|
expect(response.status).toBe(400);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should fail when recording access is admin-moderator and participant is speaker', async () => {
|
it('should fail when recording access is admin-moderator and participant is speaker', async () => {
|
||||||
@ -508,7 +508,7 @@ describe('Recording API Security Tests', () => {
|
|||||||
.delete(RECORDINGS_PATH)
|
.delete(RECORDINGS_PATH)
|
||||||
.query({ recordingIds: fakeRecordingId })
|
.query({ recordingIds: fakeRecordingId })
|
||||||
.set('Cookie', recordingCookie);
|
.set('Cookie', recordingCookie);
|
||||||
expect(response.status).toBe(200);
|
expect(response.status).toBe(400);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -85,7 +85,7 @@ describe('Room API Security Tests', () => {
|
|||||||
.delete(ROOMS_PATH)
|
.delete(ROOMS_PATH)
|
||||||
.query({ roomIds: roomId })
|
.query({ roomIds: roomId })
|
||||||
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY);
|
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY);
|
||||||
expect(response.status).toBe(204);
|
expect(response.status).toBe(200);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should succeed when user is authenticated as admin', async () => {
|
it('should succeed when user is authenticated as admin', async () => {
|
||||||
@ -93,7 +93,7 @@ describe('Room API Security Tests', () => {
|
|||||||
.delete(ROOMS_PATH)
|
.delete(ROOMS_PATH)
|
||||||
.query({ roomIds: roomId })
|
.query({ roomIds: roomId })
|
||||||
.set('Cookie', adminCookie);
|
.set('Cookie', adminCookie);
|
||||||
expect(response.status).toBe(204);
|
expect(response.status).toBe(200);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should fail when user is not authenticated', async () => {
|
it('should fail when user is not authenticated', async () => {
|
||||||
@ -165,12 +165,12 @@ describe('Room API Security Tests', () => {
|
|||||||
const response = await request(app)
|
const response = await request(app)
|
||||||
.delete(`${ROOMS_PATH}/${roomId}`)
|
.delete(`${ROOMS_PATH}/${roomId}`)
|
||||||
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY);
|
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY);
|
||||||
expect(response.status).toBe(204);
|
expect(response.status).toBe(200);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should succeed when user is authenticated as admin', async () => {
|
it('should succeed when user is authenticated as admin', async () => {
|
||||||
const response = await request(app).delete(`${ROOMS_PATH}/${roomId}`).set('Cookie', adminCookie);
|
const response = await request(app).delete(`${ROOMS_PATH}/${roomId}`).set('Cookie', adminCookie);
|
||||||
expect(response.status).toBe(204);
|
expect(response.status).toBe(200);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should fail when user is not authenticated', async () => {
|
it('should fail when user is not authenticated', async () => {
|
||||||
@ -283,6 +283,38 @@ describe('Room API Security Tests', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('Update Room Status Tests', () => {
|
||||||
|
let roomId: string;
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
const room = await createRoom();
|
||||||
|
roomId = room.roomId;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should succeed when request includes API key', async () => {
|
||||||
|
const response = await request(app)
|
||||||
|
.put(`${ROOMS_PATH}/${roomId}/status`)
|
||||||
|
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY)
|
||||||
|
.send({ status: 'open' });
|
||||||
|
expect(response.status).toBe(200);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should succeed when user is authenticated as admin', async () => {
|
||||||
|
const response = await request(app)
|
||||||
|
.put(`${ROOMS_PATH}/${roomId}/status`)
|
||||||
|
.set('Cookie', adminCookie)
|
||||||
|
.send({ status: 'open' });
|
||||||
|
expect(response.status).toBe(200);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fail when user is not authenticated', async () => {
|
||||||
|
const response = await request(app)
|
||||||
|
.put(`${ROOMS_PATH}/${roomId}/status`)
|
||||||
|
.send({ status: 'open' });
|
||||||
|
expect(response.status).toBe(401);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('Generate Recording Token Tests', () => {
|
describe('Generate Recording Token Tests', () => {
|
||||||
let roomData: RoomData;
|
let roomData: RoomData;
|
||||||
|
|
||||||
|
|||||||
@ -16,7 +16,6 @@ describe('Users API Tests', () => {
|
|||||||
const newPassword = 'newpassword123';
|
const newPassword = 'newpassword123';
|
||||||
const response = await changePassword(MEET_INITIAL_ADMIN_PASSWORD, newPassword, adminCookie);
|
const response = await changePassword(MEET_INITIAL_ADMIN_PASSWORD, newPassword, adminCookie);
|
||||||
expect(response.status).toBe(200);
|
expect(response.status).toBe(200);
|
||||||
expect(response.body).toHaveProperty('message', 'Password changed successfully');
|
|
||||||
|
|
||||||
// Reset password
|
// Reset password
|
||||||
await changePassword(newPassword, MEET_INITIAL_ADMIN_PASSWORD, adminCookie);
|
await changePassword(newPassword, MEET_INITIAL_ADMIN_PASSWORD, adminCookie);
|
||||||
|
|||||||
@ -114,7 +114,7 @@ describe('Webhook Integration Tests', () => {
|
|||||||
const context = await setupSingleRoom(true);
|
const context = await setupSingleRoom(true);
|
||||||
const roomData = context.room;
|
const roomData = context.room;
|
||||||
// Forcefully delete the room
|
// Forcefully delete the room
|
||||||
await deleteRoom(roomData.roomId, { force: true });
|
await deleteRoom(roomData.roomId, { withMeeting: 'force' });
|
||||||
|
|
||||||
// Verify 'meetingEnded' webhook is sent
|
// Verify 'meetingEnded' webhook is sent
|
||||||
expect(receivedWebhooks.length).toBeGreaterThanOrEqual(1);
|
expect(receivedWebhooks.length).toBeGreaterThanOrEqual(1);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user