board / client / e2e / dev-relay.mjs
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
// Start the dev relay for an e2e run, and tell the difference between "one is
// already running" and "ours could not start".
//
// The pattern this replaces resolved BOTH cases to the same `false`:
//
//   proc.on("exit", () => resolve(false));  // port in use → external relay
//
// A relay that dies on startup — board's had never had `npm install` run in
// deploy/relay, so it exited with ERR_MODULE_NOT_FOUND every single time — is
// indistinguishable from a healthy external one. The suite then ran with NO
// relay at all and still passed, because a release dist points at the
// PRODUCTION relay (config.cljs: goog.DEBUG is false outside `npm run dev`).
// Two independent faults concealing each other.
//
// So: on exit, check whether the port is actually accepting connections. If it
// is, someone else's relay is there and that is fine. If it is not, fail with
// what the process actually said.
import { spawn } from "node:child_process";
import { connect } from "node:net";

const listening = (port) =>
  new Promise((resolve) => {
    const s = connect(port, "127.0.0.1");
    s.on("connect", () => (s.destroy(), resolve(true)));
    s.on("error", () => resolve(false));
    setTimeout(() => (s.destroy(), resolve(false)), 1500);
  });

/** Resolves { proc, external } or throws with the relay's own output. */
export async function startDevRelay(relayPath, { port = 9090, banner = "relay up" } = {}) {
  const proc = spawn(process.execPath, [relayPath, "--dev"], { stdio: ["ignore", "pipe", "pipe"] });
  let err = "";
  proc.stderr.on("data", (d) => (err += String(d)));
  const up = await new Promise((resolve) => {
    const t = setTimeout(() => resolve(false), 10000);
    proc.stdout.on("data", (d) => String(d).includes(banner) && (clearTimeout(t), resolve(true)));
    proc.on("exit", () => (clearTimeout(t), resolve(false)));
  });
  if (up) return { proc, external: false };
  if (await listening(port)) {
    console.log(`⚠️ dev relay already running externally on :${port}`);
    return { proc: null, external: true };
  }
  throw new Error(
    `the dev relay did not start and nothing is listening on :${port}. ` +
      `Without it these tests would silently fall back to the PRODUCTION relay.\n` +
      (err.trim().split("\n").slice(0, 6).join("\n") || "(no stderr)") +
      `\nIf this is ERR_MODULE_NOT_FOUND, run: npm install in deploy/relay`,
  );
}

static mirror of HEAD · about · clone: git clone https://git.ardegazu.ro/board.git