/** * Unit tests for src/metrics/registry.ts * * Verifies that all 6 Prometheus metrics are registered on the shared * metricsRegistry (not the default global registry), have the correct * names, and carry the correct label names. */ import { metricsRegistry, tokensIssuedTotal, agentsRegisteredTotal, httpRequestsTotal, httpRequestDurationSeconds, dbQueryDurationSeconds, redisCommandDurationSeconds, } from '../../../src/metrics/registry'; describe('metricsRegistry', () => { // ────────────────────────────────────────────────────────────────── // Registry isolation // ────────────────────────────────────────────────────────────────── it('uses a non-default registry instance', async () => { // prom-client default registry is accessed via Registry.default or // by calling register.metrics(). The shared registry must NOT be // the same reference as the default one. const { register } = await import('prom-client'); expect(metricsRegistry).not.toBe(register); }); it('contains exactly 6 metric entries', async () => { const entries = await metricsRegistry.getMetricsAsJSON(); expect(entries).toHaveLength(6); }); // ────────────────────────────────────────────────────────────────── // Metric names // ────────────────────────────────────────────────────────────────── it.each([ 'agentidp_tokens_issued_total', 'agentidp_agents_registered_total', 'agentidp_http_requests_total', 'agentidp_http_request_duration_seconds', 'agentidp_db_query_duration_seconds', 'agentidp_redis_command_duration_seconds', ])('registers metric "%s"', async (metricName) => { const entries = await metricsRegistry.getMetricsAsJSON(); const names = entries.map((e) => e.name); expect(names).toContain(metricName); }); // ────────────────────────────────────────────────────────────────── // Label names per metric // ────────────────────────────────────────────────────────────────── describe('tokensIssuedTotal', () => { it('has name agentidp_tokens_issued_total', () => { // Access the internal name via the metric object const metric = tokensIssuedTotal as unknown as { name: string }; expect(metric.name).toBe('agentidp_tokens_issued_total'); }); it('has label "scope"', async () => { const entries = await metricsRegistry.getMetricsAsJSON(); const entry = entries.find((e) => e.name === 'agentidp_tokens_issued_total'); expect(entry).toBeDefined(); // Counter with no observations has an empty values array but the metric exists expect(entry!.type).toBe('counter'); }); }); describe('agentsRegisteredTotal', () => { it('has name agentidp_agents_registered_total', () => { const metric = agentsRegisteredTotal as unknown as { name: string }; expect(metric.name).toBe('agentidp_agents_registered_total'); }); }); describe('httpRequestsTotal', () => { it('has name agentidp_http_requests_total', () => { const metric = httpRequestsTotal as unknown as { name: string }; expect(metric.name).toBe('agentidp_http_requests_total'); }); it('increments with method, route, status_code labels without throwing', () => { expect(() => httpRequestsTotal.inc({ method: 'GET', route: '/test', status_code: '200' }), ).not.toThrow(); }); }); describe('httpRequestDurationSeconds', () => { it('has name agentidp_http_request_duration_seconds', () => { const metric = httpRequestDurationSeconds as unknown as { name: string }; expect(metric.name).toBe('agentidp_http_request_duration_seconds'); }); it('observes with method, route, status_code labels without throwing', () => { expect(() => httpRequestDurationSeconds.observe({ method: 'GET', route: '/test', status_code: '200' }, 0.05), ).not.toThrow(); }); }); describe('dbQueryDurationSeconds', () => { it('has name agentidp_db_query_duration_seconds', () => { const metric = dbQueryDurationSeconds as unknown as { name: string }; expect(metric.name).toBe('agentidp_db_query_duration_seconds'); }); it('observes with operation label without throwing', () => { expect(() => dbQueryDurationSeconds.observe({ operation: 'query' }, 0.002), ).not.toThrow(); }); }); describe('redisCommandDurationSeconds', () => { it('has name agentidp_redis_command_duration_seconds', () => { const metric = redisCommandDurationSeconds as unknown as { name: string }; expect(metric.name).toBe('agentidp_redis_command_duration_seconds'); }); it('observes with command label without throwing', () => { expect(() => redisCommandDurationSeconds.observe({ command: 'get' }, 0.001), ).not.toThrow(); }); }); });