veza/loadtests/backend/auth.js
senke fef7e7fc7c feat(loadtests): audit 3.2 — tests de charge k6 complets
- loadtests: centraliser scripts (backend, stream, chat)
- backend: health, auth, tracks, uploads, playlists, marketplace
- stream: http health, healthz, readyz
- chat: WebSocket load (register -> login -> chat token -> WS)
- ci: workflow nightly load-test-nightly.yml
- docs: README loadtests
- make: load-test-smoke, load-test-backend, load-test-all
- fix: veza-backend-api Makefile load-test (scripts/load_test_uploads.js -> loadtests)
2026-02-15 15:22:48 +01:00

165 lines
4.6 KiB
JavaScript

/**
* Load test: register, login, /me, refresh
* Chemins corrigés: /api/v1/auth/*
* Usage: k6 run loadtests/backend/auth.js
*/
import http from 'k6/http';
import { check, sleep } from 'k6';
import { Rate, Trend } from 'k6/metrics';
import { randomString } from 'https://jslib.k6.io/k6-utils/1.2.0/index.js';
const API_ORIGIN = __ENV.API_ORIGIN || __ENV.BASE_URL || 'http://localhost:8080';
const TEST_EMAIL_PREFIX = __ENV.TEST_EMAIL_PREFIX || 'user+load';
const TEST_EMAIL_DOMAIN = __ENV.TEST_EMAIL_DOMAIN || 'example.com';
const TEST_PASSWORD_PREFIX = __ENV.TEST_PASSWORD_PREFIX || 'V3za!load-';
const loginDuration = new Trend('login_duration');
const loginFailureRate = new Rate('login_failures');
const registerDuration = new Trend('register_duration');
const registerFailureRate = new Rate('register_failures');
export const options = {
scenarios: {
auth_flow: {
executor: 'ramping-vus',
stages: [
{ duration: '30s', target: 5 },
{ duration: '1m', target: 10 },
{ duration: '30s', target: 0 },
],
gracefulRampDown: '30s',
},
},
thresholds: {
http_req_duration: ['p(95)<300', 'p(99)<500'],
login_duration: ['p(95)<300', 'p(99)<500'],
register_duration: ['p(95)<800', 'p(99)<1000'],
login_failures: ['rate<0.1'],
register_failures: ['rate<0.1'],
http_req_failed: ['rate<0.1'],
},
};
function generateTestUser() {
const rand = randomString(8);
const pwd = `${TEST_PASSWORD_PREFIX}${rand}`;
return {
email: `${TEST_EMAIL_PREFIX}${rand}@${TEST_EMAIL_DOMAIN}`,
password: pwd,
password_confirmation: pwd,
username: `user${rand}`,
};
}
export function setup() {
const users = [];
const baseURL = `${API_ORIGIN}/api/v1/auth`;
for (let i = 0; i < 20; i++) {
const user = generateTestUser();
const registerRes = http.post(`${baseURL}/register`, JSON.stringify(user), {
headers: { 'Content-Type': 'application/json' },
});
if (registerRes.status === 201) {
users.push(user);
}
}
return { users };
}
export default function (data) {
const { users } = data;
if (users.length === 0) return;
const user = users[Math.floor(Math.random() * users.length)];
const baseURL = `${API_ORIGIN}/api/v1/auth`;
const loginPayload = JSON.stringify({
email: user.email,
password: user.password,
});
const loginStart = Date.now();
const loginRes = http.post(`${baseURL}/login`, loginPayload, {
headers: { 'Content-Type': 'application/json' },
});
loginDuration.add(Date.now() - loginStart);
loginFailureRate.add(loginRes.status !== 200);
check(loginRes, {
'login status is 200': (r) => r.status === 200,
'login has access_token': (r) => {
try {
const body = JSON.parse(r.body);
return body.success && body.data?.token?.access_token;
} catch {
return false;
}
},
});
let accessToken = '';
if (loginRes.status === 200) {
try {
const body = JSON.parse(loginRes.body);
accessToken = body.data?.token?.access_token || '';
} catch (e) {}
}
sleep(1);
if (accessToken) {
const meRes = http.get(`${baseURL}/me`, {
headers: { Authorization: `Bearer ${accessToken}` },
});
check(meRes, {
'profile status is 200': (r) => r.status === 200,
'profile has user data': (r) => {
try {
const body = JSON.parse(r.body);
return body.success && body.data?.id && body.data?.email;
} catch {
return false;
}
},
});
}
sleep(1);
if (Math.random() < 0.1) {
const invalidRes = http.post(
`${baseURL}/login`,
JSON.stringify({ email: user.email, password: 'WrongPassword123!' }),
{ headers: { 'Content-Type': 'application/json' } }
);
check(invalidRes, { 'invalid login returns 401': (r) => r.status === 401 });
}
sleep(1);
if (loginRes.status === 200) {
try {
const body = JSON.parse(loginRes.body);
const refreshToken = body.data?.token?.refresh_token;
if (refreshToken) {
const refreshRes = http.post(
`${baseURL}/refresh`,
JSON.stringify({ refresh_token: refreshToken }),
{ headers: { 'Content-Type': 'application/json' } }
);
check(refreshRes, {
'refresh status is 200': (r) => r.status === 200,
'refresh has new tokens': (r) => {
try {
const rb = JSON.parse(r.body);
return rb.success && rb.data?.access_token;
} catch {
return false;
}
},
});
}
} catch (e) {}
}
sleep(2);
}