/** * Load test: GET tracks, search, track detail * Usage: k6 run loadtests/backend/tracks.js * Option: AUTH_TOKEN for authenticated requests */ import http from 'k6/http'; import { check, sleep } from 'k6'; import { Rate } from 'k6/metrics'; const errorRate = new Rate('errors'); const BASE_URL = __ENV.BASE_URL || __ENV.API_ORIGIN || 'http://localhost:8080'; const AUTH_TOKEN = __ENV.AUTH_TOKEN || ''; export const options = { stages: [ { duration: '30s', target: 10 }, { duration: '1m', target: 15 }, { duration: '30s', target: 0 }, ], thresholds: { http_req_duration: ['p(95)<500', 'p(99)<1000'], errors: ['rate<0.05'], }, }; export default function () { const headers = AUTH_TOKEN ? { Authorization: `Bearer ${AUTH_TOKEN}` } : {}; const tracksRes = http.get(`${BASE_URL}/api/v1/tracks`, { headers }); const tracksOk = check(tracksRes, { 'tracks returns 200 or 401': (r) => r.status === 200 || r.status === 401, }); errorRate.add(!tracksOk && tracksRes.status >= 500); sleep(0.5); const searchRes = http.get( `${BASE_URL}/api/v1/tracks/search?q=test&limit=10`, { headers } ); check(searchRes, { 'search returns 200 or 401': (r) => r.status === 200 || r.status === 401, }); errorRate.add(searchRes.status >= 500); sleep(0.5); if (tracksRes.status === 200) { try { const body = JSON.parse(tracksRes.body); const tracks = body.data?.tracks || body.data || body.tracks || []; if (Array.isArray(tracks) && tracks.length > 0) { const trackId = tracks[0].id || tracks[0].ID; if (trackId) { const detailRes = http.get( `${BASE_URL}/api/v1/tracks/${trackId}`, { headers } ); check(detailRes, { 'track detail returns 200 or 404': (r) => r.status === 200 || r.status === 404, }); } } } catch (e) {} } sleep(1); }