Skip to content

Commit b3a7a5b

Browse files
committed
test(cli): count chrome survivors after kill -9 of warm and cold checks
1 parent 86b6f4d commit b3a7a5b

3 files changed

Lines changed: 56 additions & 10 deletions

File tree

‎.github/checkfast/orphans.mjs‎

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// Kill -9 the warm process (or a cold check) mid busy-loop; count every chrome-headless-shell process 5 s later.
2+
import { execSync, spawn } from "node:child_process";
3+
import { existsSync, mkdirSync, mkdtempSync, readdirSync, writeFileSync } from "node:fs";
4+
import { tmpdir } from "node:os";
5+
import { join } from "node:path";
6+
const win = process.platform === "win32";
7+
const cli = join(process.cwd(), "packages/cli");
8+
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
9+
function pids() {
10+
try {
11+
return win
12+
? execSync('tasklist /FI "IMAGENAME eq chrome-headless-shell.exe" /NH /FO CSV', { encoding: "utf8" }).split("\n").filter((l) => /chrome-headless-shell/i.test(l)).map((l) => Number(l.split(",")[1]?.replace(/"/g, "")))
13+
: execSync("pgrep -f chrome-headless-shell || true", { encoding: "utf8" }).split("\n").filter(Boolean).map(Number);
14+
} catch { return []; }
15+
}
16+
const count = () => pids().length;
17+
function hangProject() {
18+
const dir = mkdtempSync(join(tmpdir(), "hf-orphan-"));
19+
mkdirSync(join(dir, "compositions"));
20+
writeFileSync(join(dir, "index.html"), `<!doctype html><html><body><div data-composition-id="main" data-width="320" data-height="180" data-duration="1"><div data-composition-id="hang" data-composition-src="compositions/hang.html" data-start="0" data-duration="1"></div></div><script>window.__timelines={main:{duration:()=>1,seek:()=>{},pause:()=>{}}};</script></body></html>`);
21+
writeFileSync(join(dir, "compositions/hang.html"), `<template id="hang"><div data-composition-id="hang"><div id="box" style="width:1px;height:1px"></div><script>const el=document.getElementById("box");while(el.offsetWidth<2){el.style.height="1px";}</script></div></template>`);
22+
return dir;
23+
}
24+
const serving = (dir) => existsSync(join(dir, ".hyperframes")) && readdirSync(join(dir, ".hyperframes")).length > 0;
25+
async function waitFor(cond, ms) { const end = Date.now() + ms; while (!cond()) { if (Date.now() > end) return false; await sleep(200); } return true; }
26+
const env = { ...process.env, HYPERFRAMES_NO_TELEMETRY: "1", CI: "" };
27+
delete env.CI;
28+
async function scenario(kind) {
29+
const dir = hangProject();
30+
const base = count();
31+
let victim;
32+
if (kind === "warm") {
33+
victim = spawn(process.execPath, ["dist/warmCheck.js", "60000", dir, "--json", "--samples=1", "--no-browser-gpu"], { cwd: cli, env, stdio: "ignore" });
34+
await waitFor(() => count() > base, 30_000);
35+
await sleep(2000);
36+
const client = spawn(process.execPath, ["bin/hyperframes.mjs", "check", dir, "--json", "--samples=1", "--no-browser-gpu"], { cwd: cli, env, stdio: ["ignore", "pipe", "pipe"] });
37+
client.stdout.on("data", () => {}); client.stderr.on("data", () => {});
38+
} else {
39+
victim = spawn(process.execPath, ["bin/hyperframes.mjs", "check", dir, "--json", "--samples=1", "--no-browser-gpu"], { cwd: cli, env: { ...env, CI: "1" }, stdio: ["ignore", "pipe", "pipe"] });
40+
victim.stdout.on("data", () => {}); victim.stderr.on("data", () => {});
41+
}
42+
const busy = await waitFor(() => serving(dir), 60_000);
43+
await sleep(3000);
44+
const during = count();
45+
process.kill(victim.pid, "SIGKILL");
46+
await sleep(5000);
47+
const after = count();
48+
console.log(`ORPHANS ${process.platform} ${kind}: busy=${busy} baseline=${base} during=${during} 5s-after-kill=${after} ${after > base ? "SURVIVORS" : "clean"}`);
49+
// clean up whatever survived so the next scenario starts from zero
50+
for (const pid of pids()) { try { process.kill(pid, "SIGKILL"); } catch {} }
51+
await sleep(2000);
52+
}
53+
for (const kind of ["cold", "warm", "cold", "warm"]) await scenario(kind);

‎.github/checkfast/winlaunch.sh‎

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,3 @@
11
set -u
2-
node --import tsx packages/cli/scripts/prepare-process-test-browser.mjs
3-
export HYPERFRAMES_BROWSER_PATH=$(grep HYPERFRAMES_BROWSER_PATH "$GITHUB_ENV" | tail -1 | cut -d= -f2-)
4-
cd packages/cli
5-
chromes() { echo "CHROME $1: $(tasklist //FI "IMAGENAME eq chrome-headless-shell.exe" //NH 2>/dev/null | grep -ci chrome-headless) headless-shell procs; $(powershell -NoProfile -Command "(Get-Process chrome-headless-shell -ErrorAction SilentlyContinue | Measure-Object -Property CPU -Sum).Sum") cpu-s"; }
6-
chromes before
7-
npx vitest run src/warmCheck.process.test.ts --maxWorkers=1 2>&1 | sed 's/\x1b\[[0-9;]*m//g' | grep -E "✓|×|Tests " | sed 's/^/WARM /'
8-
chromes after-warm; sleep 20; chromes after-warm+20s
9-
npx vitest run src/warmCheck.process.test.ts src/utils/checkDeadline.process.test.ts --maxWorkers=2 2>&1 | sed 's/\x1b\[[0-9;]*m//g' | grep -E "✓|×|Tests " | sed 's/^/BOTH /'
10-
chromes after-both
2+
if [ "$RUNNER_OS" = "Windows" ]; then node --import tsx packages/cli/scripts/prepare-process-test-browser.mjs; export HYPERFRAMES_BROWSER_PATH=$(grep HYPERFRAMES_BROWSER_PATH "$GITHUB_ENV" | tail -1 | cut -d= -f2-); else node packages/cli/bin/hyperframes.mjs browser ensure >/dev/null 2>&1; fi
3+
node .github/checkfast/orphans.mjs

‎.github/workflows/checkfast-measure.yml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ jobs:
1212
strategy:
1313
fail-fast: false
1414
matrix:
15-
os: [windows-latest]
15+
os: [ubuntu-latest, macos-latest, windows-latest]
1616
env:
1717
HYPERFRAMES_NO_TELEMETRY: "1"
1818
DO_NOT_TRACK: "1"

0 commit comments

Comments
 (0)