Spaces:
Runtime error
Runtime error
| /** | |
| * OmniRoute β k6 Load / Performance Test (T-5) | |
| * | |
| * Tests the proxy endpoint under sustained load to measure: | |
| * - Request throughput (RPS) | |
| * - Response latency (p50, p95, p99) | |
| * - Error rate | |
| * - Concurrent connection handling | |
| * | |
| * Usage: | |
| * k6 run tests/load/proxy-load.js | |
| * k6 run tests/load/proxy-load.js --env BASE_URL=https://llms.omniroute.online | |
| * k6 run tests/load/proxy-load.js --env VUS=50 --env DURATION=120s | |
| * | |
| * Prerequisites: | |
| * - k6 installed: https://grafana.com/docs/k6/latest/set-up/install-k6/ | |
| * - OMNIROUTE_API_KEY env var or --env API_KEY=... set | |
| */ | |
| import http from "k6/http"; | |
| import { check, sleep } from "k6"; | |
| import { Rate, Trend } from "k6/metrics"; | |
| // ββ Custom metrics ββ | |
| const errorRate = new Rate("errors"); | |
| const chatLatency = new Trend("chat_latency", true); // in ms | |
| const healthLatency = new Trend("health_latency", true); | |
| // ββ Configuration ββ | |
| const BASE_URL = __ENV.BASE_URL || "http://localhost:3000"; | |
| const API_KEY = __ENV.API_KEY || __ENV.OMNIROUTE_API_KEY || "test-key"; | |
| const VUS = parseInt(__ENV.VUS || "10", 10); | |
| const DURATION = __ENV.DURATION || "60s"; | |
| export const options = { | |
| scenarios: { | |
| // Ramp-up scenario for stress testing | |
| chat_stress: { | |
| executor: "ramping-vus", | |
| startVUs: 1, | |
| stages: [ | |
| { duration: "10s", target: VUS }, // Ramp up | |
| { duration: DURATION, target: VUS }, // Sustained load | |
| { duration: "10s", target: 0 }, // Ramp down | |
| ], | |
| exec: "chatCompletions", | |
| }, | |
| // Constant rate for health checks | |
| health_check: { | |
| executor: "constant-vus", | |
| vus: 2, | |
| duration: DURATION, | |
| exec: "healthCheck", | |
| }, | |
| }, | |
| thresholds: { | |
| http_req_duration: ["p(95)<5000"], // 95% of requests < 5s | |
| errors: ["rate<0.1"], // Error rate < 10% | |
| chat_latency: ["p(50)<3000", "p(95)<8000"], | |
| health_latency: ["p(95)<500"], | |
| }, | |
| }; | |
| // ββ Headers ββ | |
| const headers = { | |
| "Content-Type": "application/json", | |
| Authorization: `Bearer ${API_KEY}`, | |
| }; | |
| // ββ Scenarios ββ | |
| /** | |
| * Chat Completions β main proxy endpoint | |
| * Sends a simple non-streaming chat request. | |
| */ | |
| export function chatCompletions() { | |
| const payload = JSON.stringify({ | |
| model: "gpt-4o-mini", | |
| messages: [{ role: "user", content: "Say hello in one word." }], | |
| temperature: 0, | |
| max_tokens: 10, | |
| stream: false, | |
| }); | |
| const res = http.post(`${BASE_URL}/v1/chat/completions`, payload, { | |
| headers, | |
| timeout: "15s", | |
| }); | |
| chatLatency.add(res.timings.duration); | |
| const passed = check(res, { | |
| "status is 200": (r) => r.status === 200, | |
| "has choices": (r) => { | |
| try { | |
| const body = JSON.parse(r.body); | |
| return body.choices && body.choices.length > 0; | |
| } catch { | |
| return false; | |
| } | |
| }, | |
| "response time < 10s": (r) => r.timings.duration < 10000, | |
| }); | |
| errorRate.add(!passed); | |
| sleep(0.5); | |
| } | |
| /** | |
| * Health Check β lightweight endpoint to measure base latency. | |
| */ | |
| export function healthCheck() { | |
| const res = http.get(`${BASE_URL}/api/monitoring/health`, { | |
| headers: { Authorization: `Bearer ${API_KEY}` }, | |
| timeout: "5s", | |
| }); | |
| healthLatency.add(res.timings.duration); | |
| const passed = check(res, { | |
| "health status 200": (r) => r.status === 200, | |
| "response time < 1s": (r) => r.timings.duration < 1000, | |
| }); | |
| errorRate.add(!passed); | |
| sleep(2); | |
| } | |
| /** | |
| * Summary handler β outputs a custom summary. | |
| */ | |
| export function handleSummary(data) { | |
| const summary = { | |
| timestamp: new Date().toISOString(), | |
| scenarios: Object.keys(options.scenarios), | |
| metrics: { | |
| http_reqs: data.metrics.http_reqs?.values?.count || 0, | |
| avg_duration_ms: Math.round(data.metrics.http_req_duration?.values?.avg || 0), | |
| p95_duration_ms: Math.round(data.metrics.http_req_duration?.values?.["p(95)"] || 0), | |
| p99_duration_ms: Math.round(data.metrics.http_req_duration?.values?.["p(99)"] || 0), | |
| error_rate: (data.metrics.errors?.values?.rate || 0).toFixed(4), | |
| }, | |
| }; | |
| return { | |
| stdout: `\nπ Load Test Summary\n${JSON.stringify(summary, null, 2)}\n`, | |
| "tests/load/results.json": JSON.stringify(summary, null, 2), | |
| }; | |
| } | |