diff --git a/scripts/test-perf-budget.mjs b/scripts/test-perf-budget.mjs index e01d27690dd..8d2045af197 100644 --- a/scripts/test-perf-budget.mjs +++ b/scripts/test-perf-budget.mjs @@ -1,6 +1,6 @@ // Runs a Vitest config and enforces wall-time regression budgets. import { pathToFileURL } from "node:url"; -import { parseFlagArgs, stringFlag } from "./lib/arg-utils.mjs"; +import { booleanFlag, parseFlagArgs, stringFlag } from "./lib/arg-utils.mjs"; import { budgetFloatFlag, parseBudgetNumber, @@ -9,22 +9,35 @@ import { import { formatMs } from "./lib/vitest-report-cli-utils.mjs"; import { readJsonFile, runVitestJsonReport } from "./test-report-utils.mjs"; +function readBooleanEnv(name, env = process.env) { + const normalized = env[name]?.trim().toLowerCase(); + return normalized === "1" || normalized === "true" || normalized === "yes"; +} + function parseArgs(argv, env = process.env) { - return parseFlagArgs( + const opts = parseFlagArgs( argv, { config: "test/vitest/vitest.unit.config.ts", maxWallMs: readBudgetEnvNumber("OPENCLAW_TEST_PERF_MAX_WALL_MS", env), baselineWallMs: readBudgetEnvNumber("OPENCLAW_TEST_PERF_BASELINE_WALL_MS", env), maxRegressionPct: readBudgetEnvNumber("OPENCLAW_TEST_PERF_MAX_REGRESSION_PCT", env) ?? 10, + reportOnly: readBooleanEnv("OPENCLAW_TEST_PERF_REPORT_ONLY", env), }, [ stringFlag("--config", "config"), budgetFloatFlag("--max-wall-ms", "maxWallMs"), budgetFloatFlag("--baseline-wall-ms", "baselineWallMs"), budgetFloatFlag("--max-regression-pct", "maxRegressionPct"), + booleanFlag("--report-only", "reportOnly", true), ], ); + if (opts.maxWallMs === null && opts.baselineWallMs === null && opts.reportOnly !== true) { + throw new Error( + "[test-perf-budget] provide --max-wall-ms, --baseline-wall-ms, or set --report-only for an explicit timing-only run", + ); + } + return opts; } function formatErrorMessage(error) { diff --git a/test/scripts/test-perf-budget.test.ts b/test/scripts/test-perf-budget.test.ts index 8fbe460a541..a7b4a6793a3 100644 --- a/test/scripts/test-perf-budget.test.ts +++ b/test/scripts/test-perf-budget.test.ts @@ -19,6 +19,32 @@ function withReport(payload: unknown, run: (reportPath: string) => void) { } describe("test perf budget script", () => { + it("requires a budget source unless report-only mode is explicit", () => { + expect(() => testing.parseArgs([], {})).toThrow( + "provide --max-wall-ms, --baseline-wall-ms, or set --report-only", + ); + expect(testing.parseArgs(["--report-only"], {})).toMatchObject({ + baselineWallMs: null, + maxWallMs: null, + reportOnly: true, + }); + expect( + testing.parseArgs([], { + OPENCLAW_TEST_PERF_REPORT_ONLY: "yes", + }), + ).toMatchObject({ + baselineWallMs: null, + maxWallMs: null, + reportOnly: true, + }); + expect(testing.parseArgs(["--baseline-wall-ms", "1000"], {})).toMatchObject({ + baselineWallMs: 1000, + maxRegressionPct: 10, + maxWallMs: null, + reportOnly: false, + }); + }); + it("parses numeric budget env vars strictly before running Vitest", () => { expect( testing.parseArgs([], {