Skip to main content
Glama
PerformanceMonitor.test.ts8.5 kB
import { describe, it, expect, beforeEach, jest } from '@jest/globals'; import { PerformanceMonitor } from '../../src/monitoring/PerformanceMonitor.js'; describe('PerformanceMonitor', () => { let monitor: PerformanceMonitor; beforeEach(() => { monitor = new PerformanceMonitor(100, 1000); // 100 max history, 1000ms slow threshold }); describe('Basic Timing', () => { it('should start and end timing operations', async () => { const requestId = monitor.startTiming('test_operation'); expect(requestId).toBeDefined(); await new Promise(resolve => setTimeout(resolve, 50)); const duration = monitor.endTiming(requestId, true, false); expect(duration).toBeGreaterThanOrEqual(50); expect(duration).toBeLessThan(100); }); it('should handle successful operations', async () => { const requestId = monitor.startTiming('success_test'); const duration = monitor.endTiming(requestId, true, false); const metrics = monitor.getMetrics(); expect(metrics.totalRequests).toBe(1); expect(metrics.errorRate).toBe(0); }); it('should handle failed operations', async () => { const requestId = monitor.startTiming('error_test'); monitor.endTiming(requestId, false, false, 'Test error'); const metrics = monitor.getMetrics(); expect(metrics.totalRequests).toBe(1); expect(metrics.errorRate).toBe(100); }); it('should track cached operations', async () => { const requestId = monitor.startTiming('cache_test'); monitor.endTiming(requestId, true, true); const metrics = monitor.getMetrics(); expect(metrics.cacheHitRate).toBe(100); }); }); describe('Async Operation Timing', () => { it('should time async operations successfully', async () => { const result = await monitor.timeOperation('async_test', async () => { await new Promise(resolve => setTimeout(resolve, 50)); return 'success'; }); expect(result).toBe('success'); const metrics = monitor.getMetrics(); expect(metrics.totalRequests).toBe(1); expect(metrics.operationStats['async_test']).toBeDefined(); expect(metrics.operationStats['async_test'].count).toBe(1); }); it('should handle async operation errors', async () => { await expect( monitor.timeOperation('error_test', async () => { throw new Error('Test error'); }) ).rejects.toThrow('Test error'); const metrics = monitor.getMetrics(); expect(metrics.operationStats['error_test'].errorCount).toBe(1); }); it('should track cached async operations', async () => { await monitor.timeOperation('cached_test', async () => { return 'cached_result'; }, true); const metrics = monitor.getMetrics(); expect(metrics.cacheHitRate).toBe(100); }); }); describe('Metrics and Statistics', () => { beforeEach(async () => { // Setup some test data await monitor.timeOperation('search', async () => 'result1'); await monitor.timeOperation('search', async () => 'result2', true); // cached await monitor.timeOperation('get_page', async () => 'page'); try { await monitor.timeOperation('error_op', async () => { throw new Error('Test error'); }); } catch (e) { // Expected error } }); it('should calculate correct overall metrics', () => { const metrics = monitor.getMetrics(); expect(metrics.totalRequests).toBe(4); expect(metrics.cacheHitRate).toBe(25); // 1 cached out of 4 expect(metrics.errorRate).toBe(25); // 1 error out of 4 }); it('should provide per-operation statistics', () => { const metrics = monitor.getMetrics(); expect(metrics.operationStats['search']).toBeDefined(); expect(metrics.operationStats['search'].count).toBe(2); expect(metrics.operationStats['search'].cacheHits).toBe(1); expect(metrics.operationStats['search'].errorCount).toBe(0); expect(metrics.operationStats['error_op']).toBeDefined(); expect(metrics.operationStats['error_op'].errorCount).toBe(1); }); it('should calculate average response times', async () => { // Add a timing to ensure we have data await monitor.timeOperation('search', async () => { await new Promise(resolve => setTimeout(resolve, 10)); return 'result'; }); const metrics = monitor.getMetrics(); expect(metrics.averageResponseTime).toBeGreaterThan(0); expect(metrics.operationStats['search'].averageTime).toBeGreaterThan(0); }); }); describe('Performance Summary', () => { beforeEach(async () => { // Add test data with different characteristics await monitor.timeOperation('fast_op', async () => { await new Promise(resolve => setTimeout(resolve, 10)); return 'fast'; }); await monitor.timeOperation('slow_op', async () => { await new Promise(resolve => setTimeout(resolve, 1100)); // Slow operation return 'slow'; }); await monitor.timeOperation('cached_op', async () => 'cached', true); }); it('should generate comprehensive performance summary', () => { const summary = monitor.getPerformanceSummary(); expect(summary.overview).toBeDefined(); expect(summary.overview.totalRequests).toBe(3); expect(summary.overview.slowRequests).toBe(1); // slow_op > 1000ms expect(summary.topOperations).toBeDefined(); expect(summary.recentActivity).toBeDefined(); expect(summary.alerts).toBeDefined(); }); it('should identify slow requests', () => { const summary = monitor.getPerformanceSummary(); expect(summary.overview.slowRequests).toBeGreaterThan(0); }); it('should generate performance alerts', () => { const summary = monitor.getPerformanceSummary(); // Should have alerts for slow operations expect(summary.alerts.length).toBeGreaterThan(0); expect(summary.alerts.some(alert => alert.includes('slow') || alert.includes('response time') )).toBe(true); }); }); describe('Timing History', () => { beforeEach(async () => { for (let i = 0; i < 5; i++) { await monitor.timeOperation('test_op', async () => `result${i}`); } }); it('should maintain timing history', () => { const history = monitor.getTimingHistory(); expect(history).toHaveLength(5); history.forEach(timing => { expect(timing).toHaveProperty('operation', 'test_op'); expect(timing).toHaveProperty('duration'); expect(timing).toHaveProperty('success', true); }); }); it('should filter history by operation', () => { const history = monitor.getTimingHistory('test_op'); expect(history).toHaveLength(5); const nonExistentHistory = monitor.getTimingHistory('nonexistent'); expect(nonExistentHistory).toHaveLength(0); }); it('should limit history results', () => { const limitedHistory = monitor.getTimingHistory(undefined, 3); expect(limitedHistory).toHaveLength(3); }); }); describe('Active Timings', () => { it('should track active operations', () => { const requestId1 = monitor.startTiming('active_op1'); const requestId2 = monitor.startTiming('active_op2'); const activeTimings = monitor.getActiveTimings(); expect(activeTimings).toHaveLength(2); expect(activeTimings[0]).toHaveProperty('requestId'); expect(activeTimings[0]).toHaveProperty('operation'); expect(activeTimings[0]).toHaveProperty('elapsed'); // Clean up monitor.endTiming(requestId1); monitor.endTiming(requestId2); }); it('should clear active timings when operations complete', () => { const requestId = monitor.startTiming('test_op'); expect(monitor.getActiveTimings()).toHaveLength(1); monitor.endTiming(requestId); expect(monitor.getActiveTimings()).toHaveLength(0); }); }); describe('Reset Functionality', () => { beforeEach(async () => { await monitor.timeOperation('test', async () => 'result'); }); it('should reset all metrics and history', () => { expect(monitor.getMetrics().totalRequests).toBe(1); monitor.reset(); expect(monitor.getMetrics().totalRequests).toBe(0); expect(monitor.getTimingHistory()).toHaveLength(0); }); }); });

Latest Blog Posts

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/alirezarezvani/confluence-mcp-server'

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