Skip to content
100 changes: 100 additions & 0 deletions src/api_productions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,12 @@ const mockProductionManager = {
.mockImplementation((lines: any[], id: string) =>
lines.find((l) => l.id === id)
),
requireLine: jest.fn().mockImplementation((lines: any[], id: string) => {
const found = lines.find((l) => l.id === id);
if (!found) throw new Error(`Line ${id} not found`);
return found;
}),
clearWhepSourceIfPinned: jest.fn().mockResolvedValue(undefined),
updateUserLastSeen: jest
.fn()
.mockImplementation((sessionId: string) => sessionId === 'alive-session'),
Expand All @@ -180,6 +186,7 @@ const mockProductionManager = {
removeUserSession: jest
.fn()
.mockImplementation((sessionId: string) => sessionId),
emit: jest.fn(),
createUserSession: jest.fn().mockResolvedValue(undefined),
getActiveUsers: jest.fn().mockResolvedValue([]),
once: jest.fn(),
Expand Down Expand Up @@ -514,6 +521,47 @@ describe('Production API', () => {
});
});

describe('PATCH /session/:id', () => {
test('flushes a 204 once the SDP answer is handled', async () => {
const patchSession = {
_id: 'mock-session',
name: 'usersession',
productionId: '1',
lineId: '1',
endpointId: 'mock-endpoint-1',
isActive: true,
isExpired: false,
isWhip: false,
sessionDescription: { audio: { ssrcs: [1] }, video: { ssrcs: [] } }
};
const getSessionSpy = jest
.spyOn(mockDbManager, 'getSession')
.mockResolvedValue(patchSession as any);
mockProductionManager.getProduction = jest
.fn()
.mockResolvedValue(mockProductions[0]);
mockProductionManager.updateUserEndpoint = jest
.fn()
.mockResolvedValue(undefined);
mockProductionManager.updateSessionHasVideo = jest
.fn()
.mockResolvedValue(undefined);
mockCoreFunctions.handleAnswerRequest = jest
.fn()
.mockResolvedValue(undefined);

const response = await server.inject({
method: 'PATCH',
url: '/api/v1/session/mock-session',
body: { sdpAnswer: 'v=0' }
});

expect(response.statusCode).toBe(204);
expect(mockCoreFunctions.handleAnswerRequest).toHaveBeenCalled();
getSessionSpy.mockRestore();
});
});

describe('POST /production/:id/line/:id/participants', () => {
test('can do long polling for change in line participants', async () => {
mockProductionManager.once = jest
Expand Down Expand Up @@ -569,4 +617,56 @@ describe('Production API', () => {
expect(response.statusCode).toBe(410);
});
});
// The handler returns 410 when the session is gone, but that status was not
// in the declared response schema (204/400/500 only).
describe('PATCH /session/:id — session gone', () => {
test('answers 410 with the declared error shape', async () => {
const getSessionSpy = jest
.spyOn(mockDbManager, 'getSession')
.mockResolvedValue(null as any);

const response = await server.inject({
method: 'PATCH',
url: '/api/v1/session/missing-session',
body: { sdpAnswer: 'v=0' }
});

expect(response.statusCode).toBe(410);
expect(response.json().message).toContain('missing-session');
getSessionSpy.mockRestore();
});
});

describe('GET /session/:sessionId/name', () => {
test('returns the session display name', async () => {
mockProductionManager.getUserNameBySessionId = jest
.fn()
.mockResolvedValue('maximus');

const response = await server.inject({
method: 'GET',
url: '/api/v1/session/named-session/name'
});

expect(response.statusCode).toBe(200);
expect(response.json()).toEqual({
sessionId: 'named-session',
name: 'maximus'
});
});

test('returns 404 for an unknown session', async () => {
mockProductionManager.getUserNameBySessionId = jest
.fn()
.mockResolvedValue(null);

const response = await server.inject({
method: 'GET',
url: '/api/v1/session/nobody/name'
});

expect(response.statusCode).toBe(404);
expect(response.json()).toEqual({ message: 'Session not found' });
});
});
});
Loading
Loading