86 lines
2.8 KiB
JavaScript
86 lines
2.8 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import {
|
|
mkdir,
|
|
mkdtemp,
|
|
readFile,
|
|
rm,
|
|
stat,
|
|
writeFile,
|
|
} from "node:fs/promises";
|
|
import { tmpdir } from "node:os";
|
|
import { join } from "node:path";
|
|
import test from "node:test";
|
|
import { createWorkspaceStore } from "../src/bridge/workspace-store.js";
|
|
|
|
test("persists an owner-only versioned workspace manifest atomically", async () => {
|
|
const root = await mkdtemp(join(tmpdir(), "pi-workspace-store-"));
|
|
const store = createWorkspaceStore(join(root, "sessions"));
|
|
const first = await store.load();
|
|
assert.equal(first.migrating, true);
|
|
|
|
await store.save({
|
|
version: 2,
|
|
migrated: true,
|
|
runtimes: [
|
|
{
|
|
runtimeId: "runtime-1",
|
|
worktreePath: join(root, "home"),
|
|
sessionPath: join(root, "sessions", "agent", "one.jsonl"),
|
|
sessionId: "session-1",
|
|
},
|
|
],
|
|
});
|
|
const metadata = await stat(store.filePath);
|
|
assert.equal(metadata.mode & 0o777, 0o600);
|
|
const restored = (await store.load()).manifest;
|
|
assert.equal(restored.runtimes[0].runtimeId, "runtime-1");
|
|
assert.deepEqual(restored.directories, [join(root, "home")]);
|
|
assert.equal((await readFile(store.filePath, "utf8")).endsWith("\n"), true);
|
|
});
|
|
|
|
test("accepts old manifests and persists managed empty directories", async () => {
|
|
const root = await mkdtemp(join(tmpdir(), "pi-workspace-directories-"));
|
|
const store = createWorkspaceStore(join(root, "sessions"));
|
|
await store.save({
|
|
version: 2,
|
|
migrated: true,
|
|
directories: [join(root, "empty")],
|
|
runtimes: [],
|
|
});
|
|
assert.deepEqual((await store.load()).manifest.directories, [
|
|
join(root, "empty"),
|
|
]);
|
|
await writeFile(
|
|
store.filePath,
|
|
JSON.stringify({ version: 2, migrated: true, runtimes: [] }),
|
|
{ mode: 0o600 },
|
|
);
|
|
assert.deepEqual((await store.load()).manifest.directories, []);
|
|
});
|
|
|
|
test("reports a corrupt manifest without treating it as first migration", async () => {
|
|
const root = await mkdtemp(join(tmpdir(), "pi-workspace-corrupt-"));
|
|
const store = createWorkspaceStore(join(root, "sessions"));
|
|
await store.save({ version: 2, migrated: true, runtimes: [] });
|
|
await writeFile(store.filePath, "{broken", { mode: 0o600 });
|
|
|
|
const loaded = await store.load();
|
|
assert.equal(loaded.migrating, false);
|
|
assert.equal(loaded.manifest.runtimes.length, 0);
|
|
assert.equal(loaded.issue.code, "invalid_workspace_manifest");
|
|
});
|
|
|
|
test("recovers its serialized write queue after a failed save", async () => {
|
|
const root = await mkdtemp(join(tmpdir(), "pi-workspace-retry-"));
|
|
const sessionRoot = join(root, "sessions");
|
|
const store = createWorkspaceStore(sessionRoot);
|
|
await mkdir(sessionRoot);
|
|
await mkdir(store.filePath);
|
|
await assert.rejects(
|
|
store.save({ version: 2, migrated: true, runtimes: [] }),
|
|
);
|
|
await rm(store.filePath, { recursive: true });
|
|
await store.save({ version: 2, migrated: true, runtimes: [] });
|
|
assert.deepEqual((await store.load()).manifest.runtimes, []);
|
|
});
|