UNPKG

autotel

Version:
324 lines (262 loc) 9.54 kB
import { describe, it, expect, beforeEach, afterEach } from 'vitest'; import { AlwaysOffSampler, AlwaysOnSampler, ParentBasedSampler, TraceIdRatioBasedSampler, } from '@opentelemetry/sdk-trace-base'; import { resolveOtelEnv, parseResourceAttributes, parseOtlpHeaders, createSamplerFromEnv, envToConfig, resolveConfigFromEnv, } from './env-config'; describe('env-config', () => { const originalEnv = process.env; beforeEach(() => { // Reset environment before each test process.env = { ...originalEnv }; }); afterEach(() => { // Restore original environment process.env = originalEnv; }); describe('resolveOtelEnv', () => { it('should resolve standard OTEL env vars', () => { process.env.OTEL_SERVICE_NAME = 'test-service'; process.env.OTEL_EXPORTER_OTLP_ENDPOINT = 'http://localhost:4318'; process.env.OTEL_EXPORTER_OTLP_PROTOCOL = 'http'; const env = resolveOtelEnv(); expect(env.OTEL_SERVICE_NAME).toBe('test-service'); expect(env.OTEL_EXPORTER_OTLP_ENDPOINT).toBe('http://localhost:4318'); expect(env.OTEL_EXPORTER_OTLP_PROTOCOL).toBe('http'); }); it('should return undefined for unset env vars', () => { const env = resolveOtelEnv(); expect(env.OTEL_SERVICE_NAME).toBeUndefined(); expect(env.OTEL_EXPORTER_OTLP_ENDPOINT).toBeUndefined(); }); it('should validate protocol enum', () => { process.env.OTEL_EXPORTER_OTLP_PROTOCOL = 'grpc'; const env = resolveOtelEnv(); expect(env.OTEL_EXPORTER_OTLP_PROTOCOL).toBe('grpc'); }); it('should resolve trace sampler env vars', () => { process.env.OTEL_TRACES_SAMPLER = 'traceidratio'; process.env.OTEL_TRACES_SAMPLER_ARG = '0.5'; const env = resolveOtelEnv(); expect(env.OTEL_TRACES_SAMPLER).toBe('traceidratio'); expect(env.OTEL_TRACES_SAMPLER_ARG).toBe('0.5'); }); }); describe('parseResourceAttributes', () => { it('should parse comma-separated key=value pairs', () => { const input = 'service.version=1.0.0,deployment.environment=production'; const result = parseResourceAttributes(input); expect(result).toEqual({ 'service.version': '1.0.0', 'deployment.environment': 'production', }); }); it('should handle single attribute', () => { const result = parseResourceAttributes('team=backend'); expect(result).toEqual({ team: 'backend' }); }); it('should handle empty string', () => { expect(parseResourceAttributes('')).toEqual({}); expect(parseResourceAttributes(' ')).toEqual({}); }); it('should handle undefined', () => { expect(parseResourceAttributes()).toEqual({}); }); it('should skip invalid pairs without =', () => { const result = parseResourceAttributes('valid=value,invalid,another=ok'); expect(result).toEqual({ valid: 'value', another: 'ok', }); }); it('should handle whitespace around keys and values', () => { const result = parseResourceAttributes(' key1 = value1 , key2 = value2 '); expect(result).toEqual({ key1: 'value1', key2: 'value2', }); }); it('should skip empty pairs', () => { const result = parseResourceAttributes('key1=value1,,key2=value2'); expect(result).toEqual({ key1: 'value1', key2: 'value2', }); }); it('should handle values with = in them (takes first = as delimiter)', () => { const result = parseResourceAttributes('key=value=with=equals'); expect(result).toEqual({ key: 'value=with=equals', }); }); }); describe('parseOtlpHeaders', () => { it('should parse comma-separated header pairs', () => { const input = 'api-key=secret123,x-custom-header=value'; const result = parseOtlpHeaders(input); expect(result).toEqual({ 'api-key': 'secret123', 'x-custom-header': 'value', }); }); it('should handle single header', () => { const result = parseOtlpHeaders('authorization=Bearer token'); expect(result).toEqual({ authorization: 'Bearer token' }); }); it('should handle empty string', () => { expect(parseOtlpHeaders('')).toEqual({}); expect(parseOtlpHeaders(' ')).toEqual({}); }); it('should handle undefined', () => { expect(parseOtlpHeaders()).toEqual({}); }); it('should skip invalid pairs', () => { const result = parseOtlpHeaders('valid=value,invalid,another=ok'); expect(result).toEqual({ valid: 'value', another: 'ok', }); }); it('should handle whitespace', () => { const result = parseOtlpHeaders(' key1 = value1 , key2 = value2 '); expect(result).toEqual({ key1: 'value1', key2: 'value2', }); }); }); describe('envToConfig', () => { it('should map OTEL_SERVICE_NAME to service', () => { const config = envToConfig({ OTEL_SERVICE_NAME: 'test-service', }); expect(config.service).toBe('test-service'); }); it('should map OTEL_EXPORTER_OTLP_ENDPOINT to endpoint', () => { const config = envToConfig({ OTEL_EXPORTER_OTLP_ENDPOINT: 'http://localhost:4318', }); expect(config.endpoint).toBe('http://localhost:4318'); }); it('should map OTEL_EXPORTER_OTLP_PROTOCOL to protocol', () => { const config = envToConfig({ OTEL_EXPORTER_OTLP_PROTOCOL: 'grpc', }); expect(config.protocol).toBe('grpc'); }); it('should parse OTEL_EXPORTER_OTLP_HEADERS', () => { const config = envToConfig({ OTEL_EXPORTER_OTLP_HEADERS: 'api-key=secret,x-custom=value', }); expect(config.headers).toEqual({ 'api-key': 'secret', 'x-custom': 'value', }); }); it('should parse OTEL_RESOURCE_ATTRIBUTES', () => { const config = envToConfig({ OTEL_RESOURCE_ATTRIBUTES: 'service.version=1.0.0,deployment.environment=prod', }); expect(config.resourceAttributes).toEqual({ 'service.version': '1.0.0', 'deployment.environment': 'prod', }); }); it('should return empty config for no env vars', () => { const config = envToConfig({}); expect(config).toEqual({}); }); it('should map OTEL_TRACES_SAMPLER to an SDK sampler', () => { const config = envToConfig({ OTEL_TRACES_SAMPLER: 'always_on', }); expect(config.otelSampler).toBeInstanceOf(AlwaysOnSampler); }); }); describe('createSamplerFromEnv', () => { it('supports always_on', () => { const sampler = createSamplerFromEnv({ OTEL_TRACES_SAMPLER: 'always_on', }); expect(sampler).toBeInstanceOf(AlwaysOnSampler); }); it('supports always_off', () => { const sampler = createSamplerFromEnv({ OTEL_TRACES_SAMPLER: 'always_off', }); expect(sampler).toBeInstanceOf(AlwaysOffSampler); }); it('supports traceidratio', () => { const sampler = createSamplerFromEnv({ OTEL_TRACES_SAMPLER: 'traceidratio', OTEL_TRACES_SAMPLER_ARG: '0.25', }); expect(sampler).toBeInstanceOf(TraceIdRatioBasedSampler); }); it('supports parentbased_traceidratio', () => { const sampler = createSamplerFromEnv({ OTEL_TRACES_SAMPLER: 'parentbased_traceidratio', OTEL_TRACES_SAMPLER_ARG: '0.25', }); expect(sampler).toBeInstanceOf(ParentBasedSampler); }); it('returns undefined for unsupported remote samplers', () => { const sampler = createSamplerFromEnv({ OTEL_TRACES_SAMPLER: 'jaeger_remote', }); expect(sampler).toBeUndefined(); }); }); describe('resolveConfigFromEnv', () => { it('should return config from env vars', () => { process.env.OTEL_SERVICE_NAME = 'test-service'; process.env.OTEL_EXPORTER_OTLP_ENDPOINT = 'http://localhost:4318'; const config = resolveConfigFromEnv(); expect(config.service).toBe('test-service'); expect(config.endpoint).toBe('http://localhost:4318'); }); it('should work with no env vars set', () => { const config = resolveConfigFromEnv(); expect(config).toEqual({}); }); it('should parse complex real-world scenario', () => { process.env.OTEL_SERVICE_NAME = 'my-api'; process.env.OTEL_EXPORTER_OTLP_ENDPOINT = 'https://api.honeycomb.io'; process.env.OTEL_EXPORTER_OTLP_HEADERS = 'x-honeycomb-team=abc123,x-honeycomb-dataset=production'; process.env.OTEL_RESOURCE_ATTRIBUTES = 'service.version=1.2.3,deployment.environment=production,team=backend'; process.env.OTEL_EXPORTER_OTLP_PROTOCOL = 'http'; const config = resolveConfigFromEnv(); expect(config).toEqual({ service: 'my-api', endpoint: 'https://api.honeycomb.io', protocol: 'http', headers: { 'x-honeycomb-team': 'abc123', 'x-honeycomb-dataset': 'production', }, resourceAttributes: { 'service.version': '1.2.3', 'deployment.environment': 'production', team: 'backend', }, }); }); it('should include otelSampler when OTEL_TRACES_SAMPLER is set', () => { process.env.OTEL_TRACES_SAMPLER = 'parentbased_always_off'; const config = resolveConfigFromEnv(); expect(config.otelSampler).toBeInstanceOf(ParentBasedSampler); }); }); });