53 lines
2.7 KiB
JavaScript
53 lines
2.7 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import { execFileSync } from "node:child_process";
|
|
import { accessSync, constants, readFileSync } from "node:fs";
|
|
import { join } from "node:path";
|
|
import test from "node:test";
|
|
|
|
// Pins the wiring that makes the background-service smoke an effective gate.
|
|
// The service leg exists because v2026.824.0 shipped a service install that
|
|
// crash-looped on a missing shim while the Docker smoke stayed green; these
|
|
// assertions keep the job from being silently disconnected or weakened.
|
|
|
|
const repoRoot = new URL("..", import.meta.url).pathname.replace(/\/$/, "");
|
|
const scriptPath = join(repoRoot, "scripts", "service-onboard-smoke.sh");
|
|
const script = readFileSync(scriptPath, "utf8");
|
|
const smokeWorkflow = readFileSync(join(repoRoot, ".github", "workflows", "release-smoke.yml"), "utf8");
|
|
const releaseWorkflow = readFileSync(join(repoRoot, ".github", "workflows", "release.yml"), "utf8");
|
|
|
|
test("smoke script is executable and parses", () => {
|
|
accessSync(scriptPath, constants.X_OK);
|
|
execFileSync("bash", ["-n", scriptPath]);
|
|
});
|
|
|
|
test("smoke script keeps its load-bearing assertions", () => {
|
|
assert.match(script, /^set -euo pipefail$/m);
|
|
// Onboards the published artifact with the service leg forced on.
|
|
assert.match(script, /onboard --yes --install-service/);
|
|
// Fails when the shim never materialized.
|
|
assert.match(script, /no executable shim at .*after onboarding/);
|
|
// Fails when the unit dies instead of serving.
|
|
assert.match(script, /entered the failed state/);
|
|
// Fails when health answers but the service is not what is serving --
|
|
// the exact signature of the v2026.824.0 defect.
|
|
assert.match(script, /something other than the service is serving/);
|
|
// Refuses to smoke over a real install unless forced.
|
|
assert.match(script, /SMOKE_FORCE/);
|
|
});
|
|
|
|
test("release-smoke workflow runs the service leg against the input version", () => {
|
|
assert.match(smokeWorkflow, /^ smoke_service:$/m);
|
|
assert.match(smokeWorkflow, /scripts\/service-onboard-smoke\.sh/);
|
|
const serviceJob = smokeWorkflow.split(/^ smoke:$/m)[0];
|
|
assert.match(serviceJob, /PAPERCLIPAI_VERSION: \$\{\{ inputs\.paperclip_version \}\}/);
|
|
// Diagnostics must survive the run: cleanup stays off in CI and the
|
|
// artifact name cannot collide with the Docker job's upload.
|
|
assert.match(serviceJob, /SMOKE_CLEANUP: "false"/);
|
|
assert.match(serviceJob, /\$\{\{ inputs\.artifact_name \}\}-service/);
|
|
});
|
|
|
|
test("nightly and beta smokes still route through the reusable workflow", () => {
|
|
const calls = releaseWorkflow.match(/uses: \.\/\.github\/workflows\/release-smoke\.yml/g) ?? [];
|
|
assert.ok(calls.length >= 2, "smoke_nightly and smoke_beta must call release-smoke.yml so smoke_service gates them");
|
|
});
|