Files
dcrouter/test/test.socket-handler-integration.ts

141 lines
4.3 KiB
TypeScript

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();