106 lines
3.4 KiB
JavaScript
106 lines
3.4 KiB
JavaScript
import fs from "node:fs";
|
|
import os from "node:os";
|
|
import path from "node:path";
|
|
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
|
|
import { makeTempDir } from "./helpers.mjs";
|
|
import { resolveJobFile, resolveJobLogFile, resolveStateDir, resolveStateFile, saveState } from "../plugins/codex/scripts/lib/state.mjs";
|
|
|
|
test("resolveStateDir uses a temp-backed per-workspace directory", () => {
|
|
const workspace = makeTempDir();
|
|
const stateDir = resolveStateDir(workspace);
|
|
|
|
assert.equal(stateDir.startsWith(os.tmpdir()), true);
|
|
assert.match(path.basename(stateDir), /.+-[a-f0-9]{16}$/);
|
|
assert.match(stateDir, new RegExp(`^${os.tmpdir().replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}`));
|
|
});
|
|
|
|
test("resolveStateDir uses CLAUDE_PLUGIN_DATA when it is provided", () => {
|
|
const workspace = makeTempDir();
|
|
const pluginDataDir = makeTempDir();
|
|
const previousPluginDataDir = process.env.CLAUDE_PLUGIN_DATA;
|
|
process.env.CLAUDE_PLUGIN_DATA = pluginDataDir;
|
|
|
|
try {
|
|
const stateDir = resolveStateDir(workspace);
|
|
|
|
assert.equal(stateDir.startsWith(path.join(pluginDataDir, "state")), true);
|
|
assert.match(path.basename(stateDir), /.+-[a-f0-9]{16}$/);
|
|
assert.match(
|
|
stateDir,
|
|
new RegExp(`^${path.join(pluginDataDir, "state").replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}`)
|
|
);
|
|
} finally {
|
|
if (previousPluginDataDir == null) {
|
|
delete process.env.CLAUDE_PLUGIN_DATA;
|
|
} else {
|
|
process.env.CLAUDE_PLUGIN_DATA = previousPluginDataDir;
|
|
}
|
|
}
|
|
});
|
|
|
|
test("saveState prunes dropped job artifacts when indexed jobs exceed the cap", () => {
|
|
const workspace = makeTempDir();
|
|
const stateFile = resolveStateFile(workspace);
|
|
fs.mkdirSync(path.dirname(stateFile), { recursive: true });
|
|
|
|
const jobs = Array.from({ length: 51 }, (_, index) => {
|
|
const jobId = `job-${index}`;
|
|
const updatedAt = new Date(Date.UTC(2026, 0, 1, 0, index, 0)).toISOString();
|
|
const logFile = resolveJobLogFile(workspace, jobId);
|
|
const jobFile = resolveJobFile(workspace, jobId);
|
|
fs.writeFileSync(logFile, `log ${jobId}\n`, "utf8");
|
|
fs.writeFileSync(jobFile, JSON.stringify({ id: jobId, status: "completed" }, null, 2), "utf8");
|
|
return {
|
|
id: jobId,
|
|
status: "completed",
|
|
logFile,
|
|
updatedAt,
|
|
createdAt: updatedAt
|
|
};
|
|
});
|
|
|
|
fs.writeFileSync(
|
|
stateFile,
|
|
`${JSON.stringify(
|
|
{
|
|
version: 1,
|
|
config: { stopReviewGate: false },
|
|
jobs
|
|
},
|
|
null,
|
|
2
|
|
)}\n`,
|
|
"utf8"
|
|
);
|
|
|
|
saveState(workspace, {
|
|
version: 1,
|
|
config: { stopReviewGate: false },
|
|
jobs
|
|
});
|
|
|
|
const prunedJobFile = resolveJobFile(workspace, "job-0");
|
|
const prunedLogFile = resolveJobLogFile(workspace, "job-0");
|
|
const retainedJobFile = resolveJobFile(workspace, "job-50");
|
|
const retainedLogFile = resolveJobLogFile(workspace, "job-50");
|
|
const jobsDir = path.dirname(prunedJobFile);
|
|
|
|
assert.equal(fs.existsSync(retainedJobFile), true);
|
|
assert.equal(fs.existsSync(retainedLogFile), true);
|
|
|
|
const savedState = JSON.parse(fs.readFileSync(stateFile, "utf8"));
|
|
assert.equal(savedState.jobs.length, 50);
|
|
assert.deepEqual(
|
|
savedState.jobs.map((job) => job.id),
|
|
Array.from({ length: 50 }, (_, index) => `job-${50 - index}`)
|
|
);
|
|
assert.deepEqual(
|
|
fs.readdirSync(jobsDir).sort(),
|
|
Array.from({ length: 50 }, (_, index) => `job-${index + 1}`)
|
|
.flatMap((jobId) => [`${jobId}.json`, `${jobId}.log`])
|
|
.sort()
|
|
);
|
|
});
|