diff --git a/scripts/bench-gateway-restart.ts b/scripts/bench-gateway-restart.ts index 7c317d1d3018..a59f9f55391a 100644 --- a/scripts/bench-gateway-restart.ts +++ b/scripts/bench-gateway-restart.ts @@ -218,20 +218,29 @@ const GATEWAY_CASES: readonly GatewayBenchCase[] = [ }, ] as const; -function parseFlagValue(flag: string): string | undefined { - const index = process.argv.indexOf(flag); - if (index === -1) { - return undefined; +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`); } - return process.argv[index + 1]; + return value; } -function hasFlag(flag: string): boolean { - return process.argv.includes(flag); +function parseFlagValue(argv: string[], flag: string): string | undefined { + for (let index = 0; index < argv.length; index += 1) { + if (argv[index] === flag) { + return readRequiredFlagValue(argv, index, flag); + } + } + return undefined; } -function hasHelpFlag(): boolean { - return hasFlag("--help") || hasFlag("-h"); +function hasFlag(argv: string[], flag: string): boolean { + return argv.includes(flag); +} + +function hasHelpFlag(argv: string[]): boolean { + return hasFlag(argv, "--help") || hasFlag(argv, "-h"); } function ensureSupportedRestartPlatform(platform: NodeJS.Platform = process.platform): void { @@ -242,11 +251,12 @@ function ensureSupportedRestartPlatform(platform: NodeJS.Platform = process.plat } } -function parseRepeatableFlag(flag: string): string[] { +function parseRepeatableFlag(argv: string[], flag: string): string[] { const values: string[] = []; - for (let index = 0; index < process.argv.length; index += 1) { - if (process.argv[index] === flag && process.argv[index + 1]) { - values.push(process.argv[index + 1]); + for (let index = 0; index < argv.length; index += 1) { + if (argv[index] === flag) { + values.push(readRequiredFlagValue(argv, index, flag)); + index += 1; } } return values; @@ -296,22 +306,26 @@ function resolveCases(caseIds: string[]): GatewayBenchCase[] { }); } -function parseOptions(): CliOptions { +function parseOptions(argv: string[] = process.argv.slice(2)): CliOptions { return { - allowFailures: hasFlag("--allow-failures"), - cases: resolveCases(parseRepeatableFlag("--case")), - entry: resolveEntry(parseFlagValue("--entry")), - json: hasFlag("--json"), - output: resolveOutputPath(parseFlagValue("--output")), + allowFailures: hasFlag(argv, "--allow-failures"), + cases: resolveCases(parseRepeatableFlag(argv, "--case")), + entry: resolveEntry(parseFlagValue(argv, "--entry")), + json: hasFlag(argv, "--json"), + output: resolveOutputPath(parseFlagValue(argv, "--output")), postReadyDelayMs: parseNonNegativeInt( - parseFlagValue("--post-ready-delay-ms"), + parseFlagValue(argv, "--post-ready-delay-ms"), DEFAULT_POST_READY_DELAY_MS, "--post-ready-delay-ms", ), - restarts: parsePositiveInt(parseFlagValue("--restarts"), DEFAULT_RESTARTS, "--restarts"), - runs: parsePositiveInt(parseFlagValue("--runs"), DEFAULT_RUNS, "--runs"), - timeoutMs: parsePositiveInt(parseFlagValue("--timeout-ms"), DEFAULT_TIMEOUT_MS, "--timeout-ms"), - warmup: parseNonNegativeInt(parseFlagValue("--warmup"), DEFAULT_WARMUP, "--warmup"), + restarts: parsePositiveInt(parseFlagValue(argv, "--restarts"), DEFAULT_RESTARTS, "--restarts"), + runs: parsePositiveInt(parseFlagValue(argv, "--runs"), DEFAULT_RUNS, "--runs"), + timeoutMs: parsePositiveInt( + parseFlagValue(argv, "--timeout-ms"), + DEFAULT_TIMEOUT_MS, + "--timeout-ms", + ), + warmup: parseNonNegativeInt(parseFlagValue(argv, "--warmup"), DEFAULT_WARMUP, "--warmup"), }; } @@ -1600,13 +1614,14 @@ function shouldFailBenchmark(results: CaseResult[], options: { allowFailures: bo } async function main() { - if (hasHelpFlag()) { + const argv = process.argv.slice(2); + if (hasHelpFlag(argv)) { printUsage(); return; } ensureSupportedRestartPlatform(); - const options = parseOptions(); + const options = parseOptions(argv); const results: CaseResult[] = []; for (const benchCase of options.cases) { results.push( @@ -1665,6 +1680,7 @@ export const testing = { hasInitialReadyLogs, hasBenchmarkFailures, parseNonNegativeInt, + parseOptions, parsePositiveInt, resolveRestartDeadlineFailure, resolveEntry, diff --git a/scripts/bench-gateway-startup.ts b/scripts/bench-gateway-startup.ts index af1db1455d7a..218105490494 100644 --- a/scripts/bench-gateway-startup.ts +++ b/scripts/bench-gateway-startup.ts @@ -178,27 +178,37 @@ const GATEWAY_CASES: readonly GatewayBenchCase[] = [ }, ] as const; -function parseFlagValue(flag: string): string | undefined { - const index = process.argv.indexOf(flag); - if (index === -1) { - return undefined; +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`); } - return process.argv[index + 1]; + return value; } -function hasFlag(flag: string): boolean { - return process.argv.includes(flag); +function parseFlagValue(argv: string[], flag: string): string | undefined { + for (let index = 0; index < argv.length; index += 1) { + if (argv[index] === flag) { + return readRequiredFlagValue(argv, index, flag); + } + } + return undefined; } -function hasHelpFlag(): boolean { - return hasFlag("--help") || hasFlag("-h"); +function hasFlag(argv: string[], flag: string): boolean { + return argv.includes(flag); } -function parseRepeatableFlag(flag: string): string[] { +function hasHelpFlag(argv: string[]): boolean { + return hasFlag(argv, "--help") || hasFlag(argv, "-h"); +} + +function parseRepeatableFlag(argv: string[], flag: string): string[] { const values: string[] = []; - for (let index = 0; index < process.argv.length; index += 1) { - if (process.argv[index] === flag && process.argv[index + 1]) { - values.push(process.argv[index + 1]); + for (let index = 0; index < argv.length; index += 1) { + if (argv[index] === flag) { + values.push(readRequiredFlagValue(argv, index, flag)); + index += 1; } } return values; @@ -248,16 +258,20 @@ function resolveCases(caseIds: string[]): GatewayBenchCase[] { }); } -function parseOptions(): CliOptions { +function parseOptions(argv: string[] = process.argv.slice(2)): CliOptions { return { - cases: resolveCases(parseRepeatableFlag("--case")), - cpuProfDir: parseFlagValue("--cpu-prof-dir"), - entry: resolveEntry(parseFlagValue("--entry")), - json: hasFlag("--json"), - output: resolveOutputPath(parseFlagValue("--output")), - runs: parsePositiveInt(parseFlagValue("--runs"), DEFAULT_RUNS, "--runs"), - timeoutMs: parsePositiveInt(parseFlagValue("--timeout-ms"), DEFAULT_TIMEOUT_MS, "--timeout-ms"), - warmup: parseNonNegativeInt(parseFlagValue("--warmup"), DEFAULT_WARMUP, "--warmup"), + cases: resolveCases(parseRepeatableFlag(argv, "--case")), + cpuProfDir: parseFlagValue(argv, "--cpu-prof-dir"), + entry: resolveEntry(parseFlagValue(argv, "--entry")), + json: hasFlag(argv, "--json"), + output: resolveOutputPath(parseFlagValue(argv, "--output")), + runs: parsePositiveInt(parseFlagValue(argv, "--runs"), DEFAULT_RUNS, "--runs"), + timeoutMs: parsePositiveInt( + parseFlagValue(argv, "--timeout-ms"), + DEFAULT_TIMEOUT_MS, + "--timeout-ms", + ), + warmup: parseNonNegativeInt(parseFlagValue(argv, "--warmup"), DEFAULT_WARMUP, "--warmup"), }; } @@ -1033,12 +1047,13 @@ function printResult(result: CaseResult): void { } async function main() { - if (hasHelpFlag()) { + const argv = process.argv.slice(2); + if (hasHelpFlag(argv)) { printUsage(); return; } - const options = parseOptions(); + const options = parseOptions(argv); if (options.cpuProfDir) { mkdirSync(options.cpuProfDir, { recursive: true }); } @@ -1085,6 +1100,7 @@ export const testing = { classifyProbeErrorKind, collectResultFailures, collectStartupTrace, + parseOptions, parseNonNegativeInt, parsePositiveInt, resolveEntry, diff --git a/test/scripts/bench-gateway-restart.test.ts b/test/scripts/bench-gateway-restart.test.ts index 3965c760b9b0..daf02dfec012 100644 --- a/test/scripts/bench-gateway-restart.test.ts +++ b/test/scripts/bench-gateway-restart.test.ts @@ -44,9 +44,32 @@ describe("gateway restart benchmark script", () => { it("rejects ambiguous benchmark CLI values before spawning Node", () => { expect(testing.parsePositiveInt("5", 1, "--restarts")).toBe(5); expect(testing.parseNonNegativeInt("0", 1, "--warmup")).toBe(0); + expect( + testing.parseOptions([ + "--case", + "skipChannelsNoAcpxProbe", + "--output", + "restart.json", + "--allow-failures", + "--restarts", + "2", + ]), + ).toMatchObject({ + allowFailures: true, + cases: [{ id: "skipChannelsNoAcpxProbe" }], + output: "restart.json", + restarts: 2, + }); expect(() => testing.parsePositiveInt("2abc", 1, "--restarts")).toThrow( /--restarts must be an integer/u, ); + expect(() => testing.parseOptions(["--output", "--case", "skipChannels"])).toThrow( + "--output requires a value", + ); + expect(() => testing.parseOptions(["--case"])).toThrow("--case requires a value"); + expect(() => testing.parseOptions(["--restarts", "--runs", "1"])).toThrow( + "--restarts requires a value", + ); expect(() => testing.resolveEntry("--inspect")).toThrow(/must be a file path/u); }); diff --git a/test/scripts/bench-gateway-startup.test.ts b/test/scripts/bench-gateway-startup.test.ts index 4e6d9f5c3650..067a9a525905 100644 --- a/test/scripts/bench-gateway-startup.test.ts +++ b/test/scripts/bench-gateway-startup.test.ts @@ -54,9 +54,32 @@ describe("gateway startup benchmark script", () => { it("rejects ambiguous benchmark CLI values before spawning Node", () => { expect(testing.parsePositiveInt("5", 1, "--runs")).toBe(5); expect(testing.parseNonNegativeInt("0", 1, "--warmup")).toBe(0); + expect( + testing.parseOptions([ + "--case", + "default", + "--output", + "startup.json", + "--json", + "--runs", + "2", + ]), + ).toMatchObject({ + cases: [{ id: "default" }], + json: true, + output: "startup.json", + runs: 2, + }); expect(() => testing.parsePositiveInt("2abc", 1, "--runs")).toThrow( /--runs must be an integer/u, ); + expect(() => testing.parseOptions(["--output", "--case", "default"])).toThrow( + "--output requires a value", + ); + expect(() => testing.parseOptions(["--case"])).toThrow("--case requires a value"); + expect(() => testing.parseOptions(["--runs", "--warmup", "0"])).toThrow( + "--runs requires a value", + ); expect(() => testing.resolveEntry("--inspect")).toThrow(/must be a file path/u); });