fix(test): guard realtime perf cli args

This commit is contained in:
Vincent Koc
2026-06-20 02:33:53 +02:00
parent 7e7dc7505b
commit 4575734f59
4 changed files with 142 additions and 4 deletions
+40 -2
View File
@@ -26,6 +26,10 @@ const GOOGLE_REALTIME_VOICE = process.env.OPENCLAW_REALTIME_GOOGLE_VOICE?.trim()
const GOOGLE_LIVE_WS_URL =
"wss://generativelanguage.googleapis.com/ws/google.ai.generativelanguage.v1alpha.GenerativeService.BidiGenerateContentConstrained";
type RealtimeSmokeCliOptions = {
help: boolean;
};
type SmokeResult = {
name: string;
ok: boolean;
@@ -53,6 +57,33 @@ type OpenAIWebRtcSmokeGlobal = typeof globalThis & {
openclawReadBoundedRealtimeResponseText?: OpenAIRealtimeBrowserResponseReader;
};
class CliArgumentError extends Error {
override name = "CliArgumentError";
}
function usage(): string {
return [
"Usage: node --import tsx scripts/dev/realtime-talk-live-smoke.ts [options]",
"",
"Options:",
" -h, --help Show this help",
"",
"Environment:",
" OPENAI_API_KEY",
" GEMINI_API_KEY or GOOGLE_API_KEY",
].join("\n");
}
function parseRealtimeSmokeArgs(argv = process.argv.slice(2)): RealtimeSmokeCliOptions {
for (const arg of argv) {
if (arg === "--help" || arg === "-h") {
continue;
}
throw new CliArgumentError(`Unknown argument: ${arg}`);
}
return { help: argv.includes("--help") || argv.includes("-h") };
}
function getEnv(name: string): string | undefined {
const value = process.env[name]?.trim();
return value ? value : undefined;
@@ -729,7 +760,12 @@ try {
}
}
async function main(): Promise<void> {
async function main(argv = process.argv.slice(2)): Promise<void> {
const cli = parseRealtimeSmokeArgs(argv);
if (cli.help) {
console.log(usage());
return;
}
const openAIKey = getEnv("OPENAI_API_KEY");
const googleKey = getEnv("GEMINI_API_KEY") ?? getEnv("GOOGLE_API_KEY");
const browser = await chromium.launch({
@@ -781,7 +817,7 @@ async function main(): Promise<void> {
if (import.meta.url === pathToFileURL(process.argv[1] ?? "").href) {
await main().catch((error: unknown) => {
console.error(shortError(error));
console.error(error instanceof CliArgumentError ? error.message : shortError(error));
process.exitCode = 1;
});
}
@@ -789,9 +825,11 @@ if (import.meta.url === pathToFileURL(process.argv[1] ?? "").href) {
export const testing = {
OPENAI_HTTP_RESPONSE_MAX_BYTES,
createOpenAIClientSecret,
parseRealtimeSmokeArgs,
readOpenAIRealtimeBrowserResponseText,
readBoundedText,
resolveOpenAIHttpTimeoutMs,
usage,
};
function toLintErrorObject(value: unknown, fallbackMessage: string): Error {
+28 -1
View File
@@ -8,6 +8,22 @@ import { parsePositiveInt } from "../lib/numeric-options.mjs";
const DEFAULT_LIMIT = 30;
export function usage() {
return "Usage: scripts/perf/summarize-cpuprofile.mjs [--limit N] <profile...>";
}
export function shouldPrintHelp(argv) {
for (const arg of argv) {
if (arg === "--") {
return false;
}
if (arg === "--help" || arg === "-h") {
return true;
}
}
return false;
}
/**
* Parses CPU profile file paths and --limit.
*/
@@ -24,6 +40,13 @@ export function parseArgs(argv) {
limit = parsePositiveInt(arg.slice("--limit=".length), "--limit");
continue;
}
if (arg === "--") {
files.push(...argv.slice(index + 1));
break;
}
if (arg.startsWith("-")) {
throw new Error(`Unknown option: ${arg}`);
}
files.push(arg);
}
return { files, limit };
@@ -125,6 +148,10 @@ export function summarizeProfile(file, limit) {
}
function main() {
if (shouldPrintHelp(process.argv.slice(2))) {
console.log(usage());
return;
}
let options;
try {
options = parseArgs(process.argv.slice(2));
@@ -133,7 +160,7 @@ function main() {
process.exit(1);
}
if (options.files.length === 0) {
console.error("usage: scripts/perf/summarize-cpuprofile.mjs [--limit N] <profile...>");
console.error(usage());
process.exit(2);
}
try {
+38
View File
@@ -399,6 +399,44 @@ describe("script-specific dev tooling hardening", () => {
);
});
it("prints OpenAI realtime smoke help without launching live checks", () => {
expect(realtimeSmokeTesting.parseRealtimeSmokeArgs(["--help"])).toEqual({ help: true });
const result = spawnSync(
process.execPath,
["--import", "tsx", "scripts/dev/realtime-talk-live-smoke.ts", "--help"],
{
cwd: process.cwd(),
encoding: "utf8",
},
);
expect(result.status).toBe(0);
expect(result.stdout).toContain(
"Usage: node --import tsx scripts/dev/realtime-talk-live-smoke.ts",
);
expect(result.stderr).toBe("");
});
it("rejects unknown OpenAI realtime smoke args before launching live checks", () => {
expect(() => realtimeSmokeTesting.parseRealtimeSmokeArgs(["--wat"])).toThrow(
"Unknown argument: --wat",
);
const result = spawnSync(
process.execPath,
["--import", "tsx", "scripts/dev/realtime-talk-live-smoke.ts", "--wat"],
{
cwd: process.cwd(),
encoding: "utf8",
},
);
expect(result.status).toBe(1);
expect(result.stdout).toBe("");
expect(result.stderr.trim()).toBe("Unknown argument: --wat");
});
it("bounds OpenAI realtime smoke response body reads by content-length", async () => {
const maxBytes = realtimeSmokeTesting.OPENAI_HTTP_RESPONSE_MAX_BYTES;
const response = new Response("{}", {
+36 -1
View File
@@ -4,7 +4,7 @@ import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { describe, expect, it } from "vitest";
import { parseArgs } from "../../scripts/perf/summarize-cpuprofile.mjs";
import { parseArgs, shouldPrintHelp } from "../../scripts/perf/summarize-cpuprofile.mjs";
describe("scripts/perf/summarize-cpuprofile.mjs", () => {
it("parses split and inline positive limit flags", () => {
@@ -16,6 +16,28 @@ describe("scripts/perf/summarize-cpuprofile.mjs", () => {
files: ["a.cpuprofile", "b.cpuprofile"],
limit: 7,
});
expect(parseArgs(["--limit", "5", "--", "--dash.cpuprofile"])).toEqual({
files: ["--dash.cpuprofile"],
limit: 5,
});
});
it("prints help without treating it as a profile path", () => {
expect(shouldPrintHelp(["--help"])).toBe(true);
expect(shouldPrintHelp(["--", "--help"])).toBe(false);
const result = spawnSync(
process.execPath,
["scripts/perf/summarize-cpuprofile.mjs", "--help"],
{
cwd: process.cwd(),
encoding: "utf8",
},
);
expect(result.status).toBe(0);
expect(result.stdout).toContain("Usage: scripts/perf/summarize-cpuprofile.mjs");
expect(result.stderr).toBe("");
});
it("rejects malformed limit flags instead of falling back", () => {
@@ -29,6 +51,19 @@ describe("scripts/perf/summarize-cpuprofile.mjs", () => {
}
});
it("rejects unknown options instead of treating them as profile paths", () => {
expect(() => parseArgs(["--wat"])).toThrow("Unknown option: --wat");
const result = spawnSync(process.execPath, ["scripts/perf/summarize-cpuprofile.mjs", "--wat"], {
cwd: process.cwd(),
encoding: "utf8",
});
expect(result.status).toBe(1);
expect(result.stdout).toBe("");
expect(result.stderr.trim()).toBe("Unknown option: --wat");
});
it("rejects empty CPU profiles instead of printing zero-sample summaries", () => {
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-cpuprofile-"));
const profilePath = path.join(tempDir, "empty.cpuprofile");