test: add integration tests for generating participant tokens and validate responses
This commit is contained in:
parent
9630fa475d
commit
26103ab52a
@ -513,6 +513,40 @@ const getPermissions = (roomId: string, role: ParticipantRole) => {
|
||||
}
|
||||
};
|
||||
|
||||
export const expectValidParticipantTokenResponse = (
|
||||
response: any,
|
||||
roomId: string,
|
||||
participantName: string,
|
||||
participantRole: ParticipantRole
|
||||
) => {
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.body).toHaveProperty('token');
|
||||
|
||||
const token = response.body.token;
|
||||
const decodedToken = decodeJWTToken(token);
|
||||
|
||||
const permissions = getPermissions(roomId, participantRole);
|
||||
|
||||
expect(decodedToken).toHaveProperty('sub', participantName);
|
||||
expect(decodedToken).toHaveProperty('video', permissions.livekit);
|
||||
expect(decodedToken).toHaveProperty('metadata');
|
||||
const metadata = JSON.parse(decodedToken.metadata);
|
||||
expect(metadata).toHaveProperty('role', participantRole);
|
||||
expect(metadata).toHaveProperty('permissions', permissions.openvidu);
|
||||
|
||||
// Check that the token is included in a cookie
|
||||
expect(response.headers['set-cookie']).toBeDefined();
|
||||
const cookies = response.headers['set-cookie'] as unknown as string[];
|
||||
const participantTokenCookie = cookies.find((cookie) =>
|
||||
cookie.startsWith(`${INTERNAL_CONFIG.PARTICIPANT_TOKEN_COOKIE_NAME}=`)
|
||||
) as string;
|
||||
expect(participantTokenCookie).toBeDefined();
|
||||
expect(participantTokenCookie).toContain(token);
|
||||
expect(participantTokenCookie).toContain('HttpOnly');
|
||||
expect(participantTokenCookie).toContain('SameSite=Strict');
|
||||
expect(participantTokenCookie).toContain('Path=/');
|
||||
};
|
||||
|
||||
export const expectValidRecordingTokenResponse = (
|
||||
response: any,
|
||||
roomId: string,
|
||||
@ -523,7 +557,8 @@ export const expectValidRecordingTokenResponse = (
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.body).toHaveProperty('token');
|
||||
|
||||
const decodedToken = decodeJWTToken(response.body.token);
|
||||
const token = response.body.token;
|
||||
const decodedToken = decodeJWTToken(token);
|
||||
|
||||
expect(decodedToken).toHaveProperty('video', {
|
||||
room: roomId
|
||||
@ -535,6 +570,18 @@ export const expectValidRecordingTokenResponse = (
|
||||
canRetrieveRecordings,
|
||||
canDeleteRecordings
|
||||
});
|
||||
|
||||
// Check that the token is included in a cookie
|
||||
expect(response.headers['set-cookie']).toBeDefined();
|
||||
const cookies = response.headers['set-cookie'] as unknown as string[];
|
||||
const participantTokenCookie = cookies.find((cookie) =>
|
||||
cookie.startsWith(`${INTERNAL_CONFIG.RECORDING_TOKEN_COOKIE_NAME}=`)
|
||||
) as string;
|
||||
expect(participantTokenCookie).toBeDefined();
|
||||
expect(participantTokenCookie).toContain(token);
|
||||
expect(participantTokenCookie).toContain('HttpOnly');
|
||||
expect(participantTokenCookie).toContain('SameSite=Strict');
|
||||
expect(participantTokenCookie).toContain('Path=/');
|
||||
};
|
||||
|
||||
const decodeJWTToken = (token: string) => {
|
||||
|
||||
@ -307,14 +307,7 @@ export const getRoomRoleBySecret = async (roomId: string, secret: string) => {
|
||||
return response;
|
||||
};
|
||||
|
||||
/**
|
||||
* Generates a participant token for a room and returns the cookie containing the token
|
||||
*/
|
||||
export const generateParticipantToken = async (
|
||||
roomId: string,
|
||||
participantName: string,
|
||||
secret: string
|
||||
): Promise<string> => {
|
||||
export const generateParticipantToken = async (participantOptions: any) => {
|
||||
checkAppIsRunning();
|
||||
|
||||
// Disable authentication to generate the token
|
||||
@ -325,12 +318,25 @@ export const generateParticipantToken = async (
|
||||
// Generate the participant token
|
||||
const response = await request(app)
|
||||
.post(`${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/participants/token`)
|
||||
.send({
|
||||
roomId,
|
||||
participantName,
|
||||
secret
|
||||
})
|
||||
.expect(200);
|
||||
.send(participantOptions);
|
||||
return response;
|
||||
};
|
||||
|
||||
/**
|
||||
* Generates a participant token for a room and returns the cookie containing the token
|
||||
*/
|
||||
export const generateParticipantTokenCookie = async (
|
||||
roomId: string,
|
||||
participantName: string,
|
||||
secret: string
|
||||
): Promise<string> => {
|
||||
// Generate the participant token
|
||||
const response = await generateParticipantToken({
|
||||
roomId,
|
||||
participantName,
|
||||
secret
|
||||
});
|
||||
expect(response.status).toBe(200);
|
||||
|
||||
// Return the participant token cookie
|
||||
const cookies = response.headers['set-cookie'] as unknown as string[];
|
||||
@ -406,8 +412,6 @@ export const generateRecordingToken = async (roomId: string, secret: string) =>
|
||||
* Generates a token for retrieving/deleting recordings from a room and returns the cookie containing the token
|
||||
*/
|
||||
export const generateRecordingTokenCookie = async (roomId: string, secret: string) => {
|
||||
checkAppIsRunning();
|
||||
|
||||
// Generate the recording token
|
||||
const response = await generateRecordingToken(roomId, secret);
|
||||
expect(response.status).toBe(200);
|
||||
|
||||
@ -6,7 +6,7 @@ import { MeetRoom } from '../../src/typings/ce';
|
||||
import { expectValidStartRecordingResponse } from './assertion-helpers';
|
||||
import {
|
||||
createRoom,
|
||||
generateParticipantToken,
|
||||
generateParticipantTokenCookie,
|
||||
joinFakeParticipant,
|
||||
sleep,
|
||||
startRecording,
|
||||
@ -44,8 +44,8 @@ export const setupSingleRoom = async (withParticipant = false): Promise<RoomData
|
||||
// Extract the room secrets and generate participant tokens, saved as cookies
|
||||
const { moderatorSecret, publisherSecret } = MeetRoomHelper.extractSecretsFromRoom(room);
|
||||
const [moderatorCookie, publisherCookie] = await Promise.all([
|
||||
generateParticipantToken(room.roomId, 'MODERATOR', moderatorSecret),
|
||||
generateParticipantToken(room.roomId, 'PUBLISHER', publisherSecret),
|
||||
generateParticipantTokenCookie(room.roomId, 'MODERATOR', moderatorSecret),
|
||||
generateParticipantTokenCookie(room.roomId, 'PUBLISHER', publisherSecret),
|
||||
// Join participant if needed
|
||||
withParticipant ? joinFakeParticipant(room.roomId, 'TEST_PARTICIPANT') : Promise.resolve()
|
||||
]);
|
||||
|
||||
@ -0,0 +1,125 @@
|
||||
import { afterAll, beforeAll, describe, expect, it } from '@jest/globals';
|
||||
import { ParticipantRole } from '../../../../src/typings/ce/participant.js';
|
||||
import { expectValidationError, expectValidParticipantTokenResponse } from '../../../helpers/assertion-helpers.js';
|
||||
import { deleteAllRooms, generateParticipantToken, startTestServer } from '../../../helpers/request-helpers.js';
|
||||
import { RoomData, setupSingleRoom } from '../../../helpers/test-scenarios.js';
|
||||
|
||||
const participantName = 'TEST_PARTICIPANT';
|
||||
|
||||
describe('Participant API Tests', () => {
|
||||
let roomData: RoomData;
|
||||
|
||||
beforeAll(async () => {
|
||||
startTestServer();
|
||||
roomData = await setupSingleRoom();
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await deleteAllRooms();
|
||||
});
|
||||
|
||||
describe('Generate Participant Token Tests', () => {
|
||||
it('should generate a participant token with moderator permissions when using the moderator secret', async () => {
|
||||
const response = await generateParticipantToken({
|
||||
roomId: roomData.room.roomId,
|
||||
participantName,
|
||||
secret: roomData.moderatorSecret
|
||||
});
|
||||
expectValidParticipantTokenResponse(
|
||||
response,
|
||||
roomData.room.roomId,
|
||||
participantName,
|
||||
ParticipantRole.MODERATOR
|
||||
);
|
||||
});
|
||||
|
||||
it('should generate a participant token with publisher permissions when using the publisher secret', async () => {
|
||||
const response = await generateParticipantToken({
|
||||
roomId: roomData.room.roomId,
|
||||
participantName,
|
||||
secret: roomData.publisherSecret
|
||||
});
|
||||
expectValidParticipantTokenResponse(
|
||||
response,
|
||||
roomData.room.roomId,
|
||||
participantName,
|
||||
ParticipantRole.PUBLISHER
|
||||
);
|
||||
});
|
||||
|
||||
it('should fail with 409 when participant already exists in the room', async () => {
|
||||
roomData = await setupSingleRoom(true);
|
||||
const response = await generateParticipantToken({
|
||||
roomId: roomData.room.roomId,
|
||||
participantName,
|
||||
secret: roomData.moderatorSecret
|
||||
});
|
||||
expect(response.status).toBe(409);
|
||||
|
||||
// Recreate the room without the participant
|
||||
roomData = await setupSingleRoom();
|
||||
});
|
||||
|
||||
it('should fail with 404 when room does not exist', async () => {
|
||||
const response = await generateParticipantToken({
|
||||
roomId: 'non_existent_room',
|
||||
participantName,
|
||||
secret: roomData.moderatorSecret
|
||||
});
|
||||
expect(response.status).toBe(404);
|
||||
});
|
||||
|
||||
it('should fail with 400 when secret is invalid', async () => {
|
||||
const response = await generateParticipantToken({
|
||||
roomId: roomData.room.roomId,
|
||||
participantName,
|
||||
secret: 'invalid_secret'
|
||||
});
|
||||
expect(response.status).toBe(400);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Generate Participant Token Validation Tests', () => {
|
||||
it('should fail when roomId is not provided', async () => {
|
||||
const response = await generateParticipantToken({
|
||||
participantName,
|
||||
secret: roomData.moderatorSecret
|
||||
});
|
||||
expectValidationError(response, 'roomId', 'Required');
|
||||
});
|
||||
|
||||
it('should fail when participantName is not provided', async () => {
|
||||
const response = await generateParticipantToken({
|
||||
roomId: roomData.room.roomId,
|
||||
secret: roomData.moderatorSecret
|
||||
});
|
||||
expectValidationError(response, 'participantName', 'Required');
|
||||
});
|
||||
|
||||
it('should fail when secret is not provided', async () => {
|
||||
const response = await generateParticipantToken({
|
||||
roomId: roomData.room.roomId,
|
||||
participantName
|
||||
});
|
||||
expectValidationError(response, 'secret', 'Required');
|
||||
});
|
||||
|
||||
it('should fail when participantName is empty', async () => {
|
||||
const response = await generateParticipantToken({
|
||||
roomId: roomData.room.roomId,
|
||||
participantName: '',
|
||||
secret: roomData.moderatorSecret
|
||||
});
|
||||
expectValidationError(response, 'participantName', 'Participant name is required');
|
||||
});
|
||||
|
||||
it('should fail when secret is empty', async () => {
|
||||
const response = await generateParticipantToken({
|
||||
roomId: roomData.room.roomId,
|
||||
participantName,
|
||||
secret: ''
|
||||
});
|
||||
expectValidationError(response, 'secret', 'Secret is required');
|
||||
});
|
||||
});
|
||||
});
|
||||
Loading…
x
Reference in New Issue
Block a user