test(agenthub): Add integration tests for metrics endpoint
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 <noreply@anthropic.com>
This commit is contained in:
parent
709d8db52d
commit
7121ad5dc1
1 changed files with 131 additions and 0 deletions
131
test/metrics.test.ts
Normal file
131
test/metrics.test.ts
Normal file
|
|
@ -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+/);
|
||||||
|
});
|
||||||
|
});
|
||||||
Loading…
Reference in a new issue