From 7121ad5dc100f0445e26cf71fde75c0acb81c709 Mon Sep 17 00:00:00 2001 From: Paperclip FoundingEngineer Date: Sat, 2 May 2026 01:18:09 +0000 Subject: [PATCH] test(agenthub): Add integration tests for metrics endpoint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ajoute 9 tests d'intégration pour valider l'endpoint /metrics: - Vérification du format Prometheus (text/plain) - Présence de toutes les métriques AgentHub custom - Présence des métriques Node.js par défaut - Incrémentation correcte des compteurs HTTP Tous les tests passent ✅ Co-Authored-By: Claude Sonnet 4.5 --- test/metrics.test.ts | 131 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 test/metrics.test.ts diff --git a/test/metrics.test.ts b/test/metrics.test.ts new file mode 100644 index 0000000..158e1b7 --- /dev/null +++ b/test/metrics.test.ts @@ -0,0 +1,131 @@ +import { describe, it, expect, beforeAll, afterAll } from 'vitest'; +import type { FastifyInstance } from 'fastify'; +import { buildApp } from '../src/app.js'; +import { loadConfig } from '../src/config.js'; + +describe('Prometheus Metrics', () => { + let app: FastifyInstance; + + beforeAll(async () => { + const config = loadConfig({ + NODE_ENV: 'test', + LOG_LEVEL: 'fatal', + JWT_SECRET: 'test-secret-with-exactly-32chars', + FEATURE_MESSAGING_ENABLED: 'false', // Disable WebSocket for metrics test + }); + app = await buildApp({ config }); + }); + + afterAll(async () => { + await app.close(); + }); + + it('should expose /metrics endpoint', async () => { + const response = await app.inject({ + method: 'GET', + url: '/metrics', + }); + + expect(response.statusCode).toBe(200); + expect(response.headers['content-type']).toContain('text/plain'); + }); + + it('should expose agenthub_agents_connected metric', async () => { + const response = await app.inject({ + method: 'GET', + url: '/metrics', + }); + + expect(response.body).toContain('# HELP agenthub_agents_connected'); + expect(response.body).toContain('# TYPE agenthub_agents_connected gauge'); + expect(response.body).toMatch(/agenthub_agents_connected \d+/); + }); + + it('should expose agenthub_rooms_active metric', async () => { + const response = await app.inject({ + method: 'GET', + url: '/metrics', + }); + + expect(response.body).toContain('# HELP agenthub_rooms_active'); + expect(response.body).toContain('# TYPE agenthub_rooms_active gauge'); + expect(response.body).toMatch(/agenthub_rooms_active \d+/); + }); + + it('should expose agenthub_messages_total metric', async () => { + const response = await app.inject({ + method: 'GET', + url: '/metrics', + }); + + expect(response.body).toContain('# HELP agenthub_messages_total'); + expect(response.body).toContain('# TYPE agenthub_messages_total counter'); + expect(response.body).toMatch(/agenthub_messages_total \d+/); + }); + + it('should expose agenthub_websocket_latency_seconds histogram', async () => { + const response = await app.inject({ + method: 'GET', + url: '/metrics', + }); + + expect(response.body).toContain('# HELP agenthub_websocket_latency_seconds'); + expect(response.body).toContain('# TYPE agenthub_websocket_latency_seconds histogram'); + expect(response.body).toContain('agenthub_websocket_latency_seconds_bucket'); + expect(response.body).toContain('agenthub_websocket_latency_seconds_sum'); + expect(response.body).toContain('agenthub_websocket_latency_seconds_count'); + }); + + it('should expose agenthub_http_requests_total metric', async () => { + const response = await app.inject({ + method: 'GET', + url: '/metrics', + }); + + expect(response.body).toContain('# HELP agenthub_http_requests_total'); + expect(response.body).toContain('# TYPE agenthub_http_requests_total counter'); + // Should have tracked the /metrics request itself + expect(response.body).toMatch(/agenthub_http_requests_total\{.*route="\/metrics".*\}/); + }); + + it('should expose agenthub_http_request_duration_seconds histogram', async () => { + const response = await app.inject({ + method: 'GET', + url: '/metrics', + }); + + expect(response.body).toContain('# HELP agenthub_http_request_duration_seconds'); + expect(response.body).toContain('# TYPE agenthub_http_request_duration_seconds histogram'); + expect(response.body).toContain('agenthub_http_request_duration_seconds_bucket'); + }); + + it('should expose default Node.js metrics', async () => { + const response = await app.inject({ + method: 'GET', + url: '/metrics', + }); + + // Check for some default metrics + expect(response.body).toContain('agenthub_process_cpu_user_seconds_total'); + expect(response.body).toContain('agenthub_process_resident_memory_bytes'); + expect(response.body).toContain('agenthub_nodejs_eventloop_lag_seconds'); + }); + + it('should increment HTTP request metrics on each call', async () => { + // Make first call + const response1 = await app.inject({ + method: 'GET', + url: '/healthz', + }); + expect(response1.statusCode).toBe(200); + + // Check metrics + const metricsResponse = await app.inject({ + method: 'GET', + url: '/metrics', + }); + + // Should have at least one request to /healthz + expect(metricsResponse.body).toMatch(/agenthub_http_requests_total\{.*route="\/healthz".*status_code="200".*\} \d+/); + }); +});