snapshot of https://github.com/jitsi/jitsi-meet.git @ fd1749dd28f4138aa80234fc7f311b19aaffa0e7 (2026-09-15)
This commit is contained in:
165
tests/prosody/mod_muc_cleanup_backend_services_spec.js
Normal file
165
tests/prosody/mod_muc_cleanup_backend_services_spec.js
Normal file
@@ -0,0 +1,165 @@
|
||||
import assert from 'assert';
|
||||
|
||||
import { createTestContext } from './helpers/test_context.js';
|
||||
import { getRoomState, setBreakoutRoomsActive } from './helpers/test_observer.js';
|
||||
|
||||
const CONFERENCE = 'conference.localhost';
|
||||
|
||||
let _roomCounter = 0;
|
||||
const room = () => `cleanup-svc-${++_roomCounter}@${CONFERENCE}`;
|
||||
|
||||
/** Resolves after ms milliseconds. */
|
||||
const sleep = ms => new Promise(r => setTimeout(r, ms));
|
||||
|
||||
// services_empty_meeting_timeout is set to 1 s in prosody.cfg.lua.
|
||||
// We wait TIMER_MS + BUFFER_MS to be sure the timer has either fired or not.
|
||||
const TIMER_MS = 1000;
|
||||
const BUFFER_MS = 1000;
|
||||
|
||||
describe('mod_muc_cleanup_backend_services', () => {
|
||||
let ctx;
|
||||
|
||||
beforeEach(() => {
|
||||
ctx = createTestContext();
|
||||
});
|
||||
|
||||
afterEach(() => ctx.cleanup());
|
||||
|
||||
it('destroys room when last regular user leaves and only jibri remains', async () => {
|
||||
const r = room();
|
||||
|
||||
await ctx.connectFocus(r);
|
||||
await ctx.connectJibri(r);
|
||||
const user = await ctx.connect();
|
||||
|
||||
await user.joinRoom(r);
|
||||
await user.disconnect();
|
||||
|
||||
await sleep(TIMER_MS + BUFFER_MS);
|
||||
|
||||
const state = await getRoomState(r);
|
||||
|
||||
assert.equal(state, null, 'room should be destroyed after timeout');
|
||||
});
|
||||
|
||||
it('destroys room when last regular user leaves and only transcriber remains', async () => {
|
||||
const r = room();
|
||||
|
||||
await ctx.connectFocus(r);
|
||||
await ctx.connectTranscriber(r);
|
||||
const user = await ctx.connect();
|
||||
|
||||
await user.joinRoom(r);
|
||||
await user.disconnect();
|
||||
|
||||
await sleep(TIMER_MS + BUFFER_MS);
|
||||
|
||||
const state = await getRoomState(r);
|
||||
|
||||
assert.equal(state, null, 'room should be destroyed after timeout');
|
||||
});
|
||||
|
||||
it('does not destroy room when a second regular user is still present', async () => {
|
||||
const r = room();
|
||||
|
||||
await ctx.connectFocus(r);
|
||||
await ctx.connectJibri(r);
|
||||
const user1 = await ctx.connect();
|
||||
const user2 = await ctx.connect();
|
||||
|
||||
await user1.joinRoom(r);
|
||||
await user2.joinRoom(r);
|
||||
await user1.disconnect();
|
||||
|
||||
await sleep(TIMER_MS + BUFFER_MS);
|
||||
|
||||
const state = await getRoomState(r);
|
||||
|
||||
assert.ok(state, 'room should still exist — user2 is still a regular participant');
|
||||
});
|
||||
|
||||
it('cancels the destroy timer when a regular user joins after timer starts', async () => {
|
||||
const r = room();
|
||||
|
||||
await ctx.connectFocus(r);
|
||||
await ctx.connectJibri(r);
|
||||
const user = await ctx.connect();
|
||||
|
||||
await user.joinRoom(r);
|
||||
|
||||
// user leaves — timer starts counting down
|
||||
await user.disconnect();
|
||||
|
||||
// a new regular user joins immediately, which must cancel the timer
|
||||
const user2 = await ctx.connect();
|
||||
|
||||
await user2.joinRoom(r);
|
||||
|
||||
await sleep(TIMER_MS + BUFFER_MS);
|
||||
|
||||
const state = await getRoomState(r);
|
||||
|
||||
assert.ok(state, 'room should survive — destroy timer was cancelled by user2 joining');
|
||||
});
|
||||
|
||||
it('does not start timer when jibri leaves and a regular user is still present', async () => {
|
||||
const r = room();
|
||||
|
||||
await ctx.connectFocus(r);
|
||||
const jibri = await ctx.connectJibri(r);
|
||||
const user = await ctx.connect();
|
||||
|
||||
await user.joinRoom(r);
|
||||
|
||||
// jibri leaves — muc-occupant-left hook returns early (leaver is jibri)
|
||||
await jibri.disconnect();
|
||||
|
||||
await sleep(TIMER_MS + BUFFER_MS);
|
||||
|
||||
const state = await getRoomState(r);
|
||||
|
||||
assert.ok(state, 'room should survive — timer is not started when jibri is the leaver');
|
||||
});
|
||||
|
||||
it('does not start timer when focus (admin) leaves', async () => {
|
||||
const r = room();
|
||||
|
||||
const focus = await ctx.connectFocus(r);
|
||||
|
||||
await ctx.connectJibri(r);
|
||||
const user = await ctx.connect();
|
||||
|
||||
await user.joinRoom(r);
|
||||
|
||||
// admin leaves — muc-occupant-left hook returns early (leaver is admin)
|
||||
await focus.disconnect();
|
||||
|
||||
await sleep(TIMER_MS + BUFFER_MS);
|
||||
|
||||
const state = await getRoomState(r);
|
||||
|
||||
assert.ok(state, 'room should survive — timer is not started when an admin leaves');
|
||||
});
|
||||
|
||||
it('does not start timer when breakout rooms are active', async () => {
|
||||
const r = room();
|
||||
|
||||
await ctx.connectFocus(r);
|
||||
await ctx.connectJibri(r);
|
||||
const user = await ctx.connect();
|
||||
|
||||
await user.joinRoom(r);
|
||||
|
||||
// Simulate active breakout rooms — hook returns early when this flag is set.
|
||||
await setBreakoutRoomsActive(r, true);
|
||||
|
||||
// user leaves — would normally start the timer, but breakout_rooms_active prevents it
|
||||
await user.disconnect();
|
||||
|
||||
await sleep(TIMER_MS + BUFFER_MS);
|
||||
|
||||
const state = await getRoomState(r);
|
||||
|
||||
assert.ok(state, 'room should survive — breakout_rooms_active prevents the destroy timer');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user