Skip to main content
Glama
MetricsCollector.test.js12.7 kB
import { vi } from "vitest"; import { MetricsCollector } from "@/performance/MetricsCollector.js"; describe("MetricsCollector", () => { let collector; let mockMonitor; beforeEach(() => { // Create a mock PerformanceMonitor mockMonitor = { recordRequest: vi.fn(), updateCacheMetrics: vi.fn(), getMetrics: vi.fn().mockReturnValue({ requests: { total: 100, failed: 5, averageResponseTime: 250, }, cache: { hitRate: 0.85, totalSize: 1000, }, system: { memoryUsage: 75, cpuUsage: 30, }, tools: { toolUsageCount: {}, toolResponseTimes: {}, }, }), getAlerts: vi.fn().mockReturnValue([]), stop: vi.fn(), }; collector = new MetricsCollector(mockMonitor); }); afterEach(() => { if (collector) { collector.stop(); } vi.clearAllMocks(); }); describe("initialization", () => { it("should create collector with default configuration", () => { expect(collector).toBeDefined(); expect(collector.constructor.name).toBe("MetricsCollector"); }); it("should accept custom configuration", () => { const customCollector = new MetricsCollector(mockMonitor, { enableRealTime: false, collectInterval: 60000, }); expect(customCollector).toBeDefined(); }); }); describe("metrics collection", () => { it("should collect current metrics from monitor", () => { const metrics = collector.collectCurrentMetrics(); expect(mockMonitor.getMetrics).toHaveBeenCalled(); expect(metrics).toEqual({ requests: { total: 100, failed: 5, averageResponseTime: 250, }, cache: { hitRate: 0.85, totalSize: 1000, }, system: { memoryUsage: 75, cpuUsage: 30, }, tools: { toolUsageCount: {}, toolResponseTimes: {}, }, }); }); it("should get aggregated cache stats", () => { const stats = collector.getAggregatedCacheStats(); expect(stats).toHaveProperty("hits"); expect(stats).toHaveProperty("misses"); expect(stats).toHaveProperty("evictions"); expect(stats).toHaveProperty("totalSize"); expect(stats).toHaveProperty("hitRate"); }); it("should get aggregated client stats", () => { const stats = collector.getAggregatedClientStats(); expect(stats).toHaveProperty("totalRequests"); expect(stats).toHaveProperty("successfulRequests"); expect(stats).toHaveProperty("failedRequests"); expect(stats).toHaveProperty("averageResponseTime"); expect(stats).toHaveProperty("rateLimitHits"); expect(stats).toHaveProperty("authFailures"); }); }); describe("client registration", () => { it("should register clients", () => { const mockClient = { request: vi.fn() }; collector.registerClient("site1", mockClient); // Just verify no errors - internal state is private expect(() => collector.registerClient("site2", mockClient)).not.toThrow(); }); it("should handle client without request method", () => { const mockClient = {}; // No request method // Should not throw expect(() => collector.registerClient("site1", mockClient)).not.toThrow(); }); }); describe("cache manager registration", () => { it("should register cache managers", () => { const mockCacheManager = { getStats: vi.fn().mockReturnValue({ hits: 10, misses: 2, evictions: 1, totalSize: 100, hitRate: 0.83, }), }; collector.registerCacheManager("site1", mockCacheManager); // Verify by checking aggregated stats includes this cache const stats = collector.getAggregatedCacheStats(); expect(stats.hits).toBe(10); expect(stats.misses).toBe(2); }); }); describe("tool tracking", () => { it("should track tool execution", async () => { const executionId = collector.startToolExecution("wp_list_posts", { per_page: 10 }, "site1"); expect(executionId).toBeTruthy(); expect(typeof executionId).toBe("string"); // Wait a bit to ensure some response time await new Promise((resolve) => setTimeout(resolve, 10)); collector.endToolExecution(executionId, true); expect(mockMonitor.recordRequest).toHaveBeenCalledWith(expect.any(Number), true, "wp_list_posts"); }); it("should handle tool execution errors", () => { const executionId = collector.startToolExecution("wp_list_posts", {}, "site1"); const error = new Error("Test error"); collector.endToolExecution(executionId, false, error); expect(mockMonitor.recordRequest).toHaveBeenCalledWith(expect.any(Number), false, "wp_list_posts"); }); it("should handle invalid execution IDs gracefully", () => { // Should not throw expect(() => collector.endToolExecution("invalid-id", true)).not.toThrow(); expect(mockMonitor.recordRequest).not.toHaveBeenCalled(); }); }); describe("request tracking", () => { it("should record raw requests", () => { collector.recordRawRequest(150, true, "/wp/v2/posts", false); expect(mockMonitor.recordRequest).toHaveBeenCalledWith(150, true); }); it("should record cached requests", () => { collector.recordRawRequest(5, true, "/wp/v2/posts", true); expect(mockMonitor.recordRequest).toHaveBeenCalledWith(5, true); }); }); describe("site metrics", () => { it("should get metrics for specific site", () => { const mockClient = { getStats: vi.fn().mockReturnValue({ totalRequests: 50, successfulRequests: 45, failedRequests: 5, averageResponseTime: 200, rateLimitHits: 0, authFailures: 0, }), }; const mockCache = { getStats: vi.fn().mockReturnValue({ hits: 100, misses: 20, evictions: 5, totalSize: 500, hitRate: 0.83, }), }; collector.registerClient("site1", mockClient); collector.registerCacheManager("site1", mockCache); const siteMetrics = collector.getSiteMetrics("site1"); expect(siteMetrics).toHaveProperty("client"); expect(siteMetrics).toHaveProperty("cache"); expect(siteMetrics.isActive).toBe(true); expect(mockClient.getStats).toHaveBeenCalled(); expect(mockCache.getStats).toHaveBeenCalled(); }); it("should handle missing site", () => { const siteMetrics = collector.getSiteMetrics("non-existent"); expect(siteMetrics.isActive).toBe(false); expect(siteMetrics.client).toBeUndefined(); expect(siteMetrics.cache).toBeUndefined(); }); }); describe("performance comparison", () => { it("should compare site performance", () => { // Register multiple sites with different performance characteristics const sites = ["site1", "site2", "site3"]; sites.forEach((site, index) => { collector.registerClient(site, { getStats: vi.fn().mockReturnValue({ totalRequests: 100 * (index + 1), successfulRequests: 100 * (index + 1) - 5 * (index + 1), failedRequests: 5 * (index + 1), averageResponseTime: 100 * (index + 1), rateLimitHits: 0, authFailures: 0, }), }); collector.registerCacheManager(site, { getStats: vi.fn().mockReturnValue({ hits: 80 - index * 10, misses: 20 + index * 10, evictions: 0, totalSize: 1000, hitRate: (80 - index * 10) / 100, }), }); }); const comparison = collector.compareSitePerformance(); expect(comparison.sites).toHaveLength(3); expect(comparison.bestPerforming).toBeTruthy(); expect(comparison.worstPerforming).toBeTruthy(); expect(comparison.comparison).toBeDefined(); // Verify each site has comparison data sites.forEach((site) => { expect(comparison.comparison[site]).toHaveProperty("responseTime"); expect(comparison.comparison[site]).toHaveProperty("cacheHitRate"); expect(comparison.comparison[site]).toHaveProperty("errorRate"); expect(comparison.comparison[site]).toHaveProperty("requestCount"); expect(comparison.comparison[site]).toHaveProperty("ranking"); }); }); }); describe("optimization suggestions", () => { it("should generate optimization suggestions", () => { const suggestions = collector.generateOptimizationSuggestions(); expect(suggestions).toHaveProperty("critical"); expect(suggestions).toHaveProperty("recommended"); expect(suggestions).toHaveProperty("optional"); expect(Array.isArray(suggestions.critical)).toBe(true); expect(Array.isArray(suggestions.recommended)).toBe(true); expect(Array.isArray(suggestions.optional)).toBe(true); }); it("should identify critical issues with poor performance", () => { // Mock poor performance metrics mockMonitor.getMetrics.mockReturnValue({ requests: { total: 100, failed: 20, averageResponseTime: 6000, // > 5000ms }, cache: { hitRate: 0.5, totalSize: 1000, }, system: { memoryUsage: 90, cpuUsage: 80, }, tools: { toolUsageCount: {}, toolResponseTimes: {}, }, }); const suggestions = collector.generateOptimizationSuggestions(); expect(suggestions.critical.length).toBeGreaterThan(0); expect(suggestions.critical.some((s) => s.includes("Response times are critically high"))).toBe(true); expect(suggestions.critical.some((s) => s.includes("Error rate is critically high"))).toBe(true); }); it("should provide recommendations for suboptimal performance", () => { // Mock suboptimal but not critical performance mockMonitor.getMetrics.mockReturnValue({ requests: { total: 100, failed: 5, averageResponseTime: 2500, // Between 2000-5000ms }, cache: { hitRate: 0.7, // Below 0.8 totalSize: 1000, }, system: { memoryUsage: 85, // Above 80% cpuUsage: 50, }, tools: { toolUsageCount: {}, toolResponseTimes: {}, }, }); const suggestions = collector.generateOptimizationSuggestions(); expect(suggestions.recommended.length).toBeGreaterThan(0); expect(suggestions.recommended.some((s) => s.includes("Cache hit rate is below 80%"))).toBe(true); expect(suggestions.recommended.some((s) => s.includes("Response times could be improved"))).toBe(true); expect(suggestions.recommended.some((s) => s.includes("Memory usage is high"))).toBe(true); }); }); describe("detailed report", () => { it("should export detailed performance report", () => { // Register a site to make the report more complete collector.registerClient("site1", { getStats: vi.fn().mockReturnValue({ totalRequests: 100, successfulRequests: 95, failedRequests: 5, averageResponseTime: 200, rateLimitHits: 0, authFailures: 0, }), }); const report = collector.exportDetailedReport(); expect(report).toHaveProperty("timestamp"); expect(report).toHaveProperty("overview"); expect(report).toHaveProperty("siteComparison"); expect(report).toHaveProperty("aggregatedStats"); expect(report.aggregatedStats).toHaveProperty("cache"); expect(report.aggregatedStats).toHaveProperty("client"); expect(report).toHaveProperty("optimizations"); expect(report).toHaveProperty("alerts"); // Verify timestamp is ISO format expect(new Date(report.timestamp).toISOString()).toBe(report.timestamp); }); }); describe("cleanup", () => { it("should stop monitoring and cleanup resources", () => { // Start some tool executions to verify they get cleaned up const executionId = collector.startToolExecution("test_tool", {}, "site1"); collector.stop(); expect(mockMonitor.stop).toHaveBeenCalled(); // Verify tool execution is cleaned up (should not throw or record) collector.endToolExecution(executionId, true); expect(mockMonitor.recordRequest).not.toHaveBeenCalled(); }); }); });

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/docdyhr/mcp-wordpress'

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