dcrouter/test/test.socket-handler-integration.ts
Philipp Kunz 64da8d9100 test(socket-handler): add comprehensive tests for DNS and email socket-handler functionality
- Add unit tests for DNS route generation and socket handler creation
- Add unit tests for email route generation in both modes
- Add integration tests for combined DNS and email configuration
- Test TLS handling differences between email ports
- Verify socket-handler vs traditional forwarding mode behavior
- All tests pass without requiring actual port binding
- Mark implementation plan as complete with full test coverage
2025-05-29 16:44:34 +00:00

240 lines
6.4 KiB
TypeScript

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 run both DNS and email with socket-handlers simultaneously', async () => {
dcRouter = new DcRouter({
dnsDomain: 'dns.integration.test',
emailConfig: {
ports: [25, 587, 465],
hostname: 'mail.integration.test',
domains: ['integration.test'],
routes: [],
useSocketHandler: true
},
smartProxyConfig: {
routes: []
}
});
await dcRouter.start();
// Verify both services are running
const dnsServer = (dcRouter as any).dnsServer;
const emailServer = (dcRouter as any).emailServer;
expect(dnsServer).toBeDefined();
expect(emailServer).toBeDefined();
// Verify SmartProxy has routes for both services
const smartProxy = (dcRouter as any).smartProxy;
const routes = smartProxy?.options?.routes || [];
// Count DNS routes
const dnsRoutes = routes.filter((route: any) =>
route.name?.includes('dns-over-https')
);
expect(dnsRoutes.length).toEqual(2);
// Count email routes
const emailRoutes = routes.filter((route: any) =>
route.name?.includes('-route') && !route.name?.includes('dns')
);
expect(emailRoutes.length).toEqual(3);
// All routes should be socket-handler type
[...dnsRoutes, ...emailRoutes].forEach((route: any) => {
expect(route.action.type).toEqual('socket-handler');
expect(route.action.socketHandler).toBeDefined();
});
await dcRouter.stop();
});
tap.test('should handle mixed configuration (DNS socket-handler, email traditional)', async () => {
dcRouter = new DcRouter({
dnsDomain: 'dns.mixed.test',
emailConfig: {
ports: [25, 587],
hostname: 'mail.mixed.test',
domains: ['mixed.test'],
routes: [],
useSocketHandler: false // Traditional mode
},
smartProxyConfig: {
routes: []
}
});
await dcRouter.start();
const smartProxy = (dcRouter as any).smartProxy;
const routes = smartProxy?.options?.routes || [];
// DNS routes should be socket-handler
const dnsRoutes = routes.filter((route: any) =>
route.name?.includes('dns-over-https')
);
dnsRoutes.forEach((route: any) => {
expect(route.action.type).toEqual('socket-handler');
});
// Email routes should be forward
const emailRoutes = routes.filter((route: any) =>
route.name?.includes('-route') && !route.name?.includes('dns')
);
emailRoutes.forEach((route: any) => {
expect(route.action.type).toEqual('forward');
expect(route.action.target.port).toBeGreaterThan(10000); // Internal port
});
await dcRouter.stop();
});
tap.test('should properly clean up resources on stop', async () => {
dcRouter = new DcRouter({
dnsDomain: 'dns.cleanup.test',
emailConfig: {
ports: [25],
hostname: 'mail.cleanup.test',
domains: ['cleanup.test'],
routes: [],
useSocketHandler: true
}
});
await dcRouter.start();
// Services should be running
expect((dcRouter as any).dnsServer).toBeDefined();
expect((dcRouter as any).emailServer).toBeDefined();
expect((dcRouter as any).smartProxy).toBeDefined();
await dcRouter.stop();
// After stop, services should still be defined but stopped
// (The stop method doesn't null out the properties, just stops the services)
expect((dcRouter as any).dnsServer).toBeDefined();
expect((dcRouter as any).emailServer).toBeDefined();
});
tap.test('should handle configuration updates correctly', async () => {
// Start with minimal config
dcRouter = new DcRouter({
smartProxyConfig: {
routes: []
}
});
await dcRouter.start();
// Initially no DNS or email
expect((dcRouter as any).dnsServer).toBeUndefined();
expect((dcRouter as any).emailServer).toBeUndefined();
// Update to add email config
await dcRouter.updateEmailConfig({
ports: [25],
hostname: 'mail.update.test',
domains: ['update.test'],
routes: [],
useSocketHandler: true
});
// Now email should be running
expect((dcRouter as any).emailServer).toBeDefined();
await dcRouter.stop();
});
tap.test('performance: socket-handler should not create internal listeners', async () => {
dcRouter = new DcRouter({
dnsDomain: 'dns.perf.test',
emailConfig: {
ports: [25, 587, 465],
hostname: 'mail.perf.test',
domains: ['perf.test'],
routes: [],
useSocketHandler: true
}
});
await dcRouter.start();
// Get the number of listeners before creating handlers
const eventCounts: { [key: string]: number } = {};
// DNS server should not have HTTPS listeners
const dnsServer = (dcRouter as any).dnsServer;
// The DNS server should exist but not bind to HTTPS port
expect(dnsServer).toBeDefined();
// Email server should not have any server listeners
const emailServer = (dcRouter as any).emailServer;
expect(emailServer.servers.length).toEqual(0);
await dcRouter.stop();
});
tap.test('should handle errors gracefully', async () => {
dcRouter = new DcRouter({
dnsDomain: 'dns.error.test',
emailConfig: {
ports: [25],
hostname: 'mail.error.test',
domains: ['error.test'],
routes: [],
useSocketHandler: true
}
});
await dcRouter.start();
// Test DNS error handling
const dnsHandler = (dcRouter as any).createDnsSocketHandler();
const errorSocket = new plugins.net.Socket();
let errorThrown = false;
try {
// This should handle the error gracefully
await dnsHandler(errorSocket);
} catch (error) {
errorThrown = true;
}
// Should not throw, should handle gracefully
expect(errorThrown).toBeFalsy();
await dcRouter.stop();
});
tap.test('should correctly identify secure connections', async () => {
dcRouter = new DcRouter({
emailConfig: {
ports: [465],
hostname: 'mail.secure.test',
domains: ['secure.test'],
routes: [],
useSocketHandler: true
}
});
await dcRouter.start();
// The email socket handler for port 465 should handle TLS
const handler = (dcRouter as any).createMailSocketHandler(465);
expect(handler).toBeDefined();
// Port 465 requires immediate TLS, which is handled in the socket handler
// This is different from ports 25/587 which use STARTTLS
await dcRouter.stop();
});
tap.test('stop', async () => {
await tap.stopForcefully();
});
export default tap.start();