import assert from "node:assert/strict"; import { createServer } from "node:http"; import { readFile } from "node:fs/promises"; import { mkdtemp, rm } from "node:fs/promises"; import { spawn } from "node:child_process"; import { tmpdir } from "node:os"; import { dirname, join, normalize, sep } from "node:path"; import { fileURLToPath } from "node:url"; const root = dirname(dirname(fileURLToPath(import.meta.url))); const appRoot = join(root, "app"); const webRoot = root; function serve() { return createServer(async (request, response) => { const requested = decodeURIComponent((request.url ?? "/").split("?")[0]); const relative = requested === "/" ? "/app/browser-opfs-probe.html" : requested; const file = normalize(join(webRoot, relative)); if (!file.startsWith(webRoot + sep)) { response.writeHead(403); response.end(); return; } try { const body = await readFile(file); response.writeHead(200, { "content-type": file.endsWith(".html") ? "text/html" : "text/javascript", "cache-control": "no-store" }); response.end(body); } catch { response.writeHead(404); response.end(); } }); } function runChrome(url, profile) { return new Promise((resolve) => { const command = process.env.CHROME_BIN ?? "google-chrome"; const args = ["--headless=new", "--no-sandbox", "--disable-gpu", "--disable-dev-shm-usage", "--disable-background-networking", "--user-data-dir=" + profile, "--virtual-time-budget=5000", "--dump-dom", url]; const child = spawn(command, args, { stdio: ["ignore", "pipe", "pipe"] }); let stdout = ""; let stderr = ""; child.stdout.on("data", (chunk) => { stdout += chunk; }); child.stderr.on("data", (chunk) => { stderr += chunk; }); const timer = setTimeout(() => child.kill("SIGKILL"), 15000); child.on("close", (code, signal) => { clearTimeout(timer); resolve({ code, signal, stdout, stderr }); }); child.on("error", (error) => { clearTimeout(timer); resolve({ code: null, signal: null, stdout, stderr, error: error.message }); }); }); } const server = serve(); await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve)); const port = server.address().port; const profile = await mkdtemp(join(tmpdir(), "linuxcnc-opfs-s6-05-")); const first = await runChrome(`http://127.0.0.1:${port}/app/browser-opfs-probe.html`, profile); server.close(); await rm(profile, { recursive: true, force: true }); const match = first.stdout.match(/([^<]*)<\/output>/); if (first.code !== 0 || !match || match[1] === "pending") { console.log(JSON.stringify({ schema: "browser-opfs-s6-05-sample.v1", status: "blocked", browser: "chromium", code: first.error ? "browser_unavailable" : "opfs_worker_timeout", stage: null })); } else { const result = JSON.parse(match[1]); assert.equal(result.schema, "opfs-runtime.v1", JSON.stringify({ result, stderr: first.stderr })); assert.equal(result.status, "blocked", JSON.stringify({ result, stderr: first.stderr.slice(-500) })); assert.ok(["opfs_probe_timeout", "opfs_worker_timeout", "opfs_sync_access_handle_missing", "opfs_probe_failed"].includes(result.code)); console.log(JSON.stringify({ schema: "browser-opfs-s6-05-sample.v1", status: "blocked", browser: "chromium", code: result.code, stage: result.stage ?? null })); }