Observability: - HTTP health endpoints (/health, /ready, /health/deep) - Prometheus metrics endpoint (/metrics) with prom-client - W3C traceparent request tracing with AsyncLocalStorage - Trace ID propagation to logs and diagnostic events Enterprise: - JSONL audit logging with daily rotation and 7-day retention - RBAC permission engine with flat roles (admin, operator, user, viewer) - Tool and agent access restrictions per role - Audit integration with pairing, auth, and exec approval flows Documentation: - Enterprise deployment guide (single/multi-tenant, K8s, Docker) - Security hardening guide (TLS, RBAC, rate limiting) - Observability guide (Prometheus, Grafana, alerting) - Self-healing behaviors documentation Load Testing: - Connection stress test (WebSocket saturation) - Chat throughput test (sustained message load) - Auth stress test (rate limit verification) - Configurable scenarios with p50/p95/p99 latency metrics Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
103 lines
3.5 KiB
TypeScript
Executable File
103 lines
3.5 KiB
TypeScript
Executable File
#!/usr/bin/env bun
|
|
/**
|
|
* Gateway Load Test Runner
|
|
*
|
|
* Entry point for running gateway load tests.
|
|
*
|
|
* Usage:
|
|
* bun load-tests/run.ts --scenario connections --concurrency 100 --duration 30
|
|
* bun load-tests/run.ts --scenario chat --concurrency 20 --rps 5 --duration 60
|
|
* bun load-tests/run.ts --scenario auth-stress --concurrency 10 --duration 30
|
|
*/
|
|
|
|
import { DEFAULT_CONFIG, formatMetricsConsole, parseArgs } from "./config.js";
|
|
import type { LoadTestConfig, LoadTestMetrics } from "./config.js";
|
|
import { runConnectionsTest } from "./gateway-ws.js";
|
|
import { runChatTest } from "./gateway-chat.js";
|
|
import { runAuthStressTest } from "./gateway-auth.js";
|
|
|
|
async function main(): Promise<void> {
|
|
const args = process.argv.slice(2);
|
|
const parsedArgs = parseArgs(args);
|
|
|
|
const config: LoadTestConfig = {
|
|
...DEFAULT_CONFIG,
|
|
...parsedArgs,
|
|
};
|
|
|
|
// Validate config
|
|
if (!config.gatewayUrl) {
|
|
console.error("Error: Gateway URL is required (--url or -u)");
|
|
process.exit(1);
|
|
}
|
|
|
|
if (!["connections", "chat", "auth-stress"].includes(config.scenario)) {
|
|
console.error(`Error: Invalid scenario "${config.scenario}". Use: connections, chat, auth-stress`);
|
|
process.exit(1);
|
|
}
|
|
|
|
console.log("");
|
|
console.log("╔══════════════════════════════════════════════════════════════════╗");
|
|
console.log("║ Clawdbot Gateway Load Test ║");
|
|
console.log("╚══════════════════════════════════════════════════════════════════╝");
|
|
console.log("");
|
|
console.log(` Scenario: ${config.scenario}`);
|
|
console.log(` Gateway: ${config.gatewayUrl}`);
|
|
console.log(` Concurrency: ${config.concurrency}`);
|
|
console.log(` Duration: ${config.durationSeconds}s`);
|
|
console.log(` Ramp-up: ${config.rampUpSeconds}s`);
|
|
if (config.scenario === "chat") {
|
|
console.log(` RPS/user: ${config.rpsPerUser}`);
|
|
}
|
|
console.log(` Auth: ${config.token ? "token provided" : "none"}`);
|
|
console.log("");
|
|
|
|
let metrics: LoadTestMetrics;
|
|
|
|
try {
|
|
switch (config.scenario) {
|
|
case "connections":
|
|
metrics = await runConnectionsTest(config);
|
|
break;
|
|
case "chat":
|
|
metrics = await runChatTest(config);
|
|
break;
|
|
case "auth-stress":
|
|
metrics = await runAuthStressTest(config);
|
|
break;
|
|
}
|
|
} catch (err) {
|
|
console.error(`\nLoad test failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
process.exit(1);
|
|
}
|
|
|
|
// Output results
|
|
if (config.outputFormat === "json") {
|
|
console.log(JSON.stringify(metrics, null, 2));
|
|
} else {
|
|
console.log(formatMetricsConsole(metrics));
|
|
}
|
|
|
|
// Exit with error code if significant failures
|
|
const failureRate = metrics.requestsTotal > 0
|
|
? metrics.requestsFailed / metrics.requestsTotal
|
|
: 0;
|
|
|
|
if (failureRate > 0.1) {
|
|
console.log("⚠️ Warning: Failure rate > 10%");
|
|
process.exit(1);
|
|
}
|
|
|
|
if (metrics.connectionsFailed > 0 && metrics.connectionsSucceeded === 0) {
|
|
console.log("⚠️ Warning: All connections failed");
|
|
process.exit(1);
|
|
}
|
|
|
|
console.log("✓ Load test completed successfully");
|
|
}
|
|
|
|
main().catch((err) => {
|
|
console.error(`Fatal error: ${err instanceof Error ? err.message : String(err)}`);
|
|
process.exit(1);
|
|
});
|