From c7722c30f3bd8f941db38f9d1bcca863fe688f25 Mon Sep 17 00:00:00 2001 From: Juergen Kunz Date: Thu, 19 Feb 2026 09:12:50 +0000 Subject: [PATCH] fix(throughput): add tests for per-IP connection tracking and throughput history; assert per-IP eviction after connection close to prevent memory leak --- changelog.md | 8 ++++++++ test/test.throughput.ts | 38 ++++++++++++++++++++++---------------- ts/00_commitinfo_data.ts | 2 +- 3 files changed, 31 insertions(+), 17 deletions(-) diff --git a/changelog.md b/changelog.md index 05d1968..14ad64f 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,13 @@ # Changelog +## 2026-02-19 - 25.7.6 - fix(throughput) +add tests for per-IP connection tracking and throughput history; assert per-IP eviction after connection close to prevent memory leak + +- Adds runtime assertions for per-IP TCP connection tracking (m.connections.byIP) while a connection is active +- Adds checks for throughput history (m.throughput.history) to ensure history length and timestamps are recorded +- Asserts that per-IP tracking data is evicted after connection close (byIP.size === 0) to verify memory leak fix +- Reorders test checks so per-IP and history metrics are validated during the active connection and totals are validated after close + ## 2026-02-19 - 25.7.5 - fix(rustproxy) prune stale per-route metrics, add per-route rate limiter caching and regex cache, and improve connection tracking cleanup to prevent memory growth diff --git a/test/test.throughput.ts b/test/test.throughput.ts index 683c524..c7d7be0 100644 --- a/test/test.throughput.ts +++ b/test/test.throughput.ts @@ -151,11 +151,28 @@ tap.test('TCP forward - real-time byte tracking', async (tools) => { console.log(`TCP forward (during) — recent throughput: in=${tpDuring.in}, out=${tpDuring.out}`); expect(tpDuring.in + tpDuring.out).toBeGreaterThan(0); + // ── v25.2.0: Per-IP tracking (TCP connections) ── + // Must check WHILE connection is active — per-IP data is evicted on last close + const byIP = mDuring.connections.byIP(); + console.log('TCP forward — connections byIP:', Array.from(byIP.entries())); + expect(byIP.size).toBeGreaterThan(0); + + const topIPs = mDuring.connections.topIPs(10); + console.log('TCP forward — topIPs:', topIPs); + expect(topIPs.length).toBeGreaterThan(0); + expect(topIPs[0].ip).toBeTruthy(); + + // ── v25.2.0: Throughput history ── + const history = mDuring.throughput.history(10); + console.log('TCP forward — throughput history length:', history.length); + expect(history.length).toBeGreaterThan(0); + expect(history[0].timestamp).toBeGreaterThan(0); + // Close connection client.destroy(); await tools.delayFor(500); - // Final check + // Final check — totals persist even after connection close await pollMetrics(proxy); const m = proxy.getMetrics(); const bytesIn = m.totals.bytesIn(); @@ -168,21 +185,10 @@ tap.test('TCP forward - real-time byte tracking', async (tools) => { const byRoute = m.throughput.byRoute(); console.log('TCP forward — throughput byRoute:', Array.from(byRoute.entries())); - // ── v25.2.0: Per-IP tracking (TCP connections) ── - const byIP = m.connections.byIP(); - console.log('TCP forward — connections byIP:', Array.from(byIP.entries())); - expect(byIP.size).toBeGreaterThan(0); - - const topIPs = m.connections.topIPs(10); - console.log('TCP forward — topIPs:', topIPs); - expect(topIPs.length).toBeGreaterThan(0); - expect(topIPs[0].ip).toBeTruthy(); - - // ── v25.2.0: Throughput history ── - const history = m.throughput.history(10); - console.log('TCP forward — throughput history length:', history.length); - expect(history.length).toBeGreaterThan(0); - expect(history[0].timestamp).toBeGreaterThan(0); + // After close, per-IP data should be evicted (memory leak fix) + const byIPAfter = m.connections.byIP(); + console.log('TCP forward — connections byIP after close:', Array.from(byIPAfter.entries())); + expect(byIPAfter.size).toEqual(0); await proxy.stop(); await tools.delayFor(200); diff --git a/ts/00_commitinfo_data.ts b/ts/00_commitinfo_data.ts index 81af1f3..bb4d9c3 100644 --- a/ts/00_commitinfo_data.ts +++ b/ts/00_commitinfo_data.ts @@ -3,6 +3,6 @@ */ export const commitinfo = { name: '@push.rocks/smartproxy', - version: '25.7.5', + version: '25.7.6', description: 'A powerful proxy package with unified route-based configuration for high traffic management. Features include SSL/TLS support, flexible routing patterns, WebSocket handling, advanced security options, and automatic ACME certificate management.' }