From 8a3d946f4ae255c1e0554384da54ca975e964473 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sat, 4 Apr 2026 05:49:47 +0100 Subject: [PATCH] test: cover vitest contention scheduling --- src/infra/vitest-config.test.ts | 115 ++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) diff --git a/src/infra/vitest-config.test.ts b/src/infra/vitest-config.test.ts index 27c89efa0e7..455b932f1e9 100644 --- a/src/infra/vitest-config.test.ts +++ b/src/infra/vitest-config.test.ts @@ -3,7 +3,15 @@ import { describe, expect, it } from "vitest"; import baseConfig, { resolveDefaultVitestPool, resolveLocalVitestMaxWorkers, + resolveLocalVitestScheduling, } from "../../vitest.config.ts"; +import { parseVitestProcessStats } from "../../vitest.system-load.ts"; + +const idleVitestStats = { + otherVitestRootCount: 0, + otherVitestWorkerCount: 0, + otherVitestCpuPercent: 0, +} as const; describe("resolveLocalVitestMaxWorkers", () => { it("uses a moderate local worker cap on larger hosts", () => { @@ -17,6 +25,8 @@ describe("resolveLocalVitestMaxWorkers", () => { loadAverage1m: 0, totalMemoryBytes: 64 * 1024 ** 3, }, + "forks", + idleVitestStats, ), ).toBe(3); }); @@ -32,6 +42,8 @@ describe("resolveLocalVitestMaxWorkers", () => { loadAverage1m: 0, totalMemoryBytes: 128 * 1024 ** 3, }, + "forks", + idleVitestStats, ), ).toBe(2); }); @@ -47,6 +59,8 @@ describe("resolveLocalVitestMaxWorkers", () => { loadAverage1m: 0, totalMemoryBytes: 128 * 1024 ** 3, }, + "forks", + idleVitestStats, ), ).toBe(3); }); @@ -60,6 +74,8 @@ describe("resolveLocalVitestMaxWorkers", () => { loadAverage1m: 0, totalMemoryBytes: 16 * 1024 ** 3, }, + "forks", + idleVitestStats, ), ).toBe(2); }); @@ -73,6 +89,8 @@ describe("resolveLocalVitestMaxWorkers", () => { loadAverage1m: 0, totalMemoryBytes: 128 * 1024 ** 3, }, + "forks", + idleVitestStats, ), ).toBe(4); }); @@ -86,6 +104,8 @@ describe("resolveLocalVitestMaxWorkers", () => { loadAverage1m: 16, totalMemoryBytes: 128 * 1024 ** 3, }, + "forks", + idleVitestStats, ), ).toBe(2); }); @@ -99,11 +119,103 @@ describe("resolveLocalVitestMaxWorkers", () => { loadAverage1m: 0, totalMemoryBytes: 256 * 1024 ** 3, }, + "forks", + idleVitestStats, ), ).toBe(6); }); }); +describe("resolveLocalVitestScheduling", () => { + it("falls back to serial when other Vitest workers are already active", () => { + expect( + resolveLocalVitestScheduling( + {}, + { + cpuCount: 16, + loadAverage1m: 0.5, + totalMemoryBytes: 128 * 1024 ** 3, + }, + "forks", + { + otherVitestRootCount: 1, + otherVitestWorkerCount: 3, + otherVitestCpuPercent: 120, + }, + ), + ).toEqual({ + maxWorkers: 1, + fileParallelism: false, + throttledBySystem: true, + }); + }); + + it("caps moderate contention to two workers", () => { + expect( + resolveLocalVitestScheduling( + {}, + { + cpuCount: 16, + loadAverage1m: 0.5, + totalMemoryBytes: 128 * 1024 ** 3, + }, + "forks", + { + otherVitestRootCount: 1, + otherVitestWorkerCount: 0, + otherVitestCpuPercent: 10, + }, + ), + ).toEqual({ + maxWorkers: 2, + fileParallelism: true, + throttledBySystem: true, + }); + }); + + it("allows disabling the system throttle probe explicitly", () => { + expect( + resolveLocalVitestScheduling( + { + OPENCLAW_VITEST_DISABLE_SYSTEM_THROTTLE: "1", + }, + { + cpuCount: 16, + loadAverage1m: 0.5, + totalMemoryBytes: 128 * 1024 ** 3, + }, + "forks", + idleVitestStats, + ), + ).toEqual({ + maxWorkers: 4, + fileParallelism: true, + throttledBySystem: false, + }); + }); +}); + +describe("parseVitestProcessStats", () => { + it("counts other Vitest roots and workers while excluding the current pid", () => { + expect( + parseVitestProcessStats( + [ + "101 0.0 node /Users/me/project/node_modules/.bin/vitest run --config vitest.config.ts", + "102 41.3 /opt/homebrew/bin/node /Users/me/project/node_modules/vitest/dist/workers/forks.js", + "103 37.4 /opt/homebrew/bin/node /Users/me/project/node_modules/vitest/dist/workers/forks.js", + "200 12.0 node /Users/me/project/node_modules/.bin/vitest run --config vitest.unit.config.ts", + "201 25.5 node unrelated-script.mjs", + ].join("\n"), + 200, + ), + ).toEqual({ + otherVitestRootCount: 1, + otherVitestWorkerCount: 2, + otherVitestCpuPercent: 78.7, + }); + }); +}); + describe("base vitest config", () => { it("defaults the base pool to forks", () => { expect(resolveDefaultVitestPool()).toBe("forks"); @@ -138,6 +250,9 @@ describe("test scripts", () => { expect(pkg.scripts?.["test:serial"]).toBe( "OPENCLAW_VITEST_MAX_WORKERS=1 node scripts/test-projects.mjs", ); + expect(pkg.scripts?.["test:fast"]).toBe( + "node scripts/run-vitest.mjs run --config vitest.unit.config.ts", + ); expect(pkg.scripts?.["test:single"]).toBeUndefined(); }); });