Files
stack/packages/runs/tests/state.test.mjs
T
jason.woltjeandClaude Opus 5.5 71d874764a feat(runs): read-only runs and releases reader module (#1545, row 56)
New packages/runs reads run records, result.json, the release pointer
and the activation log without writing, pruning or following a link out
of the data root. mosaic-task.mjs list and show use it, so a malformed
result.json or a run that is a regular file no longer crashes them.
Deliberate deltas are listed in the README.

Rocko built it. Round 1 (ed3c5392) was approved with notes by Darkwing
(27115) and Filbert (27116); round 2 (2727198f, tests and wording only)
was approved by Darkwing (27123) and Filbert (27124). Sage's gate on
c9a25a47 plus the candidate: runs 41/0, queue 148/0, webui 22/0,
conversation 182/0 (181/1 in the full run on the K12 cgroup timing
test under load, 182/0 alone), control-board 124/0, every
scripts/test-*.sh 0 failed (task 98/0 with Docker, 26/0 without).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-10 12:22:37 -05:00

132 lines
5.6 KiB
JavaScript

import { test } from "node:test";
import assert from "node:assert/strict";
import fs from "node:fs";
import path from "node:path";
import { RunsError, readActivationLog, readActivePointer } from "../src/index.mjs";
import { scratch, tree, write } from "./helpers.mjs";
const POINTER = { pointerVersion: 1, release: "0.0.12", imageTag: "mosaic-poc-agent:0.84.4-r0.0.12", activatedAt: "2026-09-03T20:58:15Z" };
function entry(at, event, release, extra = {}) {
return { at, event, release, imageTag: `mosaic-poc-agent:0.84.4-r${release}`, ...extra };
}
function writeLog(dataRoot, lines) {
write(path.join(dataRoot, "state", "activation-log.jsonl"), lines.map((l) => (typeof l === "string" ? l : JSON.stringify(l))).join("\n") + "\n");
}
test("no pointer is null", (t) => {
const { dir, dataRoot } = scratch(t);
assert.equal(readActivePointer(dataRoot), null);
assert.equal(readActivePointer(path.join(dir, "absent")), null);
});
test("the pointer release.sh writes reads back", (t) => {
const { dataRoot } = scratch(t);
// The exact bytes of release.sh's printf.
write(path.join(dataRoot, "state", "active.json"),
'{"pointerVersion":1,"release":"0.0.12","imageTag":"mosaic-poc-agent:0.84.4-r0.0.12","activatedAt":"2026-09-03T20:58:15Z"}\n');
assert.deepEqual(readActivePointer(dataRoot), POINTER);
});
test("a pointer that isn't the version 1 shape refuses with exit 2", (t) => {
const { dataRoot } = scratch(t);
const file = path.join(dataRoot, "state", "active.json");
const cases = [
["{ truncated", /not valid JSON/],
["[]", /must be a JSON object/],
["null", /must be a JSON object/],
[{ ...POINTER, extra: 1 }, /unsupported key: "extra"/],
[{ ...POINTER, pointerVersion: 2 }, /unsupported pointerVersion 2/],
[{ ...POINTER, release: "" }, /non-empty string "release"/],
[{ ...POINTER, imageTag: 5 }, /non-empty string "imageTag"/],
[{ pointerVersion: 1, release: "0.0.1", imageTag: "x" }, /non-empty string "activatedAt"/],
];
for (const [content, pattern] of cases) {
write(file, content);
assert.throws(() => readActivePointer(dataRoot), (e) => e instanceof RunsError && e.exitCode === 2 && pattern.test(e.message), String(pattern));
}
});
test("a pointer that is a directory refuses with exit 4", (t) => {
const { dataRoot } = scratch(t);
fs.mkdirSync(path.join(dataRoot, "state", "active.json"), { recursive: true });
assert.throws(() => readActivePointer(dataRoot), (e) => e instanceof RunsError && e.exitCode === 4 && /EISDIR/.test(e.message));
});
test("a state file linked out of the data root refuses", (t) => {
const { dataRoot, outside } = scratch(t);
write(path.join(outside, "active.json"), POINTER);
write(path.join(outside, "log.jsonl"), `${JSON.stringify(entry("a", "activate", "0.0.1"))}\n`);
fs.mkdirSync(path.join(dataRoot, "state"));
fs.symlinkSync(path.join(outside, "active.json"), path.join(dataRoot, "state", "active.json"));
fs.symlinkSync(path.join(outside, "log.jsonl"), path.join(dataRoot, "state", "activation-log.jsonl"));
assert.throws(() => readActivePointer(dataRoot), /resolves outside the data root/);
assert.throws(() => readActivationLog(dataRoot), /resolves outside the data root/);
});
test("a state directory linked out of the data root refuses", (t) => {
const { dataRoot, outside } = scratch(t);
write(path.join(outside, "active.json"), POINTER);
fs.symlinkSync(outside, path.join(dataRoot, "state"));
assert.throws(() => readActivePointer(dataRoot), /state\/active.json resolves outside the data root/);
});
test("a state directory linked out to nothing reads as no release and an empty log", (t) => {
const { dataRoot, outside } = scratch(t);
fs.symlinkSync(path.join(outside, "absent"), path.join(dataRoot, "state"));
assert.equal(readActivePointer(dataRoot), null);
assert.deepEqual(readActivationLog(dataRoot), { entries: [], malformed: 0 });
});
test("a missing log is empty", (t) => {
const { dataRoot } = scratch(t);
assert.deepEqual(readActivationLog(dataRoot), { entries: [], malformed: 0 });
});
test("the log reads oldest first and counts malformed lines", (t) => {
const { dataRoot } = scratch(t);
const good = [
entry("2026-09-03T20:57:00Z", "package", "0.0.12"),
entry("2026-09-03T20:57:47Z", "activate", "0.0.12"),
entry("2026-09-03T20:57:50Z", "refused", "0.0.11", { note: "health check failed (fault-injected)" }),
entry("2026-09-03T20:58:15Z", "rollback", "0.0.11"),
];
writeLog(dataRoot, [
good[0],
"{ torn line",
good[1],
"",
" ",
"[]",
{ ...good[1], extra: true },
{ ...good[1], at: 5 },
{ ...good[1], note: null },
{ at: good[1].at, event: good[1].event, release: good[1].release },
{ ...good[1], release: 5 },
good[2],
good[3],
]);
assert.deepEqual(readActivationLog(dataRoot), { entries: good, malformed: 7 });
assert.deepEqual(readActivationLog(dataRoot, { last: 2 }), { entries: good.slice(2), malformed: 7 });
assert.deepEqual(readActivationLog(dataRoot, { last: 99 }).entries, good);
});
test("last must be a positive integer", (t) => {
const { dataRoot } = scratch(t);
for (const last of [0, -1, 1.5, "2", null]) {
assert.throws(() => readActivationLog(dataRoot, { last }), /last must be a positive integer/, String(last));
}
});
test("the state readers write nothing", (t) => {
const { dataRoot } = scratch(t);
write(path.join(dataRoot, "state", "active.json"), POINTER);
writeLog(dataRoot, [entry("a", "activate", "0.0.1"), "{ bad"]);
const before = tree(dataRoot);
readActivePointer(dataRoot);
readActivationLog(dataRoot);
readActivationLog(dataRoot, { last: 1 });
assert.equal(tree(dataRoot), before);
});