import * as plugins from '@push.rocks/tapbundle'; import { expect, tap } from '@push.rocks/tapbundle'; import * as net from 'net'; import { startTestServer, stopTestServer } from '../server.loader.js'; const TEST_PORT = 2525; tap.test('prepare server', async () => { await startTestServer(); await new Promise(resolve => setTimeout(resolve, 100)); }); tap.test('PERF-03: CPU utilization - Load test', async (tools) => { const done = tools.defer(); const monitoringDuration = 5000; // 5 seconds const connectionCount = 10; const connections: net.Socket[] = []; try { // Record initial CPU usage const initialCpuUsage = process.cpuUsage(); const startTime = Date.now(); // Create multiple connections and send emails console.log(`Creating ${connectionCount} connections for CPU load test...`); for (let i = 0; i < connectionCount; i++) { const socket = net.createConnection({ host: 'localhost', port: TEST_PORT, timeout: 30000 }); connections.push(socket); await new Promise((resolve, reject) => { socket.once('connect', () => { resolve(); }); socket.once('error', reject); }); // Process greeting await new Promise((resolve) => { socket.once('data', () => resolve()); }); // Send EHLO socket.write(`EHLO testhost-cpu-${i}\r\n`); await new Promise((resolve) => { let data = ''; const handleData = (chunk: Buffer) => { data += chunk.toString(); if (data.includes('250 ') && !data.includes('250-')) { socket.removeListener('data', handleData); resolve(); } }; socket.on('data', handleData); }); // Send email transaction socket.write(`MAIL FROM:\r\n`); await new Promise((resolve) => { socket.once('data', (chunk) => { const response = chunk.toString(); expect(response).toInclude('250'); resolve(); }); }); socket.write(`RCPT TO:\r\n`); await new Promise((resolve) => { socket.once('data', (chunk) => { const response = chunk.toString(); expect(response).toInclude('250'); resolve(); }); }); socket.write('DATA\r\n'); await new Promise((resolve) => { socket.once('data', (chunk) => { const response = chunk.toString(); expect(response).toInclude('354'); resolve(); }); }); // Send email content const emailContent = [ `From: sender${i}@example.com`, `To: recipient${i}@example.com`, `Subject: CPU Utilization Test ${i}`, '', `This email tests CPU utilization during concurrent operations.`, `Connection ${i} of ${connectionCount}`, '.', '' ].join('\r\n'); socket.write(emailContent); await new Promise((resolve) => { socket.once('data', (chunk) => { const response = chunk.toString(); expect(response).toInclude('250'); resolve(); }); }); } // Keep connections active during monitoring period console.log(`Monitoring CPU usage for ${monitoringDuration}ms...`); // Send periodic NOOP commands to keep connections active const noopInterval = setInterval(() => { connections.forEach((socket, idx) => { if (socket.writable) { socket.write('NOOP\r\n'); } }); }, 1000); await new Promise(resolve => setTimeout(resolve, monitoringDuration)); clearInterval(noopInterval); // Calculate CPU usage const finalCpuUsage = process.cpuUsage(initialCpuUsage); const totalCpuTimeMs = (finalCpuUsage.user + finalCpuUsage.system) / 1000; const elapsedTime = Date.now() - startTime; const cpuUtilizationPercent = (totalCpuTimeMs / elapsedTime) * 100; console.log(`\nCPU Utilization Results:`); console.log(`Total CPU time: ${totalCpuTimeMs.toFixed(0)}ms`); console.log(`Elapsed time: ${elapsedTime}ms`); console.log(`CPU utilization: ${cpuUtilizationPercent.toFixed(1)}%`); console.log(`User CPU: ${(finalCpuUsage.user / 1000).toFixed(0)}ms`); console.log(`System CPU: ${(finalCpuUsage.system / 1000).toFixed(0)}ms`); // Clean up connections for (const socket of connections) { if (socket.writable) { socket.write('QUIT\r\n'); socket.end(); } } // Test passes if CPU usage is reasonable (less than 80%) expect(cpuUtilizationPercent).toBeLessThan(80); done.resolve(); } catch (error) { // Clean up on error connections.forEach(socket => socket.destroy()); done.reject(error); } }); tap.test('PERF-03: CPU utilization - Stress test', async (tools) => { const done = tools.defer(); const testDuration = 3000; // 3 seconds let requestCount = 0; try { const initialCpuUsage = process.cpuUsage(); const startTime = Date.now(); console.log(`\nRunning CPU stress test for ${testDuration}ms...`); // Create a single connection for rapid requests const socket = net.createConnection({ host: 'localhost', port: TEST_PORT, timeout: 30000 }); await new Promise((resolve, reject) => { socket.once('connect', resolve); socket.once('error', reject); }); // Read greeting await new Promise((resolve) => { socket.once('data', () => resolve()); }); // Send EHLO socket.write('EHLO stresstest\r\n'); await new Promise((resolve) => { let data = ''; const handleData = (chunk: Buffer) => { data += chunk.toString(); if (data.includes('250 ') && !data.includes('250-')) { socket.removeListener('data', handleData); resolve(); } }; socket.on('data', handleData); }); // Rapid command loop const endTime = Date.now() + testDuration; const commands = ['NOOP', 'RSET', 'VRFY test@example.com', 'HELP']; let commandIndex = 0; while (Date.now() < endTime) { const command = commands[commandIndex % commands.length]; socket.write(`${command}\r\n`); await new Promise((resolve) => { socket.once('data', () => { requestCount++; resolve(); }); }); commandIndex++; // Small delay to avoid overwhelming if (requestCount % 20 === 0) { await new Promise(resolve => setTimeout(resolve, 10)); } } // Calculate final CPU usage const finalCpuUsage = process.cpuUsage(initialCpuUsage); const totalCpuTimeMs = (finalCpuUsage.user + finalCpuUsage.system) / 1000; const elapsedTime = Date.now() - startTime; const cpuUtilizationPercent = (totalCpuTimeMs / elapsedTime) * 100; const requestsPerSecond = (requestCount / elapsedTime) * 1000; console.log(`\nStress Test Results:`); console.log(`Requests processed: ${requestCount}`); console.log(`Requests per second: ${requestsPerSecond.toFixed(1)}`); console.log(`CPU utilization: ${cpuUtilizationPercent.toFixed(1)}%`); console.log(`CPU time per request: ${(totalCpuTimeMs / requestCount).toFixed(2)}ms`); socket.write('QUIT\r\n'); socket.end(); // Test passes if CPU usage per request is reasonable const cpuPerRequest = totalCpuTimeMs / requestCount; expect(cpuPerRequest).toBeLessThan(10); // Less than 10ms CPU per request done.resolve(); } catch (error) { done.reject(error); } }); tap.test('cleanup server', async () => { await stopTestServer(); }); tap.start();