public async Task DoNotInjectTraceParentWhenPresent(string method) { try { using var eventRecords = new EventObserverAndRecorder(); // Send a random Http request to generate some events using (var client = new HttpClient()) using (var request = new HttpRequestMessage(HttpMethod.Get, this.BuildRequestUrl())) { request.Headers.Add("traceparent", "00-abcdef0123456789abcdef0123456789-abcdef0123456789-01"); if (method == "GET") { request.Method = HttpMethod.Get; } else { request.Method = HttpMethod.Post; request.Content = new StringContent("hello world"); } (await client.SendAsync(request)).Dispose(); } // No events are sent. Assert.Empty(eventRecords.Records); } finally { this.CleanUpActivity(); } }
public async Task DoNotInjectTraceParentWhenPresent() { try { using (var eventRecords = new EventObserverAndRecorder()) { Activity.DefaultIdFormat = ActivityIdFormat.W3C; Activity.ForceDefaultIdFormat = true; // Send a random Http request to generate some events using (var client = new HttpClient()) using (var request = new HttpRequestMessage(HttpMethod.Get, Configuration.Http.RemoteEchoServer)) { request.Headers.Add("traceparent", "00-abcdef0123456789abcdef0123456789-abcdef0123456789-01"); (await client.SendAsync(request)).Dispose(); } // Check to make sure: The first record must be a request, the next record must be a response. Assert.True(eventRecords.Records.TryDequeue(out var evnt)); HttpWebRequest startRequest = ReadPublicProperty <HttpWebRequest>(evnt.Value, "Request"); Assert.NotNull(startRequest); Assert.Equal("00-abcdef0123456789abcdef0123456789-abcdef0123456789-01", startRequest.Headers["traceparent"]); } } finally { CleanUp(); } }
public async Task TestW3CHeaders() { try { using (var eventRecords = new EventObserverAndRecorder()) { Activity.DefaultIdFormat = ActivityIdFormat.W3C; Activity.ForceDefaultIdFormat = true; // Send a random Http request to generate some events using (var client = new HttpClient()) { (await client.GetAsync(Configuration.Http.RemoteEchoServer)).Dispose(); } // Check to make sure: The first record must be a request, the next record must be a response. KeyValuePair <string, object> startEvent; Assert.True(eventRecords.Records.TryDequeue(out startEvent)); Assert.Equal("System.Net.Http.Desktop.HttpRequestOut.Start", startEvent.Key); HttpWebRequest startRequest = ReadPublicProperty <HttpWebRequest>(startEvent.Value, "Request"); Assert.NotNull(startRequest); var traceparent = startRequest.Headers["traceparent"]; Assert.NotNull(traceparent); Assert.True(Regex.IsMatch(traceparent, "^[0-9a-f][0-9a-f]-[0-9a-f]{32}-[0-9a-f]{16}-[0-9a-f][0-9a-f]$")); Assert.Null(startRequest.Headers["tracestate"]); Assert.Null(startRequest.Headers["Request-Id"]); } } finally { CleanUp(); } }
public async Task TestResponseWithoutContentEvents(string method) { using var eventRecords = new EventObserverAndRecorder(); // Send a random Http request to generate some events using (var client = new HttpClient()) { using HttpResponseMessage response = method == "GET" ? await client.GetAsync(this.BuildRequestUrl (queryString : "responseCode=204")) : await client.PostAsync(this.BuildRequestUrl (queryString : "responseCode=204"), new StringContent ("hello world")); } // We should have exactly one Start and one Stop event Assert.Equal(2, eventRecords.Records.Count); Assert.Equal(1, eventRecords.Records.Count(rec => rec.Key.EndsWith("Start"))); Assert.Equal(1, eventRecords.Records.Count(rec => rec.Key.EndsWith("Stop"))); // Check to make sure: The first record must be a request, the next record must be a response. HttpWebRequest startRequest = AssertFirstEventWasStart(eventRecords); VerifyHeaders(startRequest); Assert.True(eventRecords.Records.TryDequeue(out var stopEvent)); Assert.Equal(HttpWebRequestDiagnosticSource.RequestStopName, stopEvent.Key); HttpWebRequest stopRequest = ReadPublicProperty <HttpWebRequest>(stopEvent.Value, "Request"); Assert.Equal(startRequest, stopRequest); HttpWebResponse stopResponse = ReadPublicProperty <HttpWebResponse>(stopEvent.Value, "Response"); Assert.NotNull(stopResponse); }
public async Task TestRequestWithException(string method) { using var eventRecords = new EventObserverAndRecorder(); var ex = await Assert.ThrowsAsync <HttpRequestException>(() => { return(method == "GET" ? new HttpClient().GetAsync($"http://{Guid.NewGuid()}.com") : new HttpClient().PostAsync($"http://{Guid.NewGuid()}.com", new StringContent("hello world"))); }); // check that request failed because of the wrong domain name and not because of reflection var webException = (WebException)ex.InnerException; Assert.NotNull(webException); Assert.True(webException.Status == WebExceptionStatus.NameResolutionFailure); // We should have one Start event, no Stop event, and one Exception event. Assert.Equal(2, eventRecords.Records.Count()); Assert.Equal(1, eventRecords.Records.Count(rec => rec.Key.EndsWith("Start"))); Assert.Equal(1, eventRecords.Records.Count(rec => rec.Key.EndsWith("Exception"))); // Check to make sure: The first record must be a request, the next record must be an exception. HttpWebRequest startRequest = AssertFirstEventWasStart(eventRecords); Assert.True(eventRecords.Records.TryDequeue(out KeyValuePair <string, object> exceptionEvent)); Assert.Equal(HttpWebRequestDiagnosticSource.RequestExceptionName, exceptionEvent.Key); HttpWebRequest exceptionRequest = ReadPublicProperty <HttpWebRequest>(exceptionEvent.Value, "Request"); Assert.Equal(startRequest, exceptionRequest); Exception exceptionException = ReadPublicProperty <Exception>(exceptionEvent.Value, "Exception"); Assert.Equal(webException, exceptionException); }
public async Task TestBasicReceiveAndResponseEvents() { using (var eventRecords = new EventObserverAndRecorder()) { // Send a random Http request to generate some events await new HttpClient().GetAsync("http://www.bing.com"); // Just make sure some events are written, to confirm we successfully subscribed to it. We should have // at least two events, one for request send, and one for response receive Assert.Equal(1, eventRecords.Records.Count(rec => rec.Key.EndsWith("Start"))); Assert.Equal(1, eventRecords.Records.Count(rec => rec.Key.EndsWith("Stop"))); // Check to make sure: The first record must be a request, the next record must be a response. // The rest is unknown number of responses (it depends on # of redirections) KeyValuePair <string, object> startEvent; Assert.True(eventRecords.Records.TryDequeue(out startEvent)); Assert.Equal("System.Net.Http.Desktop.HttpRequestOut.Start", startEvent.Key); WebRequest startRequest = ReadPublicProperty <WebRequest>(startEvent.Value, "Request"); Assert.NotNull(startRequest.Headers["Request-Id"]); KeyValuePair <string, object> stopEvent; Assert.True(eventRecords.Records.TryDequeue(out stopEvent)); Assert.Equal("System.Net.Http.Desktop.HttpRequestOut.Stop", stopEvent.Key); WebRequest stopRequest = ReadPublicProperty <WebRequest>(stopEvent.Value, "Request"); Assert.Equal(startRequest, stopRequest); } }
public async Task TestSecureTransportRetryFailureRequest(string method) { // This test sends an https request to an endpoint only set up for http. // It should retry. What we want to test for is 1 start, 1 exception event even // though multiple are actually sent. using var eventRecords = new EventObserverAndRecorder(); using (var client = new HttpClient()) { var ex = await Assert.ThrowsAnyAsync <Exception>(() => { return(method == "GET" ? client.GetAsync(this.BuildRequestUrl(useHttps: true)) : client.PostAsync(this.BuildRequestUrl(useHttps: true), new StringContent("hello world"))); }); Assert.True(ex is HttpRequestException); } // We should have one Start event, no Stop event, and one Exception event. Assert.Equal(2, eventRecords.Records.Count()); Assert.Equal(1, eventRecords.Records.Count(rec => rec.Key.EndsWith("Start"))); Assert.Equal(1, eventRecords.Records.Count(rec => rec.Key.EndsWith("Exception"))); }
public async Task TestInvalidBaggage() { var parentActivity = new Activity("parent") .AddBaggage("key", "value") .AddBaggage("bad/key", "value") .AddBaggage("goodkey", "bad/value") .Start(); using (var eventRecords = new EventObserverAndRecorder()) { using (var client = new HttpClient()) { (await client.GetAsync(this.BuildRequestUrl())).Dispose(); } Assert.Equal(2, eventRecords.Records.Count()); Assert.Equal(1, eventRecords.Records.Count(rec => rec.Key.EndsWith("Start"))); Assert.Equal(1, eventRecords.Records.Count(rec => rec.Key.EndsWith("Stop"))); WebRequest thisRequest = ReadPublicProperty <WebRequest>(eventRecords.Records.First().Value, "Request"); string[] correlationContext = thisRequest.Headers["Correlation-Context"].Split(','); Assert.Equal(3, correlationContext.Length); Assert.Contains("key=value", correlationContext); Assert.Contains("bad%2Fkey=value", correlationContext); Assert.Contains("goodkey=bad%2Fvalue", correlationContext); } parentActivity.Stop(); }
public async Task TestBasicReceiveAndResponseEvents() { using (var eventRecords = new EventObserverAndRecorder()) { // Send a random Http request to generate some events using (var client = new HttpClient()) { (await client.GetAsync(Configuration.Http.RemoteEchoServer)).Dispose(); } // We should have exactly one Start and one Stop event Assert.Equal(1, eventRecords.Records.Count(rec => rec.Key.EndsWith("Start"))); Assert.Equal(1, eventRecords.Records.Count(rec => rec.Key.EndsWith("Stop"))); Assert.Equal(2, eventRecords.Records.Count); // Check to make sure: The first record must be a request, the next record must be a response. KeyValuePair <string, object> startEvent; Assert.True(eventRecords.Records.TryDequeue(out startEvent)); Assert.Equal("System.Net.Http.Desktop.HttpRequestOut.Start", startEvent.Key); HttpWebRequest startRequest = ReadPublicProperty <HttpWebRequest>(startEvent.Value, "Request"); Assert.NotNull(startRequest); Assert.NotNull(startRequest.Headers["Request-Id"]); KeyValuePair <string, object> stopEvent; Assert.True(eventRecords.Records.TryDequeue(out stopEvent)); Assert.Equal("System.Net.Http.Desktop.HttpRequestOut.Stop", stopEvent.Key); HttpWebRequest stopRequest = ReadPublicProperty <HttpWebRequest>(stopEvent.Value, "Request"); Assert.Equal(startRequest, stopRequest); HttpWebResponse response = ReadPublicProperty <HttpWebResponse>(stopEvent.Value, "Response"); Assert.NotNull(response); } }
public async Task TestActivityIsCreated() { var parentActivity = new Activity("parent").AddBaggage("k1", "v1").AddBaggage("k2", "v2").Start(); using (var eventRecords = new EventObserverAndRecorder()) { using (var client = new HttpClient()) { (await client.GetAsync(Configuration.Http.RemoteEchoServer)).Dispose(); } Assert.Equal(1, eventRecords.Records.Count(rec => rec.Key.EndsWith("Start"))); Assert.Equal(1, eventRecords.Records.Count(rec => rec.Key.EndsWith("Stop"))); WebRequest thisRequest = ReadPublicProperty <WebRequest>(eventRecords.Records.First().Value, "Request"); var requestId = thisRequest.Headers["Request-Id"]; var correlationContext = thisRequest.Headers["Correlation-Context"]; Assert.NotNull(requestId); Assert.True(requestId.StartsWith(parentActivity.Id)); Assert.NotNull(correlationContext); Assert.True(correlationContext == "k1=v1,k2=v2" || correlationContext == "k2=v2,k1=v1"); } parentActivity.Stop(); }
public async Task TestIsEnabledAllOff() { using (var eventRecords = new EventObserverAndRecorder((evnt, arg1, arg2) => false)) { await new HttpClient().GetAsync("http://www.bing.com"); Assert.Equal(0, eventRecords.Records.Count); } }
public async Task TestIsEnabledAllOff() { using var eventRecords = new EventObserverAndRecorder((evnt, arg1, arg2) => false); using (var client = new HttpClient()) { (await client.GetAsync(this.BuildRequestUrl())).Dispose(); } Assert.Empty(eventRecords.Records); }
public void TestReflectInitializationViaSubscription1() { EventObserverAndRecorder eventRecords = CreateEventRecorder(); // Send a random Http request to generate some events HttpResponseMessage message = new HttpClient().GetAsync("http://www.bing.com").Result; // Just make sure some events are written, to confirm we successfully subscribed to it. We should have // at least two events, one for request send, and one for response receive Assert.True(eventRecords.Records.Count >= 2, "Didn't get two or more events from Http Diagnostic Listener. Something is wrong."); }
public async Task TestIsEnabledAllOff() { using (var eventRecords = new EventObserverAndRecorder((evnt, arg1, arg2) => false)) { using (var client = new HttpClient()) { (await client.GetAsync(Configuration.Http.RemoteEchoServer)).Dispose(); } Assert.Equal(0, eventRecords.Records.Count); } }
public void TestReflectInitializationViaSubscription3() { using (var eventRecords = new EventObserverAndRecorder((eventName, arg1, arg2) => true)) { // Send a random Http request to generate some events new HttpClient().GetAsync("http://www.bing.com").Wait(); // Just make sure some events are written, to confirm we successfully subscribed to it. We should have // at least two events, one for request send, and one for response receive Assert.Equal(2, eventRecords.Records.Count); } }
private EventObserverAndRecorder CreateEventRecorder() { EventObserverAndRecorder eventRecords = new EventObserverAndRecorder(); DiagnosticListener.AllListeners.Subscribe(new CallbackObserver <DiagnosticListener>(diagnosticListener => { if (diagnosticListener.Name == "System.Net.Http.Desktop") { diagnosticListener.Subscribe(eventRecords); } })); return(eventRecords); }
public async Task TestCanceledRequest() { using (var eventRecords = new EventObserverAndRecorder()) { CancellationTokenSource cts = new CancellationTokenSource(TimeSpan.FromMilliseconds(1)); await Assert.ThrowsAsync <TaskCanceledException>( () => new HttpClient().GetAsync("http://bing.com", cts.Token)); // Just make sure some events are written, to confirm we successfully subscribed to it. We should have // at least two events, one for request send, and one for response receive Assert.Equal(1, eventRecords.Records.Count(rec => rec.Key.EndsWith("Start"))); Assert.Equal(0, eventRecords.Records.Count(rec => rec.Key.EndsWith("Stop"))); } }
public async Task TestReflectInitializationViaSubscription3() { using var eventRecords = new EventObserverAndRecorder((eventName, arg1, arg2) => true); // Send a random Http request to generate some events using (var client = new HttpClient()) { (await client.GetAsync(this.BuildRequestUrl())).Dispose(); } // Just make sure some events are written, to confirm we successfully subscribed to it. // We should have exactly one Start and one Stop event Assert.Equal(2, eventRecords.Records.Count); }
public void TestReflectInitializationViaSubscription3() { using (var eventRecords = new EventObserverAndRecorder((eventName, arg1, arg2) => true)) { // Send a random Http request to generate some events using (var client = new HttpClient()) { client.GetAsync(Configuration.Http.RemoteEchoServer).Result.Dispose(); } // Just make sure some events are written, to confirm we successfully subscribed to it. // We should have exactly one Start and one Stop event Assert.Equal(2, eventRecords.Records.Count); } }
public async Task TestCanceledRequest() { CancellationTokenSource cts = new CancellationTokenSource(TimeSpan.FromSeconds(10)); using (var eventRecords = new EventObserverAndRecorder(_ => { cts.Cancel(); })) { var ex = await Assert.ThrowsAnyAsync <Exception>(() => new HttpClient().GetAsync("http://bing.com", cts.Token)); Assert.True(ex is TaskCanceledException || ex is WebException); // Just make sure some events are written, to confirm we successfully subscribed to it. We should have // 1 start event and no stop events Assert.Equal(1, eventRecords.Records.Count(rec => rec.Key.EndsWith("Start"))); Assert.Equal(0, eventRecords.Records.Count(rec => rec.Key.EndsWith("Stop"))); } }
public async Task TestRedirectedRequest() { using (var eventRecords = new EventObserverAndRecorder()) { using (var client = new HttpClient()) { Uri uriWithRedirect = Configuration.Http.RedirectUriForDestinationUri(true, 302, Configuration.Http.RemoteEchoServer, 10); (await client.GetAsync(uriWithRedirect)).Dispose(); } // We should have exactly one Start and one Stop event Assert.Equal(1, eventRecords.Records.Count(rec => rec.Key.EndsWith("Start"))); Assert.Equal(1, eventRecords.Records.Count(rec => rec.Key.EndsWith("Stop"))); } }
public async Task TestRedirectedRequest(string method) { using var eventRecords = new EventObserverAndRecorder(); using (var client = new HttpClient()) { using HttpResponseMessage response = method == "GET" ? await client.GetAsync(this.BuildRequestUrl (queryString : "redirects=10")) : await client.PostAsync(this.BuildRequestUrl (queryString : "redirects=10"), new StringContent ("hello world")); } // We should have exactly one Start and one Stop event Assert.Equal(2, eventRecords.Records.Count()); Assert.Equal(1, eventRecords.Records.Count(rec => rec.Key.EndsWith("Start"))); Assert.Equal(1, eventRecords.Records.Count(rec => rec.Key.EndsWith("Stop"))); }
public async Task TestCanceledRequest() { CancellationTokenSource cts = new CancellationTokenSource(TimeSpan.FromSeconds(10)); using (var eventRecords = new EventObserverAndRecorder(_ => { cts.Cancel(); })) { using (var client = new HttpClient()) { var ex = await Assert.ThrowsAnyAsync <Exception>(() => client.GetAsync(Configuration.Http.RemoteEchoServer, cts.Token)); Assert.True(ex is TaskCanceledException || ex is WebException); } // We should have one Start event and no stop event Assert.Equal(1, eventRecords.Records.Count(rec => rec.Key.EndsWith("Start"))); Assert.Equal(0, eventRecords.Records.Count(rec => rec.Key.EndsWith("Stop"))); } }
public async Task TestRequestWithException() { using (var eventRecords = new EventObserverAndRecorder()) { var ex = await Assert.ThrowsAsync <HttpRequestException>( () => new HttpClient().GetAsync($"http://{Guid.NewGuid()}.com")); // check that request failed because of the wrong domain name and not because of reflection var webException = (WebException)ex.InnerException; Assert.NotNull(webException); Assert.True(webException.Status == WebExceptionStatus.NameResolutionFailure); // We should have one Start event and no stop event Assert.Equal(1, eventRecords.Records.Count(rec => rec.Key.EndsWith("Start"))); Assert.Equal(0, eventRecords.Records.Count(rec => rec.Key.EndsWith("Stop"))); } }
public async Task TestRequestWithException() { using (var eventRecords = new EventObserverAndRecorder()) { var ex = await Assert.ThrowsAsync <HttpRequestException>( () => new HttpClient().GetAsync($"http://{Guid.NewGuid()}.com")); // check that request failed because of the wrong domain name and not because of reflection var webException = (WebException)ex.InnerException; Assert.NotNull(webException); Assert.True(webException.Status == WebExceptionStatus.NameResolutionFailure); // Just make sure some events are written, to confirm we successfully subscribed to it. We should have // at least two events, one for request send, and one for response receive Assert.Equal(1, eventRecords.Records.Count(rec => rec.Key.EndsWith("Start"))); Assert.Equal(0, eventRecords.Records.Count(rec => rec.Key.EndsWith("Stop"))); } }
public async Task DoNotInjectRequestIdWhenPresent() { using (var eventRecords = new EventObserverAndRecorder()) { // Send a random Http request to generate some events using (var client = new HttpClient()) using (var request = new HttpRequestMessage(HttpMethod.Get, Configuration.Http.RemoteEchoServer)) { request.Headers.Add("Request-Id", "|rootId.1."); (await client.SendAsync(request)).Dispose(); } // Check to make sure: The first record must be a request, the next record must be a response. Assert.True(eventRecords.Records.TryDequeue(out var evnt)); HttpWebRequest startRequest = ReadPublicProperty <HttpWebRequest>(evnt.Value, "Request"); Assert.NotNull(startRequest); Assert.Equal("|rootId.1.", startRequest.Headers["Request-Id"]); } }
public void TestReflectInitializationViaSubscription3() { EventObserverAndRecorder eventRecords = new EventObserverAndRecorder(); DiagnosticListener.AllListeners.Subscribe(new CallbackObserver <DiagnosticListener>(diagnosticListener => { if (diagnosticListener.Name == "System.Net.Http.Desktop") { diagnosticListener.Subscribe(eventRecords, (eventName, obj1, obj2) => { return(true); }); } })); // Send a random Http request to generate some events HttpResponseMessage message = new HttpClient().GetAsync("http://www.bing.com").Result; // Just make sure some events are written, to confirm we successfully subscribed to it. We should have // at least two events, one for request send, and one for response receive Assert.True(eventRecords.Records.Count >= 2, "Didn't get two or more events from Http Diagnostic Listener. Something is wrong."); }
public async Task TestW3CHeadersTraceStateAndCorrelationContext() { try { using (var eventRecords = new EventObserverAndRecorder()) { var parent = new Activity("w3c activity"); parent.SetParentId(ActivityTraceId.CreateRandom(), ActivitySpanId.CreateRandom()); parent.TraceStateString = "some=state"; parent.AddBaggage("k", "v"); parent.Start(); // Send a random Http request to generate some events using (var client = new HttpClient()) { (await client.GetAsync(Configuration.Http.RemoteEchoServer)).Dispose(); } parent.Stop(); // Check to make sure: The first record must be a request, the next record must be a response. Assert.True(eventRecords.Records.TryDequeue(out var evnt)); Assert.Equal("System.Net.Http.Desktop.HttpRequestOut.Start", evnt.Key); HttpWebRequest startRequest = ReadPublicProperty <HttpWebRequest>(evnt.Value, "Request"); Assert.NotNull(startRequest); var traceparent = startRequest.Headers["traceparent"]; var tracestate = startRequest.Headers["tracestate"]; var correlationContext = startRequest.Headers["Correlation-Context"]; Assert.NotNull(traceparent); Assert.Equal("some=state", tracestate); Assert.Equal("k=v", correlationContext); Assert.True(traceparent.StartsWith($"00-{parent.TraceId.ToHexString()}-")); Assert.True(Regex.IsMatch(traceparent, "^[0-9a-f]{2}-[0-9a-f]{32}-[0-9a-f]{16}-[0-9a-f]{2}$")); Assert.Null(startRequest.Headers["Request-Id"]); } } finally { CleanUp(); } }
public async Task TestIsEnabledRequestOff() { bool IsEnabled(string evnt, object arg1, object arg2) { if (evnt == "System.Net.Http.Desktop.HttpRequestOut") { return(!(arg1 as WebRequest).RequestUri.ToString().Contains("bing")); } return(true); } using (var eventRecords = new EventObserverAndRecorder(IsEnabled)) { await new HttpClient().GetAsync("http://www.bing.com"); Assert.Equal(0, eventRecords.Records.Count); await new HttpClient().GetAsync("http://www.microsoft.com"); Assert.True(eventRecords.Records.Count > 0); } }
public async Task TestSecureTransportFailureRequest(string method) { using var eventRecords = new EventObserverAndRecorder(); using (var client = new HttpClient()) { var ex = await Assert.ThrowsAnyAsync <Exception>(() => { // https://expired.badssl.com/ has an expired certificae. return(method == "GET" ? client.GetAsync("https://expired.badssl.com/") : client.PostAsync("https://expired.badssl.com/", new StringContent("hello world"))); }); Assert.True(ex is HttpRequestException); } // We should have one Start event, no Stop event, and one Exception event. Assert.Equal(2, eventRecords.Records.Count()); Assert.Equal(1, eventRecords.Records.Count(rec => rec.Key.EndsWith("Start"))); Assert.Equal(1, eventRecords.Records.Count(rec => rec.Key.EndsWith("Exception"))); }