public void SendANonEmptySpanBatch() { var traceId = "123"; var span = new NewRelicSpan( traceId: null, spanId: "Span1", timestamp: DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(), parentSpanId: null, attributes: new Dictionary <string, object>() { { NewRelicConsts.Tracing.AttribNameName, "TestSpan" }, }); var spanBatch = new NewRelicSpanBatch( spans: new[] { span }, commonProperties: new NewRelicSpanBatchCommonProperties(traceId)); var dataSender = new TraceDataSender(new TelemetryConfiguration() { ApiKey = "123456" }, null); dataSender.WithHttpHandlerImpl((serializedJson) => { var response = new HttpResponseMessage(System.Net.HttpStatusCode.OK); return(Task.FromResult(response)); }); var response = dataSender.SendDataAsync(spanBatch).Result; Assert.Equal(NewRelicResponseStatus.Success, response.ResponseStatus); }
public async Task RetryBackoffSequence_RetriesExceeded() { var expectedNumSendBatchAsyncCall = 9; // 1 first call + 8 calls from retries var expectedBackoffSequenceFromTestRun = new List <uint>() { 5000, 10000, 20000, 40000, 80000, 80000, 80000, 80000, }; var actualBackoffSequenceFromTestRun = new List <uint>(); var actualCountCallsSendData = 0; var dataSender = new TraceDataSender(new TelemetryConfiguration() { ApiKey = "123456" }, null); dataSender.WithDelayFunction(async(uint milliSecondsDelay) => { actualBackoffSequenceFromTestRun.Add(milliSecondsDelay); await Task.Delay(0); return; }); dataSender.WithCaptureSendDataAsyncDelegate((newRelicSpanBatch, retryNum) => { actualCountCallsSendData++; }); dataSender.WithHttpHandlerImpl((json) => { return(Task.FromResult(new HttpResponseMessage(System.Net.HttpStatusCode.RequestTimeout))); }); var spans = new List <NewRelicSpan>() { new NewRelicSpan( traceId: null, spanId: "Test Span", timestamp: 12345, parentSpanId: null, attributes: null), }; var spanBatch = new NewRelicSpanBatch(spans); var result = await dataSender.SendDataAsync(spanBatch); Assert.Equal(NewRelicResponseStatus.Failure, result.ResponseStatus); Assert.Equal(HttpStatusCode.RequestTimeout, result.HttpStatusCode); Assert.Equal(expectedNumSendBatchAsyncCall, actualCountCallsSendData); Assert.Equal(expectedBackoffSequenceFromTestRun, actualBackoffSequenceFromTestRun); }
public async Task SendDataAsyncThrowsNonHttpException() { const int expectedNumSendBatchAsyncCall = 1; const int expectedNumHttpHandlerCall = 0; var dataSender = new TraceDataSender(new TelemetryConfiguration() { ApiKey = "123456" }, null); dataSender.WithDelayFunction(async(uint milliSecondsDelay) => { await Task.Delay(0); return; }); var actualCountCallsSendData = 0; dataSender.WithCaptureSendDataAsyncDelegate((sb, retry) => { actualCountCallsSendData++; throw new Exception("Test Exception"); }); var actualCallsHttpHandler = 0; dataSender.WithHttpHandlerImpl((json) => { actualCallsHttpHandler++; return(Task.FromResult(new HttpResponseMessage() { StatusCode = HttpStatusCode.OK })); }); var spans = new List <NewRelicSpan>() { new NewRelicSpan( traceId: null, spanId: "Test Span", timestamp: 12345, parentSpanId: null, attributes: null), }; var spanBatch = new NewRelicSpanBatch(spans); var result = await dataSender.SendDataAsync(spanBatch); Assert.Equal(NewRelicResponseStatus.Failure, result.ResponseStatus); Assert.Equal("Test Exception", result.Message); Assert.Null(result.HttpStatusCode); Assert.Equal(expectedNumSendBatchAsyncCall, actualCountCallsSendData); Assert.Equal(expectedNumHttpHandlerCall, actualCallsHttpHandler); }
public async Task RetryOn429WithSpecificDate_429HappensOnce() { const int delayMs = 10000; // The actual retry delay will be slightly less than delayMs since UtcNow is recalculated in RetryWithServerDelay() var errorMargin = TimeSpan.FromMilliseconds(1000).TotalMilliseconds; var actualResponseFromTestRun = new List <Response>(); uint actualDelayFromTestRun = 0; var dataSender = new TraceDataSender(new TelemetryConfiguration() { ApiKey = "123456", MaxRetryAttempts = 1 }, null); dataSender.WithDelayFunction(async(uint milliSecondsDelay) => { actualDelayFromTestRun = milliSecondsDelay; await Task.Delay(0); return; }); dataSender.WithHttpHandlerImpl((json) => { var httpResponse = new HttpResponseMessage((HttpStatusCode)429); var retryOnSpecificTime = DateTimeOffset.UtcNow + TimeSpan.FromMilliseconds(delayMs); httpResponse.Headers.RetryAfter = new System.Net.Http.Headers.RetryConditionHeaderValue(retryOnSpecificTime); return(Task.FromResult(httpResponse)); }); var spans = new List <NewRelicSpan>() { new NewRelicSpan( traceId: null, spanId: "Test Span", timestamp: 12345, parentSpanId: null, attributes: null), }; var spanBatch = new NewRelicSpanBatch(spans); var result = await dataSender.SendDataAsync(spanBatch); Assert.True(actualDelayFromTestRun >= delayMs - errorMargin && actualDelayFromTestRun <= delayMs + errorMargin, $"Expected delay: {delayMs}, margin: +/-{errorMargin}, actual delay: {actualDelayFromTestRun}"); }
public void SendAnEmptySpanBatch() { var traceId = "123"; var spanBatch = new NewRelicSpanBatch( spans: new NewRelicSpan[0], commonProperties: new NewRelicSpanBatchCommonProperties(traceId)); var dataSender = new TraceDataSender(new TelemetryConfiguration() { ApiKey = "123456" }, null); dataSender.WithHttpHandlerImpl((serializedJson) => { var response = new HttpResponseMessage(System.Net.HttpStatusCode.OK); return(Task.FromResult(response)); }); var response = dataSender.SendDataAsync(spanBatch).Result; Assert.Equal(NewRelicResponseStatus.DidNotSend_NoData, response.ResponseStatus); }
public async Task RetryOn429WithDuration_429HappensOnce() { const int delayMS = 10000; const int expectedNumSendBatchAsyncCall = 2; var expectedBackoffSequenceFromTestRun = new List <uint>() { delayMS, }; var actualBackoffSequenceFromTestRun = new List <uint>(); var dataSender = new TraceDataSender(new TelemetryConfiguration() { ApiKey = "123456" }, null); dataSender.WithDelayFunction(async(uint milliSecondsDelay) => { actualBackoffSequenceFromTestRun.Add(milliSecondsDelay); await Task.Delay(0); return; }); var actualCountCallsSendData = 0; dataSender.WithCaptureSendDataAsyncDelegate((newRelicSpanBatch, retryNum) => { actualCountCallsSendData++; }); dataSender.WithHttpHandlerImpl((json) => { if (actualCountCallsSendData < 2) { var httpResponse = new HttpResponseMessage((HttpStatusCode)429); httpResponse.Headers.RetryAfter = new System.Net.Http.Headers.RetryConditionHeaderValue(TimeSpan.FromMilliseconds(delayMS)); return(Task.FromResult(httpResponse)); } return(Task.FromResult(new HttpResponseMessage(System.Net.HttpStatusCode.OK))); }); var spans = new List <NewRelicSpan>() { new NewRelicSpan( traceId: null, spanId: "Test Span", timestamp: 12345, parentSpanId: null, attributes: null), }; var spanBatch = new NewRelicSpanBatch(spans); var result = await dataSender.SendDataAsync(spanBatch); Assert.Equal(NewRelicResponseStatus.Success, result.ResponseStatus); Assert.Equal(expectedNumSendBatchAsyncCall, actualCountCallsSendData); Assert.Equal(expectedBackoffSequenceFromTestRun, actualBackoffSequenceFromTestRun); }
public async Task RequestTooLarge_SplitSuccess() { const int expectedCountSpans = 9; const int expectedCountCallsSendData = 7; const int expectedCountSuccessfulSpanBatches = 4; const string expectedTraceID = "TestTrace"; var actualCountCallsSendData = 0; // Arrange var successfulSpanBatches = new List <NewRelicSpanBatch>(); var dataSender = new TraceDataSender(new TelemetryConfiguration() { ApiKey = "123456" }, null); var okJsons = new List <string>(); // Mock the behavior to return EntityTooLarge for any span batch with 4 or more spans. // Anything with less than 4 will return success. dataSender.WithCaptureSendDataAsyncDelegate((spanBatch, retryNum) => { actualCountCallsSendData++; if (spanBatch.Spans.Count() < 4) { okJsons.Add(spanBatch.ToJson()); successfulSpanBatches.Add(spanBatch); } }); dataSender.WithHttpHandlerImpl((json) => { var response = okJsons.Contains(json) ? new HttpResponseMessage(System.Net.HttpStatusCode.OK) : new HttpResponseMessage(System.Net.HttpStatusCode.RequestEntityTooLarge); return(Task.FromResult(response)); }); var attribs = new Dictionary <string, object>() { { "testAttrib1", "testAttribValue1" }, }; var spans = new List <NewRelicSpan>(); for (var i = 0; i < expectedCountSpans; i++) { spans.Add(new NewRelicSpan(null, i.ToString(), i, null, null)); } var spanBatch = new NewRelicSpanBatch(spans, new NewRelicSpanBatchCommonProperties(expectedTraceID, attribs)); // Act await dataSender.SendDataAsync(spanBatch); // Assert Assert.Equal(expectedCountCallsSendData, actualCountCallsSendData); // Test the Spans Assert.Equal(expectedCountSuccessfulSpanBatches, successfulSpanBatches.Count); Assert.Equal(expectedCountSpans, successfulSpanBatches.SelectMany(x => x.Spans).Count()); Assert.Equal(expectedCountSpans, successfulSpanBatches.SelectMany(x => x.Spans).Select(x => x.Id).Distinct().Count()); // Test the attributes on the NewRelicSpanBatch Assert.Single(successfulSpanBatches.Select(x => x.CommonProperties.TraceId).Distinct()); Assert.Equal(expectedTraceID, successfulSpanBatches.FirstOrDefault().CommonProperties.TraceId); Assert.Single(successfulSpanBatches.Select(x => x.CommonProperties.Attributes).Distinct()); Assert.Equal(attribs, successfulSpanBatches.Select(x => x.CommonProperties.Attributes).FirstOrDefault()); }
public async Task RequestTooLarge_SplitFail() { const int expectedCountCallsSendData = 7; const string traceID_Success = "OK"; const string traceID_SplitBatch_Prefix = "TooLarge"; var actualCountCallsSendData = 0; var successfulSpans = new List <NewRelicSpan>(); var dataSender = new TraceDataSender(new TelemetryConfiguration() { ApiKey = "123456" }, null); var shouldSplitJsons = new List <string>(); // Mock the behavior to return EntityTooLarge for any span batch that has a span with an // id that starts with TooLarge. dataSender.WithCaptureSendDataAsyncDelegate((newRelicSpanBatch, retryNum) => { actualCountCallsSendData++; if (newRelicSpanBatch.Spans == null) { return; } if (newRelicSpanBatch.Spans.Any(x => x.Id.StartsWith(traceID_SplitBatch_Prefix))) { shouldSplitJsons.Add(newRelicSpanBatch.ToJson()); } else { successfulSpans.AddRange(newRelicSpanBatch.Spans); } }); dataSender.WithHttpHandlerImpl((json) => { var response = shouldSplitJsons.Contains(json) ? new HttpResponseMessage(System.Net.HttpStatusCode.RequestEntityTooLarge) : new HttpResponseMessage(System.Net.HttpStatusCode.OK); return(Task.FromResult(response)); }); var spans = new List <NewRelicSpan>(); spans.Add(new NewRelicSpan(null, $"{traceID_SplitBatch_Prefix}1", 0, null, null)); spans.Add(new NewRelicSpan(null, $"{traceID_SplitBatch_Prefix}2", 0, null, null)); spans.Add(new NewRelicSpan(null, $"{traceID_SplitBatch_Prefix}3", 0, null, null)); spans.Add(new NewRelicSpan(null, traceID_Success, 0, null, null)); // Act var result = await dataSender.SendDataAsync(spans); // Assert Assert.Equal(NewRelicResponseStatus.Failure, result.ResponseStatus); Assert.Equal(expectedCountCallsSendData, actualCountCallsSendData); Assert.Single(successfulSpans); Assert.Equal(traceID_Success, successfulSpans[0].Id); }