From f5334129f5fa2a2268464f71ef82f63743fcc062 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sat, 9 May 2026 05:33:07 +0100 Subject: [PATCH] test: use sqlite locators in session lifecycle tests --- .../server.sessions.compaction.test.ts | 12 +++-- .../server.sessions.delete-lifecycle.test.ts | 13 +++-- .../server.sessions.reset-hooks.test.ts | 53 ++++++++++--------- 3 files changed, 46 insertions(+), 32 deletions(-) diff --git a/src/gateway/server.sessions.compaction.test.ts b/src/gateway/server.sessions.compaction.test.ts index 716946cdbf1..27e6b07cf47 100644 --- a/src/gateway/server.sessions.compaction.test.ts +++ b/src/gateway/server.sessions.compaction.test.ts @@ -4,6 +4,7 @@ import path from "node:path"; import { expect, test, vi } from "vitest"; import { readTranscriptState } from "../agents/transcript/transcript-state.js"; import { getSessionEntry, upsertSessionEntry } from "../config/sessions.js"; +import { createSqliteSessionTranscriptLocator } from "../config/sessions/paths.js"; import { replaceSqliteSessionTranscriptEvents } from "../config/sessions/transcript-store.sqlite.js"; import { DEFAULT_AGENT_ID } from "../routing/session-key.js"; import { withEnvAsync } from "../test-utils/env.js"; @@ -23,6 +24,10 @@ import { const { createSessionStoreDir, openClient } = setupGatewaySessionsTestHarness(); +function sqliteTranscript(sessionId: string, agentId = DEFAULT_AGENT_ID): string { + return createSqliteSessionTranscriptLocator({ agentId, sessionId }); +} + test("sessions.compaction.* lists checkpoints and branches or restores from pre-compaction snapshots", async () => { const { dir } = await createSessionStoreDir(); const fixture = await createCheckpointFixture(dir); @@ -212,10 +217,11 @@ test("sessions.compaction.* lists checkpoints and branches or restores from pre- test("sessions.compact without maxLines runs embedded manual compaction for checkpoint-capable flows", async () => { const { dir } = await createSessionStoreDir(); + const sessionFile = sqliteTranscript("sess-main"); replaceSqliteSessionTranscriptEvents({ agentId: DEFAULT_AGENT_ID, sessionId: "sess-main", - transcriptPath: path.join(dir, "sess-main.jsonl"), + transcriptPath: sessionFile, events: [ { type: "session", @@ -236,7 +242,7 @@ test("sessions.compact without maxLines runs embedded manual compaction for chec agentId: "main", sessionKey: "agent:main:main", entry: sessionStoreEntry("sess-main", { - sessionFile: path.join(dir, "sess-main.jsonl"), + sessionFile, thinkingLevel: "medium", reasoningLevel: "stream", }), @@ -260,7 +266,7 @@ test("sessions.compact without maxLines runs embedded manual compaction for chec expect.objectContaining({ sessionId: "sess-main", sessionKey: "agent:main:main", - sessionFile: expect.stringMatching(/sess-main\.jsonl$/), + sessionFile, config: expect.any(Object), provider: expect.any(String), model: expect.any(String), diff --git a/src/gateway/server.sessions.delete-lifecycle.test.ts b/src/gateway/server.sessions.delete-lifecycle.test.ts index 9db734f4e74..3f191bb2947 100644 --- a/src/gateway/server.sessions.delete-lifecycle.test.ts +++ b/src/gateway/server.sessions.delete-lifecycle.test.ts @@ -1,4 +1,3 @@ -import path from "node:path"; import { expect, test } from "vitest"; import { createSqliteSessionTranscriptLocator, getSessionEntry } from "../config/sessions.js"; import { replaceSqliteSessionTranscriptEvents } from "../config/sessions/transcript-store.sqlite.js"; @@ -20,6 +19,10 @@ import { const { createSessionStoreDir, openClient } = setupGatewaySessionsTestHarness(); +function sqliteTranscript(sessionId: string): string { + return createSqliteSessionTranscriptLocator({ agentId: "main", sessionId }); +} + test("sessions.delete rejects main and aborts active runs", async () => { const { dir } = await createSessionStoreDir(); await writeSingleLineSession(dir, "sess-main", "hello"); @@ -45,7 +48,7 @@ test("sessions.delete rejects main and aborts active runs", async () => { expect(deleted.payload?.deleted).toBe(true); expectActiveRunCleanup( "agent:main:discord:group:dev", - ["discord:group:dev", "agent:main:discord:group:dev", "sess-active"], + ["agent:main:discord:group:dev", "sess-active"], "sess-active", ); expect(bundleMcpRuntimeMocks.disposeSessionMcpRuntime).toHaveBeenCalledWith("sess-active"); @@ -171,7 +174,7 @@ test("sessions.delete closes ACP runtime handles before removing ACP sessions", test("sessions.delete emits session_end with deleted reason and no replacement", async () => { const { dir } = await createSessionStoreDir(); await writeSingleLineSession(dir, "sess-main", "hello"); - const transcriptPath = path.join(dir, "sess-delete.jsonl"); + const transcriptPath = sqliteTranscript("sess-delete"); replaceSqliteSessionTranscriptEvents({ agentId: "main", sessionId: "sess-delete", @@ -211,7 +214,7 @@ test("sessions.delete emits session_end with deleted reason and no replacement", reason: "deleted", }); expect((event as { sessionFile?: string } | undefined)?.sessionFile).toBe( - createSqliteSessionTranscriptLocator({ agentId: "main", sessionId: "sess-delete" }), + sqliteTranscript("sess-delete"), ); expect((event as { nextSessionId?: string } | undefined)?.nextSessionId).toBeUndefined(); expect(context).toMatchObject({ @@ -339,7 +342,7 @@ test("sessions.delete returns unavailable when active run does not stop", async expect(deleted.error?.message ?? "").toMatch(/still active/i); expectActiveRunCleanup( "agent:main:discord:group:dev", - ["discord:group:dev", "agent:main:discord:group:dev", "sess-active"], + ["agent:main:discord:group:dev", "sess-active"], "sess-active", ); expect(browserSessionTabMocks.closeTrackedBrowserTabsForSessions).not.toHaveBeenCalled(); diff --git a/src/gateway/server.sessions.reset-hooks.test.ts b/src/gateway/server.sessions.reset-hooks.test.ts index 5177808e627..88d2dcbab80 100644 --- a/src/gateway/server.sessions.reset-hooks.test.ts +++ b/src/gateway/server.sessions.reset-hooks.test.ts @@ -1,5 +1,3 @@ -import fs from "node:fs/promises"; -import path from "node:path"; import { expect, test } from "vitest"; import { createSqliteSessionTranscriptLocator, @@ -55,6 +53,10 @@ function expectMainHookContext(context: HookEventRecord, sessionId: string) { expect(context.sessionId).toBe(sessionId); } +function sqliteTranscript(sessionId: string): string { + return createSqliteSessionTranscriptLocator({ agentId: "main", sessionId }); +} + test("sessions.reset emits internal command hook with reason", async () => { const { dir } = await createSessionStoreDir(); await writeSingleLineSession(dir, "sess-main", "hello"); @@ -104,8 +106,8 @@ test("sessions.reset emits internal command hook with reason", async () => { }); test("sessions.reset emits before_reset hook with transcript context", async () => { - const { dir } = await createSessionStoreDir(); - const transcriptPath = path.join(dir, "sess-main.jsonl"); + await createSessionStoreDir(); + const transcriptPath = sqliteTranscript("sess-main"); replaceSqliteSessionTranscriptEvents({ agentId: "main", sessionId: "sess-main", @@ -147,8 +149,8 @@ test("sessions.reset emits before_reset hook with transcript context", async () }); test("sessions.reset emits before_reset hook with scoped SQLite transcript context", async () => { - const { dir } = await createSessionStoreDir(); - const transcriptPath = path.join(dir, "missing-sess-main.jsonl"); + await createSessionStoreDir(); + const transcriptPath = sqliteTranscript("sess-main-sqlite"); replaceSqliteSessionTranscriptEvents({ agentId: "main", sessionId: "sess-main-sqlite", @@ -201,8 +203,8 @@ test("sessions.reset emits before_reset hook with scoped SQLite transcript conte }); test("sessions.reset emits enriched session_end and session_start hooks", async () => { - const { dir } = await createSessionStoreDir(); - const transcriptPath = path.join(dir, "sess-main.jsonl"); + await createSessionStoreDir(); + const transcriptPath = sqliteTranscript("sess-main"); replaceSqliteSessionTranscriptEvents({ agentId: "main", sessionId: "sess-main", @@ -281,7 +283,7 @@ test("sessions.reset returns unavailable when active run does not stop", async ( expect(reset.ok).toBe(false); expect(reset.error?.code).toBe("UNAVAILABLE"); expect(reset.error?.message ?? "").toMatch(/still active/i); - expectActiveRunCleanup("agent:main:main", ["main", "agent:main:main", "sess-main"], "sess-main"); + expectActiveRunCleanup("agent:main:main", ["agent:main:main", "sess-main"], "sess-main"); expect(beforeResetHookMocks.runBeforeReset).not.toHaveBeenCalled(); expect(waitCallCountAtSnapshotClear).toEqual([1]); expect(browserSessionTabMocks.closeTrackedBrowserTabsForSessions).not.toHaveBeenCalled(); @@ -292,9 +294,9 @@ test("sessions.reset returns unavailable when active run does not stop", async ( }); test("sessions.reset emits before_reset for the entry actually reset in the SQLite patch", async () => { - const { dir } = await createSessionStoreDir(); - const oldTranscriptPath = path.join(dir, "sess-old.jsonl"); - const newTranscriptPath = path.join(dir, "sess-new.jsonl"); + await createSessionStoreDir(); + const oldTranscriptPath = sqliteTranscript("sess-old"); + const newTranscriptPath = sqliteTranscript("sess-new"); replaceSqliteSessionTranscriptEvents({ agentId: "main", sessionId: "sess-old", @@ -390,8 +392,8 @@ test("sessions.create with emitCommandHooks=true fires command:new hook against }); test("sessions.create with emitCommandHooks=true emits reset lifecycle hooks against parent (#76957)", async () => { - const { dir } = await createSessionStoreDir(); - const transcriptPath = path.join(dir, "sess-parent-hooks.jsonl"); + await createSessionStoreDir(); + const transcriptPath = sqliteTranscript("sess-parent-hooks"); replaceSqliteSessionTranscriptEvents({ agentId: "main", sessionId: "sess-parent-hooks", @@ -448,17 +450,20 @@ test("sessions.create with emitCommandHooks=true emits reset lifecycle hooks aga }); test("sessions.create with emitCommandHooks=true resets parent in place when session.dmScope is 'main' (#77434)", async () => { - const { dir } = await createSessionStoreDir(); - const transcriptPath = path.join(dir, "sess-parent-dms.jsonl"); - await fs.writeFile( + await createSessionStoreDir(); + const transcriptPath = sqliteTranscript("sess-parent-dms"); + replaceSqliteSessionTranscriptEvents({ + agentId: "main", + sessionId: "sess-parent-dms", transcriptPath, - `${JSON.stringify({ - type: "message", - id: "m1", - message: { role: "user", content: "hello before /new" }, - })}\n`, - "utf-8", - ); + events: [ + { + type: "message", + id: "m1", + message: { role: "user", content: "hello before /new" }, + }, + ], + }); testState.sessionConfig = { dmScope: "main" }; try {