testBuildsWaitForASlot

tcmts.cli.test.e2e.suites.testBuildsWaitForASlot · #rbori3zr · term

A build of an app takes a slot of the machine's, as tests do: with the one slot held by other work (another branch's verify), tcm build waits, saying on whom, and builds once it's given back, leaving the slots as they were.

import { plainEnv, strip, tcmBin, tempDir, withChildren } from "#codebase/tcmts/cli/test/e2e/harness";
import { setUp } from "#codebase/tcmts/cli/test/e2e/prod";
import assert from "node:assert/strict";
import { spawn } from "node:child_process";
import fs from "node:fs";
import path from "node:path";

export const testBuildsWaitForASlot = () =>
  withChildren(async (keep) => {
    const { dir, tcm, scratch } = setUp();
    scratch(`// tcm: namespace app
export async function main() { document.querySelector("#app")!.textContent = "hello"; }
`);
    tcm("add");
    const slots = tempDir("slots for a build");
    // (held by this test's process, which is alive, as another tcm's verify would hold it)
    fs.writeFileSync(
      path.join(slots, "slot-0"),
      JSON.stringify({
        pid: process.pid,
        what: "verify of /x/codebase on session/other",
        since: Date.now(),
        token: "t",
      }),
    );
    // (out of the suite's own slot, which what a suite runs is otherwise in)
    const { TCM_SUITE_SLOT: _, ...outer } = plainEnv();
    const child = keep(
      spawn(process.execPath, [tcmBin(), "build", "app.main"], {
        cwd: dir,
        env: { ...outer, TCM_SLOTS: "1", TCM_SLOTS_DIR: slots },
      }),
    );
    let out = "";
    child.stdout!.setEncoding("utf8").on("data", (d: string) => (out += d));
    child.stderr!.setEncoding("utf8").on("data", (d: string) => (out += d));
    const ended = new Promise<number | null>((r) => child.on("close", r));
    for (let i = 0; i < 300 && !/waiting for a slot/.test(out); i++)
      await new Promise((r) => setTimeout(r, 100));
    assert.match(
      strip(out),
      /waiting for a slot: 1 of 1 in use \(1 by session\/other's verify of …\/x\/codebase\) \(TCM_SLOTS sets how many\)\n/,
    );
    await new Promise((r) => setTimeout(r, 500));
    assert.equal(child.exitCode, null, "still waiting");
    assert.doesNotMatch(out, /built/);
    fs.rmSync(path.join(slots, "slot-0"));
    assert.equal(await ended, 0, out);
    assert.match(strip(out), /got a slot after [\d.]+s\n/);
    assert.match(strip(out), /built app\.main/);
    assert.deepEqual(fs.readdirSync(slots), []);
  })

uses