summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/test_response.py8
-rw-r--r--test/test_retry.py70
-rw-r--r--test/test_util.py15
3 files changed, 74 insertions, 19 deletions
diff --git a/test/test_response.py b/test/test_response.py
index 18b3e373..23a63be1 100644
--- a/test/test_response.py
+++ b/test/test_response.py
@@ -440,7 +440,7 @@ class TestResponse(object):
def __init__(self, payload, payload_part_size):
self.payloads = [
- payload[i * payload_part_size : (i + 1) * payload_part_size] # noqa
+ payload[i * payload_part_size : (i + 1) * payload_part_size]
for i in range(NUMBER_OF_READS + 1)
]
@@ -633,7 +633,7 @@ class TestResponse(object):
data = compress.compress(b"foobar")
data += compress.flush()
for i in range(0, len(data), 2):
- yield data[i : i + 2] # noqa
+ yield data[i : i + 2]
fp = MockChunkedEncodingResponse(list(stream()))
r = httplib.HTTPResponse(MockSock)
@@ -801,7 +801,7 @@ class TestResponse(object):
data = compress.compress(b"foo\nbar")
data += compress.flush()
for i in range(0, len(data), 2):
- yield data[i : i + 2] # noqa
+ yield data[i : i + 2]
fp = MockChunkedEncodingResponse(list(stream()))
r = httplib.HTTPResponse(MockSock)
@@ -862,7 +862,7 @@ class MockChunkedEncodingResponse(object):
return b""
else:
chunk_part = self.cur_chunk[: i + 2]
- self.cur_chunk = self.cur_chunk[i + 2 :] # noqa
+ self.cur_chunk = self.cur_chunk[i + 2 :]
return chunk_part
elif amt <= -1:
chunk_part = self.cur_chunk
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()
diff --git a/test/test_util.py b/test/test_util.py
index b2906f22..37c09ab2 100644
--- a/test/test_util.py
+++ b/test/test_util.py
@@ -13,7 +13,6 @@ import pytest
from urllib3 import add_stderr_logger, disable_warnings
from urllib3.util.request import make_headers, rewind_body, _FAILEDTELL
from urllib3.util.response import assert_header_parsing
-from urllib3.util.retry import Retry
from urllib3.util.timeout import Timeout
from urllib3.util.url import get_host, parse_url, split_first, Url
from urllib3.util.ssl_ import (
@@ -27,7 +26,6 @@ from urllib3.exceptions import (
TimeoutStateError,
InsecureRequestWarning,
SNIMissingWarning,
- InvalidHeader,
UnrewindableBodyError,
)
from urllib3.util.connection import allowed_gai_family, _has_ipv6
@@ -782,19 +780,6 @@ class TestUtil(object):
with patch("urllib3.util.connection.HAS_IPV6", False):
assert allowed_gai_family() == socket.AF_INET
- @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("headers", [b"foo", None, object])
def test_assert_header_parsing_throws_typeerror_with_non_headers(self, headers):
with pytest.raises(TypeError):