openvidu/backend/tests/integration/api/rooms/garbage-collector.test.ts

199 lines
6.8 KiB
TypeScript

import { afterAll, beforeAll, describe, expect, it } from '@jest/globals';
import ms from 'ms';
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 {
createRoom,
deleteAllRecordings,
deleteAllRooms,
disconnectFakeParticipants,
endMeeting,
generateParticipantTokenCookie,
getRoom,
joinFakeParticipant,
runRoomGarbageCollector,
sleep,
startRecording,
startTestServer
} from '../../../helpers/request-helpers.js';
describe('Room Garbage Collector Tests', () => {
beforeAll(() => {
setInternalConfig({
MIN_FUTURE_TIME_FOR_ROOM_AUTODELETION_DATE: '0s'
});
startTestServer();
});
afterAll(async () => {
// Remove all rooms created
await disconnectFakeParticipants();
await deleteAllRooms();
await deleteAllRecordings();
});
it('should delete a room with a past auto-deletion date if no active meeting', async () => {
const createdRoom = await createRoom({
roomName: 'test-gc',
autoDeletionDate: Date.now() + ms('1s')
});
let response = await getRoom(createdRoom.roomId);
expect(response.status).toBe(200);
// Wait for auto-deletion date to pass
await sleep('2s');
// Run garbage collector
await runRoomGarbageCollector();
response = await getRoom(createdRoom.roomId);
expect(response.status).toBe(404);
});
it('should schedule room to be deleted when expiration date has passed and there is a active meeting', async () => {
const createdRoom = await createRoom({
roomName: 'test-gc-participants',
autoDeletionDate: Date.now() + ms('1s')
});
await joinFakeParticipant(createdRoom.roomId, 'test-participant');
await runRoomGarbageCollector();
// The room should not be deleted but scheduled for deletion
const response = await getRoom(createdRoom.roomId);
expect(response.status).toBe(200);
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 () => {
const createdRoom = await createRoom({
roomName: 'test-gc-future',
autoDeletionDate: Date.now() + ms('1h')
});
await runRoomGarbageCollector();
const response = await getRoom(createdRoom.roomId);
expect(response.status).toBe(200);
expect(response.body).toHaveProperty('status', 'open');
expect(response.body).toHaveProperty('meetingEndAction', 'none');
});
it('should delete a room scheduled for deletion when the the meeting ends', async () => {
const room = await createRoom({
roomName: 'test-gc-lifecycle',
autoDeletionDate: Date.now() + ms('1s')
});
await joinFakeParticipant(room.roomId, 'test-participant');
await runRoomGarbageCollector();
// The room should not be deleted but scheduled for deletion
let response = await getRoom(room.roomId);
expect(response.status).toBe(200);
expect(response.body).toHaveProperty('status', 'active_meeting');
expect(response.body).toHaveProperty('meetingEndAction', 'delete');
// End the meeting
const { moderatorSecret } = MeetRoomHelper.extractSecretsFromRoom(room);
const moderatorCookie = await generateParticipantTokenCookie(room.roomId, moderatorSecret, 'moderator');
await endMeeting(room.roomId, moderatorCookie);
// Verify that the room is deleted
response = await getRoom(room.roomId);
expect(response.status).toBe(404);
});
it('should never delete a room without an auto-deletion date', async () => {
const createdRoom = await createRoom({
roomName: 'test-gc-no-date'
});
await runRoomGarbageCollector();
const response = await getRoom(createdRoom.roomId);
expect(response.status).toBe(200);
expect(response.body).toHaveProperty('status', 'open');
expect(response.body).toHaveProperty('meetingEndAction', 'none');
});
it('should handle multiple expired rooms in one batch', async () => {
const rooms = await Promise.all([
createRoom({ roomName: 'test-gc-multi-1', autoDeletionDate: Date.now() + ms('1s') }),
createRoom({ roomName: 'test-gc-multi-2', autoDeletionDate: Date.now() + ms('1s') }),
createRoom({ roomName: 'test-gc-multi-3', autoDeletionDate: Date.now() + ms('1s') }),
createRoom({ roomName: 'test-gc-multi-4', autoDeletionDate: Date.now() + ms('1h') }),
createRoom({ roomName: 'test-gc-multi-5', autoDeletionDate: Date.now() + ms('1h') }),
createRoom({ roomName: 'test-gc-multi-6', autoDeletionDate: Date.now() + ms('1s') }),
createRoom({ roomName: 'test-gc-multi-7', autoDeletionDate: Date.now() + ms('1s') }),
createRoom({ roomName: 'test-gc-multi-8', autoDeletionDate: Date.now() + ms('1s') }),
createRoom({ roomName: 'test-gc-multi-9', autoDeletionDate: Date.now() + ms('1s') }),
createRoom({ roomName: 'test-gc-multi-10', autoDeletionDate: Date.now() + ms('1s') })
]);
// Make sure all rooms are expired
await sleep('2s');
await runRoomGarbageCollector();
for (const room of rooms) {
const response = await getRoom(room.roomId);
if (room.autoDeletionDate! < Date.now()) {
expect(response.status).toBe(404); // Should be deleted
} else {
expect(response.status).toBe(200); // Should still exist
}
}
});
it('should handle expired rooms correctly when specifying autoDeletionPolicy', async () => {
// 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.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');
});
});