chore: auto-commit after stop

GSD-Unit: M001
This commit is contained in:
2026-11-01 01:13:43 +03:00
parent 8f3814946d
commit 3377f4726b
2 changed files with 204 additions and 122 deletions
+103
View File
@@ -0,0 +1,103 @@
/** Disposable inline fixtures only: never require a built payload or workflow artifacts. */
import assert from "node:assert/strict";
import { spawnSync } from "node:child_process";
import * as fs from "node:fs";
import * as os from "node:os";
import * as path from "node:path";
import { describe, it } from "node:test";
import { fileURLToPath } from "node:url";
import { resolveSmokeOptions, validateSmokeOptions } from "../scripts/smoke-server.mjs";
const script = fileURLToPath(new URL("../scripts/smoke-server.mjs", import.meta.url));
const checkout = fileURLToPath(new URL("..", import.meta.url));
const run = (args: string[]) => spawnSync(process.execPath, [script, ...args], { encoding: "utf8", timeout: 10_000 });
function withFixture(test: (root: string) => void) {
const root = fs.mkdtempSync(path.join(os.tmpdir(), "lh-server-options-test-"));
try { test(root); }
finally { fs.rmSync(root, { recursive: true, force: true }); }
}
function fails(args: string[], message: RegExp) {
const result = run(args);
assert.equal(result.error, undefined);
assert.equal(result.status, 1, result.stdout + result.stderr);
assert.match(result.stderr, message);
assert.doesNotMatch(result.stdout, /boot ok|smoke passed|import ok/);
}
describe("standalone server smoke options", () => {
it("preserves the checkout staging default and host runtime without booting on import", () => {
const options = resolveSmokeOptions();
assert.equal(options.standalone, path.join(checkout, ".next", "standalone"));
assert.equal(options.server, path.join(options.standalone, "server.js"));
assert.equal(options.runtime, process.execPath);
});
it("resolves explicit relative paths against the caller and accepts an explicit root", () => {
const relative = resolveSmokeOptions(["--standalone", "payload", "--runtime", "bin/runtime"]);
assert.equal(relative.standalone, path.resolve("payload"));
assert.equal(relative.runtime, path.resolve("bin/runtime"));
withFixture((root) => {
fs.writeFileSync(path.join(root, "server.js"), "// fixture; never booted");
const options = resolveSmokeOptions(["--runtime", process.execPath, "--standalone", root]);
assert.equal(options.server, path.join(root, "server.js"));
assert.doesNotThrow(() => validateSmokeOptions(options));
});
});
for (const option of ["--standalone", "--runtime"]) {
for (const suffix of [[], [""], ["--electron"]]) {
it(`rejects missing or malformed ${option} value ${JSON.stringify(suffix)}`, () => {
fails([option, ...suffix], new RegExp(`${option} requires a path`));
});
}
}
it("rejects unknown flags and conflicting runtime selectors", () => {
fails(["--unknown"], /Unknown option/);
fails(["--electron", "--runtime", process.execPath], /Use either --electron or --runtime/);
});
it("retains the legacy Electron runtime selector", () => {
assert.match(resolveSmokeOptions(["--electron"]).runtime, /electron/);
});
it("fails early for nonexistent and non-directory roots", () => {
withFixture((root) => {
fails(["--standalone", path.join(root, "absent")], /Standalone directory not found/);
const file = path.join(root, "file");
fs.writeFileSync(file, "fixture");
fails(["--standalone", file], /Standalone directory not found/);
});
});
it("fails early for missing or non-file server entries", () => {
withFixture((root) => {
fails(["--standalone", root], /Standalone server not found/);
fs.mkdirSync(path.join(root, "server.js"));
fails(["--standalone", root], /Standalone server not found/);
});
});
it("fails early for missing, non-file and non-executable runtimes", () => {
withFixture((root) => {
fs.writeFileSync(path.join(root, "server.js"), "// fixture");
fails(["--standalone", root, "--runtime", path.join(root, "missing")], /Runtime not found/);
fails(["--standalone", root, "--runtime", root], /Runtime not found/);
const runtime = path.join(root, "runtime");
fs.writeFileSync(runtime, "fixture", { mode: 0o600 });
fails(["--standalone", root, "--runtime", runtime], /EACCES/);
});
});
for (const relative of ["auth.json", ".env", ".env.local", ".env.production", ".env.production.local", ".learnharness", "data"]) {
it(`rejects leaked credential/data path ${relative} before dependency probes`, () => {
withFixture((root) => {
fs.writeFileSync(path.join(root, "server.js"), "// fixture");
fs.writeFileSync(path.join(root, relative), "not-a-real-credential");
fails(["--standalone", root], /Credential\/data path leaked into standalone/);
});
});
}
});