Files
openclaw/src/agents/bootstrap-cache.test.ts
Peter Steinberger 40db3fef49 fix(agents): cache bootstrap snapshots per session key
Co-authored-by: Isis Anisoptera <github@lotuswind.net>
2026-02-23 19:19:45 +00:00

101 lines
3.0 KiB
TypeScript

import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import {
clearAllBootstrapSnapshots,
clearBootstrapSnapshot,
getOrLoadBootstrapFiles,
} from "./bootstrap-cache.js";
import type { WorkspaceBootstrapFile } from "./workspace.js";
vi.mock("./workspace.js", () => ({
loadWorkspaceBootstrapFiles: vi.fn(),
}));
import { loadWorkspaceBootstrapFiles } from "./workspace.js";
const mockLoad = vi.mocked(loadWorkspaceBootstrapFiles);
function makeFile(name: string, content: string): WorkspaceBootstrapFile {
return {
name: name as WorkspaceBootstrapFile["name"],
path: `/ws/${name}`,
content,
missing: false,
};
}
describe("getOrLoadBootstrapFiles", () => {
const files = [makeFile("AGENTS.md", "# Agent"), makeFile("SOUL.md", "# Soul")];
beforeEach(() => {
clearAllBootstrapSnapshots();
mockLoad.mockResolvedValue(files);
});
afterEach(() => {
clearAllBootstrapSnapshots();
vi.clearAllMocks();
});
it("loads from disk on first call and caches", async () => {
const result = await getOrLoadBootstrapFiles({
workspaceDir: "/ws",
sessionKey: "session-1",
});
expect(result).toBe(files);
expect(mockLoad).toHaveBeenCalledTimes(1);
});
it("returns cached result on second call", async () => {
await getOrLoadBootstrapFiles({ workspaceDir: "/ws", sessionKey: "session-1" });
const result = await getOrLoadBootstrapFiles({ workspaceDir: "/ws", sessionKey: "session-1" });
expect(result).toBe(files);
expect(mockLoad).toHaveBeenCalledTimes(1);
});
it("different session keys get independent caches", async () => {
const files2 = [makeFile("AGENTS.md", "# Agent v2")];
mockLoad.mockResolvedValueOnce(files).mockResolvedValueOnce(files2);
const r1 = await getOrLoadBootstrapFiles({ workspaceDir: "/ws", sessionKey: "session-1" });
const r2 = await getOrLoadBootstrapFiles({ workspaceDir: "/ws", sessionKey: "session-2" });
expect(r1).toBe(files);
expect(r2).toBe(files2);
expect(mockLoad).toHaveBeenCalledTimes(2);
});
});
describe("clearBootstrapSnapshot", () => {
beforeEach(() => {
clearAllBootstrapSnapshots();
mockLoad.mockResolvedValue([makeFile("AGENTS.md", "content")]);
});
afterEach(() => {
clearAllBootstrapSnapshots();
vi.clearAllMocks();
});
it("clears a single session entry", async () => {
await getOrLoadBootstrapFiles({ workspaceDir: "/ws", sessionKey: "sk" });
clearBootstrapSnapshot("sk");
// Next call should hit disk again.
await getOrLoadBootstrapFiles({ workspaceDir: "/ws", sessionKey: "sk" });
expect(mockLoad).toHaveBeenCalledTimes(2);
});
it("does not affect other sessions", async () => {
await getOrLoadBootstrapFiles({ workspaceDir: "/ws", sessionKey: "sk1" });
await getOrLoadBootstrapFiles({ workspaceDir: "/ws", sessionKey: "sk2" });
clearBootstrapSnapshot("sk1");
// sk2 should still be cached.
await getOrLoadBootstrapFiles({ workspaceDir: "/ws", sessionKey: "sk2" });
expect(mockLoad).toHaveBeenCalledTimes(2); // sk1 x1, sk2 x1
});
});