From d05eb4cd88dbfa00906a26b1b495868604a7032c Mon Sep 17 00:00:00 2001 From: Nicholas Hulston Date: Thu, 26 Sep 2024 17:00:29 -0400 Subject: [PATCH] Add unit tests --- .../build/Datadog.Trace.Trimming.xml | 4 + .../EventBridge/AwsEventBridgeCommonTests.cs | 66 +++++ .../EventBridge/ContextPropagationTests.cs | 230 ++++++++++++++++++ ...dog.Trace.ClrProfiler.Managed.Tests.csproj | 1 + .../Schema/MessagingSchemaTests.cs | 15 ++ 5 files changed, 316 insertions(+) create mode 100644 tracer/test/Datadog.Trace.ClrProfiler.Managed.Tests/AutoInstrumentation/AWS/EventBridge/AwsEventBridgeCommonTests.cs create mode 100644 tracer/test/Datadog.Trace.ClrProfiler.Managed.Tests/AutoInstrumentation/AWS/EventBridge/ContextPropagationTests.cs diff --git a/tracer/src/Datadog.Trace.Trimming/build/Datadog.Trace.Trimming.xml b/tracer/src/Datadog.Trace.Trimming/build/Datadog.Trace.Trimming.xml index b4ea1f6bddfb..1aa3e3825183 100644 --- a/tracer/src/Datadog.Trace.Trimming/build/Datadog.Trace.Trimming.xml +++ b/tracer/src/Datadog.Trace.Trimming/build/Datadog.Trace.Trimming.xml @@ -4,6 +4,7 @@ + @@ -214,6 +215,7 @@ + @@ -546,6 +548,8 @@ + + diff --git a/tracer/test/Datadog.Trace.ClrProfiler.Managed.Tests/AutoInstrumentation/AWS/EventBridge/AwsEventBridgeCommonTests.cs b/tracer/test/Datadog.Trace.ClrProfiler.Managed.Tests/AutoInstrumentation/AWS/EventBridge/AwsEventBridgeCommonTests.cs new file mode 100644 index 000000000000..8a121af9f1ff --- /dev/null +++ b/tracer/test/Datadog.Trace.ClrProfiler.Managed.Tests/AutoInstrumentation/AWS/EventBridge/AwsEventBridgeCommonTests.cs @@ -0,0 +1,66 @@ +// +// Unless explicitly stated otherwise all files in this repository are licensed under the Apache 2 License. +// This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2017 Datadog, Inc. +// + +using System.Collections.Generic; +using System.Collections.Specialized; +using Amazon.EventBridge.Model; +using Datadog.Trace.Agent; +using Datadog.Trace.ClrProfiler.AutoInstrumentation.AWS.EventBridge; +using Datadog.Trace.Configuration; +using Datadog.Trace.Sampling; +using FluentAssertions; +using Moq; +using Xunit; + +namespace Datadog.Trace.ClrProfiler.Managed.Tests.AutoInstrumentation.AWS.EventBridge; + +public class AwsEventBridgeCommonTests +{ + [Fact] + public void GetCorrectBusName() + { + var entries = new List + { + new() { EventBusName = "test-bus-1" }, + new() { EventBusName = "test-bus-2" }, + new() { EventBusName = string.Empty }, + new() { EventBusName = null } + }; + + var result = AwsEventBridgeCommon.GetBusName(entries); + result.Should().Be("test-bus-1"); + + AwsEventBridgeCommon.GetBusName(null).Should().BeNull(); + AwsEventBridgeCommon.GetBusName(new List()).Should().BeNull(); + + var emptyEntries = new List + { + new() { EventBusName = string.Empty }, + new() { EventBusName = null } + }; + AwsEventBridgeCommon.GetBusName(emptyEntries).Should().BeNull(); + } + + [Fact] + public void GetCorrectOperationName() + { + var tracerV0 = GetTracer("v0"); + AwsEventBridgeCommon.GetOperationName(tracerV0).Should().Be("eventbridge.request"); + + var tracerV1 = GetTracer("v1"); + AwsEventBridgeCommon.GetOperationName(tracerV1).Should().Be("aws.eventbridge.send"); + } + + private static Tracer GetTracer(string schemaVersion) + { + var collection = new NameValueCollection { { ConfigurationKeys.MetadataSchemaVersion, schemaVersion } }; + IConfigurationSource source = new NameValueConfigurationSource(collection); + var settings = new TracerSettings(source); + var writerMock = new Mock(); + var samplerMock = new Mock(); + + return new Tracer(settings, writerMock.Object, samplerMock.Object, scopeManager: null, statsd: null); + } +} diff --git a/tracer/test/Datadog.Trace.ClrProfiler.Managed.Tests/AutoInstrumentation/AWS/EventBridge/ContextPropagationTests.cs b/tracer/test/Datadog.Trace.ClrProfiler.Managed.Tests/AutoInstrumentation/AWS/EventBridge/ContextPropagationTests.cs new file mode 100644 index 000000000000..748c66a5f8a4 --- /dev/null +++ b/tracer/test/Datadog.Trace.ClrProfiler.Managed.Tests/AutoInstrumentation/AWS/EventBridge/ContextPropagationTests.cs @@ -0,0 +1,230 @@ +// +// Unless explicitly stated otherwise all files in this repository are licensed under the Apache 2 License. +// This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2017 Datadog, Inc. +// + +#nullable enable + +using System.Collections; +using System.Collections.Generic; +using Amazon.EventBridge.Model; +using Datadog.Trace.ClrProfiler.AutoInstrumentation.AWS.EventBridge; +using Datadog.Trace.DuckTyping; +using Datadog.Trace.Vendors.Newtonsoft.Json; +using FluentAssertions; +using Xunit; + +namespace Datadog.Trace.ClrProfiler.Managed.Tests.AutoInstrumentation.AWS.EventBridge; + +public class ContextPropagationTests +{ + private const string DatadogKey = "_datadog"; + private const string StartTimeKey = "x-datadog-start-time"; + private const string ResourceNameKey = "x-datadog-resource-name"; + private const string EventBusName = "test-event-bus"; + + private readonly SpanContext _spanContext; + + public ContextPropagationTests() + { + const long upper = 1234567890123456789; + const ulong lower = 9876543210987654321; + + var traceId = new TraceId(upper, lower); + const ulong spanId = 6766950223540265769; + _spanContext = new SpanContext(traceId, spanId, 1, "test-eventbridge", "serverless"); + } + + [Fact] + public void InjectTracingContext_EmptyDetail_AddsTraceContext() + { + var request = GeneratePutEventsRequest([ + new PutEventsRequestEntry { Detail = "{}", EventBusName = EventBusName } + ]); + + var proxy = request.DuckCast(); + + ContextPropagation.InjectTracingContext(proxy, _spanContext); + + var entries = (IList)proxy.Entries.Value!; + entries.Count.Should().Be(1); + var entry = (PutEventsRequestEntry)entries[0]!; + + var detail = JsonConvert.DeserializeObject>(entry.Detail); + detail.Should().NotBeNull(); + detail!.Count.Should().Be(1); + + var extracted = detail.TryGetValue(DatadogKey, out var datadogObject); + extracted.Should().BeTrue(); + datadogObject.Should().NotBeNull(); + + var jsonString = JsonConvert.SerializeObject(datadogObject); + var extractedTraceContext = JsonConvert.DeserializeObject>(jsonString); + + extractedTraceContext!["x-datadog-parent-id"].Should().Be(_spanContext.SpanId.ToString()); + extractedTraceContext["x-datadog-trace-id"].Should().Be(_spanContext.TraceId.ToString()); + extractedTraceContext[ResourceNameKey].Should().Be(EventBusName); + extractedTraceContext.Should().ContainKey(StartTimeKey); + extractedTraceContext[StartTimeKey].Should().NotBeNullOrEmpty(); + } + + [Fact] + public void InjectTracingContext_ExistingDetail_AddsTraceContext() + { + var request = GeneratePutEventsRequest([ + new PutEventsRequestEntry { Detail = "{\"foo\":\"bar\"}", EventBusName = EventBusName } + ]); + + var proxy = request.DuckCast(); + + ContextPropagation.InjectTracingContext(proxy, _spanContext); + + var entries = (IList)proxy.Entries.Value!; + entries.Count.Should().Be(1); + var entry = (PutEventsRequestEntry)entries[0]!; + + var detail = JsonConvert.DeserializeObject>(entry.Detail); + detail.Should().NotBeNull(); + detail!.Count.Should().Be(2); + detail["foo"].Should().Be("bar"); + + var extracted = detail.TryGetValue(DatadogKey, out var datadogObject); + extracted.Should().BeTrue(); + datadogObject.Should().NotBeNull(); + + var jsonString = JsonConvert.SerializeObject(datadogObject); + var extractedTraceContext = JsonConvert.DeserializeObject>(jsonString); + + extractedTraceContext!["x-datadog-parent-id"].Should().Be(_spanContext.SpanId.ToString()); + extractedTraceContext["x-datadog-trace-id"].Should().Be(_spanContext.TraceId.ToString()); + extractedTraceContext[ResourceNameKey].Should().Be(EventBusName); + extractedTraceContext.Should().ContainKey(StartTimeKey); + extractedTraceContext[StartTimeKey].Should().NotBeNullOrEmpty(); + } + + [Fact] + public void InjectTracingContext_NullDetail_AddsTraceContext() + { + var request = GeneratePutEventsRequest([ + new PutEventsRequestEntry { Detail = null, EventBusName = EventBusName } + ]); + + var proxy = request.DuckCast(); + + ContextPropagation.InjectTracingContext(proxy, _spanContext); + + var entries = (IList)proxy.Entries.Value!; + entries.Count.Should().Be(1); + var entry = (PutEventsRequestEntry)entries[0]!; + + var detail = JsonConvert.DeserializeObject>(entry.Detail); + detail.Should().NotBeNull(); + detail!.Count.Should().Be(1); + + var extracted = detail.TryGetValue(DatadogKey, out var datadogObject); + extracted.Should().BeTrue(); + datadogObject.Should().NotBeNull(); + + var jsonString = JsonConvert.SerializeObject(datadogObject); + var extractedTraceContext = JsonConvert.DeserializeObject>(jsonString); + + extractedTraceContext!["x-datadog-parent-id"].Should().Be(_spanContext.SpanId.ToString()); + extractedTraceContext["x-datadog-trace-id"].Should().Be(_spanContext.TraceId.ToString()); + extractedTraceContext[ResourceNameKey].Should().Be(EventBusName); + extractedTraceContext.Should().ContainKey(StartTimeKey); + extractedTraceContext[StartTimeKey].Should().NotBeNullOrEmpty(); + } + + [Fact] + public void InjectTracingContext_InvalidDetail_DoesNotAddTraceContext() + { + var request = GeneratePutEventsRequest([ + new PutEventsRequestEntry { Detail = "{invalid json", EventBusName = EventBusName } + ]); + + var proxy = request.DuckCast(); + + ContextPropagation.InjectTracingContext(proxy, _spanContext); + + var entries = (IList)proxy.Entries.Value!; + entries.Count.Should().Be(1); + var entry = (PutEventsRequestEntry)entries[0]!; + + entry.Detail.Should().Be("{invalid json"); + } + + [Fact] + public void InjectTracingContext_MultipleEntries_AddsTraceContextToAll() + { + var request = GeneratePutEventsRequest([ + new PutEventsRequestEntry { Detail = "{}", EventBusName = EventBusName }, + new PutEventsRequestEntry { Detail = "{\"foo\":\"bar\"}", EventBusName = EventBusName } + ]); + + var proxy = request.DuckCast(); + + ContextPropagation.InjectTracingContext(proxy, _spanContext); + + var entries = (IList)proxy.Entries.Value!; + entries.Count.Should().Be(2); + + foreach (var entry in entries) + { + var typedEntry = entry as PutEventsRequestEntry; + var detail = JsonConvert.DeserializeObject>(typedEntry!.Detail); + detail.Should().NotBeNull(); + detail!.Should().ContainKey(DatadogKey); + + var extracted = detail!.TryGetValue(DatadogKey, out var datadogObject); + extracted.Should().BeTrue(); + datadogObject.Should().NotBeNull(); + + var jsonString = JsonConvert.SerializeObject(datadogObject); + var extractedTraceContext = JsonConvert.DeserializeObject>(jsonString); + + extractedTraceContext!["x-datadog-parent-id"].Should().Be(_spanContext.SpanId.ToString()); + extractedTraceContext["x-datadog-trace-id"].Should().Be(_spanContext.TraceId.ToString()); + extractedTraceContext[ResourceNameKey].Should().Be(EventBusName); + extractedTraceContext.Should().ContainKey(StartTimeKey); + extractedTraceContext[StartTimeKey].Should().NotBeNullOrEmpty(); + } + } + + [Fact] + public void InjectTracingContext_NullEventBusName_OmitsResourceName() + { + var request = GeneratePutEventsRequest([ + new PutEventsRequestEntry { Detail = "{}", EventBusName = null } + ]); + + var proxy = request.DuckCast(); + + ContextPropagation.InjectTracingContext(proxy, _spanContext); + + var entries = (IList)proxy.Entries.Value!; + entries.Count.Should().Be(1); + var entry = (PutEventsRequestEntry)entries[0]!; + + var detail = JsonConvert.DeserializeObject>(entry.Detail); + detail.Should().NotBeNull(); + detail!.Count.Should().Be(1); + + var extracted = detail.TryGetValue(DatadogKey, out var datadogObject); + extracted.Should().BeTrue(); + datadogObject.Should().NotBeNull(); + + var jsonString = JsonConvert.SerializeObject(datadogObject); + var extractedTraceContext = JsonConvert.DeserializeObject>(jsonString); + + extractedTraceContext!["x-datadog-parent-id"].Should().Be(_spanContext.SpanId.ToString()); + extractedTraceContext["x-datadog-trace-id"].Should().Be(_spanContext.TraceId.ToString()); + extractedTraceContext.Should().NotContainKey(ResourceNameKey); + extractedTraceContext.Should().ContainKey(StartTimeKey); + extractedTraceContext[StartTimeKey].Should().NotBeNullOrEmpty(); + } + + private static PutEventsRequest GeneratePutEventsRequest(List entries) + { + return new PutEventsRequest { Entries = entries }; + } +} diff --git a/tracer/test/Datadog.Trace.ClrProfiler.Managed.Tests/Datadog.Trace.ClrProfiler.Managed.Tests.csproj b/tracer/test/Datadog.Trace.ClrProfiler.Managed.Tests/Datadog.Trace.ClrProfiler.Managed.Tests.csproj index 94471112ab19..b36cae25af51 100644 --- a/tracer/test/Datadog.Trace.ClrProfiler.Managed.Tests/Datadog.Trace.ClrProfiler.Managed.Tests.csproj +++ b/tracer/test/Datadog.Trace.ClrProfiler.Managed.Tests/Datadog.Trace.ClrProfiler.Managed.Tests.csproj @@ -18,6 +18,7 @@ + diff --git a/tracer/test/Datadog.Trace.Tests/Configuration/Schema/MessagingSchemaTests.cs b/tracer/test/Datadog.Trace.Tests/Configuration/Schema/MessagingSchemaTests.cs index 1ab641a248c0..8be2e81ad044 100644 --- a/tracer/test/Datadog.Trace.Tests/Configuration/Schema/MessagingSchemaTests.cs +++ b/tracer/test/Datadog.Trace.Tests/Configuration/Schema/MessagingSchemaTests.cs @@ -153,5 +153,20 @@ public void CreateAwsSnsTagsReturnsCorrectImplementation(object schemaVersionObj var namingSchema = new NamingSchema(schemaVersion, peerServiceTagsEnabled, removeClientServiceNamesEnabled, DefaultServiceName, _mappings, new Dictionary()); namingSchema.Messaging.CreateAwsSnsTags("spanKind").Should().BeOfType(expectedType); } + + [Theory] + [MemberData(nameof(GetAllConfigs))] + public void CreateAwsEventBridgeTagsReturnsCorrectImplementation(object schemaVersionObject, bool peerServiceTagsEnabled, bool removeClientServiceNamesEnabled) + { + var schemaVersion = (SchemaVersion)schemaVersionObject; // Unbox SchemaVersion, which is only defined internally + var expectedType = schemaVersion switch + { + SchemaVersion.V0 when peerServiceTagsEnabled == false => typeof(AwsEventBridgeTags), + _ => typeof(AwsEventBridgeV1Tags), + }; + + var namingSchema = new NamingSchema(schemaVersion, peerServiceTagsEnabled, removeClientServiceNamesEnabled, DefaultServiceName, _mappings, new Dictionary()); + namingSchema.Messaging.CreateAwsEventBridgeTags("spanKind").Should().BeOfType(expectedType); + } } }