185 lines
5.7 KiB
TypeScript
185 lines
5.7 KiB
TypeScript
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; |