Skip to content

Commit

Permalink
Add unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
nhulston committed Sep 27, 2024
1 parent 5469c4f commit d05eb4c
Show file tree
Hide file tree
Showing 5 changed files with 316 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<assembly fullname="amqmdnetstd" />
<assembly fullname="AWSSDK.Core" />
<assembly fullname="AWSSDK.DynamoDBv2" />
<assembly fullname="AWSSDK.EventBridge" />
<assembly fullname="AWSSDK.Kinesis" />
<assembly fullname="AWSSDK.SimpleNotificationService" />
<assembly fullname="AWSSDK.SQS" />
Expand Down Expand Up @@ -214,6 +215,7 @@
<assembly fullname="System.Data.SqlClient" />
<assembly fullname="System.Data.SQLite" />
<assembly fullname="System.Diagnostics.Debug">
<type fullname="System.Diagnostics.Debug" />
<type fullname="System.Diagnostics.Debugger" />
<type fullname="System.Diagnostics.DebuggerBrowsableAttribute" />
<type fullname="System.Diagnostics.DebuggerBrowsableState" />
Expand Down Expand Up @@ -546,6 +548,8 @@
<type fullname="System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute" />
<type fullname="System.Diagnostics.CodeAnalysis.NotNullWhenAttribute" />
<type fullname="System.Diagnostics.ConditionalAttribute" />
<type fullname="System.Diagnostics.Debug" />
<type fullname="System.Diagnostics.Debug/AssertInterpolatedStringHandler" />
<type fullname="System.Diagnostics.DebuggableAttribute" />
<type fullname="System.Diagnostics.DebuggableAttribute/DebuggingModes" />
<type fullname="System.Diagnostics.Debugger" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// <copyright file="AwsEventBridgeCommonTests.cs" company="Datadog">
// 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.
// </copyright>

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<PutEventsRequestEntry>
{
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<PutEventsRequestEntry>()).Should().BeNull();

var emptyEntries = new List<PutEventsRequestEntry>
{
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<IAgentWriter>();
var samplerMock = new Mock<ITraceSampler>();

return new Tracer(settings, writerMock.Object, samplerMock.Object, scopeManager: null, statsd: null);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
// <copyright file="ContextPropagationTests.cs" company="Datadog">
// 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.
// </copyright>

#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<IPutEventsRequest>();

ContextPropagation.InjectTracingContext(proxy, _spanContext);

var entries = (IList)proxy.Entries.Value!;
entries.Count.Should().Be(1);
var entry = (PutEventsRequestEntry)entries[0]!;

var detail = JsonConvert.DeserializeObject<Dictionary<string, object>>(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<Dictionary<string, string>>(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<IPutEventsRequest>();

ContextPropagation.InjectTracingContext(proxy, _spanContext);

var entries = (IList)proxy.Entries.Value!;
entries.Count.Should().Be(1);
var entry = (PutEventsRequestEntry)entries[0]!;

var detail = JsonConvert.DeserializeObject<Dictionary<string, object>>(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<Dictionary<string, string>>(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<IPutEventsRequest>();

ContextPropagation.InjectTracingContext(proxy, _spanContext);

var entries = (IList)proxy.Entries.Value!;
entries.Count.Should().Be(1);
var entry = (PutEventsRequestEntry)entries[0]!;

var detail = JsonConvert.DeserializeObject<Dictionary<string, object>>(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<Dictionary<string, string>>(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<IPutEventsRequest>();

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<IPutEventsRequest>();

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<Dictionary<string, object>>(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<Dictionary<string, string>>(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<IPutEventsRequest>();

ContextPropagation.InjectTracingContext(proxy, _spanContext);

var entries = (IList)proxy.Entries.Value!;
entries.Count.Should().Be(1);
var entry = (PutEventsRequestEntry)entries[0]!;

var detail = JsonConvert.DeserializeObject<Dictionary<string, object>>(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<Dictionary<string, string>>(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<PutEventsRequestEntry> entries)
{
return new PutEventsRequest { Entries = entries };
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
<PackageReference Include="AWSSDK.DynamoDBv2" Version="3.7.201.14" />
<PackageReference Include="AWSSDK.Kinesis" Version="3.7.200.21" />
<PackageReference Include="AWSSDK.SimpleNotificationService" Version="3.7.101.88" />
<PackageReference Include="AWSSDK.EventBridge" Version="3.7.303.30" />
<PackageReference Include="Confluent.Kafka" Version="1.4.3" />
<PackageReference Include="log4net" Version="$(Log4NetVersion)" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,5 +153,20 @@ public void CreateAwsSnsTagsReturnsCorrectImplementation(object schemaVersionObj
var namingSchema = new NamingSchema(schemaVersion, peerServiceTagsEnabled, removeClientServiceNamesEnabled, DefaultServiceName, _mappings, new Dictionary<string, string>());
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<string, string>());
namingSchema.Messaging.CreateAwsEventBridgeTags("spanKind").Should().BeOfType(expectedType);
}
}
}

0 comments on commit d05eb4c

Please sign in to comment.