Files
2026-05-27 23:29:53 +01:00

100 lines
3.3 KiB
TypeScript

import type { Meter, MeterProvider } from "@opentelemetry/api";
import { describe, expect, it } from "@suaveplan/testing/runner";
import {
createRateLimitInstruments,
RATE_LIMIT_COUNTER_NAMES,
} from "./instruments.js";
interface RecordedCounter {
readonly name: string;
readonly addCalls: {
value: number;
attributes?: Readonly<Record<string, unknown>>;
}[];
}
function fakeProvider(): {
provider: MeterProvider;
counters: RecordedCounter[];
} {
const counters: RecordedCounter[] = [];
const provider: MeterProvider = {
getMeter(_name: string): Meter {
const meter: Meter = {
createCounter(n: string) {
const r: RecordedCounter = { name: n, addCalls: [] };
counters.push(r);
return {
add(
v: number,
attrs?: Readonly<Record<string, unknown>>
) {
r.addCalls.push({ value: v, attributes: attrs });
},
} as ReturnType<Meter["createCounter"]>;
},
createUpDownCounter() {
throw new Error("not used");
},
createHistogram() {
throw new Error("not used");
},
createObservableCounter() {
throw new Error("not used");
},
createObservableGauge() {
throw new Error("not used");
},
createObservableUpDownCounter() {
throw new Error("not used");
},
addBatchObservableCallback() {
/* noop */
},
removeBatchObservableCallback() {
/* noop */
},
} as Meter;
return meter;
},
};
return { provider, counters };
}
describe("instruments", () => {
it("creates the rate-limit exceeded counter", { timeout: 5000 }, () => {
const { provider, counters } = fakeProvider();
const inst = createRateLimitInstruments({ meterProvider: provider });
expect(counters.map((c) => c.name)).toEqual([
"api.rate_limit.exceeded_total",
]);
inst.counters["api.rate_limit.exceeded_total"].add(1, {
plugin: "p",
route: "GET /",
key_kind: "principal",
});
expect(counters[0]!.addCalls).toHaveLength(1);
expect(counters[0]!.addCalls[0]!.attributes).toEqual({
plugin: "p",
route: "GET /",
key_kind: "principal",
});
});
it("falls back to global meter-provider when none supplied", {
timeout: 5000,
}, () => {
const inst = createRateLimitInstruments();
// Global no-op provider returns no-op counters; .add must not throw.
expect(() =>
inst.counters["api.rate_limit.exceeded_total"].add(1, {})
).not.toThrow();
});
it("exposes the full counter-name tuple", { timeout: 5000 }, () => {
expect(RATE_LIMIT_COUNTER_NAMES).toEqual([
"api.rate_limit.exceeded_total",
]);
});
});