229 lines
7.1 KiB
TypeScript
229 lines
7.1 KiB
TypeScript
import { afterEach, beforeAll, beforeEach, describe, expect, it } from '@jest/globals';
|
|
import { INTERNAL_CONFIG } from '../../../../src/config/internal-config.js';
|
|
import { AuthTransportMode, ParticipantRole } from '@openvidu-meet/typings';
|
|
import { expectValidationError, expectValidParticipantTokenResponse } from '../../../helpers/assertion-helpers.js';
|
|
import {
|
|
changeAuthTransportMode,
|
|
deleteAllRooms,
|
|
disconnectFakeParticipants,
|
|
endMeeting,
|
|
extractCookieFromHeaders,
|
|
generateParticipantToken,
|
|
generateParticipantTokenRequest,
|
|
startTestServer,
|
|
updateRoomStatus
|
|
} 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();
|
|
});
|
|
|
|
beforeEach(async () => {
|
|
roomData = await setupSingleRoom();
|
|
});
|
|
|
|
// Force to cleanup participant name reservations after each test
|
|
afterEach(async () => {
|
|
await disconnectFakeParticipants();
|
|
await deleteAllRooms();
|
|
});
|
|
|
|
describe('Generate Participant Token Tests', () => {
|
|
it('should generate a participant token without join permissions when not specifying participant name', async () => {
|
|
const response = await generateParticipantTokenRequest({
|
|
roomId: roomData.room.roomId,
|
|
secret: roomData.moderatorSecret
|
|
});
|
|
expectValidParticipantTokenResponse(response, roomData.room.roomId, ParticipantRole.MODERATOR);
|
|
});
|
|
|
|
it('should generate a participant token with moderator permissions when using the moderator secret', async () => {
|
|
const response = await generateParticipantTokenRequest({
|
|
roomId: roomData.room.roomId,
|
|
secret: roomData.moderatorSecret,
|
|
participantName
|
|
});
|
|
expectValidParticipantTokenResponse(
|
|
response,
|
|
roomData.room.roomId,
|
|
ParticipantRole.MODERATOR,
|
|
participantName
|
|
);
|
|
});
|
|
|
|
it('should generate a participant token with speaker permissions when using the speaker secret', async () => {
|
|
const response = await generateParticipantTokenRequest({
|
|
roomId: roomData.room.roomId,
|
|
secret: roomData.speakerSecret,
|
|
participantName
|
|
});
|
|
expectValidParticipantTokenResponse(
|
|
response,
|
|
roomData.room.roomId,
|
|
ParticipantRole.SPEAKER,
|
|
participantName
|
|
);
|
|
});
|
|
|
|
it(`should generate a participant token with both speaker and moderator permissions
|
|
when using the speaker secret after having a moderator token in cookie mode`, async () => {
|
|
// Set auth transport mode to cookie
|
|
await changeAuthTransportMode(AuthTransportMode.COOKIE);
|
|
|
|
const moderatorToken = await generateParticipantToken(
|
|
roomData.room.roomId,
|
|
roomData.moderatorSecret,
|
|
`${participantName}_MODERATOR`
|
|
);
|
|
const speakerResponse = await generateParticipantTokenRequest(
|
|
{
|
|
roomId: roomData.room.roomId,
|
|
secret: roomData.speakerSecret,
|
|
participantName: `${participantName}_SPEAKER`
|
|
},
|
|
moderatorToken
|
|
);
|
|
expectValidParticipantTokenResponse(
|
|
speakerResponse,
|
|
roomData.room.roomId,
|
|
ParticipantRole.SPEAKER,
|
|
`${participantName}_SPEAKER`,
|
|
undefined,
|
|
[ParticipantRole.MODERATOR]
|
|
);
|
|
|
|
// Revert auth transport mode to header
|
|
await changeAuthTransportMode(AuthTransportMode.HEADER);
|
|
});
|
|
|
|
it('should generate a participant token and store it in a cookie when in cookie mode', async () => {
|
|
// Set auth transport mode to cookie
|
|
await changeAuthTransportMode(AuthTransportMode.COOKIE);
|
|
|
|
// Generate the participant token
|
|
const response = await generateParticipantTokenRequest({
|
|
roomId: roomData.room.roomId,
|
|
secret: roomData.moderatorSecret,
|
|
participantName
|
|
});
|
|
expectValidParticipantTokenResponse(
|
|
response,
|
|
roomData.room.roomId,
|
|
ParticipantRole.MODERATOR,
|
|
participantName
|
|
);
|
|
|
|
// Check that the token is included in a cookie
|
|
const participantTokenCookie = extractCookieFromHeaders(
|
|
response,
|
|
INTERNAL_CONFIG.PARTICIPANT_TOKEN_COOKIE_NAME
|
|
);
|
|
expect(participantTokenCookie).toBeDefined();
|
|
expect(participantTokenCookie).toContain(response.body.token);
|
|
expect(participantTokenCookie).toContain('HttpOnly');
|
|
expect(participantTokenCookie).toContain('SameSite=None');
|
|
expect(participantTokenCookie).toContain('Secure');
|
|
expect(participantTokenCookie).toContain('Path=/');
|
|
|
|
// Revert auth transport mode to header
|
|
await changeAuthTransportMode(AuthTransportMode.HEADER);
|
|
});
|
|
|
|
it('should success when participant already exists in the room', async () => {
|
|
roomData = await setupSingleRoom(true);
|
|
let response = await generateParticipantTokenRequest({
|
|
roomId: roomData.room.roomId,
|
|
secret: roomData.moderatorSecret,
|
|
participantName
|
|
});
|
|
|
|
// First participant using API. LK CLI participants can reuse the same name.
|
|
expectValidParticipantTokenResponse(
|
|
response,
|
|
roomData.room.roomId,
|
|
ParticipantRole.MODERATOR,
|
|
participantName
|
|
);
|
|
|
|
response = await generateParticipantTokenRequest({
|
|
roomId: roomData.room.roomId,
|
|
secret: roomData.moderatorSecret,
|
|
participantName
|
|
});
|
|
|
|
// Second participant using API, the participant name should be unique
|
|
expectValidParticipantTokenResponse(
|
|
response,
|
|
roomData.room.roomId,
|
|
ParticipantRole.MODERATOR,
|
|
participantName + '_1'
|
|
);
|
|
|
|
// Recreate the room without the participant
|
|
roomData = await setupSingleRoom();
|
|
});
|
|
|
|
it('should fail with 409 when room is closed', async () => {
|
|
await endMeeting(roomData.room.roomId, roomData.moderatorToken);
|
|
await updateRoomStatus(roomData.room.roomId, 'closed');
|
|
const response = await generateParticipantTokenRequest({
|
|
roomId: roomData.room.roomId,
|
|
secret: roomData.moderatorSecret,
|
|
participantName
|
|
});
|
|
expect(response.status).toBe(409);
|
|
});
|
|
|
|
it('should fail with 404 when room does not exist', async () => {
|
|
const response = await generateParticipantTokenRequest({
|
|
roomId: 'non_existent_room',
|
|
secret: roomData.moderatorSecret,
|
|
participantName
|
|
});
|
|
expect(response.status).toBe(404);
|
|
});
|
|
|
|
it('should fail with 400 when secret is invalid', async () => {
|
|
const response = await generateParticipantTokenRequest({
|
|
roomId: roomData.room.roomId,
|
|
secret: 'invalid_secret',
|
|
participantName
|
|
});
|
|
expect(response.status).toBe(400);
|
|
});
|
|
});
|
|
|
|
describe('Generate Participant Token Validation Tests', () => {
|
|
it('should fail when roomId is not provided', async () => {
|
|
const response = await generateParticipantTokenRequest({
|
|
secret: roomData.moderatorSecret,
|
|
participantName
|
|
});
|
|
expectValidationError(response, 'roomId', 'Required');
|
|
});
|
|
|
|
it('should fail when secret is not provided', async () => {
|
|
const response = await generateParticipantTokenRequest({
|
|
roomId: roomData.room.roomId,
|
|
participantName
|
|
});
|
|
expectValidationError(response, 'secret', 'Required');
|
|
});
|
|
|
|
it('should fail when secret is empty', async () => {
|
|
const response = await generateParticipantTokenRequest({
|
|
roomId: roomData.room.roomId,
|
|
secret: '',
|
|
participantName
|
|
});
|
|
expectValidationError(response, 'secret', 'Secret is required');
|
|
});
|
|
});
|
|
});
|