/** * Test server loader for SMTP test suite * Provides simplified server lifecycle management for tests */ import { DcRouter } from '../../ts/classes.dcrouter.js'; import { UnifiedEmailServer } from '../../ts/mail/routing/classes.unified.email.server.js'; import { createSmtpServer } from '../../ts/mail/delivery/smtpserver/index.js'; import * as fs from 'fs'; import * as path from 'path'; import * as net from 'net'; let activeServer = null; let activePort = null; /** * Start test server on default port 2525 */ async function startTestServer(port = 2525) { if (activeServer) { console.log('Test server already running, stopping it first...'); await stopTestServer(); } console.log(`Starting test SMTP server on port ${port}...`); try { // Create a minimal email server for testing const mockEmailServer = { processEmailByMode: async (emailData: any) => { console.log('📧 Processed test email:', emailData.subject || 'No subject'); return emailData; } } as any; // Type assertion for test purposes // Load test certificates if available let key = ''; let cert = ''; try { const __dirname = path.dirname(new URL(import.meta.url).pathname); key = fs.readFileSync(path.join(__dirname, '../../../test/smtp-prod/certs/test.key'), 'utf8'); cert = fs.readFileSync(path.join(__dirname, '../../../test/smtp-prod/certs/test.cert'), 'utf8'); } catch (e) { console.log('Test certificates not found, running without TLS'); } // SMTP server options const smtpOptions = { port: port, hostname: 'localhost', key: key, cert: cert, maxConnections: 100, size: 10 * 1024 * 1024, // 10MB maxRecipients: 100, socketTimeout: 30000, connectionTimeout: 60000, cleanupInterval: 300000, auth: { required: false, methods: [] as ('PLAIN' | 'LOGIN' | 'OAUTH2')[] } }; // Create and start SMTP server const smtpServer = createSmtpServer(mockEmailServer, smtpOptions); await smtpServer.listen(); activeServer = smtpServer; activePort = port; // Wait for server to be ready await waitForServerReady('localhost', port, 10000); console.log(`✅ Test SMTP server started on port ${port}`); return smtpServer; } catch (error) { console.error('Failed to start test server:', error); throw error; } } /** * Stop test server */ async function stopTestServer() { if (!activeServer) { console.log('No active test server to stop'); return; } console.log(`Stopping test SMTP server on port ${activePort}...`); try { if (activeServer.close && typeof activeServer.close === 'function') { await activeServer.close(); } else if (activeServer.destroy && typeof activeServer.destroy === 'function') { await activeServer.destroy(); } else if (activeServer.stop && typeof activeServer.stop === 'function') { await activeServer.stop(); } // Force close any remaining connections if (activeServer._connections) { for (const conn of activeServer._connections) { if (conn && !conn.destroyed) { conn.destroy(); } } } activeServer = null; const port = activePort; activePort = null; // Wait for port to be free await waitForPortFree(port, 3000); console.log(`✅ Test SMTP server stopped`); } catch (error) { console.error('Error stopping test server:', error); activeServer = null; activePort = null; } } /** * Wait for server to be ready to accept connections */ async function waitForServerReady(hostname, port, timeout) { const startTime = Date.now(); const maxRetries = 20; let retries = 0; while (retries < maxRetries) { try { await new Promise((resolve, reject) => { const socket = net.createConnection({ port, host: hostname }); socket.on('connect', () => { socket.end(); resolve(undefined); }); socket.on('error', (error) => { socket.destroy(); reject(error); }); setTimeout(() => { socket.destroy(); reject(new Error('Connection timeout')); }, 1000); }); return; // Server is ready } catch (error) { retries++; if (Date.now() - startTime > timeout) { throw new Error(`Server did not become ready within ${timeout}ms`); } // Wait before retrying await new Promise(resolve => setTimeout(resolve, 500)); } } throw new Error(`Server did not become ready after ${maxRetries} retries`); } /** * Wait for port to be free */ async function waitForPortFree(port, timeout) { const startTime = Date.now(); while (Date.now() - startTime < timeout) { const isFree = await isPortFree(port); if (isFree) { return true; } await new Promise(resolve => setTimeout(resolve, 100)); } return false; } /** * Check if port is free */ async function isPortFree(port) { return new Promise((resolve) => { const server = net.createServer(); server.listen(port, () => { server.close(() => { resolve(true); }); }); server.on('error', () => { resolve(false); }); }); } // Export functions export { startTestServer, stopTestServer };