70 lines
2.3 KiB
TypeScript
70 lines
2.3 KiB
TypeScript
/**
|
|||
|
|
* specs/016-load-concurrency-testing User Story 5 / FR-007: load/throughput baseline for the
|
||
|
|
* 015-reporting-dashboards admin endpoints — pure database aggregation reads, no third-party
|
||
|
|
* cost (unlike ai-support-flow.load.ts). Run against a real running dev server:
|
||
|
|
* `npx tsx tests/load/admin-reporting.load.ts`.
|
||
|
|
*
|
||
|
|
* Signs in as the project's own seeded admin account once (a session JWT is reusable across
|
||
|
|
* requests, unlike 002-saas-integration's single-use integration tokens), then cycles across
|
||
|
|
* all four dashboards so the report reflects a realistic mix of the endpoint group, not just one
|
||
|
|
* route.
|
||
|
|
*/
|
||
|
|
import { runLoadTest } from './autocannon.config';
|
||
|
|
|
||
|
|
const API_URL = process.env.LOAD_TEST_API_URL ?? 'http://localhost:4501';
|
||
|
|
const CONNECTIONS = Number(process.env.LOAD_TEST_CONNECTIONS ?? 10);
|
||
|
|
const DURATION_SEC = Number(process.env.LOAD_TEST_DURATION_SEC ?? 10);
|
||
|
|
const ADMIN_EMAIL = process.env.LOAD_TEST_ADMIN_EMAIL ?? 'admin@supporthub.internal';
|
||
|
|
const ADMIN_PASSWORD = process.env.LOAD_TEST_ADMIN_PASSWORD ?? 'ChangeMe123!';
|
||
|
|
|
||
|
|
const DASHBOARD_PATHS = [
|
||
|
|
'/admin/reports/management',
|
||
|
|
'/admin/reports/support',
|
||
|
|
'/admin/reports/ai',
|
||
|
|
];
|
||
|
|
|
||
|
|
async function signIn(): Promise<string> {
|
||
|
|
const response = await fetch(`${API_URL}/auth/login`, {
|
||
|
|
method: 'POST',
|
||
|
|
headers: { 'content-type': 'application/json' },
|
||
|
|
body: JSON.stringify({ email: ADMIN_EMAIL, password: ADMIN_PASSWORD }),
|
||
|
|
});
|
||
|
|
if (!response.ok) {
|
||
|
|
throw new Error(
|
||
|
|
`Admin sign-in failed (${response.status}) — set LOAD_TEST_ADMIN_EMAIL/PASSWORD if the seeded admin credentials differ.`,
|
||
|
|
);
|
||
|
|
}
|
||
|
|
const body = (await response.json()) as { data: { token: string } };
|
||
|
|
return body.data.token;
|
||
|
|
}
|
||
|
|
|
||
|
|
async function main(): Promise<void> {
|
||
|
|
const token = await signIn();
|
||
|
|
|
||
|
|
let requestIndex = 0;
|
||
|
|
await runLoadTest('admin-reporting', {
|
||
|
|
url: API_URL,
|
||
|
|
connections: CONNECTIONS,
|
||
|
|
duration: DURATION_SEC,
|
||
|
|
requests: [
|
||
|
|
{
|
||
|
|
method: 'GET',
|
||
|
|
headers: { authorization: `Bearer ${token}` },
|
||
|
|
setupRequest: (request) => {
|
||
|
|
request.path = DASHBOARD_PATHS[requestIndex % DASHBOARD_PATHS.length];
|
||
|
|
requestIndex += 1;
|
||
|
|
return request;
|
||
|
|
},
|
||
|
|
},
|
||
|
|
],
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
main()
|
||
|
|
.then(() => process.exit(0))
|
||
|
|
.catch((error) => {
|
||
|
|
// eslint-disable-next-line no-console
|
||
|
|
console.error(error);
|
||
|
|
process.exit(1);
|
||
|
|
});
|