From d6171719517c589f33f5b02ed51c4922129e5a22 Mon Sep 17 00:00:00 2001 From: Nils Gruson Date: Tue, 5 Dec 2023 19:08:41 +0100 Subject: [PATCH 1/3] Removed Moq dependency from OpenTelemetry.Instrumentation.Http.Tests (#5115) --- .../HttpClientTests.Basic.cs | 71 ++++++------------- .../HttpWebRequestTests.Basic.cs | 29 ++------ ...elemetry.Instrumentation.Http.Tests.csproj | 8 +-- .../Shared/CustomTextMapPropagator.cs | 64 +++++++++++++++++ 4 files changed, 98 insertions(+), 74 deletions(-) create mode 100644 test/OpenTelemetry.Tests/Shared/CustomTextMapPropagator.cs diff --git a/test/OpenTelemetry.Instrumentation.Http.Tests/HttpClientTests.Basic.cs b/test/OpenTelemetry.Instrumentation.Http.Tests/HttpClientTests.Basic.cs index 49b1edca026..240abb1180a 100644 --- a/test/OpenTelemetry.Instrumentation.Http.Tests/HttpClientTests.Basic.cs +++ b/test/OpenTelemetry.Instrumentation.Http.Tests/HttpClientTests.Basic.cs @@ -16,11 +16,9 @@ using System.Diagnostics; #if NETFRAMEWORK -using System.Net; using System.Net.Http; #endif using Microsoft.Extensions.DependencyInjection; -using Moq; using OpenTelemetry.Context.Propagation; using OpenTelemetry.Instrumentation.Http.Implementation; using OpenTelemetry.Metrics; @@ -224,13 +222,9 @@ public async Task InjectsHeadersAsync(bool shouldEnrich) [Fact] public async Task InjectsHeadersAsync_CustomFormat() { - var propagator = new Mock(); - propagator.Setup(m => m.Inject(It.IsAny(), It.IsAny(), It.IsAny>())) - .Callback>((context, message, action) => - { - action(message, "custom_traceparent", $"00/{context.ActivityContext.TraceId}/{context.ActivityContext.SpanId}/01"); - action(message, "custom_tracestate", Activity.Current.TraceStateString); - }); + var propagator = new CustomTextMapPropagator(); + propagator.InjectValues.Add("custom_traceParent", context => $"00/{context.ActivityContext.TraceId}/{context.ActivityContext.SpanId}/01"); + propagator.InjectValues.Add("custom_traceState", context => Activity.Current.TraceStateString); var exportedItems = new List(); @@ -246,7 +240,7 @@ public async Task InjectsHeadersAsync_CustomFormat() parent.TraceStateString = "k1=v1,k2=v2"; parent.ActivityTraceFlags = ActivityTraceFlags.Recorded; - Sdk.SetDefaultTextMapPropagator(propagator.Object); + Sdk.SetDefaultTextMapPropagator(propagator); using (Sdk.CreateTracerProviderBuilder() .AddHttpClientInstrumentation() @@ -271,13 +265,13 @@ public async Task InjectsHeadersAsync_CustomFormat() // not the HttpRequestMessage passed to HttpClient. Assert.Empty(request.Headers); #else - Assert.True(request.Headers.TryGetValues("custom_traceparent", out var traceparents)); - Assert.True(request.Headers.TryGetValues("custom_tracestate", out var tracestates)); - Assert.Single(traceparents); - Assert.Single(tracestates); + Assert.True(request.Headers.TryGetValues("custom_traceParent", out var traceParents)); + Assert.True(request.Headers.TryGetValues("custom_traceState", out var traceStates)); + Assert.Single(traceParents); + Assert.Single(traceStates); - Assert.Equal($"00/{activity.Context.TraceId}/{activity.Context.SpanId}/01", traceparents.Single()); - Assert.Equal("k1=v1,k2=v2", tracestates.Single()); + Assert.Equal($"00/{activity.Context.TraceId}/{activity.Context.SpanId}/01", traceParents.Single()); + Assert.Equal("k1=v1,k2=v2", traceStates.Single()); #endif Sdk.SetDefaultTextMapPropagator(new CompositeTextMapPropagator(new TextMapPropagator[] @@ -292,13 +286,9 @@ public async Task RespectsSuppress() { try { - var propagator = new Mock(); - propagator.Setup(m => m.Inject(It.IsAny(), It.IsAny(), It.IsAny>())) - .Callback>((context, message, action) => - { - action(message, "custom_traceparent", $"00/{context.ActivityContext.TraceId}/{context.ActivityContext.SpanId}/01"); - action(message, "custom_tracestate", Activity.Current.TraceStateString); - }); + var propagator = new CustomTextMapPropagator(); + propagator.InjectValues.Add("custom_traceParent", context => $"00/{context.ActivityContext.TraceId}/{context.ActivityContext.SpanId}/01"); + propagator.InjectValues.Add("custom_traceState", context => Activity.Current.TraceStateString); var exportedItems = new List(); @@ -314,7 +304,7 @@ public async Task RespectsSuppress() parent.TraceStateString = "k1=v1,k2=v2"; parent.ActivityTraceFlags = ActivityTraceFlags.Recorded; - Sdk.SetDefaultTextMapPropagator(propagator.Object); + Sdk.SetDefaultTextMapPropagator(propagator); using (Sdk.CreateTracerProviderBuilder() .AddHttpClientInstrumentation() @@ -331,8 +321,8 @@ public async Task RespectsSuppress() // If suppressed, activity is not emitted and // propagation is also not performed. Assert.Empty(exportedItems); - Assert.False(request.Headers.Contains("custom_traceparent")); - Assert.False(request.Headers.Contains("custom_tracestate")); + Assert.False(request.Headers.Contains("custom_traceParent")); + Assert.False(request.Headers.Contains("custom_traceState")); } finally { @@ -685,27 +675,12 @@ public async Task CustomPropagatorCalled(bool sample, bool createParentActivity) ActivityContext parentContext = default; ActivityContext contextFromPropagator = default; - var propagator = new Mock(); - -#if NETFRAMEWORK - propagator.Setup(m => m.Inject(It.IsAny(), It.IsAny(), It.IsAny>())) - .Callback>((context, carrier, setter) => - { - contextFromPropagator = context.ActivityContext; - - setter(carrier, "custom_traceparent", $"00/{contextFromPropagator.TraceId}/{contextFromPropagator.SpanId}/01"); - setter(carrier, "custom_tracestate", contextFromPropagator.TraceState); - }); -#else - propagator.Setup(m => m.Inject(It.IsAny(), It.IsAny(), It.IsAny>())) - .Callback>((context, carrier, setter) => - { - contextFromPropagator = context.ActivityContext; - - setter(carrier, "custom_traceparent", $"00/{contextFromPropagator.TraceId}/{contextFromPropagator.SpanId}/01"); - setter(carrier, "custom_tracestate", contextFromPropagator.TraceState); - }); -#endif + var propagator = new CustomTextMapPropagator + { + Injected = (context) => contextFromPropagator = context.ActivityContext, + }; + propagator.InjectValues.Add("custom_traceParent", context => $"00/{context.ActivityContext.TraceId}/{context.ActivityContext.SpanId}/01"); + propagator.InjectValues.Add("custom_traceState", context => Activity.Current.TraceStateString); var exportedItems = new List(); @@ -716,7 +691,7 @@ public async Task CustomPropagatorCalled(bool sample, bool createParentActivity) .Build()) { var previousDefaultTextMapPropagator = Propagators.DefaultTextMapPropagator; - Sdk.SetDefaultTextMapPropagator(propagator.Object); + Sdk.SetDefaultTextMapPropagator(propagator); Activity parent = null; if (createParentActivity) diff --git a/test/OpenTelemetry.Instrumentation.Http.Tests/HttpWebRequestTests.Basic.cs b/test/OpenTelemetry.Instrumentation.Http.Tests/HttpWebRequestTests.Basic.cs index 0beac0d9835..060b264f5f1 100644 --- a/test/OpenTelemetry.Instrumentation.Http.Tests/HttpWebRequestTests.Basic.cs +++ b/test/OpenTelemetry.Instrumentation.Http.Tests/HttpWebRequestTests.Basic.cs @@ -18,7 +18,6 @@ using System.Net; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; -using Moq; using OpenTelemetry.Context.Propagation; using OpenTelemetry.Instrumentation.Http.Implementation; using OpenTelemetry.Tests; @@ -220,26 +219,12 @@ public async Task CustomPropagatorCalled(bool sample, bool createParentActivity) ActivityContext parentContext = default; ActivityContext contextFromPropagator = default; - var propagator = new Mock(); -#if NETFRAMEWORK - propagator.Setup(m => m.Inject(It.IsAny(), It.IsAny(), It.IsAny>())) - .Callback>((context, carrier, setter) => - { - contextFromPropagator = context.ActivityContext; - - setter(carrier, "traceparent", $"00/{contextFromPropagator.TraceId}/{contextFromPropagator.SpanId}/01"); - setter(carrier, "tracestate", contextFromPropagator.TraceState); - }); -#else - propagator.Setup(m => m.Inject(It.IsAny(), It.IsAny(), It.IsAny>())) - .Callback>((context, carrier, setter) => - { - contextFromPropagator = context.ActivityContext; - - setter(carrier, "traceparent", $"00/{contextFromPropagator.TraceId}/{contextFromPropagator.SpanId}/01"); - setter(carrier, "tracestate", contextFromPropagator.TraceState); - }); -#endif + var propagator = new CustomTextMapPropagator + { + Injected = (PropagationContext context) => contextFromPropagator = context.ActivityContext, + }; + propagator.InjectValues.Add("custom_traceParent", context => $"00/{context.ActivityContext.TraceId}/{context.ActivityContext.SpanId}/01"); + propagator.InjectValues.Add("custom_traceState", context => Activity.Current.TraceStateString); var exportedItems = new List(); @@ -250,7 +235,7 @@ public async Task CustomPropagatorCalled(bool sample, bool createParentActivity) .Build()) { var previousDefaultTextMapPropagator = Propagators.DefaultTextMapPropagator; - Sdk.SetDefaultTextMapPropagator(propagator.Object); + Sdk.SetDefaultTextMapPropagator(propagator); Activity parent = null; if (createParentActivity) diff --git a/test/OpenTelemetry.Instrumentation.Http.Tests/OpenTelemetry.Instrumentation.Http.Tests.csproj b/test/OpenTelemetry.Instrumentation.Http.Tests/OpenTelemetry.Instrumentation.Http.Tests.csproj index 75e4f2f2959..9bb4c1710c7 100644 --- a/test/OpenTelemetry.Instrumentation.Http.Tests/OpenTelemetry.Instrumentation.Http.Tests.csproj +++ b/test/OpenTelemetry.Instrumentation.Http.Tests/OpenTelemetry.Instrumentation.Http.Tests.csproj @@ -7,16 +7,16 @@ - - + - + + + - diff --git a/test/OpenTelemetry.Tests/Shared/CustomTextMapPropagator.cs b/test/OpenTelemetry.Tests/Shared/CustomTextMapPropagator.cs new file mode 100644 index 00000000000..e22904fd126 --- /dev/null +++ b/test/OpenTelemetry.Tests/Shared/CustomTextMapPropagator.cs @@ -0,0 +1,64 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System.Diagnostics; +using OpenTelemetry.Context.Propagation; + +namespace OpenTelemetry.Tests; + +internal sealed class CustomTextMapPropagator : TextMapPropagator +{ + private static readonly PropagationContext DefaultPropagationContext = default; + + public ActivityTraceId TraceId { get; set; } + + public ActivitySpanId SpanId { get; set; } + + public Action Injected { get; set; } + + public override ISet Fields => null; + +#pragma warning disable SA1201 // Elements should appear in the correct order +#pragma warning disable SA1010 // Opening square brackets should be spaced correctly + public Dictionary> InjectValues = []; +#pragma warning restore SA1010 // Opening square brackets should be spaced correctly +#pragma warning restore SA1201 // Elements should appear in the correct order + + public override PropagationContext Extract(PropagationContext context, T carrier, Func> getter) + { + if (this.TraceId != default && this.SpanId != default) + { + return new PropagationContext( + new ActivityContext( + this.TraceId, + this.SpanId, + ActivityTraceFlags.Recorded), + default); + } + + return DefaultPropagationContext; + } + + public override void Inject(PropagationContext context, T carrier, Action setter) + { + foreach (var kv in this.InjectValues) + { + setter(carrier, kv.Key, kv.Value.Invoke(context)); + } + + this.Injected?.Invoke(context); + } +} From 5ca11244664df597614f3a148b41c4910bca07bb Mon Sep 17 00:00:00 2001 From: Nils Gruson Date: Tue, 5 Dec 2023 19:21:29 +0100 Subject: [PATCH 2/3] Removed Moq dependency from Exporter.OpenTelemetryProtocol.Tests (#5118) --- .../AssemblyInfo.cs | 6 --- .../OtlpHttpTraceExportClientTests.cs | 49 ++++--------------- ...xporter.OpenTelemetryProtocol.Tests.csproj | 1 - .../OtlpLogExporterTests.cs | 24 +++------ .../OtlpTraceExporterTests.cs | 10 ++-- .../TestExportClient.cs | 45 +++++++++++++++++ .../TestHttpMessageHandler.cs | 47 ++++++++++++++++++ 7 files changed, 113 insertions(+), 69 deletions(-) create mode 100644 test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/TestExportClient.cs create mode 100644 test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/TestHttpMessageHandler.cs diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/AssemblyInfo.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/AssemblyInfo.cs index 2bc348cad9a..b57075574b1 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/AssemblyInfo.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/AssemblyInfo.cs @@ -20,14 +20,8 @@ [assembly: InternalsVisibleTo("OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests, PublicKey=002400000480000094000000060200000024000052534131000400000100010051c1562a090fb0c9f391012a32198b5e5d9a60e9b80fa2d7b434c9e5ccb7259bd606e66f9660676afc6692b8cdc6793d190904551d2103b7b22fa636dcbb8208839785ba402ea08fc00c8f1500ccef28bbf599aa64ffb1e1d5dc1bf3420a3777badfe697856e9d52070a50c3ea5821c80bef17ca3acffa28f89dd413f096f898")] [assembly: InternalsVisibleTo("Benchmarks, PublicKey=002400000480000094000000060200000024000052534131000400000100010051c1562a090fb0c9f391012a32198b5e5d9a60e9b80fa2d7b434c9e5ccb7259bd606e66f9660676afc6692b8cdc6793d190904551d2103b7b22fa636dcbb8208839785ba402ea08fc00c8f1500ccef28bbf599aa64ffb1e1d5dc1bf3420a3777badfe697856e9d52070a50c3ea5821c80bef17ca3acffa28f89dd413f096f898")] [assembly: InternalsVisibleTo("MockOpenTelemetryCollector, PublicKey=002400000480000094000000060200000024000052534131000400000100010051c1562a090fb0c9f391012a32198b5e5d9a60e9b80fa2d7b434c9e5ccb7259bd606e66f9660676afc6692b8cdc6793d190904551d2103b7b22fa636dcbb8208839785ba402ea08fc00c8f1500ccef28bbf599aa64ffb1e1d5dc1bf3420a3777badfe697856e9d52070a50c3ea5821c80bef17ca3acffa28f89dd413f096f898")] - -// Used by Moq. -[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")] #else [assembly: InternalsVisibleTo("OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests")] [assembly: InternalsVisibleTo("Benchmarks")] [assembly: InternalsVisibleTo("MockOpenTelemetryCollector")] - -// Used by Moq. -[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")] #endif diff --git a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/Implementation/ExportClient/OtlpHttpTraceExportClientTests.cs b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/Implementation/ExportClient/OtlpHttpTraceExportClientTests.cs index 240c8ad88c1..548f38b96cc 100644 --- a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/Implementation/ExportClient/OtlpHttpTraceExportClientTests.cs +++ b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/Implementation/ExportClient/OtlpHttpTraceExportClientTests.cs @@ -18,8 +18,6 @@ #if !NET6_0_OR_GREATER using System.Net.Http; #endif -using Moq; -using Moq.Protected; using OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation; using OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation.ExportClient; using OpenTelemetry.Resources; @@ -94,42 +92,11 @@ public void SendExportRequest_ExportTraceServiceRequest_SendsCorrectHttpRequest( Headers = $"{header1.Name}={header1.Value}, {header2.Name} = {header2.Value}", }; - var httpHandlerMock = new Mock(); + var testHttpHandler = new TestHttpMessageHandler(); - HttpRequestMessage httpRequest = null; var httpRequestContent = Array.Empty(); - httpHandlerMock.Protected() -#if NET6_0_OR_GREATER - .Setup("Send", ItExpr.IsAny(), ItExpr.IsAny()) - .Returns((HttpRequestMessage request, CancellationToken token) => - { - return new HttpResponseMessage(); - }) - .Callback(async (r, ct) => - { - httpRequest = r; - - // We have to capture content as it can't be accessed after request is disposed inside of SendExportRequest method - httpRequestContent = await r.Content.ReadAsByteArrayAsync(ct); - }) -#else - .Setup>("SendAsync", ItExpr.IsAny(), ItExpr.IsAny()) - .ReturnsAsync((HttpRequestMessage request, CancellationToken token) => - { - return new HttpResponseMessage(); - }) - .Callback(async (r, ct) => - { - httpRequest = r; - - // We have to capture content as it can't be accessed after request is disposed inside of SendExportRequest method - httpRequestContent = await r.Content.ReadAsByteArrayAsync(); - }) -#endif - .Verifiable(); - - var exportClient = new OtlpHttpTraceExportClient(options, new HttpClient(httpHandlerMock.Object)); + var exportClient = new OtlpHttpTraceExportClient(options, new HttpClient(testHttpHandler)); var resourceBuilder = ResourceBuilder.CreateEmpty(); if (includeServiceNameInResource) @@ -137,8 +104,8 @@ public void SendExportRequest_ExportTraceServiceRequest_SendsCorrectHttpRequest( resourceBuilder.AddAttributes( new List> { - new KeyValuePair(ResourceSemanticConventions.AttributeServiceName, "service_name"), - new KeyValuePair(ResourceSemanticConventions.AttributeServiceNamespace, "ns_1"), + new(ResourceSemanticConventions.AttributeServiceName, "service_name"), + new(ResourceSemanticConventions.AttributeServiceNamespace, "ns_1"), }); } @@ -166,7 +133,7 @@ public void SendExportRequest_ExportTraceServiceRequest_SendsCorrectHttpRequest( processor.Shutdown(); - var batch = new Batch(exportedItems.ToArray(), exportedItems.Count); + var batch = new Batch([.. exportedItems], exportedItems.Count); RunTest(batch); void RunTest(Batch batch) @@ -178,6 +145,8 @@ void RunTest(Batch batch) // Act var result = exportClient.SendExportRequest(request); + var httpRequest = testHttpHandler.HttpRequestMessage; + // Assert Assert.True(result); Assert.NotNull(httpRequest); @@ -192,11 +161,11 @@ void RunTest(Batch batch) Assert.Contains(httpRequest.Headers, entry => entry.Key == OtlpExporterOptions.StandardHeaders[i].Key && entry.Value.First() == OtlpExporterOptions.StandardHeaders[i].Value); } - Assert.NotNull(httpRequest.Content); + Assert.NotNull(testHttpHandler.HttpRequestContent); Assert.IsType(httpRequest.Content); Assert.Contains(httpRequest.Content.Headers, h => h.Key == "Content-Type" && h.Value.First() == OtlpHttpTraceExportClient.MediaContentType); - var exportTraceRequest = OtlpCollector.ExportTraceServiceRequest.Parser.ParseFrom(httpRequestContent); + var exportTraceRequest = OtlpCollector.ExportTraceServiceRequest.Parser.ParseFrom(testHttpHandler.HttpRequestContent); Assert.NotNull(exportTraceRequest); Assert.Single(exportTraceRequest.ResourceSpans); diff --git a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests.csproj b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests.csproj index 2e9775519da..ad60a2385a2 100644 --- a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests.csproj +++ b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests.csproj @@ -12,7 +12,6 @@ - runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpLogExporterTests.cs b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpLogExporterTests.cs index 090a950b75c..5e0297e1397 100644 --- a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpLogExporterTests.cs +++ b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpLogExporterTests.cs @@ -22,9 +22,7 @@ using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; -using Moq; using OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation; -using OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation.ExportClient; using OpenTelemetry.Internal; using OpenTelemetry.Logs; using OpenTelemetry.Resources; @@ -589,37 +587,34 @@ public void CheckToOtlpLogRecordRespectsAttributeLimits() public void Export_WhenExportClientIsProvidedInCtor_UsesProvidedExportClient() { // Arrange. - var fakeExportClient = new Mock>(); + var testExportClient = new TestExportClient(); var emptyLogRecords = Array.Empty(); var emptyBatch = new Batch(emptyLogRecords, emptyLogRecords.Length); var sut = new OtlpLogExporter( new OtlpExporterOptions(), new SdkLimitOptions(), new ExperimentalOptions(), - fakeExportClient.Object); + testExportClient); // Act. - var result = sut.Export(emptyBatch); + sut.Export(emptyBatch); // Assert. - fakeExportClient.Verify(x => x.SendExportRequest(It.IsAny(), default), Times.Once()); + Assert.True(testExportClient.SendExportRequestCalled); } [Fact] public void Export_WhenExportClientThrowsException_ReturnsExportResultFailure() { // Arrange. - var fakeExportClient = new Mock>(); + var testExportClient = new TestExportClient(throwException: true); var emptyLogRecords = Array.Empty(); var emptyBatch = new Batch(emptyLogRecords, emptyLogRecords.Length); - fakeExportClient - .Setup(_ => _.SendExportRequest(It.IsAny(), default)) - .Throws(new Exception("Test Exception")); var sut = new OtlpLogExporter( new OtlpExporterOptions(), new SdkLimitOptions(), new ExperimentalOptions(), - fakeExportClient.Object); + testExportClient); // Act. var result = sut.Export(emptyBatch); @@ -632,17 +627,14 @@ public void Export_WhenExportClientThrowsException_ReturnsExportResultFailure() public void Export_WhenExportIsSuccessful_ReturnsExportResultSuccess() { // Arrange. - var fakeExportClient = new Mock>(); + var testExportClient = new TestExportClient(); var emptyLogRecords = Array.Empty(); var emptyBatch = new Batch(emptyLogRecords, emptyLogRecords.Length); - fakeExportClient - .Setup(_ => _.SendExportRequest(It.IsAny(), default)) - .Returns(true); var sut = new OtlpLogExporter( new OtlpExporterOptions(), new SdkLimitOptions(), new ExperimentalOptions(), - fakeExportClient.Object); + testExportClient); // Act. var result = sut.Export(emptyBatch); diff --git a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpTraceExporterTests.cs b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpTraceExporterTests.cs index 03fd86bdebe..8663177d889 100644 --- a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpTraceExporterTests.cs +++ b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpTraceExporterTests.cs @@ -17,9 +17,7 @@ using System.Diagnostics; using Google.Protobuf.Collections; using Microsoft.Extensions.DependencyInjection; -using Moq; using OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation; -using OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation.ExportClient; using OpenTelemetry.Metrics; using OpenTelemetry.Resources; using OpenTelemetry.Tests; @@ -642,13 +640,13 @@ public void UseOpenTelemetryProtocolActivityExporterWithCustomActivityProcessor( [Fact] public void Shutdown_ClientShutdownIsCalled() { - var exportClientMock = new Mock>(); + var exportClientMock = new TestExportClient(); - var exporter = new OtlpTraceExporter(new OtlpExporterOptions(), DefaultSdkLimitOptions, exportClientMock.Object); + var exporter = new OtlpTraceExporter(new OtlpExporterOptions(), DefaultSdkLimitOptions, exportClientMock); - var result = exporter.Shutdown(); + exporter.Shutdown(); - exportClientMock.Verify(m => m.Shutdown(It.IsAny()), Times.Once()); + Assert.True(exportClientMock.ShutdownCalled); } [Fact] diff --git a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/TestExportClient.cs b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/TestExportClient.cs new file mode 100644 index 00000000000..b7123187f6f --- /dev/null +++ b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/TestExportClient.cs @@ -0,0 +1,45 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation.ExportClient; + +namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests; + +internal class TestExportClient(bool throwException = false) : IExportClient +{ + public bool SendExportRequestCalled { get; private set; } + + public bool ShutdownCalled { get; private set; } + + public bool ThrowException { get; set; } = throwException; + + public bool SendExportRequest(T request, CancellationToken cancellationToken = default) + { + if (this.ThrowException) + { + throw new Exception("Exception thrown from SendExportRequest"); + } + + this.SendExportRequestCalled = true; + return true; + } + + public bool Shutdown(int timeoutMilliseconds) + { + this.ShutdownCalled = true; + return true; + } +} diff --git a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/TestHttpMessageHandler.cs b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/TestHttpMessageHandler.cs new file mode 100644 index 00000000000..f3006cf03db --- /dev/null +++ b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/TestHttpMessageHandler.cs @@ -0,0 +1,47 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#if !NET6_0_OR_GREATER +using System.Net.Http; +#endif + +namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests; + +internal class TestHttpMessageHandler : HttpMessageHandler +{ + public HttpRequestMessage HttpRequestMessage { get; private set; } + + public byte[] HttpRequestContent { get; private set; } + + public virtual HttpResponseMessage InternalSend(HttpRequestMessage request, CancellationToken cancellationToken) + { + this.HttpRequestMessage = request; + this.HttpRequestContent = request.Content.ReadAsByteArrayAsync().Result; + return new HttpResponseMessage(); + } + +#if NET6_0_OR_GREATER + protected override HttpResponseMessage Send(HttpRequestMessage request, CancellationToken cancellationToken) + { + return this.InternalSend(request, cancellationToken); + } +#endif + + protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) + { + return Task.FromResult(this.InternalSend(request, cancellationToken)); + } +} From f11801da9254f1d72decf13a947f2fa61fd40293 Mon Sep 17 00:00:00 2001 From: Nils Gruson Date: Tue, 5 Dec 2023 19:39:27 +0100 Subject: [PATCH 3/3] Removed Moq dependency from Shims.OpenTracing.Tests (#5126) --- ...enTelemetry.Shims.OpenTracing.Tests.csproj | 1 - .../ScopeManagerShimTests.cs | 3 +- .../TestFormatTextMap.cs | 23 ++++ .../TestSpan.cs | 110 ++++++++++++++++++ .../TestSpanContext.cs | 31 +++++ .../TestTextMap.cs | 47 ++++++++ .../TracerShimTests.cs | 53 ++++----- 7 files changed, 235 insertions(+), 33 deletions(-) create mode 100644 test/OpenTelemetry.Shims.OpenTracing.Tests/TestFormatTextMap.cs create mode 100644 test/OpenTelemetry.Shims.OpenTracing.Tests/TestSpan.cs create mode 100644 test/OpenTelemetry.Shims.OpenTracing.Tests/TestSpanContext.cs create mode 100644 test/OpenTelemetry.Shims.OpenTracing.Tests/TestTextMap.cs diff --git a/test/OpenTelemetry.Shims.OpenTracing.Tests/OpenTelemetry.Shims.OpenTracing.Tests.csproj b/test/OpenTelemetry.Shims.OpenTracing.Tests/OpenTelemetry.Shims.OpenTracing.Tests.csproj index fb6948c69e8..7e08df554f3 100644 --- a/test/OpenTelemetry.Shims.OpenTracing.Tests/OpenTelemetry.Shims.OpenTracing.Tests.csproj +++ b/test/OpenTelemetry.Shims.OpenTracing.Tests/OpenTelemetry.Shims.OpenTracing.Tests.csproj @@ -8,7 +8,6 @@ - runtime; build; native; contentfiles; analyzers diff --git a/test/OpenTelemetry.Shims.OpenTracing.Tests/ScopeManagerShimTests.cs b/test/OpenTelemetry.Shims.OpenTracing.Tests/ScopeManagerShimTests.cs index 4d0b4641525..1ae49d32318 100644 --- a/test/OpenTelemetry.Shims.OpenTracing.Tests/ScopeManagerShimTests.cs +++ b/test/OpenTelemetry.Shims.OpenTracing.Tests/ScopeManagerShimTests.cs @@ -15,7 +15,6 @@ // using System.Diagnostics; -using Moq; using OpenTelemetry.Trace; using Xunit; @@ -56,7 +55,7 @@ public void Activate_SpanMustBeShim() { var shim = new ScopeManagerShim(); - Assert.Throws(() => shim.Activate(new Mock().Object, true)); + Assert.Throws(() => shim.Activate(new TestSpan(), true)); } [Fact] diff --git a/test/OpenTelemetry.Shims.OpenTracing.Tests/TestFormatTextMap.cs b/test/OpenTelemetry.Shims.OpenTracing.Tests/TestFormatTextMap.cs new file mode 100644 index 00000000000..b16e3a50b7a --- /dev/null +++ b/test/OpenTelemetry.Shims.OpenTracing.Tests/TestFormatTextMap.cs @@ -0,0 +1,23 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using OpenTracing.Propagation; + +namespace OpenTelemetry.Shims.OpenTracing.Tests; + +internal class TestFormatTextMap : IFormat +{ +} diff --git a/test/OpenTelemetry.Shims.OpenTracing.Tests/TestSpan.cs b/test/OpenTelemetry.Shims.OpenTracing.Tests/TestSpan.cs new file mode 100644 index 00000000000..f2e4e54f4b5 --- /dev/null +++ b/test/OpenTelemetry.Shims.OpenTracing.Tests/TestSpan.cs @@ -0,0 +1,110 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using OpenTracing; +using OpenTracing.Tag; + +namespace OpenTelemetry.Shims.OpenTracing.Tests; + +internal class TestSpan : ISpan +{ + public ISpanContext Context => throw new NotImplementedException(); + + public void Finish() + { + throw new NotImplementedException(); + } + + public void Finish(DateTimeOffset finishTimestamp) + { + throw new NotImplementedException(); + } + + public string GetBaggageItem(string key) + { + throw new NotImplementedException(); + } + + public ISpan Log(IEnumerable> fields) + { + throw new NotImplementedException(); + } + + public ISpan Log(DateTimeOffset timestamp, IEnumerable> fields) + { + throw new NotImplementedException(); + } + + public ISpan Log(string @event) + { + throw new NotImplementedException(); + } + + public ISpan Log(DateTimeOffset timestamp, string @event) + { + throw new NotImplementedException(); + } + + public ISpan SetBaggageItem(string key, string value) + { + throw new NotImplementedException(); + } + + public ISpan SetOperationName(string operationName) + { + throw new NotImplementedException(); + } + + public ISpan SetTag(string key, string value) + { + throw new NotImplementedException(); + } + + public ISpan SetTag(string key, bool value) + { + throw new NotImplementedException(); + } + + public ISpan SetTag(string key, int value) + { + throw new NotImplementedException(); + } + + public ISpan SetTag(string key, double value) + { + throw new NotImplementedException(); + } + + public ISpan SetTag(BooleanTag tag, bool value) + { + throw new NotImplementedException(); + } + + public ISpan SetTag(IntOrStringTag tag, string value) + { + throw new NotImplementedException(); + } + + public ISpan SetTag(IntTag tag, int value) + { + throw new NotImplementedException(); + } + + public ISpan SetTag(StringTag tag, string value) + { + throw new NotImplementedException(); + } +} diff --git a/test/OpenTelemetry.Shims.OpenTracing.Tests/TestSpanContext.cs b/test/OpenTelemetry.Shims.OpenTracing.Tests/TestSpanContext.cs new file mode 100644 index 00000000000..097a54aab44 --- /dev/null +++ b/test/OpenTelemetry.Shims.OpenTracing.Tests/TestSpanContext.cs @@ -0,0 +1,31 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using OpenTracing; + +namespace OpenTelemetry.Shims.OpenTracing.Tests; + +internal class TestSpanContext : ISpanContext +{ + public string TraceId => throw new NotImplementedException(); + + public string SpanId => throw new NotImplementedException(); + + public IEnumerable> GetBaggageItems() + { + throw new NotImplementedException(); + } +} diff --git a/test/OpenTelemetry.Shims.OpenTracing.Tests/TestTextMap.cs b/test/OpenTelemetry.Shims.OpenTracing.Tests/TestTextMap.cs new file mode 100644 index 00000000000..f72f78b5f44 --- /dev/null +++ b/test/OpenTelemetry.Shims.OpenTracing.Tests/TestTextMap.cs @@ -0,0 +1,47 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System.Collections; +using OpenTracing.Propagation; + +namespace OpenTelemetry.Shims.OpenTracing.Tests; + +internal class TestTextMap : ITextMap +{ + public bool GetEnumeratorCalled { get; private set; } + + public bool SetCalled { get; private set; } + +#pragma warning disable IDE0028 // Simplify collection initialization + public Dictionary Items { get; } = new(); +#pragma warning restore IDE0028 // Simplify collection initialization + + public IEnumerator> GetEnumerator() + { + this.GetEnumeratorCalled = true; + return this.Items.GetEnumerator(); + } + + public void Set(string key, string value) + { + this.SetCalled = true; + } + + IEnumerator IEnumerable.GetEnumerator() + { + throw new NotImplementedException(); + } +} diff --git a/test/OpenTelemetry.Shims.OpenTracing.Tests/TracerShimTests.cs b/test/OpenTelemetry.Shims.OpenTracing.Tests/TracerShimTests.cs index 08f2147c7cb..ec9cabfa41f 100644 --- a/test/OpenTelemetry.Shims.OpenTracing.Tests/TracerShimTests.cs +++ b/test/OpenTelemetry.Shims.OpenTracing.Tests/TracerShimTests.cs @@ -16,7 +16,6 @@ using System.Collections; using System.Diagnostics; -using Moq; using OpenTelemetry.Context.Propagation; using OpenTelemetry.Trace; using OpenTracing; @@ -31,10 +30,10 @@ public class TracerShimTests public void CtorArgumentValidation() { // null tracer provider and text format - Assert.Throws(() => new TracerShim((TracerProvider)null, null)); + Assert.Throws(() => new TracerShim(null, null)); // null tracer provider - Assert.Throws(() => new TracerShim((TracerProvider)null, new TraceContextPropagator())); + Assert.Throws(() => new TracerShim(null, new TraceContextPropagator())); } [Fact] @@ -61,13 +60,13 @@ public void Inject_ArgumentValidation() var shim = new TracerShim(TracerProvider.Default, new TraceContextPropagator()); var spanContextShim = new SpanContextShim(new SpanContext(ActivityTraceId.CreateRandom(), ActivitySpanId.CreateRandom(), ActivityTraceFlags.None)); - var mockFormat = new Mock>(); - var mockCarrier = new Mock(); + var testFormat = new TestFormatTextMap(); + var testCarrier = new TestTextMap(); - Assert.Throws(() => shim.Inject(null, mockFormat.Object, mockCarrier.Object)); - Assert.Throws(() => shim.Inject(new Mock().Object, mockFormat.Object, mockCarrier.Object)); - Assert.Throws(() => shim.Inject(spanContextShim, null, mockCarrier.Object)); - Assert.Throws(() => shim.Inject(spanContextShim, mockFormat.Object, null)); + Assert.Throws(() => shim.Inject(null, testFormat, testCarrier)); + Assert.Throws(() => shim.Inject(new TestSpanContext(), testFormat, testCarrier)); + Assert.Throws(() => shim.Inject(spanContextShim, null, testCarrier)); + Assert.Throws(() => shim.Inject(spanContextShim, testFormat, null)); } [Fact] @@ -78,11 +77,11 @@ public void Inject_UnknownFormatIgnored() var spanContextShim = new SpanContextShim(new SpanContext(ActivityTraceId.CreateRandom(), ActivitySpanId.CreateRandom(), ActivityTraceFlags.Recorded)); // Only two specific types of ITextMap are supported, and neither is a Mock. - var mockCarrier = new Mock(); - shim.Inject(spanContextShim, new Mock>().Object, mockCarrier.Object); + var testCarrier = new TestTextMap(); + shim.Inject(spanContextShim, new TestFormatTextMap(), testCarrier); - // Verify that the carrier mock was never called. - mockCarrier.Verify(x => x.Set(It.IsAny(), It.IsAny()), Times.Never); + // Verify that the test carrier was never called. + Assert.False(testCarrier.SetCalled); } [Fact] @@ -90,23 +89,22 @@ public void Extract_ArgumentValidation() { var shim = new TracerShim(TracerProvider.Default, new TraceContextPropagator()); - Assert.Throws(() => shim.Extract(null, new Mock().Object)); - Assert.Throws(() => shim.Extract(new Mock>().Object, null)); + Assert.Throws(() => shim.Extract(null, new TestTextMap())); + Assert.Throws(() => shim.Extract(new TestFormatTextMap(), null)); } [Fact] public void Extract_UnknownFormatIgnored() { var shim = new TracerShim(TracerProvider.Default, new TraceContextPropagator()); - - var spanContextShim = new SpanContextShim(new SpanContext(ActivityTraceId.CreateRandom(), ActivitySpanId.CreateRandom(), ActivityTraceFlags.None)); + _ = new SpanContextShim(new SpanContext(ActivityTraceId.CreateRandom(), ActivitySpanId.CreateRandom(), ActivityTraceFlags.None)); // Only two specific types of ITextMap are supported, and neither is a Mock. - var mockCarrier = new Mock(); - var context = shim.Extract(new Mock>().Object, mockCarrier.Object); + var testCarrier = new TestTextMap(); + _ = shim.Extract(new TestFormatTextMap(), testCarrier); - // Verify that the carrier mock was never called. - mockCarrier.Verify(x => x.GetEnumerator(), Times.Never); + // Verify that the test carrier was never called. + Assert.False(testCarrier.SetCalled); } [Fact] @@ -114,20 +112,15 @@ public void Extract_InvalidTraceParent() { var shim = new TracerShim(TracerProvider.Default, new TraceContextPropagator()); - var mockCarrier = new Mock(); + var testCarrier = new TestTextMap(); // The ProxyTracer uses OpenTelemetry.Context.Propagation.TraceContextPropagator, so we need to satisfy the traceparent key at the least - var carrierMap = new Dictionary - { - // This is an invalid traceparent value - { "traceparent", "unused" }, - }; + testCarrier.Items["traceparent"] = "unused"; - mockCarrier.Setup(x => x.GetEnumerator()).Returns(carrierMap.GetEnumerator()); - var spanContextShim = shim.Extract(BuiltinFormats.TextMap, mockCarrier.Object) as SpanContextShim; + var spanContextShim = shim.Extract(BuiltinFormats.TextMap, testCarrier) as SpanContextShim; // Verify that the carrier was called - mockCarrier.Verify(x => x.GetEnumerator(), Times.Once); + Assert.True(testCarrier.GetEnumeratorCalled); Assert.Null(spanContextShim); }