test: keep vitest thread workers conservative

This commit is contained in:
Peter Steinberger
2026-04-04 05:20:07 +01:00
parent 943da1864a
commit 5b294b7fbd
3 changed files with 50 additions and 10 deletions

View File

@@ -17,8 +17,9 @@ describe("resolveLocalVitestMaxWorkers", () => {
loadAverage1m: 0,
totalMemoryBytes: 64 * 1024 ** 3,
},
"threads",
),
).toBe(3);
).toBe(2);
});
it("lets OPENCLAW_VITEST_MAX_WORKERS override the inferred cap", () => {
@@ -60,8 +61,9 @@ describe("resolveLocalVitestMaxWorkers", () => {
loadAverage1m: 0,
totalMemoryBytes: 16 * 1024 ** 3,
},
"threads",
),
).toBe(2);
).toBe(1);
});
it("lets roomy hosts use more local parallelism", () => {
@@ -73,8 +75,9 @@ describe("resolveLocalVitestMaxWorkers", () => {
loadAverage1m: 0,
totalMemoryBytes: 128 * 1024 ** 3,
},
"threads",
),
).toBe(4);
).toBe(3);
});
it("backs off further when the host is already busy", () => {
@@ -86,8 +89,23 @@ describe("resolveLocalVitestMaxWorkers", () => {
loadAverage1m: 16,
totalMemoryBytes: 128 * 1024 ** 3,
},
"threads",
),
).toBe(2);
).toBe(1);
});
it("keeps fork pools less conservative than thread pools on roomy hosts", () => {
expect(
resolveLocalVitestMaxWorkers(
{},
{
cpuCount: 16,
loadAverage1m: 0,
totalMemoryBytes: 128 * 1024 ** 3,
},
"forks",
),
).toBe(4);
});
});

View File

@@ -65,7 +65,11 @@ describe("createScopedVitestConfig", () => {
setupFiles: ["test/setup.extensions.ts"],
});
expect(config.test?.setupFiles).toEqual(["test/setup.extensions.ts"]);
expect(config.test?.setupFiles).toEqual([
"test/setup.ts",
"test/setup.extensions.ts",
"test/setup-openclaw-runtime.ts",
]);
});
});
@@ -85,7 +89,7 @@ describe("scoped vitest configs", () => {
it("defaults channel tests to non-isolated mode", () => {
expect(defaultChannelsConfig.test?.isolate).toBe(false);
expect(defaultChannelsConfig.test?.pool).toBe("forks");
expect(defaultChannelsConfig.test?.pool).toBe("threads");
});
it("keeps the core channel lane limited to non-extension roots", () => {
@@ -121,7 +125,7 @@ describe("scoped vitest configs", () => {
it("defaults extension tests to non-isolated mode", () => {
expect(defaultExtensionsConfig.test?.isolate).toBe(false);
expect(defaultExtensionsConfig.test?.pool).toBe("forks");
expect(defaultExtensionsConfig.test?.pool).toBe("threads");
});
it("normalizes extension channel include patterns relative to the scoped dir", () => {
@@ -165,7 +169,11 @@ describe("scoped vitest configs", () => {
expect(defaultChannelsConfig.test?.exclude).not.toContain(
bundledPluginFile("telegram", "src/fetch.test.ts"),
);
expect(defaultExtensionsConfig.test?.setupFiles).toEqual(["test/setup.extensions.ts"]);
expect(defaultExtensionsConfig.test?.setupFiles).toEqual([
"test/setup.ts",
"test/setup.extensions.ts",
"test/setup-openclaw-runtime.ts",
]);
});
it("keeps provider plugin tests out of the shared extensions lane", () => {

View File

@@ -44,6 +44,7 @@ function detectVitestHostInfo(): Required<VitestHostInfo> {
export function resolveLocalVitestMaxWorkers(
env: Record<string, string | undefined> = process.env,
system: VitestHostInfo = detectVitestHostInfo(),
pool: OpenClawVitestPool = resolveDefaultVitestPool(env),
): number {
const override = parsePositiveInt(env.OPENCLAW_VITEST_MAX_WORKERS ?? env.OPENCLAW_TEST_WORKERS);
if (override !== null) {
@@ -76,6 +77,19 @@ export function resolveLocalVitestMaxWorkers(
inferred = Math.max(1, inferred - 1);
}
if (pool === "threads") {
// Thread workers are faster per slot on the steady state, but their startup
// compile pressure is much burstier. Keep headroom so a second local Vitest
// run can start without immediately saturating the host.
inferred = Math.min(inferred, 4);
if (cpuCount >= 8) {
inferred = Math.max(1, inferred - 1);
}
if (loadRatio >= 0.5) {
inferred = Math.max(1, inferred - 1);
}
}
return clamp(inferred, 1, 16);
}
@@ -92,9 +106,9 @@ export function resolveDefaultVitestPool(
const repoRoot = path.dirname(fileURLToPath(import.meta.url));
const isCI = process.env.CI === "true" || process.env.GITHUB_ACTIONS === "true";
const isWindows = process.platform === "win32";
const localWorkers = resolveLocalVitestMaxWorkers();
const ciWorkers = isWindows ? 2 : 3;
const defaultPool = resolveDefaultVitestPool();
const localWorkers = resolveLocalVitestMaxWorkers(process.env, detectVitestHostInfo(), defaultPool);
const ciWorkers = isWindows ? 2 : 3;
export const sharedVitestConfig = {
resolve: {