testForgesStopWhenIdle
a forge no one reads stops (TCM_FORGE_IDLE seconds after the last request it answered), and the next request
starts it again
import { codebase, env, LIB, uiPage } from "#codebase/tcmts/cli/test/e2e/contributions"; import { strip, tcmBin, tempDir, withChildren } from "#codebase/tcmts/cli/test/e2e/harness"; import assert from "node:assert/strict"; import { spawn } from "node:child_process"; export const testForgesStopWhenIdle = async () => { const root = tempDir("forges idle"); const server = codebase(root, "served"); server.write(LIB); server.tcm("add"); const shown = codebase(root, "shown"); shown.write(`// tcm: namespace geo\nexport const tau = 6.28;\n`); shown.tcm("add"); await withChildren(async (keep) => { const child = keep( spawn( process.execPath, [tcmBin(), "serve", "--port", "0", "--token", "tok", "--forge", `/code/shown=${shown.dir}`], { cwd: server.dir, env: { ...env(), TCM_FORGE_IDLE: "2" } }, ), ); let out = ""; child.stdout.setEncoding("utf8").on("data", (d: string) => (out += d)); child.stderr.setEncoding("utf8").on("data", (d: string) => (out += d)); const url = await new Promise<string>((resolve) => { const look = setInterval(() => { const m = /url\s+(https?:\/\/[\d.]+:\d+)/.exec(out); if (!m) return; clearInterval(look); resolve(m[1]!); }, 50); }); const first = await uiPage(`${url}/code/shown/`); assert.equal(first.status, 200, first.html); assert.match(first.html, />geo</); const ui = /ui\s+url\s+(https?:\/\/[\d.]+:\d+)/.exec(strip(out)); assert.ok(ui, out); // asked nothing for two seconds, it stops const until = Date.now() + 15_000; let answers = true; while (answers && Date.now() < until) { await new Promise((r) => setTimeout(r, 250)); answers = await fetch(`${ui[1]}/code/shown/`).then( () => true, () => false, ); } assert.ok(!answers, "the forge's web UI stopped"); assert.match(strip(out), /\/code\/shown\/ asked nothing for 2s: stopped/); // and the next request starts it again const again = await uiPage(`${url}/code/shown/`); assert.equal(again.status, 200, again.html); assert.match(again.html, />geo</); }); }