perf(core): opt-in in-memory SQLite for *-store tests

Adds an opt-in `inMemory` flag to `Database`/`ArchiveDatabase` (and
`{ inMemoryDb }` to TaskStore, AgentStore, RoutineStore,
AutomationStore, PluginStore) that swaps the on-disk fusion.db /
archive.db for SQLite's `:memory:` connection. Production callers
never set the flag, so behavior is unchanged.

Test files for each store now flip the flag in `beforeEach`. The
handful of tests that exercise cross-instance persistence (open store
A, close, open store B on same dir, expect data) construct disk-backed
stores explicitly inside the test body, marked with a comment at each
site.

Wall-clock impact:
- core:      69.4s → 18.5s  (3.7× faster, 3038 tests)
- dashboard: 156.6s → 30.0s (5.2× faster — improvement ripples through
                              any test that constructs a TaskStore)

The refactor eliminates the per-test SQLite open + WAL fsync + tmp
dir cleanup loop that dominated setup cost: ~50ms/test → ~5ms/test.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
gsxdsm
2026-04-26 18:45:14 -07:00
parent e2bc644fd5
commit 6e4797ff14
17 changed files with 179 additions and 34 deletions

View File

@@ -31,7 +31,10 @@ describe("AgentStore", () => {
beforeEach(async () => {
rootDir = makeTmpDir();
store = new AgentStore({ rootDir });
// In-memory SQLite — see store.test.ts beforeEach for rationale.
// Tests that exercise cross-instance persistence (search for `store2`)
// construct disk-backed stores explicitly inside the test body.
store = new AgentStore({ rootDir, inMemoryDb: true });
await store.init();
});
@@ -102,6 +105,13 @@ describe("AgentStore", () => {
});
it("normalizes legacy durable agents to heartbeat enabled once", async () => {
// Migration test: opens a raw Database on disk to seed a meta key,
// then re-opens the AgentStore to assert migration ran. Needs both
// the store and the raw DB to be disk-backed.
store.close();
store = new AgentStore({ rootDir });
await store.init();
const agent = await store.createAgent({
name: "Legacy Durable Agent",
role: "executor",
@@ -2459,6 +2469,12 @@ describe("AgentStore", () => {
});
it("API keys survive store reinitialization", async () => {
// Cross-instance persistence — swap in-memory beforeEach store for
// disk-backed so store2 (also disk-backed) can read what we wrote.
store.close();
store = new AgentStore({ rootDir });
await store.init();
const agent = await store.createAgent({ name: "KeyPersistence", role: "executor" });
const { key } = await store.createApiKey(agent.id, { label: "persist" });
@@ -2536,6 +2552,11 @@ describe("AgentStore", () => {
describe("SQLite persistence", () => {
it("agent data survives store reinitialization", async () => {
// Cross-instance persistence — see counterpart in API keys describe.
store.close();
store = new AgentStore({ rootDir });
await store.init();
const agent = await store.createAgent({
name: "Persistent",
role: "reviewer",

View File

@@ -28,7 +28,10 @@ describe("AutomationStore", () => {
beforeEach(async () => {
rootDir = makeTmpDir();
store = new AutomationStore(rootDir);
// In-memory SQLite for test speed; see store.test.ts beforeEach.
// Cross-instance persistence sub-test below opens a disk-backed
// secondStore explicitly.
store = new AutomationStore(rootDir, { inMemoryDb: true });
await store.init();
});
@@ -179,6 +182,12 @@ describe("AutomationStore", () => {
});
it("persists schedule to database", async () => {
// Cross-instance persistence — swap to disk-backed for both stores.
// AutomationStore has no close() method; the in-memory beforeEach
// store is dropped on reassignment and its DB connection is GC'd.
store = new AutomationStore(rootDir);
await store.init();
const schedule = await store.createSchedule({
name: "Persist test",
command: "echo persist",

View File

@@ -19,7 +19,8 @@ describe("ChatStore", () => {
beforeEach(() => {
tmpDir = makeTmpDir();
fusionDir = join(tmpDir, ".fusion");
db = new Database(fusionDir);
// In-memory SQLite for test speed; see store.test.ts beforeEach.
db = new Database(fusionDir, { inMemory: true });
db.init();
store = new ChatStore(fusionDir, db);
});

View File

@@ -47,7 +47,10 @@ function createProvenance(overrides: Partial<InsightProvenance> = {}): InsightPr
beforeEach(() => {
fusionDir = makeTmpDir();
db = createDatabase(fusionDir);
// In-memory SQLite for test speed; see store.test.ts beforeEach.
// Tests below that exercise migration on a real on-disk DB construct
// their own disk-backed Database explicitly.
db = createDatabase(fusionDir, { inMemory: true });
db.init();
store = new InsightStore(db);
});

View File

@@ -13,7 +13,8 @@ describe("MessageStore", () => {
beforeEach(() => {
tempDir = mkdtempSync(join(tmpdir(), "kb-msg-test-"));
db = new Database(tempDir);
// In-memory SQLite for test speed; see store.test.ts beforeEach.
db = new Database(tempDir, { inMemory: true });
db.init();
store = new MessageStore(db);
});

View File

@@ -32,7 +32,10 @@ describe("MissionStore", () => {
beforeEach(() => {
tmpDir = makeTmpDir();
fusionDir = join(tmpDir, ".fusion");
db = new Database(fusionDir);
// In-memory SQLite for test speed — see store.test.ts beforeEach for
// the broader rationale. MissionStore tests don't exercise
// cross-instance persistence, so this is safe across the whole file.
db = new Database(fusionDir, { inMemory: true });
db.init();
store = new MissionStore(fusionDir, db);
});

View File

@@ -26,7 +26,8 @@ describe("PluginStore", () => {
beforeEach(async () => {
rootDir = makeTmpDir();
store = new PluginStore(rootDir);
// In-memory SQLite for test speed; see store.test.ts beforeEach.
store = new PluginStore(rootDir, { inMemoryDb: true });
await store.init();
});
@@ -38,6 +39,10 @@ describe("PluginStore", () => {
describe("init", () => {
it("creates the database file", async () => {
// Asserts a real file on disk exists, which the in-memory
// beforeEach store can't satisfy — open a disk-backed store.
const diskStore = new PluginStore(rootDir);
await diskStore.init();
const dbPath = join(rootDir, ".fusion", "fusion.db");
const { existsSync } = await import("node:fs");
expect(existsSync(dbPath)).toBe(true);

View File

@@ -28,7 +28,10 @@ describe("RoadmapStore", () => {
beforeEach(() => {
tmpDir = makeTmpDir();
db = new Database(join(tmpDir, ".fusion"));
// In-memory SQLite for test speed; see store.test.ts beforeEach.
// Cross-instance persistence sub-tests below construct disk-backed
// Database instances explicitly (search for `persistDb`).
db = new Database(join(tmpDir, ".fusion"), { inMemory: true });
db.init();
store = new RoadmapStore(db);
});

View File

@@ -21,7 +21,8 @@ describe("RoutineStore", () => {
beforeEach(async () => {
rootDir = makeTmpDir();
store = new RoutineStore(rootDir);
// In-memory SQLite for test speed; see store.test.ts beforeEach.
store = new RoutineStore(rootDir, { inMemoryDb: true });
await store.init();
});

View File

@@ -43,7 +43,12 @@ describe("TaskStore", () => {
beforeEach(async () => {
rootDir = makeTmpDir();
globalDir = makeTmpDir();
store = new TaskStore(rootDir, globalDir);
// In-memory SQLite cuts per-test setup from ~50ms to ~5ms by avoiding
// disk open + WAL fsync for both fusion.db and archive.db. The few
// tests below that exercise cross-instance persistence (open store A,
// close, open store B on same dir, expect data) construct disk-backed
// stores explicitly — they are flagged with a comment at each site.
store = new TaskStore(rootDir, globalDir, { inMemoryDb: true });
await store.init();
});
@@ -292,6 +297,13 @@ describe("TaskStore", () => {
});
it("persists token usage across TaskStore reinitialization", async () => {
// Cross-instance persistence test — swap beforeEach's in-memory
// store for disk-backed so the second `new TaskStore` below can
// observe what this instance writes.
store.close();
store = new TaskStore(rootDir, globalDir);
await store.init();
const tokenUsage = {
inputTokens: 300,
outputTokens: 120,
@@ -315,6 +327,11 @@ describe("TaskStore", () => {
});
it("clears token usage via null update and keeps it absent after reload", async () => {
// Cross-instance persistence test — see counterpart above.
store.close();
store = new TaskStore(rootDir, globalDir);
await store.init();
const task = await store.createTask({
description: "Clear token usage",
tokenUsage: {
@@ -2663,6 +2680,13 @@ describe("TaskStore", () => {
};
it("round-trips nested remoteAccess settings with both providers, token strategy, and lifecycle", async () => {
// Cross-instance persistence test — beforeEach uses in-memory DB
// for speed, but this case reloads via a second TaskStore on the
// same dir, so we need disk-backed for both.
store.close();
store = new TaskStore(rootDir, globalDir);
await store.init();
await store.updateSettings({ remoteAccess: baseRemoteAccess });
const settings = await store.getSettings();
@@ -6918,6 +6942,12 @@ Task with acceptance criteria
describe("cleanupArchivedTasks", () => {
it("writes compact entry to archive DB with compact agent log", async () => {
// This test asserts the archive.db file exists on disk, which the
// in-memory beforeEach store can't satisfy. Swap to disk-backed.
store.close();
store = new TaskStore(rootDir, globalDir);
await store.init();
// Create and archive a task
const task = await store.createTask({ description: "Test cleanup", title: "Cleanup Task" });
await store.moveTask(task.id, "todo");
@@ -7335,6 +7365,14 @@ Task with acceptance criteria
describe("archive log persistence", () => {
it("archive log survives TaskStore reinitialization", async () => {
// Cross-instance persistence test — beforeEach creates an in-memory
// store, but this test verifies disk persistence. Swap to a
// disk-backed store before doing any work so newStore (also
// disk-backed) can read what the first instance wrote.
store.close();
store = new TaskStore(rootDir, globalDir);
await store.init();
const task = await store.createTask({ description: "Survival test" });
await store.moveTask(task.id, "todo");
await store.moveTask(task.id, "in-progress");
@@ -7515,6 +7553,12 @@ Task with acceptance criteria
});
it("activity log survives TaskStore reinitialization", async () => {
// Cross-instance persistence test — see archive-log counterpart
// above for the in-memory carve-out rationale.
store.close();
store = new TaskStore(rootDir, globalDir);
await store.init();
await store.recordActivity({ type: "task:created", taskId: "FN-001", details: "Test" });
// Create new store instance
@@ -9233,6 +9277,12 @@ Task with acceptance criteria
});
it("recovery metadata persists across store re-initialization", async () => {
// Cross-instance persistence test — see archive-log counterpart in
// this file for the in-memory carve-out rationale.
store.close();
store = new TaskStore(rootDir, globalDir);
await store.init();
const task = await createTestTask();
const futureTime = new Date(Date.now() + 60_000).toISOString();
await store.updateTask(task.id, {