import http from 'k6/http'; import { check, sleep } from 'k6'; import { Rate, Trend } from 'k6/metrics'; const BASE_URL = __ENV.BASE_URL || 'http://localhost:8080'; const TENANT_HEADER = __ENV.TENANT_HEADER || 'X-StellaOps-Tenant'; const TENANTS = (__ENV.TENANTS || 'tenant-a,tenant-b,tenant-c,tenant-d,tenant-e,tenant-f,tenant-g,tenant-h,tenant-i,tenant-j') .split(',') .map((t) => t.trim()) .filter(Boolean); const READ_PATHS = (__ENV.TENANT_READ_PATHS || '/api/v1/policy/effective,/api/v1/vuln/search?limit=50,/notify/api/v1/events?limit=20,/health/readiness') .split(',') .map((p) => p.trim()) .filter(Boolean); const WRITE_PATHS = (__ENV.TENANT_WRITE_PATHS || '/api/v1/policy/evaluate,/notify/api/v1/test,/api/v1/tasks/submit') .split(',') .map((p) => p.trim()) .filter(Boolean); const READ_FRACTION = Number(__ENV.READ_FRACTION || '0.9'); const SLEEP_MS = Number(__ENV.SLEEP_MS || '250'); let seed = Number(__ENV.SEED || '1'); function rnd() { seed = (seed * 1664525 + 1013904223) >>> 0; return seed / 4294967296; } export const options = { vus: Number(__ENV.VUS || '250'), duration: __ENV.DURATION || '10m', thresholds: { http_req_failed: ['rate<0.005'], http_req_duration: ['p(95)<300'], 'tenant_write_duration': ['p(95)<600'], 'tenant_auth_failures': ['rate<0.01'], }, }; const readDuration = new Trend('tenant_read_duration', true); const writeDuration = new Trend('tenant_write_duration', true); const authFailures = new Rate('tenant_auth_failures'); function pick(list) { return list[Math.floor(rnd() * list.length)]; } export default function () { const tenant = pick(TENANTS); const doWrite = rnd() > READ_FRACTION; const path = doWrite ? pick(WRITE_PATHS) : pick(READ_PATHS); const headers = { [TENANT_HEADER]: tenant, 'Content-Type': 'application/json', }; const url = `${BASE_URL}${path}`; const payload = JSON.stringify({ tenant, traceId: __VU + '-' + Date.now(), now: new Date().toISOString(), sample: 'tenant-chaos', }); const params = { headers, tags: { tenant, path, kind: doWrite ? 'write' : 'read' } }; const res = doWrite ? http.post(url, payload, params) : http.get(url, params); if (!check(res, { 'status ok': (r) => r.status >= 200 && r.status < 300, })) { if (res.status === 401 || res.status === 403) { authFailures.add(1); } } if (doWrite) { writeDuration.add(res.timings.duration); } else { readDuration.add(res.timings.duration); } sleep(SLEEP_MS / 1000); }