Files
openclaw/src/cli/parse-timeout.test.ts
openclaw-clownfish[bot] 99d0bdc23a fix(cli): validate gateway RPC timeout inputs
Reject malformed or explicit empty Gateway RPC timeout values before opening Gateway calls, align the shared Gateway RPC omitted-timeout fallback with the 30000 ms CLI default, and validate explicit `cron add --timeout-seconds` values at the CLI boundary.

Carries forward the useful source work from #54646 and the earlier timeout-validation context from #40953. #60661 remains separate accepted-run timeout semantics work and is intentionally not folded into this change.

Validation:
- `npm run review-results -- /tmp/clownfish-check-27341769444`
- `git diff --check`
- OpenClaw PR checks on `ce7bd8b9388a5689b14ddc2b3a984f7b4647e5ca`: 132 pass, 0 pending, 0 failing
- ClawSweeper re-review: https://github.com/openclaw/clawsweeper/actions/runs/27344244608

Co-authored-by: RayRuan <43744645+ruanrrn@users.noreply.github.com>
Co-authored-by: Homeran <11574611+comeran@users.noreply.github.com>
2026-06-11 20:52:07 +09:00

70 lines
2.7 KiB
TypeScript

// Parse timeout tests cover CLI timeout argument parsing and validation.
import { describe, expect, it } from "vitest";
import { parseTimeoutMs, parseTimeoutMsWithFallback } from "./parse-timeout.js";
describe("parseTimeoutMs", () => {
it("parses positive string values", () => {
expect(parseTimeoutMs("1500")).toBe(1500);
expect(parseTimeoutMs("+1500")).toBe(1500);
});
it("returns undefined for empty or invalid values", () => {
expect(parseTimeoutMs(undefined)).toBeUndefined();
expect(parseTimeoutMs("")).toBeUndefined();
expect(parseTimeoutMs("nope")).toBeUndefined();
expect(parseTimeoutMs("10abc")).toBeUndefined();
expect(parseTimeoutMs("1.5")).toBeUndefined();
expect(parseTimeoutMs("0x10")).toBeUndefined();
expect(parseTimeoutMs("0")).toBeUndefined();
});
});
describe("parseTimeoutMsWithFallback", () => {
it("returns the fallback for missing or empty values", () => {
expect(parseTimeoutMsWithFallback(undefined, 3000)).toBe(3000);
expect(parseTimeoutMsWithFallback(null, 3000)).toBe(3000);
expect(parseTimeoutMsWithFallback(" ", 3000)).toBe(3000);
});
it("parses positive numbers and strings", () => {
expect(parseTimeoutMsWithFallback(2500, 3000)).toBe(2500);
expect(parseTimeoutMsWithFallback(2500n, 3000)).toBe(2500);
expect(parseTimeoutMsWithFallback("2500", 3000)).toBe(2500);
expect(parseTimeoutMsWithFallback("+2500", 3000)).toBe(2500);
});
it("falls back on unsupported types by default", () => {
expect(parseTimeoutMsWithFallback({}, 3000)).toBe(3000);
});
it("throws on unsupported types when requested", () => {
expect(() => parseTimeoutMsWithFallback({}, 3000, { invalidType: "error" })).toThrow(
"Invalid --timeout",
);
});
it("throws on empty values when requested", () => {
expect(() => parseTimeoutMsWithFallback(" ", 3000, { invalidType: "error" })).toThrow(
"Invalid --timeout",
);
});
it("throws on non-positive parsed values", () => {
expect(() => parseTimeoutMsWithFallback("0", 3000)).toThrow('Received: "0"');
expect(() => parseTimeoutMsWithFallback("-1", 3000)).toThrow('Received: "-1"');
});
it("throws on malformed or unsafe parsed values", () => {
expect(() => parseTimeoutMsWithFallback("10abc", 3000)).toThrow('Received: "10abc"');
expect(() => parseTimeoutMsWithFallback("1.5", 3000)).toThrow('Received: "1.5"');
expect(() => parseTimeoutMsWithFallback("0x10", 3000)).toThrow('Received: "0x10"');
expect(() => parseTimeoutMsWithFallback(String(Number.MAX_SAFE_INTEGER + 1), 3000)).toThrow(
"Received",
);
});
it("throws on partial-numeric values", () => {
expect(() => parseTimeoutMsWithFallback("1000ms", 3000)).toThrow('Received: "1000ms"');
});
});