diff options
Diffstat (limited to 'test/test_retry.py')
| -rw-r--r-- | test/test_retry.py | 70 |
1 files changed, 70 insertions, 0 deletions
diff --git a/test/test_retry.py b/test/test_retry.py index 7b228d75..c36476f8 100644 --- a/test/test_retry.py +++ b/test/test_retry.py @@ -1,10 +1,15 @@ +import datetime +import mock import pytest +import time from urllib3.response import HTTPResponse +from urllib3.packages import six from urllib3.packages.six.moves import xrange from urllib3.util.retry import Retry, RequestHistory from urllib3.exceptions import ( ConnectTimeoutError, + InvalidHeader, MaxRetryError, ReadTimeoutError, ResponseError, @@ -271,3 +276,68 @@ class TestRetry(object): retry = Retry(remove_headers_on_redirect=["X-API-Secret"]) assert list(retry.remove_headers_on_redirect) == ["x-api-secret"] + + @pytest.mark.parametrize("value", ["-1", "+1", "1.0", six.u("\xb2")]) # \xb2 = ^2 + def test_parse_retry_after_invalid(self, value): + retry = Retry() + with pytest.raises(InvalidHeader): + retry.parse_retry_after(value) + + @pytest.mark.parametrize( + "value, expected", [("0", 0), ("1000", 1000), ("\t42 ", 42)] + ) + def test_parse_retry_after(self, value, expected): + retry = Retry() + assert retry.parse_retry_after(value) == expected + + @pytest.mark.parametrize("respect_retry_after_header", [True, False]) + def test_respect_retry_after_header_propagated(self, respect_retry_after_header): + + retry = Retry(respect_retry_after_header=respect_retry_after_header) + new_retry = retry.new() + assert new_retry.respect_retry_after_header == respect_retry_after_header + + @pytest.mark.parametrize( + "retry_after_header,respect_retry_after_header,sleep_duration", + [ + ("3600", True, 3600), + ("3600", False, None), + # Will sleep due to header is 1 hour in future + ("Mon, 3 Jun 2019 12:00:00 UTC", True, 3600), + # Won't sleep due to not respecting header + ("Mon, 3 Jun 2019 12:00:00 UTC", False, None), + # Won't sleep due to current time reached + ("Mon, 3 Jun 2019 11:00:00 UTC", True, None), + # Won't sleep due to current time reached + not respecting header + ("Mon, 3 Jun 2019 11:00:00 UTC", False, None), + ], + ) + def test_respect_retry_after_header_sleep( + self, retry_after_header, respect_retry_after_header, sleep_duration + ): + retry = Retry(respect_retry_after_header=respect_retry_after_header) + + # Date header syntax can specify an absolute date; compare this to the + # time in the parametrized inputs above. + current_time = mock.MagicMock( + return_value=time.mktime( + datetime.datetime(year=2019, month=6, day=3, hour=11).timetuple() + ) + ) + + with mock.patch("time.sleep") as sleep_mock, mock.patch( + "time.time", current_time + ): + # for the default behavior, it must be in RETRY_AFTER_STATUS_CODES + response = HTTPResponse( + status=503, headers={"Retry-After": retry_after_header} + ) + + retry.sleep(response) + + # The expected behavior is that we'll only sleep if respecting + # this header (since we won't have any backoff sleep attempts) + if respect_retry_after_header and sleep_duration is not None: + sleep_mock.assert_called_with(sleep_duration) + else: + sleep_mock.assert_not_called() |
