Something went wrong. Try again.
Monorepo for Tangled tangled.org
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";import { pushMetrics, Registry, type Metric, type PushOptions } from "#lib/server/otlp.ts";
const ids = (value: unknown) => JSON.stringify(value);
const collect = (registry: Registry): Metric[] => registry.payload({ "service.name": "svfe" }, 1_000_000n, 2_000_000n).resourceMetrics[0] .scopeMetrics[0].metrics;
describe("registry", () => { it("sums a counter per label set, whatever the order of the labels", () => { const registry = new Registry(); const counter = registry.counter("svfe.test.requests", "{request}"); counter.add({ a: "1", b: "2" }); counter.add({ b: "2", a: "1" }, 2); counter.add({ a: "other" }); const sum = collect(registry)[0].sum!; expect(sum.isMonotonic).toBe(true); expect(sum.aggregationTemporality).toBe(2); expect(sum.dataPoints.map((p) => [ids(p.attributes), p.asInt])).toEqual([ [ ids([ { key: "a", value: { stringValue: "1" } }, { key: "b", value: { stringValue: "2" } } ]), "3" ], [ids([{ key: "a", value: { stringValue: "other" } }]), "1"] ]); expect(sum.dataPoints[0]).toMatchObject({ startTimeUnixNano: "1000000", timeUnixNano: "2000000" }); });
it("puts a value on the first bound it doesn't pass, and past the last one in the overflow", () => { const registry = new Registry(); const histogram = registry.histogram("svfe.test.duration", "s", [1, 5]); for (const value of [0.5, 1, 3, 9]) histogram.record({}, value); const [point] = collect(registry)[0].histogram!.dataPoints; expect(point).toMatchObject({ count: "4", sum: 13.5, bucketCounts: ["2", "1", "1"], explicitBounds: [1, 5] }); });
it("reads a gauge when it is collected", () => { const registry = new Registry(); let value = 3; registry.gauge("svfe.test.in_flight", "{request}", () => value); value = 7; expect(collect(registry)[0].gauge!.dataPoints[0]).toMatchObject({ asInt: "7" }); });});
describe("pushMetrics", () => { beforeEach(() => { vi.useFakeTimers(); vi.spyOn(console, "warn").mockImplementation(() => {}); }); afterEach(() => vi.useRealTimers());
const registry = new Registry(); registry.counter("svfe.test.requests", "{request}").add({}); const push = (fetch: NonNullable<PushOptions["fetch"]>, auth = "user:pass") => pushMetrics({ registry, endpoint: "https://telemetry.test", auth, resource: { "service.name": "svfe" }, intervalMs: 15_000, fetch });
it("posts the json payload with basic auth every interval", async () => { const fetch = vi.fn(async () => new Response(null, { status: 200 })); const pusher = push(fetch); await vi.advanceTimersByTimeAsync(30_000); pusher.stop(); expect(fetch).toHaveBeenCalledTimes(2); const [url, init] = fetch.mock.calls[0] as unknown as [string, RequestInit]; expect(url).toBe("https://telemetry.test/v1/metrics"); expect(init.method).toBe("POST"); expect(init.headers).toMatchObject({ "content-type": "application/json", authorization: `Basic ${btoa("user:pass")}` }); expect(JSON.parse(init.body as string).resourceMetrics[0].resource.attributes).toEqual([ { key: "service.name", value: { stringValue: "svfe" } } ]); });
it("sends no authorization without credentials", async () => { const fetch = vi.fn(async () => new Response(null, { status: 200 })); const pusher = push(fetch, ""); await vi.advanceTimersByTimeAsync(15_000); pusher.stop(); expect( (fetch.mock.calls[0] as unknown as [string, RequestInit])[1].headers ).not.toHaveProperty("authorization"); });
it("warns once per streak of failed pushes and keeps pushing", async () => { let status = 500; const fetch = vi.fn(async () => new Response(null, { status })); const pusher = push(fetch); await vi.advanceTimersByTimeAsync(45_000); expect(fetch).toHaveBeenCalledTimes(3); expect(console.warn).toHaveBeenCalledTimes(1); status = 200; await vi.advanceTimersByTimeAsync(15_000); status = 500; await vi.advanceTimersByTimeAsync(15_000); pusher.stop(); expect(console.warn).toHaveBeenCalledTimes(2); });
it("stops pushing once stopped", async () => { const fetch = vi.fn(async () => new Response(null, { status: 200 })); push(fetch).stop(); await vi.advanceTimersByTimeAsync(60_000); expect(fetch).not.toHaveBeenCalled(); });});