nxtgauge-backend-rust/load-tests/critical-flows.js

99 lines
2.9 KiB
JavaScript

import http from 'k6/http';
import { check, sleep, Trend } from 'k6';
import { Rate } from 'k6/metrics';
export let options = {
stages: [
{ duration: '1m', target: 20 }, // warm-up
{ duration: '3m', target: 50 }, // peak load
{ duration: '1m', target: 0 }, // ramp down
],
thresholds: {
http_req_duration: [
{ threshold: 'p(95)<800', abortOnFail: true },
{ threshold: 'p(99)<2000', abortOnFail: false },
],
'api success rate': ['rate>0.99'],
},
noConnectionReuse: false,
maxRedirects: 5,
};
const BASE_URL = __ENV.BASE_URL || 'http://localhost:8000';
const ADMIN_TOKEN = __ENV.ADMIN_TOKEN || ''; // optional
// Custom metrics
const loginTrend = new Trend('login_duration');
const registerTrend = new Trend('register_duration');
const jobsTrend = new Trend('jobs_list_duration');
const leadsTrend = new Trend('leads_list_duration');
// Helper: get auth headers
function authHeaders() {
return ADMIN_TOKEN ? { Authorization: `Bearer ${ADMIN_TOKEN}` } : {};
}
export default function () {
// 1. Login flow (simulate admin)
let loginRes = http.post(
`${BASE_URL}/api/auth/login`,
JSON.stringify({
email: 'admin@example.com',
password: 'test123',
loginTarget: 'admin',
}),
{
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
'x-portal-target': 'admin',
},
}
);
loginTrend.add(loginRes.timings.duration);
let success = check(loginRes, {
'login 200': (r) => r.status === 200,
'login has token': (r) => {
const t = r.json('token');
return t !== undefined && t !== null;
},
});
if (success) {
const body = loginRes.json();
const token = body.token;
const headers = { ...authHeaders(), Authorization: `Bearer ${token}` };
// 2. List companies
let res = http.get(`${BASE_URL}/api/admin/companies`, { headers });
check(res, { 'companies 200': (r) => r.status === 200 });
jobsTrend.add(res.timings.duration);
// 3. List jobs (via companies service)
res = http.get(`${BASE_URL}/api/admin/companies/jobs`, { headers });
check(res, { 'jobs 200': (r) => r.status === 200 });
leadsTrend.add(res.timings.duration);
// 4. Get single company detail
if (res.json().length > 0) {
const firstJob = res.json()[0];
if (firstJob.id) {
http.get(`${BASE_URL}/api/admin/companies/jobs/${firstJob.id}`, { headers });
}
}
// 5. List leads
res = http.get(`${BASE_URL}/api/admin/leads`, { headers });
check(res, { 'leads 200': (r) => r.status === 200 });
leadsTrend.add(res.timings.duration);
}
sleep(2);
}
// Summarize metrics at end
export function teardown() {
console.log(`Login avg: ${loginTrend.avg.toFixed(2)}ms`);
console.log(`Jobs list avg: ${jobsTrend.avg.toFixed(2)}ms`);
console.log(`Leads list avg: ${leadsTrend.avg.toFixed(2)}ms`);
}