93 lines
5.3 KiB
JavaScript
93 lines
5.3 KiB
JavaScript
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;
|
|
});
|