dcrouter/test/suite/smtpserver_performance/test.perf-01.throughput.ts
2025-05-25 19:05:43 +00:00

183 lines
6.2 KiB
TypeScript

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:<size-test@example.com>', '250');
await sendSmtpCommand(socket, 'RCPT TO:<recipient@example.com>', '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<void>((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();