import { tap, expect } from '@git.zone/tstest/tapbundle'; import { UnifiedEmailServer } from '../ts/mail/routing/classes.unified.email.server.js'; import { RustSecurityBridge } from '../ts/security/classes.rustsecuritybridge.js'; import { connectToSmtp, waitForGreeting, sendSmtpCommand, performSmtpHandshake, createConcurrentConnections, createMimeMessage, } from './helpers/utils.js'; const storageMap = new Map(); const mockDcRouter = { storageManager: { get: async (key: string) => storageMap.get(key) || null, set: async (key: string, value: string) => { storageMap.set(key, value); }, }, }; let server: UnifiedEmailServer; let bridge: RustSecurityBridge; let bridgeAvailable = false; tap.test('setup - start server on port 10125', async () => { RustSecurityBridge.resetInstance(); bridge = RustSecurityBridge.getInstance(); server = new UnifiedEmailServer(mockDcRouter, { ports: [10125], hostname: 'test.inbound.local', domains: [ { domain: 'testdomain.com', dnsMode: 'forward', }, ], routes: [ { name: 'catch-all', priority: 0, match: { recipients: '*@testdomain.com', }, action: { type: 'process', }, }, ], }); try { await server.start(); bridgeAvailable = true; } catch (err) { console.log(`SKIP: Server failed to start — ${(err as Error).message}`); console.log('Build the Rust binary with: cd rust && cargo build --release'); } }); tap.test('EHLO and capability discovery', async () => { if (!bridgeAvailable) { console.log('SKIP: bridge not running'); return; } const socket = await connectToSmtp('127.0.0.1', 10125, 10000); const capabilities = await performSmtpHandshake(socket, 'test-client.local'); // Verify we received capabilities from the EHLO response expect(capabilities.length).toBeGreaterThan(0); // The server hostname should be in the first capability line const firstLine = capabilities[0]; expect(firstLine).toBeTruthy(); socket.destroy(); }); tap.test('send valid email - full SMTP transaction', async () => { if (!bridgeAvailable) { console.log('SKIP: bridge not running'); return; } const socket = await connectToSmtp('127.0.0.1', 10125, 10000); await waitForGreeting(socket, 10000); // EHLO await sendSmtpCommand(socket, 'EHLO test-client.local', '250', 10000); // MAIL FROM await sendSmtpCommand(socket, 'MAIL FROM:', '250', 10000); // RCPT TO await sendSmtpCommand(socket, 'RCPT TO:', '250', 10000); // DATA await sendSmtpCommand(socket, 'DATA', '354', 10000); // Send MIME message const mimeMessage = createMimeMessage({ from: 'sender@example.com', to: 'user@testdomain.com', subject: 'E2E Test Email', text: 'This is an end-to-end test email.', }); // Send the message data followed by the terminator await new Promise((resolve, reject) => { let buffer = ''; const timer = setTimeout(() => { socket.removeAllListeners('data'); reject(new Error('DATA response timeout')); }, 10000); const onData = (data: Buffer) => { buffer += data.toString(); if (buffer.includes('250')) { clearTimeout(timer); socket.removeListener('data', onData); resolve(); } }; socket.on('data', onData); socket.write(mimeMessage + '\r\n.\r\n'); }); // QUIT try { await sendSmtpCommand(socket, 'QUIT', '221', 5000); } catch { // Ignore QUIT errors } socket.destroy(); // Verify the email was queued for processing const stats = server.deliveryQueue.getStats(); expect(stats.queueSize).toBeGreaterThan(0); }); tap.test('multiple recipients', async () => { if (!bridgeAvailable) { console.log('SKIP: bridge not running'); return; } const socket = await connectToSmtp('127.0.0.1', 10125, 10000); await waitForGreeting(socket, 10000); await sendSmtpCommand(socket, 'EHLO test-client.local', '250', 10000); await sendSmtpCommand(socket, 'MAIL FROM:', '250', 10000); await sendSmtpCommand(socket, 'RCPT TO:', '250', 10000); await sendSmtpCommand(socket, 'RCPT TO:', '250', 10000); await sendSmtpCommand(socket, 'DATA', '354', 10000); const mimeMessage = createMimeMessage({ from: 'sender@example.com', to: 'user1@testdomain.com', subject: 'Multi-recipient Test', text: 'Testing multiple recipients.', }); await new Promise((resolve, reject) => { let buffer = ''; const timer = setTimeout(() => { socket.removeAllListeners('data'); reject(new Error('DATA response timeout')); }, 10000); const onData = (data: Buffer) => { buffer += data.toString(); if (buffer.includes('250')) { clearTimeout(timer); socket.removeListener('data', onData); resolve(); } }; socket.on('data', onData); socket.write(mimeMessage + '\r\n.\r\n'); }); socket.destroy(); }); tap.test('concurrent connections', async () => { if (!bridgeAvailable) { console.log('SKIP: bridge not running'); return; } const sockets = await createConcurrentConnections('127.0.0.1', 10125, 3, 10000); expect(sockets.length).toEqual(3); // Perform EHLO on each connection for (const socket of sockets) { await waitForGreeting(socket, 10000); await sendSmtpCommand(socket, 'EHLO concurrent-client.local', '250', 10000); } // Close all connections for (const socket of sockets) { socket.destroy(); } }); tap.test('RSET mid-session', async () => { if (!bridgeAvailable) { console.log('SKIP: bridge not running'); return; } const socket = await connectToSmtp('127.0.0.1', 10125, 10000); await waitForGreeting(socket, 10000); await sendSmtpCommand(socket, 'EHLO test-client.local', '250', 10000); // Start a transaction await sendSmtpCommand(socket, 'MAIL FROM:', '250', 10000); // Reset the transaction await sendSmtpCommand(socket, 'RSET', '250', 10000); // Start a new transaction after RSET await sendSmtpCommand(socket, 'MAIL FROM:', '250', 10000); socket.destroy(); }); tap.test('cleanup - stop server', async () => { if (bridgeAvailable) { await server.stop(); } await tap.stopForcefully(); }); export default tap.start();