import { tap, expect } from '@git.zone/tstest/tapbundle'; import { DcRouter } from '../ts/classes.dcrouter.js'; import * as plugins from '../ts/plugins.js'; /** * Integration tests for socket-handler functionality * * Note: These tests verify the actual startup and route configuration of DcRouter * with socket-handler mode. Each test starts a full DcRouter instance. * * The unit tests (test.socket-handler-unit.ts) cover route generation logic * without starting actual servers. */ let dcRouter: DcRouter; tap.test('should start email server with socket-handlers and verify routes', async () => { dcRouter = new DcRouter({ emailConfig: { ports: [10025, 10587, 10465], hostname: 'mail.integration.test', domains: ['integration.test'], routes: [], useSocketHandler: true }, smartProxyConfig: { routes: [] } }); await dcRouter.start(); // Verify email service is running const emailServer = (dcRouter as any).emailServer; expect(emailServer).toBeDefined(); // Verify SmartProxy has routes for email const smartProxy = (dcRouter as any).smartProxy; // Try different ways to access routes // SmartProxy might store routes in different locations after initialization const optionsRoutes = smartProxy?.options?.routes || []; const routeManager = (smartProxy as any)?.routeManager; const routeManagerRoutes = routeManager?.routes || routeManager?.getAllRoutes?.() || []; // Use whichever has routes const routes = optionsRoutes.length > 0 ? optionsRoutes : routeManagerRoutes; // Count email routes - they should be named email-port-{port}-route for non-standard ports const emailRoutes = routes.filter((route: any) => route.name?.includes('email-port-') && route.name?.includes('-route') ); // Verify we have 3 routes (one for each port) expect(emailRoutes.length).toEqual(3); // All routes should be socket-handler type emailRoutes.forEach((route: any) => { expect(route.action.type).toEqual('socket-handler'); expect(route.action.socketHandler).toBeDefined(); expect(typeof route.action.socketHandler).toEqual('function'); }); // Verify each port has a route const routePorts = emailRoutes.map((r: any) => r.match.ports[0]).sort((a: number, b: number) => a - b); expect(routePorts).toEqual([10025, 10465, 10587]); // Verify email server has NO internal listeners (socket-handler mode) expect(emailServer.servers.length).toEqual(0); await dcRouter.stop(); }); tap.test('should create mail socket handler for different ports', async () => { // The dcRouter from the previous test should still be available // but we need a fresh one to test handler creation dcRouter = new DcRouter({ emailConfig: { ports: [11025, 11465], hostname: 'mail.handler.test', domains: ['handler.test'], routes: [], useSocketHandler: true } }); // Don't start the server - just test handler creation const handler25 = (dcRouter as any).createMailSocketHandler(11025); const handler465 = (dcRouter as any).createMailSocketHandler(11465); expect(handler25).toBeDefined(); expect(handler465).toBeDefined(); expect(typeof handler25).toEqual('function'); expect(typeof handler465).toEqual('function'); // Handlers should be different functions expect(handler25).not.toEqual(handler465); }); tap.test('should handle socket handler errors gracefully', async () => { dcRouter = new DcRouter({ emailConfig: { ports: [12025], hostname: 'mail.error.test', domains: ['error.test'], routes: [], useSocketHandler: true } }); // Test email socket handler error handling without starting the server const emailHandler = (dcRouter as any).createMailSocketHandler(12025); const errorSocket = new plugins.net.Socket(); let errorThrown = false; try { // This should handle the error gracefully // The socket is not connected so it should fail gracefully await emailHandler(errorSocket); } catch (error) { errorThrown = true; } // Should not throw, should handle gracefully expect(errorThrown).toBeFalsy(); }); tap.test('stop', async () => { // Ensure any remaining dcRouter is stopped if (dcRouter) { try { await dcRouter.stop(); } catch (e) { // Ignore errors during cleanup } } await tap.stopForcefully(); }); export default tap.start();