openclaw/scripts/test-force.ts
Peter Steinberger 7875352583
perf(cli): reduce gateway call cold-start imports (#166657)
* perf(cli): reduce gateway call cold-start imports

Let the Gateway transport own dispatch configuration, preserving environment
resolution facts for literal credentials and rereading only after shell env
fallback changes its inputs. Defer plugin-install policy, SecretRef resolution,
and TLS certificate inspection until needed, and retire the unused program
barrel after moving its callers to the builder.

Keep raw Gateway calls usable without validating unrelated configuration.
Regression coverage preserves escaped credentials, authentication, CLI output,
and read-only state behavior. Paired cold-process timing on the Linux rig
improved from 1.904s to 1.617s median; the 500ms target remains unmet.

* test(cli): prepare smoke workers before action deadlines

* fix(cli): keep force cleanup signal errors outside discovery fallback

* test(cli): harden port cleanup fixtures

* test(cli): exercise config read recovery through gateway probe
2026-10-07 16:42:51 +00:00

95 lines
2.6 KiB
JavaScript
Executable file

#!/usr/bin/env -S node --import tsx
import { spawnSync } from "node:child_process";
import os from "node:os";
import path from "node:path";
import { pathToFileURL } from "node:url";
import { forceFreePortAndWait } from "../src/cli/ports.js";
import { resolveGatewayPort } from "../src/config/paths.js";
type PortProcess = Awaited<ReturnType<typeof forceFreePortAndWait>>["killed"][number];
function usage(): string {
return [
"Usage: node --import tsx scripts/test-force.ts",
"",
"Clears the configured OpenClaw gateway port, then runs the local test suite.",
"",
"Options:",
" -h, --help Show this help.",
].join("\n");
}
function parseArgs(argv: readonly string[]): { help: boolean } {
for (const arg of argv) {
if (arg === "--help" || arg === "-h") {
return { help: true };
}
throw new Error(`unknown argument: ${arg}\n\n${usage()}`);
}
return { help: false };
}
async function killGatewayListeners(port: number): Promise<PortProcess[]> {
try {
const { killed } = await forceFreePortAndWait(port);
if (killed.length > 0) {
console.log(
`freed port ${port}; terminated: ${killed
.map((p) => `${p.command} (pid ${p.pid})`)
.join(", ")}`,
);
} else {
console.log(`port ${port} already free`);
}
return killed;
} catch (err) {
console.error(`failed to free port ${port}: ${String(err)}`);
return [];
}
}
function runTests() {
const isolatedLock =
process.env.OPENCLAW_GATEWAY_LOCK ??
path.join(os.tmpdir(), `openclaw-gateway.lock.test.${Date.now()}`);
const result = spawnSync(process.execPath, ["--import", "tsx", "scripts/test-projects.mts"], {
stdio: "inherit",
env: {
...process.env,
OPENCLAW_GATEWAY_LOCK: isolatedLock,
},
});
if (result.error) {
console.error(`test runner failed to start: ${String(result.error)}`);
process.exit(1);
}
process.exit(result.status ?? 1);
}
async function main(argv: readonly string[] = process.argv.slice(2)) {
const args = parseArgs(argv);
if (args.help) {
console.log(usage());
return;
}
const port = resolveGatewayPort(undefined, process.env);
console.log(`🧹 test:force - clearing gateway on port ${port}`);
const killed = await killGatewayListeners(port);
if (killed.length === 0) {
console.log("no listeners to kill");
}
console.log("running pnpm test…");
runTests();
}
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
try {
await main();
} catch (error) {
console.error(error instanceof Error ? error.message : String(error));
process.exit(2);
}
}