131 lines
4.0 KiB
TypeScript
131 lines
4.0 KiB
TypeScript
![]() |
import { tap, expect } from '@git.zone/tstest/tapbundle';
|
||
|
|
||
|
tap.test('memory leak fixes - unit tests', async () => {
|
||
|
console.log('\n=== Testing MetricsCollector memory management ===');
|
||
|
|
||
|
// Import and test MetricsCollector directly
|
||
|
const { MetricsCollector } = await import('../ts/proxies/smart-proxy/metrics-collector.js');
|
||
|
|
||
|
// Create a mock SmartProxy with minimal required properties
|
||
|
const mockProxy = {
|
||
|
connectionManager: {
|
||
|
getConnectionCount: () => 0,
|
||
|
getConnections: () => new Map(),
|
||
|
getTerminationStats: () => ({ incoming: {} })
|
||
|
},
|
||
|
routeConnectionHandler: {
|
||
|
newConnectionSubject: {
|
||
|
subscribe: () => ({ unsubscribe: () => {} })
|
||
|
}
|
||
|
},
|
||
|
settings: {}
|
||
|
};
|
||
|
|
||
|
const collector = new MetricsCollector(mockProxy as any);
|
||
|
collector.start();
|
||
|
|
||
|
// Test timestamp cleanup
|
||
|
console.log('Testing requestTimestamps cleanup...');
|
||
|
|
||
|
// Add 6000 timestamps
|
||
|
for (let i = 0; i < 6000; i++) {
|
||
|
collector.recordRequest();
|
||
|
}
|
||
|
|
||
|
// Access private property for testing
|
||
|
let timestamps = (collector as any).requestTimestamps;
|
||
|
console.log(`Timestamps after 6000 requests: ${timestamps.length}`);
|
||
|
|
||
|
// Force one more request to trigger cleanup
|
||
|
collector.recordRequest();
|
||
|
timestamps = (collector as any).requestTimestamps;
|
||
|
console.log(`Timestamps after cleanup trigger: ${timestamps.length}`);
|
||
|
|
||
|
// Now check the RPS window - all timestamps are within 1 minute so they won't be cleaned
|
||
|
const now = Date.now();
|
||
|
const oldestTimestamp = Math.min(...timestamps);
|
||
|
const windowAge = now - oldestTimestamp;
|
||
|
console.log(`Window age: ${windowAge}ms (should be < 60000ms for all to be kept)`);
|
||
|
|
||
|
// Since all timestamps are recent (within RPS window), they won't be cleaned by window
|
||
|
// But the array size should still be limited
|
||
|
console.log(`MAX_TIMESTAMPS: ${(collector as any).MAX_TIMESTAMPS}`);
|
||
|
|
||
|
// The issue is our rapid-fire test - all timestamps are within the window
|
||
|
// Let's test with older timestamps
|
||
|
console.log('\nTesting with mixed old/new timestamps...');
|
||
|
(collector as any).requestTimestamps = [];
|
||
|
|
||
|
// Add some old timestamps (older than window)
|
||
|
const oldTime = now - 70000; // 70 seconds ago
|
||
|
for (let i = 0; i < 3000; i++) {
|
||
|
(collector as any).requestTimestamps.push(oldTime);
|
||
|
}
|
||
|
|
||
|
// Add new timestamps to exceed limit
|
||
|
for (let i = 0; i < 3000; i++) {
|
||
|
collector.recordRequest();
|
||
|
}
|
||
|
|
||
|
timestamps = (collector as any).requestTimestamps;
|
||
|
console.log(`After mixed timestamps: ${timestamps.length} (old ones should be cleaned)`);
|
||
|
|
||
|
// Old timestamps should be cleaned when we exceed MAX_TIMESTAMPS
|
||
|
expect(timestamps.length).toBeLessThanOrEqual(5000);
|
||
|
|
||
|
// Stop the collector
|
||
|
collector.stop();
|
||
|
|
||
|
console.log('\n=== Testing FunctionCache cleanup ===');
|
||
|
|
||
|
const { FunctionCache } = await import('../ts/proxies/http-proxy/function-cache.js');
|
||
|
|
||
|
const mockLogger = {
|
||
|
debug: () => {},
|
||
|
info: () => {},
|
||
|
warn: () => {},
|
||
|
error: () => {}
|
||
|
};
|
||
|
|
||
|
const cache = new FunctionCache(mockLogger as any);
|
||
|
|
||
|
// Check that cleanup interval was set
|
||
|
expect((cache as any).cleanupInterval).toBeTruthy();
|
||
|
|
||
|
// Test destroy method
|
||
|
cache.destroy();
|
||
|
|
||
|
// Cleanup interval should be cleared
|
||
|
expect((cache as any).cleanupInterval).toBeNull();
|
||
|
|
||
|
console.log('✓ FunctionCache properly cleans up interval');
|
||
|
|
||
|
console.log('\n=== Testing RequestHandler cleanup ===');
|
||
|
|
||
|
const { RequestHandler } = await import('../ts/proxies/http-proxy/request-handler.js');
|
||
|
|
||
|
const mockConnectionPool = {
|
||
|
getConnection: () => null,
|
||
|
releaseConnection: () => {}
|
||
|
};
|
||
|
|
||
|
const handler = new RequestHandler(
|
||
|
{ logLevel: 'error' },
|
||
|
mockConnectionPool as any
|
||
|
);
|
||
|
|
||
|
// Check that cleanup interval was set
|
||
|
expect((handler as any).rateLimitCleanupInterval).toBeTruthy();
|
||
|
|
||
|
// Test destroy method
|
||
|
handler.destroy();
|
||
|
|
||
|
// Cleanup interval should be cleared
|
||
|
expect((handler as any).rateLimitCleanupInterval).toBeNull();
|
||
|
|
||
|
console.log('✓ RequestHandler properly cleans up interval');
|
||
|
|
||
|
console.log('\n✅ All memory leak fixes verified!');
|
||
|
});
|
||
|
|
||
|
tap.start();
|