124 lines
4.6 KiB
TypeScript
124 lines
4.6 KiB
TypeScript
|
|
import { tap, expect } from '@git.zone/tstest/tapbundle';
|
||
|
|
|
||
|
|
import {
|
||
|
|
createHttpsTerminateRoute,
|
||
|
|
createCompleteHttpsServer,
|
||
|
|
createHttpRoute,
|
||
|
|
} from '../ts/proxies/smart-proxy/utils/route-helpers.js';
|
||
|
|
|
||
|
|
import {
|
||
|
|
mergeRouteConfigs,
|
||
|
|
cloneRoute,
|
||
|
|
routeMatchesPath,
|
||
|
|
} from '../ts/proxies/smart-proxy/utils/route-utils.js';
|
||
|
|
|
||
|
|
import {
|
||
|
|
validateRoutes,
|
||
|
|
validateRouteConfig,
|
||
|
|
} from '../ts/proxies/smart-proxy/utils/route-validator.js';
|
||
|
|
|
||
|
|
import type { IRouteConfig } from '../ts/proxies/smart-proxy/models/route-types.js';
|
||
|
|
|
||
|
|
tap.test('route creation - createHttpsTerminateRoute produces correct structure', async () => {
|
||
|
|
const route = createHttpsTerminateRoute('secure.example.com', { host: '127.0.0.1', port: 8443 });
|
||
|
|
expect(route).toHaveProperty('match');
|
||
|
|
expect(route).toHaveProperty('action');
|
||
|
|
expect(route.action.type).toEqual('forward');
|
||
|
|
expect(route.action.tls).toBeDefined();
|
||
|
|
expect(route.action.tls!.mode).toEqual('terminate');
|
||
|
|
expect(route.match.domains).toEqual('secure.example.com');
|
||
|
|
});
|
||
|
|
|
||
|
|
tap.test('route creation - createCompleteHttpsServer returns redirect and main route', async () => {
|
||
|
|
const routes = createCompleteHttpsServer('app.example.com', { host: '127.0.0.1', port: 3000 });
|
||
|
|
expect(routes).toBeArray();
|
||
|
|
expect(routes.length).toBeGreaterThanOrEqual(2);
|
||
|
|
// Should have an HTTP→HTTPS redirect and an HTTPS route
|
||
|
|
const hasRedirect = routes.some((r) => r.action.type === 'forward' && r.action.redirect !== undefined);
|
||
|
|
const hasHttps = routes.some((r) => r.action.tls?.mode === 'terminate');
|
||
|
|
expect(hasRedirect || hasHttps).toBeTrue();
|
||
|
|
});
|
||
|
|
|
||
|
|
tap.test('route validation - validateRoutes on a set of routes', async () => {
|
||
|
|
const routes: IRouteConfig[] = [
|
||
|
|
createHttpRoute('a.com', { host: '127.0.0.1', port: 3000 }),
|
||
|
|
createHttpRoute('b.com', { host: '127.0.0.1', port: 4000 }),
|
||
|
|
];
|
||
|
|
const result = validateRoutes(routes);
|
||
|
|
expect(result.valid).toBeTrue();
|
||
|
|
expect(result.errors).toHaveLength(0);
|
||
|
|
});
|
||
|
|
|
||
|
|
tap.test('route validation - validateRoutes catches invalid route in set', async () => {
|
||
|
|
const routes: any[] = [
|
||
|
|
createHttpRoute('valid.com', { host: '127.0.0.1', port: 3000 }),
|
||
|
|
{ match: { ports: 80 } }, // missing action
|
||
|
|
];
|
||
|
|
const result = validateRoutes(routes);
|
||
|
|
expect(result.valid).toBeFalse();
|
||
|
|
expect(result.errors.length).toBeGreaterThan(0);
|
||
|
|
});
|
||
|
|
|
||
|
|
tap.test('path matching - routeMatchesPath with exact path', async () => {
|
||
|
|
const route = createHttpRoute('example.com', { host: '127.0.0.1', port: 3000 });
|
||
|
|
route.match.path = '/api';
|
||
|
|
expect(routeMatchesPath(route, '/api')).toBeTrue();
|
||
|
|
expect(routeMatchesPath(route, '/other')).toBeFalse();
|
||
|
|
});
|
||
|
|
|
||
|
|
tap.test('path matching - route without path matches everything', async () => {
|
||
|
|
const route = createHttpRoute('example.com', { host: '127.0.0.1', port: 3000 });
|
||
|
|
// No path set, should match any path
|
||
|
|
expect(routeMatchesPath(route, '/anything')).toBeTrue();
|
||
|
|
expect(routeMatchesPath(route, '/')).toBeTrue();
|
||
|
|
});
|
||
|
|
|
||
|
|
tap.test('route merging - mergeRouteConfigs combines routes', async () => {
|
||
|
|
const base = createHttpRoute('example.com', { host: '127.0.0.1', port: 3000 });
|
||
|
|
base.priority = 10;
|
||
|
|
base.name = 'base-route';
|
||
|
|
|
||
|
|
const merged = mergeRouteConfigs(base, {
|
||
|
|
priority: 50,
|
||
|
|
name: 'merged-route',
|
||
|
|
});
|
||
|
|
|
||
|
|
expect(merged.priority).toEqual(50);
|
||
|
|
expect(merged.name).toEqual('merged-route');
|
||
|
|
// Original route fields should be preserved
|
||
|
|
expect(merged.match.domains).toEqual('example.com');
|
||
|
|
expect(merged.action.targets![0].host).toEqual('127.0.0.1');
|
||
|
|
});
|
||
|
|
|
||
|
|
tap.test('route merging - mergeRouteConfigs does not mutate original', async () => {
|
||
|
|
const base = createHttpRoute('example.com', { host: '127.0.0.1', port: 3000 });
|
||
|
|
base.name = 'original';
|
||
|
|
|
||
|
|
const merged = mergeRouteConfigs(base, { name: 'changed' });
|
||
|
|
expect(base.name).toEqual('original');
|
||
|
|
expect(merged.name).toEqual('changed');
|
||
|
|
});
|
||
|
|
|
||
|
|
tap.test('route cloning - cloneRoute produces independent copy', async () => {
|
||
|
|
const original = createHttpRoute('example.com', { host: '127.0.0.1', port: 3000 });
|
||
|
|
original.priority = 42;
|
||
|
|
original.name = 'original-route';
|
||
|
|
|
||
|
|
const cloned = cloneRoute(original);
|
||
|
|
|
||
|
|
// Should be equal in value
|
||
|
|
expect(cloned.match.domains).toEqual('example.com');
|
||
|
|
expect(cloned.priority).toEqual(42);
|
||
|
|
expect(cloned.name).toEqual('original-route');
|
||
|
|
expect(cloned.action.targets![0].host).toEqual('127.0.0.1');
|
||
|
|
expect(cloned.action.targets![0].port).toEqual(3000);
|
||
|
|
|
||
|
|
// Should be independent - modifying clone shouldn't affect original
|
||
|
|
cloned.name = 'cloned-route';
|
||
|
|
cloned.priority = 99;
|
||
|
|
expect(original.name).toEqual('original-route');
|
||
|
|
expect(original.priority).toEqual(42);
|
||
|
|
});
|
||
|
|
|
||
|
|
export default tap.start();
|