import { describe, test, expect, beforeAll, afterAll } from 'bun:test'; import { setupFileRig, type FileTestRig } from './helpers/rig.js'; import { METRIC_OP_DURATION_MS, METRIC_OP_TOTAL, METRIC_RATE_LIMIT_REJECT_TOTAL, type MetricSink, type MetricTags, type FileEntry, } from '../../src/index.js'; interface MetricEvent { name: string; value: number; tags: MetricTags; } describe('Metrics — onMetric on success', () => { let rig: FileTestRig; const events: MetricEvent[] = []; const sink: MetricSink = (name, value, tags) => events.push({ name, value, tags }); beforeAll(async () => { rig = await setupFileRig({ onMetric: sink, list: async () => ({ entries: [], hasMore: false }), }); }); afterAll(async () => { await rig.teardown(); }); test('emits op_total + op_duration_ms with result=ok on success', async () => { events.length = 0; await rig.fs.list('/'); const totals = events.filter((e) => e.name === METRIC_OP_TOTAL); expect(totals.length).toBeGreaterThanOrEqual(1); expect(totals[0]!.tags.result).toBe('ok'); expect(totals[0]!.tags.op).toBe('list'); const durations = events.filter((e) => e.name === METRIC_OP_DURATION_MS); expect(durations.length).toBeGreaterThanOrEqual(1); expect(durations[0]!.value).toBeGreaterThanOrEqual(0); }); }); describe('Metrics — onMetric rate-limit reject', () => { let rig: FileTestRig; const events: MetricEvent[] = []; const sink: MetricSink = (name, value, tags) => events.push({ name, value, tags }); beforeAll(async () => { rig = await setupFileRig({ onMetric: sink, rateLimits: { maxOpsPerMinutePerSender: 3 }, stat: async (_ctx) => { const e: FileEntry = { name: 'x', kind: 'file', size: 1, mtime: 0, metadata: {} }; return e; }, }); }); afterAll(async () => { await rig.teardown(); }); test('emits rate_limit_reject_total when capacity exhausted', async () => { events.length = 0; // Cap is 3; first 3 stats succeed, 4th rejected. await rig.fs.stat('/x'); await rig.fs.stat('/x'); await rig.fs.stat('/x'); await expect(rig.fs.stat('/x')).rejects.toThrow(); const rejects = events.filter((e) => e.name === METRIC_RATE_LIMIT_REJECT_TOTAL); expect(rejects.length).toBeGreaterThanOrEqual(1); expect(rejects[0]!.tags.op).toBe('stat'); }); });