/** * Phase-0-Baseline: parallele GET /api/health (kein Auth). * BASE_URL optional, z. B. https://dev.kairo.jinkendo.de * * K6_CI=1: leichtere Last für Self-hosted Runner (Raspberry Pi). */ import http from 'k6/http' import { check } from 'k6' const isCi = __ENV.K6_CI === '1' || __ENV.K6_CI === 'true' const vus = parseInt(__ENV.K6_VUS || (isCi ? '5' : '10'), 10) const duration = __ENV.K6_DURATION || (isCi ? '15s' : '30s') const p95Ms = parseInt(__ENV.K6_P95_MS || (isCi ? '5000' : '3000'), 10) export const options = { scenarios: { health: { executor: 'constant-vus', vus, duration, gracefulStop: '5s', tags: { scenario: 'health' }, exec: 'health', }, }, thresholds: { http_req_failed: ['rate<0.05'], 'http_req_duration{scenario:health}': [`p(95)<${p95Ms}`], }, summaryTrendStats: ['avg', 'min', 'med', 'max', 'p(90)', 'p(95)'], } const BASE = (__ENV.BASE_URL || 'https://dev.kairo.jinkendo.de').replace(/\/$/, '') export function health() { const res = http.get(`${BASE}/api/health`, { tags: { scenario: 'health' } }) check(res, { 'health 2xx': (r) => r.status >= 200 && r.status < 300, }) } export function handleSummary(data) { const failed = data.metrics.http_req_failed?.values?.rate ?? 0 const p95 = data.metrics.http_req_duration?.values?.['p(95)'] ?? 0 const lines = [ `k6 summary: BASE=${BASE} vus=${vus} duration=${duration}`, ` http_req_failed=${(failed * 100).toFixed(2)}% p(95)=${p95.toFixed(1)}ms (limit ${p95Ms}ms)`, ] return { stdout: lines.join('\n') + '\n' } }