Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Non-serializable data ('System.Object[]') found in tests #5089

Merged
merged 2 commits into from
Feb 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -55,17 +55,24 @@ public void CanGetIntegrationIdFromInstrumentAttributeWithMultipleTypeNames()
info.Value.Should().Be(IntegrationId.MongoDb);
}

[Theory]
[InlineData(typeof(System.Data.SqlClient.SqlCommand), (int)IntegrationId.SqlClient)]
[InlineData(typeof(System.Data.SQLite.SQLiteCommand), (int)IntegrationId.Sqlite)]
public void CanGetIntegrationIdForAdoNetAttribute(Type targetType, int expected)
[Fact]
public void CanGetIntegrationIdForAdoNetAttribute()
{
var integrationType = typeof(CommandExecuteNonQueryIntegration).FullName;
var types = new[]
{
(typeof(System.Data.SqlClient.SqlCommand), (int)IntegrationId.SqlClient),
(typeof(System.Data.SQLite.SQLiteCommand), (int)IntegrationId.Sqlite),
};

var info = InstrumentationDefinitions.GetIntegrationId(integrationType, targetType);
foreach (var (targetType, expected) in types)
{
var integrationType = typeof(CommandExecuteNonQueryIntegration).FullName;

info.Should().NotBeNull();
info.Value.Should().Be((IntegrationId)expected);
var info = InstrumentationDefinitions.GetIntegrationId(integrationType, targetType);

info.Should().NotBeNull();
info.Value.Should().Be((IntegrationId)expected);
}
}

[Fact]
Expand Down
110 changes: 58 additions & 52 deletions tracer/test/Datadog.Trace.Tests/Logging/ExceptionRedactorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,54 +56,60 @@ public void RedactStackTrace_IsEmptyForEmptyException()
redacted.Should().BeEmpty();
}

[Theory]
[MemberData(nameof(TestData.MethodsToRedact), MemberType = typeof(TestData))]
public void RedactStackTrace_RedactsUserCode(object method)
[Fact]
public void RedactStackTrace_RedactsUserCode()
{
var methodBase = method.Should().NotBeNull().And.BeAssignableTo<MethodBase>().Subject;
var stackFrame = new TestStackFrame(methodBase);
var stackTrace = new StackTrace(stackFrame);
foreach (var method in TestData.MethodsToRedact())
{
var methodBase = method.Should().NotBeNull().And.BeAssignableTo<MethodBase>().Subject;
var stackFrame = new TestStackFrame(methodBase);
var stackTrace = new StackTrace(stackFrame);

var sb = new StringBuilder();
ExceptionRedactor.RedactStackTrace(sb, stackTrace);
var redacted = sb.ToString();
var sb = new StringBuilder();
ExceptionRedactor.RedactStackTrace(sb, stackTrace);
var redacted = sb.ToString();

redacted.Should().Be($"{ExceptionRedactor.StackFrameAt}{ExceptionRedactor.Redacted}" + Environment.NewLine);
redacted.Should().Be($"{ExceptionRedactor.StackFrameAt}{ExceptionRedactor.Redacted}" + Environment.NewLine);
}
}

[Theory]
[MemberData(nameof(TestData.MethodsToNotRedact), MemberType = typeof(TestData))]
public void RedactStackTrace_DoesNotRedactBclAndDatadog(object method)
[Fact]
public void RedactStackTrace_DoesNotRedactBclAndDatadog()
{
var methodBase = method.Should().NotBeNull().And.BeAssignableTo<MethodBase>().Subject;
var stackFrame = new TestStackFrame(methodBase);
var stackTrace = new StackTrace(stackFrame);
foreach (var method in TestData.MethodsToNotRedact())
{
var methodBase = method.Should().NotBeNull().And.BeAssignableTo<MethodBase>().Subject;
var stackFrame = new TestStackFrame(methodBase);
var stackTrace = new StackTrace(stackFrame);

var sb = new StringBuilder();
ExceptionRedactor.RedactStackTrace(sb, stackTrace);
var redacted = sb.ToString();
var sb = new StringBuilder();
ExceptionRedactor.RedactStackTrace(sb, stackTrace);
var redacted = sb.ToString();

redacted.Should().Be(stackTrace.ToString());
redacted.Should().Be(stackTrace.ToString());
}
}

[Theory]
[MemberData(nameof(TestData.ToStringTestData), MemberType = typeof(TestData))]
public void RedactStackTrace_ContainsExpectedStrings(StackTrace stackTrace, string expectedToString)
[Fact]
public void RedactStackTrace_ContainsExpectedStrings()
{
var sb = new StringBuilder();
ExceptionRedactor.RedactStackTrace(sb, stackTrace);
var redacted = sb.ToString();

if (expectedToString.Length == 0)
foreach (var (stackTrace, expectedToString) in TestData.ToStringTestData())
{
redacted.Should().BeEmpty();
return;
}
var sb = new StringBuilder();
ExceptionRedactor.RedactStackTrace(sb, stackTrace);
var redacted = sb.ToString();

redacted.Should().Contain(expectedToString);
redacted.Should().EndWith(Environment.NewLine);
if (expectedToString.Length == 0)
{
redacted.Should().BeEmpty();
return;
}

HasExpectedFrames(stackTrace, redacted);
redacted.Should().Contain(expectedToString);
redacted.Should().EndWith(Environment.NewLine);

HasExpectedFrames(stackTrace, redacted);
}
}

[Fact]
Expand Down Expand Up @@ -165,18 +171,18 @@ private static Exception InvokeException()

public static class TestData
{
public static TheoryData<object> MethodsToRedact() => new()
{
public static List<object> MethodsToRedact() =>
[
typeof(AssertionExtensions).GetMethod(nameof(AssertionExtensions.Should), types: new[] { typeof(object) }),
typeof(Xunit.Assert).GetMethod(nameof(Assert.False), types: new[] { typeof(bool) }),
typeof(VerifyTests.VerifierSettings).GetMethod(nameof(VerifyTests.VerifierSettings.DisableClipboard)),
typeof(VerifyTests.VerifierSettings).GetProperty(nameof(VerifyTests.VerifierSettings.StrictJson))?.GetMethod,
typeof(VerifyTests.VerifierSettings).GetProperty(nameof(VerifyTests.VerifierSettings.StrictJson))?.SetMethod,
typeof(VerifyTests.SerializationSettings).GetConstructor(Array.Empty<Type>()),
};
];

public static TheoryData<object> MethodsToNotRedact() => new()
{
public static List<object> MethodsToNotRedact() =>
[
typeof(ExceptionRedactorTests.TestData).GetMethod(nameof(NoParameters)),
typeof(Datadog.Trace.Tracer).GetMethod(nameof(Tracer.UnsafeSetTracerInstance), BindingFlags.Static | BindingFlags.NonPublic),
typeof(Datadog.Trace.Tracer).GetProperty(nameof(Tracer.Instance))?.GetMethod,
Expand All @@ -198,19 +204,19 @@ public static class TestData
typeof(Microsoft.CodeAnalysis.DiagnosticDescriptor).GetProperty(nameof(Microsoft.CodeAnalysis.DiagnosticDescriptor.Id))?.GetMethod,
typeof(Microsoft.Extensions.DependencyInjection.ServiceCollection).GetMethod(nameof(Microsoft.Extensions.DependencyInjection.ServiceCollection.Contains), types: new[] { typeof(Microsoft.Extensions.DependencyInjection.ServiceDescriptor) }),
#endif
};

public static IEnumerable<object[]> ToStringTestData()
{
yield return new object[] { new StackTrace(InvokeException()), "Datadog.Trace.Tests.Logging.ExceptionRedactorTests.ThrowException()" };
yield return new object[] { new StackTrace(new Exception()), string.Empty };
yield return new object[] { NoParameters(), "Datadog.Trace.Tests.Logging.ExceptionRedactorTests.TestData.NoParameters()" };
yield return new object[] { OneParameter(1), "Datadog.Trace.Tests.Logging.ExceptionRedactorTests.TestData.OneParameter(Int32 x)" };
yield return new object[] { TwoParameters(1, null), "Datadog.Trace.Tests.Logging.ExceptionRedactorTests.TestData.TwoParameters(Int32 x, String y)" };
yield return new object[] { Generic<int>(), "Datadog.Trace.Tests.Logging.ExceptionRedactorTests.TestData.Generic[T]()" };
yield return new object[] { Generic<int, string>(), "Datadog.Trace.Tests.Logging.ExceptionRedactorTests.TestData.Generic[T1,T2]()" };
yield return new object[] { new ClassWithConstructor().StackTrace, "Datadog.Trace.Tests.Logging.ExceptionRedactorTests.TestData.ClassWithConstructor..ctor()" };
}
];

public static List<(StackTrace StackTrace, string ExpectedToString)> ToStringTestData() =>
[
(new StackTrace(InvokeException()), "Datadog.Trace.Tests.Logging.ExceptionRedactorTests.ThrowException()"),
(new StackTrace(new Exception()), string.Empty),
(NoParameters(), "Datadog.Trace.Tests.Logging.ExceptionRedactorTests.TestData.NoParameters()"),
(OneParameter(1), "Datadog.Trace.Tests.Logging.ExceptionRedactorTests.TestData.OneParameter(Int32 x)"),
(TwoParameters(1, null), "Datadog.Trace.Tests.Logging.ExceptionRedactorTests.TestData.TwoParameters(Int32 x, String y)"),
(Generic<int>(), "Datadog.Trace.Tests.Logging.ExceptionRedactorTests.TestData.Generic[T]()"),
(Generic<int, string>(), "Datadog.Trace.Tests.Logging.ExceptionRedactorTests.TestData.Generic[T1,T2]()"),
(new ClassWithConstructor().StackTrace, "Datadog.Trace.Tests.Logging.ExceptionRedactorTests.TestData.ClassWithConstructor..ctor()"),
];

[MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
public static unsafe StackTrace FunctionPointerParameter(delegate*<void> x) => new();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.Collections.Generic;
using Datadog.Trace.Activity;
using Datadog.Trace.Tagging;
using Datadog.Trace.TestHelpers;
using Xunit;

namespace Datadog.Trace.Tests
Expand All @@ -15,37 +16,36 @@ namespace Datadog.Trace.Tests
public class OpenTelemetryOperationNameMapperTests
{
// Note: These test cases were copy/pasted from parametric tests (with some find/replace to make it work here)
public static IEnumerable<object[]> NameData =>
new List<object[]>
{
// expected_operation_name, span_kind, tags_related_to_operation_name
new object[] { "http.server.request", SpanKinds.Server, new Dictionary<string, string>() { { "http.request.method", "GET" } } },
new object[] { "http.client.request", SpanKinds.Client, new Dictionary<string, string>() { { "http.request.method", "GET" } } },
new object[] { "redis.query", SpanKinds.Client, new Dictionary<string, string>() { { "db.system", "Redis" } } },
new object[] { "kafka.receive", SpanKinds.Client, new Dictionary<string, string>() { { "messaging.system", "Kafka" }, { "messaging.operation", "Receive" } } },
new object[] { "kafka.receive", SpanKinds.Server, new Dictionary<string, string>() { { "messaging.system", "Kafka" }, { "messaging.operation", "Receive" } } },
new object[] { "kafka.receive", SpanKinds.Producer, new Dictionary<string, string>() { { "messaging.system", "Kafka" }, { "messaging.operation", "Receive" } } },
new object[] { "kafka.receive", SpanKinds.Consumer, new Dictionary<string, string>() { { "messaging.system", "Kafka" }, { "messaging.operation", "Receive" } } },
new object[] { "aws.s3.request", SpanKinds.Client, new Dictionary<string, string>() { { "rpc.system", "aws-api" }, { "rpc.service", "S3" } } },
new object[] { "aws.client.request", SpanKinds.Client, new Dictionary<string, string>() { { "rpc.system", "aws-api" } } },
new object[] { "grpc.client.request", SpanKinds.Client, new Dictionary<string, string>() { { "rpc.system", "GRPC" } } },
new object[] { "grpc.server.request", SpanKinds.Server, new Dictionary<string, string>() { { "rpc.system", "GRPC" } } },
new object[] { "aws.my-function.invoke", SpanKinds.Client, new Dictionary<string, string>() { { "faas.invoked_provider", "aws" }, { "faas.invoked_name", "My-Function" } } },
new object[] { "datasource.invoke", SpanKinds.Server, new Dictionary<string, string>() { { "faas.trigger", "Datasource" } } },
new object[] { "graphql.server.request", SpanKinds.Server, new Dictionary<string, string>() { { "graphql.operation.type", "query" } } },
new object[] { "amqp.server.request", SpanKinds.Server, new Dictionary<string, string>() { { "network.protocol.name", "Amqp" } } },
new object[] { "server.request", SpanKinds.Server, new Dictionary<string, string>() },
new object[] { "amqp.client.request", SpanKinds.Client, new Dictionary<string, string>() { { "network.protocol.name", "Amqp" } } },
new object[] { "client.request", SpanKinds.Client, new Dictionary<string, string>() },
new object[] { "internal", SpanKinds.Internal, new Dictionary<string, string>() },
new object[] { "consumer", SpanKinds.Consumer, new Dictionary<string, string>() },
new object[] { "producer", SpanKinds.Producer, new Dictionary<string, string>() },
new object[] { "internal", null, new Dictionary<string, string>() },
};
public static TheoryData<string, string, SerializableDictionary> NameData => new()
{
// expected_operation_name, span_kind, tags_related_to_operation_name
{ "http.server.request", SpanKinds.Server, new SerializableDictionary { { "http.request.method", "GET" } } },
{ "http.client.request", SpanKinds.Client, new SerializableDictionary { { "http.request.method", "GET" } } },
{ "redis.query", SpanKinds.Client, new SerializableDictionary { { "db.system", "Redis" } } },
{ "kafka.receive", SpanKinds.Client, new SerializableDictionary { { "messaging.system", "Kafka" }, { "messaging.operation", "Receive" } } },
{ "kafka.receive", SpanKinds.Server, new SerializableDictionary { { "messaging.system", "Kafka" }, { "messaging.operation", "Receive" } } },
{ "kafka.receive", SpanKinds.Producer, new SerializableDictionary { { "messaging.system", "Kafka" }, { "messaging.operation", "Receive" } } },
{ "kafka.receive", SpanKinds.Consumer, new SerializableDictionary { { "messaging.system", "Kafka" }, { "messaging.operation", "Receive" } } },
{ "aws.s3.request", SpanKinds.Client, new SerializableDictionary { { "rpc.system", "aws-api" }, { "rpc.service", "S3" } } },
{ "aws.client.request", SpanKinds.Client, new SerializableDictionary { { "rpc.system", "aws-api" } } },
{ "grpc.client.request", SpanKinds.Client, new SerializableDictionary { { "rpc.system", "GRPC" } } },
{ "grpc.server.request", SpanKinds.Server, new SerializableDictionary { { "rpc.system", "GRPC" } } },
{ "aws.my-function.invoke", SpanKinds.Client, new SerializableDictionary { { "faas.invoked_provider", "aws" }, { "faas.invoked_name", "My-Function" } } },
{ "datasource.invoke", SpanKinds.Server, new SerializableDictionary { { "faas.trigger", "Datasource" } } },
{ "graphql.server.request", SpanKinds.Server, new SerializableDictionary { { "graphql.operation.type", "query" } } },
{ "amqp.server.request", SpanKinds.Server, new SerializableDictionary { { "network.protocol.name", "Amqp" } } },
{ "server.request", SpanKinds.Server, new SerializableDictionary() },
{ "amqp.client.request", SpanKinds.Client, new SerializableDictionary() { { "network.protocol.name", "Amqp" } } },
{ "client.request", SpanKinds.Client, new SerializableDictionary() },
{ "internal", SpanKinds.Internal, new SerializableDictionary() },
{ "consumer", SpanKinds.Consumer, new SerializableDictionary() },
{ "producer", SpanKinds.Producer, new SerializableDictionary() },
{ "internal", null, new SerializableDictionary() },
};

[Theory]
[MemberData(nameof(NameData))]
public void OperationName_ShouldBeSet_BasedOnTags(string expectedOperationName, string expectedActivityKind, Dictionary<string, string> tags)
public void OperationName_ShouldBeSet_BasedOnTags(string expectedOperationName, string expectedActivityKind, SerializableDictionary tags)
{
var span = new Span(new SpanContext(1, 1), DateTimeOffset.UtcNow, new OpenTelemetryTags());

Expand Down Expand Up @@ -140,14 +140,14 @@ public OperationNameData(object[] data)

ExpectedActivityKind = data[1]?.ToString() ?? string.Empty;

Tags = data[2] is null ? new Dictionary<string, string>() : (Dictionary<string, string>)data[2];
Tags = data[2] is null ? new SerializableDictionary() : (SerializableDictionary)data[2];
}

public string ExpectedOperationName { get; }

public string ExpectedActivityKind { get; }

public Dictionary<string, string> Tags { get; }
public SerializableDictionary Tags { get; }
}
}
}
Loading