backend: replace roomIdPrefix with roomName

This commit is contained in:
juancarmore 2025-08-05 16:36:03 +02:00
parent d8e6da5b4b
commit 459537ecfb
18 changed files with 152 additions and 135 deletions

View File

@ -8,7 +8,7 @@ content:
summary: Full room details response
value:
roomId: 'room-123'
roomIdPrefix: 'room'
roomName: 'room'
creationDate: 1620000000000
autoDeletionDate: 1900000000000
preferences:
@ -26,11 +26,11 @@ content:
value:
roomId: 'room-123'
fields=roomId,roomIdPrefix,creationDate,autoDeletionDate,preferences:
summary: Room details with roomId, roomIdPrefix, creationDate, autoDeletionDate, and preferences
fields=roomId,roomName,creationDate,autoDeletionDate,preferences:
summary: Room details with roomId, roomName, creationDate, autoDeletionDate, and preferences
value:
roomId: 'room-123'
roomIdPrefix: 'room'
roomName: 'room'
creationDate: 1620000000000
autoDeletionDate: 1900000000000
preferences:

View File

@ -17,7 +17,7 @@ content:
value:
rooms:
- roomId: 'room-123'
roomIdPrefix: 'room'
roomName: 'room'
creationDate: 1620000000000
autoDeletionDate: 1900000000000
preferences:
@ -30,7 +30,7 @@ content:
moderatorURL: 'http://localhost:6080/room/room-123?secret=123456'
publisherURL: 'http://localhost:6080/room/room-123?secret=654321'
- roomId: 'room-456'
roomIdPrefix: 'room'
roomName: 'room'
creationDate: 1620001000000
autoDeletionDate: 1900000000000
preferences:
@ -55,12 +55,12 @@ content:
isTruncated: false
maxItems: 10
fields=roomId,roomIdPrefix,creationDate,autoDeletionDate,preferences:
fields=roomId,roomName,creationDate,autoDeletionDate,preferences:
summary: Room details including preferences but no URLs
value:
rooms:
- roomId: 'room-123'
roomIdPrefix: 'room'
roomName: 'room'
creationDate: 1620000000000
autoDeletionDate: 1900000000000
preferences:
@ -71,7 +71,7 @@ content:
virtualBackgroundPreferences:
enabled: true
- roomId: 'room-456'
roomIdPrefix: 'room'
roomName: 'room'
creationDate: 1620001000000
autoDeletionDate: 1900000000000
preferences:

View File

@ -1,5 +1,14 @@
type: object
properties:
roomName:
type: [string, 'null']
maxLength: 50
example: 'room'
default: 'Room'
description: |
The display name of the room, used to identify it in a user-friendly way. This value does not need to be unique.
Maximum length: 50 characters. If not provided, the default value "Room" will be used.
autoDeletionDate:
type: [number, 'null']
example: 1900000000000
@ -11,12 +20,6 @@ properties:
It will be removed after the last participant leaves (graceful deletion).
If not set, the room remains active until manually deleted.
roomIdPrefix:
type: string
example: 'room'
description: >
A prefix to be used for the room ID. The room ID will be generated by concatenating this prefix with an unique identifier.
The maximum length of the room ID is 50 characters.
# maxParticipants:
# type: integer
# example: 10

View File

@ -4,12 +4,16 @@ properties:
type: string
example: 'room-123'
description: >
The unique identifier of the room. This ID is generated when the room is created.
roomIdPrefix:
type: string
The unique identifier of the room. This ID is generated by combining the room name with a unique identifier.
roomName:
type: [string, 'null']
maxLength: 50
example: 'room'
description: >
The prefix used for the room ID. This prefix is used to generate the room ID.
default: 'Room'
description: |
The display name of the room, used to identify it in a user-friendly way. This value does not need to be unique.
Maximum length: 50 characters. If not provided, the default value "Room" will be used.
creationDate:
type: number
example: 1620000000000

View File

@ -14,10 +14,10 @@ export class MeetRoomHelper {
*/
static toOpenViduOptions(room: MeetRoom): MeetRoomOptions {
return {
roomName: room.roomName,
autoDeletionDate: room.autoDeletionDate,
// maxParticipants: room.maxParticipants,
preferences: room.preferences,
roomIdPrefix: room.roomIdPrefix
preferences: room.preferences
// maxParticipants: room.maxParticipants
};
}

View File

@ -13,6 +13,25 @@ import { z } from 'zod';
import INTERNAL_CONFIG from '../../config/internal-config.js';
import { rejectUnprocessableRequest } from '../../models/error.model.js';
/**
* Sanitizes a room name by removing invalid characters and normalizing format.
*
* @param val The string to sanitize
* @returns A sanitized string safe for use as a room name
*/
const sanitizeRoomName = (val: string): string => {
return val
.trim() // Remove leading/trailing spaces
.replace(/[^a-zA-Z0-9_-\s]/g, '') // Allow alphanumeric, underscores, hyphens and spaces
.replace(/\s+/g, ' ') // Replace multiple consecutive spaces with a single space
.replace(/-+/g, '-') // Replace multiple consecutive hyphens with a single hyphen
.replace(/_+/g, '_') // Replace multiple consecutive underscores with a single underscore
.replace(/-+$/, '') // Remove trailing hyphens
.replace(/_+$/, '') // Remove trailing underscores
.replace(/^-+/, '') // Remove leading hyphens
.replace(/^_+/, ''); // Remove leading underscores
};
/**
* Sanitizes an identifier by removing/replacing invalid characters
* and normalizing format.
@ -21,19 +40,7 @@ import { rejectUnprocessableRequest } from '../../models/error.model.js';
* @returns A sanitized string safe for use as an identifier
*/
const sanitizeRoomId = (val: string): string => {
let transformed = val
.trim() // Remove leading/trailing spaces
.replace(/\s+/g, '') // Remove all spaces
.replace(/[^a-zA-Z0-9_-]/g, '') // Allow alphanumeric, underscores and hyphens
.replace(/-+/g, '-') // Replace multiple consecutive hyphens
.replace(/-+$/, ''); // Remove trailing hyphens
// Remove leading hyphens
if (transformed.startsWith('-')) {
transformed = transformed.substring(1);
}
return transformed;
return sanitizeRoomName(val).replace(/\s+/g, ''); // Remove all spaces
};
export const nonEmptySanitizedRoomId = (fieldName: string) =>
@ -94,6 +101,12 @@ const RoomPreferencesSchema: z.ZodType<MeetRoomPreferences> = z.object({
});
const RoomRequestOptionsSchema: z.ZodType<MeetRoomOptions> = z.object({
roomName: z
.string()
.max(50, 'roomName cannot exceed 50 characters')
.transform(sanitizeRoomName)
.optional()
.default('Room'),
autoDeletionDate: z
.number()
.positive('autoDeletionDate must be a positive integer')
@ -102,12 +115,6 @@ const RoomRequestOptionsSchema: z.ZodType<MeetRoomOptions> = z.object({
`autoDeletionDate must be at least ${INTERNAL_CONFIG.MIN_FUTURE_TIME_FOR_ROOM_AUTODELETION_DATE} in the future`
)
.optional(),
roomIdPrefix: z
.string()
.max(50, 'roomIdPrefix cannot exceed 50 characters')
.transform(sanitizeRoomId)
.optional()
.default(''),
preferences: RoomPreferencesSchema.optional().default({
recordingPreferences: { enabled: true, allowAccessTo: MeetRecordingAccess.ADMIN_MODERATOR_PUBLISHER },
chatPreferences: { enabled: true },
@ -185,6 +192,7 @@ export const withValidRoomOptions = (req: Request, res: Response, next: NextFunc
return rejectUnprocessableRequest(res, error);
}
console.log('VALID ROOM OPTIONS', data);
req.body = data;
next();
};

View File

@ -50,7 +50,6 @@ roomRouter.get(
configureRoomAuthorization,
roomCtrl.getRoom
);
roomRouter.put(
'/:roomId',
withAuth(apiKeyValidator, tokenAndRoleValidator(UserRole.ADMIN)),

View File

@ -69,12 +69,13 @@ export class RoomService {
*
*/
async createMeetRoom(baseUrl: string, roomOptions: MeetRoomOptions): Promise<MeetRoom> {
const { preferences, autoDeletionDate, roomIdPrefix } = roomOptions;
const roomId = roomIdPrefix ? `${roomIdPrefix}-${uid(15)}` : uid(15);
const { roomName, autoDeletionDate, preferences } = roomOptions;
const roomIdPrefix = roomName!.replace(/\s+/g, ''); // Remove all spaces
const roomId = `${roomIdPrefix}-${uid(15)}`; // Generate a unique room ID based on the room name
const meetRoom: MeetRoom = {
roomId,
roomIdPrefix,
roomName: roomName!,
creationDate: Date.now(),
// maxParticipants,
autoDeletionDate,

View File

@ -86,12 +86,12 @@ export const expectSuccessRoomsResponse = (
export const expectSuccessRoomResponse = (
response: any,
idPrefix: string,
roomName: string,
autoDeletionDate?: number,
preferences?: MeetRoomPreferences
) => {
expect(response.status).toBe(200);
expectValidRoom(response.body, idPrefix, autoDeletionDate, preferences);
expectValidRoom(response.body, roomName, autoDeletionDate, preferences);
};
export const expectSuccessRoomPreferencesResponse = (response: any, preferences: MeetRoomPreferences) => {
@ -102,7 +102,7 @@ export const expectSuccessRoomPreferencesResponse = (response: any, preferences:
export const expectValidRoom = (
room: MeetRoom,
idPrefix: string,
name: string,
autoDeletionDate?: number,
preferences?: MeetRoomPreferences,
markedForDeletion?: boolean
@ -110,10 +110,10 @@ export const expectValidRoom = (
expect(room).toBeDefined();
expect(room.roomId).toBeDefined();
expect(room.roomIdPrefix).toBeDefined();
expect(room.roomIdPrefix).toBe(idPrefix);
expect(room.roomName).toBeDefined();
expect(room.roomName).toBe(name);
expect(room.roomId).not.toBe('');
expect(room.roomId).toContain(room.roomIdPrefix);
expect(room.roomId).toContain(room.roomName.replace(/\s+/g, '')); // Ensure roomId contains the name without spaces
expect(room.creationDate).toBeDefined();
if (autoDeletionDate !== undefined) {

View File

@ -34,15 +34,17 @@ export interface TestContext {
* Creates a single room with optional participant.
*
* @param withParticipant Whether to join a fake participant in the room.
* @param roomName Name of the room to create.
* @param preferences Optional room preferences.
* @returns Room data including secrets and cookies.
*/
export const setupSingleRoom = async (
withParticipant = false,
roomPrefix = 'TEST_ROOM',
roomName = 'TEST_ROOM',
preferences?: MeetRoomPreferences
): Promise<RoomData> => {
const room = await createRoom({
roomIdPrefix: roomPrefix,
roomName,
preferences
});

View File

@ -31,7 +31,7 @@ describe('Room API Tests', () => {
});
it('should delete room (204) with invalid force parameter when no participants exist', async () => {
const { roomId } = await createRoom({ roomIdPrefix: 'test-invalid-force' });
const { roomId } = await createRoom({ roomName: 'test-invalid-force' });
const response = await bulkDeleteRooms([roomId]);
@ -41,7 +41,7 @@ describe('Room API Tests', () => {
});
it('should mark room for deletion (202) with invalid force parameter when participants exist', async () => {
const { roomId } = await createRoom({ roomIdPrefix: 'test-invalid-force' });
const { roomId } = await createRoom({ roomName: 'test-invalid-force' });
await joinFakeParticipant(roomId, 'test-participant-1');
@ -53,7 +53,7 @@ describe('Room API Tests', () => {
});
it('should delete room (204) with force=true parameter when no participants exist', async () => {
const { roomId } = await createRoom({ roomIdPrefix: 'test-force' });
const { roomId } = await createRoom({ roomName: 'test-force' });
const response = await bulkDeleteRooms([roomId], true);
@ -63,7 +63,7 @@ describe('Room API Tests', () => {
});
it('should delete room (204) with force=true parameter when participants exist', async () => {
const { roomId } = await createRoom({ roomIdPrefix: 'test-force' });
const { roomId } = await createRoom({ roomName: 'test-force' });
await joinFakeParticipant(roomId, 'test-participant-1');
@ -75,7 +75,7 @@ describe('Room API Tests', () => {
});
it('should successfully delete the room requesting the same roomId multiple times', async () => {
const { roomId } = await createRoom({ roomIdPrefix: 'test-duplicate' });
const { roomId } = await createRoom({ roomName: 'test-duplicate' });
const response = await bulkDeleteRooms([roomId, roomId, roomId], true);
@ -84,7 +84,7 @@ describe('Room API Tests', () => {
});
it('should successfully delete valid roomIds while ignoring invalid ones', async () => {
const { roomId } = await createRoom({ roomIdPrefix: 'test-invalid-force' });
const { roomId } = await createRoom({ roomName: 'test-invalid-force' });
const response = await bulkDeleteRooms([roomId, '!!@##$']);
@ -95,8 +95,8 @@ describe('Room API Tests', () => {
it('should successfully delete multiple rooms with valid roomIds', async () => {
// Create test rooms
const [room1, room2] = await Promise.all([
createRoom({ roomIdPrefix: 'test-bulk-1' }),
createRoom({ roomIdPrefix: 'test-bulk-2' })
createRoom({ roomName: 'test-bulk-1' }),
createRoom({ roomName: 'test-bulk-2' })
]);
// Delete both rooms
@ -117,8 +117,8 @@ describe('Room API Tests', () => {
it('should successfully marked for deletion multiple rooms with valid roomIds', async () => {
// Create test rooms
const [room1, room2] = await Promise.all([
createRoom({ roomIdPrefix: 'test-bulk-1' }),
createRoom({ roomIdPrefix: 'test-bulk-2' })
createRoom({ roomName: 'test-bulk-1' }),
createRoom({ roomName: 'test-bulk-2' })
]);
await Promise.all([
@ -147,7 +147,7 @@ describe('Room API Tests', () => {
it('should sanitize roomIds before deleting', async () => {
// Create a test room
const { roomId } = await createRoom({ roomIdPrefix: 'test-sanitize' });
const { roomId } = await createRoom({ roomName: 'test-sanitize' });
const response = await bulkDeleteRooms([roomId + '!!@##$']);
expect(response.status).toBe(204);
@ -160,8 +160,8 @@ describe('Room API Tests', () => {
it('should delete rooms when force=true and participants exist', async () => {
// Create test rooms
const [room1, room2] = await Promise.all([
createRoom({ roomIdPrefix: 'test-bulk-1' }),
createRoom({ roomIdPrefix: 'test-bulk-2' })
createRoom({ roomName: 'test-bulk-1' }),
createRoom({ roomName: 'test-bulk-2' })
]);
// Join a participant to the rooms
@ -188,8 +188,8 @@ describe('Room API Tests', () => {
it('should return mixed results (200) when some rooms are deleted and others marked for deletion', async () => {
// Create rooms
const room1 = await createRoom({ roomIdPrefix: 'empty-room' });
const room2 = await createRoom({ roomIdPrefix: 'occupied-room' });
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');
@ -214,7 +214,7 @@ describe('Room API Tests', () => {
it('should handle a large number of room IDs', async () => {
// Create 20+ rooms and test deletion
const rooms = await Promise.all(
Array.from({ length: 20 }, (_, i) => createRoom({ roomIdPrefix: `bulk-${i}` }))
Array.from({ length: 20 }, (_, i) => createRoom({ roomName: `bulk-${i}` }))
);
const response = await bulkDeleteRooms(rooms.map((r) => r.roomId));
@ -230,7 +230,7 @@ describe('Room API Tests', () => {
it('should handle a large number of room IDs with mixed valid and invalid IDs', async () => {
// Create 20+ rooms and test deletion
const rooms = await Promise.all(
Array.from({ length: 20 }, (_, i) => createRoom({ roomIdPrefix: `bulk-${i}` }))
Array.from({ length: 20 }, (_, i) => createRoom({ roomName: `bulk-${i}` }))
);
await joinFakeParticipant(rooms[0].roomId, 'test-participant-1');

View File

@ -27,23 +27,23 @@ describe('Room API Tests', () => {
describe('Room Creation Tests', () => {
it('Should create a room without autoDeletionDate (default behavior)', async () => {
const room = await createRoom({
roomIdPrefix: ' Test Room '
roomName: ' Test Room '
});
expectValidRoom(room, 'TestRoom');
expectValidRoom(room, 'Test Room');
});
it('Should create a room with a valid autoDeletionDate', async () => {
const room = await createRoom({
autoDeletionDate: validAutoDeletionDate,
roomIdPrefix: ' .,-------}{¡$#<+My Room *123 '
roomName: ' .,-------}{¡$#<+My Room *123 '
});
expectValidRoom(room, 'MyRoom123', validAutoDeletionDate);
expectValidRoom(room, 'My Room 123', validAutoDeletionDate);
});
it('Should create a room when sending full valid payload', async () => {
const payload = {
roomIdPrefix: ' =Example Room&/ ',
roomName: ' =Example Room&/ ',
autoDeletionDate: validAutoDeletionDate,
preferences: {
recordingPreferences: {
@ -57,7 +57,7 @@ describe('Room API Tests', () => {
const room = await createRoom(payload);
expectValidRoom(room, 'ExampleRoom', validAutoDeletionDate, payload.preferences);
expectValidRoom(room, 'Example Room', validAutoDeletionDate, payload.preferences);
});
});
@ -65,7 +65,7 @@ describe('Room API Tests', () => {
it('should fail when autoDeletionDate is negative', async () => {
const payload = {
autoDeletionDate: -5000,
roomIdPrefix: 'TestRoom'
roomName: 'TestRoom'
};
const response = await request(app).post(ROOMS_PATH).set('Cookie', adminCookie).send(payload).expect(422);
@ -78,7 +78,7 @@ describe('Room API Tests', () => {
it('should fail when autoDeletionDate is less than 1 hour in the future', async () => {
const payload = {
autoDeletionDate: Date.now() + ms('30m'),
roomIdPrefix: 'TestRoom'
roomName: 'TestRoom'
};
const response = await request(app).post(ROOMS_PATH).set('Cookie', adminCookie).send(payload).expect(422);
@ -92,7 +92,7 @@ describe('Room API Tests', () => {
it('should fail when autoDeletionDate is not a number (string provided)', async () => {
const payload = {
autoDeletionDate: 'not-a-number',
roomIdPrefix: 'TestRoom'
roomName: 'TestRoom'
};
const response = await request(app).post(ROOMS_PATH).set('Cookie', adminCookie).send(payload).expect(422);
@ -103,7 +103,7 @@ describe('Room API Tests', () => {
it('should fail when autoDeletionDate is a boolean', async () => {
const payload = {
autoDeletionDate: true,
roomIdPrefix: 'TestRoom'
roomName: 'TestRoom'
};
const response = await request(app).post(ROOMS_PATH).set('Cookie', adminCookie).send(payload).expect(422);
@ -114,7 +114,7 @@ describe('Room API Tests', () => {
it('should fail when autoDeletionDate is omitted but provided as null', async () => {
const payload = {
autoDeletionDate: null,
roomIdPrefix: 'TestRoom'
roomName: 'TestRoom'
};
const response = await request(app).post(ROOMS_PATH).set('Cookie', adminCookie).send(payload).expect(422);
@ -122,9 +122,9 @@ describe('Room API Tests', () => {
expect(JSON.stringify(response.body.details)).toContain('Expected number');
});
it('should fail when roomIdPrefix is not a string (number provided)', async () => {
it('should fail when roomName is not a string (number provided)', async () => {
const payload = {
roomIdPrefix: 12345,
roomName: 12345,
autoDeletionDate: validAutoDeletionDate
};
@ -133,9 +133,9 @@ describe('Room API Tests', () => {
expect(JSON.stringify(response.body.details)).toContain('Expected string');
});
it('should fail when roomIdPrefix is a boolean', async () => {
it('should fail when roomName is a boolean', async () => {
const payload = {
roomIdPrefix: false,
roomName: false,
autoDeletionDate: validAutoDeletionDate
};
@ -146,7 +146,7 @@ describe('Room API Tests', () => {
it('should fail when preferences is not an object (string provided)', async () => {
const payload = {
roomIdPrefix: 'TestRoom',
roomName: 'TestRoom',
autoDeletionDate: validAutoDeletionDate,
preferences: 'invalid-preferences'
};
@ -160,7 +160,7 @@ describe('Room API Tests', () => {
// Assuming preferences expects each sub-property to be an object with a boolean "enabled",
// here we deliberately use an invalid structure.
const payload = {
roomIdPrefix: 'TestRoom',
roomName: 'TestRoom',
autoDeletionDate: validAutoDeletionDate,
preferences: {
recordingPreferences: {
@ -183,23 +183,23 @@ describe('Room API Tests', () => {
.post(ROOMS_PATH)
.set('Cookie', adminCookie)
.set('Content-Type', 'application/json')
.send('{"roomIdPrefix": "TestRoom",') // invalid JSON syntax
.send('{"roomName": "TestRoom",') // invalid JSON syntax
.expect(400);
expect(response.body.error).toContain('Bad Request');
expect(response.body.message).toContain('Malformed body');
});
it('should fail when roomIdPrefix is too long', async () => {
it('should fail when roomName is too long', async () => {
const longRoomId = 'a'.repeat(51);
const payload = {
roomIdPrefix: longRoomId,
roomName: longRoomId,
autoDeletionDate: validAutoDeletionDate
};
const response = await request(app).post(ROOMS_PATH).set('Cookie', adminCookie).send(payload).expect(422);
expect(JSON.stringify(response.body.details)).toContain('roomIdPrefix cannot exceed 50 characters');
expect(JSON.stringify(response.body.details)).toContain('roomName cannot exceed 50 characters');
});
});
});

View File

@ -36,7 +36,7 @@ describe('Room API Tests', () => {
it('should default to force=false when force parameter is invalid', async () => {
// Create a room first
const { roomId } = await createRoom({
roomIdPrefix: 'test-room'
roomName: 'test-room'
});
const response = await deleteRoom(roomId, { force: 'not-a-boolean' });
@ -49,7 +49,7 @@ describe('Room API Tests', () => {
it('should mark room for deletion when participants exist and force parameter is invalid', async () => {
// Create a room first
const { roomId } = await createRoom({
roomIdPrefix: 'test-room'
roomName: 'test-room'
});
await joinFakeParticipant(roomId, 'test-participant');
@ -70,7 +70,7 @@ describe('Room API Tests', () => {
});
it('should delete an empty room completely (204)', async () => {
const { roomId } = await createRoom({ roomIdPrefix: 'test-room' });
const { roomId } = await createRoom({ roomName: 'test-room' });
const response = await deleteRoom(roomId);
@ -84,7 +84,7 @@ describe('Room API Tests', () => {
it('should sanitize roomId with spaces and special characters before deletion', async () => {
// Create a room first
const createdRoom = await createRoom({
roomIdPrefix: 'test-mixed'
roomName: 'test-mixed'
});
// Add some spaces and special chars to the valid roomId
@ -101,7 +101,7 @@ describe('Room API Tests', () => {
it('should handle explicit force=true for room with no participants', async () => {
const createdRoom = await createRoom({
roomIdPrefix: 'test-room'
roomName: 'test-room'
});
const response = await deleteRoom(createdRoom.roomId, { force: true });
@ -116,7 +116,7 @@ describe('Room API Tests', () => {
it('should mark room for deletion (202) when participants exist and force=false', async () => {
const autoDeletionDate = Date.now() + ms('5h');
const { roomId } = await createRoom({
roomIdPrefix: 'test-room',
roomName: 'test-room',
autoDeletionDate
});
@ -133,7 +133,7 @@ describe('Room API Tests', () => {
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({
roomIdPrefix: 'test-room',
roomName: 'test-room',
autoDeletionDate
});
@ -166,7 +166,7 @@ describe('Room API Tests', () => {
it('should force delete (204) room with active participants when force=true', async () => {
const { roomId } = await createRoom({
roomIdPrefix: 'test-room'
roomName: 'test-room'
});
await joinFakeParticipant(roomId, 'test-participant');
@ -182,7 +182,7 @@ describe('Room API Tests', () => {
});
it('should successfully delete a room already marked for deletion', async () => {
const { roomId } = await createRoom({ roomIdPrefix: 'test-marked' });
const { roomId } = await createRoom({ roomName: 'test-marked' });
// First mark it for deletion
await joinFakeParticipant(roomId, 'test-participant');
@ -195,7 +195,7 @@ describe('Room API Tests', () => {
});
it('should handle repeated deletion of the same room gracefully', async () => {
const { roomId } = await createRoom({ roomIdPrefix: 'test-idempotent' });
const { roomId } = await createRoom({ roomName: 'test-idempotent' });
// Delete first time
const response1 = await deleteRoom(roomId);

View File

@ -31,7 +31,7 @@ describe('Room Garbage Collector Tests', () => {
it('should delete a room with a past auto-deletion date if no participant is present', async () => {
const createdRoom = await createRoom({
roomIdPrefix: 'test-gc',
roomName: 'test-gc',
autoDeletionDate: Date.now() + ms('1s')
});
@ -50,7 +50,7 @@ describe('Room Garbage Collector Tests', () => {
it('should mark room for deletion but not delete when expiration date has passed and participants exist', async () => {
const createdRoom = await createRoom({
roomIdPrefix: 'test-gc-participants',
roomName: 'test-gc-participants',
autoDeletionDate: Date.now() + ms('1s')
});
@ -66,7 +66,7 @@ describe('Room Garbage Collector Tests', () => {
it('should not touch a room with a future auto-deletion date', async () => {
const createdRoom = await createRoom({
roomIdPrefix: 'test-gc-future',
roomName: 'test-gc-future',
autoDeletionDate: Date.now() + ms('1h')
});
@ -79,7 +79,7 @@ describe('Room Garbage Collector Tests', () => {
it('should delete a room after the last participant leaves when it was marked for deletion', async () => {
const { roomId } = await createRoom({
roomIdPrefix: 'test-gc-lifecycle',
roomName: 'test-gc-lifecycle',
autoDeletionDate: Date.now() + ms('1s')
});
@ -118,7 +118,7 @@ describe('Room Garbage Collector Tests', () => {
it('should never delete a room without an auto-deletion date', async () => {
const createdRoom = await createRoom({
roomIdPrefix: 'test-gc-no-date'
roomName: 'test-gc-no-date'
});
await runRoomGarbageCollector();
@ -135,16 +135,16 @@ describe('Room Garbage Collector Tests', () => {
it('should handle multiple expired rooms in one batch', async () => {
const rooms = await Promise.all([
createRoom({ roomIdPrefix: 'test-gc-multi-1', autoDeletionDate: Date.now() + ms('1s') }),
createRoom({ roomIdPrefix: 'test-gc-multi-2', autoDeletionDate: Date.now() + ms('1s') }),
createRoom({ roomIdPrefix: 'test-gc-multi-3', autoDeletionDate: Date.now() + ms('1s') }),
createRoom({ roomIdPrefix: 'test-gc-multi-4', autoDeletionDate: Date.now() + ms('1h') }),
createRoom({ roomIdPrefix: 'test-gc-multi-5', autoDeletionDate: Date.now() + ms('1h') }),
createRoom({ roomIdPrefix: 'test-gc-multi-6', autoDeletionDate: Date.now() + ms('1s') }),
createRoom({ roomIdPrefix: 'test-gc-multi-7', autoDeletionDate: Date.now() + ms('1s') }),
createRoom({ roomIdPrefix: 'test-gc-multi-8', autoDeletionDate: Date.now() + ms('1s') }),
createRoom({ roomIdPrefix: 'test-gc-multi-9', autoDeletionDate: Date.now() + ms('1s') }),
createRoom({ roomIdPrefix: 'test-gc-multi-10', autoDeletionDate: Date.now() + ms('1s') })
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

View File

@ -35,7 +35,7 @@ describe('Room API Tests', () => {
it('should retrieve custom room preferences', async () => {
const payload = {
roomIdPrefix: 'custom-prefs',
roomName: 'custom-prefs',
preferences: {
recordingPreferences: {
enabled: true,
@ -46,7 +46,7 @@ describe('Room API Tests', () => {
}
};
const roomData = await setupSingleRoom(false, payload.roomIdPrefix, payload.preferences);
const roomData = await setupSingleRoom(false, payload.roomName, payload.preferences);
const roomId = roomData.room.roomId;
const cookie = roomData.moderatorCookie;

View File

@ -22,7 +22,7 @@ describe('Room API Tests', () => {
describe('Get Room Tests', () => {
it('should successfully retrieve a room by its ID', async () => {
const createdRoom = await createRoom({
roomIdPrefix: 'test-room'
roomName: 'test-room'
});
expectValidRoom(createdRoom, 'test-room');
@ -33,7 +33,7 @@ describe('Room API Tests', () => {
it('should retrieve a room with custom preferences', async () => {
const payload = {
roomIdPrefix: 'custom-prefs',
roomName: 'custom-prefs',
preferences: {
recordingPreferences: {
enabled: true,
@ -55,22 +55,22 @@ describe('Room API Tests', () => {
it('should retrieve only specified fields when using fields parameter', async () => {
// Create a room
const createdRoom = await createRoom({
roomIdPrefix: 'field-filtered'
roomName: 'field-filtered'
});
// Get the room with field filtering
const response = await getRoom(createdRoom.roomId, 'roomId,roomIdPrefix');
const response = await getRoom(createdRoom.roomId, 'roomId,roomName');
// Verify that only the requested fields are returned
expect(response.status).toBe(200);
expectValidRoomWithFields(response.body, ['roomId', 'roomIdPrefix']);
expectValidRoomWithFields(response.body, ['roomId', 'roomName']);
});
it('should handle roomId with characters that need sanitization', async () => {
// Create a room
const createdRoom = await createRoom({
roomIdPrefix: 'test-room'
roomName: 'test-room'
});
const dirtyRoomId = ' ' + createdRoom.roomId + ' '; // Add spaces that should be trimmed
@ -86,7 +86,7 @@ describe('Room API Tests', () => {
// Create a room with autoDeletionDate
const createdRoom = await createRoom({
roomIdPrefix: 'deletion-date',
roomName: 'deletion-date',
autoDeletionDate: validAutoDeletionDate
});

View File

@ -30,7 +30,7 @@ describe('Room API Tests', () => {
it('should return a list of rooms', async () => {
await createRoom({
roomIdPrefix: 'test-room'
roomName: 'test-room'
});
const response = await getRooms();
@ -41,7 +41,7 @@ describe('Room API Tests', () => {
it('should return a list of rooms applying fields filter', async () => {
await createRoom({
roomIdPrefix: 'test-room',
roomName: 'test-room',
autoDeletionDate: validAutoDeletionDate
});
@ -56,7 +56,7 @@ describe('Room API Tests', () => {
it('should return a list of rooms with pagination', async () => {
const promises = [0, 1, 2, 3, 4, 5].map((i) => {
return createRoom({
roomIdPrefix: `test-room-${i}`,
roomName: `test-room-${i}`,
autoDeletionDate: validAutoDeletionDate
});
});

View File

@ -32,7 +32,7 @@ describe('Room API Tests', () => {
it('should successfully update room preferences', async () => {
const sendSignalSpy = jest.spyOn(frontendEventService as any, 'sendSignal');
const createdRoom = await createRoom({
roomIdPrefix: 'update-test',
roomName: 'update-test',
preferences: {
recordingPreferences: {
enabled: true,
@ -81,7 +81,7 @@ describe('Room API Tests', () => {
it('should allow partial preference updates', async () => {
// Create a room first with all preferences enabled
const createdRoom = await createRoom({
roomIdPrefix: 'partial-update',
roomName: 'partial-update',
preferences: {
recordingPreferences: {
enabled: true,
@ -118,7 +118,7 @@ describe('Room API Tests', () => {
describe('Update Room Validation failures', () => {
it('should fail when preferences have incorrect structure', async () => {
const { roomId } = await createRoom({
roomIdPrefix: 'validation-test'
roomName: 'validation-test'
});
// Invalid preferences (missing required fields)
@ -139,7 +139,7 @@ describe('Room API Tests', () => {
it('should fail when preferences have incorrect types', async () => {
const createdRoom = await createRoom({
roomIdPrefix: 'type-test'
roomName: 'type-test'
});
// Invalid preferences (wrong types)
@ -161,7 +161,7 @@ describe('Room API Tests', () => {
it('should fail when preferences are missing required properties', async () => {
const createdRoom = await createRoom({
roomIdPrefix: 'missing-props'
roomName: 'missing-props'
});
const emptyPreferences = {};
@ -174,7 +174,7 @@ describe('Room API Tests', () => {
it('should fail when recording is enabled but allowAccessTo is missing', async () => {
const createdRoom = await createRoom({
roomIdPrefix: 'missing-access'
roomName: 'missing-access'
});
const invalidPreferences = {
recordingPreferences: {