test(sessions): close SQLite fixtures before cleanup (#113074)

This commit is contained in:
Peter Steinberger
2026-08-09 07:29:03 -07:00
committed by GitHub
parent 6680b0faac
commit e9250be4bb
5 changed files with 56 additions and 12 deletions
@@ -1,7 +1,9 @@
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { afterEach, beforeEach, describe, expect, it } from "vitest";
import { cleanupTempDirs, makeTempDir } from "../../../test/helpers/temp-dir.js";
import { closeOpenClawAgentDatabasesForTest } from "../../state/openclaw-agent-db.js";
import { closeOpenClawStateDatabaseForTest } from "../../state/openclaw-state-db.js";
import {
readAmbientTranscriptWatermark,
resolveAmbientTranscriptWatermarkKey,
@@ -9,6 +11,8 @@ import {
} from "./ambient-transcript-watermark.js";
import { loadSessionEntry, replaceSessionEntry } from "./session-accessor.js";
const tempDirs: string[] = [];
describe("ambient transcript watermark", () => {
let tempDir: string;
let storePath: string;
@@ -20,12 +24,14 @@ describe("ambient transcript watermark", () => {
});
beforeEach(() => {
tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-ambient-watermark-"));
tempDir = makeTempDir(tempDirs, "openclaw-ambient-watermark-");
storePath = path.join(tempDir, "sessions.json");
});
afterEach(() => {
fs.rmSync(tempDir, { recursive: true, force: true });
closeOpenClawAgentDatabasesForTest();
closeOpenClawStateDatabaseForTest();
cleanupTempDirs(tempDirs);
});
it("stamps and resolves the watermark for the current session id only", async () => {
@@ -1,6 +1,8 @@
import path from "node:path";
import { afterEach, beforeEach, describe, expect, it } from "vitest";
import { cleanupTempDirs, makeTempDir } from "../../../test/helpers/temp-dir.js";
import { closeOpenClawAgentDatabasesForTest } from "../../state/openclaw-agent-db.js";
import { closeOpenClawStateDatabaseForTest } from "../../state/openclaw-state-db.js";
import { resolveSessionEntryResetFreshness } from "./entry-freshness.js";
import { appendTranscriptEvent, upsertSessionEntry } from "./session-accessor.js";
@@ -18,6 +20,8 @@ describe("resolveSessionEntryResetFreshness", () => {
});
afterEach(() => {
closeOpenClawAgentDatabasesForTest();
closeOpenClawStateDatabaseForTest();
cleanupTempDirs(tempDirs);
});
+35 -3
View File
@@ -1,10 +1,10 @@
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { DatabaseSync } from "node:sqlite";
import { expectDefined } from "@openclaw/normalization-core";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { withTestTimeout } from "../../../test/helpers/promise.js";
import { cleanupTempDirs, makeTempDir } from "../../../test/helpers/temp-dir.js";
import type { MsgContext } from "../../auto-reply/templating.js";
import {
onInternalSessionTranscriptUpdate,
@@ -17,6 +17,10 @@ import {
openOpenClawAgentDatabase,
resolveOpenClawAgentSqlitePath,
} from "../../state/openclaw-agent-db.js";
import {
closeOpenClawStateDatabaseForTest,
isOpenClawStateDatabaseOpen,
} from "../../state/openclaw-state-db.js";
import { appendSqliteTrajectoryRuntimeEvents } from "../../trajectory/runtime-store.sqlite.js";
import type { TrajectoryEvent } from "../../trajectory/types.js";
import {
@@ -88,6 +92,7 @@ import { withOwnedSessionTranscriptWrites } from "./transcript-write-context.js"
import type { InternalSessionEntry, SessionEntry } from "./types.js";
const cleanupArchivedSessionTranscriptsMock = vi.hoisted(() => vi.fn(async () => {}));
const tempDirs: string[] = [];
vi.mock("../../gateway/session-archive.runtime.js", async (importOriginal) => {
const actual = await importOriginal<typeof import("../../gateway/session-archive.runtime.js")>();
@@ -127,6 +132,8 @@ describe("session accessor seam", () => {
let tempDir: string;
let storePath: string;
let transcriptPath: string;
let cleanupProbeDatabasePath = "";
let cleanupProbeRoot = "";
function loadMainInitializationSnapshot(sessionKey: string) {
return loadReplySessionInitializationSnapshot({ agentId: "main", sessionKey, storePath });
@@ -134,13 +141,38 @@ describe("session accessor seam", () => {
beforeEach(() => {
cleanupArchivedSessionTranscriptsMock.mockReset();
tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-session-accessor-"));
tempDir = makeTempDir(tempDirs, "openclaw-session-accessor-");
storePath = path.join(tempDir, "sessions.json");
transcriptPath = path.join(tempDir, "session.jsonl");
});
afterEach(() => {
fs.rmSync(tempDir, { recursive: true, force: true });
closeOpenClawAgentDatabasesForTest();
closeOpenClawStateDatabaseForTest();
cleanupTempDirs(tempDirs);
});
describe.sequential("session database teardown boundary", () => {
it("opens cached agent and shared-state handles", async () => {
await replaceSessionEntry(
{ agentId: "main", sessionKey: "agent:main:cleanup-probe", storePath },
{ sessionId: "cleanup-probe", updatedAt: 1 },
);
cleanupProbeDatabasePath = expectDefined(
resolveSqliteTargetFromSessionStorePath(storePath, { agentId: "main" }).path,
"cleanup probe database path",
);
cleanupProbeRoot = tempDir;
expect(isOpenClawAgentDatabaseOpen(cleanupProbeDatabasePath)).toBe(true);
expect(isOpenClawStateDatabaseOpen()).toBe(true);
});
it("releases both cache owners before the next test", () => {
expect(isOpenClawAgentDatabaseOpen(cleanupProbeDatabasePath)).toBe(false);
expect(isOpenClawStateDatabaseOpen()).toBe(false);
expect(fs.existsSync(cleanupProbeRoot)).toBe(false);
});
});
it("exposes the canonical SQLite session lifecycle owners", () => {
@@ -3,6 +3,8 @@ import fs from "node:fs/promises";
import path from "node:path";
import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { beginSessionWorkAdmission } from "../../sessions/session-lifecycle-admission.js";
import { closeOpenClawAgentDatabasesForTest } from "../../state/openclaw-agent-db.js";
import { closeOpenClawStateDatabaseForTest } from "../../state/openclaw-state-db.js";
import { createFixtureSuite } from "../../test-utils/fixture-suite.js";
import { readSessionArchiveContentSync } from "./archive-compression.js";
import { isRetainedSessionTranscriptArchiveName } from "./artifacts.js";
@@ -24,6 +26,8 @@ beforeAll(async () => {
});
afterAll(async () => {
closeOpenClawAgentDatabasesForTest();
closeOpenClawStateDatabaseForTest();
await fixtureSuite.cleanup();
});
+4 -6
View File
@@ -1,25 +1,23 @@
// Loads fixture suites from disk for parametrized tests.
import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { cleanupTempDirs, makeTempDir } from "../../test/helpers/temp-dir.js";
/** Creates a temp fixture root with deterministic per-case subdirectories. */
export function createFixtureSuite(rootPrefix: string) {
let fixtureRoot = "";
let fixtureCount = 0;
const fixtureRoots = new Set<string>();
return {
async setup(): Promise<void> {
// Canonicalize: macOS tmpdir sits behind a symlink (/var -> /private/var)
// and production realpaths state/session paths, so symlinked roots break
// path-equality assertions.
fixtureRoot = await fs.realpath(await fs.mkdtemp(path.join(os.tmpdir(), rootPrefix)));
fixtureRoot = makeTempDir(fixtureRoots, rootPrefix);
},
async cleanup(): Promise<void> {
if (!fixtureRoot) {
return;
}
await fs.rm(fixtureRoot, { recursive: true, force: true });
cleanupTempDirs(fixtureRoots);
fixtureRoot = "";
},
async createCaseDir(prefix: string): Promise<string> {