import { tap, expect } from '@git.zone/tstest/tapbundle'; import { startTestServer, stopTestServer, type ITestServer } from '../../helpers/server.loader.js'; import { createSmtpClient } from '../../../ts/mail/delivery/smtpclient/index.js'; import { Email } from '../../../ts/mail/core/classes.email.js'; let testServer: ITestServer; tap.test('setup test SMTP server', async () => { testServer = await startTestServer({ port: 2537, tlsEnabled: false, authRequired: false, socketTimeout: 30000 // 30 second timeout for keep-alive tests }); expect(testServer).toBeTruthy(); expect(testServer.port).toEqual(2537); }); tap.test('CCM-11: Basic keep-alive functionality', async () => { const smtpClient = createSmtpClient({ host: testServer.hostname, port: testServer.port, secure: false, keepAlive: true, keepAliveInterval: 5000, // 5 seconds connectionTimeout: 10000, debug: true }); // Verify connection works const verified = await smtpClient.verify(); expect(verified).toBeTrue(); // Send an email to establish connection const email = new Email({ from: 'sender@example.com', to: 'recipient@example.com', subject: 'Keep-alive test', text: 'Testing connection keep-alive' }); const result = await smtpClient.sendMail(email); expect(result.success).toBeTrue(); // Wait to simulate idle time await new Promise(resolve => setTimeout(resolve, 3000)); // Send another email to verify connection is still working const result2 = await smtpClient.sendMail(email); expect(result2.success).toBeTrue(); console.log('✅ Keep-alive functionality verified'); await smtpClient.close(); }); tap.test('CCM-11: Connection reuse with keep-alive', async () => { const smtpClient = createSmtpClient({ host: testServer.hostname, port: testServer.port, secure: false, keepAlive: true, keepAliveInterval: 3000, connectionTimeout: 10000, poolSize: 1, // Use single connection to test keep-alive debug: true }); // Send multiple emails with delays to test keep-alive const emails = []; for (let i = 0; i < 3; i++) { const email = new Email({ from: 'sender@example.com', to: 'recipient@example.com', subject: `Keep-alive test ${i + 1}`, text: `Testing connection keep-alive - email ${i + 1}` }); const result = await smtpClient.sendMail(email); expect(result.success).toBeTrue(); emails.push(result); // Wait between emails (less than keep-alive interval) if (i < 2) { await new Promise(resolve => setTimeout(resolve, 2000)); } } // All emails should have been sent successfully expect(emails.length).toEqual(3); expect(emails.every(r => r.success)).toBeTrue(); console.log('✅ Connection reused successfully with keep-alive'); await smtpClient.close(); }); tap.test('CCM-11: Connection without keep-alive', async () => { // Create a client without keep-alive const smtpClient = createSmtpClient({ host: testServer.hostname, port: testServer.port, secure: false, keepAlive: false, // Disabled connectionTimeout: 5000, socketTimeout: 5000, // 5 second socket timeout poolSize: 1, debug: true }); // Send first email const email1 = new Email({ from: 'sender@example.com', to: 'recipient@example.com', subject: 'No keep-alive test 1', text: 'Testing without keep-alive' }); const result1 = await smtpClient.sendMail(email1); expect(result1.success).toBeTrue(); // Wait longer than socket timeout await new Promise(resolve => setTimeout(resolve, 7000)); // Send second email - connection might need to be re-established const email2 = new Email({ from: 'sender@example.com', to: 'recipient@example.com', subject: 'No keep-alive test 2', text: 'Testing without keep-alive after timeout' }); const result2 = await smtpClient.sendMail(email2); expect(result2.success).toBeTrue(); console.log('✅ Client handles reconnection without keep-alive'); await smtpClient.close(); }); tap.test('CCM-11: Keep-alive with long operations', async () => { const smtpClient = createSmtpClient({ host: testServer.hostname, port: testServer.port, secure: false, keepAlive: true, keepAliveInterval: 2000, connectionTimeout: 10000, poolSize: 2, // Use small pool debug: true }); // Send multiple emails with varying delays const operations = []; for (let i = 0; i < 5; i++) { operations.push((async () => { // Simulate random processing delay await new Promise(resolve => setTimeout(resolve, Math.random() * 3000)); const email = new Email({ from: 'sender@example.com', to: 'recipient@example.com', subject: `Long operation test ${i + 1}`, text: `Testing keep-alive during long operations - email ${i + 1}` }); const result = await smtpClient.sendMail(email); return { index: i, result }; })()); } const results = await Promise.all(operations); // All operations should succeed const successCount = results.filter(r => r.result.success).length; expect(successCount).toEqual(5); console.log('✅ Keep-alive maintained during long operations'); await smtpClient.close(); }); tap.test('CCM-11: Keep-alive interval effect on connection pool', async () => { const intervals = [1000, 3000, 5000]; // Different intervals to test for (const interval of intervals) { console.log(`\nTesting keep-alive with ${interval}ms interval`); const smtpClient = createSmtpClient({ host: testServer.hostname, port: testServer.port, secure: false, keepAlive: true, keepAliveInterval: interval, connectionTimeout: 10000, poolSize: 2, debug: false // Less verbose for this test }); const startTime = Date.now(); // Send multiple emails over time period longer than interval const emails = []; for (let i = 0; i < 3; i++) { const email = new Email({ from: 'sender@example.com', to: 'recipient@example.com', subject: `Interval test ${i + 1}`, text: `Testing with ${interval}ms keep-alive interval` }); const result = await smtpClient.sendMail(email); expect(result.success).toBeTrue(); emails.push(result); // Wait approximately one interval if (i < 2) { await new Promise(resolve => setTimeout(resolve, interval)); } } const totalTime = Date.now() - startTime; console.log(`Sent ${emails.length} emails in ${totalTime}ms with ${interval}ms keep-alive`); // Check pool status const poolStatus = smtpClient.getPoolStatus(); console.log(`Pool status: ${JSON.stringify(poolStatus)}`); await smtpClient.close(); } }); tap.test('CCM-11: Event monitoring during keep-alive', async () => { const smtpClient = createSmtpClient({ host: testServer.hostname, port: testServer.port, secure: false, keepAlive: true, keepAliveInterval: 2000, connectionTimeout: 10000, poolSize: 1, debug: true }); let connectionEvents = 0; let disconnectEvents = 0; let errorEvents = 0; // Monitor events smtpClient.on('connection', () => { connectionEvents++; console.log('📡 Connection event'); }); smtpClient.on('disconnect', () => { disconnectEvents++; console.log('🔌 Disconnect event'); }); smtpClient.on('error', (error) => { errorEvents++; console.log('❌ Error event:', error.message); }); // Send emails with delays for (let i = 0; i < 3; i++) { const email = new Email({ from: 'sender@example.com', to: 'recipient@example.com', subject: `Event test ${i + 1}`, text: 'Testing events during keep-alive' }); const result = await smtpClient.sendMail(email); expect(result.success).toBeTrue(); if (i < 2) { await new Promise(resolve => setTimeout(resolve, 1500)); } } // Should have at least one connection event expect(connectionEvents).toBeGreaterThan(0); console.log(`✅ Captured ${connectionEvents} connection events`); await smtpClient.close(); // Wait a bit for close event await new Promise(resolve => setTimeout(resolve, 100)); }); tap.test('cleanup test SMTP server', async () => { if (testServer) { await stopTestServer(testServer); } }); tap.start();