Skip to main content
Glama

Prompt Auto-Optimizer MCP

by sloth-wq
gc-optimizer.test.ts18.7 kB
/** * Comprehensive Tests for Garbage Collection Optimizer */ import { describe, test, expect, beforeEach, afterEach, vi } from 'vitest'; import { GarbageCollectionOptimizer, ObjectPool } from './gc-optimizer'; import { PerformanceTracker } from '../services/performance-tracker'; import { MemoryLeakDetector } from './memory-leak-detector'; describe('GarbageCollectionOptimizer', () => { let optimizer: GarbageCollectionOptimizer; let performanceTracker: PerformanceTracker; let memoryLeakDetector: MemoryLeakDetector; beforeEach(() => { performanceTracker = new PerformanceTracker(); memoryLeakDetector = new MemoryLeakDetector(); optimizer = new GarbageCollectionOptimizer(performanceTracker, memoryLeakDetector); }); afterEach(() => { optimizer.shutdown(); memoryLeakDetector.shutdown(); }); describe('Initialization', () => { test('should initialize with default balanced strategy', () => { expect(optimizer).toBeDefined(); const stats = optimizer.getOptimizationStatistics(); expect(stats.adaptiveTuning.enabled).toBe(true); }); test('should create default object pools', () => { const candidatesPool = optimizer.getObjectPool('candidates'); const trajectoryPool = optimizer.getObjectPool('trajectory-data'); const analysisPool = optimizer.getObjectPool('analysis-results'); expect(candidatesPool).toBeDefined(); expect(trajectoryPool).toBeDefined(); expect(analysisPool).toBeDefined(); }); }); describe('Strategy Management', () => { test('should switch to high-throughput strategy', async () => { const strategyChangedPromise = new Promise((resolve) => { optimizer.once('strategyChanged', resolve); }); optimizer.setOptimizationStrategy('high-throughput'); const event = await strategyChangedPromise; expect(event).toMatchObject({ workloadType: 'high-throughput', strategy: expect.objectContaining({ name: 'high-throughput' }) }); }); test('should switch to low-latency strategy', async () => { const strategyChangedPromise = new Promise((resolve) => { optimizer.once('strategyChanged', resolve); }); optimizer.setOptimizationStrategy('low-latency'); const event = await strategyChangedPromise; expect(event).toMatchObject({ workloadType: 'low-latency', strategy: expect.objectContaining({ name: 'low-latency', gcTuning: expect.objectContaining({ maxPauseTime: 10 }) }) }); }); test('should handle unknown strategy by using balanced', async () => { const strategyChangedPromise = new Promise((resolve) => { optimizer.once('strategyChanged', resolve); }); optimizer.setOptimizationStrategy('unknown-strategy'); const event = await strategyChangedPromise; expect(event).toMatchObject({ workloadType: 'unknown-strategy', strategy: expect.objectContaining({ name: 'balanced' }) }); }); }); describe('Object Pool Management', () => { test('should create custom object pool', () => { const pool = optimizer.createObjectPool({ name: 'test-pool', maxSize: 100, minSize: 10, factory: () => ({ value: 0 }), reset: (obj) => { obj.value = 0; }, evictionStrategy: 'lru', autoTune: true, }); expect(pool).toBeDefined(); expect(pool.config.name).toBe('test-pool'); expect(pool.config.maxSize).toBe(100); }); test('should emit pool events', async () => { const pool = optimizer.createObjectPool({ name: 'event-test-pool', maxSize: 5, minSize: 1, factory: () => ({ id: Math.random() }), evictionStrategy: 'fifo', autoTune: false, }); const hitPromise = new Promise((resolve) => { optimizer.once('poolHit', resolve); }); // Get and return an object to trigger hit const obj1 = pool.get(); pool.return(obj1); const obj2 = pool.get(); // Should be a hit const hitEvent = await hitPromise; expect(hitEvent).toMatchObject({ pool: 'event-test-pool', stats: expect.objectContaining({ hits: 1 }) }); }); }); describe('Forced Garbage Collection', () => { test('should perform forced GC and return metrics', async () => { const metrics = await optimizer.forceGarbageCollection('test'); expect(metrics).toMatchObject({ type: 'forced', triggerReason: 'test', timestamp: expect.any(Number), duration: expect.any(Number), heapBefore: expect.any(Number), heapAfter: expect.any(Number) }); }); test('should emit GC metrics event', async () => { const metricsPromise = new Promise((resolve) => { optimizer.once('gcMetrics', resolve); }); await optimizer.forceGarbageCollection('test-emit'); const metrics = await metricsPromise; expect(metrics).toMatchObject({ type: 'forced', triggerReason: 'test-emit' }); }); }); describe('Buffer Management', () => { test('should reuse buffers of same size', () => { const buffer1 = optimizer.getBuffer(1024); expect(buffer1.length).toBe(1024); // Return and get again optimizer.returnBuffer(buffer1); const buffer2 = optimizer.getBuffer(1024); // Should be reused (same underlying buffer) expect(buffer2.length).toBe(1024); }); test('should handle different buffer sizes', () => { const small = optimizer.getBuffer(512); const medium = optimizer.getBuffer(2048); const large = optimizer.getBuffer(8192); expect(small.length).toBe(512); expect(medium.length).toBe(2048); expect(large.length).toBe(8192); optimizer.returnBuffer(small); optimizer.returnBuffer(medium); optimizer.returnBuffer(large); }); }); describe('Memory Pressure Response', () => { test('should handle critical memory pressure', async () => { const handlerPromise = new Promise((resolve) => { optimizer.once('pressureHandlerExecuted', resolve); }); // Mock high memory usage const originalMemoryUsage = process.memoryUsage; process.memoryUsage = vi.fn().mockReturnValue({ rss: 1000000000, heapTotal: 500000000, heapUsed: 480000000, // 96% usage - critical external: 10000000, arrayBuffers: 0 }); // Trigger monitoring cycle await new Promise(resolve => setTimeout(resolve, 100)); process.memoryUsage = originalMemoryUsage; }); }); describe('Allocation Pattern Analysis', () => { test('should analyze allocation patterns', () => { // Generate some GC metrics optimizer['gcMetricsHistory'] = [ { timestamp: Date.now() - 10000, type: 'minor', duration: 5, heapBefore: 100000000, heapAfter: 80000000, heapReclaimed: 20000000, pauseTime: 5, efficiency: 0.2, triggerReason: 'auto' }, { timestamp: Date.now() - 5000, type: 'major', duration: 15, heapBefore: 120000000, heapAfter: 70000000, heapReclaimed: 50000000, pauseTime: 15, efficiency: 0.42, triggerReason: 'auto' } ]; const analysis = optimizer.analyzeAllocationPatterns(); expect(analysis).toMatchObject({ hotspots: expect.any(Array), patterns: expect.any(Array), recommendations: expect.any(Array) }); }); }); describe('Optimization Statistics', () => { test('should provide comprehensive statistics', () => { const stats = optimizer.getOptimizationStatistics(); expect(stats).toMatchObject({ gcMetrics: expect.objectContaining({ totalCollections: expect.any(Number), averageDuration: expect.any(Number), averageEfficiency: expect.any(Number), memoryReclaimed: expect.any(Number) }), objectPools: expect.any(Array), memoryPressure: expect.objectContaining({ currentLevel: expect.stringMatching(/^(low|medium|high|critical)$/), responseTime: expect.any(Number), handlersExecuted: expect.any(Number) }), bufferReuse: expect.objectContaining({ totalReuses: expect.any(Number), poolUtilization: expect.any(Array), memoryEfficiency: expect.any(Number) }), adaptiveTuning: expect.objectContaining({ enabled: expect.any(Boolean), lastTuning: expect.any(Number), performanceGain: expect.any(Number), strategyEffectiveness: expect.any(Number) }) }); }); }); describe('Shutdown', () => { test('should shutdown cleanly', () => { const shutdownPromise = new Promise((resolve) => { optimizer.once('shutdown', resolve); }); optimizer.shutdown(); return shutdownPromise; }); }); }); describe('ObjectPool', () => { let pool: ObjectPool<{ value: number }>; let performanceTracker: PerformanceTracker; beforeEach(() => { performanceTracker = new PerformanceTracker(); pool = new ObjectPool({ name: 'test-pool', maxSize: 10, minSize: 2, factory: () => ({ value: 0 }), reset: (obj) => { obj.value = 0; }, evictionStrategy: 'lru', autoTune: false, }, performanceTracker); }); afterEach(() => { pool.shutdown(); }); describe('Object Management', () => { test('should get and return objects', () => { // Pool starts with minSize=2 objects, so first gets should be hits const obj1 = pool.get(); expect(obj1).toMatchObject({ value: 0 }); obj1.value = 42; pool.return(obj1); const obj2 = pool.get(); expect(obj2.value).toBe(0); // Should be reset }); test('should create new objects when pool is empty', () => { // Get all objects from pool const objects = []; for (let i = 0; i < 20; i++) { objects.push(pool.get()); } const stats = pool.getStatistics(); expect(stats.creates).toBeGreaterThan(stats.currentSize); }); test('should evict objects when pool is full', () => { // Fill pool beyond capacity for (let i = 0; i < 15; i++) { const obj = pool.get(); obj.value = i; pool.return(obj); } const stats = pool.getStatistics(); expect(stats.currentSize).toBeLessThanOrEqual(pool.config.maxSize); }); }); describe('Eviction Strategies', () => { test('should evict using LRU strategy', async () => { const lruPool = new ObjectPool({ name: 'lru-pool', maxSize: 3, minSize: 0, // Start empty to test eviction properly factory: () => ({ id: Math.random() }), evictionStrategy: 'lru', autoTune: false, }, performanceTracker); // Fill pool to capacity first const objects = []; for (let i = 0; i < 3; i++) { const obj = lruPool.get(); obj.testId = i; // Add identifier objects.push(obj); lruPool.return(obj); await new Promise(resolve => setTimeout(resolve, 10)); // Ensure different timestamps } expect(lruPool.getStatistics().currentSize).toBe(3); // Adding 4th object should evict oldest (first one) const obj4 = lruPool.get(); obj4.testId = 4; lruPool.return(obj4); const stats = lruPool.getStatistics(); expect(stats.currentSize).toBe(3); lruPool.shutdown(); }); test('should evict using FIFO strategy', () => { const fifoPool = new ObjectPool({ name: 'fifo-pool', maxSize: 2, minSize: 0, // Start empty to test eviction properly factory: () => ({ value: Math.random() }), evictionStrategy: 'fifo', autoTune: false, }, performanceTracker); // Fill pool to capacity const obj1 = fifoPool.get(); obj1.testId = 1; fifoPool.return(obj1); const obj2 = fifoPool.get(); obj2.testId = 2; fifoPool.return(obj2); expect(fifoPool.getStatistics().currentSize).toBe(2); // Adding 3rd object should evict first one (FIFO) const obj3 = fifoPool.get(); obj3.testId = 3; fifoPool.return(obj3); const stats = fifoPool.getStatistics(); expect(stats.currentSize).toBe(2); fifoPool.shutdown(); }); }); describe('TTL Support', () => { test('should evict expired objects', async () => { const ttlPool = new ObjectPool({ name: 'ttl-pool', maxSize: 5, minSize: 0, factory: () => ({ created: Date.now() }), evictionStrategy: 'ttl', ttl: 50, // 50ms TTL autoTune: false, }, performanceTracker); const obj1 = ttlPool.get(); ttlPool.return(obj1); // Wait for TTL to expire await new Promise(resolve => setTimeout(resolve, 100)); const obj2 = ttlPool.get(); // Should create new object, not reuse expired one const stats = ttlPool.getStatistics(); expect(stats.creates).toBeGreaterThan(1); ttlPool.shutdown(); }); }); describe('Auto-tuning', () => { test('should auto-tune pool size based on usage', async () => { const autoTunePool = new ObjectPool({ name: 'auto-tune-pool', maxSize: 10, minSize: 2, factory: () => ({ id: Math.random() }), evictionStrategy: 'lru', autoTune: true, }, performanceTracker); // Simulate high miss rate by getting many objects for (let i = 0; i < 20; i++) { autoTunePool.get(); } const beforeSize = autoTunePool.config.maxSize; await autoTunePool.autoTune(); const afterSize = autoTunePool.config.maxSize; // Pool should have increased due to low hit rate expect(afterSize).toBeGreaterThanOrEqual(beforeSize); autoTunePool.shutdown(); }); }); describe('Pool Statistics', () => { test('should calculate correct hit rate', () => { // Pool starts with minSize=2 objects, so first gets are hits const obj1 = pool.get(); // Hit (from initial pool) pool.return(obj1); const obj2 = pool.get(); // Hit (reused object) const stats = pool.getStatistics(); expect(stats.hits).toBe(2); // Both should be hits expect(stats.hitRate).toBeGreaterThan(0); }); test('should calculate utilization rate', () => { // Fill pool partially const objects = []; for (let i = 0; i < 5; i++) { const obj = pool.get(); objects.push(obj); } // Return half for (let i = 0; i < 3; i++) { pool.return(objects[i]); } const stats = pool.getStatistics(); expect(stats.utilizationRate).toBeGreaterThan(0); expect(stats.utilizationRate).toBeLessThanOrEqual(1); }); }); describe('Maintenance Operations', () => { test('should compact pool by removing invalid objects', async () => { const compactPool = new ObjectPool({ name: 'compact-pool', maxSize: 10, minSize: 0, factory: () => ({ valid: true }), validate: (obj) => obj.valid, evictionStrategy: 'fifo', autoTune: false, }, performanceTracker); // Add objects and invalidate some for (let i = 0; i < 5; i++) { const obj = compactPool.get(); if (i % 2 === 0) obj.valid = false; // Invalidate every other object compactPool.return(obj); } const beforeCompact = compactPool.getStatistics().currentSize; const removed = await compactPool.compact(); const afterCompact = compactPool.getStatistics().currentSize; expect(removed).toBeGreaterThan(0); expect(afterCompact).toBeLessThan(beforeCompact); compactPool.shutdown(); }); test('should perform maintenance cleanup', async () => { await pool.performMaintenanceCleanup(); // Should not throw and should complete successfully expect(true).toBe(true); }); }); describe('Force Operations', () => { test('should force eviction of percentage of objects', async () => { // Fill pool for (let i = 0; i < 8; i++) { const obj = pool.get(); pool.return(obj); } const beforeEviction = pool.getStatistics().currentSize; const evicted = await pool.forceEviction(0.5); // Evict 50% const afterEviction = pool.getStatistics().currentSize; expect(evicted).toBeGreaterThan(0); expect(afterEviction).toBeLessThan(beforeEviction); }); test('should evict LRU objects by percentage', async () => { // Fill pool with tracked access - start from empty since minSize=2 const initialSize = pool.getStatistics().currentSize; // Should be 2 from minSize // Add more objects to make the test meaningful for (let i = 0; i < 4; i++) { const obj = pool.get(); obj.testId = i; pool.return(obj); } const beforeEviction = pool.getStatistics().currentSize; expect(beforeEviction).toBeGreaterThan(0); // Ensure we have objects to evict const evicted = await pool.evictLRU(0.3); // Evict 30% of LRU const afterEviction = pool.getStatistics().currentSize; expect(evicted).toBeGreaterThan(0); expect(afterEviction).toBeLessThan(beforeEviction); }); }); describe('Pool Resizing', () => { test('should increase pool size', () => { const originalSize = pool.config.maxSize; pool.increaseSize(5); expect(pool.config.maxSize).toBe(originalSize + 5); }); test('should decrease pool size', () => { const originalSize = pool.config.maxSize; pool.decreaseSize(3); expect(pool.config.maxSize).toBe(originalSize - 3); }); test('should not decrease below minimum size', () => { pool.decreaseSize(20); // Try to decrease by more than current size expect(pool.config.maxSize).toBeGreaterThanOrEqual(pool.config.minSize); }); }); });

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/sloth-wq/prompt-auto-optimizer-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server