import { tap, expect } from '@git.zone/tstest/tapbundle'; import { startTestServer, stopTestServer, type ITestServer } from '../../helpers/server.loader.js'; // import { createTestSmtpClient, sendConcurrentEmails, measureClientThroughput } from '../../helpers/smtp.client.js'; import { connectToSmtp, sendSmtpCommand, waitForGreeting, createMimeMessage, closeSmtpConnection } from '../../helpers/utils.js'; let testServer: ITestServer; tap.test('setup - start SMTP server for performance testing', async () => { testServer = await startTestServer({ port: 2531, hostname: 'localhost', maxConnections: 1000, size: 50 * 1024 * 1024 // 50MB for performance testing }); expect(testServer).toBeInstanceOf(Object); }); // TODO: Enable these tests when the helper functions are implemented /* tap.test('PERF-01: Throughput Testing - measure emails per second', async () => { const client = createTestSmtpClient({ host: testServer.hostname, port: testServer.port, maxConnections: 10 }); try { // Warm up the connection pool console.log('šŸ”„ Warming up connection pool...'); await sendConcurrentEmails(client, 5); // Measure throughput for 10 seconds console.log('šŸ“Š Measuring throughput for 10 seconds...'); const startTime = Date.now(); const testDuration = 10000; // 10 seconds const result = await measureClientThroughput(client, testDuration, { from: 'perf-test@example.com', to: 'recipient@example.com', subject: 'Performance Test Email', text: 'This is a performance test email to measure throughput.' }); const actualDuration = (Date.now() - startTime) / 1000; console.log('šŸ“ˆ Throughput Test Results:'); console.log(` Total emails sent: ${result.totalSent}`); console.log(` Successful: ${result.successCount}`); console.log(` Failed: ${result.errorCount}`); console.log(` Duration: ${actualDuration.toFixed(2)}s`); console.log(` Throughput: ${result.throughput.toFixed(2)} emails/second`); // Performance expectations expect(result.throughput).toBeGreaterThan(10); // At least 10 emails/second expect(result.errorCount).toBeLessThan(result.totalSent * 0.05); // Less than 5% errors console.log('āœ… Throughput test passed'); } finally { if (client.close) { await client.close(); } } }); tap.test('PERF-01: Burst throughput - handle sudden load spikes', async () => { const client = createTestSmtpClient({ host: testServer.hostname, port: testServer.port, maxConnections: 20 }); try { // Send burst of emails const burstSize = 100; console.log(`šŸ’„ Sending burst of ${burstSize} emails...`); const startTime = Date.now(); const results = await sendConcurrentEmails(client, burstSize, { from: 'burst-test@example.com', to: 'recipient@example.com', subject: 'Burst Test Email', text: 'Testing burst performance.' }); const duration = Date.now() - startTime; const successCount = results.filter(r => r && !r.rejected).length; const throughput = (successCount / duration) * 1000; console.log(`āœ… Burst completed in ${duration}ms`); console.log(` Success rate: ${successCount}/${burstSize} (${(successCount/burstSize*100).toFixed(1)}%)`); console.log(` Burst throughput: ${throughput.toFixed(2)} emails/second`); expect(successCount).toBeGreaterThan(burstSize * 0.95); // 95% success rate } finally { if (client.close) { await client.close(); } } }); */ tap.test('PERF-01: Large message throughput - measure with varying sizes', async () => { const messageSizes = [ { size: 1024, label: '1KB' }, { size: 100 * 1024, label: '100KB' }, { size: 1024 * 1024, label: '1MB' }, { size: 5 * 1024 * 1024, label: '5MB' } ]; for (const { size, label } of messageSizes) { console.log(`\nšŸ“§ Testing throughput with ${label} messages...`); const socket = await connectToSmtp(testServer.hostname, testServer.port); try { await waitForGreeting(socket); await sendSmtpCommand(socket, 'EHLO test.example.com', '250'); // Send a few messages of this size const messageCount = 5; const timings: number[] = []; for (let i = 0; i < messageCount; i++) { const startTime = Date.now(); await sendSmtpCommand(socket, 'MAIL FROM:', '250'); await sendSmtpCommand(socket, 'RCPT TO:', '250'); await sendSmtpCommand(socket, 'DATA', '354'); // Create message with padding to reach target size const padding = 'X'.repeat(Math.max(0, size - 200)); // Account for headers const emailContent = createMimeMessage({ from: 'size-test@example.com', to: 'recipient@example.com', subject: `${label} Performance Test`, text: padding }); socket.write(emailContent); socket.write('\r\n.\r\n'); // Wait for acceptance await new Promise((resolve, reject) => { const timeout = setTimeout(() => reject(new Error('Timeout')), 30000); const onData = (data: Buffer) => { if (data.toString().includes('250')) { clearTimeout(timeout); socket.removeListener('data', onData); resolve(); } }; socket.on('data', onData); }); const duration = Date.now() - startTime; timings.push(duration); // Reset for next message await sendSmtpCommand(socket, 'RSET', '250'); } const avgTime = timings.reduce((a, b) => a + b, 0) / timings.length; const throughputMBps = (size / 1024 / 1024) / (avgTime / 1000); console.log(` Average time: ${avgTime.toFixed(0)}ms`); console.log(` Throughput: ${throughputMBps.toFixed(2)} MB/s`); } finally { await closeSmtpConnection(socket); } } console.log('\nāœ… Large message throughput test completed'); }); tap.test('cleanup - stop SMTP server', async () => { await stopTestServer(testServer); console.log('āœ… Test server stopped'); }); export default tap.start();