import { expect, tap } from '@push.rocks/tapbundle'; import { AcmeStateManager } from '../ts/proxies/smart-proxy/acme-state-manager.js'; import type { IRouteConfig } from '../ts/proxies/smart-proxy/models/route-types.js'; tap.test('AcmeStateManager should track challenge routes correctly', async (tools) => { const stateManager = new AcmeStateManager(); const challengeRoute: IRouteConfig = { name: 'acme-challenge', priority: 1000, match: { ports: 80, path: '/.well-known/acme-challenge/*' }, action: { type: 'static', handler: async () => ({ status: 200, body: 'challenge' }) } }; // Initially no challenge routes tools.expect(stateManager.isChallengeRouteActive()).toBeFalse(); tools.expect(stateManager.getActiveChallengeRoutes()).toHaveLength(0); // Add challenge route stateManager.addChallengeRoute(challengeRoute); tools.expect(stateManager.isChallengeRouteActive()).toBeTrue(); tools.expect(stateManager.getActiveChallengeRoutes()).toHaveLength(1); tools.expect(stateManager.getPrimaryChallengeRoute()).toEqual(challengeRoute); // Remove challenge route stateManager.removeChallengeRoute('acme-challenge'); tools.expect(stateManager.isChallengeRouteActive()).toBeFalse(); tools.expect(stateManager.getActiveChallengeRoutes()).toHaveLength(0); tools.expect(stateManager.getPrimaryChallengeRoute()).toBeNull(); }); tap.test('AcmeStateManager should track port allocations', async (tools) => { const stateManager = new AcmeStateManager(); const challengeRoute1: IRouteConfig = { name: 'acme-challenge-1', priority: 1000, match: { ports: 80, path: '/.well-known/acme-challenge/*' }, action: { type: 'static' } }; const challengeRoute2: IRouteConfig = { name: 'acme-challenge-2', priority: 900, match: { ports: [80, 8080], path: '/.well-known/acme-challenge/*' }, action: { type: 'static' } }; // Add first route stateManager.addChallengeRoute(challengeRoute1); tools.expect(stateManager.isPortAllocatedForAcme(80)).toBeTrue(); tools.expect(stateManager.isPortAllocatedForAcme(8080)).toBeFalse(); tools.expect(stateManager.getAcmePorts()).toEqual([80]); // Add second route stateManager.addChallengeRoute(challengeRoute2); tools.expect(stateManager.isPortAllocatedForAcme(80)).toBeTrue(); tools.expect(stateManager.isPortAllocatedForAcme(8080)).toBeTrue(); tools.expect(stateManager.getAcmePorts()).toContain(80); tools.expect(stateManager.getAcmePorts()).toContain(8080); // Remove first route - port 80 should still be allocated stateManager.removeChallengeRoute('acme-challenge-1'); tools.expect(stateManager.isPortAllocatedForAcme(80)).toBeTrue(); tools.expect(stateManager.isPortAllocatedForAcme(8080)).toBeTrue(); // Remove second route - all ports should be deallocated stateManager.removeChallengeRoute('acme-challenge-2'); tools.expect(stateManager.isPortAllocatedForAcme(80)).toBeFalse(); tools.expect(stateManager.isPortAllocatedForAcme(8080)).toBeFalse(); tools.expect(stateManager.getAcmePorts()).toHaveLength(0); }); tap.test('AcmeStateManager should select primary route by priority', async (tools) => { const stateManager = new AcmeStateManager(); const lowPriorityRoute: IRouteConfig = { name: 'low-priority', priority: 100, match: { ports: 80 }, action: { type: 'static' } }; const highPriorityRoute: IRouteConfig = { name: 'high-priority', priority: 2000, match: { ports: 80 }, action: { type: 'static' } }; const defaultPriorityRoute: IRouteConfig = { name: 'default-priority', // No priority specified - should default to 0 match: { ports: 80 }, action: { type: 'static' } }; // Add low priority first stateManager.addChallengeRoute(lowPriorityRoute); tools.expect(stateManager.getPrimaryChallengeRoute()?.name).toEqual('low-priority'); // Add high priority - should become primary stateManager.addChallengeRoute(highPriorityRoute); tools.expect(stateManager.getPrimaryChallengeRoute()?.name).toEqual('high-priority'); // Add default priority - primary should remain high priority stateManager.addChallengeRoute(defaultPriorityRoute); tools.expect(stateManager.getPrimaryChallengeRoute()?.name).toEqual('high-priority'); // Remove high priority - primary should fall back to low priority stateManager.removeChallengeRoute('high-priority'); tools.expect(stateManager.getPrimaryChallengeRoute()?.name).toEqual('low-priority'); }); tap.test('AcmeStateManager should handle clear operation', async (tools) => { const stateManager = new AcmeStateManager(); const challengeRoute1: IRouteConfig = { name: 'route-1', match: { ports: [80, 443] }, action: { type: 'static' } }; const challengeRoute2: IRouteConfig = { name: 'route-2', match: { ports: 8080 }, action: { type: 'static' } }; // Add routes stateManager.addChallengeRoute(challengeRoute1); stateManager.addChallengeRoute(challengeRoute2); // Verify state before clear tools.expect(stateManager.isChallengeRouteActive()).toBeTrue(); tools.expect(stateManager.getActiveChallengeRoutes()).toHaveLength(2); tools.expect(stateManager.getAcmePorts()).toHaveLength(3); // Clear all state stateManager.clear(); // Verify state after clear tools.expect(stateManager.isChallengeRouteActive()).toBeFalse(); tools.expect(stateManager.getActiveChallengeRoutes()).toHaveLength(0); tools.expect(stateManager.getAcmePorts()).toHaveLength(0); tools.expect(stateManager.getPrimaryChallengeRoute()).toBeNull(); }); export default tap;