change to route based approach
This commit is contained in:
181
test/test.route-config.ts
Normal file
181
test/test.route-config.ts
Normal file
@ -0,0 +1,181 @@
|
||||
/**
|
||||
* Tests for the new route-based configuration system
|
||||
*/
|
||||
import { expect, tap } from '@push.rocks/tapbundle';
|
||||
|
||||
// Import from core modules
|
||||
import {
|
||||
SmartProxy,
|
||||
createHttpRoute,
|
||||
createHttpsRoute,
|
||||
createPassthroughRoute,
|
||||
createRedirectRoute,
|
||||
createHttpToHttpsRedirect,
|
||||
createHttpsServer,
|
||||
createLoadBalancerRoute
|
||||
} from '../ts/proxies/smart-proxy/index.js';
|
||||
|
||||
// Import test helpers
|
||||
import { getCertificate } from './helpers/certificates.js';
|
||||
|
||||
tap.test('Routes: Should create basic HTTP route', async () => {
|
||||
// Create a simple HTTP route
|
||||
const httpRoute = createHttpRoute({
|
||||
ports: 8080,
|
||||
domains: 'example.com',
|
||||
target: {
|
||||
host: 'localhost',
|
||||
port: 3000
|
||||
},
|
||||
name: 'Basic HTTP Route'
|
||||
});
|
||||
|
||||
// Validate the route configuration
|
||||
expect(httpRoute.match.ports).to.equal(8080);
|
||||
expect(httpRoute.match.domains).to.equal('example.com');
|
||||
expect(httpRoute.action.type).to.equal('forward');
|
||||
expect(httpRoute.action.target?.host).to.equal('localhost');
|
||||
expect(httpRoute.action.target?.port).to.equal(3000);
|
||||
expect(httpRoute.name).to.equal('Basic HTTP Route');
|
||||
});
|
||||
|
||||
tap.test('Routes: Should create HTTPS route with TLS termination', async () => {
|
||||
// Create an HTTPS route with TLS termination
|
||||
const httpsRoute = createHttpsRoute({
|
||||
domains: 'secure.example.com',
|
||||
target: {
|
||||
host: 'localhost',
|
||||
port: 8080
|
||||
},
|
||||
certificate: 'auto',
|
||||
name: 'HTTPS Route'
|
||||
});
|
||||
|
||||
// Validate the route configuration
|
||||
expect(httpsRoute.match.ports).to.equal(443); // Default HTTPS port
|
||||
expect(httpsRoute.match.domains).to.equal('secure.example.com');
|
||||
expect(httpsRoute.action.type).to.equal('forward');
|
||||
expect(httpsRoute.action.tls?.mode).to.equal('terminate');
|
||||
expect(httpsRoute.action.tls?.certificate).to.equal('auto');
|
||||
expect(httpsRoute.action.target?.host).to.equal('localhost');
|
||||
expect(httpsRoute.action.target?.port).to.equal(8080);
|
||||
expect(httpsRoute.name).to.equal('HTTPS Route');
|
||||
});
|
||||
|
||||
tap.test('Routes: Should create HTTP to HTTPS redirect', async () => {
|
||||
// Create an HTTP to HTTPS redirect
|
||||
const redirectRoute = createHttpToHttpsRedirect({
|
||||
domains: 'example.com',
|
||||
statusCode: 301
|
||||
});
|
||||
|
||||
// Validate the route configuration
|
||||
expect(redirectRoute.match.ports).to.equal(80);
|
||||
expect(redirectRoute.match.domains).to.equal('example.com');
|
||||
expect(redirectRoute.action.type).to.equal('redirect');
|
||||
expect(redirectRoute.action.redirect?.to).to.equal('https://{domain}{path}');
|
||||
expect(redirectRoute.action.redirect?.status).to.equal(301);
|
||||
});
|
||||
|
||||
tap.test('Routes: Should create complete HTTPS server with redirects', async () => {
|
||||
// Create a complete HTTPS server setup
|
||||
const routes = createHttpsServer({
|
||||
domains: 'example.com',
|
||||
target: {
|
||||
host: 'localhost',
|
||||
port: 8080
|
||||
},
|
||||
certificate: 'auto',
|
||||
addHttpRedirect: true
|
||||
});
|
||||
|
||||
// Validate that we got two routes (HTTPS route and HTTP redirect)
|
||||
expect(routes.length).to.equal(2);
|
||||
|
||||
// Validate HTTPS route
|
||||
const httpsRoute = routes[0];
|
||||
expect(httpsRoute.match.ports).to.equal(443);
|
||||
expect(httpsRoute.match.domains).to.equal('example.com');
|
||||
expect(httpsRoute.action.type).to.equal('forward');
|
||||
expect(httpsRoute.action.tls?.mode).to.equal('terminate');
|
||||
|
||||
// Validate HTTP redirect route
|
||||
const redirectRoute = routes[1];
|
||||
expect(redirectRoute.match.ports).to.equal(80);
|
||||
expect(redirectRoute.action.type).to.equal('redirect');
|
||||
expect(redirectRoute.action.redirect?.to).to.equal('https://{domain}{path}');
|
||||
});
|
||||
|
||||
tap.test('Routes: Should create load balancer route', async () => {
|
||||
// Create a load balancer route
|
||||
const lbRoute = createLoadBalancerRoute({
|
||||
domains: 'app.example.com',
|
||||
targets: ['10.0.0.1', '10.0.0.2', '10.0.0.3'],
|
||||
targetPort: 8080,
|
||||
tlsMode: 'terminate',
|
||||
certificate: 'auto',
|
||||
name: 'Load Balanced Route'
|
||||
});
|
||||
|
||||
// Validate the route configuration
|
||||
expect(lbRoute.match.domains).to.equal('app.example.com');
|
||||
expect(lbRoute.action.type).to.equal('forward');
|
||||
expect(Array.isArray(lbRoute.action.target?.host)).to.equal(true);
|
||||
expect((lbRoute.action.target?.host as string[]).length).to.equal(3);
|
||||
expect((lbRoute.action.target?.host as string[])[0]).to.equal('10.0.0.1');
|
||||
expect(lbRoute.action.target?.port).to.equal(8080);
|
||||
expect(lbRoute.action.tls?.mode).to.equal('terminate');
|
||||
});
|
||||
|
||||
tap.test('SmartProxy: Should create instance with route-based config', async () => {
|
||||
// Create TLS certificates for testing
|
||||
const cert = await getCertificate();
|
||||
|
||||
// Create a SmartProxy instance with route-based configuration
|
||||
const proxy = new SmartProxy({
|
||||
routes: [
|
||||
createHttpRoute({
|
||||
ports: 8080,
|
||||
domains: 'example.com',
|
||||
target: {
|
||||
host: 'localhost',
|
||||
port: 3000
|
||||
},
|
||||
name: 'HTTP Route'
|
||||
}),
|
||||
createHttpsRoute({
|
||||
domains: 'secure.example.com',
|
||||
target: {
|
||||
host: 'localhost',
|
||||
port: 8443
|
||||
},
|
||||
certificate: {
|
||||
key: cert.key,
|
||||
cert: cert.cert
|
||||
},
|
||||
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(proxy).to.be.an('object');
|
||||
expect(proxy.start).to.be.a('function');
|
||||
expect(proxy.stop).to.be.a('function');
|
||||
});
|
||||
|
||||
export default tap.start();
|
@ -66,13 +66,25 @@ function createTestClient(port: number, data: string): Promise<string> {
|
||||
tap.test('setup port proxy test environment', async () => {
|
||||
testServer = await createTestServer(TEST_SERVER_PORT);
|
||||
smartProxy = new SmartProxy({
|
||||
fromPort: PROXY_PORT,
|
||||
toPort: TEST_SERVER_PORT,
|
||||
targetIP: 'localhost',
|
||||
domainConfigs: [],
|
||||
sniEnabled: false,
|
||||
defaultAllowedIPs: ['127.0.0.1'],
|
||||
globalPortRanges: []
|
||||
routes: [
|
||||
{
|
||||
match: {
|
||||
ports: PROXY_PORT
|
||||
},
|
||||
action: {
|
||||
type: 'forward',
|
||||
target: {
|
||||
host: 'localhost',
|
||||
port: TEST_SERVER_PORT
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
defaults: {
|
||||
security: {
|
||||
allowedIPs: ['127.0.0.1']
|
||||
}
|
||||
}
|
||||
});
|
||||
allProxies.push(smartProxy); // Track this proxy
|
||||
});
|
||||
@ -92,13 +104,25 @@ tap.test('should forward TCP connections and data to localhost', async () => {
|
||||
// Test proxy with a custom target host.
|
||||
tap.test('should forward TCP connections to custom host', async () => {
|
||||
const customHostProxy = new SmartProxy({
|
||||
fromPort: PROXY_PORT + 1,
|
||||
toPort: TEST_SERVER_PORT,
|
||||
targetIP: '127.0.0.1',
|
||||
domainConfigs: [],
|
||||
sniEnabled: false,
|
||||
defaultAllowedIPs: ['127.0.0.1'],
|
||||
globalPortRanges: []
|
||||
routes: [
|
||||
{
|
||||
match: {
|
||||
ports: PROXY_PORT + 1
|
||||
},
|
||||
action: {
|
||||
type: 'forward',
|
||||
target: {
|
||||
host: '127.0.0.1',
|
||||
port: TEST_SERVER_PORT
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
defaults: {
|
||||
security: {
|
||||
allowedIPs: ['127.0.0.1']
|
||||
}
|
||||
}
|
||||
});
|
||||
allProxies.push(customHostProxy); // Track this proxy
|
||||
|
||||
@ -125,14 +149,25 @@ tap.test('should forward connections to custom IP', async () => {
|
||||
// We're simulating routing to a different IP by using a different port
|
||||
// This tests the core functionality without requiring multiple IPs
|
||||
const domainProxy = new SmartProxy({
|
||||
fromPort: forcedProxyPort, // 4003 - Listen on this port
|
||||
toPort: targetServerPort, // 4200 - Forward to this port
|
||||
targetIP: '127.0.0.1', // Always use localhost (works in Docker)
|
||||
domainConfigs: [], // No domain configs to confuse things
|
||||
sniEnabled: false,
|
||||
defaultAllowedIPs: ['127.0.0.1', '::ffff:127.0.0.1'], // Allow localhost
|
||||
// We'll test the functionality WITHOUT port ranges this time
|
||||
globalPortRanges: []
|
||||
routes: [
|
||||
{
|
||||
match: {
|
||||
ports: forcedProxyPort
|
||||
},
|
||||
action: {
|
||||
type: 'forward',
|
||||
target: {
|
||||
host: '127.0.0.1',
|
||||
port: targetServerPort
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
defaults: {
|
||||
security: {
|
||||
allowedIPs: ['127.0.0.1', '::ffff:127.0.0.1']
|
||||
}
|
||||
}
|
||||
});
|
||||
allProxies.push(domainProxy); // Track this proxy
|
||||
|
||||
@ -208,22 +243,46 @@ tap.test('should stop port proxy', async () => {
|
||||
tap.test('should support optional source IP preservation in chained proxies', async () => {
|
||||
// Chained proxies without IP preservation.
|
||||
const firstProxyDefault = new SmartProxy({
|
||||
fromPort: PROXY_PORT + 4,
|
||||
toPort: PROXY_PORT + 5,
|
||||
targetIP: 'localhost',
|
||||
domainConfigs: [],
|
||||
sniEnabled: false,
|
||||
defaultAllowedIPs: ['127.0.0.1', '::ffff:127.0.0.1'],
|
||||
globalPortRanges: []
|
||||
routes: [
|
||||
{
|
||||
match: {
|
||||
ports: PROXY_PORT + 4
|
||||
},
|
||||
action: {
|
||||
type: 'forward',
|
||||
target: {
|
||||
host: 'localhost',
|
||||
port: PROXY_PORT + 5
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
defaults: {
|
||||
security: {
|
||||
allowedIPs: ['127.0.0.1', '::ffff:127.0.0.1']
|
||||
}
|
||||
}
|
||||
});
|
||||
const secondProxyDefault = new SmartProxy({
|
||||
fromPort: PROXY_PORT + 5,
|
||||
toPort: TEST_SERVER_PORT,
|
||||
targetIP: 'localhost',
|
||||
domainConfigs: [],
|
||||
sniEnabled: false,
|
||||
defaultAllowedIPs: ['127.0.0.1', '::ffff:127.0.0.1'],
|
||||
globalPortRanges: []
|
||||
routes: [
|
||||
{
|
||||
match: {
|
||||
ports: PROXY_PORT + 5
|
||||
},
|
||||
action: {
|
||||
type: 'forward',
|
||||
target: {
|
||||
host: 'localhost',
|
||||
port: TEST_SERVER_PORT
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
defaults: {
|
||||
security: {
|
||||
allowedIPs: ['127.0.0.1', '::ffff:127.0.0.1']
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
allProxies.push(firstProxyDefault, secondProxyDefault); // Track these proxies
|
||||
@ -243,24 +302,50 @@ tap.test('should support optional source IP preservation in chained proxies', as
|
||||
|
||||
// Chained proxies with IP preservation.
|
||||
const firstProxyPreserved = new SmartProxy({
|
||||
fromPort: PROXY_PORT + 6,
|
||||
toPort: PROXY_PORT + 7,
|
||||
targetIP: 'localhost',
|
||||
domainConfigs: [],
|
||||
sniEnabled: false,
|
||||
defaultAllowedIPs: ['127.0.0.1'],
|
||||
preserveSourceIP: true,
|
||||
globalPortRanges: []
|
||||
routes: [
|
||||
{
|
||||
match: {
|
||||
ports: PROXY_PORT + 6
|
||||
},
|
||||
action: {
|
||||
type: 'forward',
|
||||
target: {
|
||||
host: 'localhost',
|
||||
port: PROXY_PORT + 7
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
defaults: {
|
||||
security: {
|
||||
allowedIPs: ['127.0.0.1']
|
||||
},
|
||||
preserveSourceIP: true
|
||||
},
|
||||
preserveSourceIP: true
|
||||
});
|
||||
const secondProxyPreserved = new SmartProxy({
|
||||
fromPort: PROXY_PORT + 7,
|
||||
toPort: TEST_SERVER_PORT,
|
||||
targetIP: 'localhost',
|
||||
domainConfigs: [],
|
||||
sniEnabled: false,
|
||||
defaultAllowedIPs: ['127.0.0.1'],
|
||||
preserveSourceIP: true,
|
||||
globalPortRanges: []
|
||||
routes: [
|
||||
{
|
||||
match: {
|
||||
ports: PROXY_PORT + 7
|
||||
},
|
||||
action: {
|
||||
type: 'forward',
|
||||
target: {
|
||||
host: 'localhost',
|
||||
port: TEST_SERVER_PORT
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
defaults: {
|
||||
security: {
|
||||
allowedIPs: ['127.0.0.1']
|
||||
},
|
||||
preserveSourceIP: true
|
||||
},
|
||||
preserveSourceIP: true
|
||||
});
|
||||
|
||||
allProxies.push(firstProxyPreserved, secondProxyPreserved); // Track these proxies
|
||||
|
Reference in New Issue
Block a user