"use strict"; // Runs a file of examples/ as its reader does, with node, in a process of its own. The process gets the environment // the test names and nothing else, a directory without a .env file, and test/helpers/loopback.js, which sends its // broker connection to the broker of the test. const { spawn } = require("node:child_process"); const fs = require("node:fs"); const os = require("node:os"); const path = require("node:path"); const { cleanup, until } = require("./harness.js"); const ROOT = path.join(__dirname, "..", ".."); const LOOPBACK = path.join(__dirname, "loopback.js"); /** * Start examples/. broker is one of harness.broker(); without it the example can connect nowhere. Resolves * with { child, output, write, exited, stop } once the example has subscribed to /discover or, without a * root, at once. output() is what it wrote to stdout and stderr so far. */ async function run(file, { broker, root, env = {}, directory = path.join(ROOT, "examples") } = {}) { const cwd = fs.mkdtempSync(path.join(os.tmpdir(), "alex2node-example-")); let subscribed = false; const onSubscribe = (subscriptions) => { if (subscriptions.some(({ topic }) => topic === `${root}/discover` || topic === `${root}/#`)) subscribed = true; }; if (broker && root) broker.aedes.on("subscribe", onSubscribe); const child = spawn(process.execPath, ["--require", LOOPBACK, path.join(directory, file)], { cwd, env: { PATH: process.env.PATH, LOOPBACK_PORT: String(broker ? broker.port : 1), ...env }, stdio: ["pipe", "pipe", "pipe"], }); let text = ""; child.stdout.on("data", (chunk) => { text += chunk; }); child.stderr.on("data", (chunk) => { text += chunk; }); const exited = new Promise((resolve) => child.once("exit", (code) => resolve(code))); const stop = async () => { if (broker && root) broker.aedes.off("subscribe", onSubscribe); if (child.exitCode === null && child.signalCode === null) child.kill("SIGKILL"); await exited; fs.rmdirSync(cwd); }; cleanup(stop); const started = { child, output: () => text, write: (line) => child.stdin.write(line), exited, stop }; if (broker && root) { await until(() => subscribed || child.exitCode !== null, 10000, `${file} to subscribe`); broker.aedes.off("subscribe", onSubscribe); if (!subscribed) throw new Error(`${file} ended before it subscribed:\n${text}`); } return started; } module.exports = { run, ROOT };