import { tap, expect } from '@git.zone/tstest/tapbundle'; import { UnifiedEmailServer } from '../ts/mail/routing/classes.unified.email.server.js'; import { RustSecurityBridge, BridgeState } from '../ts/security/classes.rustsecuritybridge.js'; import { connectToSmtp, waitForGreeting } from './helpers/utils.js'; import * as net from 'net'; // Common mock pattern for dcRouter dependency 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; tap.test('setup - reset bridge singleton', async () => { RustSecurityBridge.resetInstance(); bridge = RustSecurityBridge.getInstance(); }); tap.test('construct server - should create UnifiedEmailServer', async () => { server = new UnifiedEmailServer(mockDcRouter, { ports: [10025, 10587], hostname: 'test.e2e.local', domains: [ { domain: 'e2e-test.com', dnsMode: 'forward', }, ], routes: [ { name: 'catch-all', priority: 0, match: { recipients: '*@e2e-test.com', }, action: { type: 'process', }, }, ], }); expect(server).toBeTruthy(); expect(server).toBeInstanceOf(UnifiedEmailServer); }); tap.test('start server - should start and accept SMTP connections', async () => { try { await server.start(); } 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'); return; } expect(bridge.running).toBeTrue(); // Connect to port 10025 and verify we get a 220 greeting const socket = await connectToSmtp('127.0.0.1', 10025, 10000); const greeting = await waitForGreeting(socket, 10000); expect(greeting).toInclude('220'); socket.destroy(); }); tap.test('get stats - should return server statistics', async () => { if (!bridge.running) { console.log('SKIP: bridge not running'); return; } const stats = server.getStats(); expect(stats).toBeTruthy(); expect(stats.startTime).toBeInstanceOf(Date); expect(stats.connections).toBeTruthy(); expect(typeof stats.connections.current).toEqual('number'); expect(typeof stats.connections.total).toEqual('number'); expect(stats.messages).toBeTruthy(); expect(typeof stats.messages.processed).toEqual('number'); }); tap.test('stop server - should stop and refuse connections', async () => { if (!bridge.running) { console.log('SKIP: bridge not running'); return; } await server.stop(); // Verify connection is refused after stop try { const socket = await connectToSmtp('127.0.0.1', 10025, 3000); socket.destroy(); // If we get here, the connection was accepted — that's unexpected throw new Error('Expected connection to be refused after server stop'); } catch (err) { // Connection refused or timeout is expected const msg = (err as Error).message; expect( msg.includes('ECONNREFUSED') || msg.includes('timeout') || msg.includes('refused') ).toBeTrue(); } expect(bridge.state).toEqual(BridgeState.Stopped); }); tap.test('stop', async () => { // Clean up if not already stopped if (bridge.running) { await server.stop(); } await tap.stopForcefully(); }); export default tap.start();