import { describe, test, expect } from 'bun:test'; import { Hono } from 'hono'; import { createHealthRoutes } from '../src/health.js'; import { createMetricsRoutes, metricsMiddleware, metrics } from '../src/metrics.js'; import { MemoryPrekeyStore } from '../src/memory-store.js'; describe('Health endpoints', () => { test('GET /health returns ok with version and uptime', async () => { const store = new MemoryPrekeyStore(); const app = createHealthRoutes(store, '1.2.3'); const res = await app.request('/health'); expect(res.status).toBe(200); const body = await res.json(); expect(body.status).toBe('ok'); expect(body.version).toBe('1.2.3'); expect(body.uptimeSeconds).toBeGreaterThanOrEqual(0); }); test('GET /healthz returns text "ok"', async () => { const store = new MemoryPrekeyStore(); const app = createHealthRoutes(store, '1.0.0'); const res = await app.request('/healthz'); expect(res.status).toBe(200); expect(await res.text()).toBe('ok'); }); test('GET /ready returns text "ready"', async () => { const store = new MemoryPrekeyStore(); const app = createHealthRoutes(store, '1.0.0'); const res = await app.request('/ready'); expect(res.status).toBe(200); expect(await res.text()).toBe('ready'); }); test('returns 503 if store throws', async () => { const broken = { getOneTimePreKeyCount: async () => { throw new Error('db down'); }, } as any; const app = createHealthRoutes(broken, '1.0.0'); const res = await app.request('/health'); expect(res.status).toBe(503); const body = await res.json(); expect(body.status).toBe('error'); }); }); describe('Metrics endpoint', () => { test('returns Prometheus exposition format', async () => { // Trigger some metrics const app = new Hono(); app.use('*', metricsMiddleware()); app.get('/test', (c) => c.text('hello')); app.route('/', createMetricsRoutes()); await app.request('/test'); await app.request('/test'); const res = await app.request('/metrics'); expect(res.status).toBe(200); expect(res.headers.get('content-type')).toMatch(/text\/plain/); const body = await res.text(); expect(body).toContain('shade_requests_total'); expect(body).toContain('shade_request_duration_ms'); }); });