Skip to content

Commit 27e24ca

Browse files
committed
fix(test): extend watchdog for slow vitest shards
1 parent 68e234f commit 27e24ca

4 files changed

Lines changed: 97 additions & 15 deletions

File tree

scripts/run-vitest.mjs

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25,19 +25,29 @@ export const DEFAULT_VITEST_NO_OUTPUT_TIMEOUT_MS = 120_000;
2525
export const DEFAULT_VITEST_NO_OUTPUT_HEARTBEAT_MS = 30_000;
2626
/** Longer watchdog timeout for known long-running Vitest configs. */
2727
export const DEFAULT_LONG_RUNNING_VITEST_NO_OUTPUT_TIMEOUT_MS = 300_000;
28+
/** Extra-long watchdog timeout for broad configs that can stay silent on macOS. */
29+
export const DEFAULT_EXTRA_LONG_RUNNING_VITEST_NO_OUTPUT_TIMEOUT_MS = 2_400_000;
2830
const VITEST_NO_OUTPUT_TIMEOUT_ENV_KEY = "OPENCLAW_VITEST_NO_OUTPUT_TIMEOUT_MS";
2931
const VITEST_NO_OUTPUT_HEARTBEAT_ENV_KEY = "OPENCLAW_VITEST_NO_OUTPUT_HEARTBEAT_MS";
3032
const UI_VITEST_CONFIG = "test/vitest/vitest.ui.config.ts";
3133
const UNIT_UI_VITEST_CONFIG = "test/vitest/vitest.unit-ui.config.ts";
3234
const TOOLING_DOCKER_VITEST_CONFIG = "test/vitest/vitest.tooling-docker.config.ts";
3335
const TOOLING_VITEST_CONFIG = "test/vitest/vitest.tooling.config.ts";
3436
const GATEWAY_VITEST_CONFIG = "test/vitest/vitest.gateway.config.ts";
35-
const LONG_RUNNING_VITEST_CONFIGS = new Set([
36-
"test/vitest/vitest.e2e.config.ts",
37-
GATEWAY_VITEST_CONFIG,
38-
"test/vitest/vitest.ui-e2e.config.ts",
39-
"test/vitest/vitest.full-agentic.config.ts",
40-
"test/vitest/vitest.full-core-contracts.config.ts",
37+
const VITEST_CONFIG_NO_OUTPUT_TIMEOUT_MS = new Map([
38+
["test/vitest/vitest.e2e.config.ts", DEFAULT_LONG_RUNNING_VITEST_NO_OUTPUT_TIMEOUT_MS],
39+
[GATEWAY_VITEST_CONFIG, DEFAULT_LONG_RUNNING_VITEST_NO_OUTPUT_TIMEOUT_MS],
40+
["test/vitest/vitest.ui-e2e.config.ts", DEFAULT_LONG_RUNNING_VITEST_NO_OUTPUT_TIMEOUT_MS],
41+
["test/vitest/vitest.full-agentic.config.ts", DEFAULT_LONG_RUNNING_VITEST_NO_OUTPUT_TIMEOUT_MS],
42+
[
43+
"test/vitest/vitest.full-core-contracts.config.ts",
44+
DEFAULT_LONG_RUNNING_VITEST_NO_OUTPUT_TIMEOUT_MS,
45+
],
46+
[
47+
"test/vitest/vitest.contracts-plugin.config.ts",
48+
DEFAULT_EXTRA_LONG_RUNNING_VITEST_NO_OUTPUT_TIMEOUT_MS,
49+
],
50+
["test/vitest/vitest.infra.config.ts", DEFAULT_EXTRA_LONG_RUNNING_VITEST_NO_OUTPUT_TIMEOUT_MS],
4151
]);
4252
const TOOLING_EXCLUDED_TESTS = new Set([
4353
...boundaryTestFiles,
@@ -362,10 +372,9 @@ export function resolveRunVitestSpawnEnv(env = process.env, argv = []) {
362372
*/
363373
export function resolveDefaultVitestNoOutputTimeoutMs(argv = []) {
364374
const config = resolveVitestConfigArg(argv);
365-
if (config !== null && isLongRunningVitestConfig(config)) {
366-
return DEFAULT_LONG_RUNNING_VITEST_NO_OUTPUT_TIMEOUT_MS;
367-
}
368-
return DEFAULT_VITEST_NO_OUTPUT_TIMEOUT_MS;
375+
return config === null
376+
? DEFAULT_VITEST_NO_OUTPUT_TIMEOUT_MS
377+
: (resolveVitestConfigNoOutputTimeoutMs(config) ?? DEFAULT_VITEST_NO_OUTPUT_TIMEOUT_MS);
369378
}
370379

371380
function resolveVitestConfigArg(argv) {
@@ -384,14 +393,14 @@ function resolveVitestConfigArg(argv) {
384393
return null;
385394
}
386395

387-
function isLongRunningVitestConfig(config) {
396+
function resolveVitestConfigNoOutputTimeoutMs(config) {
388397
const normalized = path.normalize(config).replaceAll(path.sep, "/").replace(/^\.\//u, "");
389-
for (const candidate of LONG_RUNNING_VITEST_CONFIGS) {
398+
for (const [candidate, timeoutMs] of VITEST_CONFIG_NO_OUTPUT_TIMEOUT_MS) {
390399
if (normalized === candidate || normalized.endsWith(`/${candidate}`)) {
391-
return true;
400+
return timeoutMs;
392401
}
393402
}
394-
return false;
403+
return null;
395404
}
396405

397406
/**

scripts/test-projects.test-support.mjs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ import {
5555
import { isCiLikeEnv, resolveLocalFullSuiteProfile } from "./lib/vitest-local-scheduling.mjs";
5656
import {
5757
DEFAULT_VITEST_NO_OUTPUT_HEARTBEAT_MS,
58+
resolveDefaultVitestNoOutputTimeoutMs,
5859
resolveVitestCliEntry,
5960
resolveVitestNodeArgs,
6061
} from "./run-vitest.mjs";
@@ -865,6 +866,12 @@ const GATEWAY_SERVER_EXCLUDED_TEST_TARGETS = new Set([
865866
"src/gateway/server.startup-matrix-migration.integration.test.ts",
866867
"src/gateway/sessions-history-http.test.ts",
867868
]);
869+
function resolveTestProjectsVitestNoOutputTimeoutMs(config) {
870+
const directRunnerTimeoutMs = resolveDefaultVitestNoOutputTimeoutMs(["run", "--config", config]);
871+
return String(
872+
Math.max(Number(DEFAULT_TEST_PROJECTS_VITEST_NO_OUTPUT_TIMEOUT_MS), directRunnerTimeoutMs),
873+
);
874+
}
868875
const VITEST_CONFIG_TARGET_KIND_BY_PATH = new Map(
869876
Object.entries(VITEST_CONFIG_BY_KIND).map(([kind, config]) => [config, kind]),
870877
);
@@ -2601,7 +2608,9 @@ export function applyDefaultVitestNoOutputTimeout(specs, params = {}) {
26012608
!Object.hasOwn(baseEnv, VITEST_NO_OUTPUT_TIMEOUT_ENV_KEY) &&
26022609
!Object.hasOwn(env, VITEST_NO_OUTPUT_TIMEOUT_ENV_KEY)
26032610
) {
2604-
nextEnv[VITEST_NO_OUTPUT_TIMEOUT_ENV_KEY] = DEFAULT_TEST_PROJECTS_VITEST_NO_OUTPUT_TIMEOUT_MS;
2611+
nextEnv[VITEST_NO_OUTPUT_TIMEOUT_ENV_KEY] = resolveTestProjectsVitestNoOutputTimeoutMs(
2612+
spec.config,
2613+
);
26052614
}
26062615
if (
26072616
!Object.hasOwn(baseEnv, VITEST_NO_OUTPUT_HEARTBEAT_ENV_KEY) &&

test/scripts/run-vitest.test.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import nodePath from "node:path";
77
import { setTimeout as delay } from "node:timers/promises";
88
import { describe, expect, it, vi } from "vitest";
99
import {
10+
DEFAULT_EXTRA_LONG_RUNNING_VITEST_NO_OUTPUT_TIMEOUT_MS,
1011
DEFAULT_LONG_RUNNING_VITEST_NO_OUTPUT_TIMEOUT_MS,
1112
installVitestNoOutputWatchdog,
1213
resolveDefaultVitestNoOutputTimeoutMs,
@@ -473,6 +474,7 @@ describe("scripts/run-vitest", () => {
473474

474475
it("uses a longer default stall watchdog for broad e2e and project shard configs", () => {
475476
const timeout = String(DEFAULT_LONG_RUNNING_VITEST_NO_OUTPUT_TIMEOUT_MS);
477+
const extraLongTimeout = String(DEFAULT_EXTRA_LONG_RUNNING_VITEST_NO_OUTPUT_TIMEOUT_MS);
476478

477479
for (const configArg of [
478480
"--config=test/vitest/vitest.e2e.config.ts",
@@ -487,6 +489,16 @@ describe("scripts/run-vitest", () => {
487489
OPENCLAW_VITEST_NO_OUTPUT_TIMEOUT_MS: timeout,
488490
});
489491
}
492+
for (const configArg of [
493+
"--config=test/vitest/vitest.contracts-plugin.config.ts",
494+
"--config=test/vitest/vitest.infra.config.ts",
495+
]) {
496+
expect(resolveRunVitestSpawnEnv({ PATH: "/usr/bin" }, ["run", configArg])).toEqual({
497+
PATH: "/usr/bin",
498+
OPENCLAW_VITEST_NO_OUTPUT_HEARTBEAT_MS: "30000",
499+
OPENCLAW_VITEST_NO_OUTPUT_TIMEOUT_MS: extraLongTimeout,
500+
});
501+
}
490502
expect(
491503
resolveDefaultVitestNoOutputTimeoutMs([
492504
"run",
@@ -515,6 +527,20 @@ describe("scripts/run-vitest", () => {
515527
"/repo/test/vitest/vitest.full-core-contracts.config.ts",
516528
]),
517529
).toBe(DEFAULT_LONG_RUNNING_VITEST_NO_OUTPUT_TIMEOUT_MS);
530+
expect(
531+
resolveDefaultVitestNoOutputTimeoutMs([
532+
"run",
533+
"--config",
534+
"/repo/test/vitest/vitest.contracts-plugin.config.ts",
535+
]),
536+
).toBe(DEFAULT_EXTRA_LONG_RUNNING_VITEST_NO_OUTPUT_TIMEOUT_MS);
537+
expect(
538+
resolveDefaultVitestNoOutputTimeoutMs([
539+
"run",
540+
"--config",
541+
"/repo/test/vitest/vitest.infra.config.ts",
542+
]),
543+
).toBe(DEFAULT_EXTRA_LONG_RUNNING_VITEST_NO_OUTPUT_TIMEOUT_MS);
518544
});
519545

520546
it("does not default implicit interactive runs to the stall watchdog", () => {

test/scripts/test-projects.test.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2716,6 +2716,44 @@ describe("scripts/test-projects Vitest stall watchdog", () => {
27162716
);
27172717
});
27182718

2719+
it("extends the no-output watchdog for slow silent full-suite configs", () => {
2720+
const specs = applyDefaultVitestNoOutputTimeout(
2721+
[
2722+
{
2723+
config: "test/vitest/vitest.contracts-plugin.config.ts",
2724+
env: { PATH: "/usr/bin" },
2725+
includeFilePath: null,
2726+
includePatterns: null,
2727+
pnpmArgs: [],
2728+
watchMode: false,
2729+
},
2730+
{
2731+
config: "test/vitest/vitest.infra.config.ts",
2732+
env: { PATH: "/usr/bin" },
2733+
includeFilePath: null,
2734+
includePatterns: null,
2735+
pnpmArgs: [],
2736+
watchMode: false,
2737+
},
2738+
{
2739+
config: "test/vitest/vitest.extension-feishu.config.ts",
2740+
env: { PATH: "/usr/bin" },
2741+
includeFilePath: null,
2742+
includePatterns: null,
2743+
pnpmArgs: [],
2744+
watchMode: false,
2745+
},
2746+
],
2747+
{ env: { PATH: "/usr/bin" } },
2748+
);
2749+
2750+
expect(specs[0]?.env.OPENCLAW_VITEST_NO_OUTPUT_TIMEOUT_MS).toBe("2400000");
2751+
expect(specs[1]?.env.OPENCLAW_VITEST_NO_OUTPUT_TIMEOUT_MS).toBe("2400000");
2752+
expect(specs[2]?.env.OPENCLAW_VITEST_NO_OUTPUT_TIMEOUT_MS).toBe(
2753+
DEFAULT_TEST_PROJECTS_VITEST_NO_OUTPUT_TIMEOUT_MS,
2754+
);
2755+
});
2756+
27192757
it("keeps explicit watchdog settings and watch mode untouched", () => {
27202758
const specs = applyDefaultVitestNoOutputTimeout(
27212759
[

0 commit comments

Comments
 (0)