600 lines
21 KiB
TypeScript
600 lines
21 KiB
TypeScript
/**
|
|
* Tests for the unified route-based configuration system
|
|
*/
|
|
import { expect, tap } from '@push.rocks/tapbundle';
|
|
|
|
// Import from core modules
|
|
import { SmartProxy } from '../ts/proxies/smart-proxy/index.js';
|
|
|
|
// Import route utilities and helpers
|
|
import {
|
|
findMatchingRoutes,
|
|
findBestMatchingRoute,
|
|
routeMatchesDomain,
|
|
routeMatchesPort,
|
|
routeMatchesPath,
|
|
routeMatchesHeaders,
|
|
mergeRouteConfigs,
|
|
generateRouteId,
|
|
cloneRoute
|
|
} from '../ts/proxies/smart-proxy/utils/route-utils.js';
|
|
|
|
import {
|
|
validateRouteConfig,
|
|
validateRoutes,
|
|
isValidDomain,
|
|
isValidPort,
|
|
hasRequiredPropertiesForAction,
|
|
assertValidRoute
|
|
} from '../ts/proxies/smart-proxy/utils/route-validators.js';
|
|
|
|
import {
|
|
createHttpRoute,
|
|
createHttpsTerminateRoute,
|
|
createHttpsPassthroughRoute,
|
|
createHttpToHttpsRedirect,
|
|
createCompleteHttpsServer,
|
|
createLoadBalancerRoute,
|
|
createStaticFileRoute,
|
|
createApiRoute,
|
|
createWebSocketRoute
|
|
} from '../ts/proxies/smart-proxy/utils/route-helpers.js';
|
|
|
|
// Import test helpers
|
|
import { loadTestCertificates } from './helpers/certificates.js';
|
|
|
|
import type { IRouteConfig } from '../ts/proxies/smart-proxy/models/route-types.js';
|
|
|
|
// --------------------------------- Route Creation Tests ---------------------------------
|
|
|
|
tap.test('Routes: Should create basic HTTP route', async () => {
|
|
// Create a simple HTTP route
|
|
const httpRoute = createHttpRoute('example.com', { host: 'localhost', port: 3000 }, {
|
|
name: 'Basic HTTP Route'
|
|
});
|
|
|
|
// Validate the route configuration
|
|
expect(httpRoute.match.ports).toEqual(80);
|
|
expect(httpRoute.match.domains).toEqual('example.com');
|
|
expect(httpRoute.action.type).toEqual('forward');
|
|
expect(httpRoute.action.target?.host).toEqual('localhost');
|
|
expect(httpRoute.action.target?.port).toEqual(3000);
|
|
expect(httpRoute.name).toEqual('Basic HTTP Route');
|
|
});
|
|
|
|
tap.test('Routes: Should create HTTPS route with TLS termination', async () => {
|
|
// Create an HTTPS route with TLS termination
|
|
const httpsRoute = createHttpsTerminateRoute('secure.example.com', { host: 'localhost', port: 8080 }, {
|
|
certificate: 'auto',
|
|
name: 'HTTPS Route'
|
|
});
|
|
|
|
// Validate the route configuration
|
|
expect(httpsRoute.match.ports).toEqual(443); // Default HTTPS port
|
|
expect(httpsRoute.match.domains).toEqual('secure.example.com');
|
|
expect(httpsRoute.action.type).toEqual('forward');
|
|
expect(httpsRoute.action.tls?.mode).toEqual('terminate');
|
|
expect(httpsRoute.action.tls?.certificate).toEqual('auto');
|
|
expect(httpsRoute.action.target?.host).toEqual('localhost');
|
|
expect(httpsRoute.action.target?.port).toEqual(8080);
|
|
expect(httpsRoute.name).toEqual('HTTPS Route');
|
|
});
|
|
|
|
tap.test('Routes: Should create HTTP to HTTPS redirect', async () => {
|
|
// Create an HTTP to HTTPS redirect
|
|
const redirectRoute = createHttpToHttpsRedirect('example.com', 443, {
|
|
status: 301
|
|
});
|
|
|
|
// Validate the route configuration
|
|
expect(redirectRoute.match.ports).toEqual(80);
|
|
expect(redirectRoute.match.domains).toEqual('example.com');
|
|
expect(redirectRoute.action.type).toEqual('redirect');
|
|
expect(redirectRoute.action.redirect?.to).toEqual('https://{domain}:443{path}');
|
|
expect(redirectRoute.action.redirect?.status).toEqual(301);
|
|
});
|
|
|
|
tap.test('Routes: Should create complete HTTPS server with redirects', async () => {
|
|
// Create a complete HTTPS server setup
|
|
const routes = createCompleteHttpsServer('example.com', { host: 'localhost', port: 8080 }, {
|
|
certificate: 'auto'
|
|
});
|
|
|
|
// Validate that we got two routes (HTTPS route and HTTP redirect)
|
|
expect(routes.length).toEqual(2);
|
|
|
|
// Validate HTTPS route
|
|
const httpsRoute = routes[0];
|
|
expect(httpsRoute.match.ports).toEqual(443);
|
|
expect(httpsRoute.match.domains).toEqual('example.com');
|
|
expect(httpsRoute.action.type).toEqual('forward');
|
|
expect(httpsRoute.action.tls?.mode).toEqual('terminate');
|
|
|
|
// Validate HTTP redirect route
|
|
const redirectRoute = routes[1];
|
|
expect(redirectRoute.match.ports).toEqual(80);
|
|
expect(redirectRoute.action.type).toEqual('redirect');
|
|
expect(redirectRoute.action.redirect?.to).toEqual('https://{domain}:443{path}');
|
|
});
|
|
|
|
tap.test('Routes: Should create load balancer route', async () => {
|
|
// Create a load balancer route
|
|
const lbRoute = createLoadBalancerRoute(
|
|
'app.example.com',
|
|
['10.0.0.1', '10.0.0.2', '10.0.0.3'],
|
|
8080,
|
|
{
|
|
tls: {
|
|
mode: 'terminate',
|
|
certificate: 'auto'
|
|
},
|
|
name: 'Load Balanced Route'
|
|
}
|
|
);
|
|
|
|
// Validate the route configuration
|
|
expect(lbRoute.match.domains).toEqual('app.example.com');
|
|
expect(lbRoute.action.type).toEqual('forward');
|
|
expect(Array.isArray(lbRoute.action.target?.host)).toBeTrue();
|
|
expect((lbRoute.action.target?.host as string[]).length).toEqual(3);
|
|
expect((lbRoute.action.target?.host as string[])[0]).toEqual('10.0.0.1');
|
|
expect(lbRoute.action.target?.port).toEqual(8080);
|
|
expect(lbRoute.action.tls?.mode).toEqual('terminate');
|
|
});
|
|
|
|
tap.test('Routes: Should create API route with CORS', async () => {
|
|
// Create an API route with CORS headers
|
|
const apiRoute = createApiRoute('api.example.com', '/v1', { host: 'localhost', port: 3000 }, {
|
|
useTls: true,
|
|
certificate: 'auto',
|
|
addCorsHeaders: true,
|
|
name: 'API Route'
|
|
});
|
|
|
|
// Validate the route configuration
|
|
expect(apiRoute.match.domains).toEqual('api.example.com');
|
|
expect(apiRoute.match.path).toEqual('/v1/*');
|
|
expect(apiRoute.action.type).toEqual('forward');
|
|
expect(apiRoute.action.tls?.mode).toEqual('terminate');
|
|
expect(apiRoute.action.target?.host).toEqual('localhost');
|
|
expect(apiRoute.action.target?.port).toEqual(3000);
|
|
|
|
// Check CORS headers
|
|
expect(apiRoute.headers).toBeDefined();
|
|
if (apiRoute.headers?.response) {
|
|
expect(apiRoute.headers.response['Access-Control-Allow-Origin']).toEqual('*');
|
|
expect(apiRoute.headers.response['Access-Control-Allow-Methods']).toInclude('GET');
|
|
}
|
|
});
|
|
|
|
tap.test('Routes: Should create WebSocket route', async () => {
|
|
// Create a WebSocket route
|
|
const wsRoute = createWebSocketRoute('ws.example.com', '/socket', { host: 'localhost', port: 5000 }, {
|
|
useTls: true,
|
|
certificate: 'auto',
|
|
pingInterval: 15000,
|
|
name: 'WebSocket Route'
|
|
});
|
|
|
|
// Validate the route configuration
|
|
expect(wsRoute.match.domains).toEqual('ws.example.com');
|
|
expect(wsRoute.match.path).toEqual('/socket');
|
|
expect(wsRoute.action.type).toEqual('forward');
|
|
expect(wsRoute.action.tls?.mode).toEqual('terminate');
|
|
expect(wsRoute.action.target?.host).toEqual('localhost');
|
|
expect(wsRoute.action.target?.port).toEqual(5000);
|
|
|
|
// Check WebSocket configuration
|
|
expect(wsRoute.action.websocket).toBeDefined();
|
|
if (wsRoute.action.websocket) {
|
|
expect(wsRoute.action.websocket.enabled).toBeTrue();
|
|
expect(wsRoute.action.websocket.pingInterval).toEqual(15000);
|
|
}
|
|
});
|
|
|
|
tap.test('Routes: Should create static file route', async () => {
|
|
// Create a static file route
|
|
const staticRoute = createStaticFileRoute('static.example.com', '/var/www/html', {
|
|
serveOnHttps: true,
|
|
certificate: 'auto',
|
|
indexFiles: ['index.html', 'index.htm', 'default.html'],
|
|
name: 'Static File Route'
|
|
});
|
|
|
|
// Validate the route configuration
|
|
expect(staticRoute.match.domains).toEqual('static.example.com');
|
|
expect(staticRoute.action.type).toEqual('static');
|
|
expect(staticRoute.action.static?.root).toEqual('/var/www/html');
|
|
expect(staticRoute.action.static?.index).toBeInstanceOf(Array);
|
|
expect(staticRoute.action.static?.index).toInclude('index.html');
|
|
expect(staticRoute.action.static?.index).toInclude('default.html');
|
|
expect(staticRoute.action.tls?.mode).toEqual('terminate');
|
|
});
|
|
|
|
tap.test('SmartProxy: Should create instance with route-based config', async () => {
|
|
// Create TLS certificates for testing
|
|
const certs = loadTestCertificates();
|
|
|
|
// Create a SmartProxy instance with route-based configuration
|
|
const proxy = new SmartProxy({
|
|
routes: [
|
|
createHttpRoute('example.com', { host: 'localhost', port: 3000 }, {
|
|
name: 'HTTP Route'
|
|
}),
|
|
createHttpsTerminateRoute('secure.example.com', { host: 'localhost', port: 8443 }, {
|
|
certificate: {
|
|
key: certs.privateKey,
|
|
cert: certs.publicKey
|
|
},
|
|
name: 'HTTPS Route'
|
|
})
|
|
],
|
|
defaults: {
|
|
target: {
|
|
host: 'localhost',
|
|
port: 8080
|
|
},
|
|
security: {
|
|
allowedIps: ['127.0.0.1', '192.168.0.*'],
|
|
maxConnections: 100
|
|
}
|
|
},
|
|
// Additional settings
|
|
initialDataTimeout: 10000,
|
|
inactivityTimeout: 300000,
|
|
enableDetailedLogging: true
|
|
});
|
|
|
|
// Simply verify the instance was created successfully
|
|
expect(typeof proxy).toEqual('object');
|
|
expect(typeof proxy.start).toEqual('function');
|
|
expect(typeof proxy.stop).toEqual('function');
|
|
});
|
|
|
|
// --------------------------------- Edge Case Tests ---------------------------------
|
|
|
|
tap.test('Edge Case - Empty Routes Array', async () => {
|
|
// Attempting to find routes in an empty array
|
|
const emptyRoutes: IRouteConfig[] = [];
|
|
const matches = findMatchingRoutes(emptyRoutes, { domain: 'example.com', port: 80 });
|
|
|
|
expect(matches).toBeInstanceOf(Array);
|
|
expect(matches.length).toEqual(0);
|
|
|
|
const bestMatch = findBestMatchingRoute(emptyRoutes, { domain: 'example.com', port: 80 });
|
|
expect(bestMatch).toBeUndefined();
|
|
});
|
|
|
|
tap.test('Edge Case - Multiple Matching Routes with Same Priority', async () => {
|
|
// Create multiple routes with identical priority but different targets
|
|
const route1 = createHttpRoute('example.com', { host: 'server1', port: 3000 });
|
|
const route2 = createHttpRoute('example.com', { host: 'server2', port: 3000 });
|
|
const route3 = createHttpRoute('example.com', { host: 'server3', port: 3000 });
|
|
|
|
// Set all to the same priority
|
|
route1.priority = 100;
|
|
route2.priority = 100;
|
|
route3.priority = 100;
|
|
|
|
const routes = [route1, route2, route3];
|
|
|
|
// Find matching routes
|
|
const matches = findMatchingRoutes(routes, { domain: 'example.com', port: 80 });
|
|
|
|
// Should find all three routes
|
|
expect(matches.length).toEqual(3);
|
|
|
|
// First match could be any of the routes since they have the same priority
|
|
// But the implementation should be consistent (likely keep the original order)
|
|
const bestMatch = findBestMatchingRoute(routes, { domain: 'example.com', port: 80 });
|
|
expect(bestMatch).not.toBeUndefined();
|
|
});
|
|
|
|
tap.test('Edge Case - Wildcard Domains and Path Matching', async () => {
|
|
// Create routes with wildcard domains and path patterns
|
|
const wildcardApiRoute = createApiRoute('*.example.com', '/api', { host: 'api-server', port: 3000 }, {
|
|
useTls: true,
|
|
certificate: 'auto'
|
|
});
|
|
|
|
const exactApiRoute = createApiRoute('api.example.com', '/api', { host: 'specific-api-server', port: 3001 }, {
|
|
useTls: true,
|
|
certificate: 'auto',
|
|
priority: 200 // Higher priority
|
|
});
|
|
|
|
const routes = [wildcardApiRoute, exactApiRoute];
|
|
|
|
// Test with a specific subdomain that matches both routes
|
|
const matches = findMatchingRoutes(routes, { domain: 'api.example.com', path: '/api/users', port: 443 });
|
|
|
|
// Should match both routes
|
|
expect(matches.length).toEqual(2);
|
|
|
|
// The exact domain match should have higher priority
|
|
const bestMatch = findBestMatchingRoute(routes, { domain: 'api.example.com', path: '/api/users', port: 443 });
|
|
expect(bestMatch).not.toBeUndefined();
|
|
if (bestMatch) {
|
|
expect(bestMatch.action.target.port).toEqual(3001); // Should match the exact domain route
|
|
}
|
|
|
|
// Test with a different subdomain - should only match the wildcard route
|
|
const otherMatches = findMatchingRoutes(routes, { domain: 'other.example.com', path: '/api/products', port: 443 });
|
|
expect(otherMatches.length).toEqual(1);
|
|
expect(otherMatches[0].action.target.port).toEqual(3000); // Should match the wildcard domain route
|
|
});
|
|
|
|
tap.test('Edge Case - Disabled Routes', async () => {
|
|
// Create enabled and disabled routes
|
|
const enabledRoute = createHttpRoute('example.com', { host: 'server1', port: 3000 });
|
|
const disabledRoute = createHttpRoute('example.com', { host: 'server2', port: 3001 });
|
|
disabledRoute.enabled = false;
|
|
|
|
const routes = [enabledRoute, disabledRoute];
|
|
|
|
// Find matching routes
|
|
const matches = findMatchingRoutes(routes, { domain: 'example.com', port: 80 });
|
|
|
|
// Should only find the enabled route
|
|
expect(matches.length).toEqual(1);
|
|
expect(matches[0].action.target.port).toEqual(3000);
|
|
});
|
|
|
|
tap.test('Edge Case - Complex Path and Headers Matching', async () => {
|
|
// Create route with complex path and headers matching
|
|
const complexRoute: IRouteConfig = {
|
|
match: {
|
|
domains: 'api.example.com',
|
|
ports: 443,
|
|
path: '/api/v2/*',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'X-API-Key': 'valid-key'
|
|
}
|
|
},
|
|
action: {
|
|
type: 'forward',
|
|
target: {
|
|
host: 'internal-api',
|
|
port: 8080
|
|
},
|
|
tls: {
|
|
mode: 'terminate',
|
|
certificate: 'auto'
|
|
}
|
|
},
|
|
name: 'Complex API Route'
|
|
};
|
|
|
|
// Test with matching criteria
|
|
const matchingPath = routeMatchesPath(complexRoute, '/api/v2/users');
|
|
expect(matchingPath).toBeTrue();
|
|
|
|
const matchingHeaders = routeMatchesHeaders(complexRoute, {
|
|
'Content-Type': 'application/json',
|
|
'X-API-Key': 'valid-key',
|
|
'Accept': 'application/json'
|
|
});
|
|
expect(matchingHeaders).toBeTrue();
|
|
|
|
// Test with non-matching criteria
|
|
const nonMatchingPath = routeMatchesPath(complexRoute, '/api/v1/users');
|
|
expect(nonMatchingPath).toBeFalse();
|
|
|
|
const nonMatchingHeaders = routeMatchesHeaders(complexRoute, {
|
|
'Content-Type': 'application/json',
|
|
'X-API-Key': 'invalid-key'
|
|
});
|
|
expect(nonMatchingHeaders).toBeFalse();
|
|
});
|
|
|
|
tap.test('Edge Case - Port Range Matching', async () => {
|
|
// Create route with port range matching
|
|
const portRangeRoute: IRouteConfig = {
|
|
match: {
|
|
domains: 'example.com',
|
|
ports: [{ from: 8000, to: 9000 }]
|
|
},
|
|
action: {
|
|
type: 'forward',
|
|
target: {
|
|
host: 'backend',
|
|
port: 3000
|
|
}
|
|
},
|
|
name: 'Port Range Route'
|
|
};
|
|
|
|
// Test with ports in the range
|
|
expect(routeMatchesPort(portRangeRoute, 8000)).toBeTrue(); // Lower bound
|
|
expect(routeMatchesPort(portRangeRoute, 8500)).toBeTrue(); // Middle
|
|
expect(routeMatchesPort(portRangeRoute, 9000)).toBeTrue(); // Upper bound
|
|
|
|
// Test with ports outside the range
|
|
expect(routeMatchesPort(portRangeRoute, 7999)).toBeFalse(); // Just below
|
|
expect(routeMatchesPort(portRangeRoute, 9001)).toBeFalse(); // Just above
|
|
|
|
// Test with multiple port ranges
|
|
const multiRangeRoute: IRouteConfig = {
|
|
match: {
|
|
domains: 'example.com',
|
|
ports: [
|
|
{ from: 80, to: 90 },
|
|
{ from: 8000, to: 9000 }
|
|
]
|
|
},
|
|
action: {
|
|
type: 'forward',
|
|
target: {
|
|
host: 'backend',
|
|
port: 3000
|
|
}
|
|
},
|
|
name: 'Multi Range Route'
|
|
};
|
|
|
|
expect(routeMatchesPort(multiRangeRoute, 85)).toBeTrue();
|
|
expect(routeMatchesPort(multiRangeRoute, 8500)).toBeTrue();
|
|
expect(routeMatchesPort(multiRangeRoute, 100)).toBeFalse();
|
|
});
|
|
|
|
// --------------------------------- Wildcard Domain Tests ---------------------------------
|
|
|
|
tap.test('Wildcard Domain Handling', async () => {
|
|
// Create routes with different wildcard patterns
|
|
const simpleDomainRoute = createHttpRoute('example.com', { host: 'server1', port: 3000 });
|
|
const wildcardSubdomainRoute = createHttpRoute('*.example.com', { host: 'server2', port: 3001 });
|
|
const specificSubdomainRoute = createHttpRoute('api.example.com', { host: 'server3', port: 3002 });
|
|
|
|
// Set explicit priorities to ensure deterministic matching
|
|
specificSubdomainRoute.priority = 200; // Highest priority for specific domain
|
|
wildcardSubdomainRoute.priority = 100; // Medium priority for wildcard
|
|
simpleDomainRoute.priority = 50; // Lowest priority for generic domain
|
|
|
|
const routes = [simpleDomainRoute, wildcardSubdomainRoute, specificSubdomainRoute];
|
|
|
|
// Test exact domain match
|
|
expect(routeMatchesDomain(simpleDomainRoute, 'example.com')).toBeTrue();
|
|
expect(routeMatchesDomain(simpleDomainRoute, 'sub.example.com')).toBeFalse();
|
|
|
|
// Test wildcard subdomain match
|
|
expect(routeMatchesDomain(wildcardSubdomainRoute, 'any.example.com')).toBeTrue();
|
|
expect(routeMatchesDomain(wildcardSubdomainRoute, 'nested.sub.example.com')).toBeTrue();
|
|
expect(routeMatchesDomain(wildcardSubdomainRoute, 'example.com')).toBeFalse();
|
|
|
|
// Test specific subdomain match
|
|
expect(routeMatchesDomain(specificSubdomainRoute, 'api.example.com')).toBeTrue();
|
|
expect(routeMatchesDomain(specificSubdomainRoute, 'other.example.com')).toBeFalse();
|
|
expect(routeMatchesDomain(specificSubdomainRoute, 'sub.api.example.com')).toBeFalse();
|
|
|
|
// Test finding best match when multiple domains match
|
|
const specificSubdomainRequest = { domain: 'api.example.com', port: 80 };
|
|
const bestSpecificMatch = findBestMatchingRoute(routes, specificSubdomainRequest);
|
|
expect(bestSpecificMatch).not.toBeUndefined();
|
|
if (bestSpecificMatch) {
|
|
// Find which route was matched
|
|
const matchedPort = bestSpecificMatch.action.target.port;
|
|
console.log(`Matched route with port: ${matchedPort}`);
|
|
|
|
// Verify it's the specific subdomain route (with highest priority)
|
|
expect(bestSpecificMatch.priority).toEqual(200);
|
|
}
|
|
|
|
// Test with a subdomain that matches wildcard but not specific
|
|
const otherSubdomainRequest = { domain: 'other.example.com', port: 80 };
|
|
const bestWildcardMatch = findBestMatchingRoute(routes, otherSubdomainRequest);
|
|
expect(bestWildcardMatch).not.toBeUndefined();
|
|
if (bestWildcardMatch) {
|
|
// Find which route was matched
|
|
const matchedPort = bestWildcardMatch.action.target.port;
|
|
console.log(`Matched route with port: ${matchedPort}`);
|
|
|
|
// Verify it's the wildcard subdomain route (with medium priority)
|
|
expect(bestWildcardMatch.priority).toEqual(100);
|
|
}
|
|
});
|
|
|
|
// --------------------------------- Integration Tests ---------------------------------
|
|
|
|
tap.test('Route Integration - Combining Multiple Route Types', async () => {
|
|
// Create a comprehensive set of routes for a full application
|
|
const routes: IRouteConfig[] = [
|
|
// Main website with HTTPS and HTTP redirect
|
|
...createCompleteHttpsServer('example.com', { host: 'web-server', port: 8080 }, {
|
|
certificate: 'auto'
|
|
}),
|
|
|
|
// API endpoints
|
|
createApiRoute('api.example.com', '/v1', { host: 'api-server', port: 3000 }, {
|
|
useTls: true,
|
|
certificate: 'auto',
|
|
addCorsHeaders: true
|
|
}),
|
|
|
|
// WebSocket for real-time updates
|
|
createWebSocketRoute('ws.example.com', '/live', { host: 'websocket-server', port: 5000 }, {
|
|
useTls: true,
|
|
certificate: 'auto'
|
|
}),
|
|
|
|
// Static assets
|
|
createStaticFileRoute('static.example.com', '/var/www/assets', {
|
|
serveOnHttps: true,
|
|
certificate: 'auto'
|
|
}),
|
|
|
|
// Legacy system with passthrough
|
|
createHttpsPassthroughRoute('legacy.example.com', { host: 'legacy-server', port: 443 })
|
|
];
|
|
|
|
// Validate all routes
|
|
const validationResult = validateRoutes(routes);
|
|
expect(validationResult.valid).toBeTrue();
|
|
expect(validationResult.errors.length).toEqual(0);
|
|
|
|
// Test route matching for different endpoints
|
|
|
|
// Web server (HTTPS)
|
|
const webServerMatch = findBestMatchingRoute(routes, { domain: 'example.com', port: 443 });
|
|
expect(webServerMatch).not.toBeUndefined();
|
|
if (webServerMatch) {
|
|
expect(webServerMatch.action.type).toEqual('forward');
|
|
expect(webServerMatch.action.target.host).toEqual('web-server');
|
|
}
|
|
|
|
// Web server (HTTP redirect)
|
|
const webRedirectMatch = findBestMatchingRoute(routes, { domain: 'example.com', port: 80 });
|
|
expect(webRedirectMatch).not.toBeUndefined();
|
|
if (webRedirectMatch) {
|
|
expect(webRedirectMatch.action.type).toEqual('redirect');
|
|
}
|
|
|
|
// API server
|
|
const apiMatch = findBestMatchingRoute(routes, {
|
|
domain: 'api.example.com',
|
|
port: 443,
|
|
path: '/v1/users'
|
|
});
|
|
expect(apiMatch).not.toBeUndefined();
|
|
if (apiMatch) {
|
|
expect(apiMatch.action.type).toEqual('forward');
|
|
expect(apiMatch.action.target.host).toEqual('api-server');
|
|
}
|
|
|
|
// WebSocket server
|
|
const wsMatch = findBestMatchingRoute(routes, {
|
|
domain: 'ws.example.com',
|
|
port: 443,
|
|
path: '/live'
|
|
});
|
|
expect(wsMatch).not.toBeUndefined();
|
|
if (wsMatch) {
|
|
expect(wsMatch.action.type).toEqual('forward');
|
|
expect(wsMatch.action.target.host).toEqual('websocket-server');
|
|
expect(wsMatch.action.websocket?.enabled).toBeTrue();
|
|
}
|
|
|
|
// Static assets
|
|
const staticMatch = findBestMatchingRoute(routes, {
|
|
domain: 'static.example.com',
|
|
port: 443
|
|
});
|
|
expect(staticMatch).not.toBeUndefined();
|
|
if (staticMatch) {
|
|
expect(staticMatch.action.type).toEqual('static');
|
|
expect(staticMatch.action.static.root).toEqual('/var/www/assets');
|
|
}
|
|
|
|
// Legacy system
|
|
const legacyMatch = findBestMatchingRoute(routes, {
|
|
domain: 'legacy.example.com',
|
|
port: 443
|
|
});
|
|
expect(legacyMatch).not.toBeUndefined();
|
|
if (legacyMatch) {
|
|
expect(legacyMatch.action.type).toEqual('forward');
|
|
expect(legacyMatch.action.tls?.mode).toEqual('passthrough');
|
|
}
|
|
});
|
|
|
|
export default tap.start(); |