fix(test): extend watchdog for slow vitest shards

This commit is contained in:
Vincent Koc
2026-06-13 21:37:57 +08:00
parent 68e234f9e2
commit 27e24ca683
4 changed files with 97 additions and 15 deletions
+23 -14
View File
@@ -25,6 +25,8 @@ export const DEFAULT_VITEST_NO_OUTPUT_TIMEOUT_MS = 120_000;
export const DEFAULT_VITEST_NO_OUTPUT_HEARTBEAT_MS = 30_000;
/** Longer watchdog timeout for known long-running Vitest configs. */
export const DEFAULT_LONG_RUNNING_VITEST_NO_OUTPUT_TIMEOUT_MS = 300_000;
/** Extra-long watchdog timeout for broad configs that can stay silent on macOS. */
export const DEFAULT_EXTRA_LONG_RUNNING_VITEST_NO_OUTPUT_TIMEOUT_MS = 2_400_000;
const VITEST_NO_OUTPUT_TIMEOUT_ENV_KEY = "OPENCLAW_VITEST_NO_OUTPUT_TIMEOUT_MS";
const VITEST_NO_OUTPUT_HEARTBEAT_ENV_KEY = "OPENCLAW_VITEST_NO_OUTPUT_HEARTBEAT_MS";
const UI_VITEST_CONFIG = "test/vitest/vitest.ui.config.ts";
@@ -32,12 +34,20 @@ const UNIT_UI_VITEST_CONFIG = "test/vitest/vitest.unit-ui.config.ts";
const TOOLING_DOCKER_VITEST_CONFIG = "test/vitest/vitest.tooling-docker.config.ts";
const TOOLING_VITEST_CONFIG = "test/vitest/vitest.tooling.config.ts";
const GATEWAY_VITEST_CONFIG = "test/vitest/vitest.gateway.config.ts";
const LONG_RUNNING_VITEST_CONFIGS = new Set([
"test/vitest/vitest.e2e.config.ts",
GATEWAY_VITEST_CONFIG,
"test/vitest/vitest.ui-e2e.config.ts",
"test/vitest/vitest.full-agentic.config.ts",
"test/vitest/vitest.full-core-contracts.config.ts",
const VITEST_CONFIG_NO_OUTPUT_TIMEOUT_MS = new Map([
["test/vitest/vitest.e2e.config.ts", DEFAULT_LONG_RUNNING_VITEST_NO_OUTPUT_TIMEOUT_MS],
[GATEWAY_VITEST_CONFIG, DEFAULT_LONG_RUNNING_VITEST_NO_OUTPUT_TIMEOUT_MS],
["test/vitest/vitest.ui-e2e.config.ts", DEFAULT_LONG_RUNNING_VITEST_NO_OUTPUT_TIMEOUT_MS],
["test/vitest/vitest.full-agentic.config.ts", DEFAULT_LONG_RUNNING_VITEST_NO_OUTPUT_TIMEOUT_MS],
[
"test/vitest/vitest.full-core-contracts.config.ts",
DEFAULT_LONG_RUNNING_VITEST_NO_OUTPUT_TIMEOUT_MS,
],
[
"test/vitest/vitest.contracts-plugin.config.ts",
DEFAULT_EXTRA_LONG_RUNNING_VITEST_NO_OUTPUT_TIMEOUT_MS,
],
["test/vitest/vitest.infra.config.ts", DEFAULT_EXTRA_LONG_RUNNING_VITEST_NO_OUTPUT_TIMEOUT_MS],
]);
const TOOLING_EXCLUDED_TESTS = new Set([
...boundaryTestFiles,
@@ -362,10 +372,9 @@ export function resolveRunVitestSpawnEnv(env = process.env, argv = []) {
*/
export function resolveDefaultVitestNoOutputTimeoutMs(argv = []) {
const config = resolveVitestConfigArg(argv);
if (config !== null && isLongRunningVitestConfig(config)) {
return DEFAULT_LONG_RUNNING_VITEST_NO_OUTPUT_TIMEOUT_MS;
}
return DEFAULT_VITEST_NO_OUTPUT_TIMEOUT_MS;
return config === null
? DEFAULT_VITEST_NO_OUTPUT_TIMEOUT_MS
: (resolveVitestConfigNoOutputTimeoutMs(config) ?? DEFAULT_VITEST_NO_OUTPUT_TIMEOUT_MS);
}
function resolveVitestConfigArg(argv) {
@@ -384,14 +393,14 @@ function resolveVitestConfigArg(argv) {
return null;
}
function isLongRunningVitestConfig(config) {
function resolveVitestConfigNoOutputTimeoutMs(config) {
const normalized = path.normalize(config).replaceAll(path.sep, "/").replace(/^\.\//u, "");
for (const candidate of LONG_RUNNING_VITEST_CONFIGS) {
for (const [candidate, timeoutMs] of VITEST_CONFIG_NO_OUTPUT_TIMEOUT_MS) {
if (normalized === candidate || normalized.endsWith(`/${candidate}`)) {
return true;
return timeoutMs;
}
}
return false;
return null;
}
/**
+10 -1
View File
@@ -55,6 +55,7 @@ import {
import { isCiLikeEnv, resolveLocalFullSuiteProfile } from "./lib/vitest-local-scheduling.mjs";
import {
DEFAULT_VITEST_NO_OUTPUT_HEARTBEAT_MS,
resolveDefaultVitestNoOutputTimeoutMs,
resolveVitestCliEntry,
resolveVitestNodeArgs,
} from "./run-vitest.mjs";
@@ -865,6 +866,12 @@ const GATEWAY_SERVER_EXCLUDED_TEST_TARGETS = new Set([
"src/gateway/server.startup-matrix-migration.integration.test.ts",
"src/gateway/sessions-history-http.test.ts",
]);
function resolveTestProjectsVitestNoOutputTimeoutMs(config) {
const directRunnerTimeoutMs = resolveDefaultVitestNoOutputTimeoutMs(["run", "--config", config]);
return String(
Math.max(Number(DEFAULT_TEST_PROJECTS_VITEST_NO_OUTPUT_TIMEOUT_MS), directRunnerTimeoutMs),
);
}
const VITEST_CONFIG_TARGET_KIND_BY_PATH = new Map(
Object.entries(VITEST_CONFIG_BY_KIND).map(([kind, config]) => [config, kind]),
);
@@ -2601,7 +2608,9 @@ export function applyDefaultVitestNoOutputTimeout(specs, params = {}) {
!Object.hasOwn(baseEnv, VITEST_NO_OUTPUT_TIMEOUT_ENV_KEY) &&
!Object.hasOwn(env, VITEST_NO_OUTPUT_TIMEOUT_ENV_KEY)
) {
nextEnv[VITEST_NO_OUTPUT_TIMEOUT_ENV_KEY] = DEFAULT_TEST_PROJECTS_VITEST_NO_OUTPUT_TIMEOUT_MS;
nextEnv[VITEST_NO_OUTPUT_TIMEOUT_ENV_KEY] = resolveTestProjectsVitestNoOutputTimeoutMs(
spec.config,
);
}
if (
!Object.hasOwn(baseEnv, VITEST_NO_OUTPUT_HEARTBEAT_ENV_KEY) &&
+26
View File
@@ -7,6 +7,7 @@ import nodePath from "node:path";
import { setTimeout as delay } from "node:timers/promises";
import { describe, expect, it, vi } from "vitest";
import {
DEFAULT_EXTRA_LONG_RUNNING_VITEST_NO_OUTPUT_TIMEOUT_MS,
DEFAULT_LONG_RUNNING_VITEST_NO_OUTPUT_TIMEOUT_MS,
installVitestNoOutputWatchdog,
resolveDefaultVitestNoOutputTimeoutMs,
@@ -473,6 +474,7 @@ describe("scripts/run-vitest", () => {
it("uses a longer default stall watchdog for broad e2e and project shard configs", () => {
const timeout = String(DEFAULT_LONG_RUNNING_VITEST_NO_OUTPUT_TIMEOUT_MS);
const extraLongTimeout = String(DEFAULT_EXTRA_LONG_RUNNING_VITEST_NO_OUTPUT_TIMEOUT_MS);
for (const configArg of [
"--config=test/vitest/vitest.e2e.config.ts",
@@ -487,6 +489,16 @@ describe("scripts/run-vitest", () => {
OPENCLAW_VITEST_NO_OUTPUT_TIMEOUT_MS: timeout,
});
}
for (const configArg of [
"--config=test/vitest/vitest.contracts-plugin.config.ts",
"--config=test/vitest/vitest.infra.config.ts",
]) {
expect(resolveRunVitestSpawnEnv({ PATH: "/usr/bin" }, ["run", configArg])).toEqual({
PATH: "/usr/bin",
OPENCLAW_VITEST_NO_OUTPUT_HEARTBEAT_MS: "30000",
OPENCLAW_VITEST_NO_OUTPUT_TIMEOUT_MS: extraLongTimeout,
});
}
expect(
resolveDefaultVitestNoOutputTimeoutMs([
"run",
@@ -515,6 +527,20 @@ describe("scripts/run-vitest", () => {
"/repo/test/vitest/vitest.full-core-contracts.config.ts",
]),
).toBe(DEFAULT_LONG_RUNNING_VITEST_NO_OUTPUT_TIMEOUT_MS);
expect(
resolveDefaultVitestNoOutputTimeoutMs([
"run",
"--config",
"/repo/test/vitest/vitest.contracts-plugin.config.ts",
]),
).toBe(DEFAULT_EXTRA_LONG_RUNNING_VITEST_NO_OUTPUT_TIMEOUT_MS);
expect(
resolveDefaultVitestNoOutputTimeoutMs([
"run",
"--config",
"/repo/test/vitest/vitest.infra.config.ts",
]),
).toBe(DEFAULT_EXTRA_LONG_RUNNING_VITEST_NO_OUTPUT_TIMEOUT_MS);
});
it("does not default implicit interactive runs to the stall watchdog", () => {
+38
View File
@@ -2716,6 +2716,44 @@ describe("scripts/test-projects Vitest stall watchdog", () => {
);
});
it("extends the no-output watchdog for slow silent full-suite configs", () => {
const specs = applyDefaultVitestNoOutputTimeout(
[
{
config: "test/vitest/vitest.contracts-plugin.config.ts",
env: { PATH: "/usr/bin" },
includeFilePath: null,
includePatterns: null,
pnpmArgs: [],
watchMode: false,
},
{
config: "test/vitest/vitest.infra.config.ts",
env: { PATH: "/usr/bin" },
includeFilePath: null,
includePatterns: null,
pnpmArgs: [],
watchMode: false,
},
{
config: "test/vitest/vitest.extension-feishu.config.ts",
env: { PATH: "/usr/bin" },
includeFilePath: null,
includePatterns: null,
pnpmArgs: [],
watchMode: false,
},
],
{ env: { PATH: "/usr/bin" } },
);
expect(specs[0]?.env.OPENCLAW_VITEST_NO_OUTPUT_TIMEOUT_MS).toBe("2400000");
expect(specs[1]?.env.OPENCLAW_VITEST_NO_OUTPUT_TIMEOUT_MS).toBe("2400000");
expect(specs[2]?.env.OPENCLAW_VITEST_NO_OUTPUT_TIMEOUT_MS).toBe(
DEFAULT_TEST_PROJECTS_VITEST_NO_OUTPUT_TIMEOUT_MS,
);
});
it("keeps explicit watchdog settings and watch mode untouched", () => {
const specs = applyDefaultVitestNoOutputTimeout(
[