fix(coding-agent): test forkFrom copied content instead of fs calls

Move the forkFrom test into custom-session-id.test.ts, drop the fs mock
and call-count checks, and clean up the temp directory.
This commit is contained in:
David Brailovsky 2026-10-22 20:02:59 +02:00 • committed by Petr Houška
parent 8ddc44ec8b
commit ed76cca69b
2 changed files with 44 additions and 67 deletions

View file

@ -1,4 +1,4 @@
import { existsSync, mkdtempSync, writeFileSync } from "node:fs";
import { existsSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { basename, join } from "node:path";
import { describe, expect, it } from "vitest";
@ -167,3 +167,46 @@ describe("SessionManager.newSession with custom id", () => {
expect(basename(sessionFile)).toMatch(/^\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}-\d{3}Z_forked-session-id\.jsonl$/);
});
});
describe("SessionManager.forkFrom", () => {
it("copies all entries unchanged into the forked session", () => {
const tempDir = mkdtempSync(join(tmpdir(), "pi-session-manager-"));
try {
const sourcePath = join(tempDir, "source.jsonl");
const lines = [
JSON.stringify({
type: "session",
version: 3,
id: "source-id",
timestamp: new Date().toISOString(),
cwd: tempDir,
}),
];
let parentId: string | null = null;
for (let i = 0; i < 50; i++) {
const id = `e${i}`;
lines.push(
JSON.stringify({
type: "message",
id,
parentId,
timestamp: new Date().toISOString(),
message: { role: "user", content: `message ${i}`, timestamp: 0 },
}),
);
parentId = id;
}
writeFileSync(sourcePath, `${lines.join("\n")}\n`);
const forked = SessionManager.forkFrom(sourcePath, tempDir, join(tempDir, "sessions"));
const written = readFileSync(forked.getSessionFile()!, "utf8").trimEnd().split("\n");
expect(written).toHaveLength(51);
expect(JSON.parse(written[0]).parentSession).toBe(sourcePath);
expect(written.slice(1)).toEqual(lines.slice(1));
expect(forked.getEntries()).toHaveLength(50);
} finally {
rmSync(tempDir, { recursive: true, force: true });
}
});
});

View file

@ -1,66 +0,0 @@
import type * as Fs from "node:fs";
import { mkdtempSync, readFileSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { describe, expect, it, vi } from "vitest";
import { SessionManager } from "../../src/core/session-manager.ts";
const { openSyncSpy, appendFileSyncSpy } = vi.hoisted(() => ({
openSyncSpy: vi.fn(),
appendFileSyncSpy: vi.fn(),
}));
vi.mock("fs", async (importOriginal) => {
const actual = await importOriginal<typeof Fs>();
openSyncSpy.mockImplementation(actual.openSync);
appendFileSyncSpy.mockImplementation(actual.appendFileSync);
return { ...actual, openSync: openSyncSpy, appendFileSync: appendFileSyncSpy };
});
describe("SessionManager.forkFrom", () => {
// Regression test for #11253: forking reopened the target file once per entry.
it("copies all entries while opening the new session file only once for writing", () => {
const tempDir = mkdtempSync(join(tmpdir(), "pi-fork-from-"));
const sourcePath = join(tempDir, "source.jsonl");
const lines = [
JSON.stringify({
type: "session",
version: 3,
id: "source-id",
timestamp: new Date().toISOString(),
cwd: tempDir,
}),
];
let parentId: string | null = null;
for (let i = 0; i < 50; i++) {
const id = `e${i}`;
lines.push(
JSON.stringify({
type: "message",
id,
parentId,
timestamp: new Date().toISOString(),
message: { role: "user", content: `message ${i}`, timestamp: 0 },
}),
);
parentId = id;
}
writeFileSync(sourcePath, `${lines.join("\n")}\n`);
const targetDir = join(tempDir, "sessions");
openSyncSpy.mockClear();
appendFileSyncSpy.mockClear();
const forked = SessionManager.forkFrom(sourcePath, tempDir, targetDir);
const newFile = forked.getSessionFile()!;
const writeOpens = openSyncSpy.mock.calls.filter(([path, flags]) => path === newFile && flags !== "r");
expect(writeOpens).toEqual([[newFile, "wx"]]);
expect(appendFileSyncSpy.mock.calls.filter(([path]) => path === newFile)).toHaveLength(0);
const written = readFileSync(newFile, "utf8").trimEnd().split("\n");
expect(written).toHaveLength(51);
expect(JSON.parse(written[0]).parentSession).toBe(sourcePath);
expect(written.slice(1)).toEqual(lines.slice(1));
expect(forked.getEntries()).toHaveLength(50);
});
});