fix(rustproxy): Use cooperative cancellation for background tasks, prune stale caches and metric entries, and switch tests to dynamic port allocation to avoid port conflicts

This commit is contained in:
2026-02-24 20:56:37 +00:00
parent 755c81c042
commit 33cd5330c4
24 changed files with 535 additions and 560 deletions
+26 -15
View File
@@ -1,11 +1,19 @@
import { expect, tap } from '@git.zone/tstest/tapbundle';
import * as net from 'net';
import { SmartProxy } from '../ts/proxies/smart-proxy/index.js';
import { findFreePorts, assertPortsFree } from './helpers/port-allocator.js';
let testServer: net.Server;
let smartProxy: SmartProxy;
const TEST_SERVER_PORT = 47770;
const PROXY_PORT = 47771;
let TEST_SERVER_PORT: number;
let PROXY_PORT: number;
let CUSTOM_HOST_PORT: number;
let CUSTOM_IP_PROXY_PORT: number;
let CUSTOM_IP_TARGET_PORT: number;
let CHAIN_DEFAULT_1_PORT: number;
let CHAIN_DEFAULT_2_PORT: number;
let CHAIN_PRESERVED_1_PORT: number;
let CHAIN_PRESERVED_2_PORT: number;
const TEST_DATA = 'Hello through port proxy!';
// Track all created servers and proxies for proper cleanup
@@ -64,6 +72,7 @@ function createTestClient(port: number, data: string): Promise<string> {
// SETUP: Create a test server and a PortProxy instance.
tap.test('setup port proxy test environment', async () => {
[TEST_SERVER_PORT, PROXY_PORT, CUSTOM_HOST_PORT, CUSTOM_IP_PROXY_PORT, CUSTOM_IP_TARGET_PORT, CHAIN_DEFAULT_1_PORT, CHAIN_DEFAULT_2_PORT, CHAIN_PRESERVED_1_PORT, CHAIN_PRESERVED_2_PORT] = await findFreePorts(9);
testServer = await createTestServer(TEST_SERVER_PORT);
smartProxy = new SmartProxy({
routes: [
@@ -110,7 +119,7 @@ tap.test('should forward TCP connections to custom host', async () => {
{
name: 'custom-host-route',
match: {
ports: PROXY_PORT + 1
ports: CUSTOM_HOST_PORT
},
action: {
type: 'forward',
@@ -128,9 +137,9 @@ tap.test('should forward TCP connections to custom host', async () => {
}
});
allProxies.push(customHostProxy); // Track this proxy
await customHostProxy.start();
const response = await createTestClient(PROXY_PORT + 1, TEST_DATA);
const response = await createTestClient(CUSTOM_HOST_PORT, TEST_DATA);
expect(response).toEqual(`Echo: ${TEST_DATA}`);
await customHostProxy.stop();
@@ -143,8 +152,8 @@ tap.test('should forward TCP connections to custom host', async () => {
// Modified to work in Docker/CI environments without needing 127.0.0.2
tap.test('should forward connections to custom IP', async () => {
// Set up ports that are FAR apart to avoid any possible confusion
const forcedProxyPort = PROXY_PORT + 2; // 4003 - The port that our proxy listens on
const targetServerPort = TEST_SERVER_PORT + 200; // 4200 - Target test server on different port
const forcedProxyPort = CUSTOM_IP_PROXY_PORT;
const targetServerPort = CUSTOM_IP_TARGET_PORT;
// Create a test server listening on a unique port on 127.0.0.1 (works in all environments)
const testServer2 = await createTestServer(targetServerPort, '127.0.0.1');
@@ -252,13 +261,13 @@ tap.test('should support optional source IP preservation in chained proxies', as
{
name: 'first-proxy-default-route',
match: {
ports: PROXY_PORT + 4
ports: CHAIN_DEFAULT_1_PORT
},
action: {
type: 'forward',
targets: [{
host: 'localhost',
port: PROXY_PORT + 5
port: CHAIN_DEFAULT_2_PORT
}]
}
}
@@ -274,7 +283,7 @@ tap.test('should support optional source IP preservation in chained proxies', as
{
name: 'second-proxy-default-route',
match: {
ports: PROXY_PORT + 5
ports: CHAIN_DEFAULT_2_PORT
},
action: {
type: 'forward',
@@ -296,7 +305,7 @@ tap.test('should support optional source IP preservation in chained proxies', as
await secondProxyDefault.start();
await firstProxyDefault.start();
const response1 = await createTestClient(PROXY_PORT + 4, TEST_DATA);
const response1 = await createTestClient(CHAIN_DEFAULT_1_PORT, TEST_DATA);
expect(response1).toEqual(`Echo: ${TEST_DATA}`);
await firstProxyDefault.stop();
await secondProxyDefault.stop();
@@ -313,13 +322,13 @@ tap.test('should support optional source IP preservation in chained proxies', as
{
name: 'first-proxy-preserved-route',
match: {
ports: PROXY_PORT + 6
ports: CHAIN_PRESERVED_1_PORT
},
action: {
type: 'forward',
targets: [{
host: 'localhost',
port: PROXY_PORT + 7
port: CHAIN_PRESERVED_2_PORT
}]
}
}
@@ -337,7 +346,7 @@ tap.test('should support optional source IP preservation in chained proxies', as
{
name: 'second-proxy-preserved-route',
match: {
ports: PROXY_PORT + 7
ports: CHAIN_PRESERVED_2_PORT
},
action: {
type: 'forward',
@@ -361,7 +370,7 @@ tap.test('should support optional source IP preservation in chained proxies', as
await secondProxyPreserved.start();
await firstProxyPreserved.start();
const response2 = await createTestClient(PROXY_PORT + 6, TEST_DATA);
const response2 = await createTestClient(CHAIN_PRESERVED_1_PORT, TEST_DATA);
expect(response2).toEqual(`Echo: ${TEST_DATA}`);
await firstProxyPreserved.stop();
await secondProxyPreserved.stop();
@@ -446,6 +455,8 @@ tap.test('cleanup port proxy test environment', async () => {
// Verify all resources are cleaned up
expect(allProxies.length).toEqual(0);
expect(allServers.length).toEqual(0);
await assertPortsFree([TEST_SERVER_PORT, PROXY_PORT, CUSTOM_HOST_PORT, CUSTOM_IP_PROXY_PORT, CUSTOM_IP_TARGET_PORT, CHAIN_DEFAULT_1_PORT, CHAIN_DEFAULT_2_PORT, CHAIN_PRESERVED_1_PORT, CHAIN_PRESERVED_2_PORT]);
});
export default tap.start();