diff --git a/test/OpenTelemetry.Instrumentation.Grpc.Tests/GrpcTests.client.cs b/test/OpenTelemetry.Instrumentation.Grpc.Tests/GrpcTests.client.cs index 53328008bfb..3a7c513aa3b 100644 --- a/test/OpenTelemetry.Instrumentation.Grpc.Tests/GrpcTests.client.cs +++ b/test/OpenTelemetry.Instrumentation.Grpc.Tests/GrpcTests.client.cs @@ -23,9 +23,9 @@ using Grpc.Net.Client; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; -using Moq; #if !NETFRAMEWORK using OpenTelemetry.Context.Propagation; +using OpenTelemetry.Tests; #endif using OpenTelemetry.Instrumentation.Grpc.Tests.GrpcTestHelpers; using OpenTelemetry.Instrumentation.GrpcNetClient; @@ -61,7 +61,7 @@ public void GrpcClientCallsAreCollectedSuccessfully(string baseAddress, bool sho return response; }); - var processor = new Mock>(); + var exportedItems = new List(); using var parent = new Activity("parent") .SetIdFormat(ActivityIdFormat.W3C) @@ -77,7 +77,7 @@ public void GrpcClientCallsAreCollectedSuccessfully(string baseAddress, bool sho options.EnrichWithHttpResponseMessage = (activity, httpResponseMessage) => { enrichWithHttpResponseMessageCalled = true; }; } }) - .AddProcessor(processor.Object) + .AddInMemoryExporter(exportedItems) .Build()) { var channel = GrpcChannel.ForAddress(uri, new GrpcChannelOptions @@ -88,8 +88,8 @@ public void GrpcClientCallsAreCollectedSuccessfully(string baseAddress, bool sho var rs = client.SayHello(new HelloRequest()); } - Assert.Equal(5, processor.Invocations.Count); // SetParentProvider/OnStart/OnEnd/OnShutdown/Dispose called. - var activity = (Activity)processor.Invocations[2].Arguments[0]; + Assert.Single(exportedItems); + var activity = exportedItems[0]; ValidateGrpcActivity(activity); Assert.Equal(parent.TraceId, activity.Context.TraceId); @@ -137,7 +137,7 @@ public void GrpcClientCallsAreCollectedSuccessfully(string baseAddress, bool sho [InlineData("http://[::1]", false)] public void GrpcClientCallsAreCollectedSuccessfully_New(string baseAddress, bool shouldEnrich = true) { - KeyValuePair[] config = new KeyValuePair[] { new KeyValuePair("OTEL_SEMCONV_STABILITY_OPT_IN", "http") }; + var config = new KeyValuePair[] { new("OTEL_SEMCONV_STABILITY_OPT_IN", "http") }; var configuration = new ConfigurationBuilder() .AddInMemoryCollection(config) .Build(); @@ -156,7 +156,7 @@ public void GrpcClientCallsAreCollectedSuccessfully_New(string baseAddress, bool return response; }); - var processor = new Mock>(); + var exportedItems = new List(); using var parent = new Activity("parent") .SetIdFormat(ActivityIdFormat.W3C) @@ -173,7 +173,7 @@ public void GrpcClientCallsAreCollectedSuccessfully_New(string baseAddress, bool options.EnrichWithHttpResponseMessage = (activity, httpResponseMessage) => { enrichWithHttpResponseMessageCalled = true; }; } }) - .AddProcessor(processor.Object) + .AddInMemoryExporter(exportedItems) .Build()) { var channel = GrpcChannel.ForAddress(uri, new GrpcChannelOptions @@ -184,8 +184,8 @@ public void GrpcClientCallsAreCollectedSuccessfully_New(string baseAddress, bool var rs = client.SayHello(new HelloRequest()); } - Assert.Equal(5, processor.Invocations.Count); // SetParentProvider/OnStart/OnEnd/OnShutdown/Dispose called. - var activity = (Activity)processor.Invocations[2].Arguments[0]; + Assert.Single(exportedItems); + var activity = exportedItems[0]; ValidateGrpcActivity(activity); Assert.Equal(parent.TraceId, activity.Context.TraceId); @@ -233,7 +233,7 @@ public void GrpcClientCallsAreCollectedSuccessfully_New(string baseAddress, bool [InlineData("http://[::1]", false)] public void GrpcClientCallsAreCollectedSuccessfully_Dupe(string baseAddress, bool shouldEnrich = true) { - KeyValuePair[] config = new KeyValuePair[] { new KeyValuePair("OTEL_SEMCONV_STABILITY_OPT_IN", "http/dup") }; + var config = new KeyValuePair[] { new("OTEL_SEMCONV_STABILITY_OPT_IN", "http/dup") }; var configuration = new ConfigurationBuilder() .AddInMemoryCollection(config) .Build(); @@ -252,7 +252,7 @@ public void GrpcClientCallsAreCollectedSuccessfully_Dupe(string baseAddress, boo return response; }); - var processor = new Mock>(); + var exportedItems = new List(); using var parent = new Activity("parent") .SetIdFormat(ActivityIdFormat.W3C) @@ -269,7 +269,7 @@ public void GrpcClientCallsAreCollectedSuccessfully_Dupe(string baseAddress, boo options.EnrichWithHttpResponseMessage = (activity, httpResponseMessage) => { enrichWithHttpResponseMessageCalled = true; }; } }) - .AddProcessor(processor.Object) + .AddInMemoryExporter(exportedItems) .Build()) { var channel = GrpcChannel.ForAddress(uri, new GrpcChannelOptions @@ -280,8 +280,8 @@ public void GrpcClientCallsAreCollectedSuccessfully_Dupe(string baseAddress, boo var rs = client.SayHello(new HelloRequest()); } - Assert.Equal(5, processor.Invocations.Count); // SetParentProvider/OnStart/OnEnd/OnShutdown/Dispose called. - var activity = (Activity)processor.Invocations[2].Arguments[0]; + Assert.Single(exportedItems); + var activity = exportedItems[0]; ValidateGrpcActivity(activity); Assert.Equal(parent.TraceId, activity.Context.TraceId); @@ -332,12 +332,7 @@ public void GrpcClientCallsAreCollectedSuccessfully_Dupe(string baseAddress, boo public void GrpcAndHttpClientInstrumentationIsInvoked(bool shouldEnrich) { var uri = new Uri($"http://localhost:{this.server.Port}"); - var processor = new Mock>(); - processor.Setup(x => x.OnStart(It.IsAny())).Callback(c => - { - c.SetTag("enrichedWithHttpRequestMessage", "no"); - c.SetTag("enrichedWithHttpResponseMessage", "no"); - }); + var exportedItems = new List(); using var parent = new Activity("parent") .Start(); @@ -360,7 +355,7 @@ public void GrpcAndHttpClientInstrumentationIsInvoked(bool shouldEnrich) } }) .AddHttpClientInstrumentation() - .AddProcessor(processor.Object) + .AddInMemoryExporter(exportedItems) .Build()) { // With net5, based on the grpc changes, the quantity of default activities changed. @@ -374,9 +369,9 @@ public void GrpcAndHttpClientInstrumentationIsInvoked(bool shouldEnrich) var rs = client.SayHello(new HelloRequest()); } - Assert.Equal(7, processor.Invocations.Count); // SetParentProvider + OnStart/OnEnd (gRPC) + OnStart/OnEnd (HTTP) + OnShutdown/Dispose called. - var httpSpan = (Activity)processor.Invocations[3].Arguments[0]; - var grpcSpan = (Activity)processor.Invocations[4].Arguments[0]; + Assert.Equal(2, exportedItems.Count); + var httpSpan = exportedItems.Single(activity => activity.OperationName == OperationNameHttpOut); + var grpcSpan = exportedItems.Single(activity => activity.OperationName == OperationNameGrpcOut); ValidateGrpcActivity(grpcSpan); Assert.Equal($"greet.Greeter/SayHello", grpcSpan.DisplayName); @@ -384,17 +379,23 @@ public void GrpcAndHttpClientInstrumentationIsInvoked(bool shouldEnrich) Assert.Equal("POST", httpSpan.DisplayName); Assert.Equal(grpcSpan.SpanId, httpSpan.ParentSpanId); - Assert.NotEmpty(grpcSpan.Tags.Where(tag => tag.Key == "enrichedWithHttpRequestMessage")); - Assert.NotEmpty(grpcSpan.Tags.Where(tag => tag.Key == "enrichedWithHttpResponseMessage")); - Assert.Equal(shouldEnrich ? "yes" : "no", grpcSpan.Tags.Where(tag => tag.Key == "enrichedWithHttpRequestMessage").FirstOrDefault().Value); - Assert.Equal(shouldEnrich ? "yes" : "no", grpcSpan.Tags.Where(tag => tag.Key == "enrichedWithHttpResponseMessage").FirstOrDefault().Value); + if (shouldEnrich) + { + Assert.Single(grpcSpan.Tags, tag => tag.Key == "enrichedWithHttpRequestMessage" && tag.Value == "yes"); + Assert.Single(grpcSpan.Tags, tag => tag.Key == "enrichedWithHttpResponseMessage" && tag.Value == "yes"); + } + else + { + Assert.Empty(grpcSpan.Tags.Where(tag => tag.Key == "enrichedWithHttpRequestMessage")); + Assert.Empty(grpcSpan.Tags.Where(tag => tag.Key == "enrichedWithHttpResponseMessage")); + } } [Fact(Skip = "https://github.com/open-telemetry/opentelemetry-dotnet/issues/5092")] public void GrpcAndHttpClientInstrumentationWithSuppressInstrumentation() { var uri = new Uri($"http://localhost:{this.server.Port}"); - var processor = new Mock>(); + var exportedItems = new List(); using var parent = new Activity("parent") .Start(); @@ -403,7 +404,7 @@ public void GrpcAndHttpClientInstrumentationWithSuppressInstrumentation() .SetSampler(new AlwaysOnSampler()) .AddGrpcClientInstrumentation(o => o.SuppressDownstreamInstrumentation = true) .AddHttpClientInstrumentation() - .AddProcessor(processor.Object) + .AddInMemoryExporter(exportedItems) .Build()) { Parallel.ForEach( @@ -420,11 +421,11 @@ public void GrpcAndHttpClientInstrumentationWithSuppressInstrumentation() }); } - Assert.Equal(11, processor.Invocations.Count); // SetParentProvider + OnStart/OnEnd (gRPC) * 4 + OnShutdown/Dispose called. - var grpcSpan1 = (Activity)processor.Invocations[2].Arguments[0]; - var grpcSpan2 = (Activity)processor.Invocations[4].Arguments[0]; - var grpcSpan3 = (Activity)processor.Invocations[6].Arguments[0]; - var grpcSpan4 = (Activity)processor.Invocations[8].Arguments[0]; + Assert.Equal(4, exportedItems.Count); + var grpcSpan1 = exportedItems[0]; + var grpcSpan2 = exportedItems[1]; + var grpcSpan3 = exportedItems[2]; + var grpcSpan4 = exportedItems[3]; ValidateGrpcActivity(grpcSpan1); Assert.Equal($"greet.Greeter/SayHello", grpcSpan1.DisplayName); @@ -449,21 +450,17 @@ public void GrpcPropagatesContextWithSuppressInstrumentationOptionSetToTrue() try { var uri = new Uri($"http://localhost:{this.server.Port}"); - var processor = new Mock>(); + var exportedItems = new List(); using var source = new ActivitySource("test-source"); - var propagator = new Mock(); - propagator.Setup(m => m.Inject(It.IsAny(), It.IsAny(), It.IsAny>())) - .Callback>((context, message, action) => - { - action(message, "customField", "customValue"); - }); + var propagator = new CustomTextMapPropagator(); + propagator.InjectValues.Add("customField", context => "customValue"); Sdk.SetDefaultTextMapPropagator(new CompositeTextMapPropagator(new TextMapPropagator[] { new TraceContextPropagator(), - propagator.Object, + propagator, })); using (Sdk.CreateTracerProviderBuilder() @@ -480,37 +477,21 @@ public void GrpcPropagatesContextWithSuppressInstrumentationOptionSetToTrue() activity.SetCustomProperty("customField", request.Headers["customField"].ToString()); }; }) // Instrumenting the server side as well - .AddProcessor(processor.Object) + .AddInMemoryExporter(exportedItems) .Build()) { - using (var activity = source.StartActivity("parent")) - { - Assert.NotNull(activity); - var channel = GrpcChannel.ForAddress(uri); - var client = new Greeter.GreeterClient(channel); - var rs = client.SayHello(new HelloRequest()); - } - - WaitForProcessorInvocations(processor, 7); + using var activity = source.StartActivity("parent"); + Assert.NotNull(activity); + var channel = GrpcChannel.ForAddress(uri); + var client = new Greeter.GreeterClient(channel); + var rs = client.SayHello(new HelloRequest()); } - Assert.Equal(9, processor.Invocations.Count); // SetParentProvider + (OnStart + OnEnd) * 3 (parent, gRPC client, and server) + Shutdown + Dispose called. - - Assert.Single(processor.Invocations, invo => invo.Method.Name == "SetParentProvider"); - Assert.Single(processor.Invocations, GeneratePredicateForMoqProcessorActivity(nameof(processor.Object.OnStart), "parent")); - Assert.Single(processor.Invocations, GeneratePredicateForMoqProcessorActivity(nameof(processor.Object.OnStart), OperationNameGrpcOut)); - Assert.Single(processor.Invocations, GeneratePredicateForMoqProcessorActivity(nameof(processor.Object.OnStart), OperationNameHttpRequestIn)); - Assert.Single(processor.Invocations, GeneratePredicateForMoqProcessorActivity(nameof(processor.Object.OnEnd), OperationNameHttpRequestIn)); - Assert.Single(processor.Invocations, GeneratePredicateForMoqProcessorActivity(nameof(processor.Object.OnEnd), OperationNameGrpcOut)); - Assert.Single(processor.Invocations, GeneratePredicateForMoqProcessorActivity(nameof(processor.Object.OnEnd), "parent")); - Assert.Single(processor.Invocations, invo => invo.Method.Name == "OnShutdown"); - Assert.Single(processor.Invocations, invo => invo.Method.Name == nameof(processor.Object.Dispose)); - - var serverActivity = GetActivityFromProcessorInvocation(processor, nameof(processor.Object.OnEnd), OperationNameHttpRequestIn); - var clientActivity = GetActivityFromProcessorInvocation(processor, nameof(processor.Object.OnEnd), OperationNameGrpcOut); + var serverActivity = exportedItems.Single(activity => activity.OperationName == OperationNameHttpRequestIn); + var clientActivity = exportedItems.Single(activity => activity.OperationName == OperationNameGrpcOut); Assert.Equal($"greet.Greeter/SayHello", clientActivity.DisplayName); - Assert.Equal($"greet.Greeter/SayHello", serverActivity.DisplayName); + Assert.Equal($"POST /greet.Greeter/SayHello", serverActivity.DisplayName); Assert.Equal(clientActivity.TraceId, serverActivity.TraceId); Assert.Equal(clientActivity.SpanId, serverActivity.ParentSpanId); Assert.Equal(0, clientActivity.GetTagValue(SemanticConventions.AttributeRpcGrpcStatusCode)); @@ -532,19 +513,16 @@ public void GrpcDoesNotPropagateContextWithSuppressInstrumentationOptionSetToFal try { var uri = new Uri($"http://localhost:{this.server.Port}"); - var processor = new Mock>(); - + var exportedItems = new List(); using var source = new ActivitySource("test-source"); bool isPropagatorCalled = false; - var propagator = new Mock(); - propagator.Setup(m => m.Inject(It.IsAny(), It.IsAny(), It.IsAny>())) - .Callback>((context, message, action) => - { - isPropagatorCalled = true; - }); + var propagator = new CustomTextMapPropagator + { + Injected = (context) => isPropagatorCalled = true, + }; - Sdk.SetDefaultTextMapPropagator(propagator.Object); + Sdk.SetDefaultTextMapPropagator(propagator); var headers = new Metadata(); @@ -554,7 +532,7 @@ public void GrpcDoesNotPropagateContextWithSuppressInstrumentationOptionSetToFal { o.SuppressDownstreamInstrumentation = false; }) - .AddProcessor(processor.Object) + .AddInMemoryExporter(exportedItems) .Build()) { using var activity = source.StartActivity("parent"); @@ -563,15 +541,12 @@ public void GrpcDoesNotPropagateContextWithSuppressInstrumentationOptionSetToFal var rs = client.SayHello(new HelloRequest(), headers); } - Assert.Equal(7, processor.Invocations.Count); // SetParentProvider/OnShutdown/Dispose called. + Assert.Equal(2, exportedItems.Count); - Assert.Single(processor.Invocations, invo => invo.Method.Name == "SetParentProvider"); - Assert.Single(processor.Invocations, GeneratePredicateForMoqProcessorActivity(nameof(processor.Object.OnStart), "parent")); - Assert.Single(processor.Invocations, GeneratePredicateForMoqProcessorActivity(nameof(processor.Object.OnStart), OperationNameGrpcOut)); - Assert.Single(processor.Invocations, GeneratePredicateForMoqProcessorActivity(nameof(processor.Object.OnEnd), OperationNameGrpcOut)); - Assert.Single(processor.Invocations, GeneratePredicateForMoqProcessorActivity(nameof(processor.Object.OnEnd), "parent")); - Assert.Single(processor.Invocations, invo => invo.Method.Name == "OnShutdown"); - Assert.Single(processor.Invocations, invo => invo.Method.Name == nameof(processor.Object.Dispose)); + var parentActivity = exportedItems.Single(activity => activity.OperationName == "parent"); + var clientActivity = exportedItems.Single(activity => activity.OperationName == OperationNameGrpcOut); + + Assert.Equal(clientActivity.ParentSpanId, parentActivity.SpanId); // Propagator is not called Assert.False(isPropagatorCalled); @@ -592,22 +567,18 @@ public void GrpcClientInstrumentationRespectsSdkSuppressInstrumentation() try { var uri = new Uri($"http://localhost:{this.server.Port}"); - var processor = new Mock>(); + var exportedItems = new List(); using var source = new ActivitySource("test-source"); bool isPropagatorCalled = false; - var propagator = new Mock(); - propagator.Setup(m => m.Inject(It.IsAny(), It.IsAny(), It.IsAny>())) - .Callback>((context, message, action) => - { - isPropagatorCalled = true; - }); + var propagator = new CustomTextMapPropagator(); + propagator.Injected = (context) => isPropagatorCalled = true; Sdk.SetDefaultTextMapPropagator(new CompositeTextMapPropagator(new TextMapPropagator[] { new TraceContextPropagator(), - propagator.Object, + propagator, })); using (Sdk.CreateTracerProviderBuilder() @@ -616,7 +587,7 @@ public void GrpcClientInstrumentationRespectsSdkSuppressInstrumentation() { o.SuppressDownstreamInstrumentation = true; }) - .AddProcessor(processor.Object) + .AddInMemoryExporter(exportedItems) .Build()) { using var activity = source.StartActivity("parent"); @@ -630,9 +601,7 @@ public void GrpcClientInstrumentationRespectsSdkSuppressInstrumentation() // If suppressed, activity is not emitted and // propagation is also not performed. - Assert.Equal(5, processor.Invocations.Count); // SetParentProvider + (OnStart + OnEnd) * 3 for parent + OnShutdown + Dispose called. - Assert.Single(processor.Invocations, GeneratePredicateForMoqProcessorActivity(nameof(processor.Object.OnStart), "parent")); - Assert.Single(processor.Invocations, GeneratePredicateForMoqProcessorActivity(nameof(processor.Object.OnEnd), "parent")); + Assert.Single(exportedItems); Assert.False(isPropagatorCalled); } finally @@ -680,9 +649,4 @@ private static void ValidateGrpcActivity(Activity activityToValidate) Assert.Equal(GrpcClientDiagnosticListener.Version.ToString(), activityToValidate.Source.Version); Assert.Equal(ActivityKind.Client, activityToValidate.Kind); } - - private static Predicate GeneratePredicateForMoqProcessorActivity(string methodName, string activityOperationName) - { - return invo => invo.Method.Name == methodName && (invo.Arguments[0] as Activity)?.OperationName == activityOperationName; - } } diff --git a/test/OpenTelemetry.Instrumentation.Grpc.Tests/GrpcTests.server.cs b/test/OpenTelemetry.Instrumentation.Grpc.Tests/GrpcTests.server.cs index 73ce23b4c0c..e874cfe3167 100644 --- a/test/OpenTelemetry.Instrumentation.Grpc.Tests/GrpcTests.server.cs +++ b/test/OpenTelemetry.Instrumentation.Grpc.Tests/GrpcTests.server.cs @@ -16,7 +16,6 @@ #if NET6_0_OR_GREATER using System.Diagnostics; -using Moq; using OpenTelemetry.Instrumentation.Grpc.Services.Tests; using Xunit; @@ -217,29 +216,5 @@ private static void WaitForExporterToReceiveItems(List itemsReceived, }, TimeSpan.FromSeconds(1))); } - - private static void WaitForProcessorInvocations(Mock> spanProcessor, int invocationCount) - { - // We need to let End callback execute as it is executed AFTER response was returned. - // In unit tests environment there may be a lot of parallel unit tests executed, so - // giving some breezing room for the End callback to complete - Assert.True(SpinWait.SpinUntil( - () => - { - Thread.Sleep(10); - return spanProcessor.Invocations.Count >= invocationCount; - }, - TimeSpan.FromSeconds(1))); - } - - private static Activity GetActivityFromProcessorInvocation(Mock> processor, string methodName, string activityOperationName) - { - return processor.Invocations - .FirstOrDefault(invo => - { - return invo.Method.Name == methodName - && (invo.Arguments[0] as Activity)?.OperationName == activityOperationName; - })?.Arguments[0] as Activity; - } } #endif diff --git a/test/OpenTelemetry.Instrumentation.Grpc.Tests/OpenTelemetry.Instrumentation.Grpc.Tests.csproj b/test/OpenTelemetry.Instrumentation.Grpc.Tests/OpenTelemetry.Instrumentation.Grpc.Tests.csproj index 9c393cac718..c56cc504187 100644 --- a/test/OpenTelemetry.Instrumentation.Grpc.Tests/OpenTelemetry.Instrumentation.Grpc.Tests.csproj +++ b/test/OpenTelemetry.Instrumentation.Grpc.Tests/OpenTelemetry.Instrumentation.Grpc.Tests.csproj @@ -17,7 +17,6 @@ - runtime; build; native; contentfiles; analyzers @@ -46,7 +45,9 @@ + +