kuwot-api/testLoad.js
2025-10-20 08:18:02 +07:00

195 lines
6.1 KiB
JavaScript

// Stress test script for Quote API
// Usage: node stress-test.js
const ENDPOINTS = [
'http://localhost:8080/quotes/random',
'http://localhost:8080/translations',
];
// Test configurations
const TESTS = [
{ name: 'Light Load', concurrent: 10, duration: 10 },
{ name: 'Medium Load', concurrent: 50, duration: 10 },
{ name: 'Heavy Load', concurrent: 100, duration: 10 },
{ name: 'Extreme Load', concurrent: 200, duration: 10 },
];
class StressTest {
constructor(endpoint, concurrent, duration) {
this.endpoint = endpoint;
this.concurrent = concurrent;
this.duration = duration;
this.results = {
total: 0,
success: 0,
failed: 0,
rateLimited: 0,
totalTime: 0,
responseTimes: [],
};
}
async makeRequest() {
const start = Date.now();
try {
const response = await fetch(this.endpoint);
const elapsed = Date.now() - start;
this.results.total++;
this.results.totalTime += elapsed;
this.results.responseTimes.push(elapsed);
if (response.status === 429) {
this.results.rateLimited++;
} else if (response.ok) {
this.results.success++;
} else {
this.results.failed++;
}
} catch (error) {
this.results.total++;
this.results.failed++;
}
}
async runWorker(stopTime) {
while (Date.now() < stopTime) {
await this.makeRequest();
}
}
async run() {
console.log(
`\n🚀 Starting test: ${this.concurrent} concurrent requests for ${this.duration}s`
);
console.log(` Endpoint: ${this.endpoint}`);
const startTime = Date.now();
const stopTime = startTime + this.duration * 1000;
// Launch concurrent workers
const workers = [];
for (let i = 0; i < this.concurrent; i++) {
workers.push(this.runWorker(stopTime));
}
await Promise.all(workers);
const actualDuration = (Date.now() - startTime) / 1000;
return this.calculateStats(actualDuration);
}
calculateStats(duration) {
const { total, success, failed, rateLimited, responseTimes } = this.results;
// Sort response times for percentile calculations
responseTimes.sort((a, b) => a - b);
const getPercentile = (p) => {
const index = Math.ceil((p / 100) * responseTimes.length) - 1;
return responseTimes[index] || 0;
};
return {
requestsPerSecond: (total / duration).toFixed(2),
totalRequests: total,
successful: success,
failed: failed,
rateLimited: rateLimited,
successRate: ((success / total) * 100).toFixed(2) + '%',
avgResponseTime: (this.results.totalTime / total).toFixed(2) + 'ms',
minResponseTime: Math.min(...responseTimes) + 'ms',
maxResponseTime: Math.max(...responseTimes) + 'ms',
p50: getPercentile(50) + 'ms',
p95: getPercentile(95) + 'ms',
p99: getPercentile(99) + 'ms',
};
}
printResults(stats) {
console.log('\n📊 Results:');
console.log(` Requests/sec: ${stats.requestsPerSecond}`);
console.log(` Total requests: ${stats.totalRequests}`);
console.log(` Successful: ${stats.successful}`);
console.log(` Failed: ${stats.failed}`);
console.log(` Rate limited: ${stats.rateLimited}`);
console.log(` Success rate: ${stats.successRate}`);
console.log(`\n⏱️ Response Times:`);
console.log(` Average: ${stats.avgResponseTime}`);
console.log(` Min: ${stats.minResponseTime}`);
console.log(` Max: ${stats.maxResponseTime}`);
console.log(` 50th percentile: ${stats.p50}`);
console.log(` 95th percentile: ${stats.p95}`);
console.log(` 99th percentile: ${stats.p99}`);
}
}
async function runAllTests() {
console.log('═══════════════════════════════════════════');
console.log(' API STRESS TEST');
console.log('═══════════════════════════════════════════');
const endpoint = ENDPOINTS[0]; // Test random quotes endpoint
const allResults = [];
for (const testConfig of TESTS) {
const test = new StressTest(
endpoint,
testConfig.concurrent,
testConfig.duration
);
console.log(`\n\n▶️ ${testConfig.name.toUpperCase()}`);
const stats = await test.run();
test.printResults(stats);
allResults.push({
name: testConfig.name,
...stats,
});
// Cool down period between tests
if (testConfig !== TESTS[TESTS.length - 1]) {
console.log('\n\n⏳ Cooling down for 5 seconds...');
await new Promise((resolve) => setTimeout(resolve, 5000));
}
}
// Print summary
console.log('\n\n═══════════════════════════════════════════');
console.log(' SUMMARY');
console.log('═══════════════════════════════════════════\n');
console.log('Test Name | Req/s | Success Rate | Avg Response');
console.log('-------------------|--------|--------------|-------------');
allResults.forEach((result) => {
const name = result.name.padEnd(18);
const rps = result.requestsPerSecond.padEnd(6);
const successRate = result.successRate.padEnd(12);
const avgTime = result.avgResponseTime.padEnd(12);
console.log(`${name} | ${rps} | ${successRate} | ${avgTime}`);
});
console.log('\n✅ All tests completed!');
}
// Check if endpoint is reachable before starting
async function checkEndpoint() {
try {
const response = await fetch(ENDPOINTS[0]);
if (!response.ok && response.status !== 429) {
console.error('❌ Server not responding correctly. Is it running?');
process.exit(1);
}
} catch (error) {
console.error('❌ Cannot reach server. Please start your server first.');
console.error(` URL: ${ENDPOINTS[0]}`);
process.exit(1);
}
}
// Run the tests
(async () => {
await checkEndpoint();
await runAllTests();
})();