UNPKG

mediasoup

Version:

Cutting Edge WebRTC Video Conferencing

228 lines (227 loc) 10.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const os = require("node:os"); const process = require("node:process"); const path = require("node:path"); const mediasoup = require("../"); const enhancedEvents_1 = require("../enhancedEvents"); const errors_1 = require("../errors"); test('mediasoup.workerBin matches mediasoup-worker absolute path', () => { const workerBin = process.env['MEDIASOUP_WORKER_BIN'] ? process.env['MEDIASOUP_WORKER_BIN'] : process.env['MEDIASOUP_BUILDTYPE'] === 'Debug' ? path.join(__dirname, '..', '..', '..', 'worker', 'out', 'Debug', 'mediasoup-worker') : path.join(__dirname, '..', '..', '..', 'worker', 'out', 'Release', 'mediasoup-worker'); expect(mediasoup.workerBin).toBe(workerBin); }); test('mediasoup.createWorker() succeeds', async () => { const onObserverNewWorker = jest.fn(); mediasoup.observer.once('newworker', onObserverNewWorker); const worker1 = await mediasoup.createWorker(); expect(onObserverNewWorker).toHaveBeenCalledTimes(1); expect(onObserverNewWorker).toHaveBeenCalledWith(worker1); expect(worker1.constructor.name).toBe('WorkerImpl'); expect(typeof worker1.pid).toBe('number'); expect(worker1.closed).toBe(false); expect(worker1.subprocessClosed).toBe(false); expect(worker1.died).toBe(false); worker1.close(); await (0, enhancedEvents_1.enhancedOnce)(worker1, 'subprocessclose'); expect(worker1.closed).toBe(true); expect(worker1.subprocessClosed).toBe(true); expect(worker1.died).toBe(false); const worker2 = await mediasoup.createWorker({ logLevel: 'debug', logTags: ['info'], rtcMinPort: 0, rtcMaxPort: 9999, dtlsCertificateFile: path.join(__dirname, 'data', 'dtls-cert.pem'), dtlsPrivateKeyFile: path.join(__dirname, 'data', 'dtls-key.pem'), libwebrtcFieldTrials: 'WebRTC-Bwe-AlrLimitedBackoff/Disabled/', disableLiburing: true, appData: { foo: 456 }, }); expect(worker2.constructor.name).toBe('WorkerImpl'); expect(typeof worker2.pid).toBe('number'); expect(worker2.closed).toBe(false); expect(worker2.subprocessClosed).toBe(false); expect(worker2.died).toBe(false); expect(worker2.appData).toEqual({ foo: 456 }); worker2.close(); await (0, enhancedEvents_1.enhancedOnce)(worker2, 'subprocessclose'); expect(worker2.closed).toBe(true); expect(worker2.subprocessClosed).toBe(true); expect(worker2.died).toBe(false); }, 2000); test('mediasoup.createWorker() with wrong settings rejects with TypeError', async () => { // @ts-expect-error --- Testing purposes. await expect(mediasoup.createWorker({ logLevel: 'chicken' })).rejects.toThrow(TypeError); await expect(mediasoup.createWorker({ rtcMinPort: 1000, rtcMaxPort: 999 })).rejects.toThrow(TypeError); // Port is from 0 to 65535. await expect(mediasoup.createWorker({ rtcMinPort: 1000, rtcMaxPort: 65536 })).rejects.toThrow(TypeError); await expect(mediasoup.createWorker({ dtlsCertificateFile: '/notfound/cert.pem' })).rejects.toThrow(TypeError); await expect(mediasoup.createWorker({ dtlsPrivateKeyFile: '/notfound/priv.pem' })).rejects.toThrow(TypeError); await expect( // @ts-expect-error --- Testing purposes. mediasoup.createWorker({ appData: 'NOT-AN-OBJECT' })).rejects.toBeInstanceOf(TypeError); }, 2000); test('mediasoup.createWorker() with wrong `workerBin` rejects with Error', async () => { await expect(mediasoup.createWorker({ workerBin: '/tmp/foo/mediasoup-worker' })).rejects.toBeInstanceOf(Error); }, 2000); test('worker.updateSettings() succeeds', async () => { const worker = await mediasoup.createWorker(); await expect(worker.updateSettings({ logLevel: 'debug', logTags: ['ice'] })).resolves.toBeUndefined(); worker.close(); await (0, enhancedEvents_1.enhancedOnce)(worker, 'subprocessclose'); }, 2000); test('worker.updateSettings() with wrong settings rejects with TypeError', async () => { const worker = await mediasoup.createWorker(); // @ts-expect-error --- Testing purposes. await expect(worker.updateSettings({ logLevel: 'chicken' })).rejects.toThrow(TypeError); worker.close(); await (0, enhancedEvents_1.enhancedOnce)(worker, 'subprocessclose'); }, 2000); test('worker.updateSettings() rejects with InvalidStateError if closed', async () => { const worker = await mediasoup.createWorker(); worker.close(); await (0, enhancedEvents_1.enhancedOnce)(worker, 'subprocessclose'); await expect(worker.updateSettings({ logLevel: 'error' })).rejects.toThrow(errors_1.InvalidStateError); }, 2000); test('worker.dump() succeeds', async () => { const worker = await mediasoup.createWorker({ // Just for testing purposes. This does nothing since by default // `mediasoup.workerBin` is used. workerBin: mediasoup.workerBin, }); await expect(worker.dump()).resolves.toMatchObject({ pid: worker.pid, webRtcServerIds: [], routerIds: [], channelMessageHandlers: { channelRequestHandlers: [], channelNotificationHandlers: [], }, }); worker.close(); }, 2000); test('worker.dump() rejects with InvalidStateError if closed', async () => { const worker = await mediasoup.createWorker(); worker.close(); await (0, enhancedEvents_1.enhancedOnce)(worker, 'subprocessclose'); await expect(worker.dump()).rejects.toThrow(errors_1.InvalidStateError); }, 2000); test('worker.getResourceUsage() succeeds', async () => { const worker = await mediasoup.createWorker(); await expect(worker.getResourceUsage()).resolves.toMatchObject({}); worker.close(); await (0, enhancedEvents_1.enhancedOnce)(worker, 'subprocessclose'); }, 2000); test('worker.close() succeeds', async () => { const worker = await mediasoup.createWorker({ logLevel: 'warn' }); const onObserverClose = jest.fn(); worker.observer.once('close', onObserverClose); worker.close(); await (0, enhancedEvents_1.enhancedOnce)(worker, 'subprocessclose'); expect(onObserverClose).toHaveBeenCalledTimes(1); expect(worker.closed).toBe(true); expect(worker.subprocessClosed).toBe(true); expect(worker.died).toBe(false); }, 2000); test('Worker emits "died" if mediasoup-worker process died unexpectedly', async () => { let onDied; let onObserverClose; const worker1 = await mediasoup.createWorker({ logLevel: 'warn' }); onDied = jest.fn(); onObserverClose = jest.fn(); worker1.observer.once('close', onObserverClose); await new Promise((resolve, reject) => { worker1.on('died', () => { onDied(); if (onObserverClose.mock.calls.length > 0) { reject(new Error('observer "close" event emitted before worker "died" event')); } else if (worker1.closed) { resolve(); } else { reject(new Error('worker.closed is false')); } }); process.kill(worker1.pid, 'SIGINT'); }); expect(onDied).toHaveBeenCalledTimes(1); expect(onObserverClose).toHaveBeenCalledTimes(1); expect(worker1.closed).toBe(true); expect(worker1.subprocessClosed).toBe(true); expect(worker1.died).toBe(true); const worker2 = await mediasoup.createWorker({ logLevel: 'warn' }); onDied = jest.fn(); onObserverClose = jest.fn(); worker2.observer.once('close', onObserverClose); await new Promise((resolve, reject) => { worker2.on('died', () => { onDied(); if (onObserverClose.mock.calls.length > 0) { reject(new Error('observer "close" event emitted before worker "died" event')); } else if (worker2.closed) { resolve(); } else { reject(new Error('worker.closed is false')); } }); process.kill(worker2.pid, 'SIGTERM'); }); expect(onDied).toHaveBeenCalledTimes(1); expect(onObserverClose).toHaveBeenCalledTimes(1); expect(worker2.closed).toBe(true); expect(worker2.subprocessClosed).toBe(true); expect(worker2.died).toBe(true); const worker3 = await mediasoup.createWorker({ logLevel: 'warn' }); onDied = jest.fn(); onObserverClose = jest.fn(); worker3.observer.once('close', onObserverClose); await new Promise((resolve, reject) => { worker3.on('died', () => { onDied(); if (onObserverClose.mock.calls.length > 0) { reject(new Error('observer "close" event emitted before worker "died" event')); } else if (worker3.closed) { resolve(); } else { reject(new Error('worker.closed is false')); } }); process.kill(worker3.pid, 'SIGKILL'); }); expect(onDied).toHaveBeenCalledTimes(1); expect(onObserverClose).toHaveBeenCalledTimes(1); expect(worker3.closed).toBe(true); expect(worker3.subprocessClosed).toBe(true); expect(worker3.died).toBe(true); }, 5000); // Windows doesn't have some signals such as SIGPIPE, SIGALRM, SIGUSR1, SIGUSR2 // so we just skip this test in Windows. if (os.platform() !== 'win32') { test('mediasoup-worker process ignores PIPE, HUP, ALRM, USR1 and USR2 signals', async () => { const worker = await mediasoup.createWorker({ logLevel: 'warn' }); await new Promise((resolve, reject) => { worker.on('died', reject); process.kill(worker.pid, 'SIGPIPE'); process.kill(worker.pid, 'SIGHUP'); process.kill(worker.pid, 'SIGALRM'); process.kill(worker.pid, 'SIGUSR1'); process.kill(worker.pid, 'SIGUSR2'); setTimeout(() => { expect(worker.closed).toBe(false); expect(worker.subprocessClosed).toBe(false); expect(worker.died).toBe(false); worker.on('subprocessclose', resolve); worker.close(); }, 2000); }); }, 4000); }