示例#1
0
        public async Task HttpRetryHandler_404VerifySingleHit()
        {
            // Arrange
            var hits = 0;

            Func <HttpRequestMessage, HttpResponseMessage> handler = requestMessage =>
            {
                hits++;
                return(new HttpResponseMessage(HttpStatusCode.OK));
            };

            var retryHandler = new HttpRetryHandler();
            var testHandler  = new HttpRetryTestHandler(handler);
            var httpClient   = new HttpClient(testHandler);
            var request      = new HttpRetryHandlerRequest(httpClient, () => new HttpRequestMessage(HttpMethod.Get, TestUrl))
            {
                MaxTries       = MaxTries,
                RequestTimeout = Timeout.InfiniteTimeSpan,
                RetryDelay     = TimeSpan.Zero
            };
            var log = new TestLogger();

            // Act
            using (var response = await retryHandler.SendAsync(request, log, CancellationToken.None))
            {
                // Assert
                Assert.Equal(1, hits);
                Assert.Equal(HttpStatusCode.OK, response.StatusCode);
            }
        }
        public async Task HttpRetryHandler_EnhancedRetryAllowsSettingMoreRetries()
        {
            // Arrange
            var tries   = 0;
            var sent503 = false;

            Func <HttpRequestMessage, HttpResponseMessage> handler = requestMessage =>
            {
                tries++;

                // Return 503 for the first 2 tries
                if (tries > 10)
                {
                    return(new HttpResponseMessage(HttpStatusCode.OK));
                }
                else
                {
                    sent503 = true;
                    return(new HttpResponseMessage(HttpStatusCode.ServiceUnavailable));
                }
            };

            TestEnvironmentVariableReader testEnvironmentVariableReader = new TestEnvironmentVariableReader(
                new Dictionary <string, string>()
            {
                [EnhancedHttpRetryHelper.IsEnabledEnvironmentVariableName]           = bool.TrueString,
                [EnhancedHttpRetryHelper.RetryCountEnvironmentVariableName]          = "11",
                [EnhancedHttpRetryHelper.DelayInMillisecondsEnvironmentVariableName] = "3"
            });

            EnhancedHttpRetryHelper helper = new EnhancedHttpRetryHelper(testEnvironmentVariableReader);

            Assert.Equal(helper.IsEnabled, true);
            // Enhanced retry mode causes a random 0-199 ms jitter so we can't time it in this test
            // but we can make sure the setting got through
            Assert.Equal(helper.DelayInMilliseconds, 3);
            Assert.Equal(helper.RetryCount, 11);

            var retryHandler = new HttpRetryHandler(testEnvironmentVariableReader);
            var testHandler  = new HttpRetryTestHandler(handler);
            var httpClient   = new HttpClient(testHandler);
            var request      = new HttpRetryHandlerRequest(httpClient, () => new HttpRequestMessage(HttpMethod.Get, TestUrl))
            {
                MaxTries       = helper.RetryCount,
                RequestTimeout = Timeout.InfiniteTimeSpan,
                // HttpRetryHandler will override with values from NUGET_ENHANCED_NETWORK_RETRY_DELAY_MILLISECONDS
                // so set this to a value that will cause test timeout if the correct value is not honored.
                RetryDelay = TimeSpan.FromMilliseconds(int.MaxValue) // = about 24 days
            };
            var log = new TestLogger();

            // Act
            using (var response = await retryHandler.SendAsync(request, log, CancellationToken.None))
            {
                // Assert
                Assert.True(sent503);
                Assert.Equal(11, tries);
                Assert.Equal(HttpStatusCode.OK, response.StatusCode);
            }
        }
示例#3
0
        public async Task HttpRetryHandler_DifferentRequestInstanceEachTime()
        {
            // Arrange
            var requests = new HashSet <HttpRequestMessage>();
            Func <HttpRequestMessage, HttpResponseMessage> handler = requestMessage =>
            {
                requests.Add(requestMessage);
                return(new HttpResponseMessage(HttpStatusCode.ServiceUnavailable));
            };

            var retryHandler = new HttpRetryHandler();
            var testHandler  = new HttpRetryTestHandler(handler);
            var httpClient   = new HttpClient(testHandler);
            var request      = new HttpRetryHandlerRequest(httpClient, () => new HttpRequestMessage(HttpMethod.Get, TestUrl))
            {
                MaxTries       = MaxTries,
                RequestTimeout = Timeout.InfiniteTimeSpan,
                RetryDelay     = TimeSpan.Zero
            };
            var log = new TestLogger();

            // Act
            using (await retryHandler.SendAsync(request, log, CancellationToken.None))
            {
            }

            // Assert
            Assert.Equal(MaxTries, requests.Count);
        }
示例#4
0
        public async Task HttpRetryHandler_MultipleTriesNoSuccess()
        {
            // Arrange
            var hits = 0;

            Func <HttpRequestMessage, HttpResponseMessage> handler = requestMessage =>
            {
                hits++;

                return(new HttpResponseMessage(HttpStatusCode.ServiceUnavailable));
            };

            var retryHandler = new HttpRetryHandler();
            var testHandler  = new HttpRetryTestHandler(handler);
            var httpClient   = new HttpClient(testHandler);
            var request      = new HttpRetryHandlerRequest(httpClient, () => new HttpRequestMessage(HttpMethod.Get, TestUrl))
            {
                MaxTries       = MaxTries,
                RequestTimeout = Timeout.InfiniteTimeSpan,
                RetryDelay     = TimeSpan.Zero
            };
            var log = new TestLogger();

            // Act
            using (await retryHandler.SendAsync(request, log, CancellationToken.None))
            {
            }

            // Assert
            Assert.Equal(MaxTries, hits);
        }
示例#5
0
        public async Task HttpRetryHandler_ThrowsTimeoutExceptionForTimeout()
        {
            // Arrange
            Func <HttpRequestMessage, CancellationToken, Task <HttpResponseMessage> > handler = async(requestMessage, token) =>
            {
                await Task.Delay(LargeTimeout);

                return(new HttpResponseMessage(HttpStatusCode.OK));
            };

            var retryHandler = new HttpRetryHandler();
            var testHandler  = new HttpRetryTestHandler(handler);
            var httpClient   = new HttpClient(testHandler);
            var request      = new HttpRetryHandlerRequest(httpClient, () => new HttpRequestMessage(HttpMethod.Get, TestUrl))
            {
                MaxTries       = 1,
                RequestTimeout = TimeSpan.Zero,
                RetryDelay     = TimeSpan.Zero
            };

            // Act
            Func <Task> actionAsync = () => retryHandler.SendAsync(
                request,
                new TestLogger(),
                CancellationToken.None);

            // Assert
            await Assert.ThrowsAsync <TimeoutException>(actionAsync);
        }
        public async Task HttpRetryHandler_MultipleTriesUntilSuccess()
        {
            // Arrange
            TimeSpan retryDelay = TimeSpan.Zero;

            TestEnvironmentVariableReader testEnvironmentVariableReader = new TestEnvironmentVariableReader(
                new Dictionary <string, string>()
            {
                [EnhancedHttpRetryHelper.RetryCountEnvironmentVariableName]          = MaxTries.ToString(),
                [EnhancedHttpRetryHelper.DelayInMillisecondsEnvironmentVariableName] = retryDelay.TotalMilliseconds.ToString()
            });
            var tries   = 0;
            var sent503 = false;

            Func <HttpRequestMessage, HttpResponseMessage> handler = requestMessage =>
            {
                tries++;

                // Return 503 for the first 2 tries
                if (tries > 2)
                {
                    return(new HttpResponseMessage(HttpStatusCode.OK));
                }
                else
                {
                    sent503 = true;
                    return(new HttpResponseMessage(HttpStatusCode.ServiceUnavailable));
                }
            };

            var retryHandler = new HttpRetryHandler(testEnvironmentVariableReader);
            var testHandler  = new HttpRetryTestHandler(handler);
            var httpClient   = new HttpClient(testHandler);
            var request      = new HttpRetryHandlerRequest(httpClient, () => new HttpRequestMessage(HttpMethod.Get, TestUrl))
            {
                MaxTries       = MaxTries,
                RequestTimeout = Timeout.InfiniteTimeSpan,
                RetryDelay     = retryDelay
            };
            var log = new TestLogger();

            // Act
            using (var response = await retryHandler.SendAsync(request, log, CancellationToken.None))
            {
                // Assert
                Assert.True(sent503);
                Assert.Equal(3, tries);
                Assert.Equal(HttpStatusCode.OK, response.StatusCode);
            }
        }
        public async Task HttpRetryHandler_AppliesTimeoutToRequestsIndividually()
        {
            // Arrange

            // 20 requests that take 250ms each for a total of 5 seconds (plus noise).
            var requestDuration = TimeSpan.FromMilliseconds(250);
            var maxTries        = 20;
            var retryDelay      = TimeSpan.Zero;

            TestEnvironmentVariableReader testEnvironmentVariableReader = new TestEnvironmentVariableReader(
                new Dictionary <string, string>()
            {
                [EnhancedHttpRetryHelper.RetryCountEnvironmentVariableName]          = maxTries.ToString(),
                [EnhancedHttpRetryHelper.DelayInMillisecondsEnvironmentVariableName] = retryDelay.TotalMilliseconds.ToString()
            });

            // Make the request timeout longer than each request duration but less than the total
            // duration of all attempts.
            var requestTimeout = TimeSpan.FromMilliseconds(4000);

            var hits = 0;
            Func <HttpRequestMessage, CancellationToken, Task <HttpResponseMessage> > handler = async(requestMessage, token) =>
            {
                hits++;
                await Task.Delay(requestDuration);

                return(new HttpResponseMessage(HttpStatusCode.InternalServerError));
            };

            var retryHandler = new HttpRetryHandler(testEnvironmentVariableReader);
            var testHandler  = new HttpRetryTestHandler(handler);
            var httpClient   = new HttpClient(testHandler);
            var request      = new HttpRetryHandlerRequest(httpClient, () => new HttpRequestMessage(HttpMethod.Get, TestUrl))
            {
                MaxTries       = maxTries,
                RequestTimeout = requestTimeout,
                RetryDelay     = retryDelay
            };
            var log = new TestLogger();

            // Act
            using (await retryHandler.SendAsync(request, log, CancellationToken.None))
            {
            }

            // Assert
            Assert.Equal(maxTries, hits);
        }
        public async Task HttpRetryHandler_MultipleTriesTimed()
        {
            // Arrange
            TimeSpan retryDelay = SmallTimeout;

            TestEnvironmentVariableReader testEnvironmentVariableReader = new TestEnvironmentVariableReader(
                new Dictionary <string, string>()
            {
                [EnhancedHttpRetryHelper.RetryCountEnvironmentVariableName]          = MaxTries.ToString(),
                [EnhancedHttpRetryHelper.DelayInMillisecondsEnvironmentVariableName] = retryDelay.TotalMilliseconds.ToString()
            });
            Func <HttpRequestMessage, HttpResponseMessage> handler = requestMessage =>
            {
                return(new HttpResponseMessage(HttpStatusCode.ServiceUnavailable));
            };

            var minTime = GetRetryMinTime(MaxTries, SmallTimeout);

            var retryHandler = new HttpRetryHandler(testEnvironmentVariableReader);
            var testHandler  = new HttpRetryTestHandler(handler);
            var httpClient   = new HttpClient(testHandler);
            var request      = new HttpRetryHandlerRequest(httpClient, () => new HttpRequestMessage(HttpMethod.Get, TestUrl))
            {
                MaxTries       = MaxTries,
                RequestTimeout = Timeout.InfiniteTimeSpan,
                RetryDelay     = retryDelay
            };
            var log = new TestLogger();

            // Act
            var timer = new Stopwatch();

            timer.Start();

            using (await retryHandler.SendAsync(request, log, CancellationToken.None))
            {
            }

            timer.Stop();

            // Assert
            Assert.True(
                timer.Elapsed >= minTime,
                $"Expected this to take at least: {minTime} But it finished in: {timer.Elapsed}");
        }
        public async Task HttpRetryHandler_TimesOutDownload()
        {
            // Arrange
            var hits                 = 0;
            var memoryStream         = new MemoryStream(Encoding.ASCII.GetBytes("foobar"));
            var expectedMilliseconds = 50;
            Func <HttpRequestMessage, HttpResponseMessage> handler = requestMessage =>
            {
                hits++;
                return(new HttpResponseMessage(HttpStatusCode.OK)
                {
                    Content = new StreamContent(new SlowStream(memoryStream)
                    {
                        DelayPerByte = TimeSpan.FromSeconds(1)
                    })
                });
            };

            var retryHandler = new HttpRetryHandler();
            var testHandler  = new HttpRetryTestHandler(handler);
            var httpClient   = new HttpClient(testHandler);
            var request      = new HttpRetryHandlerRequest(httpClient, () => new HttpRequestMessage(HttpMethod.Get, TestUrl))
            {
                DownloadTimeout = TimeSpan.FromMilliseconds(expectedMilliseconds)
            };
            var destinationStream = new MemoryStream();
            var log = new TestLogger();

            // Act
            using (var response = await retryHandler.SendAsync(request, log, CancellationToken.None))
                using (var stream = await response.Content.ReadAsStreamAsync())
                {
                    var actual = await Assert.ThrowsAsync <IOException>(() => stream.CopyToAsync(destinationStream));

                    // Assert
                    Assert.Equal(1, hits);
                    Assert.Equal(HttpStatusCode.OK, response.StatusCode);
                    Assert.IsType <TimeoutException>(actual.InnerException);
                    Assert.EndsWith(
                        $"timed out because no data was received for {expectedMilliseconds}ms.",
                        actual.Message);
                }
        }
        public async Task HttpRetryHandler_CancelsRequestAfterTimeout()
        {
            // Arrange
            TimeSpan retryDelay = TimeSpan.Zero;

            TestEnvironmentVariableReader testEnvironmentVariableReader = new TestEnvironmentVariableReader(
                new Dictionary <string, string>()
            {
                [EnhancedHttpRetryHelper.RetryCountEnvironmentVariableName]          = MaxTries.ToString(),
                [EnhancedHttpRetryHelper.DelayInMillisecondsEnvironmentVariableName] = retryDelay.TotalMilliseconds.ToString()
            });
            var requestToken = CancellationToken.None;
            Func <HttpRequestMessage, CancellationToken, Task <HttpResponseMessage> > handler = async(requestMessage, token) =>
            {
                requestToken = token;
                await Task.Delay(LargeTimeout, token);

                return(new HttpResponseMessage(HttpStatusCode.OK));
            };

            var retryHandler = new HttpRetryHandler(testEnvironmentVariableReader);
            var testHandler  = new HttpRetryTestHandler(handler);
            var httpClient   = new HttpClient(testHandler);
            var request      = new HttpRetryHandlerRequest(httpClient, () => new HttpRequestMessage(HttpMethod.Get, TestUrl))
            {
                MaxTries       = 1,
                RequestTimeout = SmallTimeout,
                RetryDelay     = retryDelay
            };

            // Act
            Func <Task> actionAsync = () => retryHandler.SendAsync(
                request,
                new TestLogger(),
                CancellationToken.None);

            // Assert
            await Assert.ThrowsAsync <TimeoutException>(actionAsync);

            Assert.True(requestToken.CanBeCanceled);
            Assert.True(requestToken.IsCancellationRequested);
        }
示例#11
0
        public async Task HttpRetryHandler_MultipleTriesUntilSuccess()
        {
            // Arrange
            var tries   = 0;
            var sent503 = false;

            Func <HttpRequestMessage, HttpResponseMessage> handler = requestMessage =>
            {
                tries++;

                // Return 503 for the first 2 tries
                if (tries > 2)
                {
                    return(new HttpResponseMessage(HttpStatusCode.OK));
                }
                else
                {
                    sent503 = true;
                    return(new HttpResponseMessage(HttpStatusCode.ServiceUnavailable));
                }
            };

            var retryHandler = new HttpRetryHandler();
            var testHandler  = new HttpRetryTestHandler(handler);
            var httpClient   = new HttpClient(testHandler);
            var request      = new HttpRetryHandlerRequest(httpClient, () => new HttpRequestMessage(HttpMethod.Get, TestUrl))
            {
                MaxTries       = MaxTries,
                RequestTimeout = Timeout.InfiniteTimeSpan,
                RetryDelay     = TimeSpan.Zero
            };
            var log = new TestLogger();

            // Act
            using (var response = await retryHandler.SendAsync(request, log, CancellationToken.None))
            {
                // Assert
                Assert.True(sent503);
                Assert.Equal(3, tries);
                Assert.Equal(HttpStatusCode.OK, response.StatusCode);
            }
        }
        public async Task HttpRetryHandler_ReturnsContentHeaders()
        {
            // Arrange
            Func <HttpRequestMessage, HttpResponseMessage> handler = requestMessage =>
            {
                var stringContent = new StringContent("Plain text document.", Encoding.UTF8, "text/plain");
                stringContent.Headers.TryAddWithoutValidation("X-Content-ID", "49f47c14-c21f-4c1d-9e13-4f5fcf5f8013");
                var response = new HttpResponseMessage(HttpStatusCode.OK)
                {
                    Content = stringContent,
                };
                response.Headers.TryAddWithoutValidation("X-Message-Header", "This isn't on the content.");
                return(response);
            };

            var retryHandler = new HttpRetryHandler();
            var testHandler  = new HttpRetryTestHandler(handler);
            var httpClient   = new HttpClient(testHandler);
            var request      = new HttpRetryHandlerRequest(
                httpClient,
                () => new HttpRequestMessage(HttpMethod.Get, TestUrl));
            var log = new TestLogger();

            // Act
            var actualResponse = await retryHandler.SendAsync(request, log, CancellationToken.None);

            // Assert
            var actualHeaders = actualResponse
                                .Content
                                .Headers
                                .OrderBy(x => x.Key)
                                .ToDictionary(x => x.Key, x => x.Value);

            Assert.Equal(
                new List <string> {
                "Content-Type", "X-Content-ID"
            },
                actualHeaders.Keys.OrderBy(x => x).ToList());
            Assert.Equal(actualHeaders["Content-Type"], new[] { "text/plain; charset=utf-8" });
            Assert.Equal(actualHeaders["X-Content-ID"], new[] { "49f47c14-c21f-4c1d-9e13-4f5fcf5f8013" });
        }
        public async Task HttpRetryHandler_MultipleTriesNoSuccess()
        {
            // Arrange
            TimeSpan retryDelay = TimeSpan.Zero;

            TestEnvironmentVariableReader testEnvironmentVariableReader = new TestEnvironmentVariableReader(
                new Dictionary <string, string>()
            {
                [EnhancedHttpRetryHelper.RetryCountEnvironmentVariableName]          = MaxTries.ToString(),
                [EnhancedHttpRetryHelper.DelayInMillisecondsEnvironmentVariableName] = retryDelay.TotalMilliseconds.ToString()
            });
            var hits = 0;

            Func <HttpRequestMessage, HttpResponseMessage> handler = requestMessage =>
            {
                hits++;

                return(new HttpResponseMessage(HttpStatusCode.ServiceUnavailable));
            };

            var retryHandler = new HttpRetryHandler(testEnvironmentVariableReader);
            var testHandler  = new HttpRetryTestHandler(handler);
            var httpClient   = new HttpClient(testHandler);
            var request      = new HttpRetryHandlerRequest(httpClient, () => new HttpRequestMessage(HttpMethod.Get, TestUrl))
            {
                MaxTries       = MaxTries,
                RequestTimeout = Timeout.InfiniteTimeSpan,
                RetryDelay     = retryDelay
            };
            var log = new TestLogger();

            // Act
            using (await retryHandler.SendAsync(request, log, CancellationToken.None))
            {
            }

            // Assert
            Assert.Equal(MaxTries, hits);
        }
示例#14
0
        public async Task HttpRetryHandler_MultipleTriesTimed()
        {
            // Arrange
            Func <HttpRequestMessage, HttpResponseMessage> handler = requestMessage =>
            {
                return(new HttpResponseMessage(HttpStatusCode.ServiceUnavailable));
            };

            var minTime = GetRetryMinTime(MaxTries, SmallTimeout);

            var retryHandler = new HttpRetryHandler();
            var testHandler  = new HttpRetryTestHandler(handler);
            var httpClient   = new HttpClient(testHandler);
            var request      = new HttpRetryHandlerRequest(httpClient, () => new HttpRequestMessage(HttpMethod.Get, TestUrl))
            {
                MaxTries       = MaxTries,
                RequestTimeout = Timeout.InfiniteTimeSpan,
                RetryDelay     = SmallTimeout
            };
            var log = new TestLogger();

            // Act
            var timer = new Stopwatch();

            timer.Start();

            using (await retryHandler.SendAsync(request, log, CancellationToken.None))
            {
            }

            timer.Stop();

            // Assert
            Assert.True(
                timer.Elapsed >= minTime,
                $"Expected this to take at least: {minTime} But it finished in: {timer.Elapsed}");
        }