tests: refactor API tests to reflect backend code changes
- Updated the `generateRoomMemberToken` function to use `joinMeeting` instead of `grantJoinMeetingPermission` for clarity. - Changed test descriptions to reflect the new parameter names and improved readability. - Removed unnecessary imports and cleaned up tests related to recording access configurations. - Updated validation error messages for better clarity in the API responses. - Refactored security configuration tests to align with the new authentication structure. - Removed deprecated tests for room member roles. - Adjusted user profile tests to reflect changes in the response structure.
This commit is contained in:
parent
2bc1d02620
commit
b2488544e3
@ -1,18 +1,17 @@
|
||||
import { expect } from '@jest/globals';
|
||||
import {
|
||||
LiveKitPermissions,
|
||||
MeetingEndAction,
|
||||
MeetRecordingAccess,
|
||||
MeetRecordingInfo,
|
||||
MeetRecordingLayout,
|
||||
MeetRecordingStatus,
|
||||
MeetRoom,
|
||||
MeetRoomAutoDeletionPolicy,
|
||||
MeetRoomConfig,
|
||||
MeetRoomDeletionPolicyWithMeeting,
|
||||
MeetRoomDeletionPolicyWithRecordings,
|
||||
MeetRoomMemberPermissions,
|
||||
MeetRoomMemberRole,
|
||||
MeetRoomStatus
|
||||
MeetRoomStatus,
|
||||
TrackSource
|
||||
} from '@openvidu-meet/typings';
|
||||
import { Response } from 'supertest';
|
||||
import { container } from '../../src/config/dependency-injector.config';
|
||||
@ -136,16 +135,12 @@ export const expectValidRoom = (
|
||||
expect(room.autoDeletionDate).toBe(autoDeletionDate);
|
||||
} else {
|
||||
expect(room.autoDeletionDate).toBeUndefined();
|
||||
expect(room.autoDeletionPolicy).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.config).toBeDefined();
|
||||
@ -156,8 +151,7 @@ export const expectValidRoom = (
|
||||
expect(room.config).toEqual({
|
||||
recording: {
|
||||
enabled: true,
|
||||
layout: MeetRecordingLayout.GRID,
|
||||
allowAccessTo: MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
layout: MeetRecordingLayout.GRID
|
||||
},
|
||||
chat: { enabled: true },
|
||||
virtualBackground: { enabled: true },
|
||||
@ -165,10 +159,21 @@ export const expectValidRoom = (
|
||||
});
|
||||
}
|
||||
|
||||
expect(room.moderatorUrl).toBeDefined();
|
||||
expect(room.speakerUrl).toBeDefined();
|
||||
expect(room.moderatorUrl).toContain(room.roomId);
|
||||
expect(room.speakerUrl).toContain(room.roomId);
|
||||
expect(room.owner).toBeDefined();
|
||||
expect(room.roles).toBeDefined();
|
||||
|
||||
expect(room.anonymous).toBeDefined();
|
||||
expect(room.anonymous.moderator).toBeDefined();
|
||||
expect(room.anonymous.speaker).toBeDefined();
|
||||
expect(room.anonymous.moderator.enabled).toBeDefined();
|
||||
expect(room.anonymous.speaker.enabled).toBeDefined();
|
||||
expect(room.anonymous.moderator.accessUrl).toBeDefined();
|
||||
expect(room.anonymous.speaker.accessUrl).toBeDefined();
|
||||
expect(room.anonymous.moderator.accessUrl).toContain(room.roomId);
|
||||
expect(room.anonymous.speaker.accessUrl).toContain(room.roomId);
|
||||
|
||||
expect(room.accessUrl).toBeDefined();
|
||||
expect(room.accessUrl).toContain(room.roomId);
|
||||
|
||||
expect(room.status).toBeDefined();
|
||||
expect(room.status).toEqual(status || MeetRoomStatus.OPEN);
|
||||
@ -518,90 +523,13 @@ export const expectValidGetRecordingUrlResponse = (response: Response, recording
|
||||
expect(parsedUrl.searchParams.get('secret')).toBeDefined();
|
||||
};
|
||||
|
||||
export const expectValidRoomMemberRolesAndPermissionsResponse = (response: Response, roomId: string) => {
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.body).toEqual(
|
||||
expect.arrayContaining([
|
||||
{
|
||||
role: MeetRoomMemberRole.MODERATOR,
|
||||
permissions: getPermissions(roomId, MeetRoomMemberRole.MODERATOR, true, true)
|
||||
},
|
||||
{
|
||||
role: MeetRoomMemberRole.SPEAKER,
|
||||
permissions: getPermissions(roomId, MeetRoomMemberRole.SPEAKER, true, false)
|
||||
}
|
||||
])
|
||||
);
|
||||
};
|
||||
|
||||
export const expectValidRoomMemberRoleAndPermissionsResponse = (
|
||||
response: Response,
|
||||
roomId: string,
|
||||
role: MeetRoomMemberRole
|
||||
) => {
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.body).toEqual({
|
||||
role: role,
|
||||
permissions: getPermissions(roomId, role, true, role === MeetRoomMemberRole.MODERATOR)
|
||||
});
|
||||
};
|
||||
|
||||
export const getPermissions = (
|
||||
roomId: string,
|
||||
role: MeetRoomMemberRole,
|
||||
canRetrieveRecordings: boolean,
|
||||
canDeleteRecordings: boolean,
|
||||
addJoinPermission = true
|
||||
): MeetRoomMemberPermissions => {
|
||||
switch (role) {
|
||||
case MeetRoomMemberRole.MODERATOR:
|
||||
return {
|
||||
livekit: {
|
||||
roomJoin: addJoinPermission,
|
||||
room: roomId,
|
||||
canPublish: true,
|
||||
canSubscribe: true,
|
||||
canPublishData: true,
|
||||
canUpdateOwnMetadata: true
|
||||
},
|
||||
meet: {
|
||||
canRecord: true,
|
||||
canRetrieveRecordings,
|
||||
canDeleteRecordings,
|
||||
canChat: true,
|
||||
canChangeVirtualBackground: true
|
||||
}
|
||||
};
|
||||
case MeetRoomMemberRole.SPEAKER:
|
||||
return {
|
||||
livekit: {
|
||||
roomJoin: addJoinPermission,
|
||||
room: roomId,
|
||||
canPublish: true,
|
||||
canSubscribe: true,
|
||||
canPublishData: true,
|
||||
canUpdateOwnMetadata: true
|
||||
},
|
||||
meet: {
|
||||
canRecord: false,
|
||||
canRetrieveRecordings,
|
||||
canDeleteRecordings,
|
||||
canChat: true,
|
||||
canChangeVirtualBackground: true
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
export const expectValidRoomMemberTokenResponse = (
|
||||
response: Response,
|
||||
roomId: string,
|
||||
role: MeetRoomMemberRole,
|
||||
addJoinPermission = false,
|
||||
baseRole: MeetRoomMemberRole,
|
||||
joinMeeting = false,
|
||||
participantName?: string,
|
||||
participantIdentityPrefix?: string,
|
||||
canRetrieveRecordings?: boolean,
|
||||
canDeleteRecordings?: boolean
|
||||
participantIdentityPrefix?: string
|
||||
) => {
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.body).toHaveProperty('token');
|
||||
@ -609,11 +537,7 @@ export const expectValidRoomMemberTokenResponse = (
|
||||
const token = response.body.token;
|
||||
const decodedToken = decodeJWTToken(token);
|
||||
|
||||
canRetrieveRecordings = canRetrieveRecordings ?? true;
|
||||
canDeleteRecordings = canDeleteRecordings ?? role === MeetRoomMemberRole.MODERATOR;
|
||||
const permissions = getPermissions(roomId, role, canRetrieveRecordings, canDeleteRecordings, addJoinPermission);
|
||||
|
||||
if (addJoinPermission) {
|
||||
if (joinMeeting) {
|
||||
expect(participantName).toBeDefined();
|
||||
expect(decodedToken).toHaveProperty('name', participantName);
|
||||
expect(decodedToken).toHaveProperty('sub');
|
||||
@ -621,17 +545,88 @@ export const expectValidRoomMemberTokenResponse = (
|
||||
if (participantIdentityPrefix) {
|
||||
expect(decodedToken.sub?.startsWith(participantIdentityPrefix)).toBe(true);
|
||||
}
|
||||
|
||||
// const livekitPermissions = getLiveKitPermissions(roomId, getPermissions(baseRole));
|
||||
expect(decodedToken).toHaveProperty('video');
|
||||
} else {
|
||||
expect(decodedToken).not.toHaveProperty('name');
|
||||
expect(decodedToken).not.toHaveProperty('sub');
|
||||
expect(decodedToken).not.toHaveProperty('video');
|
||||
}
|
||||
|
||||
expect(decodedToken).toHaveProperty('video', permissions.livekit);
|
||||
expect(decodedToken).toHaveProperty('metadata');
|
||||
const metadata = JSON.parse(decodedToken.metadata || '{}');
|
||||
expect(metadata).toHaveProperty('livekitUrl');
|
||||
expect(metadata).toHaveProperty('role', role);
|
||||
expect(metadata).toHaveProperty('permissions', permissions.meet);
|
||||
expect(metadata).toHaveProperty('baseRole', baseRole);
|
||||
const permissions = getPermissions(baseRole);
|
||||
expect(metadata).toHaveProperty('effectivePermissions', permissions);
|
||||
};
|
||||
|
||||
export const getPermissions = (role: MeetRoomMemberRole): MeetRoomMemberPermissions => {
|
||||
switch (role) {
|
||||
case MeetRoomMemberRole.MODERATOR:
|
||||
return {
|
||||
canRecord: true,
|
||||
canRetrieveRecordings: true,
|
||||
canDeleteRecordings: true,
|
||||
canJoinMeeting: true,
|
||||
canShareAccessLinks: true,
|
||||
canMakeModerator: true,
|
||||
canKickParticipants: true,
|
||||
canEndMeeting: true,
|
||||
canPublishVideo: true,
|
||||
canPublishAudio: true,
|
||||
canShareScreen: true,
|
||||
canReadChat: true,
|
||||
canWriteChat: true,
|
||||
canChangeVirtualBackground: true
|
||||
};
|
||||
case MeetRoomMemberRole.SPEAKER:
|
||||
return {
|
||||
canRecord: false,
|
||||
canRetrieveRecordings: true,
|
||||
canDeleteRecordings: false,
|
||||
canJoinMeeting: true,
|
||||
canShareAccessLinks: false,
|
||||
canMakeModerator: false,
|
||||
canKickParticipants: false,
|
||||
canEndMeeting: false,
|
||||
canPublishVideo: true,
|
||||
canPublishAudio: true,
|
||||
canShareScreen: true,
|
||||
canReadChat: true,
|
||||
canWriteChat: true,
|
||||
canChangeVirtualBackground: true
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const getLiveKitPermissions = (roomId: string, permissions: MeetRoomMemberPermissions): LiveKitPermissions => {
|
||||
const canPublishSources: TrackSource[] = [];
|
||||
|
||||
if (permissions.canPublishAudio) {
|
||||
canPublishSources.push(TrackSource.MICROPHONE);
|
||||
}
|
||||
|
||||
if (permissions.canPublishVideo) {
|
||||
canPublishSources.push(TrackSource.CAMERA);
|
||||
}
|
||||
|
||||
if (permissions.canShareScreen) {
|
||||
canPublishSources.push(TrackSource.SCREEN_SHARE);
|
||||
canPublishSources.push(TrackSource.SCREEN_SHARE_AUDIO);
|
||||
}
|
||||
|
||||
const livekitPermissions: LiveKitPermissions = {
|
||||
room: roomId,
|
||||
roomJoin: true,
|
||||
canPublish: permissions.canPublishAudio || permissions.canPublishVideo || permissions.canShareScreen,
|
||||
canPublishSources,
|
||||
canSubscribe: true,
|
||||
canPublishData: true,
|
||||
canUpdateOwnMetadata: true
|
||||
};
|
||||
return livekitPermissions;
|
||||
};
|
||||
|
||||
const decodeJWTToken = (token: string) => {
|
||||
|
||||
@ -1,8 +1,6 @@
|
||||
import { expect } from '@jest/globals';
|
||||
import {
|
||||
AuthMode,
|
||||
MeetAppearanceConfig,
|
||||
MeetRecordingAccess,
|
||||
MeetRecordingInfo,
|
||||
MeetRecordingStatus,
|
||||
MeetRoom,
|
||||
@ -30,13 +28,6 @@ import { GlobalConfigService } from '../../src/services/global-config.service.js
|
||||
import { RecordingService } from '../../src/services/recording.service.js';
|
||||
import { RoomScheduledTasksService } from '../../src/services/room-scheduled-tasks.service.js';
|
||||
|
||||
const CREDENTIALS = {
|
||||
admin: {
|
||||
username: MEET_ENV.INITIAL_ADMIN_USER,
|
||||
password: MEET_ENV.INITIAL_ADMIN_PASSWORD
|
||||
}
|
||||
};
|
||||
|
||||
let app: Express;
|
||||
const fakeParticipantsProcesses = new Map<string, ChildProcess>();
|
||||
|
||||
@ -58,7 +49,7 @@ export const startTestServer = async (): Promise<Express> => {
|
||||
export const generateApiKey = async (): Promise<string> => {
|
||||
checkAppIsRunning();
|
||||
|
||||
const accessToken = await loginUser();
|
||||
const accessToken = await loginAdminUser();
|
||||
const response = await request(app)
|
||||
.post(`${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/api-keys`)
|
||||
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, accessToken)
|
||||
@ -71,7 +62,7 @@ export const generateApiKey = async (): Promise<string> => {
|
||||
export const getApiKeys = async () => {
|
||||
checkAppIsRunning();
|
||||
|
||||
const accessToken = await loginUser();
|
||||
const accessToken = await loginAdminUser();
|
||||
const response = await request(app)
|
||||
.get(`${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/api-keys`)
|
||||
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, accessToken)
|
||||
@ -82,7 +73,7 @@ export const getApiKeys = async () => {
|
||||
export const deleteApiKeys = async () => {
|
||||
checkAppIsRunning();
|
||||
|
||||
const accessToken = await loginUser();
|
||||
const accessToken = await loginAdminUser();
|
||||
const response = await request(app)
|
||||
.delete(`${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/api-keys`)
|
||||
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, accessToken)
|
||||
@ -115,7 +106,7 @@ export const getRoomsAppearanceConfig = async () => {
|
||||
export const updateRoomsAppearanceConfig = async (config: { appearance: MeetAppearanceConfig }) => {
|
||||
checkAppIsRunning();
|
||||
|
||||
const accessToken = await loginUser();
|
||||
const accessToken = await loginAdminUser();
|
||||
const response = await request(app)
|
||||
.put(`${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/config/rooms/appearance`)
|
||||
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, accessToken)
|
||||
@ -126,7 +117,7 @@ export const updateRoomsAppearanceConfig = async (config: { appearance: MeetAppe
|
||||
export const getWebbhookConfig = async () => {
|
||||
checkAppIsRunning();
|
||||
|
||||
const accessToken = await loginUser();
|
||||
const accessToken = await loginAdminUser();
|
||||
const response = await request(app)
|
||||
.get(`${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/config/webhooks`)
|
||||
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, accessToken)
|
||||
@ -137,7 +128,7 @@ export const getWebbhookConfig = async () => {
|
||||
export const updateWebbhookConfig = async (config: WebhookConfig) => {
|
||||
checkAppIsRunning();
|
||||
|
||||
const accessToken = await loginUser();
|
||||
const accessToken = await loginAdminUser();
|
||||
const response = await request(app)
|
||||
.put(`${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/config/webhooks`)
|
||||
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, accessToken)
|
||||
@ -165,7 +156,7 @@ export const getSecurityConfig = async () => {
|
||||
export const updateSecurityConfig = async (config: SecurityConfig) => {
|
||||
checkAppIsRunning();
|
||||
|
||||
const accessToken = await loginUser();
|
||||
const accessToken = await loginAdminUser();
|
||||
const response = await request(app)
|
||||
.put(`${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/config/security`)
|
||||
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, accessToken)
|
||||
@ -173,17 +164,6 @@ export const updateSecurityConfig = async (config: SecurityConfig) => {
|
||||
return response;
|
||||
};
|
||||
|
||||
export const changeSecurityConfig = async (authMode: AuthMode) => {
|
||||
// Get current config to avoid overwriting other properties
|
||||
let response = await getSecurityConfig();
|
||||
expect(response.status).toBe(200);
|
||||
const currentConfig = response.body;
|
||||
|
||||
currentConfig.authentication.authModeToAccessRoom = authMode;
|
||||
response = await updateSecurityConfig(currentConfig);
|
||||
expect(response.status).toBe(200);
|
||||
};
|
||||
|
||||
export const restoreDefaultGlobalConfig = async () => {
|
||||
const configService = container.get(GlobalConfigService);
|
||||
const defaultGlobalConfig = configService['getDefaultConfig']();
|
||||
@ -191,25 +171,28 @@ export const restoreDefaultGlobalConfig = async () => {
|
||||
};
|
||||
|
||||
/**
|
||||
* Logs in a user and returns the access token in the format "Bearer <token>"
|
||||
* Logs in admin user and returns the access token in the format "Bearer <token>"
|
||||
*/
|
||||
export const loginUser = async (): Promise<string> => {
|
||||
export const loginAdminUser = async (): Promise<string> => {
|
||||
checkAppIsRunning();
|
||||
|
||||
const response = await request(app)
|
||||
.post(`${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/auth/login`)
|
||||
.send(CREDENTIALS.admin)
|
||||
.send({
|
||||
username: MEET_ENV.INITIAL_ADMIN_USER,
|
||||
password: MEET_ENV.INITIAL_ADMIN_PASSWORD
|
||||
})
|
||||
.expect(200);
|
||||
|
||||
expect(response.body).toHaveProperty('accessToken');
|
||||
return `Bearer ${response.body.accessToken}`;
|
||||
};
|
||||
|
||||
export const getProfile = async (accessToken: string) => {
|
||||
export const getMe = async (accessToken: string) => {
|
||||
checkAppIsRunning();
|
||||
|
||||
return await request(app)
|
||||
.get(`${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/users/profile`)
|
||||
.get(`${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/users/me`)
|
||||
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, accessToken)
|
||||
.send();
|
||||
};
|
||||
@ -284,16 +267,6 @@ export const updateRoomConfig = async (roomId: string, config: Partial<MeetRoomC
|
||||
.send({ config });
|
||||
};
|
||||
|
||||
export const updateRecordingAccessConfigInRoom = async (roomId: string, recordingAccess: MeetRecordingAccess) => {
|
||||
const response = await updateRoomConfig(roomId, {
|
||||
recording: {
|
||||
enabled: true,
|
||||
allowAccessTo: recordingAccess
|
||||
}
|
||||
});
|
||||
expect(response.status).toBe(200);
|
||||
};
|
||||
|
||||
export const updateRoomStatus = async (roomId: string, status: MeetRoomStatus) => {
|
||||
checkAppIsRunning();
|
||||
|
||||
@ -368,14 +341,14 @@ export const runExpiredRoomsGC = async () => {
|
||||
* Runs the inconsistent rooms garbage collector.
|
||||
*
|
||||
* This function retrieves the RoomScheduledTasksService from the dependency injection container
|
||||
* and calls its checkInconsistentRooms method to clean up inconsistent rooms.
|
||||
* and calls its validateRoomsStatusGC method to clean up inconsistent rooms.
|
||||
* It then waits for 1 second before completing.
|
||||
*/
|
||||
export const executeRoomStatusValidationGC = async () => {
|
||||
checkAppIsRunning();
|
||||
|
||||
const roomTaskScheduler = container.get(RoomScheduledTasksService);
|
||||
await (roomTaskScheduler as any)['validateRoomsStatusGC']();
|
||||
await (roomTaskScheduler)['validateRoomsStatusGC']();
|
||||
await sleep('1s');
|
||||
};
|
||||
|
||||
@ -386,33 +359,11 @@ export const runReleaseActiveRecordingLock = async (roomId: string) => {
|
||||
await recordingService.releaseRecordingLockIfNoEgress(roomId);
|
||||
};
|
||||
|
||||
export const getRoomMemberRoles = async (roomId: string) => {
|
||||
checkAppIsRunning();
|
||||
|
||||
const response = await request(app)
|
||||
.get(`${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/rooms/${roomId}/roles`)
|
||||
.send();
|
||||
return response;
|
||||
};
|
||||
|
||||
export const getRoomMemberRoleBySecret = async (roomId: string, secret: string) => {
|
||||
checkAppIsRunning();
|
||||
|
||||
const response = await request(app)
|
||||
.get(`${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/rooms/${roomId}/roles/${secret}`)
|
||||
.send();
|
||||
return response;
|
||||
};
|
||||
|
||||
export const generateRoomMemberTokenRequest = async (roomId: string, tokenOptions: MeetRoomMemberTokenOptions) => {
|
||||
checkAppIsRunning();
|
||||
|
||||
// Disable authentication to generate the token
|
||||
await changeSecurityConfig(AuthMode.NONE);
|
||||
|
||||
// Generate the room member token
|
||||
const response = await request(app)
|
||||
.post(`${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/rooms/${roomId}/token`)
|
||||
.post(`${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/rooms/${roomId}/members/token`)
|
||||
.send(tokenOptions);
|
||||
return response;
|
||||
};
|
||||
@ -760,7 +711,7 @@ export const deleteAllRecordings = async () => {
|
||||
export const getAnalytics = async () => {
|
||||
checkAppIsRunning();
|
||||
|
||||
const accessToken = await loginUser();
|
||||
const accessToken = await loginAdminUser();
|
||||
const response = await request(app)
|
||||
.get(`${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/analytics`)
|
||||
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, accessToken)
|
||||
|
||||
@ -37,8 +37,8 @@ export const setupSingleRoom = async (
|
||||
// Extract the room secrets and generate room member tokens
|
||||
const { moderatorSecret, speakerSecret } = MeetRoomHelper.extractSecretsFromRoom(room);
|
||||
const [moderatorToken, speakerToken] = await Promise.all([
|
||||
generateRoomMemberToken(room.roomId, { secret: moderatorSecret, grantJoinMeetingPermission: false }),
|
||||
generateRoomMemberToken(room.roomId, { secret: speakerSecret, grantJoinMeetingPermission: false })
|
||||
generateRoomMemberToken(room.roomId, { secret: moderatorSecret, joinMeeting: false }),
|
||||
generateRoomMemberToken(room.roomId, { secret: speakerSecret, joinMeeting: false })
|
||||
]);
|
||||
|
||||
// Join participant if needed
|
||||
|
||||
@ -5,7 +5,7 @@ import { INTERNAL_CONFIG } from '../../../../src/config/internal-config.js';
|
||||
import {
|
||||
generateApiKey,
|
||||
getApiKeys,
|
||||
loginUser,
|
||||
loginAdminUser,
|
||||
restoreDefaultApiKeys,
|
||||
startTestServer
|
||||
} from '../../../helpers/request-helpers.js';
|
||||
@ -18,7 +18,7 @@ describe('API Keys API Tests', () => {
|
||||
|
||||
beforeAll(async () => {
|
||||
app = await startTestServer();
|
||||
adminAccessToken = await loginUser();
|
||||
adminAccessToken = await loginAdminUser();
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
|
||||
@ -15,7 +15,7 @@ describe('Authentication API Tests', () => {
|
||||
});
|
||||
|
||||
describe('Login Tests', () => {
|
||||
it('should successfully login with valid credentials', async () => {
|
||||
it('should successfully login with valid root admin credentials', async () => {
|
||||
const response = await request(app)
|
||||
.post(`${AUTH_PATH}/login`)
|
||||
.send({
|
||||
|
||||
@ -14,7 +14,7 @@ describe('Authentication API Tests', () => {
|
||||
});
|
||||
|
||||
describe('Refresh Token Tests', () => {
|
||||
it('should successfully refresh token with valid refresh token', async () => {
|
||||
it('should successfully refresh access token with valid refresh token', async () => {
|
||||
// First, login to get a valid refresh token
|
||||
const loginResponse = await request(app)
|
||||
.post(`${AUTH_PATH}/login`)
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { afterEach, beforeAll, describe, expect, it } from '@jest/globals';
|
||||
import { AuthMode, AuthType, SecurityConfig } from '@openvidu-meet/typings';
|
||||
import { SecurityConfig } from '@openvidu-meet/typings';
|
||||
import { expectValidationError } from '../../../helpers/assertion-helpers.js';
|
||||
import {
|
||||
getSecurityConfig,
|
||||
@ -19,12 +19,10 @@ describe('Security Config API Tests', () => {
|
||||
|
||||
describe('Update security config', () => {
|
||||
it('should update security config with valid complete data', async () => {
|
||||
const validConfig = {
|
||||
const validConfig: SecurityConfig = {
|
||||
authentication: {
|
||||
authMethod: {
|
||||
type: AuthType.SINGLE_USER
|
||||
},
|
||||
authModeToAccessRoom: AuthMode.ALL_USERS
|
||||
allowUserCreation: true,
|
||||
oauthProviders: []
|
||||
}
|
||||
};
|
||||
let response = await updateSecurityConfig(validConfig);
|
||||
@ -39,75 +37,57 @@ describe('Security Config API Tests', () => {
|
||||
});
|
||||
|
||||
describe('Update security config validation', () => {
|
||||
it('should reject when authModeToAccessRoom is not a valid enum value', async () => {
|
||||
it('should reject when allowUserCreation is not a boolean', async () => {
|
||||
const response = await updateSecurityConfig({
|
||||
authentication: {
|
||||
authMethod: {
|
||||
type: AuthType.SINGLE_USER
|
||||
},
|
||||
authModeToAccessRoom: 'invalid'
|
||||
allowUserCreation: 'invalid'
|
||||
}
|
||||
} as unknown as SecurityConfig);
|
||||
|
||||
expectValidationError(
|
||||
response,
|
||||
'authentication.authModeToAccessRoom',
|
||||
"Invalid enum value. Expected 'none' | 'moderators_only' | 'all_users', received 'invalid'"
|
||||
);
|
||||
expectValidationError(response, 'authentication.allowUserCreation', 'Expected boolean, received string');
|
||||
});
|
||||
|
||||
it('should reject when authType is not a valid enum value', async () => {
|
||||
it('should reject when oauthProviders is not an array', async () => {
|
||||
const response = await updateSecurityConfig({
|
||||
authentication: {
|
||||
authMethod: {
|
||||
type: 'invalid'
|
||||
},
|
||||
authModeToAccessRoom: AuthMode.ALL_USERS
|
||||
allowUserCreation: true,
|
||||
oauthProviders: 'invalid'
|
||||
}
|
||||
} as unknown as SecurityConfig);
|
||||
|
||||
expectValidationError(
|
||||
response,
|
||||
'authentication.authMethod.type',
|
||||
"Invalid enum value. Expected 'single_user', received 'invalid'"
|
||||
);
|
||||
expectValidationError(response, 'authentication.oauthProviders', 'Expected array, received string');
|
||||
});
|
||||
|
||||
it('should reject when authModeToAccessRoom or authMethod are not provided', async () => {
|
||||
let response = await updateSecurityConfig({
|
||||
it('should reject when allowUserCreation is not provided', async () => {
|
||||
const response = await updateSecurityConfig({
|
||||
authentication: {
|
||||
authModeToAccessRoom: AuthMode.NONE
|
||||
oauthProviders: []
|
||||
}
|
||||
} as unknown as SecurityConfig);
|
||||
expectValidationError(response, 'authentication.authMethod', 'Required');
|
||||
expectValidationError(response, 'authentication.allowUserCreation', 'Required');
|
||||
});
|
||||
|
||||
response = await updateSecurityConfig({
|
||||
it('should reject when oauthProviders is not provided', async () => {
|
||||
const response = await updateSecurityConfig({
|
||||
authentication: {
|
||||
authMethod: {
|
||||
type: AuthType.SINGLE_USER
|
||||
}
|
||||
allowUserCreation: true
|
||||
}
|
||||
} as unknown as SecurityConfig);
|
||||
expectValidationError(response, 'authentication.authModeToAccessRoom', 'Required');
|
||||
} as SecurityConfig);
|
||||
expectValidationError(response, 'authentication.oauthProviders', 'Required');
|
||||
});
|
||||
|
||||
it('should reject when authentication is not an object', async () => {
|
||||
const response = await updateSecurityConfig({
|
||||
authentication: 'invalid'
|
||||
} as unknown as SecurityConfig);
|
||||
|
||||
expectValidationError(response, 'authentication', 'Expected object, received string');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Get security config', () => {
|
||||
it('should return security config when authenticated as admin', async () => {
|
||||
const defaultConfig = {
|
||||
const defaultConfig: SecurityConfig = {
|
||||
authentication: {
|
||||
authMethod: {
|
||||
type: AuthType.SINGLE_USER
|
||||
},
|
||||
authModeToAccessRoom: AuthMode.NONE
|
||||
allowUserCreation: true,
|
||||
oauthProviders: []
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -33,11 +33,12 @@ describe('Meetings API Tests', () => {
|
||||
});
|
||||
|
||||
describe('Update Participant Tests', () => {
|
||||
const setParticipantMetadata = async (roomId: string, role: MeetRoomMemberRole) => {
|
||||
const setParticipantMetadata = async (roomId: string, baseRole: MeetRoomMemberRole) => {
|
||||
const metadata: MeetRoomMemberTokenMetadata = {
|
||||
livekitUrl: MEET_ENV.LIVEKIT_URL,
|
||||
role,
|
||||
permissions: getPermissions(roomId, role, true, true).meet
|
||||
roomId,
|
||||
baseRole,
|
||||
effectivePermissions: getPermissions(baseRole)
|
||||
};
|
||||
await updateParticipantMetadata(roomId, participantIdentity, metadata);
|
||||
};
|
||||
@ -65,7 +66,10 @@ describe('Meetings API Tests', () => {
|
||||
expect(participant).toBeDefined();
|
||||
expect(participant).toHaveProperty('metadata');
|
||||
const metadata = JSON.parse(participant.metadata || '{}');
|
||||
expect(metadata).toHaveProperty('role', MeetRoomMemberRole.MODERATOR);
|
||||
expect(metadata).toHaveProperty('roomId', roomData.room.roomId);
|
||||
expect(metadata).toHaveProperty('baseRole', MeetRoomMemberRole.MODERATOR);
|
||||
const permissions = getPermissions(MeetRoomMemberRole.MODERATOR);
|
||||
expect(metadata).toHaveProperty('effectivePermissions', permissions);
|
||||
|
||||
// Verify sendSignal method has been called twice
|
||||
expect(sendSignalSpy).toHaveBeenCalledTimes(2);
|
||||
@ -119,7 +123,10 @@ describe('Meetings API Tests', () => {
|
||||
expect(participant).toBeDefined();
|
||||
expect(participant).toHaveProperty('metadata');
|
||||
const metadata = JSON.parse(participant.metadata || '{}');
|
||||
expect(metadata).toHaveProperty('role', MeetRoomMemberRole.SPEAKER);
|
||||
expect(metadata).toHaveProperty('roomId', roomData.room.roomId);
|
||||
expect(metadata).toHaveProperty('baseRole', MeetRoomMemberRole.SPEAKER);
|
||||
const permissions = getPermissions(MeetRoomMemberRole.SPEAKER);
|
||||
expect(metadata).toHaveProperty('effectivePermissions', permissions);
|
||||
});
|
||||
|
||||
it('should fail with 404 if participant does not exist', async () => {
|
||||
|
||||
@ -164,7 +164,7 @@ describe('Recording API Tests', () => {
|
||||
it('should handle empty recordingIds array gracefully', async () => {
|
||||
const response = await bulkDeleteRecordings([]);
|
||||
|
||||
expectValidationError(response, 'recordingIds', 'recordingIds must contain at least one item');
|
||||
expectValidationError(response, 'recordingIds', 'At least one recordingId is required');
|
||||
});
|
||||
|
||||
it('should reject a CSV string with invalid format', async () => {
|
||||
@ -178,7 +178,7 @@ describe('Recording API Tests', () => {
|
||||
const invalidRecordingIds = ['', ' '];
|
||||
const response = await bulkDeleteRecordings(invalidRecordingIds);
|
||||
|
||||
expectValidationError(response, 'recordingIds', 'recordingIds must contain at least one item');
|
||||
expectValidationError(response, 'recordingIds', 'At least one recordingId is required');
|
||||
});
|
||||
|
||||
it('should reject an array with mixed valid and totally invalid IDs', async () => {
|
||||
|
||||
@ -92,7 +92,7 @@ describe('Recording API Tests', () => {
|
||||
it('should handle empty recordingIds array gracefully', async () => {
|
||||
const response = await downloadRecordings([], false);
|
||||
|
||||
expectValidationError(response, 'recordingIds', 'recordingIds must contain at least one item');
|
||||
expectValidationError(response, 'recordingIds', 'At least one recordingId is required');
|
||||
});
|
||||
|
||||
it('should reject an array with mixed valid and totally invalid IDs', async () => {
|
||||
@ -106,7 +106,7 @@ describe('Recording API Tests', () => {
|
||||
const invalidRecordingIds = ['', ' '];
|
||||
const response = await downloadRecordings(invalidRecordingIds, false);
|
||||
|
||||
expectValidationError(response, 'recordingIds', 'recordingIds must contain at least one item');
|
||||
expectValidationError(response, 'recordingIds', 'At least one recordingId is required');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
import { afterAll, beforeAll, describe, expect, it } from '@jest/globals';
|
||||
import {
|
||||
MeetRecordingAccess,
|
||||
MeetRecordingLayout,
|
||||
MeetRoomDeletionPolicyWithMeeting,
|
||||
MeetRoomDeletionPolicyWithRecordings
|
||||
@ -61,8 +60,7 @@ describe('Room API Tests', () => {
|
||||
config: {
|
||||
recording: {
|
||||
enabled: false,
|
||||
layout: MeetRecordingLayout.GRID,
|
||||
allowAccessTo: MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
layout: MeetRecordingLayout.GRID
|
||||
},
|
||||
chat: { enabled: false },
|
||||
virtualBackground: { enabled: true },
|
||||
@ -98,8 +96,7 @@ describe('Room API Tests', () => {
|
||||
const expectedConfig = {
|
||||
recording: {
|
||||
enabled: false,
|
||||
layout: MeetRecordingLayout.GRID, // Default value
|
||||
allowAccessTo: MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER // Default value
|
||||
layout: MeetRecordingLayout.GRID // Default value
|
||||
},
|
||||
chat: { enabled: true }, // Default value
|
||||
virtualBackground: { enabled: true }, // Default value
|
||||
@ -127,8 +124,7 @@ describe('Room API Tests', () => {
|
||||
const expectedConfig = {
|
||||
recording: {
|
||||
enabled: true, // Default value
|
||||
layout: MeetRecordingLayout.GRID, // Default value
|
||||
allowAccessTo: MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER // Default value
|
||||
layout: MeetRecordingLayout.GRID // Default value
|
||||
},
|
||||
chat: { enabled: false },
|
||||
virtualBackground: { enabled: false },
|
||||
@ -492,8 +488,7 @@ describe('Room API Tests', () => {
|
||||
autoDeletionDate: validAutoDeletionDate,
|
||||
config: {
|
||||
recording: {
|
||||
enabled: 'yes', // invalid boolean
|
||||
allowAccessTo: MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
enabled: 'yes' // invalid boolean
|
||||
},
|
||||
chat: { enabled: true },
|
||||
virtualBackground: { enabled: true }
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { afterAll, beforeAll, describe, expect, it } from '@jest/globals';
|
||||
import { MeetRecordingAccess, MeetRoom } from '@openvidu-meet/typings';
|
||||
import { MeetRoom } from '@openvidu-meet/typings';
|
||||
import { Express } from 'express';
|
||||
import request from 'supertest';
|
||||
import { INTERNAL_CONFIG } from '../../../../src/config/internal-config.js';
|
||||
@ -48,8 +48,7 @@ describe('E2EE Room Configuration Tests', () => {
|
||||
roomName: 'Test E2EE Enabled',
|
||||
config: {
|
||||
recording: {
|
||||
enabled: true, // This should be automatically disabled
|
||||
allowAccessTo: MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
enabled: true // This should be automatically disabled
|
||||
},
|
||||
chat: { enabled: true },
|
||||
virtualBackground: { enabled: true },
|
||||
@ -87,8 +86,7 @@ describe('E2EE Room Configuration Tests', () => {
|
||||
roomName: 'Test E2EE Update',
|
||||
config: {
|
||||
recording: {
|
||||
enabled: true,
|
||||
allowAccessTo: MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
enabled: true
|
||||
},
|
||||
chat: { enabled: true },
|
||||
virtualBackground: { enabled: true },
|
||||
@ -122,8 +120,7 @@ describe('E2EE Room Configuration Tests', () => {
|
||||
roomName: 'Test Invalid E2EE',
|
||||
config: {
|
||||
recording: {
|
||||
enabled: true,
|
||||
allowAccessTo: MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
enabled: true
|
||||
},
|
||||
chat: { enabled: true },
|
||||
virtualBackground: { enabled: true },
|
||||
@ -145,8 +142,7 @@ describe('E2EE Room Configuration Tests', () => {
|
||||
roomName: 'Test Invalid E2EE Enabled',
|
||||
config: {
|
||||
recording: {
|
||||
enabled: true,
|
||||
allowAccessTo: MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
enabled: true
|
||||
},
|
||||
chat: { enabled: true },
|
||||
virtualBackground: { enabled: true },
|
||||
@ -174,8 +170,7 @@ describe('E2EE Room Configuration Tests', () => {
|
||||
|
||||
const { status, body } = await updateRoomConfig(room.roomId, {
|
||||
recording: {
|
||||
enabled: false,
|
||||
allowAccessTo: MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
enabled: false
|
||||
},
|
||||
chat: { enabled: true },
|
||||
virtualBackground: { enabled: true },
|
||||
@ -201,8 +196,7 @@ describe('E2EE Room Configuration Tests', () => {
|
||||
roomName: 'E2EE Enabled Room',
|
||||
config: {
|
||||
recording: {
|
||||
enabled: false,
|
||||
allowAccessTo: MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
enabled: false
|
||||
},
|
||||
chat: { enabled: true },
|
||||
virtualBackground: { enabled: true },
|
||||
@ -214,8 +208,7 @@ describe('E2EE Room Configuration Tests', () => {
|
||||
roomName: 'E2EE Disabled Room',
|
||||
config: {
|
||||
recording: {
|
||||
enabled: true,
|
||||
allowAccessTo: MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
enabled: true
|
||||
},
|
||||
chat: { enabled: true },
|
||||
virtualBackground: { enabled: true },
|
||||
|
||||
@ -1,10 +1,5 @@
|
||||
import { afterAll, beforeAll, describe, expect, it } from '@jest/globals';
|
||||
import {
|
||||
MeetRecordingAccess,
|
||||
MeetRoomMemberRole,
|
||||
MeetRoomMemberTokenOptions,
|
||||
MeetRoomStatus
|
||||
} from '@openvidu-meet/typings';
|
||||
import { MeetRoomMemberRole, MeetRoomStatus } from '@openvidu-meet/typings';
|
||||
import { expectValidationError, expectValidRoomMemberTokenResponse } from '../../../helpers/assertion-helpers.js';
|
||||
import {
|
||||
deleteAllRooms,
|
||||
@ -12,7 +7,6 @@ import {
|
||||
endMeeting,
|
||||
generateRoomMemberTokenRequest,
|
||||
startTestServer,
|
||||
updateRecordingAccessConfigInRoom,
|
||||
updateRoomStatus
|
||||
} from '../../../helpers/request-helpers.js';
|
||||
import { setupSingleRoom } from '../../../helpers/test-scenarios.js';
|
||||
@ -48,18 +42,18 @@ describe('Room API Tests', () => {
|
||||
expectValidRoomMemberTokenResponse(response, roomId, MeetRoomMemberRole.SPEAKER);
|
||||
});
|
||||
|
||||
it('should generate a room member token without join meeting permission when not specifying grantJoinMeetingPermission', async () => {
|
||||
it('should generate a room member token without join meeting permission when not specifying joinMeeting', async () => {
|
||||
const response = await generateRoomMemberTokenRequest(roomId, {
|
||||
secret: roomData.moderatorSecret
|
||||
});
|
||||
expectValidRoomMemberTokenResponse(response, roomId, MeetRoomMemberRole.MODERATOR, false);
|
||||
});
|
||||
|
||||
it('should generate a room member token with join meeting permission when specifying grantJoinMeetingPermission true and participantName', async () => {
|
||||
it('should generate a room member token to join meeting when specifying joinMeeting true and participantName', async () => {
|
||||
const participantName = 'TEST_PARTICIPANT';
|
||||
const response = await generateRoomMemberTokenRequest(roomId, {
|
||||
secret: roomData.moderatorSecret,
|
||||
grantJoinMeetingPermission: true,
|
||||
joinMeeting: true,
|
||||
participantName
|
||||
});
|
||||
expectValidRoomMemberTokenResponse(
|
||||
@ -75,13 +69,13 @@ describe('Room API Tests', () => {
|
||||
await endMeeting(roomId, roomData.moderatorToken);
|
||||
});
|
||||
|
||||
it('should success when when specifying grantJoinMeetingPermission true and participant already exists in the room', async () => {
|
||||
it('should success when specifying joinMeeting true and participant already exists in the room', async () => {
|
||||
const participantName = 'TEST_PARTICIPANT';
|
||||
|
||||
// Create token for the first participant
|
||||
let response = await generateRoomMemberTokenRequest(roomId, {
|
||||
secret: roomData.moderatorSecret,
|
||||
grantJoinMeetingPermission: true,
|
||||
joinMeeting: true,
|
||||
participantName
|
||||
});
|
||||
expectValidRoomMemberTokenResponse(
|
||||
@ -96,7 +90,7 @@ describe('Room API Tests', () => {
|
||||
// Create token for the second participant with the same name
|
||||
response = await generateRoomMemberTokenRequest(roomId, {
|
||||
secret: roomData.moderatorSecret,
|
||||
grantJoinMeetingPermission: true,
|
||||
joinMeeting: true,
|
||||
participantName
|
||||
});
|
||||
expectValidRoomMemberTokenResponse(
|
||||
@ -112,7 +106,7 @@ describe('Room API Tests', () => {
|
||||
await endMeeting(roomId, roomData.moderatorToken);
|
||||
});
|
||||
|
||||
it('should refresh a room member token with join meeting permission for an existing participant', async () => {
|
||||
it('should refresh a room member token to join meeting for an existing participant', async () => {
|
||||
const participantName = 'TEST_PARTICIPANT';
|
||||
|
||||
// Create room with initial participant
|
||||
@ -121,7 +115,7 @@ describe('Room API Tests', () => {
|
||||
// Refresh token for the participant by specifying participantIdentity
|
||||
const response = await generateRoomMemberTokenRequest(roomWithParticipant.room.roomId, {
|
||||
secret: roomWithParticipant.moderatorSecret,
|
||||
grantJoinMeetingPermission: true,
|
||||
joinMeeting: true,
|
||||
participantName,
|
||||
participantIdentity: participantName
|
||||
});
|
||||
@ -135,13 +129,13 @@ describe('Room API Tests', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('should fail with 409 when generating a room member token with join meeting permission and room is closed', async () => {
|
||||
it('should fail with 409 when generating a room member token to join meeting and room is closed', async () => {
|
||||
// Close the room
|
||||
await updateRoomStatus(roomId, MeetRoomStatus.CLOSED);
|
||||
|
||||
const response = await generateRoomMemberTokenRequest(roomId, {
|
||||
secret: roomData.moderatorSecret,
|
||||
grantJoinMeetingPermission: true,
|
||||
joinMeeting: true,
|
||||
participantName: 'TEST_PARTICIPANT'
|
||||
});
|
||||
expect(response.status).toBe(409);
|
||||
@ -161,7 +155,7 @@ describe('Room API Tests', () => {
|
||||
const participantName = 'NON_EXISTENT_PARTICIPANT';
|
||||
const response = await generateRoomMemberTokenRequest(roomId, {
|
||||
secret: roomData.moderatorSecret,
|
||||
grantJoinMeetingPermission: true,
|
||||
joinMeeting: true,
|
||||
participantName,
|
||||
participantIdentity: participantName
|
||||
});
|
||||
@ -176,149 +170,21 @@ describe('Room API Tests', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Generate Room Member Token Recording Permissions Tests', () => {
|
||||
afterAll(async () => {
|
||||
// Reset recording access to default for other tests
|
||||
await updateRecordingAccessConfigInRoom(roomId, MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER);
|
||||
});
|
||||
|
||||
it(`should generate a room member token with canRetrieve and canDelete permissions
|
||||
when using the moderator secret and recording access is admin_moderator_speaker`, async () => {
|
||||
await updateRecordingAccessConfigInRoom(roomId, MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER);
|
||||
|
||||
const response = await generateRoomMemberTokenRequest(roomId, { secret: roomData.moderatorSecret });
|
||||
expectValidRoomMemberTokenResponse(
|
||||
response,
|
||||
roomId,
|
||||
MeetRoomMemberRole.MODERATOR,
|
||||
false,
|
||||
undefined,
|
||||
undefined,
|
||||
true, // canRetrieveRecordings
|
||||
true // canDeleteRecordings
|
||||
);
|
||||
});
|
||||
|
||||
it(`should generate a room member token with canRetrieve permission but not canDelete
|
||||
when using the speaker secret and recording access is admin_moderator_speaker`, async () => {
|
||||
await updateRecordingAccessConfigInRoom(roomId, MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER);
|
||||
|
||||
const response = await generateRoomMemberTokenRequest(roomId, { secret: roomData.speakerSecret });
|
||||
expectValidRoomMemberTokenResponse(
|
||||
response,
|
||||
roomId,
|
||||
MeetRoomMemberRole.SPEAKER,
|
||||
false,
|
||||
undefined,
|
||||
undefined,
|
||||
true, // canRetrieveRecordings
|
||||
false // canDeleteRecordings
|
||||
);
|
||||
});
|
||||
|
||||
it(`should generate a room member token with canRetrieve and canDelete permissions
|
||||
when using the moderator secret and recording access is admin_moderator`, async () => {
|
||||
await updateRecordingAccessConfigInRoom(roomId, MeetRecordingAccess.ADMIN_MODERATOR);
|
||||
|
||||
const response = await generateRoomMemberTokenRequest(roomId, { secret: roomData.moderatorSecret });
|
||||
expectValidRoomMemberTokenResponse(
|
||||
response,
|
||||
roomId,
|
||||
MeetRoomMemberRole.MODERATOR,
|
||||
false,
|
||||
undefined,
|
||||
undefined,
|
||||
true, // canRetrieveRecordings
|
||||
true // canDeleteRecordings
|
||||
);
|
||||
});
|
||||
|
||||
it(`should generate a room member token without any permissions
|
||||
when using the speaker secret and recording access is admin_moderator`, async () => {
|
||||
await updateRecordingAccessConfigInRoom(roomId, MeetRecordingAccess.ADMIN_MODERATOR);
|
||||
|
||||
const response = await generateRoomMemberTokenRequest(roomId, { secret: roomData.speakerSecret });
|
||||
expectValidRoomMemberTokenResponse(
|
||||
response,
|
||||
roomId,
|
||||
MeetRoomMemberRole.SPEAKER,
|
||||
false,
|
||||
undefined,
|
||||
undefined,
|
||||
false, // canRetrieveRecordings
|
||||
false // canDeleteRecordings
|
||||
);
|
||||
});
|
||||
|
||||
it(`should generate a room member token without any permissions
|
||||
when using the moderator secret and recording access is admin`, async () => {
|
||||
await updateRecordingAccessConfigInRoom(roomId, MeetRecordingAccess.ADMIN);
|
||||
|
||||
const response = await generateRoomMemberTokenRequest(roomId, { secret: roomData.moderatorSecret });
|
||||
expectValidRoomMemberTokenResponse(
|
||||
response,
|
||||
roomId,
|
||||
MeetRoomMemberRole.MODERATOR,
|
||||
false,
|
||||
undefined,
|
||||
undefined,
|
||||
false, // canRetrieveRecordings
|
||||
false // canDeleteRecordings
|
||||
);
|
||||
});
|
||||
|
||||
it(`should generate a room member token without any permissions
|
||||
when using the speaker secret and recording access is admin`, async () => {
|
||||
await updateRecordingAccessConfigInRoom(roomId, MeetRecordingAccess.ADMIN);
|
||||
|
||||
const response = await generateRoomMemberTokenRequest(roomId, { secret: roomData.speakerSecret });
|
||||
expectValidRoomMemberTokenResponse(
|
||||
response,
|
||||
roomId,
|
||||
MeetRoomMemberRole.SPEAKER,
|
||||
false,
|
||||
undefined,
|
||||
undefined,
|
||||
false, // canRetrieveRecordings
|
||||
false // canDeleteRecordings
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Generate Room Member Token Validation Tests', () => {
|
||||
it('should fail when secret is not provided', async () => {
|
||||
const response = await generateRoomMemberTokenRequest(
|
||||
roomData.room.roomId,
|
||||
{} as unknown as MeetRoomMemberTokenOptions
|
||||
);
|
||||
expectValidationError(response, 'secret', 'Required');
|
||||
});
|
||||
|
||||
it('should fail when secret is empty', async () => {
|
||||
const response = await generateRoomMemberTokenRequest(roomData.room.roomId, {
|
||||
secret: ''
|
||||
});
|
||||
expectValidationError(response, 'secret', 'Secret is required');
|
||||
});
|
||||
|
||||
it('should fail when grantJoinMeetingPermission is not a boolean', async () => {
|
||||
it('should fail when joinMeeting is not a boolean', async () => {
|
||||
const response = await generateRoomMemberTokenRequest(roomData.room.roomId, {
|
||||
secret: roomData.moderatorSecret,
|
||||
grantJoinMeetingPermission: 'not-a-boolean' as unknown as boolean
|
||||
joinMeeting: 'not-a-boolean' as unknown as boolean
|
||||
});
|
||||
expectValidationError(response, 'grantJoinMeetingPermission', 'Expected boolean');
|
||||
expectValidationError(response, 'joinMeeting', 'Expected boolean');
|
||||
});
|
||||
|
||||
it('should fail when grantJoinMeetingPermission is true but participantName is not provided', async () => {
|
||||
it('should fail when joinMeeting is true but participantName is not provided', async () => {
|
||||
const response = await generateRoomMemberTokenRequest(roomData.room.roomId, {
|
||||
secret: roomData.moderatorSecret,
|
||||
grantJoinMeetingPermission: true
|
||||
joinMeeting: true
|
||||
});
|
||||
expectValidationError(
|
||||
response,
|
||||
'participantName',
|
||||
'participantName is required when grantJoinMeetingPermission is true'
|
||||
);
|
||||
expectValidationError(response, 'participantName', 'participantName is required when joinMeeting is true');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { afterEach, beforeAll, describe, it } from '@jest/globals';
|
||||
import { MeetRecordingAccess, MeetRecordingLayout } from '@openvidu-meet/typings';
|
||||
import { MeetRecordingLayout } from '@openvidu-meet/typings';
|
||||
import { Response } from 'supertest';
|
||||
import { expectSuccessRoomConfigResponse } from '../../../helpers/assertion-helpers.js';
|
||||
import { deleteAllRooms, getRoomConfig, startTestServer } from '../../../helpers/request-helpers.js';
|
||||
@ -9,8 +9,7 @@ describe('Room API Tests', () => {
|
||||
const DEFAULT_CONFIG = {
|
||||
recording: {
|
||||
enabled: true,
|
||||
layout: MeetRecordingLayout.GRID,
|
||||
allowAccessTo: MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
layout: MeetRecordingLayout.GRID
|
||||
},
|
||||
chat: { enabled: true },
|
||||
virtualBackground: { enabled: true },
|
||||
@ -41,8 +40,7 @@ describe('Room API Tests', () => {
|
||||
config: {
|
||||
recording: {
|
||||
enabled: true,
|
||||
layout: MeetRecordingLayout.SPEAKER,
|
||||
allowAccessTo: MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
layout: MeetRecordingLayout.SPEAKER
|
||||
},
|
||||
chat: { enabled: true },
|
||||
virtualBackground: { enabled: false },
|
||||
|
||||
@ -1,65 +0,0 @@
|
||||
import { afterAll, beforeAll, describe, expect, it } from '@jest/globals';
|
||||
import { MeetRoomMemberRole } from '@openvidu-meet/typings';
|
||||
import {
|
||||
expectValidRoomMemberRoleAndPermissionsResponse,
|
||||
expectValidRoomMemberRolesAndPermissionsResponse
|
||||
} from '../../../helpers/assertion-helpers.js';
|
||||
import {
|
||||
deleteAllRooms,
|
||||
getRoomMemberRoleBySecret,
|
||||
getRoomMemberRoles,
|
||||
startTestServer
|
||||
} from '../../../helpers/request-helpers.js';
|
||||
import { setupSingleRoom } from '../../../helpers/test-scenarios.js';
|
||||
import { RoomData } from '../../../interfaces/scenarios.js';
|
||||
|
||||
describe('Room API Tests', () => {
|
||||
let roomData: RoomData;
|
||||
|
||||
beforeAll(async () => {
|
||||
await startTestServer();
|
||||
roomData = await setupSingleRoom();
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await deleteAllRooms();
|
||||
});
|
||||
|
||||
describe('Get Room Member Roles Tests', () => {
|
||||
it('should retrieve all roles and associated permissions for a room', async () => {
|
||||
const response = await getRoomMemberRoles(roomData.room.roomId);
|
||||
expectValidRoomMemberRolesAndPermissionsResponse(response, roomData.room.roomId);
|
||||
});
|
||||
|
||||
it('should return a 404 error if the room does not exist', async () => {
|
||||
const response = await getRoomMemberRoles('non-existent-room-id');
|
||||
expect(response.status).toBe(404);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Get Room Member Role Tests', () => {
|
||||
it('should retrieve moderator role and associated permissions for a room with a valid moderator secret', async () => {
|
||||
const response = await getRoomMemberRoleBySecret(roomData.room.roomId, roomData.moderatorSecret);
|
||||
expectValidRoomMemberRoleAndPermissionsResponse(
|
||||
response,
|
||||
roomData.room.roomId,
|
||||
MeetRoomMemberRole.MODERATOR
|
||||
);
|
||||
});
|
||||
|
||||
it('should retrieve speaker role and associated permissions for a room with a valid speaker secret', async () => {
|
||||
const response = await getRoomMemberRoleBySecret(roomData.room.roomId, roomData.speakerSecret);
|
||||
expectValidRoomMemberRoleAndPermissionsResponse(response, roomData.room.roomId, MeetRoomMemberRole.SPEAKER);
|
||||
});
|
||||
|
||||
it('should return a 404 error if the room does not exist', async () => {
|
||||
const response = await getRoomMemberRoleBySecret('non-existent-room-id', roomData.moderatorSecret);
|
||||
expect(response.status).toBe(404);
|
||||
});
|
||||
|
||||
it('should return a 400 error if the secret is invalid', async () => {
|
||||
const response = await getRoomMemberRoleBySecret(roomData.room.roomId, 'invalid-secret');
|
||||
expect(response.status).toBe(400);
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -1,5 +1,5 @@
|
||||
import { afterEach, beforeAll, describe, expect, it } from '@jest/globals';
|
||||
import { MeetRecordingAccess, MeetRecordingLayout } from '@openvidu-meet/typings';
|
||||
import { MeetRecordingLayout } from '@openvidu-meet/typings';
|
||||
import ms from 'ms';
|
||||
import {
|
||||
expectSuccessRoomResponse,
|
||||
@ -38,8 +38,7 @@ describe('Room API Tests', () => {
|
||||
config: {
|
||||
recording: {
|
||||
enabled: true,
|
||||
layout: MeetRecordingLayout.SPEAKER,
|
||||
allowAccessTo: MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
layout: MeetRecordingLayout.SPEAKER
|
||||
},
|
||||
chat: { enabled: true },
|
||||
virtualBackground: { enabled: false },
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { afterAll, beforeAll, describe, it } from '@jest/globals';
|
||||
import { MeetRecordingAccess, MeetRecordingLayout } from '@openvidu-meet/typings';
|
||||
import { MeetRecordingLayout } from '@openvidu-meet/typings';
|
||||
import { expectValidRoom } from '../../../helpers/assertion-helpers.js';
|
||||
import { createRoom, deleteAllRooms, startTestServer } from '../../../helpers/request-helpers.js';
|
||||
|
||||
@ -27,8 +27,7 @@ describe('Room API Tests', () => {
|
||||
const expectedConfig = {
|
||||
recording: {
|
||||
enabled: true,
|
||||
layout: MeetRecordingLayout.GRID, // Default value
|
||||
allowAccessTo: MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
layout: MeetRecordingLayout.GRID // Default value
|
||||
},
|
||||
chat: { enabled: true },
|
||||
virtualBackground: { enabled: true },
|
||||
@ -43,8 +42,7 @@ describe('Room API Tests', () => {
|
||||
config: {
|
||||
recording: {
|
||||
enabled: true,
|
||||
layout: MeetRecordingLayout.SPEAKER,
|
||||
allowAccessTo: MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
layout: MeetRecordingLayout.SPEAKER
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -54,8 +52,7 @@ describe('Room API Tests', () => {
|
||||
const expectedConfig = {
|
||||
recording: {
|
||||
enabled: true,
|
||||
layout: MeetRecordingLayout.SPEAKER,
|
||||
allowAccessTo: MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
layout: MeetRecordingLayout.SPEAKER
|
||||
},
|
||||
chat: { enabled: true },
|
||||
virtualBackground: { enabled: true },
|
||||
@ -70,8 +67,7 @@ describe('Room API Tests', () => {
|
||||
config: {
|
||||
recording: {
|
||||
enabled: true,
|
||||
layout: MeetRecordingLayout.SINGLE_SPEAKER,
|
||||
allowAccessTo: MeetRecordingAccess.ADMIN
|
||||
layout: MeetRecordingLayout.SINGLE_SPEAKER
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -81,8 +77,7 @@ describe('Room API Tests', () => {
|
||||
const expectedConfig = {
|
||||
recording: {
|
||||
enabled: true,
|
||||
layout: MeetRecordingLayout.SINGLE_SPEAKER,
|
||||
allowAccessTo: MeetRecordingAccess.ADMIN
|
||||
layout: MeetRecordingLayout.SINGLE_SPEAKER
|
||||
},
|
||||
chat: { enabled: true },
|
||||
virtualBackground: { enabled: true },
|
||||
|
||||
@ -1,7 +1,5 @@
|
||||
import { afterEach, beforeAll, describe, expect, it, jest } from '@jest/globals';
|
||||
import { MeetRecordingAccess, MeetRecordingLayout, MeetRoomConfig, MeetSignalType } from '@openvidu-meet/typings';
|
||||
import { container } from '../../../../src/config/dependency-injector.config.js';
|
||||
import { FrontendEventService } from '../../../../src/services/frontend-event.service.js';
|
||||
import { afterEach, beforeAll, describe, expect, it } from '@jest/globals';
|
||||
import { MeetRecordingLayout, MeetRoomConfig } from '@openvidu-meet/typings';
|
||||
import {
|
||||
createRoom,
|
||||
deleteAllRooms,
|
||||
@ -22,21 +20,12 @@ describe('Room API Tests', () => {
|
||||
});
|
||||
|
||||
describe('Update Room Config Tests', () => {
|
||||
let frontendEventService: FrontendEventService;
|
||||
|
||||
beforeAll(() => {
|
||||
// Ensure the FrontendEventService is registered
|
||||
frontendEventService = container.get(FrontendEventService);
|
||||
});
|
||||
|
||||
it('should successfully update room config', async () => {
|
||||
const sendSignalSpy = jest.spyOn(frontendEventService as any, 'sendSignal');
|
||||
const createdRoom = await createRoom({
|
||||
roomName: 'update-test',
|
||||
config: {
|
||||
recording: {
|
||||
enabled: true,
|
||||
allowAccessTo: MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
enabled: true
|
||||
},
|
||||
chat: { enabled: true },
|
||||
virtualBackground: { enabled: true },
|
||||
@ -47,8 +36,7 @@ describe('Room API Tests', () => {
|
||||
// Update the room config
|
||||
const updatedConfig = {
|
||||
recording: {
|
||||
enabled: false,
|
||||
allowAccessTo: MeetRecordingAccess.ADMIN
|
||||
enabled: false
|
||||
},
|
||||
chat: { enabled: false },
|
||||
virtualBackground: { enabled: false },
|
||||
@ -56,22 +44,6 @@ describe('Room API Tests', () => {
|
||||
};
|
||||
const updateResponse = await updateRoomConfig(createdRoom.roomId, updatedConfig);
|
||||
|
||||
// Verify a method of frontend event service is called
|
||||
expect(sendSignalSpy).toHaveBeenCalledWith(
|
||||
createdRoom.roomId,
|
||||
{
|
||||
roomId: createdRoom.roomId,
|
||||
config: {
|
||||
...updatedConfig,
|
||||
recording: { ...updatedConfig.recording, layout: MeetRecordingLayout.GRID }
|
||||
},
|
||||
timestamp: expect.any(Number)
|
||||
},
|
||||
{
|
||||
topic: MeetSignalType.MEET_ROOM_CONFIG_UPDATED
|
||||
}
|
||||
);
|
||||
|
||||
// Verify update response
|
||||
expect(updateResponse.status).toBe(200);
|
||||
expect(updateResponse.body).toHaveProperty('message');
|
||||
@ -120,8 +92,7 @@ describe('Room API Tests', () => {
|
||||
const expectedConfig: MeetRoomConfig = {
|
||||
recording: {
|
||||
enabled: false,
|
||||
layout: MeetRecordingLayout.SPEAKER,
|
||||
allowAccessTo: MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
layout: MeetRecordingLayout.SPEAKER
|
||||
},
|
||||
chat: { enabled: true },
|
||||
virtualBackground: { enabled: true },
|
||||
@ -161,8 +132,7 @@ describe('Room API Tests', () => {
|
||||
|
||||
const config = {
|
||||
recording: {
|
||||
enabled: false,
|
||||
allowAccessTo: MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
enabled: false
|
||||
},
|
||||
chat: { enabled: false },
|
||||
virtualBackground: { enabled: false }
|
||||
@ -183,8 +153,7 @@ describe('Room API Tests', () => {
|
||||
// Invalid config (wrong types)
|
||||
const invalidConfig = {
|
||||
recording: {
|
||||
enabled: 'true', // String instead of boolean
|
||||
allowAccessTo: MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
enabled: 'true' // String instead of boolean
|
||||
},
|
||||
chat: { enabled: false },
|
||||
virtualBackground: { enabled: false }
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
import { beforeAll, describe, expect, it } from '@jest/globals';
|
||||
import { MEET_ENV } from '../../../../src/environment.js';
|
||||
import { expectValidationError } from '../../../helpers/assertion-helpers.js';
|
||||
import { changePassword, loginUser, startTestServer } from '../../../helpers/request-helpers.js';
|
||||
import { changePassword, loginAdminUser, startTestServer } from '../../../helpers/request-helpers.js';
|
||||
|
||||
describe('Users API Tests', () => {
|
||||
let adminAccessToken: string;
|
||||
|
||||
beforeAll(async () => {
|
||||
await startTestServer();
|
||||
adminAccessToken = await loginUser();
|
||||
adminAccessToken = await loginAdminUser();
|
||||
});
|
||||
|
||||
describe('Change Password Tests', () => {
|
||||
|
||||
@ -1,22 +1,22 @@
|
||||
import { beforeAll, describe, expect, it } from '@jest/globals';
|
||||
import { getProfile, loginUser, startTestServer } from '../../../helpers/request-helpers.js';
|
||||
import { getMe, loginAdminUser, startTestServer } from '../../../helpers/request-helpers.js';
|
||||
|
||||
describe('Users API Tests', () => {
|
||||
let adminAccessToken: string;
|
||||
|
||||
beforeAll(async () => {
|
||||
await startTestServer();
|
||||
adminAccessToken = await loginUser();
|
||||
adminAccessToken = await loginAdminUser();
|
||||
});
|
||||
|
||||
describe('Profile Tests', () => {
|
||||
it('should return 200 and admin profile', async () => {
|
||||
const response = await getProfile(adminAccessToken);
|
||||
const response = await getMe(adminAccessToken);
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.body).toHaveProperty('username');
|
||||
expect(response.body.username).toBe('admin');
|
||||
expect(response.body).toHaveProperty('roles');
|
||||
expect(response.body.roles).toEqual(expect.arrayContaining(['admin', 'user']));
|
||||
expect(response.body).toHaveProperty('userId', 'admin');
|
||||
expect(response.body).toHaveProperty('name', 'Admin');
|
||||
expect(response.body).toHaveProperty('role', 'admin');
|
||||
expect(response.body).toHaveProperty('registrationDate');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user