import { expect, tap } from '@git.zone/tstest/tapbundle'; import { DcRouter } from '../ts/classes.dcrouter.js'; import { VpnManager } from '../ts/vpn/classes.vpn-manager.js'; tap.test('VpnManager downgrades back to socket mode when no host-IP clients remain', async () => { const manager = new VpnManager({ forwardingMode: 'socket' }); let stopCalls = 0; let startCalls = 0; (manager as any).vpnServer = { running: true }; (manager as any).resolvedForwardingMode = 'hybrid'; (manager as any).clients = new Map([ ['client-1', { useHostIp: false }], ]); (manager as any).stop = async () => { stopCalls++; }; (manager as any).start = async () => { startCalls++; (manager as any).resolvedForwardingMode = (manager as any).forwardingModeOverride ?? 'socket'; (manager as any).forwardingModeOverride = undefined; (manager as any).vpnServer = { running: true }; }; const restarted = await (manager as any).reconcileForwardingMode(); expect(restarted).toEqual(true); expect(stopCalls).toEqual(1); expect(startCalls).toEqual(1); expect((manager as any).resolvedForwardingMode).toEqual('socket'); }); tap.test('VpnManager keeps explicit hybrid mode even without host-IP clients', async () => { const manager = new VpnManager({ forwardingMode: 'hybrid' }); let stopCalls = 0; let startCalls = 0; (manager as any).vpnServer = { running: true }; (manager as any).resolvedForwardingMode = 'hybrid'; (manager as any).clients = new Map([ ['client-1', { useHostIp: false }], ]); (manager as any).stop = async () => { stopCalls++; }; (manager as any).start = async () => { startCalls++; }; const restarted = await (manager as any).reconcileForwardingMode(); expect(restarted).toEqual(false); expect(stopCalls).toEqual(0); expect(startCalls).toEqual(0); expect((manager as any).resolvedForwardingMode).toEqual('hybrid'); }); tap.test('DcRouter.updateVpnConfig swaps the runtime VPN resolver and restarts VPN services', async () => { const dcRouter = new DcRouter({ smartProxyConfig: { routes: [] }, dbConfig: { enabled: false }, vpnConfig: { enabled: false }, }); let stopCalls = 0; let setupCalls = 0; let applyCalls = 0; const resolverValues: Array = []; dcRouter.vpnManager = { stop: async () => { stopCalls++; }, } as any; (dcRouter as any).routeConfigManager = { setVpnClientIpsResolver: (resolver: unknown) => { resolverValues.push(resolver); }, applyRoutes: async () => { applyCalls++; }, }; (dcRouter as any).setupVpnServer = async () => { setupCalls++; dcRouter.vpnManager = { stop: async () => { stopCalls++; }, } as any; }; await dcRouter.updateVpnConfig({ enabled: true, subnet: '10.9.0.0/24' }); expect(stopCalls).toEqual(1); expect(setupCalls).toEqual(1); expect(applyCalls).toEqual(0); expect(typeof resolverValues.at(-1)).toEqual('function'); await dcRouter.updateVpnConfig({ enabled: false }); expect(stopCalls).toEqual(2); expect(setupCalls).toEqual(1); expect(applyCalls).toEqual(1); expect(resolverValues.at(-1)).toBeUndefined(); expect(dcRouter.vpnManager).toBeUndefined(); }); export default tap.start()