115 lines
3.8 KiB
TypeScript
115 lines
3.8 KiB
TypeScript
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
import {
|
|
getStartupTraceContext,
|
|
getStartupTracer,
|
|
resolveProtocol,
|
|
} from "./instrumentation.js";
|
|
|
|
// The span export path selects the OTLP trace-exporter package from the
|
|
// `OTEL_EXPORTER_OTLP_PROTOCOL` env var. `resolveProtocol` owns that choice.
|
|
// A wrong package name sends spans over the wrong wire protocol, so the
|
|
// exporter never reaches the collector.
|
|
describe("resolveProtocol", () => {
|
|
const PROTOCOL_ENV = "OTEL_EXPORTER_OTLP_PROTOCOL";
|
|
let previous: string | undefined;
|
|
|
|
beforeEach(() => {
|
|
previous = process.env[PROTOCOL_ENV];
|
|
delete process.env[PROTOCOL_ENV];
|
|
});
|
|
|
|
afterEach(() => {
|
|
if (previous === undefined) {
|
|
delete process.env[PROTOCOL_ENV];
|
|
} else {
|
|
process.env[PROTOCOL_ENV] = previous;
|
|
}
|
|
vi.restoreAllMocks();
|
|
});
|
|
|
|
it("defaults to grpc when the protocol is unset", () => {
|
|
expect(resolveProtocol()).toEqual({
|
|
protocol: "grpc",
|
|
packageName: "@opentelemetry/exporter-trace-otlp-grpc",
|
|
});
|
|
});
|
|
|
|
it("defaults to grpc when the protocol is an empty string", () => {
|
|
process.env[PROTOCOL_ENV] = "";
|
|
expect(resolveProtocol()).toEqual({
|
|
protocol: "grpc",
|
|
packageName: "@opentelemetry/exporter-trace-otlp-grpc",
|
|
});
|
|
});
|
|
|
|
it("selects the grpc exporter for grpc", () => {
|
|
process.env[PROTOCOL_ENV] = "grpc";
|
|
expect(resolveProtocol()).toEqual({
|
|
protocol: "grpc",
|
|
packageName: "@opentelemetry/exporter-trace-otlp-grpc",
|
|
});
|
|
});
|
|
|
|
it("selects the protobuf exporter for http/protobuf", () => {
|
|
process.env[PROTOCOL_ENV] = "http/protobuf";
|
|
expect(resolveProtocol()).toEqual({
|
|
protocol: "http/protobuf",
|
|
packageName: "@opentelemetry/exporter-trace-otlp-proto",
|
|
});
|
|
});
|
|
|
|
it("selects the json exporter for http/json", () => {
|
|
process.env[PROTOCOL_ENV] = "http/json";
|
|
expect(resolveProtocol()).toEqual({
|
|
protocol: "http/json",
|
|
packageName: "@opentelemetry/exporter-trace-otlp-http",
|
|
});
|
|
});
|
|
|
|
it("normalizes surrounding space and letter case", () => {
|
|
process.env[PROTOCOL_ENV] = " HTTP/PROTOBUF ";
|
|
expect(resolveProtocol()).toEqual({
|
|
protocol: "http/protobuf",
|
|
packageName: "@opentelemetry/exporter-trace-otlp-proto",
|
|
});
|
|
});
|
|
|
|
it("warns and falls back to grpc for an unknown protocol", () => {
|
|
process.env[PROTOCOL_ENV] = "carrier-pigeon";
|
|
const warn = vi.spyOn(console, "warn").mockImplementation(() => undefined);
|
|
|
|
expect(resolveProtocol()).toEqual({
|
|
protocol: "grpc",
|
|
packageName: "@opentelemetry/exporter-trace-otlp-grpc",
|
|
});
|
|
expect(warn).toHaveBeenCalledOnce();
|
|
});
|
|
});
|
|
|
|
// The manual startup spans read their tracer through these accessors. Both
|
|
// accessors must return a usable handle and never throw, whether or not
|
|
// `@opentelemetry/api` resolves. When the package is absent, the handle is a
|
|
// no-op; when it is present, the api returns a real no-op tracer while no SDK
|
|
// is registered. The span methods work in both cases.
|
|
describe("startup tracer accessors", () => {
|
|
it("returns a usable span from getStartupTracer", () => {
|
|
const tracer = getStartupTracer();
|
|
const span = tracer.startSpan("unit-test");
|
|
|
|
expect(() => {
|
|
span.setAttribute("k", "v");
|
|
span.setStatus({ code: 0 });
|
|
span.end();
|
|
}).not.toThrow();
|
|
});
|
|
|
|
it("returns a tracer and a parent-context helper from getStartupTraceContext", () => {
|
|
const traceContext = getStartupTraceContext();
|
|
|
|
expect(() => traceContext.tracer.startSpan("unit-test").end()).not.toThrow();
|
|
// The helper never throws. It returns a parent token when the api resolves,
|
|
// or `undefined` from the no-op fallback when it does not.
|
|
expect(() => traceContext.contextWithSpan({})).not.toThrow();
|
|
});
|
|
});
|