56 lines
1.6 KiB
TypeScript
56 lines
1.6 KiB
TypeScript
import { constants } from "node:fs";
|
|
import { access, readFile } from "node:fs/promises";
|
|
import { spawnSync } from "node:child_process";
|
|
|
|
const failures: string[] = [];
|
|
|
|
async function requireExecutable(path: string, label: string): Promise<void> {
|
|
try {
|
|
await access(path, constants.X_OK);
|
|
} catch {
|
|
failures.push(`${label} is required at ${path}`);
|
|
}
|
|
}
|
|
|
|
await Promise.all([
|
|
requireExecutable("/usr/bin/bwrap", "bubblewrap"),
|
|
requireExecutable("/usr/bin/systemctl", "systemctl"),
|
|
requireExecutable("/usr/bin/tar", "tar"),
|
|
]);
|
|
|
|
try {
|
|
const controllers = await readFile("/sys/fs/cgroup/cgroup.controllers", "utf8");
|
|
if (controllers.trim().length === 0) {
|
|
failures.push("cgroup v2 controllers are unavailable");
|
|
}
|
|
} catch {
|
|
failures.push("cgroup v2 is required at /sys/fs/cgroup/cgroup.controllers");
|
|
}
|
|
|
|
if (!failures.some((failure) => failure.includes("systemctl"))) {
|
|
const probe = spawnSync("/usr/bin/systemctl", ["show-environment"], {
|
|
encoding: "utf8",
|
|
timeout: 3_000,
|
|
});
|
|
if (probe.error || probe.status !== 0) {
|
|
failures.push("a reachable systemd manager bus is required");
|
|
}
|
|
}
|
|
|
|
if (failures.length > 0) {
|
|
process.stderr.write(
|
|
[
|
|
"System/CI-runner test prerequisites are unavailable:",
|
|
...failures.map((failure) => ` - ${failure}`),
|
|
"",
|
|
"Run test:unit/test:contract/test:component/test:integration for the",
|
|
"developer loop. test:system is intentionally reserved for a compatible",
|
|
"Linux CI-runner host.",
|
|
"",
|
|
].join("\n"),
|
|
);
|
|
process.exit(1);
|
|
}
|
|
|
|
process.stdout.write("System test prerequisites: PASS\n");
|