Live video on the AT Protocol
1import fs from "fs/promises";
2import os from "os";
3import path from "path";
4import { v7 as uuidv7 } from "uuid";
5import makeNode from "../node";
6import { makeWindow } from "../window";
7import { E2ETest, TestEnv } from "./test-env";
8import { delay, PlayerReport, randomPort } from "./util";
9
10/**
11 * This test:
12 * - Starts a new Streamplace node
13 * - Starts playing
14 * - Crashes that node and restarts it
15 * - Make sure we're still playing again afterwards
16 */
17
18const PLAYING_THRESHOLD = 0.5;
19
20export const serverRestartTest: E2ETest = {
21 test: async (testEnv: TestEnv): Promise<string | null> => {
22 const mainWindow = await makeWindow();
23
24 const tmpDir = await fs.mkdtemp(
25 path.join(os.tmpdir(), "streamplace-test-"),
26 );
27
28 // this test runs another node so we can still use node 1 for reporting!
29 const env = {
30 SP_HTTP_ADDR: `127.0.0.1:${randomPort()}`,
31 SP_HTTP_INTERNAL_ADDR: `127.0.0.1:${randomPort()}`,
32 SP_DATA_DIR: tmpDir,
33 SP_TEST_STREAM: "true",
34 };
35 let { proc } = await makeNode({
36 env: env,
37 autoQuit: false,
38 });
39
40 const testId = uuidv7();
41 const playerId = `${testId}-server-restart`;
42 const playerConfig = {
43 name: "server-restart-stream",
44 playerId,
45 src: "self-test", // <-- Make sure this matches your Go alias!
46 showControls: true,
47 telemetry: true,
48 forceProtocol: "webrtc",
49 reportingURL: `${testEnv.addr}/api/player-event`,
50 };
51 const enc = encodeURIComponent(JSON.stringify([playerConfig]));
52 const load = `http://${env.SP_HTTP_ADDR}/multi/${enc}`;
53
54 console.log(`Opening player at ${load}`);
55 await mainWindow.loadURL(load);
56
57 await delay(20000);
58 proc.kill("SIGKILL");
59 await delay(500);
60 let { proc: proc2 } = await makeNode({
61 env: env,
62 autoQuit: false,
63 });
64
65 await delay(60000);
66 proc2.kill("SIGTERM");
67
68 const res = await fetch(
69 `${testEnv.internalAddr}/player-report/${playerId}`,
70 );
71 const data = (await res.json()) as PlayerReport;
72
73 const stateTimes = data.whatHappened || {};
74 const total = Object.values(stateTimes).reduce((a, b) => a + b, 0);
75 const playing = stateTimes["playing"] || 0;
76
77 const playingPct = total > 0 ? playing / total : 0;
78
79 console.log(
80 `Overall playing percentage: ${(playingPct * 100).toFixed(1)}%`,
81 );
82 console.log("Full state times:", JSON.stringify(stateTimes, null, 2));
83
84 mainWindow.close();
85
86 if (playingPct < PLAYING_THRESHOLD) {
87 return `Player spent too little time playing during server-restart stream (${(
88 playingPct * 100
89 ).toFixed(1)}%). Possible stall or failure to recover.`;
90 }
91 proc2.kill("SIGTERM");
92
93 return null;
94 },
95};