fix(test): guard gateway benchmark cli args

This commit is contained in:
Vincent Koc
2026-06-20 03:04:34 +02:00
parent b6d91d96ef
commit 4b2b70ec79
4 changed files with 117 additions and 2 deletions
+38 -1
View File
@@ -178,6 +178,21 @@ const DEFAULT_TIMEOUT_MS = 30_000;
const DEFAULT_POST_READY_DELAY_MS = 250;
const DEFAULT_ENTRY = "dist/entry.js";
const RESTART_INTENT_FILENAME = "gateway-restart-intent.json";
const BOOLEAN_FLAGS = new Set(["--allow-failures", "--help", "-h", "--json"]);
const VALUE_FLAGS = new Set([
"--case",
"--entry",
"--output",
"--post-ready-delay-ms",
"--restarts",
"--runs",
"--timeout-ms",
"--warmup",
]);
class CliArgumentError extends Error {
override name = "CliArgumentError";
}
const BASE_CONFIG = {
browser: { enabled: false },
@@ -233,11 +248,26 @@ const GATEWAY_CASES: readonly GatewayBenchCase[] = [
function readRequiredFlagValue(argv: string[], index: number, flag: string): string {
const value = argv[index + 1];
if (!value || value.startsWith("-")) {
throw new Error(`${flag} requires a value`);
throw new CliArgumentError(`${flag} requires a value`);
}
return value;
}
function validateCliArgs(argv: string[]): void {
for (let index = 0; index < argv.length; index += 1) {
const arg = argv[index] ?? "";
if (BOOLEAN_FLAGS.has(arg)) {
continue;
}
if (VALUE_FLAGS.has(arg)) {
readRequiredFlagValue(argv, index, arg);
index += 1;
continue;
}
throw new CliArgumentError(`Unknown argument: ${arg}`);
}
}
function parseFlagValue(argv: string[], flag: string): string | undefined {
for (let index = 0; index < argv.length; index += 1) {
if (argv[index] === flag) {
@@ -319,6 +349,7 @@ function resolveCases(caseIds: string[]): GatewayBenchCase[] {
}
function parseOptions(argv: string[] = process.argv.slice(2)): CliOptions {
validateCliArgs(argv);
return {
allowFailures: hasFlag(argv, "--allow-failures"),
cases: resolveCases(parseRepeatableFlag(argv, "--case")),
@@ -1649,6 +1680,7 @@ export const testing = {
shouldFailBenchmark,
stopChild,
summarizeCase,
validateCliArgs,
waitForRestartProbe,
writeConfig,
writeRestartIntent,
@@ -1656,6 +1688,11 @@ export const testing = {
if (import.meta.url === pathToFileURL(process.argv[1] ?? "").href) {
main().catch((err: unknown) => {
if (err instanceof CliArgumentError) {
console.error(err.message);
process.exitCode = 1;
return;
}
console.error(err instanceof Error ? err.stack : String(err));
process.exitCode = 1;
});
+37 -1
View File
@@ -108,6 +108,20 @@ const DEFAULT_RUNS = 5;
const DEFAULT_WARMUP = 1;
const DEFAULT_TIMEOUT_MS = 30_000;
const DEFAULT_ENTRY = "dist/entry.js";
const BOOLEAN_FLAGS = new Set(["--help", "-h", "--json"]);
const VALUE_FLAGS = new Set([
"--case",
"--cpu-prof-dir",
"--entry",
"--output",
"--runs",
"--timeout-ms",
"--warmup",
]);
class CliArgumentError extends Error {
override name = "CliArgumentError";
}
const BASE_CONFIG = {
browser: { enabled: false },
@@ -187,11 +201,26 @@ const GATEWAY_CASES: readonly GatewayBenchCase[] = [
function readRequiredFlagValue(argv: string[], index: number, flag: string): string {
const value = argv[index + 1];
if (!value || value.startsWith("-")) {
throw new Error(`${flag} requires a value`);
throw new CliArgumentError(`${flag} requires a value`);
}
return value;
}
function validateCliArgs(argv: string[]): void {
for (let index = 0; index < argv.length; index += 1) {
const arg = argv[index] ?? "";
if (BOOLEAN_FLAGS.has(arg)) {
continue;
}
if (VALUE_FLAGS.has(arg)) {
readRequiredFlagValue(argv, index, arg);
index += 1;
continue;
}
throw new CliArgumentError(`Unknown argument: ${arg}`);
}
}
function parseFlagValue(argv: string[], flag: string): string | undefined {
for (let index = 0; index < argv.length; index += 1) {
if (argv[index] === flag) {
@@ -265,6 +294,7 @@ function resolveCases(caseIds: string[]): GatewayBenchCase[] {
}
function parseOptions(argv: string[] = process.argv.slice(2)): CliOptions {
validateCliArgs(argv);
return {
cases: resolveCases(parseRepeatableFlag(argv, "--case")),
cpuProfDir: parseFlagValue(argv, "--cpu-prof-dir"),
@@ -965,12 +995,18 @@ export const testing = {
sanitizedEnv,
stopChild,
summarizeCase,
validateCliArgs,
waitForProbe,
writeConfig,
};
if (import.meta.url === pathToFileURL(process.argv[1] ?? "").href) {
main().catch((err: unknown) => {
if (err instanceof CliArgumentError) {
console.error(err.message);
process.exitCode = 1;
return;
}
console.error(err instanceof Error ? err.stack : String(err));
process.exitCode = 1;
});
@@ -42,6 +42,7 @@ describe("gateway restart benchmark script", () => {
});
it("rejects ambiguous benchmark CLI values before spawning Node", () => {
expect(() => testing.parseOptions(["--wat"])).toThrow("Unknown argument: --wat");
expect(testing.parsePositiveInt("5", 1, "--restarts")).toBe(5);
expect(testing.parseNonNegativeInt("0", 1, "--warmup")).toBe(0);
expect(
@@ -73,6 +74,26 @@ describe("gateway restart benchmark script", () => {
expect(() => testing.resolveEntry("--inspect")).toThrow(/must be a file path/u);
});
it("rejects unknown benchmark CLI args before checking platform or running cases", () => {
const result = spawnSync(
process.execPath,
["--import", "tsx", "scripts/bench-gateway-restart.ts", "--wat"],
{
cwd: process.cwd(),
encoding: "utf8",
env: {
...process.env,
NODE_NO_WARNINGS: "1",
},
},
);
expect(result.status).toBe(1);
expect(result.stdout).toBe("");
expect(result.stderr.trim()).toBe("Unknown argument: --wat");
expect(result.stderr).not.toContain("\n at ");
});
it("guards the SIGUSR1 restart benchmark on Windows", () => {
expect(() => testing.ensureSupportedRestartPlatform("linux")).not.toThrow();
expect(() => testing.ensureSupportedRestartPlatform("darwin")).not.toThrow();
@@ -52,6 +52,7 @@ describe("gateway startup benchmark script", () => {
});
it("rejects ambiguous benchmark CLI values before spawning Node", () => {
expect(() => testing.parseOptions(["--wat"])).toThrow("Unknown argument: --wat");
expect(testing.parsePositiveInt("5", 1, "--runs")).toBe(5);
expect(testing.parseNonNegativeInt("0", 1, "--warmup")).toBe(0);
expect(
@@ -83,6 +84,26 @@ describe("gateway startup benchmark script", () => {
expect(() => testing.resolveEntry("--inspect")).toThrow(/must be a file path/u);
});
it("rejects unknown benchmark CLI args before running cases", () => {
const result = spawnSync(
process.execPath,
["--import", "tsx", "scripts/bench-gateway-startup.ts", "--wat"],
{
cwd: process.cwd(),
encoding: "utf8",
env: {
...process.env,
NODE_NO_WARNINGS: "1",
},
},
);
expect(result.status).toBe(1);
expect(result.stdout).toBe("");
expect(result.stderr.trim()).toBe("Unknown argument: --wat");
expect(result.stderr).not.toContain("\n at ");
});
it("does not disable local-check policy in the child gateway environment", () => {
const env = testing.sanitizedEnv("/tmp/openclaw-bench", "/tmp/openclaw-bench/config.json", {
config: {},