Files
module4_backend_project/tests/load-test.js
T

284 lines
8.2 KiB
JavaScript
Raw Normal View History

2025-08-04 13:16:53 +01:00
const autocannon = require("autocannon");
const { performance } = require("perf_hooks");
class LoadTester {
constructor() {
2025-08-04 13:16:53 +01:00
this.baseUrl = process.env.TEST_URL || "http://localhost:3049";
this.results = [];
}
async runPurchaseLoadTest(eventId = 1, options = {}) {
const defaultOptions = {
url: `${this.baseUrl}/buy/${eventId}`,
connections: 5000,
duration: 30,
2025-08-04 13:16:53 +01:00
method: "POST",
headers: {
2025-08-04 13:16:53 +01:00
"Content-Type": "application/json",
},
body: JSON.stringify({}),
2025-08-04 13:16:53 +01:00
...options,
};
2025-08-04 13:16:53 +01:00
console.log(`\n Starting load test for Event ${eventId}`);
console.log(`Connections: ${defaultOptions.connections}`);
console.log(`Duration: ${defaultOptions.duration}s`);
console.log(`Target: ${defaultOptions.url}\n`);
const startTime = performance.now();
try {
const result = await autocannon(defaultOptions);
const endTime = performance.now();
2025-08-04 13:16:53 +01:00
const testResult = {
eventId,
timestamp: new Date().toISOString(),
duration: endTime - startTime,
2025-08-04 13:16:53 +01:00
...result,
};
this.results.push(testResult);
this.printResults(testResult);
2025-08-04 13:16:53 +01:00
return testResult;
} catch (error) {
2025-08-04 13:16:53 +01:00
console.error("❌ Load test failed:", error);
throw error;
}
}
async runMultiEventLoadTest(eventIds = [1, 2, 3], options = {}) {
2025-08-04 13:16:53 +01:00
console.log(
`\n Running multi-event load test for events: ${eventIds.join(", ")}`
);
const promises = eventIds.map((eventId) =>
this.runPurchaseLoadTest(eventId, {
2025-08-04 13:16:53 +01:00
connections: Math.floor(
(options.connections || 5000) / eventIds.length
),
duration: options.duration || 30,
})
);
try {
const results = await Promise.all(promises);
this.printSummary(results);
return results;
} catch (error) {
2025-08-04 13:16:53 +01:00
console.error("❌ Multi-event load test failed:", error);
throw error;
}
}
async runHealthCheckTest(options = {}) {
const defaultOptions = {
url: `${this.baseUrl}/health`,
connections: 100,
duration: 10,
2025-08-04 13:16:53 +01:00
...options,
};
2025-08-04 13:16:53 +01:00
console.log("\n Running health check load test...");
try {
const result = await autocannon(defaultOptions);
console.log(`✅ Health check test completed`);
2025-08-04 13:16:53 +01:00
console.log(`RPS: ${result.requests.average}`);
console.log(`Latency: ${result.latency.average}ms`);
return result;
} catch (error) {
2025-08-04 13:16:53 +01:00
console.error("❌ Health check test failed:", error);
throw error;
}
}
async runMetricsTest(options = {}) {
const defaultOptions = {
url: `${this.baseUrl}/metrics`,
connections: 50,
duration: 10,
2025-08-04 13:16:53 +01:00
...options,
};
2025-08-04 13:16:53 +01:00
console.log("\nRunning metrics endpoint test...");
try {
const result = await autocannon(defaultOptions);
console.log(`✅ Metrics test completed`);
2025-08-04 13:16:53 +01:00
console.log(`RPS: ${result.requests.average}`);
console.log(`Latency: ${result.latency.average}ms`);
return result;
} catch (error) {
2025-08-04 13:16:53 +01:00
console.error("Metrics test failed:", error);
throw error;
}
}
printResults(result) {
2025-08-04 13:16:53 +01:00
console.log("LOAD TEST RESULTS");
console.log("═".repeat(50));
console.log(`Event ID: ${result.eventId}`);
console.log(`Duration: ${(result.duration / 1000).toFixed(2)}s`);
console.log(`Total Requests: ${result.requests.total}`);
console.log(`Requests/sec: ${result.requests.average.toFixed(2)}`);
console.log(`Avg Latency: ${result.latency.average.toFixed(2)}ms`);
console.log(`Max Latency: ${result.latency.max}ms`);
console.log(
`✅ Success Rate: ${(
((result.requests.total - result.non2xx) / result.requests.total) *
100
).toFixed(2)}%`
);
console.log(`❌ Errors: ${result.non2xx}`);
2025-08-04 13:16:53 +01:00
console.log(`Connections: ${result.connections}`);
console.log(
`Throughput: ${(result.throughput.average / 1024 / 1024).toFixed(2)} MB/s`
);
console.log("═".repeat(50));
}
printSummary(results) {
2025-08-04 13:16:53 +01:00
console.log("\nMULTI-EVENT TEST SUMMARY");
console.log("═".repeat(60));
const totalRequests = results.reduce((sum, r) => sum + r.requests.total, 0);
const avgRPS = results.reduce((sum, r) => sum + r.requests.average, 0);
2025-08-04 13:16:53 +01:00
const avgLatency =
results.reduce((sum, r) => sum + r.latency.average, 0) / results.length;
const totalErrors = results.reduce((sum, r) => sum + r.non2xx, 0);
2025-08-04 13:16:53 +01:00
console.log(`Events Tested: ${results.length}`);
console.log(`Total Requests: ${totalRequests}`);
console.log(`Combined RPS: ${avgRPS.toFixed(2)}`);
console.log(`Avg Latency: ${avgLatency.toFixed(2)}ms`);
console.log(
`✅ Overall Success Rate: ${(
((totalRequests - totalErrors) / totalRequests) *
100
).toFixed(2)}%`
);
console.log(`❌ Total Errors: ${totalErrors}`);
2025-08-04 13:16:53 +01:00
console.log("═".repeat(60));
// Individual event breakdown
results.forEach((result, index) => {
2025-08-04 13:16:53 +01:00
console.log(`\nEvent ${result.eventId}:`);
console.log(` RPS: ${result.requests.average.toFixed(2)}`);
console.log(` Latency: ${result.latency.average.toFixed(2)}ms`);
console.log(
` ✅ Success: ${(
((result.requests.total - result.non2xx) / result.requests.total) *
100
).toFixed(2)}%`
);
});
}
async runFullTestSuite() {
2025-08-04 13:16:53 +01:00
console.log("STARTING FULL LOAD TEST SUITE");
console.log("═".repeat(60));
try {
// 1. Health check test
await this.runHealthCheckTest();
2025-08-04 13:16:53 +01:00
// 2. Metrics test
await this.runMetricsTest();
2025-08-04 13:16:53 +01:00
// 3. Single event high-load test
2025-08-04 13:16:53 +01:00
await this.runPurchaseLoadTest(1, {
connections: 5000,
duration: 30,
});
2025-08-04 13:16:53 +01:00
// 4. Multi-event test
await this.runMultiEventLoadTest([1, 2, 3], {
connections: 6000,
2025-08-04 13:16:53 +01:00
duration: 30,
});
2025-08-04 13:16:53 +01:00
console.log("\n FULL TEST SUITE COMPLETED!");
console.log(` Total tests run: ${this.results.length + 2}`);
} catch (error) {
2025-08-04 13:16:53 +01:00
console.error("❌ Test suite failed:", error);
process.exit(1);
}
}
getResults() {
return this.results;
}
2025-08-04 13:16:53 +01:00
exportResults(filename = "load-test-results.json") {
const fs = require("fs");
const data = {
timestamp: new Date().toISOString(),
2025-08-04 13:16:53 +01:00
testSuite: "Ticket Microservice Load Test",
results: this.results,
};
2025-08-04 13:16:53 +01:00
fs.writeFileSync(filename, JSON.stringify(data, null, 2));
console.log(`📄 Results exported to: ${filename}`);
}
}
// CLI execution
if (require.main === module) {
const args = process.argv.slice(2);
const tester = new LoadTester();
2025-08-04 13:16:53 +01:00
async function main() {
try {
2025-08-04 13:16:53 +01:00
if (args.includes("--full")) {
await tester.runFullTestSuite();
2025-08-04 13:16:53 +01:00
} else if (args.includes("--event")) {
const eventId = parseInt(args[args.indexOf("--event") + 1]) || 1;
const connections =
parseInt(args[args.indexOf("--connections") + 1]) || 5000;
const duration = parseInt(args[args.indexOf("--duration") + 1]) || 30;
await tester.runPurchaseLoadTest(eventId, { connections, duration });
2025-08-04 13:16:53 +01:00
} else if (args.includes("--multi")) {
const eventIds = args.includes("--events")
? args[args.indexOf("--events") + 1].split(",").map(Number)
: [1, 2, 3];
2025-08-04 13:16:53 +01:00
const connections =
parseInt(args[args.indexOf("--connections") + 1]) || 6000;
const duration = parseInt(args[args.indexOf("--duration") + 1]) || 30;
await tester.runMultiEventLoadTest(eventIds, { connections, duration });
} else {
2025-08-04 13:16:53 +01:00
console.log("Ticket Microservice Load Tester");
console.log("Usage:");
console.log(
" node tests/load-test.js --full # Run full test suite"
);
console.log(
" node tests/load-test.js --event 1 --connections 5000 --duration 30"
);
console.log(
" node tests/load-test.js --multi --events 1,2,3 --connections 6000"
);
console.log("");
console.log("Running default single event test...");
await tester.runPurchaseLoadTest(1);
}
2025-08-04 13:16:53 +01:00
if (args.includes("--export")) {
tester.exportResults();
}
} catch (error) {
2025-08-04 13:16:53 +01:00
console.error("Test execution failed:", error);
process.exit(1);
}
}
2025-08-04 13:16:53 +01:00
main();
}
module.exports = LoadTester;