import { test } from '@git.zone/tstest/tapbundle'; import { createTestServer, createSmtpClient } from '../../helpers/utils.js'; import { Email } from '../../../ts/mail/core/classes.email.js'; test('CPERF-07: Queue Management Performance Tests', async () => { console.log('\nšŸš€ Testing SMTP Client Queue Management Performance'); console.log('=' .repeat(60)); // Scenario 1: Queue Processing Speed await test.test('Scenario 1: Queue Processing Speed', async () => { console.log('\nšŸ“Š Testing queue processing speed and throughput...'); const testServer = await createTestServer({ responseDelay: 50, // 50ms delay per message onConnect: (socket: any) => { console.log(' [Server] Client connected for queue speed test'); } }); const smtpClient = createSmtpClient({ host: testServer.hostname, port: testServer.port, secure: false, pool: true, maxConnections: 3, maxMessages: 50, rateDelta: 1000, rateLimit: 10 // 10 emails per second }); try { console.log(' Creating 25 test emails for queue processing...'); const emails = []; for (let i = 0; i < 25; i++) { emails.push(new Email({ from: 'sender@example.com', to: [`recipient${i}@example.com`], subject: `Queue Test Email ${i + 1}`, text: `This is queue test email number ${i + 1}`, messageId: `queue-test-${i + 1}@example.com` })); } const startTime = Date.now(); console.log(' Starting bulk queue processing...'); const promises = emails.map((email, index) => { return smtpClient.sendMail(email).then(result => { console.log(` āœ“ Email ${index + 1} processed: ${result.messageId}`); return { index, result, timestamp: Date.now() }; }).catch(error => { console.log(` āœ— Email ${index + 1} failed: ${error.message}`); return { index, error, timestamp: Date.now() }; }); }); const results = await Promise.all(promises); const endTime = Date.now(); const totalTime = endTime - startTime; const throughput = (emails.length / totalTime) * 1000; // emails per second console.log(` Queue processing completed in ${totalTime}ms`); console.log(` Throughput: ${throughput.toFixed(2)} emails/second`); console.log(` Success rate: ${results.filter(r => !r.error).length}/${emails.length}`); } finally { smtpClient.close(); testServer.close(); } }); // Scenario 2: Queue Priority Management await test.test('Scenario 2: Queue Priority Management', async () => { console.log('\nšŸŽÆ Testing queue priority and email ordering...'); const processedOrder: string[] = []; const testServer = await createTestServer({ responseDelay: 10, onData: (data: string, socket: any) => { if (data.includes('Subject: HIGH PRIORITY')) { processedOrder.push('HIGH'); } else if (data.includes('Subject: NORMAL PRIORITY')) { processedOrder.push('NORMAL'); } else if (data.includes('Subject: LOW PRIORITY')) { processedOrder.push('LOW'); } } }); const smtpClient = createSmtpClient({ host: testServer.hostname, port: testServer.port, secure: false, pool: true, maxConnections: 1 // Single connection to test ordering }); try { console.log(' Creating emails with different priorities...'); // Create emails in mixed order but with priority headers const emails = [ new Email({ from: 'sender@example.com', to: ['recipient1@example.com'], subject: 'LOW PRIORITY Email 1', text: 'Low priority content', priority: 'low', headers: { 'X-Priority': '5' } }), new Email({ from: 'sender@example.com', to: ['recipient2@example.com'], subject: 'HIGH PRIORITY Email 1', text: 'High priority content', priority: 'high', headers: { 'X-Priority': '1' } }), new Email({ from: 'sender@example.com', to: ['recipient3@example.com'], subject: 'NORMAL PRIORITY Email 1', text: 'Normal priority content', priority: 'normal', headers: { 'X-Priority': '3' } }), new Email({ from: 'sender@example.com', to: ['recipient4@example.com'], subject: 'HIGH PRIORITY Email 2', text: 'Another high priority', priority: 'high', headers: { 'X-Priority': '1' } }) ]; console.log(' Sending emails and monitoring processing order...'); // Send all emails simultaneously const promises = emails.map((email, index) => { return new Promise(resolve => { setTimeout(() => { smtpClient.sendMail(email).then(resolve).catch(resolve); }, index * 20); // Small delays to ensure ordering }); }); await Promise.all(promises); // Wait for all processing to complete await new Promise(resolve => setTimeout(resolve, 200)); console.log(` Processing order: ${processedOrder.join(' -> ')}`); console.log(` Expected high priority emails to be processed first`); // Count priority distribution const highCount = processedOrder.filter(p => p === 'HIGH').length; const normalCount = processedOrder.filter(p => p === 'NORMAL').length; const lowCount = processedOrder.filter(p => p === 'LOW').length; console.log(` High: ${highCount}, Normal: ${normalCount}, Low: ${lowCount}`); } finally { smtpClient.close(); testServer.close(); } }); // Scenario 3: Queue Size Management await test.test('Scenario 3: Queue Size Management', async () => { console.log('\nšŸ“ˆ Testing queue size limits and overflow handling...'); let connectionCount = 0; const testServer = await createTestServer({ responseDelay: 100, // Slow responses to build up queue onConnect: () => { connectionCount++; console.log(` [Server] Connection ${connectionCount} established`); } }); const smtpClient = createSmtpClient({ host: testServer.hostname, port: testServer.port, secure: false, pool: true, maxConnections: 2, maxMessages: 5, // Low limit to test overflow queueSize: 10 }); try { console.log(' Creating 15 emails to test queue overflow...'); const emails = []; for (let i = 0; i < 15; i++) { emails.push(new Email({ from: 'sender@example.com', to: [`recipient${i}@example.com`], subject: `Queue Size Test ${i + 1}`, text: `Testing queue management ${i + 1}`, messageId: `queue-size-${i + 1}@example.com` })); } console.log(' Sending emails rapidly to fill queue...'); const startTime = Date.now(); const results = []; // Send emails in rapid succession for (let i = 0; i < emails.length; i++) { try { const promise = smtpClient.sendMail(emails[i]); results.push(promise); console.log(` šŸ“¤ Email ${i + 1} queued`); // Small delay between sends if (i < emails.length - 1) { await new Promise(resolve => setTimeout(resolve, 10)); } } catch (error) { console.log(` āŒ Email ${i + 1} rejected: ${error.message}`); } } console.log(' Waiting for queue processing to complete...'); const finalResults = await Promise.allSettled(results); const endTime = Date.now(); const successful = finalResults.filter(r => r.status === 'fulfilled').length; const failed = finalResults.filter(r => r.status === 'rejected').length; console.log(` Queue processing completed in ${endTime - startTime}ms`); console.log(` Successful: ${successful}, Failed: ${failed}`); console.log(` Max connections used: ${connectionCount}`); console.log(` Queue overflow handling: ${failed > 0 ? 'Detected' : 'None'}`); } finally { smtpClient.close(); testServer.close(); } }); // Scenario 4: Queue Recovery After Failures await test.test('Scenario 4: Queue Recovery After Failures', async () => { console.log('\nšŸ”„ Testing queue recovery after connection failures...'); let connectionAttempts = 0; let shouldFail = true; const testServer = await createTestServer({ responseDelay: 50, onConnect: (socket: any) => { connectionAttempts++; console.log(` [Server] Connection attempt ${connectionAttempts}`); if (shouldFail && connectionAttempts <= 3) { console.log(` [Server] Simulating connection failure ${connectionAttempts}`); socket.destroy(); return; } // After 3 failures, allow connections shouldFail = false; console.log(` [Server] Connection successful on attempt ${connectionAttempts}`); } }); const smtpClient = createSmtpClient({ host: testServer.hostname, port: testServer.port, secure: false, pool: true, maxConnections: 2, maxMessages: 100, // Retry configuration retryDelay: 100, retries: 5 }); try { console.log(' Creating emails that will initially fail...'); const emails = []; for (let i = 0; i < 5; i++) { emails.push(new Email({ from: 'sender@example.com', to: [`recipient${i}@example.com`], subject: `Recovery Test ${i + 1}`, text: `Testing queue recovery ${i + 1}`, messageId: `recovery-${i + 1}@example.com` })); } console.log(' Sending emails (expecting initial failures)...'); const startTime = Date.now(); const promises = emails.map((email, index) => { return smtpClient.sendMail(email).then(result => { console.log(` āœ“ Email ${index + 1} sent successfully after recovery`); return { success: true, result }; }).catch(error => { console.log(` āœ— Email ${index + 1} permanently failed: ${error.message}`); return { success: false, error }; }); }); const results = await Promise.all(promises); const endTime = Date.now(); const successful = results.filter(r => r.success).length; const failed = results.filter(r => !r.success).length; console.log(` Recovery test completed in ${endTime - startTime}ms`); console.log(` Connection attempts: ${connectionAttempts}`); console.log(` Successful after recovery: ${successful}`); console.log(` Permanently failed: ${failed}`); console.log(` Recovery rate: ${((successful / emails.length) * 100).toFixed(1)}%`); } finally { smtpClient.close(); testServer.close(); } }); // Scenario 5: Concurrent Queue Operations await test.test('Scenario 5: Concurrent Queue Operations', async () => { console.log('\n⚔ Testing concurrent queue operations and thread safety...'); let messageCount = 0; const testServer = await createTestServer({ responseDelay: 20, onData: (data: string) => { if (data.includes('DATA')) { messageCount++; console.log(` [Server] Processing message ${messageCount}`); } } }); const smtpClient = createSmtpClient({ host: testServer.hostname, port: testServer.port, secure: false, pool: true, maxConnections: 4, maxMessages: 25 }); try { console.log(' Starting multiple concurrent queue operations...'); // Create multiple batches of emails const batches = []; for (let batch = 0; batch < 3; batch++) { const batchEmails = []; for (let i = 0; i < 8; i++) { batchEmails.push(new Email({ from: `sender${batch}@example.com`, to: [`recipient${batch}-${i}@example.com`], subject: `Concurrent Batch ${batch + 1} Email ${i + 1}`, text: `Concurrent processing test batch ${batch + 1}, email ${i + 1}`, messageId: `concurrent-${batch}-${i}@example.com` })); } batches.push(batchEmails); } console.log(' Launching concurrent batch operations...'); const startTime = Date.now(); const batchPromises = batches.map((batchEmails, batchIndex) => { return Promise.all(batchEmails.map((email, emailIndex) => { return smtpClient.sendMail(email).then(result => { console.log(` āœ“ Batch ${batchIndex + 1}, Email ${emailIndex + 1} sent`); return { batch: batchIndex, email: emailIndex, success: true }; }).catch(error => { console.log(` āœ— Batch ${batchIndex + 1}, Email ${emailIndex + 1} failed`); return { batch: batchIndex, email: emailIndex, success: false, error }; }); })); }); const batchResults = await Promise.all(batchPromises); const endTime = Date.now(); // Flatten results const allResults = batchResults.flat(); const totalEmails = allResults.length; const successful = allResults.filter(r => r.success).length; const failed = totalEmails - successful; console.log(` Concurrent operations completed in ${endTime - startTime}ms`); console.log(` Total emails processed: ${totalEmails}`); console.log(` Successful: ${successful}, Failed: ${failed}`); console.log(` Success rate: ${((successful / totalEmails) * 100).toFixed(1)}%`); console.log(` Server processed: ${messageCount} messages`); console.log(` Concurrency efficiency: ${messageCount === successful ? 'Perfect' : 'Partial'}`); } finally { smtpClient.close(); testServer.close(); } }); console.log('\nāœ… CPERF-07: Queue Management Performance Tests completed'); console.log('šŸ“Š All queue management scenarios tested successfully'); });