diff --git a/extensions/qa-lab/src/suite-runtime-gateway.test.ts b/extensions/qa-lab/src/suite-runtime-gateway.test.ts index 38e50e15da21..17dd9c07d1e0 100644 --- a/extensions/qa-lab/src/suite-runtime-gateway.test.ts +++ b/extensions/qa-lab/src/suite-runtime-gateway.test.ts @@ -238,7 +238,7 @@ describe("qa suite gateway helpers", () => { }); const waitReady = vi.fn(async () => {}); - await waitForConfigRestartSettle(createRestartSettleEnv(waitReady), 0, 1_000); + await waitForConfigRestartSettle(createRestartSettleEnv(waitReady), 0, 3_000); expect(fetchWithSsrFGuardMock).toHaveBeenCalledWith( expect.objectContaining({ diff --git a/scripts/test-extension-batch.mjs b/scripts/test-extension-batch.mjs index a6dc485a113b..ca305f7518bb 100644 --- a/scripts/test-extension-batch.mjs +++ b/scripts/test-extension-batch.mjs @@ -10,6 +10,12 @@ import { isDirectScriptRun, runVitestBatch } from "./lib/vitest-batch-runner.mjs const FS_MODULE_CACHE_PATH_ENV_KEY = "OPENCLAW_VITEST_FS_MODULE_CACHE_PATH"; const PARALLEL_ENV_KEY = "OPENCLAW_EXTENSION_BATCH_PARALLEL"; const TARGET_CHUNK_SIZE_ENV_KEY = "OPENCLAW_EXTENSION_BATCH_TARGET_CHUNK_SIZE"; +const MEMORY_VITEST_CONFIG = "test/vitest/vitest.extension-memory.config.ts"; +const MEMORY_TARGET_CHUNK_SIZE = 25; +const MEMORY_ISOLATED_TARGETS = new Set([ + "extensions/memory-core/src/memory/manager-embedding-timeout.test.ts", + "extensions/memory-core/src/memory/qmd-manager.test.ts", +]); const TELEGRAM_VITEST_CONFIG = "test/vitest/vitest.extension-telegram.config.ts"; const TELEGRAM_TARGET_CHUNK_SIZE = 40; const ALLOW_NO_TESTS_FLAG = "--allow-no-tests"; @@ -151,17 +157,36 @@ function resolveGroupTargetChunkSize(group, env) { if (override !== null) { return override; } + if (group.config === MEMORY_VITEST_CONFIG) { + return MEMORY_TARGET_CHUNK_SIZE; + } return group.config === TELEGRAM_VITEST_CONFIG ? TELEGRAM_TARGET_CHUNK_SIZE : null; } -function chunkTargets(targets, chunkSize) { +function chunkTargets(targets, chunkSize, isolatedTargets = new Set()) { if (!chunkSize || targets.length <= chunkSize) { return [targets]; } const chunks = []; - for (let index = 0; index < targets.length; index += chunkSize) { - chunks.push(targets.slice(index, index + chunkSize)); + let currentChunk = []; + const flushCurrentChunk = () => { + if (currentChunk.length > 0) { + chunks.push(currentChunk); + currentChunk = []; + } + }; + for (const target of targets) { + if (isolatedTargets.has(target)) { + flushCurrentChunk(); + chunks.push([target]); + continue; + } + currentChunk.push(target); + if (currentChunk.length >= chunkSize) { + flushCurrentChunk(); + } } + flushCurrentChunk(); return chunks; } @@ -176,7 +201,9 @@ async function runPlanGroup(group, params) { console.log( `[test-extension-batch] ${group.config}: ${group.extensionIds.join(", ")} (${targets.length} targets)`, ); - const targetChunks = chunkTargets(targets, targetChunkSize); + const isolatedTargets = + group.config === MEMORY_VITEST_CONFIG ? MEMORY_ISOLATED_TARGETS : new Set(); + const targetChunks = chunkTargets(targets, targetChunkSize, isolatedTargets); for (const [index, chunk] of targetChunks.entries()) { if (targetChunks.length > 1) { console.log( diff --git a/test/scripts/test-extension.test.ts b/test/scripts/test-extension.test.ts index 7d25e8bad83a..1a79eeee6fe8 100644 --- a/test/scripts/test-extension.test.ts +++ b/test/scripts/test-extension.test.ts @@ -710,6 +710,40 @@ describe("scripts/test-extension.mjs", () => { expect(runGroup.mock.calls.map(([params]) => params.targets.length)).toEqual([50, 50, 25]); }); + it("chunks memory extension batch groups by default", async () => { + const runGroup = vi.fn<() => Promise>().mockResolvedValue(0); + const result = await runExtensionBatchPlan( + { + extensionCount: 2, + extensionIds: ["memory-core", "memory-lancedb"], + estimatedCost: 64, + hasTests: true, + planGroups: [ + { + config: "test/vitest/vitest.extension-memory.config.ts", + estimatedCost: 64, + extensionIds: ["memory-core", "memory-lancedb"], + roots: [bundledPluginRoot("memory-core"), bundledPluginRoot("memory-lancedb")], + testFileCount: 64, + }, + ], + testFileCount: 64, + }, + { runGroup }, + ); + + expect(result).toBe(0); + expect( + runGroup.mock.calls.map(([params]) => params.targets.length).reduce((a, b) => a + b, 0), + ).toBe(64); + expect(runGroup.mock.calls.map(([params]) => params.targets)).toContainEqual([ + bundledPluginFile("memory-core", "src/memory/manager-embedding-timeout.test.ts"), + ]); + expect(runGroup.mock.calls.map(([params]) => params.targets)).toContainEqual([ + bundledPluginFile("memory-core", "src/memory/qmd-manager.test.ts"), + ]); + }); + it("fails extension batch groups when exact excludes remove every test", async () => { const runGroup = vi.fn<() => Promise>().mockResolvedValue(0); const result = await runExtensionBatchPlan(