Skip to content

Commit 2907367

Browse files
authored
Add Input Validation Tests for all ADOT JS User-Configurable Environment Variables (#102)
*Issue #, if available:* *Description of changes:* Add unit tests for user-configurable environment variables that are not currently tested: ``` OTEL_TRACES_SAMPLER OTEL_TRACES_SAMPLER_ARG OTEL_TRACES_EXPORTER OTEL_NODE_RESOURCE_DETECTORS OTEL_AWS_APPLICATION_SIGNALS_ENABLED OTEL_EXPORTER_OTLP_TRACES_PROTOCOL OTEL_EXPORTER_OTLP_METRICS_PROTOCOL OTEL_EXPORTER_OTLP_PROTOCOL OTEL_AWS_APPLICATION_SIGNALS_EXPORTER_ENDPOINT ``` By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.
1 parent c09824f commit 2907367

File tree

1 file changed

+225
-1
lines changed

1 file changed

+225
-1
lines changed

aws-distro-opentelemetry-node-autoinstrumentation/test/aws-opentelemetry-configurator.test.ts

Lines changed: 225 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@
44
import { Span, TraceFlags, Tracer } from '@opentelemetry/api';
55
import { OTLPMetricExporter as OTLPGrpcOTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-grpc';
66
import { OTLPMetricExporter as OTLPHttpOTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-http';
7+
import { OTLPTraceExporter as OTLPGrpcTraceExporter } from '@opentelemetry/exporter-trace-otlp-grpc';
8+
import { OTLPTraceExporter as OTLPHttpTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
9+
import { OTLPTraceExporter as OTLPProtoTraceExporter } from '@opentelemetry/exporter-trace-otlp-proto';
710
import { Resource } from '@opentelemetry/resources';
811
import { PushMetricExporter } from '@opentelemetry/sdk-metrics';
9-
import { ReadableSpan, SpanProcessor } from '@opentelemetry/sdk-trace-base';
12+
import { AlwaysOffSampler, ReadableSpan, SpanProcessor, TraceIdRatioBasedSampler } from '@opentelemetry/sdk-trace-base';
1013
import {
1114
AlwaysOnSampler,
1215
NodeTracerProvider,
@@ -222,6 +225,16 @@ describe('AwsOpenTelemetryConfiguratorTest', () => {
222225

223226
process.env.OTEL_AWS_APPLICATION_SIGNALS_ENABLED = 'False';
224227
expect(AwsOpentelemetryConfigurator.isApplicationSignalsEnabled()).toBeFalsy();
228+
process.env.OTEL_AWS_APPLICATION_SIGNALS_ENABLED = 'abcdefg';
229+
expect(AwsOpentelemetryConfigurator.isApplicationSignalsEnabled()).toBeFalsy();
230+
process.env.OTEL_AWS_APPLICATION_SIGNALS_ENABLED = 'True_abcdefg';
231+
expect(AwsOpentelemetryConfigurator.isApplicationSignalsEnabled()).toBeFalsy();
232+
process.env.OTEL_AWS_APPLICATION_SIGNALS_ENABLED = 'abcdefg_True';
233+
expect(AwsOpentelemetryConfigurator.isApplicationSignalsEnabled()).toBeFalsy();
234+
process.env.OTEL_AWS_APPLICATION_SIGNALS_ENABLED = '0';
235+
expect(AwsOpentelemetryConfigurator.isApplicationSignalsEnabled()).toBeFalsy();
236+
process.env.OTEL_AWS_APPLICATION_SIGNALS_ENABLED = '1';
237+
expect(AwsOpentelemetryConfigurator.isApplicationSignalsEnabled()).toBeFalsy();
225238
delete process.env.OTEL_AWS_APPLICATION_SIGNALS_ENABLED;
226239
expect(AwsOpentelemetryConfigurator.isApplicationSignalsEnabled()).toBeFalsy();
227240
});
@@ -294,6 +307,9 @@ describe('AwsOpenTelemetryConfiguratorTest', () => {
294307
});
295308

296309
it('ApplicationSignalsExporterProviderTest', () => {
310+
const DEFAULT_OTEL_EXPORTER_OTLP_PROTOCOL = process.env.OTEL_EXPORTER_OTLP_PROTOCOL;
311+
delete process.env.OTEL_EXPORTER_OTLP_METRICS_PROTOCOL;
312+
297313
// Check default protocol - HTTP, as specified by aws-distro-opentelemetry-node-autoinstrumentation's register.ts.
298314
let exporter: PushMetricExporter = ApplicationSignalsExporterProvider.Instance.createExporter();
299315
expect(exporter).toBeInstanceOf(OTLPHttpOTLPMetricExporter);
@@ -310,6 +326,61 @@ describe('AwsOpenTelemetryConfiguratorTest', () => {
310326
exporter = ApplicationSignalsExporterProvider.Instance.createExporter();
311327
expect(exporter).toBeInstanceOf(OTLPHttpOTLPMetricExporter);
312328
expect('http://localhost:4316/v1/metrics').toEqual((exporter as any)._otlpExporter.url);
329+
330+
// If for some reason, the env var is undefined (it shouldn't), overwrite protocol to gRPC.
331+
delete process.env.OTEL_EXPORTER_OTLP_PROTOCOL;
332+
exporter = ApplicationSignalsExporterProvider.Instance.createExporter();
333+
expect(exporter).toBeInstanceOf(OTLPGrpcOTLPMetricExporter);
334+
expect('localhost:4315').toEqual((exporter as any)._otlpExporter.url);
335+
336+
// Expect invalid protocol to throw error.
337+
process.env.OTEL_EXPORTER_OTLP_PROTOCOL = 'invalid_protocol';
338+
expect(() => ApplicationSignalsExporterProvider.Instance.createExporter()).toThrow();
339+
340+
// Cleanup
341+
process.env.OTEL_EXPORTER_OTLP_PROTOCOL = DEFAULT_OTEL_EXPORTER_OTLP_PROTOCOL;
342+
343+
// Repeat tests using OTEL_EXPORTER_OTLP_METRICS_PROTOCOL environment variable instead
344+
345+
// Check default protocol - HTTP, as specified by aws-distro-opentelemetry-node-autoinstrumentation's register.ts.
346+
exporter = ApplicationSignalsExporterProvider.Instance.createExporter();
347+
expect(exporter).toBeInstanceOf(OTLPHttpOTLPMetricExporter);
348+
expect('http://localhost:4316/v1/metrics').toEqual((exporter as any)._otlpExporter.url);
349+
350+
// Overwrite protocol to gRPC.
351+
process.env.OTEL_EXPORTER_OTLP_METRICS_PROTOCOL = 'grpc';
352+
exporter = ApplicationSignalsExporterProvider.Instance.createExporter();
353+
expect(exporter).toBeInstanceOf(OTLPGrpcOTLPMetricExporter);
354+
expect('localhost:4315').toEqual((exporter as any)._otlpExporter.url);
355+
356+
// Overwrite protocol back to HTTP.
357+
process.env.OTEL_EXPORTER_OTLP_METRICS_PROTOCOL = 'http/protobuf';
358+
exporter = ApplicationSignalsExporterProvider.Instance.createExporter();
359+
expect(exporter).toBeInstanceOf(OTLPHttpOTLPMetricExporter);
360+
expect('http://localhost:4316/v1/metrics').toEqual((exporter as any)._otlpExporter.url);
361+
362+
// Expect invalid protocol to throw error.
363+
process.env.OTEL_EXPORTER_OTLP_METRICS_PROTOCOL = 'invalid_protocol';
364+
expect(() => ApplicationSignalsExporterProvider.Instance.createExporter()).toThrow();
365+
366+
// Test custom URLs via OTEL_AWS_APPLICATION_SIGNALS_EXPORTER_ENDPOINT
367+
process.env.OTEL_AWS_APPLICATION_SIGNALS_EXPORTER_ENDPOINT = 'my_custom_endpoint';
368+
369+
// Overwrite protocol to gRPC, export to url "my_custom_endpoint"
370+
process.env.OTEL_EXPORTER_OTLP_METRICS_PROTOCOL = 'grpc';
371+
exporter = ApplicationSignalsExporterProvider.Instance.createExporter();
372+
expect(exporter).toBeInstanceOf(OTLPGrpcOTLPMetricExporter);
373+
expect('my_custom_endpoint').toEqual((exporter as any)._otlpExporter.url);
374+
375+
// Overwrite protocol back to HTTP, export to url "my_custom_endpoint"
376+
process.env.OTEL_EXPORTER_OTLP_METRICS_PROTOCOL = 'http/protobuf';
377+
exporter = ApplicationSignalsExporterProvider.Instance.createExporter();
378+
expect(exporter).toBeInstanceOf(OTLPHttpOTLPMetricExporter);
379+
expect('my_custom_endpoint').toEqual((exporter as any)._otlpExporter.url);
380+
381+
// Cleanup
382+
delete process.env.OTEL_EXPORTER_OTLP_METRICS_PROTOCOL;
383+
delete process.env.OTEL_AWS_APPLICATION_SIGNALS_EXPORTER_ENDPOINT;
313384
});
314385

315386
it('tests getSamplerProbabilityFromEnv() ratio out of bounds', () => {
@@ -411,4 +482,157 @@ describe('AwsOpenTelemetryConfiguratorTest', () => {
411482
expect(undefined).toEqual(process.env.OTEL_TRACES_EXPORTER);
412483
expect(undefined).toEqual(process.env.OTEL_METRICS_EXPORTER);
413484
}
485+
486+
it('OtelTracesSamplerInputValidationTest', () => {
487+
let config;
488+
489+
// Test that the samplers that should exist, do exist
490+
process.env.OTEL_TRACES_SAMPLER = 'always_off';
491+
config = new AwsOpentelemetryConfigurator([]).configure();
492+
expect(config.sampler).toBeInstanceOf(AlwaysOffSampler);
493+
494+
process.env.OTEL_TRACES_SAMPLER = 'always_on';
495+
config = new AwsOpentelemetryConfigurator([]).configure();
496+
expect(config.sampler).toBeInstanceOf(AlwaysOnSampler);
497+
498+
process.env.OTEL_TRACES_SAMPLER = 'parentbased_always_off';
499+
config = new AwsOpentelemetryConfigurator([]).configure();
500+
expect(config.sampler).toBeInstanceOf(ParentBasedSampler);
501+
502+
process.env.OTEL_TRACES_SAMPLER = 'parentbased_always_on';
503+
config = new AwsOpentelemetryConfigurator([]).configure();
504+
expect(config.sampler).toBeInstanceOf(ParentBasedSampler);
505+
506+
process.env.OTEL_TRACES_SAMPLER = 'parentbased_traceidratio';
507+
config = new AwsOpentelemetryConfigurator([]).configure();
508+
expect(config.sampler).toBeInstanceOf(ParentBasedSampler);
509+
510+
// Test invalid and out-of-bound cases for traceidratio sampler
511+
process.env.OTEL_TRACES_SAMPLER = 'traceidratio';
512+
config = new AwsOpentelemetryConfigurator([]).configure();
513+
expect(config.sampler).toBeInstanceOf(TraceIdRatioBasedSampler);
514+
process.env.OTEL_TRACES_SAMPLER_ARG = '0.5';
515+
config = new AwsOpentelemetryConfigurator([]).configure();
516+
expect((config.sampler as any)._ratio).toEqual(0.5);
517+
process.env.OTEL_TRACES_SAMPLER_ARG = '2';
518+
config = new AwsOpentelemetryConfigurator([]).configure();
519+
expect((config.sampler as any)._ratio).toEqual(1);
520+
process.env.OTEL_TRACES_SAMPLER_ARG = '-3';
521+
config = new AwsOpentelemetryConfigurator([]).configure();
522+
expect((config.sampler as any)._ratio).toEqual(1);
523+
process.env.OTEL_TRACES_SAMPLER_ARG = 'abc';
524+
config = new AwsOpentelemetryConfigurator([]).configure();
525+
expect((config.sampler as any)._ratio).toEqual(1);
526+
527+
// In-depth testing for 'xray' sampler arguments can be found in test case 'ImportXRaySamplerWhenSamplerArgsSet'
528+
process.env.OTEL_TRACES_SAMPLER = 'xray';
529+
config = new AwsOpentelemetryConfigurator([]).configure();
530+
expect(config.sampler).toBeInstanceOf(AwsXRayRemoteSampler);
531+
532+
// Invalid sampler cases
533+
process.env.OTEL_TRACES_SAMPLER = 'invalid_sampler';
534+
config = new AwsOpentelemetryConfigurator([]).configure();
535+
expect(config.sampler).toBeInstanceOf(AlwaysOnSampler);
536+
537+
process.env.OTEL_TRACES_SAMPLER = '123';
538+
config = new AwsOpentelemetryConfigurator([]).configure();
539+
expect(config.sampler).toBeInstanceOf(AlwaysOnSampler);
540+
541+
// Cleanup
542+
delete process.env.OTEL_TRACES_SAMPLER;
543+
});
544+
545+
it('OtelTraceExporterInputValidationTest', () => {
546+
process.env.OTEL_AWS_APPLICATION_SIGNALS_ENABLED = 'true';
547+
let config;
548+
549+
// Default scenario where no trace exporter is specified
550+
process.env.OTEL_TRACES_EXPORTER = 'none';
551+
config = new AwsOpentelemetryConfigurator([]).configure();
552+
expect((config.spanProcessors as any)[0]).toBeInstanceOf(AttributePropagatingSpanProcessor);
553+
expect((config.spanProcessors as any)[1]).toBeInstanceOf(AwsSpanMetricsProcessor);
554+
expect(config.spanProcessors?.length).toEqual(2);
555+
556+
// Scenario where otlp trace exporter is specified, adds one more exporter compared to default case
557+
process.env.OTEL_TRACES_EXPORTER = 'otlp';
558+
config = new AwsOpentelemetryConfigurator([]).configure();
559+
expect((config.spanProcessors as any)[0]._exporter.delegate).toBeInstanceOf(OTLPProtoTraceExporter);
560+
expect((config.spanProcessors as any)[1]).toBeInstanceOf(AttributePropagatingSpanProcessor);
561+
expect((config.spanProcessors as any)[2]).toBeInstanceOf(AwsSpanMetricsProcessor);
562+
expect(config.spanProcessors?.length).toEqual(3);
563+
564+
// Specify invalid exporter, same result as default scenario where no trace exporter is specified
565+
process.env.OTEL_TRACES_EXPORTER = 'invalid_exporter_name';
566+
config = new AwsOpentelemetryConfigurator([]).configure();
567+
expect((config.spanProcessors as any)[0]).toBeInstanceOf(AttributePropagatingSpanProcessor);
568+
expect((config.spanProcessors as any)[1]).toBeInstanceOf(AwsSpanMetricsProcessor);
569+
expect(config.spanProcessors?.length).toEqual(2);
570+
571+
// Cleanup
572+
delete process.env.OTEL_AWS_APPLICATION_SIGNALS_ENABLED;
573+
delete process.env.OTEL_TRACES_EXPORTER;
574+
});
575+
576+
it('ResourceDetectorInputValidationTest', () => {
577+
let config;
578+
process.env.OTEL_SERVICE_NAME = 'test_service_name';
579+
580+
// Default 2 attributes detected in test environment
581+
process.env.OTEL_NODE_RESOURCE_DETECTORS = 'container';
582+
config = new AwsOpentelemetryConfigurator([]).configure();
583+
expect(Object.keys((config.resource as any).attributes).length).toEqual(2);
584+
expect((config.resource as any).attributes['service.name']).toEqual('test_service_name');
585+
expect((config.resource as any).attributes['telemetry.auto.version'].endsWith('-aws')).toBeTruthy();
586+
587+
// Still default 2 attributes detected given invalid resource detectors
588+
process.env.OTEL_NODE_RESOURCE_DETECTORS = 'invalid_detector_1,invalid_detector_2';
589+
config = new AwsOpentelemetryConfigurator([]).configure();
590+
expect(Object.keys((config.resource as any).attributes).length).toEqual(2);
591+
expect((config.resource as any).attributes['service.name']).toEqual('test_service_name');
592+
expect((config.resource as any).attributes['telemetry.auto.version'].endsWith('-aws')).toBeTruthy();
593+
594+
// Still default 2 attributes detected given mix of valid and invalid resource detectors
595+
process.env.OTEL_NODE_RESOURCE_DETECTORS = 'container,invalid_detector_1,invalid_detector_2';
596+
config = new AwsOpentelemetryConfigurator([]).configure();
597+
expect(Object.keys((config.resource as any).attributes).length).toEqual(2);
598+
expect((config.resource as any).attributes['service.name']).toEqual('test_service_name');
599+
expect((config.resource as any).attributes['telemetry.auto.version'].endsWith('-aws')).toBeTruthy();
600+
601+
// Cleanup
602+
delete process.env.OTEL_SERVICE_NAME;
603+
delete process.env.OTEL_NODE_RESOURCE_DETECTORS;
604+
});
605+
606+
it('AwsSpanProcessorProviderTest', () => {
607+
let spanExporter;
608+
609+
// Test span exporter configurations via valid environment variables
610+
delete process.env.OTEL_EXPORTER_OTLP_TRACES_PROTOCOL;
611+
spanExporter = AwsSpanProcessorProvider.configureOtlp();
612+
expect(spanExporter).toBeInstanceOf(OTLPProtoTraceExporter);
613+
614+
process.env.OTEL_EXPORTER_OTLP_TRACES_PROTOCOL = 'grpc';
615+
spanExporter = AwsSpanProcessorProvider.configureOtlp();
616+
expect(spanExporter).toBeInstanceOf(OTLPGrpcTraceExporter);
617+
618+
process.env.OTEL_EXPORTER_OTLP_TRACES_PROTOCOL = 'http/json';
619+
spanExporter = AwsSpanProcessorProvider.configureOtlp();
620+
expect(spanExporter).toBeInstanceOf(OTLPHttpTraceExporter);
621+
622+
process.env.OTEL_EXPORTER_OTLP_TRACES_PROTOCOL = 'http/protobuf';
623+
spanExporter = AwsSpanProcessorProvider.configureOtlp();
624+
expect(spanExporter).toBeInstanceOf(OTLPProtoTraceExporter);
625+
626+
process.env.OTEL_EXPORTER_OTLP_TRACES_PROTOCOL = 'udp';
627+
spanExporter = AwsSpanProcessorProvider.configureOtlp();
628+
expect(spanExporter).toBeInstanceOf(OTLPUdpSpanExporter);
629+
630+
// Test that a default span exporter is configured via invalid environment variable
631+
process.env.OTEL_EXPORTER_OTLP_TRACES_PROTOCOL = 'invalid_protocol';
632+
spanExporter = AwsSpanProcessorProvider.configureOtlp();
633+
expect(spanExporter).toBeInstanceOf(OTLPProtoTraceExporter);
634+
635+
// Cleanup
636+
delete process.env.OTEL_EXPORTER_OTLP_TRACES_PROTOCOL;
637+
});
414638
});

0 commit comments

Comments
 (0)