summaryrefslogtreecommitdiff
path: root/test/test_retry.py
diff options
context:
space:
mode:
authorSeth Michael Larson <sethmichaellarson@gmail.com>2019-06-05 08:43:06 -0500
committerSeth Michael Larson <sethmichaellarson@gmail.com>2019-06-05 08:43:06 -0500
commitcce19dcd3c29e93e490ef526dc87aad2255b9c99 (patch)
tree4707723b7f9625b48f94afc0184af7c1c4fc92c9 /test/test_retry.py
parent02fd90adbb388de72e4fea0826f33dcd35298a6f (diff)
parent728d9244665ef5b03103cb74d7b409ebe4f23b43 (diff)
downloadurllib3-delete-makefile.tar.gz
Merge branch 'master' of ssh://github.com/urllib3/urllib3 into delete-makefiledelete-makefile
Diffstat (limited to 'test/test_retry.py')
-rw-r--r--test/test_retry.py70
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()