import { expect, tap } from '@git.zone/tstest/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 expect(stateManager.isChallengeRouteActive()).toBeFalse(); expect(stateManager.getActiveChallengeRoutes()).toEqual([]); // Add challenge route stateManager.addChallengeRoute(challengeRoute); expect(stateManager.isChallengeRouteActive()).toBeTrue(); expect(stateManager.getActiveChallengeRoutes()).toHaveProperty("length", 1); expect(stateManager.getPrimaryChallengeRoute()).toEqual(challengeRoute); // Remove challenge route stateManager.removeChallengeRoute('acme-challenge'); expect(stateManager.isChallengeRouteActive()).toBeFalse(); expect(stateManager.getActiveChallengeRoutes()).toEqual([]); 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); expect(stateManager.isPortAllocatedForAcme(80)).toBeTrue(); expect(stateManager.isPortAllocatedForAcme(8080)).toBeFalse(); expect(stateManager.getAcmePorts()).toEqual([80]); // Add second route stateManager.addChallengeRoute(challengeRoute2); expect(stateManager.isPortAllocatedForAcme(80)).toBeTrue(); expect(stateManager.isPortAllocatedForAcme(8080)).toBeTrue(); expect(stateManager.getAcmePorts()).toContain(80); expect(stateManager.getAcmePorts()).toContain(8080); // Remove first route - port 80 should still be allocated stateManager.removeChallengeRoute('acme-challenge-1'); expect(stateManager.isPortAllocatedForAcme(80)).toBeTrue(); expect(stateManager.isPortAllocatedForAcme(8080)).toBeTrue(); // Remove second route - all ports should be deallocated stateManager.removeChallengeRoute('acme-challenge-2'); expect(stateManager.isPortAllocatedForAcme(80)).toBeFalse(); expect(stateManager.isPortAllocatedForAcme(8080)).toBeFalse(); expect(stateManager.getAcmePorts()).toEqual([]); }); 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); expect(stateManager.getPrimaryChallengeRoute()?.name).toEqual('low-priority'); // Add high priority - should become primary stateManager.addChallengeRoute(highPriorityRoute); expect(stateManager.getPrimaryChallengeRoute()?.name).toEqual('high-priority'); // Add default priority - primary should remain high priority stateManager.addChallengeRoute(defaultPriorityRoute); expect(stateManager.getPrimaryChallengeRoute()?.name).toEqual('high-priority'); // Remove high priority - primary should fall back to low priority stateManager.removeChallengeRoute('high-priority'); 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 expect(stateManager.isChallengeRouteActive()).toBeTrue(); expect(stateManager.getActiveChallengeRoutes()).toHaveProperty("length", 2); expect(stateManager.getAcmePorts()).toHaveProperty("length", 3); // Clear all state stateManager.clear(); // Verify state after clear expect(stateManager.isChallengeRouteActive()).toBeFalse(); expect(stateManager.getActiveChallengeRoutes()).toEqual([]); expect(stateManager.getAcmePorts()).toEqual([]); expect(stateManager.getPrimaryChallengeRoute()).toBeNull(); }); export default tap.start();