mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-12 21:53:00 -06:00
fix(test): guard realtime perf cli args
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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("{}", {
|
||||
|
||||
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user