mirror of
https://github.com/moltbot/moltbot.git
synced 2026-05-13 23:56:07 +00:00
test: stabilize vitest full-suite runner
This commit is contained in:
@@ -3,6 +3,7 @@ import { acquireLocalHeavyCheckLockSync } from "./lib/local-heavy-check-runtime.
|
||||
import { spawnPnpmRunner } from "./pnpm-runner.mjs";
|
||||
import { resolveVitestCliEntry, resolveVitestNodeArgs } from "./run-vitest.mjs";
|
||||
import {
|
||||
applyParallelVitestCachePaths,
|
||||
buildFullSuiteVitestRunPlans,
|
||||
createVitestRunSpecs,
|
||||
parseTestProjectsArgs,
|
||||
@@ -130,7 +131,7 @@ function applyDefaultParallelVitestWorkerBudget(specs, env) {
|
||||
...spec,
|
||||
env: {
|
||||
...spec.env,
|
||||
OPENCLAW_VITEST_MAX_WORKERS: "2",
|
||||
OPENCLAW_VITEST_MAX_WORKERS: "1",
|
||||
},
|
||||
}));
|
||||
}
|
||||
@@ -213,7 +214,10 @@ async function main() {
|
||||
const concurrency = resolveParallelFullSuiteConcurrency(runSpecs.length, process.env);
|
||||
if (concurrency > 1) {
|
||||
const parallelSpecs = applyDefaultParallelVitestWorkerBudget(
|
||||
orderFullSuiteSpecsForParallelRun(runSpecs),
|
||||
applyParallelVitestCachePaths(orderFullSuiteSpecsForParallelRun(runSpecs), {
|
||||
cwd: process.cwd(),
|
||||
env: process.env,
|
||||
}),
|
||||
process.env,
|
||||
);
|
||||
console.error(
|
||||
|
||||
@@ -87,6 +87,8 @@ const UI_VITEST_CONFIG = "test/vitest/vitest.ui.config.ts";
|
||||
const UTILS_VITEST_CONFIG = "test/vitest/vitest.utils.config.ts";
|
||||
const WIZARD_VITEST_CONFIG = "test/vitest/vitest.wizard.config.ts";
|
||||
const INCLUDE_FILE_ENV_KEY = "OPENCLAW_VITEST_INCLUDE_FILE";
|
||||
const FS_MODULE_CACHE_PATH_ENV_KEY = "OPENCLAW_VITEST_FS_MODULE_CACHE_PATH";
|
||||
const DEFAULT_LOCAL_FULL_SUITE_PARALLELISM = 4;
|
||||
const CHANGED_ARGS_PATTERN = /^--changed(?:=(.+))?$/u;
|
||||
const VITEST_CONFIG_BY_KIND = {
|
||||
acp: ACP_VITEST_CONFIG,
|
||||
@@ -688,7 +690,42 @@ export function resolveParallelFullSuiteConcurrency(specCount, env = process.env
|
||||
) {
|
||||
return 1;
|
||||
}
|
||||
return Math.min(10, specCount);
|
||||
return Math.min(DEFAULT_LOCAL_FULL_SUITE_PARALLELISM, specCount);
|
||||
}
|
||||
|
||||
function sanitizeVitestCachePathSegment(value) {
|
||||
return (
|
||||
value
|
||||
.replace(/[^a-zA-Z0-9._-]+/gu, "-")
|
||||
.replace(/^-+|-+$/gu, "")
|
||||
.slice(0, 180) || "default"
|
||||
);
|
||||
}
|
||||
|
||||
export function applyParallelVitestCachePaths(specs, params = {}) {
|
||||
const baseEnv = params.env ?? process.env;
|
||||
if (baseEnv[FS_MODULE_CACHE_PATH_ENV_KEY]?.trim()) {
|
||||
return specs;
|
||||
}
|
||||
const cwd = params.cwd ?? process.cwd();
|
||||
return specs.map((spec, index) => {
|
||||
if (spec.env?.[FS_MODULE_CACHE_PATH_ENV_KEY]?.trim()) {
|
||||
return spec;
|
||||
}
|
||||
const cacheSegment = sanitizeVitestCachePathSegment(`${index}-${spec.config}`);
|
||||
return {
|
||||
...spec,
|
||||
env: {
|
||||
...spec.env,
|
||||
[FS_MODULE_CACHE_PATH_ENV_KEY]: path.join(
|
||||
cwd,
|
||||
"node_modules",
|
||||
".experimental-vitest-cache",
|
||||
cacheSegment,
|
||||
),
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
export function createVitestRunSpecs(args, params = {}) {
|
||||
|
||||
@@ -7,6 +7,7 @@ import { captureEnv } from "../test-utils/env.js";
|
||||
import { sanitizeBinaryOutput } from "./shell-utils.js";
|
||||
|
||||
const isWin = process.platform === "win32";
|
||||
const FOREGROUND_TEST_YIELD_MS = 120_000;
|
||||
type GetShellPathFromLoginShell = typeof import("../infra/shell-env.js").getShellPathFromLoginShell;
|
||||
const shellEnvMocks = vi.hoisted(() => ({
|
||||
getShellPathFromLoginShell: vi.fn<GetShellPathFromLoginShell>(() => "/custom/bin:/opt/bin"),
|
||||
@@ -111,7 +112,10 @@ describe("exec PATH login shell merge", () => {
|
||||
shellPathMock.mockReturnValue("/custom/bin:/opt/bin");
|
||||
|
||||
const tool = createExecTool({ host: "gateway", security: "full", ask: "off" });
|
||||
const result = await tool.execute("call1", { command: "echo $PATH" });
|
||||
const result = await tool.execute("call1", {
|
||||
command: "echo $PATH",
|
||||
yieldMs: FOREGROUND_TEST_YIELD_MS,
|
||||
});
|
||||
const entries = normalizePathEntries(result.content.find((c) => c.type === "text")?.text);
|
||||
|
||||
expect(entries).toEqual(["/custom/bin", "/opt/bin", "/usr/bin"]);
|
||||
@@ -126,6 +130,7 @@ describe("exec PATH login shell merge", () => {
|
||||
const tool = createExecTool({ host: "gateway", security: "full", ask: "off" });
|
||||
const result = await tool.execute("call-openclaw-shell", {
|
||||
command: 'printf "%s" "${OPENCLAW_SHELL:-}"',
|
||||
yieldMs: FOREGROUND_TEST_YIELD_MS,
|
||||
});
|
||||
const value = normalizeText(result.content.find((c) => c.type === "text")?.text);
|
||||
|
||||
@@ -190,7 +195,10 @@ describe("exec PATH login shell merge", () => {
|
||||
);
|
||||
|
||||
const tool = createExecTool({ host: "gateway", security: "full", ask: "off" });
|
||||
const result = await tool.execute("call1", { command: "echo $PATH" });
|
||||
const result = await tool.execute("call1", {
|
||||
command: "echo $PATH",
|
||||
yieldMs: FOREGROUND_TEST_YIELD_MS,
|
||||
});
|
||||
const entries = normalizePathEntries(result.content.find((c) => c.type === "text")?.text);
|
||||
|
||||
expect(entries).toEqual(["/usr/bin"]);
|
||||
@@ -245,6 +253,7 @@ describe("exec host env validation", () => {
|
||||
const tool = createExecTool({ host: "gateway", security: "full", ask: "off" });
|
||||
const result = await tool.execute("call1", {
|
||||
command: "printf '%s' \"${SSLKEYLOGFILE:-}\"",
|
||||
yieldMs: FOREGROUND_TEST_YIELD_MS,
|
||||
});
|
||||
const output = normalizeText(result.content.find((c) => c.type === "text")?.text);
|
||||
expect(output).not.toContain("/tmp/openclaw-ssl-keys.log");
|
||||
@@ -262,6 +271,7 @@ describe("exec host env validation", () => {
|
||||
|
||||
const result = await tool.execute("call1", {
|
||||
command: "echo ok",
|
||||
yieldMs: FOREGROUND_TEST_YIELD_MS,
|
||||
});
|
||||
expect(normalizeText(result.content.find((c) => c.type === "text")?.text)).toBe("ok");
|
||||
});
|
||||
|
||||
@@ -16,6 +16,8 @@ import { withTempConfig } from "./test-temp-config.js";
|
||||
|
||||
installGatewayTestHooks({ scope: "suite" });
|
||||
|
||||
const PREAUTH_HANDSHAKE_TEST_CLOSE_LIMIT_MS = 5_000;
|
||||
|
||||
let cleanupEnv: Array<() => void> = [];
|
||||
|
||||
afterEach(async () => {
|
||||
@@ -124,7 +126,7 @@ describe("gateway pre-auth hardening", () => {
|
||||
});
|
||||
expect(close.code).toBe(1000);
|
||||
expect(close.elapsedMs).toBeGreaterThan(0);
|
||||
expect(close.elapsedMs).toBeLessThan(2_500);
|
||||
expect(close.elapsedMs).toBeLessThan(PREAUTH_HANDSHAKE_TEST_CLOSE_LIMIT_MS);
|
||||
} finally {
|
||||
await harness.close();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
const {
|
||||
applyParallelVitestCachePaths,
|
||||
buildFullSuiteVitestRunPlans,
|
||||
buildVitestArgs,
|
||||
buildVitestRunPlans,
|
||||
@@ -8,6 +9,19 @@ const {
|
||||
parseTestProjectsArgs,
|
||||
resolveParallelFullSuiteConcurrency,
|
||||
} = (await import("../../scripts/test-projects.test-support.mjs")) as unknown as {
|
||||
applyParallelVitestCachePaths: (
|
||||
specs: Array<{
|
||||
config: string;
|
||||
env: NodeJS.ProcessEnv;
|
||||
}>,
|
||||
params?: {
|
||||
cwd?: string;
|
||||
env?: NodeJS.ProcessEnv;
|
||||
},
|
||||
) => Array<{
|
||||
config: string;
|
||||
env: NodeJS.ProcessEnv;
|
||||
}>;
|
||||
buildFullSuiteVitestRunPlans: (
|
||||
args: string[],
|
||||
cwd?: string,
|
||||
@@ -470,6 +484,60 @@ describe("test-projects args", () => {
|
||||
).toBe(3);
|
||||
});
|
||||
|
||||
it("uses a bounded local default for full-suite project parallelism", () => {
|
||||
expect(
|
||||
resolveParallelFullSuiteConcurrency(58, {
|
||||
OPENCLAW_TEST_PROJECTS_LEAF_SHARDS: "1",
|
||||
}),
|
||||
).toBe(4);
|
||||
});
|
||||
|
||||
it("gives parallel Vitest shards separate filesystem module caches", () => {
|
||||
const specs = applyParallelVitestCachePaths(
|
||||
[
|
||||
{
|
||||
config: "test/vitest/vitest.gateway.config.ts",
|
||||
env: { KEEP_ME: "1" },
|
||||
},
|
||||
{
|
||||
config: "test/vitest/vitest.gateway-server.config.ts",
|
||||
env: {},
|
||||
},
|
||||
],
|
||||
{
|
||||
cwd: "/repo",
|
||||
env: {},
|
||||
},
|
||||
);
|
||||
|
||||
expect(specs[0]?.env).toMatchObject({
|
||||
KEEP_ME: "1",
|
||||
OPENCLAW_VITEST_FS_MODULE_CACHE_PATH:
|
||||
"/repo/node_modules/.experimental-vitest-cache/0-test-vitest-vitest.gateway.config.ts",
|
||||
});
|
||||
expect(specs[1]?.env.OPENCLAW_VITEST_FS_MODULE_CACHE_PATH).toBe(
|
||||
"/repo/node_modules/.experimental-vitest-cache/1-test-vitest-vitest.gateway-server.config.ts",
|
||||
);
|
||||
});
|
||||
|
||||
it("preserves explicit Vitest filesystem module cache paths", () => {
|
||||
const specs = [
|
||||
{
|
||||
config: "test/vitest/vitest.gateway.config.ts",
|
||||
env: {},
|
||||
},
|
||||
];
|
||||
|
||||
expect(
|
||||
applyParallelVitestCachePaths(specs, {
|
||||
cwd: "/repo",
|
||||
env: {
|
||||
OPENCLAW_VITEST_FS_MODULE_CACHE_PATH: "/tmp/cache",
|
||||
},
|
||||
}),
|
||||
).toBe(specs);
|
||||
});
|
||||
|
||||
it("routes cli targets to the cli config", () => {
|
||||
expect(buildVitestRunPlans(["src/cli/test-runtime-capture.test.ts"])).toEqual([
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user