fix flaky resume behavior
This commit is contained in:
82
tests/progress-multiprd.test.ts
Normal file
82
tests/progress-multiprd.test.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
/// <reference types="bun-types" />
|
||||
import { describe, it, expect, beforeEach } from "bun:test";
|
||||
import * as fs from "node:fs";
|
||||
import * as os from "node:os";
|
||||
import * as path from "node:path";
|
||||
import { ProgressTracker } from "../src/progress";
|
||||
|
||||
/**
|
||||
* Regression test: two concurrent loops (different PRDs) each run their own
|
||||
* ProgressTracker. Each instance snapshots the whole state at construction;
|
||||
* a save() that writes that stale snapshot verbatim would revert the OTHER
|
||||
* loop's task status changes — tasks wrongly back to "pending" while their
|
||||
* worktrees carry real work, stranding it on the next resume.
|
||||
*/
|
||||
let root: string;
|
||||
|
||||
beforeEach(() => {
|
||||
root = fs.mkdtempSync(path.join(os.tmpdir(), "ralpi-prog-test-"));
|
||||
});
|
||||
|
||||
function prdA(projectDir: string): ProgressTracker {
|
||||
return new ProgressTracker(
|
||||
projectDir,
|
||||
path.join(projectDir, "tasks/a/README.md"),
|
||||
);
|
||||
}
|
||||
function prdB(projectDir: string): ProgressTracker {
|
||||
return new ProgressTracker(
|
||||
projectDir,
|
||||
path.join(projectDir, "tasks/b/README.md"),
|
||||
);
|
||||
}
|
||||
|
||||
/** Read the on-disk progress state; the file is written by the tracker, so
|
||||
* a parse failure is a test bug worth surfacing. */
|
||||
function readState(): Record<string, any> {
|
||||
const raw = fs.readFileSync(
|
||||
path.join(root, ".ralpi", "progress.json"),
|
||||
"utf-8",
|
||||
);
|
||||
try {
|
||||
return JSON.parse(raw) as Record<string, any>;
|
||||
} catch {
|
||||
throw new Error(`malformed progress.json:\n${raw.slice(0, 200)}`);
|
||||
}
|
||||
}
|
||||
|
||||
describe("ProgressTracker multi-PRD save isolation", () => {
|
||||
it("does not clobber another PRD's task status on save", () => {
|
||||
const a = prdA(root);
|
||||
const b = prdB(root);
|
||||
expect(a.getKey()).not.toBe(b.getKey());
|
||||
|
||||
// Loop A marks its task in_progress.
|
||||
a.markInProgress("01");
|
||||
expect(a.getTaskStatus("01")).toBe("in_progress");
|
||||
|
||||
// Loop B (stale snapshot from before A's update) marks ITS task.
|
||||
b.markInProgress("02");
|
||||
|
||||
// The on-disk state must show BOTH updates.
|
||||
const raw = readState();
|
||||
expect(raw.prds[a.getKey()].tasks["01"].status).toBe("in_progress");
|
||||
expect(raw.prds[b.getKey()].tasks["02"].status).toBe("in_progress");
|
||||
});
|
||||
|
||||
it("preserves other PRD completions when this PRD saves", () => {
|
||||
const a = prdA(root);
|
||||
const b = prdB(root);
|
||||
|
||||
a.markCompleted("01", 1000);
|
||||
b.markInProgress("02");
|
||||
|
||||
// A completes another task later — A's save must not revert B.
|
||||
a.markCompleted("03", 500);
|
||||
|
||||
const raw = readState();
|
||||
expect(raw.prds[a.getKey()].tasks["01"].status).toBe("completed");
|
||||
expect(raw.prds[a.getKey()].tasks["03"].status).toBe("completed");
|
||||
expect(raw.prds[b.getKey()].tasks["02"].status).toBe("in_progress");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user