diff --git a/packages/core-shared/src/instrumentation/noop-tracer.test.ts b/packages/core-shared/src/instrumentation/noop-tracer.test.ts new file mode 100644 index 0000000..24e6162 --- /dev/null +++ b/packages/core-shared/src/instrumentation/noop-tracer.test.ts @@ -0,0 +1,41 @@ +import { describe, it, expect, vi } from "vitest"; +import { NoopTracer } from "@/instrumentation/noop-tracer"; +import type { ISpan } from "@/instrumentation/tracer.interface"; + +describe("NoopTracer", () => { + it("startSpan returns the function result", async () => { + const tracer = new NoopTracer(); + const result = await tracer.startSpan({ name: "test.op" }, async () => 42); + expect(result).toBe(42); + }); + + it("startSpan passes a no-op ISpan to the function", async () => { + const tracer = new NoopTracer(); + let received: ISpan | undefined; + await tracer.startSpan({ name: "test.op" }, async (span) => { + received = span; + return undefined; + }); + expect(received).toBeDefined(); + expect(() => received!.setAttribute("k", "v")).not.toThrow(); + expect(() => received!.setStatus("ok")).not.toThrow(); + expect(() => received!.setStatus("error", "msg")).not.toThrow(); + }); + + it("propagates exceptions from the wrapped function", async () => { + const tracer = new NoopTracer(); + const err = new Error("boom"); + await expect( + tracer.startSpan({ name: "test.op" }, async () => { + throw err; + }), + ).rejects.toBe(err); + }); + + it("does not invoke external services", async () => { + const tracer = new NoopTracer(); + const fn = vi.fn(async () => "ok"); + await tracer.startSpan({ name: "test.op" }, fn); + expect(fn).toHaveBeenCalledTimes(1); + }); +}); diff --git a/packages/core-shared/src/instrumentation/noop-tracer.ts b/packages/core-shared/src/instrumentation/noop-tracer.ts new file mode 100644 index 0000000..ab3a5f0 --- /dev/null +++ b/packages/core-shared/src/instrumentation/noop-tracer.ts @@ -0,0 +1,12 @@ +import type { ITracer, ISpan, SpanOpts } from "./tracer.interface"; + +const NOOP_SPAN: ISpan = { + setAttribute: () => {}, + setStatus: () => {}, +}; + +export class NoopTracer implements ITracer { + async startSpan(_opts: SpanOpts, fn: (span: ISpan) => Promise): Promise { + return fn(NOOP_SPAN); + } +}