@@ -17,7 +17,10 @@ import { tmpdir } from "node:os";
|
17 | 17 | import { basename, delimiter, join, win32 } from "node:path"; |
18 | 18 | import { setTimeout as delay } from "node:timers/promises"; |
19 | 19 | import { pathToFileURL } from "node:url"; |
20 | | -import { MAX_TIMER_TIMEOUT_MS } from "@openclaw/normalization-core/number-coercion"; |
| 20 | +import { |
| 21 | +MAX_TIMER_TIMEOUT_MS, |
| 22 | +MAX_TIMER_TIMEOUT_SECONDS, |
| 23 | +} from "@openclaw/normalization-core/number-coercion"; |
21 | 24 | import { afterEach, beforeAll, describe, expect, it, vi } from "vitest"; |
22 | 25 | import { |
23 | 26 | extractLastOpenClawVersionFromLog, |
@@ -1271,6 +1274,24 @@ if (isPrlctl) {
|
1271 | 1274 | } |
1272 | 1275 | }); |
1273 | 1276 | |
| 1277 | +it("clamps oversized phase timers before scheduling", async () => { |
| 1278 | +const runDir = makeTempDir(tempDirs, "openclaw-parallels-phase-timeout-"); |
| 1279 | +const phaseRunner = new PhaseRunner(runDir, 128); |
| 1280 | +const setTimeoutSpy = vi.spyOn(globalThis, "setTimeout"); |
| 1281 | + |
| 1282 | +try { |
| 1283 | +await expect( |
| 1284 | +phaseRunner.phase("oversized", MAX_TIMER_TIMEOUT_SECONDS + 1, () => undefined), |
| 1285 | +).resolves.toBeUndefined(); |
| 1286 | +expect(setTimeoutSpy).toHaveBeenCalledWith(expect.any(Function), MAX_TIMER_TIMEOUT_MS); |
| 1287 | +expect(readFileSync(join(runDir, "phase-timings.json"), "utf8")).toContain( |
| 1288 | +`"timeoutSeconds": ${MAX_TIMER_TIMEOUT_SECONDS + 1}`, |
| 1289 | +); |
| 1290 | +} finally { |
| 1291 | +setTimeoutSpy.mockRestore(); |
| 1292 | +} |
| 1293 | +}); |
| 1294 | + |
1274 | 1295 | it("runs POSIX guest shell scripts with a normal install umask", () => { |
1275 | 1296 | const guestTransports = readFileSync(TS_PATHS.guestTransports, "utf8"); |
1276 | 1297 | |
|