// Нагрузочный смоук-тест API Deal на k6 (этап 12, пакет C) — альтернатива // scripts/loadtest/api-loadtest.sh, если в системе есть k6. // // Логин — в setup() (один раз), затем виртуальные пользователи в цикле читают // GET /api/containers и GET /api/cards. Пороги (thresholds) проваливают прогон // при доле ошибок > 1% или p95 > 500 мс. // // Запуск (API dev на :5080): // k6 run scripts/loadtest/deal-loadtest.js // BASE_URL=http://localhost:5080 VUS=10 DURATION=30s k6 run scripts/loadtest/deal-loadtest.js // // Переменные окружения: BASE_URL, LOGIN, PASSWORD, VUS, DURATION. // Внимание: в PROD включён rate-limit (api — 600/мин на тенанта) — гоняйте на dev. import http from 'k6/http'; import { check, sleep } from 'k6'; const BASE_URL = __ENV.BASE_URL || 'http://localhost:5080'; const LOGIN = __ENV.LOGIN || 'admin'; const PASSWORD = __ENV.PASSWORD || 'admin'; export const options = { vus: __ENV.VUS ? Number(__ENV.VUS) : 5, duration: __ENV.DURATION || '20s', thresholds: { http_req_failed: ['rate<0.01'], http_req_duration: ['p(95)<500'], }, }; export function setup() { const res = http.post( `${BASE_URL}/api/auth/login`, JSON.stringify({ login: LOGIN, password: PASSWORD }), { headers: { 'Content-Type': 'application/json' } } ); if (res.status !== 200) { throw new Error(`login failed: HTTP ${res.status} — ${res.body}`); } const cookies = res.cookies['deal_session']; const session = cookies && cookies.length ? cookies[0].value : ''; if (!session) { throw new Error('login succeeded but deal_session cookie is missing'); } return { session }; } export default function (data) { const params = { headers: { Cookie: `deal_session=${data.session}` } }; const paths = ['/api/containers', '/api/cards']; for (const path of paths) { const res = http.get(`${BASE_URL}${path}`, params); check(res, { [`${path} → 200`]: (r) => r.status === 200 }); } sleep(0.2); }