const assert = require("assert"); const fs = require("fs"); const path = require("path"); const root = path.join(__dirname, ".."); const { ladderFor, ffmpegArgs, streamTestingService, resolveFfmpegExecutable } = require("../src/services/stream-testing"); const protocol = require("../plugins/lumi_transcription/backend/companion/protocol"); async function main() { assert.equal(typeof resolveFfmpegExecutable(), "string"); const fullHd = ladderFor({ width: 1920, height: 1080, fps: 60 }); assert.deepStrictEqual(fullHd.variants.map((item) => item.name), ["source", "720p", "480p"]); assert(fullHd.variants.every((item) => item.width <= 1920 && item.height <= 1080), "adaptive ladder must never upscale"); const hd = ladderFor({ width: 1280, height: 720, fps: 30 }); assert.deepStrictEqual(hd.variants.map((item) => item.name), ["source", "480p"]); const sd = ladderFor({ width: 854, height: 480, fps: 30 }); assert.deepStrictEqual(sd.variants.map((item) => item.name), ["source"]); const fakeSession = { source: fullHd, receiver: { encoder: "h264_nvenc" }, listenerUrl: "rtmp://0.0.0.0:19350/lumi-test/private-secret", directory: path.join(root, ".tmp-stream-test"), }; const args = ffmpegArgs(fakeSession); assert(args.includes("h264_nvenc") && args.includes("master.m3u8")); assert(args.includes("v:0,a:0,name:source v:1,a:1,name:720p v:2,a:2,name:480p")); assert(args.includes("delete_segments+independent_segments+program_date_time+temp_file")); assert(args.includes("512") && args.includes("1024"), "receiver queues must be bounded"); for (const type of ["stream_test_create", "stream_test_obs_metrics", "stream_test_caption", "stream_test_stop"]) { const parsed = protocol.parseEnvelope(Buffer.from(JSON.stringify(protocol.envelope(type, {}, null)))); assert.strictEqual(parsed.type, type); } const server = fs.readFileSync(path.join(root, "src/web/server.js"), "utf8"); const service = fs.readFileSync(path.join(root, "src/services/stream-testing.js"), "utf8"); const gateway = fs.readFileSync(path.join(root, "plugins/lumi_transcription/backend/companion/gateway.js"), "utf8"); const nativeBridge = fs.readFileSync(path.join(root, "companion/native/obs-bridge/src/plugin.cpp"), "utf8"); const companion = fs.readFileSync(path.join(root, "companion/src/Lumi.Companion.App/CompanionRuntime.cs"), "utf8"); const companionUi = fs.readFileSync(path.join(root, "companion/src/Lumi.Companion.App/MainWindow.axaml.cs"), "utf8"); const companionView = fs.readFileSync(path.join(root, "companion/src/Lumi.Companion.App/MainWindow.axaml"), "utf8"); const bridgeManager = fs.readFileSync(path.join(root, "companion/src/Lumi.Companion.App/ObsBridgeManager.cs"), "utf8"); const webUi = fs.readFileSync(path.join(root, "src/web/views/admin-stream-testing.ejs"), "utf8"); assert.match(server, /admin\/stream-testing", requireRole\("admin"\)/); assert.match(server, /admin\/stream-testing\/media\/:id\/:name", requireRole\("admin"\)/); assert.match(service, /MAX_SESSION_MS/); assert.match(service, /INACTIVITY_MS/); assert.match(service, /MAX_OUTPUT_BYTES/); assert.match(service, /redactDiagnostic/); assert.match(service, /caption_delay/); assert.match(service, /receiver_slow/); assert.match(service, /PUBLIC_INGEST_PORT/); assert.match(service, /Microsoft", "WinGet", "Packages/); assert.strictEqual(/^(?:master|stream_(?:source|720p|480p))(?:\.m3u8|_\d{6}\.ts)$/.test("master.m3u8"), true); assert.match(service, /spawn\(FFMPEG, args, \{[^}]*stdio:/s); assert.match(service, /testsrc2=size=1280x720:rate=30/); assert.match(service, /sine=frequency=880:sample_rate=48000/); assert(!service.includes("shell: true"), "receiver commands must not use a shell"); assert.match(gateway, /stream_test_create/); assert.match(gateway, /Companion disconnected; the private receiver was stopped/); assert.match(nativeBridge, /stream_test_snapshot/); assert.match(nativeBridge, /obs_frontend_save_streaming_service/); assert.match(nativeBridge, /stream_test_restore/); assert.match(companion, /StreamTestRecoveryStore/); assert.match(companion, /StartStreamTestAsync/); assert.match(companion, /RestoreObsAfterStreamTestAsync/); assert.match(companion, /finally\s*\{\s*Interlocked\.Exchange\(ref _streamTestRestoreRunning, 0\)/s); assert.match(companion, /StreamTestDetail = streamTestPending/); assert.match(companion, /stream_test_start_failed/); assert.match(companionUi, /CheckUpdateButton\.IsEnabled = !state\.UpdateCheckRunning/); assert.match(companionUi, /CheckUpdateButton\.Content = state\.UpdateCheckRunning \? "Checking…" : "Check now"/); assert.match(companionUi, /ObsBridgeUpdateAvailable/); assert.match(companionUi, /Update OBS Bridge/); assert.match(companionView, /OverviewBridgeUpdatePanel/); assert.match(companionView, /ConnectionBridgeUpdatePanel/); assert.match(bridgeManager, /InstalledVersion/); assert.match(bridgeManager, /UpdateAvailable/); assert.match(webUi, /data-stream-player/); assert.match(webUi, /data-stream-quality/); assert.match(webUi, /data-stream-captions/); assert.match(webUi, /data-stream-timeline/); await streamTestingService.close(); console.log("Stream testing and Companion lifecycle verification passed."); } main().catch((error) => { console.error(error); process.exitCode = 1; });