From df7fff8fd7876634de4bb508247451fbffd01893 Mon Sep 17 00:00:00 2001 From: Tak Hoffman <781889+Takhoffman@users.noreply.github.com> Date: Sun, 15 Feb 2026 07:40:13 -0600 Subject: [PATCH] test: add serial macmini test profile --- package.json | 1 + scripts/test-parallel.mjs | 52 ++++++++++++++++++++++++++++++++------- 2 files changed, 44 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index 435e09be2e..c85cc08b2b 100644 --- a/package.json +++ b/package.json @@ -103,6 +103,7 @@ "test:install:e2e:openai": "OPENCLAW_E2E_MODELS=openai CLAWDBOT_E2E_MODELS=openai bash scripts/test-install-sh-e2e-docker.sh", "test:install:smoke": "bash scripts/test-install-sh-docker.sh", "test:live": "OPENCLAW_LIVE_TEST=1 CLAWDBOT_LIVE_TEST=1 vitest run --config vitest.live.config.ts", + "test:macmini": "OPENCLAW_TEST_VM_FORKS=0 OPENCLAW_TEST_PROFILE=serial node scripts/test-parallel.mjs", "test:ui": "pnpm --dir ui test", "test:watch": "vitest", "tsgo:test": "tsgo -p tsconfig.test.json", diff --git a/scripts/test-parallel.mjs b/scripts/test-parallel.mjs index 0c5757baca..04b60c3556 100644 --- a/scripts/test-parallel.mjs +++ b/scripts/test-parallel.mjs @@ -116,6 +116,14 @@ const silentArgs = const rawPassthroughArgs = process.argv.slice(2); const passthroughArgs = rawPassthroughArgs[0] === "--" ? rawPassthroughArgs.slice(1) : rawPassthroughArgs; +const rawTestProfile = process.env.OPENCLAW_TEST_PROFILE?.trim().toLowerCase(); +const testProfile = + rawTestProfile === "low" || + rawTestProfile === "max" || + rawTestProfile === "normal" || + rawTestProfile === "serial" + ? rawTestProfile + : "normal"; const overrideWorkers = Number.parseInt(process.env.OPENCLAW_TEST_WORKERS ?? "", 10); const resolvedOverride = Number.isFinite(overrideWorkers) && overrideWorkers > 0 ? overrideWorkers : null; @@ -124,14 +132,41 @@ const resolvedOverride = const keepGatewaySerial = isWindowsCi || process.env.OPENCLAW_TEST_SERIAL_GATEWAY === "1" || + testProfile === "serial" || (isCI && process.env.OPENCLAW_TEST_PARALLEL_GATEWAY !== "1"); const parallelRuns = keepGatewaySerial ? runs.filter((entry) => entry.name !== "gateway") : runs; const serialRuns = keepGatewaySerial ? runs.filter((entry) => entry.name === "gateway") : []; const localWorkers = Math.max(4, Math.min(16, os.cpus().length)); -const defaultUnitWorkers = localWorkers; -// Local perf: extensions tend to be the critical path under parallel vitest runs; give them more headroom. -const defaultExtensionsWorkers = Math.max(1, Math.min(6, Math.floor(localWorkers / 2))); -const defaultGatewayWorkers = Math.max(1, Math.min(2, Math.floor(localWorkers / 4))); +const defaultWorkerBudget = + testProfile === "low" + ? { + unit: 2, + unitIsolated: 1, + extensions: 1, + gateway: 1, + } + : testProfile === "serial" + ? { + unit: 1, + unitIsolated: 1, + extensions: 1, + gateway: 1, + } + : testProfile === "max" + ? { + unit: localWorkers, + unitIsolated: Math.min(4, localWorkers), + extensions: Math.max(1, Math.min(6, Math.floor(localWorkers / 2))), + gateway: Math.max(1, Math.min(2, Math.floor(localWorkers / 4))), + } + : { + // Local `pnpm test` runs multiple vitest groups concurrently; + // keep per-group workers conservative to avoid pegging all cores. + unit: Math.max(2, Math.min(8, Math.floor(localWorkers / 2))), + unitIsolated: 1, + extensions: Math.max(1, Math.min(4, Math.floor(localWorkers / 4))), + gateway: 1, + }; // Keep worker counts predictable for local runs; trim macOS CI workers to avoid worker crashes/OOM. // In CI on linux/windows, prefer Vitest defaults to avoid cross-test interference from lower worker counts. @@ -146,16 +181,15 @@ const maxWorkersForRun = (name) => { return 1; } if (name === "unit-isolated") { - // Local: allow a bit of parallelism while keeping this run stable. - return Math.min(4, localWorkers); + return defaultWorkerBudget.unitIsolated; } if (name === "extensions") { - return defaultExtensionsWorkers; + return defaultWorkerBudget.extensions; } if (name === "gateway") { - return defaultGatewayWorkers; + return defaultWorkerBudget.gateway; } - return defaultUnitWorkers; + return defaultWorkerBudget.unit; }; const WARNING_SUPPRESSION_FLAGS = [