Files
pi/packages/coding-agent/test/session-analytics-reader.test.ts
2026-06-04 09:41:42 +02:00

84 lines
3.0 KiB
TypeScript

import { mkdirSync, mkdtempSync, rmSync, utimesSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { afterEach, describe, expect, it } from "vitest";
import { buildSessionAnalyticsUpload } from "../src/core/session-analytics-reader.ts";
const tempDirs: string[] = [];
function createTempDir(): string {
const dir = mkdtempSync(join(tmpdir(), "pi-session-analytics-reader-"));
tempDirs.push(dir);
return dir;
}
afterEach(() => {
for (const dir of tempDirs.splice(0)) {
rmSync(dir, { recursive: true, force: true });
}
});
function writeJsonl(path: string, lines: unknown[]): void {
writeFileSync(path, `${lines.map((line) => JSON.stringify(line)).join("\n")}\n`);
}
function sessionHeader(id: string, timestamp: string): unknown {
return { type: "session", version: 3, id, timestamp, cwd: `/work/${id}` };
}
function entry(id: string, timestamp: string): unknown {
return { type: "model_change", id, parentId: null, timestamp, provider: "anthropic", modelId: "model" };
}
describe("buildSessionAnalyticsUpload", () => {
it("selects files by mtime and includes old records before the scan cutoff", async () => {
const root = createTempDir();
const project = join(root, "--project--");
mkdirSync(project, { recursive: true });
const oldFile = join(project, "old.jsonl");
const changedFile = join(project, "changed.jsonl");
writeJsonl(oldFile, [
sessionHeader("old", "2026-01-01T00:00:00.000Z"),
entry("old-entry", "2026-01-01T00:00:01.000Z"),
]);
writeJsonl(changedFile, [
sessionHeader("changed", "2026-01-01T00:00:00.000Z"),
entry("included-old-entry", "2026-01-01T00:00:01.000Z"),
entry("future-entry", "2026-01-03T00:00:00.000Z"),
]);
utimesSync(oldFile, new Date("2026-01-01T00:10:00.000Z"), new Date("2026-01-01T00:10:00.000Z"));
utimesSync(changedFile, new Date("2026-01-02T00:10:00.000Z"), new Date("2026-01-02T00:10:00.000Z"));
const result = await buildSessionAnalyticsUpload({
sessionsRoot: root,
serverWatermark: "2026-01-02T00:00:00.000Z",
scanCutoff: new Date("2026-01-02T12:00:00.000Z"),
});
expect(result.filesScanned).toBe(1);
expect(result.malformedFiles).toBe(0);
expect(result.scanCutoff).toBe("2026-01-02T12:00:00.000Z");
expect(
result.records.map((record) => (record.recordType === "entry" ? record.entryId : record.sessionId)),
).toEqual(["changed", "included-old-entry"]);
});
it("skips malformed selected files", async () => {
const root = createTempDir();
const project = join(root, "--project--");
mkdirSync(project, { recursive: true });
const malformed = join(project, "malformed.jsonl");
writeFileSync(malformed, `${JSON.stringify(sessionHeader("bad", "2026-01-01T00:00:00.000Z"))}\nnot json\n`);
const result = await buildSessionAnalyticsUpload({
sessionsRoot: root,
serverWatermark: null,
scanCutoff: new Date("2026-01-02T00:00:00.000Z"),
});
expect(result.records).toEqual([]);
expect(result.filesScanned).toBe(1);
expect(result.malformedFiles).toBe(1);
});
});