perf(test): speed up test runs and harden temp cleanup

This commit is contained in:
Peter Steinberger
2026-02-12 17:59:44 +00:00
parent d3aee84499
commit 069670388e
2 changed files with 40 additions and 6 deletions

View File

@@ -32,14 +32,22 @@ const shardCount = isWindowsCi
: 2
: 1;
const windowsCiArgs = isWindowsCi ? ["--dangerouslyIgnoreUnhandledErrors"] : [];
const silentArgs =
process.env.OPENCLAW_TEST_SHOW_PASSED_LOGS === "1" ? [] : ["--silent=passed-only"];
const rawPassthroughArgs = process.argv.slice(2);
const passthroughArgs =
rawPassthroughArgs[0] === "--" ? rawPassthroughArgs.slice(1) : rawPassthroughArgs;
const overrideWorkers = Number.parseInt(process.env.OPENCLAW_TEST_WORKERS ?? "", 10);
const resolvedOverride =
Number.isFinite(overrideWorkers) && overrideWorkers > 0 ? overrideWorkers : null;
const parallelRuns = runs.filter((entry) => entry.name !== "gateway");
const serialRuns = runs.filter((entry) => entry.name === "gateway");
// Keep gateway serial by default to avoid resource contention with unit/extensions.
// Allow explicit opt-in parallel runs on non-Windows CI/local when requested.
const keepGatewaySerial =
isWindowsCi ||
process.env.OPENCLAW_TEST_SERIAL_GATEWAY === "1" ||
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;
const defaultExtensionsWorkers = Math.max(1, Math.min(4, Math.floor(localWorkers / 4)));
@@ -120,11 +128,12 @@ const runOnce = (entry, extraArgs = []) =>
...entry.args,
"--maxWorkers",
String(maxWorkers),
...silentArgs,
...reporterArgs,
...windowsCiArgs,
...extraArgs,
]
: [...entry.args, ...reporterArgs, ...windowsCiArgs, ...extraArgs];
: [...entry.args, ...silentArgs, ...reporterArgs, ...windowsCiArgs, ...extraArgs];
const nodeOptions = process.env.NODE_OPTIONS ?? "";
const nextNodeOptions = WARNING_SUPPRESSION_FLAGS.reduce(
(acc, flag) => (acc.includes(flag) ? acc : `${acc} ${flag}`.trim()),
@@ -168,8 +177,16 @@ process.on("SIGTERM", () => shutdown("SIGTERM"));
if (passthroughArgs.length > 0) {
const maxWorkers = maxWorkersForRun("unit");
const args = maxWorkers
? ["vitest", "run", "--maxWorkers", String(maxWorkers), ...windowsCiArgs, ...passthroughArgs]
: ["vitest", "run", ...windowsCiArgs, ...passthroughArgs];
? [
"vitest",
"run",
"--maxWorkers",
String(maxWorkers),
...silentArgs,
...windowsCiArgs,
...passthroughArgs,
]
: ["vitest", "run", ...silentArgs, ...windowsCiArgs, ...passthroughArgs];
const nodeOptions = process.env.NODE_OPTIONS ?? "";
const nextNodeOptions = WARNING_SUPPRESSION_FLAGS.reduce(
(acc, flag) => (acc.includes(flag) ? acc : `${acc} ${flag}`.trim()),

View File

@@ -1,6 +1,7 @@
import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { setTimeout as delay } from "node:timers/promises";
import { describe, expect, it, vi } from "vitest";
import { OPENAI_DEFAULT_MODEL } from "./openai-model-default.js";
@@ -29,6 +30,22 @@ type OnboardEnv = {
runtime: RuntimeMock;
};
async function removeDirWithRetry(dir: string): Promise<void> {
for (let attempt = 0; attempt < 5; attempt += 1) {
try {
await fs.rm(dir, { recursive: true, force: true });
return;
} catch (error) {
const code = (error as NodeJS.ErrnoException).code;
const isTransient = code === "ENOTEMPTY" || code === "EBUSY" || code === "EPERM";
if (!isTransient || attempt === 4) {
throw error;
}
await delay(25 * (attempt + 1));
}
}
}
function captureEnv(): EnvSnapshot {
return {
home: process.env.HOME,
@@ -102,7 +119,7 @@ async function withOnboardEnv(
try {
await run({ configPath, runtime });
} finally {
await fs.rm(tempHome, { recursive: true, force: true });
await removeDirWithRetry(tempHome);
restoreEnv(prev);
}
}