mirror of
https://github.com/openclaw/openclaw.git
synced 2026-06-03 20:44:07 +00:00
101 lines
3.0 KiB
JavaScript
101 lines
3.0 KiB
JavaScript
import { pathToFileURL } from "node:url";
|
|
import { parseFlagArgs, stringFlag } from "./lib/arg-utils.mjs";
|
|
import {
|
|
budgetFloatFlag,
|
|
parseBudgetNumber,
|
|
readBudgetEnvNumber,
|
|
} from "./lib/budget-number-args.mjs";
|
|
import { formatMs } from "./lib/vitest-report-cli-utils.mjs";
|
|
import { readJsonFile, runVitestJsonReport } from "./test-report-utils.mjs";
|
|
|
|
function parseArgs(argv, env = process.env) {
|
|
return 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,
|
|
},
|
|
[
|
|
stringFlag("--config", "config"),
|
|
budgetFloatFlag("--max-wall-ms", "maxWallMs"),
|
|
budgetFloatFlag("--baseline-wall-ms", "baselineWallMs"),
|
|
budgetFloatFlag("--max-regression-pct", "maxRegressionPct"),
|
|
],
|
|
);
|
|
}
|
|
|
|
function main() {
|
|
let opts;
|
|
try {
|
|
opts = parseArgs(process.argv.slice(2));
|
|
} catch (error) {
|
|
console.error(error instanceof Error ? error.message : String(error));
|
|
process.exit(1);
|
|
}
|
|
|
|
const startedAt = process.hrtime.bigint();
|
|
const reportPath = runVitestJsonReport({
|
|
config: opts.config,
|
|
prefix: "openclaw-vitest-perf",
|
|
});
|
|
const elapsedMs = Number.parseFloat(String(process.hrtime.bigint() - startedAt)) / 1_000_000;
|
|
|
|
let totalFileDurationMs = 0;
|
|
let fileCount = 0;
|
|
try {
|
|
const report = readJsonFile(reportPath);
|
|
for (const result of report.testResults ?? []) {
|
|
if (typeof result.startTime === "number" && typeof result.endTime === "number") {
|
|
totalFileDurationMs += Math.max(0, result.endTime - result.startTime);
|
|
fileCount += 1;
|
|
}
|
|
}
|
|
} catch {
|
|
// Keep budget checks based on wall time when JSON parsing fails.
|
|
}
|
|
|
|
const allowedByBaseline =
|
|
opts.baselineWallMs !== null
|
|
? opts.baselineWallMs * (1 + (opts.maxRegressionPct ?? 0) / 100)
|
|
: null;
|
|
|
|
let failed = false;
|
|
if (opts.maxWallMs !== null && elapsedMs > opts.maxWallMs) {
|
|
console.error(
|
|
`[test-perf-budget] wall time ${formatMs(elapsedMs)} exceeded max ${formatMs(
|
|
opts.maxWallMs,
|
|
)}.`,
|
|
);
|
|
failed = true;
|
|
}
|
|
if (allowedByBaseline !== null && elapsedMs > allowedByBaseline) {
|
|
console.error(
|
|
`[test-perf-budget] wall time ${formatMs(elapsedMs)} exceeded baseline budget ${formatMs(
|
|
allowedByBaseline,
|
|
)} (baseline ${formatMs(opts.baselineWallMs ?? 0)}, +${String(opts.maxRegressionPct)}%).`,
|
|
);
|
|
failed = true;
|
|
}
|
|
|
|
console.log(
|
|
`[test-perf-budget] config=${opts.config} wall=${formatMs(elapsedMs)} file-sum=${formatMs(
|
|
totalFileDurationMs,
|
|
)} files=${String(fileCount)}`,
|
|
);
|
|
|
|
if (failed) {
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
export const testing = {
|
|
parseArgs,
|
|
parseBudgetNumber,
|
|
};
|
|
|
|
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
|
|
main();
|
|
}
|