import { tap, expect } from '@git.zone/tstest/tapbundle'; import { DcRouter } from '../ts/classes.dcrouter.js'; import * as plugins from '../ts/plugins.js'; let dcRouter: DcRouter; tap.test('should use traditional port forwarding when useSocketHandler is false', async () => { dcRouter = new DcRouter({ emailConfig: { ports: [2525, 2587, 2465], hostname: 'mail.test.local', domains: ['test.local'], routes: [], useSocketHandler: false // Traditional mode }, smartProxyConfig: { routes: [] } }); await dcRouter.start(); // Check that email server is created and listening on ports const emailServer = (dcRouter as any).emailServer; expect(emailServer).toBeDefined(); // Check SmartProxy routes are forward type const smartProxy = (dcRouter as any).smartProxy; const routes = smartProxy?.options?.routes || []; const emailRoutes = routes.filter((route: any) => route.name?.includes('-route') ); emailRoutes.forEach((route: any) => { expect(route.action.type).toEqual('forward'); expect(route.action.target).toBeDefined(); expect(route.action.target.host).toEqual('localhost'); }); await dcRouter.stop(); }); tap.test('should use socket-handler mode when useSocketHandler is true', async () => { dcRouter = new DcRouter({ emailConfig: { ports: [2525, 2587, 2465], hostname: 'mail.test.local', domains: ['test.local'], routes: [], useSocketHandler: true // Socket-handler mode }, smartProxyConfig: { routes: [] } }); await dcRouter.start(); // Check that email server is created const emailServer = (dcRouter as any).emailServer; expect(emailServer).toBeDefined(); // Check SmartProxy routes are socket-handler type const smartProxy = (dcRouter as any).smartProxy; const routes = smartProxy?.options?.routes || []; const emailRoutes = routes.filter((route: any) => route.name?.includes('-route') ); emailRoutes.forEach((route: any) => { expect(route.action.type).toEqual('socket-handler'); expect(route.action.socketHandler).toBeDefined(); expect(typeof route.action.socketHandler).toEqual('function'); }); await dcRouter.stop(); }); tap.test('should generate correct email routes for each port', async () => { const emailConfig = { ports: [2525, 2587, 2465], hostname: 'mail.test.local', domains: ['test.local'], routes: [], useSocketHandler: true }; dcRouter = new DcRouter({ emailConfig }); // Access the private method to generate routes const emailRoutes = (dcRouter as any).generateEmailRoutes(emailConfig); expect(emailRoutes.length).toEqual(3); // Check route for port 2525 (non-standard ports use generic naming) const port2525Route = emailRoutes.find((r: any) => r.name === 'email-port-2525-route'); expect(port2525Route).toBeDefined(); expect(port2525Route.match.ports).toContain(2525); expect(port2525Route.action.type).toEqual('socket-handler'); // Check route for port 2587 const port2587Route = emailRoutes.find((r: any) => r.name === 'email-port-2587-route'); expect(port2587Route).toBeDefined(); expect(port2587Route.match.ports).toContain(2587); expect(port2587Route.action.type).toEqual('socket-handler'); // Check route for port 2465 const port2465Route = emailRoutes.find((r: any) => r.name === 'email-port-2465-route'); expect(port2465Route).toBeDefined(); expect(port2465Route.match.ports).toContain(2465); expect(port2465Route.action.type).toEqual('socket-handler'); }); tap.test('email socket handler should handle different ports correctly', async () => { dcRouter = new DcRouter({ emailConfig: { ports: [2525, 2587, 2465], hostname: 'mail.test.local', domains: ['test.local'], routes: [], useSocketHandler: true } }); await dcRouter.start(); // Test port 2525 handler (plain SMTP) const port2525Handler = (dcRouter as any).createMailSocketHandler(2525); expect(port2525Handler).toBeDefined(); expect(typeof port2525Handler).toEqual('function'); // Test port 2465 handler (SMTPS - should wrap in TLS) const port2465Handler = (dcRouter as any).createMailSocketHandler(2465); expect(port2465Handler).toBeDefined(); expect(typeof port2465Handler).toEqual('function'); await dcRouter.stop(); }); tap.test('email server handleSocket method should work', async () => { dcRouter = new DcRouter({ emailConfig: { ports: [2525], hostname: 'mail.test.local', domains: ['test.local'], routes: [], useSocketHandler: true } }); await dcRouter.start(); const emailServer = (dcRouter as any).emailServer; expect(emailServer).toBeDefined(); expect(emailServer.handleSocket).toBeDefined(); expect(typeof emailServer.handleSocket).toEqual('function'); // Create a mock socket const mockSocket = new plugins.net.Socket(); let socketDestroyed = false; mockSocket.destroy = () => { socketDestroyed = true; }; // Test handleSocket try { await emailServer.handleSocket(mockSocket, 2525); // It will fail because we don't have a real socket, but it should handle it gracefully } catch (error) { // Expected to error with mock socket } await dcRouter.stop(); }); tap.test('should not create SMTP servers when useSocketHandler is true', async () => { dcRouter = new DcRouter({ emailConfig: { ports: [2525, 2587, 2465], hostname: 'mail.test.local', domains: ['test.local'], routes: [], useSocketHandler: true } }); await dcRouter.start(); // The email server should not have any SMTP server instances const emailServer = (dcRouter as any).emailServer; expect(emailServer).toBeDefined(); // The servers array should be empty (no port binding) expect(emailServer.servers).toBeDefined(); expect(emailServer.servers.length).toEqual(0); await dcRouter.stop(); }); tap.test('TLS handling should differ between ports', async () => { // Use standard ports 25 and 465 to test TLS behavior // This test doesn't start the server, just checks route generation const emailConfig = { ports: [25, 465], hostname: 'mail.test.local', domains: ['test.local'], routes: [], useSocketHandler: false // Use traditional mode to check TLS config }; dcRouter = new DcRouter({ emailConfig }); const emailRoutes = (dcRouter as any).generateEmailRoutes(emailConfig); // Port 25 should use passthrough const smtpRoute = emailRoutes.find((r: any) => r.match.ports[0] === 25); expect(smtpRoute.action.tls.mode).toEqual('passthrough'); // Port 465 should use terminate const smtpsRoute = emailRoutes.find((r: any) => r.match.ports[0] === 465); expect(smtpsRoute.action.tls.mode).toEqual('terminate'); expect(smtpsRoute.action.tls.certificate).toEqual('auto'); }); tap.test('stop', async () => { await tap.stopForcefully(); }); export default tap.start();