public async Task HttpOutCallsAreCollectedSuccessfullyAsync(HttpTestData.HttpOutTestCase tc)
        {
            var serverLifeTime = TestHttpServer.RunServer(
                (ctx) =>
            {
                ctx.Response.StatusCode = tc.ResponseCode == 0 ? 200 : tc.ResponseCode;
                ctx.Response.OutputStream.Close();
            },
                out var host,
                out var port);

            var expectedResource = Resources.Resources.CreateServiceResource("test-service");
            var spanProcessor    = new Mock <ActivityProcessor>();

            tc.Url = HttpTestData.NormalizeValues(tc.Url, host, port);

            using (serverLifeTime)

                using (OpenTelemetrySdk.CreateTracerProvider(
                           (builder) => builder.AddHttpClientDependencyInstrumentation((opt) => opt.SetHttpFlavor = tc.SetHttpFlavor)
                           .SetResource(expectedResource)
                           .AddProcessorPipeline(p => p.AddProcessor(n => spanProcessor.Object))))
                {
                    try
                    {
                        using var c = new HttpClient();
                        var request = new HttpRequestMessage
                        {
                            RequestUri = new Uri(tc.Url),
                            Method     = new HttpMethod(tc.Method),
                            Version    = new Version(2, 0),
                        };

                        if (tc.Headers != null)
                        {
                            foreach (var header in tc.Headers)
                            {
                                request.Headers.Add(header.Key, header.Value);
                            }
                        }

                        await c.SendAsync(request);
                    }
                    catch (Exception)
                    {
                        // test case can intentionally send request that will result in exception
                    }
                }

            Assert.Equal(2, spanProcessor.Invocations.Count); // begin and end was called
            var span = (Activity)spanProcessor.Invocations[1].Arguments[0];

            Assert.Equal(tc.SpanName, span.DisplayName);
            Assert.Equal(tc.SpanKind, span.Kind.ToString());

            var d = new Dictionary <string, string>()
            {
                { "Ok", "OK" },
                { "Cancelled", "CANCELLED" },
                { "Unknown", "UNKNOWN" },
                { "InvalidArgument", "INVALID_ARGUMENT" },
                { "DeadlineExceeded", "DEADLINE_EXCEEDED" },
                { "NotFound", "NOT_FOUND" },
                { "AlreadyExists", "ALREADY_EXISTS" },
                { "PermissionDenied", "PERMISSION_DENIED" },
                { "ResourceExhausted", "RESOURCE_EXHAUSTED" },
                { "FailedPrecondition", "FAILED_PRECONDITION" },
                { "Aborted", "ABORTED" },
                { "OutOfRange", "OUT_OF_RANGE" },
                { "Unimplemented", "UNIMPLEMENTED" },
                { "Internal", "INTERNAL" },
                { "Unavailable", "UNAVAILABLE" },
                { "DataLoss", "DATA_LOSS" },
                { "Unauthenticated", "UNAUTHENTICATED" },
            };

            // Assert.Equal(tc.SpanStatus, d[span.Status.CanonicalCode]);
            Assert.Equal(
                tc.SpanStatus,
                d[span.Tags.FirstOrDefault(i => i.Key == SpanAttributeConstants.StatusCodeKey).Value]);

            if (tc.SpanStatusHasDescription.HasValue)
            {
                var desc = span.Tags.FirstOrDefault(i => i.Key == SpanAttributeConstants.StatusDescriptionKey).Value;
                Assert.Equal(tc.SpanStatusHasDescription.Value, !string.IsNullOrEmpty(desc));
            }

            var normalizedAttributes         = span.Tags.Where(kv => !kv.Key.StartsWith("ot")).ToImmutableSortedDictionary(x => x.Key, x => x.Value.ToString());
            var normalizedAttributesTestCase = tc.SpanAttributes.ToDictionary(x => x.Key, x => HttpTestData.NormalizeValues(x.Value, host, port));

            Assert.Equal(normalizedAttributesTestCase.Count, normalizedAttributes.Count);

            foreach (var kv in normalizedAttributesTestCase)
            {
                // TODO: Fix this test. This is mostly broken because Status is stored in tags.
                // Assert.Contains(span.Tags, i => i.Key == kv.Key && i.Value.Equals(kv.Value, StringComparison.InvariantCultureIgnoreCase));
            }

            Assert.Equal(expectedResource, span.GetResource());
        }
Beispiel #2
0
        public void HttpOutCallsAreCollectedSuccessfullyAsync(HttpTestData.HttpOutTestCase tc)
        {
            using var serverLifeTime = TestHttpServer.RunServer(
                      (ctx) =>
            {
                ctx.Response.StatusCode = tc.ResponseCode == 0 ? 200 : tc.ResponseCode;
                ctx.Response.OutputStream.Close();
            },
                      out var host,
                      out var port);

            var expectedResource  = Resources.Resources.CreateServiceResource("test-service");
            var activityProcessor = new Mock <ActivityProcessor>();

            using var shutdownSignal = OpenTelemetrySdk.EnableOpenTelemetry(b =>
            {
                b.SetResource(expectedResource);
                b.AddProcessorPipeline(c => c.AddProcessor(ap => activityProcessor.Object));
                b.AddHttpWebRequestDependencyInstrumentation();
            });

            tc.Url = HttpTestData.NormalizeValues(tc.Url, host, port);

            try
            {
                var request = (HttpWebRequest)WebRequest.Create(tc.Url);

                request.Method = tc.Method;

                if (tc.Headers != null)
                {
                    foreach (var header in tc.Headers)
                    {
                        request.Headers.Add(header.Key, header.Value);
                    }
                }

                request.ContentLength = 0;

                using var response = (HttpWebResponse)request.GetResponse();

                new StreamReader(response.GetResponseStream()).ReadToEnd();
            }
            catch (Exception)
            {
                // test case can intentionally send request that will result in exception
            }

            Assert.Equal(2, activityProcessor.Invocations.Count); // begin and end was called
            var activity = (Activity)activityProcessor.Invocations[1].Arguments[0];

            Assert.Equal(tc.SpanName, activity.DisplayName);
            Assert.Equal(tc.SpanKind, activity.Kind.ToString());

            var d = new Dictionary <string, string>()
            {
                { StatusCanonicalCode.Ok.ToString(), "OK" },
                { StatusCanonicalCode.Cancelled.ToString(), "CANCELLED" },
                { StatusCanonicalCode.Unknown.ToString(), "UNKNOWN" },
                { StatusCanonicalCode.InvalidArgument.ToString(), "INVALID_ARGUMENT" },
                { StatusCanonicalCode.DeadlineExceeded.ToString(), "DEADLINE_EXCEEDED" },
                { StatusCanonicalCode.NotFound.ToString(), "NOT_FOUND" },
                { StatusCanonicalCode.AlreadyExists.ToString(), "ALREADY_EXISTS" },
                { StatusCanonicalCode.PermissionDenied.ToString(), "PERMISSION_DENIED" },
                { StatusCanonicalCode.ResourceExhausted.ToString(), "RESOURCE_EXHAUSTED" },
                { StatusCanonicalCode.FailedPrecondition.ToString(), "FAILED_PRECONDITION" },
                { StatusCanonicalCode.Aborted.ToString(), "ABORTED" },
                { StatusCanonicalCode.OutOfRange.ToString(), "OUT_OF_RANGE" },
                { StatusCanonicalCode.Unimplemented.ToString(), "UNIMPLEMENTED" },
                { StatusCanonicalCode.Internal.ToString(), "INTERNAL" },
                { StatusCanonicalCode.Unavailable.ToString(), "UNAVAILABLE" },
                { StatusCanonicalCode.DataLoss.ToString(), "DATA_LOSS" },
                { StatusCanonicalCode.Unauthenticated.ToString(), "UNAUTHENTICATED" },
            };

            tc.SpanAttributes = tc.SpanAttributes.ToDictionary(
                x => x.Key,
                x =>
            {
                if (x.Key == "http.flavor" && x.Value == "2.0")
                {
                    return("1.1");
                }

                return(HttpTestData.NormalizeValues(x.Value, host, port));
            });

            foreach (KeyValuePair <string, string> tag in activity.Tags)
            {
                if (!tc.SpanAttributes.TryGetValue(tag.Key, out string value))
                {
                    if (tag.Key == "http.flavor")
                    {
                        // http.flavor is optional in .NET Core instrumentation but there is no way to pass that option to the new ActivitySource model so it always shows up here.
                        if (tc.SetHttpFlavor)
                        {
                            Assert.Equal(value, tag.Value);
                        }

                        continue;
                    }

                    if (tag.Key == SpanAttributeConstants.StatusCodeKey)
                    {
                        Assert.Equal(tc.SpanStatus, d[tag.Value]);
                        continue;
                    }

                    if (tag.Key == SpanAttributeConstants.StatusDescriptionKey)
                    {
                        if (tc.SpanStatusHasDescription.HasValue)
                        {
                            Assert.Equal(tc.SpanStatusHasDescription.Value, !string.IsNullOrEmpty(tag.Value));
                        }

                        continue;
                    }

                    Assert.True(false, $"Tag {tag.Key} was not found in test data.");
                }

                Assert.Equal(value, tag.Value);
            }

            Assert.Equal(expectedResource, activity.GetResource());
        }
Beispiel #3
0
        public async Task HttpOutCallsAreCollectedSuccessfullyAsync(HttpTestData.HttpOutTestCase tc)
        {
            var serverLifeTime = TestHttpServer.RunServer(
                (ctx) =>
            {
                ctx.Response.StatusCode = tc.ResponseCode == 0 ? 200 : tc.ResponseCode;
                ctx.Response.OutputStream.Close();
            },
                out var host,
                out var port);

            var spanProcessor = new Mock <SpanProcessor>();
            var tracer        = TracerFactory.Create(b => b
                                                     .AddProcessorPipeline(p => p.AddProcessor(_ => spanProcessor.Object)))
                                .GetTracer(null);

            tc.Url = HttpTestData.NormalizeValues(tc.Url, host, port);

            using (serverLifeTime)

                using (new HttpClientInstrumentation(tracer, new HttpClientInstrumentationOptions()
                {
                    SetHttpFlavor = tc.SetHttpFlavor
                }))
                {
                    try
                    {
                        using var c = new HttpClient();
                        var request = new HttpRequestMessage
                        {
                            RequestUri = new Uri(tc.Url),
                            Method     = new HttpMethod(tc.Method),
                            Version    = new Version(2, 0),
                        };

                        if (tc.Headers != null)
                        {
                            foreach (var header in tc.Headers)
                            {
                                request.Headers.Add(header.Key, header.Value);
                            }
                        }

                        await c.SendAsync(request);
                    }
                    catch (Exception)
                    {
                        //test case can intentionally send request that will result in exception
                    }
                }

            Assert.Equal(2, spanProcessor.Invocations.Count); // begin and end was called
            var span = (SpanData)spanProcessor.Invocations[1].Arguments[0];

            Assert.Equal(tc.SpanName, span.Name);
            Assert.Equal(tc.SpanKind, span.Kind.ToString());

            var d = new Dictionary <StatusCanonicalCode, string>()
            {
                { StatusCanonicalCode.Ok, "OK" },
                { StatusCanonicalCode.Cancelled, "CANCELLED" },
                { StatusCanonicalCode.Unknown, "UNKNOWN" },
                { StatusCanonicalCode.InvalidArgument, "INVALID_ARGUMENT" },
                { StatusCanonicalCode.DeadlineExceeded, "DEADLINE_EXCEEDED" },
                { StatusCanonicalCode.NotFound, "NOT_FOUND" },
                { StatusCanonicalCode.AlreadyExists, "ALREADY_EXISTS" },
                { StatusCanonicalCode.PermissionDenied, "PERMISSION_DENIED" },
                { StatusCanonicalCode.ResourceExhausted, "RESOURCE_EXHAUSTED" },
                { StatusCanonicalCode.FailedPrecondition, "FAILED_PRECONDITION" },
                { StatusCanonicalCode.Aborted, "ABORTED" },
                { StatusCanonicalCode.OutOfRange, "OUT_OF_RANGE" },
                { StatusCanonicalCode.Unimplemented, "UNIMPLEMENTED" },
                { StatusCanonicalCode.Internal, "INTERNAL" },
                { StatusCanonicalCode.Unavailable, "UNAVAILABLE" },
                { StatusCanonicalCode.DataLoss, "DATA_LOSS" },
                { StatusCanonicalCode.Unauthenticated, "UNAUTHENTICATED" },
            };

            Assert.Equal(tc.SpanStatus, d[span.Status.CanonicalCode]);
            if (tc.SpanStatusHasDescription.HasValue)
            {
                Assert.Equal(tc.SpanStatusHasDescription.Value, !string.IsNullOrEmpty(span.Status.Description));
            }

            var normalizedAttributes = span.Attributes.ToDictionary(x => x.Key, x => x.Value.ToString());

            tc.SpanAttributes = tc.SpanAttributes.ToDictionary(x => x.Key, x => HttpTestData.NormalizeValues(x.Value, host, port));

            Assert.Equal(tc.SpanAttributes, normalizedAttributes);
        }