diff --git a/extensions/acpx/doctor-contract-api.test.ts b/extensions/acpx/doctor-contract-api.test.ts index ab76a8de02bd..b1d46bd7463f 100644 --- a/extensions/acpx/doctor-contract-api.test.ts +++ b/extensions/acpx/doctor-contract-api.test.ts @@ -12,6 +12,7 @@ import type { OpenKeyedStoreOptions, PluginDoctorStateMigrationContext, } from "openclaw/plugin-sdk/runtime-doctor-migrations"; +import { closeOpenClawStateDatabaseAsync } from "openclaw/plugin-sdk/sqlite-runtime-testing"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { legacyConfigRules, @@ -109,6 +110,7 @@ describe("acpx doctor state migration", () => { }); afterEach(async () => { + await closeOpenClawStateDatabaseAsync(); resetPluginStateStoreForTests(); await fs.rm(stateDir, { recursive: true, force: true }); }); diff --git a/extensions/active-memory/doctor-contract-api.test.ts b/extensions/active-memory/doctor-contract-api.test.ts index 566b7302dc5a..b836b012f47d 100644 --- a/extensions/active-memory/doctor-contract-api.test.ts +++ b/extensions/active-memory/doctor-contract-api.test.ts @@ -11,6 +11,7 @@ import type { OpenKeyedStoreOptions, PluginDoctorStateMigrationContext, } from "openclaw/plugin-sdk/runtime-doctor-migrations"; +import { closeOpenClawStateDatabaseAsync } from "openclaw/plugin-sdk/sqlite-runtime-testing"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { legacyConfigRules, @@ -65,6 +66,7 @@ describe("active-memory doctor state migration", () => { afterEach(async () => { vi.useRealTimers(); + await closeOpenClawStateDatabaseAsync(); resetPluginStateStoreForTests(); await fs.rm(stateDir, { recursive: true, force: true }); }); diff --git a/extensions/active-memory/index.test.ts b/extensions/active-memory/index.test.ts index 434346ea5892..d0147d757603 100644 --- a/extensions/active-memory/index.test.ts +++ b/extensions/active-memory/index.test.ts @@ -17,7 +17,10 @@ import { appendSessionTranscriptMessageByIdentity, type SessionTranscriptTargetParams, } from "openclaw/plugin-sdk/session-transcript-runtime"; -import { closeOpenClawAgentDatabasesForTest } from "openclaw/plugin-sdk/sqlite-runtime-testing"; +import { + closeOpenClawAgentDatabasesForTest, + closeOpenClawStateDatabaseAsync, +} from "openclaw/plugin-sdk/sqlite-runtime-testing"; import { afterAll, afterEach, @@ -756,6 +759,7 @@ describe("active-memory plugin", () => { afterAll(async () => { closeOpenClawAgentDatabasesForTest(); + await closeOpenClawStateDatabaseAsync(); resetPluginStateStoreForTests(); await fs.rm(fixtureRoot, { recursive: true, force: true }); fixtureRoot = ""; diff --git a/extensions/buzz/src/buzz-bus.socket.test.ts b/extensions/buzz/src/buzz-bus.socket.test.ts index efa3e58edbde..5e7867a14ffb 100644 --- a/extensions/buzz/src/buzz-bus.socket.test.ts +++ b/extensions/buzz/src/buzz-bus.socket.test.ts @@ -12,6 +12,7 @@ import { createPluginStateKeyedStoreForTests, resetPluginStateStoreForTests, } from "openclaw/plugin-sdk/plugin-state-test-runtime"; +import { closeOpenClawStateDatabaseAsync } from "openclaw/plugin-sdk/sqlite-runtime-testing"; import { afterEach, beforeEach, expect, it, vi } from "vitest"; import { startBuzzBus, type BuzzBus } from "./buzz-bus.js"; import { createBuzzRelayFixture } from "./buzz-relay.test-harness.js"; @@ -347,7 +348,8 @@ it("revokes the active bot immediately on a signed role downgrade", async () => await fixture.close(); } }); -afterEach(() => { +afterEach(async () => { + await closeOpenClawStateDatabaseAsync(); resetPluginStateStoreForTests(); vi.restoreAllMocks(); vi.unstubAllEnvs(); diff --git a/extensions/buzz/src/gateway.cold-start-recovery.test.ts b/extensions/buzz/src/gateway.cold-start-recovery.test.ts index 58fe82b51a76..1fa4d23f09af 100644 --- a/extensions/buzz/src/gateway.cold-start-recovery.test.ts +++ b/extensions/buzz/src/gateway.cold-start-recovery.test.ts @@ -8,6 +8,7 @@ import { createPluginStateKeyedStoreForTests, resetPluginStateStoreForTests, } from "openclaw/plugin-sdk/plugin-state-test-runtime"; +import { closeOpenClawStateDatabaseAsync } from "openclaw/plugin-sdk/sqlite-runtime-testing"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import type { ChannelGatewayContext } from "../runtime-api.js"; import type { BuzzInboundMessage } from "./message-event.js"; @@ -325,9 +326,10 @@ beforeEach(() => { ); }); -afterEach(() => { +afterEach(async () => { vi.restoreAllMocks(); vi.unstubAllGlobals(); + await closeOpenClawStateDatabaseAsync(); resetPluginStateStoreForTests(); if (previousStateDir === undefined) { delete process.env.OPENCLAW_STATE_DIR; diff --git a/extensions/device-pair/doctor-contract-api.test.ts b/extensions/device-pair/doctor-contract-api.test.ts index 8e78bd53a0d5..b391e181d4b7 100644 --- a/extensions/device-pair/doctor-contract-api.test.ts +++ b/extensions/device-pair/doctor-contract-api.test.ts @@ -11,6 +11,7 @@ import type { OpenKeyedStoreOptions, PluginDoctorStateMigrationContext, } from "openclaw/plugin-sdk/runtime-doctor-migrations"; +import { closeOpenClawStateDatabaseAsync } from "openclaw/plugin-sdk/sqlite-runtime-testing"; import { afterEach, beforeEach, describe, expect, it } from "vitest"; import { stateMigrations } from "./doctor-contract-api.js"; import { @@ -43,6 +44,7 @@ describe("device-pair doctor notify migration", () => { }); afterEach(async () => { + await closeOpenClawStateDatabaseAsync(); resetPluginStateStoreForTests(); await fs.rm(stateDir, { recursive: true, force: true }); }); diff --git a/extensions/discord/src/monitor/model-picker-preferences.test.ts b/extensions/discord/src/monitor/model-picker-preferences.test.ts index cda91cf7b09c..c019a1cd738b 100644 --- a/extensions/discord/src/monitor/model-picker-preferences.test.ts +++ b/extensions/discord/src/monitor/model-picker-preferences.test.ts @@ -7,6 +7,7 @@ import { createPluginStateKeyedStoreForTests, resetPluginStateStoreForTests, } from "openclaw/plugin-sdk/plugin-state-test-runtime"; +import { closeOpenClawStateDatabaseAsync } from "openclaw/plugin-sdk/sqlite-runtime-testing"; import { afterEach, describe, expect, it, vi } from "vitest"; import { setDiscordRuntime } from "../runtime.js"; import { @@ -35,6 +36,7 @@ async function createStateEnv(): Promise { } afterEach(async () => { + await closeOpenClawStateDatabaseAsync(); resetPluginStateStoreForTests(); await Promise.all( tempDirs.splice(0).map(async (dir) => { diff --git a/extensions/imessage/src/state-migrations.test.ts b/extensions/imessage/src/state-migrations.test.ts index 80576c0f2aeb..7beabfcf825d 100644 --- a/extensions/imessage/src/state-migrations.test.ts +++ b/extensions/imessage/src/state-migrations.test.ts @@ -3,11 +3,11 @@ import { createHash } from "node:crypto"; import fs from "node:fs"; import path from "node:path"; import { - closeOpenClawStateDatabaseForTest, createPluginStateKeyedStoreForTests, resetPluginStateStoreForTests, } from "openclaw/plugin-sdk/plugin-state-test-runtime"; import { buildLegacyMigrationPreview } from "openclaw/plugin-sdk/runtime-doctor-migrations"; +import { closeOpenClawStateDatabaseAsync } from "openclaw/plugin-sdk/sqlite-runtime-testing"; import { resolvePreferredOpenClawTmpDir, tempWorkspaceSync, @@ -28,8 +28,8 @@ describe("detectIMessageLegacyStateMigrations", () => { }); }); - afterEach(() => { - closeOpenClawStateDatabaseForTest(); + afterEach(async () => { + await closeOpenClawStateDatabaseAsync(); resetPluginStateStoreForTests(); stateWorkspace.cleanup(); vi.doUnmock("./runtime.js"); diff --git a/extensions/matrix/src/matrix/client/file-sync-store.test.ts b/extensions/matrix/src/matrix/client/file-sync-store.test.ts index a9762601c028..37ed9805cfb0 100644 --- a/extensions/matrix/src/matrix/client/file-sync-store.test.ts +++ b/extensions/matrix/src/matrix/client/file-sync-store.test.ts @@ -9,6 +9,7 @@ import { createPluginStateSyncKeyedStoreForTests, resetPluginStateStoreForTests, } from "openclaw/plugin-sdk/plugin-state-test-runtime"; +import { closeOpenClawStateDatabaseAsync } from "openclaw/plugin-sdk/sqlite-runtime-testing"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { getMatrixRuntime } from "../../runtime.js"; import { installMatrixTestRuntime } from "../../test-runtime.js"; @@ -80,13 +81,14 @@ describe("SqliteBackedMatrixSyncStore", () => { installMatrixTestRuntime(); }); - afterEach(() => { + afterEach(async () => { vi.restoreAllMocks(); vi.useRealTimers(); + await closeOpenClawStateDatabaseAsync(); + resetPluginStateStoreForTests(); for (const dir of tempDirs.splice(0)) { fs.rmSync(dir, { recursive: true, force: true }); } - resetPluginStateStoreForTests(); }); it("persists sync data so restart resumes from the saved cursor", async () => { diff --git a/extensions/matrix/src/matrix/client/storage.test.ts b/extensions/matrix/src/matrix/client/storage.test.ts index 6b5c0d679767..decd612f7f02 100644 --- a/extensions/matrix/src/matrix/client/storage.test.ts +++ b/extensions/matrix/src/matrix/client/storage.test.ts @@ -6,6 +6,7 @@ import { createPluginStateSyncKeyedStoreForTests, resetPluginStateStoreForTests, } from "openclaw/plugin-sdk/plugin-state-test-runtime"; +import { closeOpenClawStateDatabaseAsync } from "openclaw/plugin-sdk/sqlite-runtime-testing"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { resolveMatrixAccountStorageRoot } from "../../storage-paths.js"; import { installMatrixTestRuntime } from "../../test-runtime.js"; @@ -38,8 +39,9 @@ describe("matrix client storage paths", () => { resetPluginStateStoreForTests(); }); - afterEach(() => { + afterEach(async () => { vi.restoreAllMocks(); + await closeOpenClawStateDatabaseAsync(); resetPluginStateStoreForTests(); for (const dir of tempDirs.splice(0)) { fs.rmSync(dir, { recursive: true, force: true }); @@ -437,6 +439,7 @@ describe("matrix client storage paths", () => { "synthetic migration archive denied", ); rename.mockRestore(); + await closeOpenClawStateDatabaseAsync(); resetPluginStateStoreForTests(); const expectPreservedState = () => { @@ -476,6 +479,7 @@ describe("matrix client storage paths", () => { resetPluginStateStoreForTests(); await maybeMigrateLegacyStorage({ storagePaths, env }); + await closeOpenClawStateDatabaseAsync(); resetPluginStateStoreForTests(); expectPreservedState(); diff --git a/extensions/matrix/src/matrix/sdk/idb-persistence.test.ts b/extensions/matrix/src/matrix/sdk/idb-persistence.test.ts index 34258703808c..940ab4b3efd6 100644 --- a/extensions/matrix/src/matrix/sdk/idb-persistence.test.ts +++ b/extensions/matrix/src/matrix/sdk/idb-persistence.test.ts @@ -10,6 +10,7 @@ import { openOpenClawStateDatabase, resetPluginStateStoreForTests, } from "openclaw/plugin-sdk/plugin-state-test-runtime"; +import { closeOpenClawStateDatabaseAsync } from "openclaw/plugin-sdk/sqlite-runtime-testing"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { getMatrixRuntime } from "../../runtime.js"; import { installMatrixTestRuntime } from "../../test-runtime.js"; @@ -53,6 +54,7 @@ describe("Matrix IndexedDB persistence", () => { afterEach(async () => { warnSpy.mockRestore(); await clearTestIndexedDbState(); + await closeOpenClawStateDatabaseAsync(); resetFileLockStateForTest(); resetPluginStateStoreForTests(); fs.rmSync(tmpDir, { recursive: true, force: true }); diff --git a/extensions/memory-core/src/cli.test.ts b/extensions/memory-core/src/cli.test.ts index dfef59d31c28..50121a8b7d36 100644 --- a/extensions/memory-core/src/cli.test.ts +++ b/extensions/memory-core/src/cli.test.ts @@ -16,6 +16,7 @@ import { appendSessionTranscriptMessageByIdentity } from "openclaw/plugin-sdk/se import { resolveOpenClawAgentSqlitePath } from "openclaw/plugin-sdk/sqlite-runtime"; import { closeOpenClawAgentDatabasesForTest, + closeOpenClawStateDatabaseAsync, openOpenClawAgentDatabase, } from "openclaw/plugin-sdk/sqlite-runtime-testing"; import { @@ -187,6 +188,7 @@ afterAll(async () => { // The agent close releases its leases through shared state and reopens it, so the // shared handle is released second; otherwise Windows fails the removal with EBUSY. closeOpenClawAgentDatabasesForTest(); + await closeOpenClawStateDatabaseAsync(); resetPluginStateStoreForTests(); await fs.rm(fixtureRoot, { recursive: true, force: true }); resetMemoryCoreDreamingStateForTests(); diff --git a/extensions/memory-core/src/dreaming-state.test.ts b/extensions/memory-core/src/dreaming-state.test.ts index f4e8648c1bd4..c84d2562b14c 100644 --- a/extensions/memory-core/src/dreaming-state.test.ts +++ b/extensions/memory-core/src/dreaming-state.test.ts @@ -6,6 +6,7 @@ import { openOpenClawStateDatabase, resetPluginStateStoreForTests, } from "openclaw/plugin-sdk/plugin-state-test-runtime"; +import { closeOpenClawStateDatabaseAsync } from "openclaw/plugin-sdk/sqlite-runtime-testing"; import { useAutoCleanupTempDirTracker } from "openclaw/plugin-sdk/test-env"; import { afterEach, expect, test } from "vitest"; import { @@ -17,10 +18,11 @@ import { } from "./dreaming-state.js"; const tempDirs = useAutoCleanupTempDirTracker((cleanup) => - afterEach(() => { + afterEach(async () => { configureMemoryCoreDreamingState(() => { throw new Error("memory workspace test store is closed"); }); + await closeOpenClawStateDatabaseAsync(); resetPluginStateStoreForTests(); cleanup(); }), diff --git a/extensions/memory-core/src/memory-forget-consolidation.test.ts b/extensions/memory-core/src/memory-forget-consolidation.test.ts index 1b3abb47db2d..2d5e8e7621a8 100644 --- a/extensions/memory-core/src/memory-forget-consolidation.test.ts +++ b/extensions/memory-core/src/memory-forget-consolidation.test.ts @@ -7,6 +7,7 @@ import { upsertSessionEntry } from "openclaw/plugin-sdk/session-store-runtime"; import { openOpenClawAgentDatabase } from "openclaw/plugin-sdk/sqlite-runtime"; import { closeOpenClawAgentDatabasesForTest, + closeOpenClawStateDatabaseAsync, closeOpenClawStateDatabaseForTest, } from "openclaw/plugin-sdk/sqlite-runtime-testing"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; @@ -44,6 +45,7 @@ describe("memory forget", () => { afterEach(async () => { closeOpenClawAgentDatabasesForTest(); + await closeOpenClawStateDatabaseAsync(); closeOpenClawStateDatabaseForTest(); resetPluginStateStoreForTests(); vi.unstubAllEnvs(); diff --git a/extensions/memory-core/src/memory/manager.fts-only-reindex.test.ts b/extensions/memory-core/src/memory/manager.fts-only-reindex.test.ts index 79cb5a3fd673..f21a0327c549 100644 --- a/extensions/memory-core/src/memory/manager.fts-only-reindex.test.ts +++ b/extensions/memory-core/src/memory/manager.fts-only-reindex.test.ts @@ -6,7 +6,10 @@ import { DatabaseSync } from "node:sqlite"; import type { OpenClawConfig } from "openclaw/plugin-sdk/memory-core-host-engine-foundation"; import { resetPluginStateStoreForTests } from "openclaw/plugin-sdk/plugin-state-test-runtime"; import { resolveOpenClawAgentSqlitePath } from "openclaw/plugin-sdk/sqlite-runtime"; -import { closeOpenClawAgentDatabasesForTest } from "openclaw/plugin-sdk/sqlite-runtime-testing"; +import { + closeOpenClawAgentDatabasesForTest, + closeOpenClawStateDatabaseAsync, +} from "openclaw/plugin-sdk/sqlite-runtime-testing"; import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import { closeAllMemorySearchManagers, getMemorySearchManager } from "./index.js"; import type { MemoryIndexMeta } from "./manager-reindex-state.js"; @@ -112,6 +115,7 @@ describe("memory manager FTS-only reindex", () => { // The agent close releases its leases through shared state and reopens it, so the // shared handle is released second; otherwise Windows fails the removal with EBUSY. closeOpenClawAgentDatabasesForTest(); + await closeOpenClawStateDatabaseAsync(); resetPluginStateStoreForTests(); if (fixtureRoot) { await fs.rm(fixtureRoot, { recursive: true, force: true }); diff --git a/extensions/memory-core/src/memory/manager.reindex-recovery.test.ts b/extensions/memory-core/src/memory/manager.reindex-recovery.test.ts index 35b712a640dc..8e740fbb6162 100644 --- a/extensions/memory-core/src/memory/manager.reindex-recovery.test.ts +++ b/extensions/memory-core/src/memory/manager.reindex-recovery.test.ts @@ -12,7 +12,10 @@ import { upsertSessionEntry } from "openclaw/plugin-sdk/session-store-runtime"; import { withSessionTranscriptWriteLock } from "openclaw/plugin-sdk/session-transcript-runtime"; import { resolveOpenClawAgentSqlitePath } from "openclaw/plugin-sdk/sqlite-runtime"; import * as sqliteRuntime from "openclaw/plugin-sdk/sqlite-runtime"; -import { closeOpenClawAgentDatabasesForTest } from "openclaw/plugin-sdk/sqlite-runtime-testing"; +import { + closeOpenClawAgentDatabasesForTest, + closeOpenClawStateDatabaseAsync, +} from "openclaw/plugin-sdk/sqlite-runtime-testing"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import "./test-runtime-mocks.js"; import { recordMemorySessionTombstones } from "../memory-entry-origins.js"; @@ -112,6 +115,7 @@ describe("memory manager reindex recovery", () => { // The agent close releases its leases through shared state and reopens it, so the // shared handle is released second; otherwise Windows fails the removal with EBUSY. closeOpenClawAgentDatabasesForTest(); + await closeOpenClawStateDatabaseAsync(); resetPluginStateStoreForTests(); await fs.rm(fixtureRoot, { recursive: true, force: true }); }); diff --git a/extensions/memory-core/src/memory/manager.self-heal-missing-identity.test.ts b/extensions/memory-core/src/memory/manager.self-heal-missing-identity.test.ts index 00feafd02e62..55e264648c32 100644 --- a/extensions/memory-core/src/memory/manager.self-heal-missing-identity.test.ts +++ b/extensions/memory-core/src/memory/manager.self-heal-missing-identity.test.ts @@ -5,6 +5,7 @@ import type { OpenClawConfig } from "openclaw/plugin-sdk/memory-core-host-engine import { resetPluginStateStoreForTests } from "openclaw/plugin-sdk/plugin-state-test-runtime"; import { closeOpenClawAgentDatabasesForTest, + closeOpenClawStateDatabaseAsync, openOpenClawAgentDatabase, } from "openclaw/plugin-sdk/sqlite-runtime-testing"; import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; @@ -81,6 +82,7 @@ describe("memory manager self-heal missing identity with FTS-only chunks", () => // The agent close releases its leases through shared state and reopens it, so the // shared handle is released second; otherwise Windows fails the removal with EBUSY. closeOpenClawAgentDatabasesForTest(); + await closeOpenClawStateDatabaseAsync(); resetPluginStateStoreForTests(); if (fixtureRoot) { await fs.rm(fixtureRoot, { recursive: true, force: true }); diff --git a/extensions/msteams/doctor-contract-api.retention.test.ts b/extensions/msteams/doctor-contract-api.retention.test.ts index 7220795dd771..ae12acfd7bf0 100644 --- a/extensions/msteams/doctor-contract-api.retention.test.ts +++ b/extensions/msteams/doctor-contract-api.retention.test.ts @@ -11,6 +11,7 @@ import { setMaxPluginStateEntriesPerPluginForTests, } from "openclaw/plugin-sdk/plugin-state-test-runtime"; import type { PluginDoctorStateMigrationContext } from "openclaw/plugin-sdk/runtime-doctor-migrations"; +import { closeOpenClawStateDatabaseAsync } from "openclaw/plugin-sdk/sqlite-runtime-testing"; import { afterEach, beforeEach, describe, expect, it } from "vitest"; import { stateMigrations } from "./doctor-contract-api.js"; import { @@ -56,6 +57,7 @@ describe("Teams custom migration retention", () => { }); afterEach(async () => { + await closeOpenClawStateDatabaseAsync(); setMaxPluginStateEntriesPerPluginForTests(); resetPluginStateStoreForTests(); await fs.rm(stateDir, { recursive: true, force: true }); diff --git a/extensions/msteams/doctor-contract-api.test.ts b/extensions/msteams/doctor-contract-api.test.ts index 9ca4d6bd18b0..868de10aa592 100644 --- a/extensions/msteams/doctor-contract-api.test.ts +++ b/extensions/msteams/doctor-contract-api.test.ts @@ -14,6 +14,7 @@ import type { PluginDoctorStateMigrationContext, PluginStateKeyedStore, } from "openclaw/plugin-sdk/runtime-doctor-migrations"; +import { closeOpenClawStateDatabaseAsync } from "openclaw/plugin-sdk/sqlite-runtime-testing"; import { afterEach, beforeEach, describe, expect, it } from "vitest"; import { legacyConfigRules, @@ -90,6 +91,7 @@ describe("msteams doctor state migration", () => { }); afterEach(async () => { + await closeOpenClawStateDatabaseAsync(); resetPluginStateStoreForTests(); await fs.rm(stateDir, { recursive: true, force: true }); }); diff --git a/extensions/msteams/src/conversation-store-state.test.ts b/extensions/msteams/src/conversation-store-state.test.ts index e3bf93301414..37fdfaf174be 100644 --- a/extensions/msteams/src/conversation-store-state.test.ts +++ b/extensions/msteams/src/conversation-store-state.test.ts @@ -6,6 +6,7 @@ import { createPluginStateKeyedStoreForTests, resetPluginStateStoreForTests, } from "openclaw/plugin-sdk/plugin-state-test-runtime"; +import { closeOpenClawStateDatabaseAsync } from "openclaw/plugin-sdk/sqlite-runtime-testing"; import { useAutoCleanupTempDirTracker } from "openclaw/plugin-sdk/test-env"; import { afterAll, beforeEach, describe, expect, it } from "vitest"; import { createMSTeamsConversationStoreState } from "./conversation-store-state.js"; @@ -14,7 +15,8 @@ import { setMSTeamsRuntime } from "./runtime.js"; import { msteamsRuntimeStub } from "./test-support/runtime.js"; const tempDirs = useAutoCleanupTempDirTracker((cleanup) => - afterAll(() => { + afterAll(async () => { + await closeOpenClawStateDatabaseAsync(); resetPluginStateStoreForTests(); cleanup(); }), diff --git a/extensions/msteams/src/conversation-store.shared.test.ts b/extensions/msteams/src/conversation-store.shared.test.ts index 33be95030c46..35e79e644f3d 100644 --- a/extensions/msteams/src/conversation-store.shared.test.ts +++ b/extensions/msteams/src/conversation-store.shared.test.ts @@ -1,5 +1,6 @@ // Msteams tests cover conversation store.shared plugin behavior. import { resetPluginStateStoreForTests } from "openclaw/plugin-sdk/plugin-state-test-runtime"; +import { closeOpenClawStateDatabaseAsync } from "openclaw/plugin-sdk/sqlite-runtime-testing"; import { useAutoCleanupTempDirTracker } from "openclaw/plugin-sdk/test-env"; import { afterAll, beforeEach, describe, expect, it, vi } from "vitest"; import { createMSTeamsConversationStoreState } from "./conversation-store-state.js"; @@ -7,7 +8,8 @@ import { setMSTeamsRuntime } from "./runtime.js"; import { msteamsRuntimeStub } from "./test-support/runtime.js"; const tempDirs = useAutoCleanupTempDirTracker((cleanup) => - afterAll(() => { + afterAll(async () => { + await closeOpenClawStateDatabaseAsync(); resetPluginStateStoreForTests(); cleanup(); }), diff --git a/extensions/msteams/src/polls.test.ts b/extensions/msteams/src/polls.test.ts index c5edaad77813..017f8a3acfc6 100644 --- a/extensions/msteams/src/polls.test.ts +++ b/extensions/msteams/src/polls.test.ts @@ -7,6 +7,7 @@ import { createPluginStateKeyedStoreForTests, resetPluginStateStoreForTests, } from "openclaw/plugin-sdk/plugin-state-test-runtime"; +import { closeOpenClawStateDatabaseAsync } from "openclaw/plugin-sdk/sqlite-runtime-testing"; import { useAutoCleanupTempDirTracker } from "openclaw/plugin-sdk/test-env"; import { afterAll, beforeEach, describe, expect, it, vi } from "vitest"; import { @@ -19,7 +20,8 @@ import { setMSTeamsRuntime } from "./runtime.js"; import { msteamsRuntimeStub } from "./test-support/runtime.js"; const tempDirs = useAutoCleanupTempDirTracker((cleanup) => - afterAll(() => { + afterAll(async () => { + await closeOpenClawStateDatabaseAsync(); resetPluginStateStoreForTests(); cleanup(); }), diff --git a/extensions/msteams/src/sso-token-store.test.ts b/extensions/msteams/src/sso-token-store.test.ts index 94aacab40e1d..4b14d433a424 100644 --- a/extensions/msteams/src/sso-token-store.test.ts +++ b/extensions/msteams/src/sso-token-store.test.ts @@ -2,6 +2,7 @@ import fs from "node:fs/promises"; import path from "node:path"; import { resetPluginStateStoreForTests } from "openclaw/plugin-sdk/plugin-state-test-runtime"; +import { closeOpenClawStateDatabaseAsync } from "openclaw/plugin-sdk/sqlite-runtime-testing"; import { useAutoCleanupTempDirTracker } from "openclaw/plugin-sdk/test-env"; import { afterAll, beforeEach, describe, expect, it } from "vitest"; import { setMSTeamsRuntime } from "./runtime.js"; @@ -9,7 +10,8 @@ import { createMSTeamsSsoTokenStoreFs } from "./sso-token-store.js"; import { msteamsRuntimeStub } from "./test-support/runtime.js"; const tempDirs = useAutoCleanupTempDirTracker((cleanup) => - afterAll(() => { + afterAll(async () => { + await closeOpenClawStateDatabaseAsync(); resetPluginStateStoreForTests(); cleanup(); }), diff --git a/extensions/nostr/doctor-contract-api.test.ts b/extensions/nostr/doctor-contract-api.test.ts index 751a10080e85..382975e36211 100644 --- a/extensions/nostr/doctor-contract-api.test.ts +++ b/extensions/nostr/doctor-contract-api.test.ts @@ -11,6 +11,7 @@ import type { OpenKeyedStoreOptions, PluginDoctorStateMigrationContext, } from "openclaw/plugin-sdk/runtime-doctor-migrations"; +import { closeOpenClawStateDatabaseAsync } from "openclaw/plugin-sdk/sqlite-runtime-testing"; import { afterEach, beforeEach, describe, expect, it } from "vitest"; import { stateMigrations } from "./doctor-contract-api.js"; @@ -40,6 +41,7 @@ describe("nostr doctor state migration", () => { }); afterEach(async () => { + await closeOpenClawStateDatabaseAsync(); resetPluginStateStoreForTests(); await fs.rm(stateDir, { recursive: true, force: true }); }); diff --git a/extensions/nostr/src/nostr-state-store.test.ts b/extensions/nostr/src/nostr-state-store.test.ts index 313bd71be333..e58d0e1408ef 100644 --- a/extensions/nostr/src/nostr-state-store.test.ts +++ b/extensions/nostr/src/nostr-state-store.test.ts @@ -7,6 +7,7 @@ import { createPluginStateKeyedStoreForTests, resetPluginStateStoreForTests, } from "openclaw/plugin-sdk/plugin-state-test-runtime"; +import { closeOpenClawStateDatabaseAsync } from "openclaw/plugin-sdk/sqlite-runtime-testing"; import { describe, expect, it } from "vitest"; import type { PluginRuntime } from "../runtime-api.js"; import { @@ -51,6 +52,7 @@ async function withTempStateDir(fn: (dir: string) => Promise) { } // The keyed store keeps the state database open under the temporary dir, so Windows // fails the removal with EBUSY unless the cached handle is released first. + await closeOpenClawStateDatabaseAsync(); resetPluginStateStoreForTests(); await fs.rm(dir, { recursive: true, force: true }); } diff --git a/extensions/qa-lab/src/test-file-scenario-runner.coverage.test.ts b/extensions/qa-lab/src/test-file-scenario-runner.coverage.test.ts index 97be4c3ca142..5cabb1a9c2a6 100644 --- a/extensions/qa-lab/src/test-file-scenario-runner.coverage.test.ts +++ b/extensions/qa-lab/src/test-file-scenario-runner.coverage.test.ts @@ -224,6 +224,8 @@ describe.skipIf(process.platform === "win32")("onboarding assertion attribution" expect(written.entries).toEqual(result.evidence.entries); expect(written.evidenceMode).toBe(evidenceMode); + const docsRoot = path.join(tempRoot, "docs"); + await fs.mkdir(docsRoot); const taxonomyPath = path.join(tempRoot, "taxonomy.json"); const scoresPath = path.join(tempRoot, "scores.json"); const surface = { id: "cli", name: "CLI", family: "core", level: "experimental" }; @@ -280,6 +282,8 @@ describe.skipIf(process.platform === "win32")("onboarding assertion attribution" "--import", "tsx", "scripts/qa/render-maturity-docs.ts", + "--docs-root", + docsRoot, "--taxonomy", taxonomyPath, "--scores", diff --git a/extensions/reef/doctor-contract-api.test.ts b/extensions/reef/doctor-contract-api.test.ts index 318f68b86630..a76d347f7813 100644 --- a/extensions/reef/doctor-contract-api.test.ts +++ b/extensions/reef/doctor-contract-api.test.ts @@ -12,6 +12,7 @@ import type { OpenKeyedStoreOptions, PluginDoctorStateMigrationContext, } from "openclaw/plugin-sdk/runtime-doctor-migrations"; +import { closeOpenClawStateDatabaseAsync } from "openclaw/plugin-sdk/sqlite-runtime-testing"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { legacyConfigRules, @@ -144,8 +145,9 @@ describe("Reef doctor contract", () => { env = { ...process.env, OPENCLAW_STATE_DIR: stateDir }; }); - afterEach(() => { + afterEach(async () => { vi.restoreAllMocks(); + await closeOpenClawStateDatabaseAsync(); resetPluginStateStoreForTests(); fs.rmSync(stateDir, { recursive: true, force: true }); }); diff --git a/extensions/telegram/src/bot.create-telegram-bot.test.ts b/extensions/telegram/src/bot.create-telegram-bot.test.ts index 6645dfc664a5..59dc18f03ab5 100644 --- a/extensions/telegram/src/bot.create-telegram-bot.test.ts +++ b/extensions/telegram/src/bot.create-telegram-bot.test.ts @@ -23,6 +23,7 @@ import { clearRuntimeConfigSnapshot, setRuntimeConfigSnapshot, } from "openclaw/plugin-sdk/runtime-config-snapshot"; +import { closeOpenClawStateDatabaseAsync } from "openclaw/plugin-sdk/sqlite-runtime-testing"; import { withEnvAsync } from "openclaw/plugin-sdk/test-env"; import { createRequireRecord, sanitizeTerminalText } from "openclaw/plugin-sdk/test-fixtures"; import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; @@ -479,7 +480,8 @@ describe("createTelegramBot", () => { process.env.TZ = ORIGINAL_TZ; } }); - afterEach(() => { + afterEach(async () => { + await closeOpenClawStateDatabaseAsync(); pluginStateTestRuntime.resetPluginStateStoreForTests(); clearPluginInteractiveHandlers(); if (previousStateDir === undefined) { diff --git a/extensions/telegram/src/send.test.ts b/extensions/telegram/src/send.test.ts index 243700af7cc8..436432d26d06 100644 --- a/extensions/telegram/src/send.test.ts +++ b/extensions/telegram/src/send.test.ts @@ -9,6 +9,7 @@ import { createPluginStateSyncKeyedStoreForTests, resetPluginStateStoreForTests, } from "openclaw/plugin-sdk/plugin-state-test-runtime"; +import { closeOpenClawStateDatabaseAsync } from "openclaw/plugin-sdk/sqlite-runtime-testing"; import { createRequireRecord, importFreshModule } from "openclaw/plugin-sdk/test-fixtures"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { markdownToTelegramHtml, telegramHtmlToPlainTextFallback } from "./format.js"; @@ -517,9 +518,10 @@ async function capturedLogText(logFile: string): Promise { return content; } -afterEach(() => { +afterEach(async () => { resetTelegramSentMessageCacheForTest(); clearTelegramRuntime(); + await closeOpenClawStateDatabaseAsync(); resetPluginStateStoreForTests(); setLoggerOverride(null); resetLogger(); diff --git a/extensions/telegram/src/telegram-ingress-callback.integration.test.ts b/extensions/telegram/src/telegram-ingress-callback.integration.test.ts index d4a1da21e16b..39fd4bf80306 100644 --- a/extensions/telegram/src/telegram-ingress-callback.integration.test.ts +++ b/extensions/telegram/src/telegram-ingress-callback.integration.test.ts @@ -14,6 +14,7 @@ import { resetPluginStateStoreForTests, } from "openclaw/plugin-sdk/plugin-state-test-runtime"; import type { MsgContext } from "openclaw/plugin-sdk/reply-runtime"; +import { closeOpenClawStateDatabaseAsync } from "openclaw/plugin-sdk/sqlite-runtime-testing"; import { expect, it, vi } from "vitest"; import { defaultTelegramBotDeps } from "./bot-deps.js"; import { telegramBotInfoForTest } from "./bot.create-telegram-bot.test-support.js"; @@ -270,6 +271,7 @@ it.each(["none", "middleware", "handler"] as const)( }); clearTelegramRuntimeForTest(); resetTelegramAccountThrottlersForTest(); + await closeOpenClawStateDatabaseAsync(); closeOpenClawStateDatabaseForTest(); resetPluginStateStoreForTests({ closeDatabase: false }); if (previousStateDir === undefined) { diff --git a/extensions/telegram/src/telegram-ingress-spool.test.ts b/extensions/telegram/src/telegram-ingress-spool.test.ts index e86bd9478463..d8e3e636bed2 100644 --- a/extensions/telegram/src/telegram-ingress-spool.test.ts +++ b/extensions/telegram/src/telegram-ingress-spool.test.ts @@ -9,6 +9,7 @@ import { createPluginStateKeyedStoreForTests, createPluginStateSyncKeyedStoreForTests, } from "openclaw/plugin-sdk/plugin-state-test-runtime"; +import { closeOpenClawStateDatabaseAsync } from "openclaw/plugin-sdk/sqlite-runtime-testing"; import { afterEach, describe, expect, it, vi } from "vitest"; import { beginTelegramPollRegistration } from "./poll-answer-context.js"; import { recordTelegramPollRegistryEntry } from "./poll-registry.js"; @@ -54,13 +55,15 @@ async function withTempState( return await fn(stateDir, spoolDir); } finally { clearTelegramRuntimeForTest(); + await closeOpenClawStateDatabaseAsync(); closeOpenClawStateDatabaseForTest(); await fs.rm(stateDir, { recursive: true, force: true }); } } -afterEach(() => { +afterEach(async () => { clearTelegramRuntimeForTest(); + await closeOpenClawStateDatabaseAsync(); closeOpenClawStateDatabaseForTest(); }); diff --git a/extensions/visitor-access/index.test.ts b/extensions/visitor-access/index.test.ts index cf914eac40ca..4ab8d70bb9e0 100644 --- a/extensions/visitor-access/index.test.ts +++ b/extensions/visitor-access/index.test.ts @@ -14,6 +14,7 @@ import { resetPluginStateStoreForTests, } from "openclaw/plugin-sdk/plugin-state-test-runtime"; import { createTestPluginApi } from "openclaw/plugin-sdk/plugin-test-api"; +import { closeOpenClawStateDatabaseAsync } from "openclaw/plugin-sdk/sqlite-runtime-testing"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import plugin from "./index.js"; import type { VisitorGrant } from "./src/visitors.js"; @@ -79,6 +80,7 @@ describe("visitor-access plugin lifecycle", () => { for (const cleanup of cleanups.splice(0)) { await cleanup(); } + await closeOpenClawStateDatabaseAsync(); resetPluginStateStoreForTests(); vi.useRealTimers(); vi.unstubAllGlobals(); diff --git a/extensions/voice-call/doctor-contract-api.test.ts b/extensions/voice-call/doctor-contract-api.test.ts index 10cf69eaa751..bb5af7be5d56 100644 --- a/extensions/voice-call/doctor-contract-api.test.ts +++ b/extensions/voice-call/doctor-contract-api.test.ts @@ -13,6 +13,7 @@ import type { OpenKeyedStoreOptions, PluginDoctorStateMigrationContext, } from "openclaw/plugin-sdk/runtime-doctor-migrations"; +import { closeOpenClawStateDatabaseAsync } from "openclaw/plugin-sdk/sqlite-runtime-testing"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import { resolveSessionStoreAgentIds, stateMigrations } from "./doctor-contract-api.js"; import { @@ -146,6 +147,7 @@ describe("voice-call doctor state migration", () => { historyCallIds: history.map((entry) => entry.callId), }; } finally { + await closeOpenClawStateDatabaseAsync(); resetPluginStateStoreForTests(); await fs.rm(warmStateDir, { recursive: true, force: true }); await fs.rm(warmStorePath, { recursive: true, force: true }); @@ -161,6 +163,7 @@ describe("voice-call doctor state migration", () => { }); afterEach(async () => { + await closeOpenClawStateDatabaseAsync(); resetPluginStateStoreForTests(); await fs.rm(stateDir, { recursive: true, force: true }); await fs.rm(storePath, { recursive: true, force: true }); @@ -467,6 +470,7 @@ describe("voice-call doctor state migration", () => { chunk_index: index, })), ); + await closeOpenClawStateDatabaseAsync(); resetPluginStateStoreForTests(); await expect(getCallHistoryFromStore(storePath)).resolves.toEqual([]); const retried = await migration.migrateLegacyState({ diff --git a/extensions/voice-call/src/manager.async-store.test.ts b/extensions/voice-call/src/manager.async-store.test.ts index a6c660fc5fb6..471b45980ab7 100644 --- a/extensions/voice-call/src/manager.async-store.test.ts +++ b/extensions/voice-call/src/manager.async-store.test.ts @@ -8,6 +8,7 @@ import { resetPluginStateStoreForTests, } from "openclaw/plugin-sdk/plugin-state-test-runtime"; import type { RealtimeVoiceProviderPlugin } from "openclaw/plugin-sdk/realtime-voice"; +import { closeOpenClawStateDatabaseAsync } from "openclaw/plugin-sdk/sqlite-runtime-testing"; import { expect, it, vi } from "vitest"; import { VoiceCallConfigSchema, type VoiceCallConfig } from "./config.js"; import { CallManager } from "./manager.js"; @@ -115,6 +116,7 @@ async function withDelayedStore( await manager.stop(); await Promise.allSettled(writes); persistence.mockRestore(); + await closeOpenClawStateDatabaseAsync(); resetPluginStateStoreForTests(); fs.rmSync(storePath, { recursive: true, force: true }); } diff --git a/extensions/voice-call/src/manager.lifecycle.test.ts b/extensions/voice-call/src/manager.lifecycle.test.ts index 828c7c223d4c..0a63f6d74c52 100644 --- a/extensions/voice-call/src/manager.lifecycle.test.ts +++ b/extensions/voice-call/src/manager.lifecycle.test.ts @@ -1,6 +1,7 @@ import fs from "node:fs"; import { createDeferred } from "openclaw/plugin-sdk/extension-shared"; import { resetPluginStateStoreForTests } from "openclaw/plugin-sdk/plugin-state-test-runtime"; +import { closeOpenClawStateDatabaseAsync } from "openclaw/plugin-sdk/sqlite-runtime-testing"; import { describe, expect, it, onTestFinished } from "vitest"; import { VoiceCallConfigSchema } from "./config.js"; import { CallManager } from "./manager.js"; @@ -62,6 +63,7 @@ describe("CallManager termination lifecycle", () => { await finalizeTestManagerCalls(owner); } } finally { + await closeOpenClawStateDatabaseAsync(); resetPluginStateStoreForTests(); fs.rmSync(storePath, { recursive: true, force: true }); } diff --git a/extensions/voice-call/src/manager/store.test.ts b/extensions/voice-call/src/manager/store.test.ts index 3cf873621d9a..40d0abc54214 100644 --- a/extensions/voice-call/src/manager/store.test.ts +++ b/extensions/voice-call/src/manager/store.test.ts @@ -11,6 +11,7 @@ import { openOpenClawStateDatabase, resetPluginStateStoreForTests, } from "openclaw/plugin-sdk/plugin-state-test-runtime"; +import { closeOpenClawStateDatabaseAsync } from "openclaw/plugin-sdk/sqlite-runtime-testing"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { registerVoiceCallLogs } from "../cli-call-log.js"; import { @@ -90,8 +91,9 @@ describe("voice-call call record store", () => { installStateRuntime(); }); - afterEach(() => { + afterEach(async () => { vi.useRealTimers(); + await closeOpenClawStateDatabaseAsync(); resetPluginStateStoreForTests(); }); @@ -134,6 +136,7 @@ describe("voice-call call record store", () => { ).toEqual(since === 0 ? ["new"] : ["third", "new"]); } finally { stdout.mockRestore(); + await closeOpenClawStateDatabaseAsync(); fs.rmSync(storePath, { recursive: true, force: true }); } }); @@ -248,6 +251,7 @@ describe("voice-call call record store", () => { ); await expect(findCallInStore(storePath, "provider-batch-127")).resolves.toEqual(calls[127]); } finally { + await closeOpenClawStateDatabaseAsync(); resetPluginStateStoreForTests(); fs.rmSync(storePath, { recursive: true, force: true }); } @@ -304,6 +308,7 @@ describe("voice-call call record store", () => { ); await expect(getCallHistoryFromStore(storePath)).resolves.toEqual([]); } finally { + await closeOpenClawStateDatabaseAsync(); resetPluginStateStoreForTests(); fs.rmSync(storePath, { recursive: true, force: true }); } @@ -415,6 +420,7 @@ describe("voice-call call record store", () => { expect((await loadActiveCallsFromStore(storePath)).activeCalls.size).toBe(0); } finally { toString.mockRestore(); + await closeOpenClawStateDatabaseAsync(); resetPluginStateStoreForTests(); fs.rmSync(storePath, { recursive: true, force: true }); } diff --git a/extensions/voice-call/src/webhook.hangup-once.lifecycle.test.ts b/extensions/voice-call/src/webhook.hangup-once.lifecycle.test.ts index 4f5a1f3b82a9..9f5f34d5981c 100644 --- a/extensions/voice-call/src/webhook.hangup-once.lifecycle.test.ts +++ b/extensions/voice-call/src/webhook.hangup-once.lifecycle.test.ts @@ -6,6 +6,7 @@ import { createPluginStateKeyedStoreForTests, resetPluginStateStoreForTests, } from "openclaw/plugin-sdk/plugin-state-test-runtime"; +import { closeOpenClawStateDatabaseAsync } from "openclaw/plugin-sdk/sqlite-runtime-testing"; import { postRawWebhook } from "openclaw/plugin-sdk/test-env"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { VoiceCallConfigSchema, type VoiceCallConfig } from "./config.js"; @@ -157,7 +158,8 @@ describe("Voice-call webhook hangup-once lifecycle", () => { installStateRuntime(); }); - afterEach(() => { + afterEach(async () => { + await closeOpenClawStateDatabaseAsync(); resetPluginStateStoreForTests(); vi.restoreAllMocks(); }); @@ -265,6 +267,7 @@ describe("Voice-call webhook hangup-once lifecycle", () => { await server.stop(); } finally { await finalizeTestManagerCalls(manager); + await closeOpenClawStateDatabaseAsync(); resetPluginStateStoreForTests(); fs.rmSync(storePath, { recursive: true, force: true }); } @@ -332,7 +335,8 @@ describe("Voice-call webhook body limits", () => { installStateRuntime(); }); - afterEach(() => { + afterEach(async () => { + await closeOpenClawStateDatabaseAsync(); resetPluginStateStoreForTests(); }); diff --git a/extensions/zalouser/doctor-contract-api.test.ts b/extensions/zalouser/doctor-contract-api.test.ts index 9ef89139969d..b26316c9a8c4 100644 --- a/extensions/zalouser/doctor-contract-api.test.ts +++ b/extensions/zalouser/doctor-contract-api.test.ts @@ -17,7 +17,10 @@ import { normalizeSessionDeliveryState, upsertSessionEntry, } from "openclaw/plugin-sdk/session-store-runtime"; -import { closeOpenClawAgentDatabasesForTest } from "openclaw/plugin-sdk/sqlite-runtime-testing"; +import { + closeOpenClawAgentDatabasesForTest, + closeOpenClawStateDatabaseAsync, +} from "openclaw/plugin-sdk/sqlite-runtime-testing"; import { afterEach, beforeEach, describe, expect, it } from "vitest"; import { stateMigrations } from "./doctor-contract-api.js"; import { setZalouserRuntime } from "./src/runtime.js"; @@ -66,6 +69,7 @@ describe("zalouser doctor state migration", () => { // resetPluginStateStoreForTests only releases plugin state plus shared state, so the // cached agent handles must be closed here or Windows fails the removal with EBUSY. closeOpenClawAgentDatabasesForTest(); + await closeOpenClawStateDatabaseAsync(); resetPluginStateStoreForTests(); await fs.rm(stateDir, { recursive: true, force: true }); }); diff --git a/src/plugin-sdk/sqlite-runtime-testing.ts b/src/plugin-sdk/sqlite-runtime-testing.ts index 8df6e29923e3..3260d051f31c 100644 --- a/src/plugin-sdk/sqlite-runtime-testing.ts +++ b/src/plugin-sdk/sqlite-runtime-testing.ts @@ -27,6 +27,7 @@ export { openOpenClawAgentDatabase, } from "../state/openclaw-agent-db.js"; export { + closeOpenClawStateDatabaseAsync, closeOpenClawStateDatabaseForTest, openOpenClawStateDatabase, } from "../state/openclaw-state-db.js";