diff --git a/extensions/memory-core/src/cli.test.ts b/extensions/memory-core/src/cli.test.ts index ed18abba760a..97351ae35f2a 100644 --- a/extensions/memory-core/src/cli.test.ts +++ b/extensions/memory-core/src/cli.test.ts @@ -5,6 +5,7 @@ import path from "node:path"; import { Command } from "commander"; import type { OpenClawConfig } from "openclaw/plugin-sdk/memory-core-host-engine-foundation"; import { resolveSessionTranscriptsDirForAgent as resolveTestSessionTranscriptsDirForAgent } from "openclaw/plugin-sdk/memory-core-host-runtime-core"; +import { resetPluginStateStoreForTests } from "openclaw/plugin-sdk/plugin-state-test-runtime"; import { upsertSessionEntry } from "openclaw/plugin-sdk/session-store-runtime"; import { appendSessionTranscriptMessageByIdentity } from "openclaw/plugin-sdk/session-transcript-runtime"; import { resolveOpenClawAgentSqlitePath } from "openclaw/plugin-sdk/sqlite-runtime"; @@ -161,6 +162,10 @@ afterAll(async () => { if (!fixtureRoot) { return; } + // 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(); + resetPluginStateStoreForTests(); await fs.rm(fixtureRoot, { recursive: true, force: true }); resetMemoryCoreDreamingStateForTests(); }); diff --git a/extensions/memory-core/src/dreaming-startup-cleanup.test.ts b/extensions/memory-core/src/dreaming-startup-cleanup.test.ts index f62a6bc613ff..07e1332eef4d 100644 --- a/extensions/memory-core/src/dreaming-startup-cleanup.test.ts +++ b/extensions/memory-core/src/dreaming-startup-cleanup.test.ts @@ -3,6 +3,7 @@ import os from "node:os"; import path from "node:path"; import type { OpenClawConfig } from "openclaw/plugin-sdk/config-contracts"; import type { OpenClawPluginApi } from "openclaw/plugin-sdk/plugin-entry"; +import { resetPluginStateStoreForTests } from "openclaw/plugin-sdk/plugin-state-test-runtime"; import { getSessionEntry, upsertSessionEntry } from "openclaw/plugin-sdk/session-store-runtime"; import { appendSqliteSessionTranscriptEventForTest, @@ -30,6 +31,7 @@ afterEach(async () => { vi.useRealTimers(); vi.unstubAllEnvs(); vi.restoreAllMocks(); + resetPluginStateStoreForTests(); await fs.rm(stateDir, { recursive: true, force: true }); }); diff --git a/extensions/memory-core/src/memory/manager-sync-ops.startup-catchup.test.ts b/extensions/memory-core/src/memory/manager-sync-ops.startup-catchup.test.ts index 6fa4607b57a4..cb4c7bfdbeb4 100644 --- a/extensions/memory-core/src/memory/manager-sync-ops.startup-catchup.test.ts +++ b/extensions/memory-core/src/memory/manager-sync-ops.startup-catchup.test.ts @@ -19,6 +19,7 @@ import { type MemorySyncParams, type MemorySyncProgressUpdate, } from "openclaw/plugin-sdk/memory-core-host-engine-storage"; +import { resetPluginStateStoreForTests } from "openclaw/plugin-sdk/plugin-state-test-runtime"; import { clearConfigCache, clearRuntimeConfigSnapshot, @@ -413,6 +414,10 @@ describe("session startup catch-up", () => { } startupHarnessDatabases.clear(); closeOpenClawAgentDatabasesForTest(); + // Closing the agent databases releases their leases through shared state, which + // reopens it, so the shared handle has to be released after that and before the + // removal or Windows fails the unlink with EBUSY. + resetPluginStateStoreForTests(); await fs.rm(stateDir, { recursive: true, force: true }); }); 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 4b0321cb7246..c1da516b39f2 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 @@ -4,7 +4,9 @@ import os from "node:os"; import path from "node:path"; 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 { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import { closeAllMemorySearchManagers, getMemorySearchManager } from "./index.js"; import type { MemoryIndexMeta } from "./manager-reindex-state.js"; @@ -107,6 +109,10 @@ describe("memory manager FTS-only reindex", () => { afterAll(async () => { await closeAllMemorySearchManagers(); + // 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(); + 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 99472a5eda27..326c461a2fb6 100644 --- a/extensions/memory-core/src/memory/manager.reindex-recovery.test.ts +++ b/extensions/memory-core/src/memory/manager.reindex-recovery.test.ts @@ -4,7 +4,9 @@ import os from "node:os"; import path from "node:path"; 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 { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { resetEmbeddingMocks } from "./embedding.test-mocks.js"; import { acquireMemoryReindexLock } from "./manager-reindex-lock.js"; @@ -52,6 +54,10 @@ describe("memory manager reindex recovery", () => { } const { closeAllMemorySearchManagers } = await import("./index.js"); await closeAllMemorySearchManagers(); + // 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(); + 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 7979ac373a66..ae84a0a2269d 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 @@ -3,7 +3,9 @@ import os from "node:os"; import path from "node:path"; 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 { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import { closeAllMemorySearchManagers, getMemorySearchManager } from "./index.js"; import type { MemoryIndexManager } from "./manager.js"; @@ -78,6 +80,10 @@ describe("memory manager self-heal missing identity with FTS-only chunks", () => afterAll(async () => { await closeAllMemorySearchManagers(); + // 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(); + resetPluginStateStoreForTests(); if (fixtureRoot) { await fs.rm(fixtureRoot, { recursive: true, force: true }); } diff --git a/extensions/memory-core/src/memory/manager.watcher-config.test.ts b/extensions/memory-core/src/memory/manager.watcher-config.test.ts index e3dc464f1caa..3f2355f368af 100644 --- a/extensions/memory-core/src/memory/manager.watcher-config.test.ts +++ b/extensions/memory-core/src/memory/manager.watcher-config.test.ts @@ -7,6 +7,8 @@ import type { MemorySearchConfig, OpenClawConfig, } from "openclaw/plugin-sdk/memory-core-host-engine-foundation"; +import { resetPluginStateStoreForTests } from "openclaw/plugin-sdk/plugin-state-test-runtime"; +import { closeOpenClawAgentDatabasesForTest } from "openclaw/plugin-sdk/sqlite-runtime-testing"; import { afterAll, afterEach, beforeEach, describe, expect, it, vi } from "vitest"; type WatchIgnoredFn = (watchPath: string, stats?: { isDirectory?: () => boolean }) => boolean; @@ -208,6 +210,10 @@ describe("memory watcher config", () => { await closeAllMemorySearchManagers(); clearRegistry(); restoreWatcherStateDir(); + // 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(); + resetPluginStateStoreForTests(); if (workspaceDir) { await fs.rm(workspaceDir, { recursive: true, force: true }); workspaceDir = ""; diff --git a/extensions/memory-core/src/test-helpers.ts b/extensions/memory-core/src/test-helpers.ts index 27ba97ac8b93..49b553466919 100644 --- a/extensions/memory-core/src/test-helpers.ts +++ b/extensions/memory-core/src/test-helpers.ts @@ -2,7 +2,11 @@ import fs from "node:fs/promises"; import path from "node:path"; import type { OpenKeyedStoreOptions } from "openclaw/plugin-sdk/plugin-state-runtime"; -import { createPluginStateKeyedStoreForTests } from "openclaw/plugin-sdk/plugin-state-test-runtime"; +import { + createPluginStateKeyedStoreForTests, + resetPluginStateStoreForTests, +} from "openclaw/plugin-sdk/plugin-state-test-runtime"; +import { closeOpenClawAgentDatabasesForTest } from "openclaw/plugin-sdk/sqlite-runtime-testing"; import { asOptionalRecord } from "openclaw/plugin-sdk/string-coerce-runtime"; import { resolvePreferredOpenClawTmpDir } from "openclaw/plugin-sdk/temp-path"; import { afterAll, beforeAll } from "vitest"; @@ -210,6 +214,10 @@ export function createMemoryCoreTestHarness() { if (!fixtureRoot) { return; } + // 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(); + resetPluginStateStoreForTests(); await fs.rm(fixtureRoot, { recursive: true, force: true }); resetMemoryCoreDreamingStateForTests(); });