Skip to content

Commit

Permalink
chore: use adapter mock to replicate production code path more accura…
Browse files Browse the repository at this point in the history
…tely
  • Loading branch information
z3z1ma committed May 22, 2024
1 parent e2e1e32 commit b46e8a6
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 33 deletions.
2 changes: 1 addition & 1 deletion dlt/sources/helpers/requests/retry.py
Original file line number Diff line number Diff line change
Expand Up @@ -252,4 +252,4 @@ def session(self) -> Session:
# Create a new session if config has changed
session = self._local.session = self._make_session()
self._local.config_version = self._config_version
return session
return session
72 changes: 40 additions & 32 deletions tests/sources/helpers/test_requests.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,12 @@ def custom_retry_cond(response, exception):
def test_retry_on_status_all_fails(mock_sleep: mock.MagicMock) -> None:
session = Client().session
url = "https://example.com/data"
m = requests_mock.Adapter()
session.mount("https://", m)
m.register_uri("GET", url, status_code=503)

with requests_mock.mock(session=session) as m:
m.get(url, status_code=503)
with pytest.raises(requests.HTTPError):
session.get(url)
with pytest.raises(requests.HTTPError):
session.get(url)

assert m.call_count == RunConfiguration.request_max_attempts

Expand All @@ -76,16 +77,17 @@ def test_retry_on_status_success_after_2(mock_sleep: mock.MagicMock) -> None:
"""Test successful request after 2 retries"""
session = Client().session
url = "https://example.com/data"
m = requests_mock.Adapter()
session.mount("https://", m)

responses = [
dict(text="error", status_code=503),
dict(text="error", status_code=503),
dict(text="error", status_code=200),
]

with requests_mock.mock(session=session) as m:
m.get(url, responses)
resp = session.get(url)
m.register_uri("GET", url, responses)
resp = session.get(url)

assert resp.status_code == 200
assert m.call_count == 3
Expand All @@ -94,30 +96,32 @@ def test_retry_on_status_success_after_2(mock_sleep: mock.MagicMock) -> None:
def test_retry_on_status_without_raise_for_status(mock_sleep: mock.MagicMock) -> None:
url = "https://example.com/data"
session = Client(raise_for_status=False).session
m = requests_mock.Adapter()
session.mount("https://", m)

with requests_mock.mock(session=session) as m:
m.get(url, status_code=503)
response = session.get(url)
assert response.status_code == 503
m.register_uri("GET", url, status_code=503)
response = session.get(url)
assert response.status_code == 503

assert m.call_count == RunConfiguration.request_max_attempts


def test_hooks_with_raise_for_statue() -> None:
url = "https://example.com/data"
session = Client(raise_for_status=True).session
m = requests_mock.Adapter()
session.mount("https://", m)

def _no_content(resp: requests.Response, *args, **kwargs) -> requests.Response:
resp.status_code = 204
resp._content = b"[]"
return resp

with requests_mock.mock(session=session) as m:
m.get(url, status_code=503)
response = session.get(url, hooks={"response": _no_content})
# we simulate empty response
assert response.status_code == 204
assert response.json() == []
m.register_uri("GET", url, status_code=503)
response = session.get(url, hooks={"response": _no_content})
# we simulate empty response
assert response.status_code == 204
assert response.json() == []

assert m.call_count == 1

Expand All @@ -130,12 +134,13 @@ def test_retry_on_exception_all_fails(
exception_class: Type[Exception], mock_sleep: mock.MagicMock
) -> None:
session = Client().session
m = requests_mock.Adapter()
session.mount("https://", m)
url = "https://example.com/data"

with requests_mock.mock(session=session) as m:
m.get(url, exc=exception_class)
with pytest.raises(exception_class):
session.get(url)
m.register_uri("GET", url, exc=exception_class)
with pytest.raises(exception_class):
session.get(url)

assert m.call_count == RunConfiguration.request_max_attempts

Expand All @@ -145,12 +150,13 @@ def retry_on(response: requests.Response, exception: BaseException) -> bool:
return response.text == "error"

session = Client(retry_condition=retry_on).session
m = requests_mock.Adapter()
session.mount("https://", m)
url = "https://example.com/data"

with requests_mock.mock(session=session) as m:
m.get(url, text="error")
response = session.get(url)
assert response.content == b"error"
m.register_uri("GET", url, text="error")
response = session.get(url)
assert response.content == b"error"

assert m.call_count == RunConfiguration.request_max_attempts

Expand All @@ -160,12 +166,12 @@ def retry_on(response: requests.Response, exception: BaseException) -> bool:
return response.text == "error"

session = Client(retry_condition=retry_on).session
m = requests_mock.Adapter()
session.mount("https://", m)
url = "https://example.com/data"
responses = [dict(text="error"), dict(text="error"), dict(text="success")]

with requests_mock.mock(session=session) as m:
m.get(url, responses)
resp = session.get(url)
m.register_uri("GET", url, [dict(text="error"), dict(text="error"), dict(text="success")])
resp = session.get(url)

assert resp.text == "success"
assert m.call_count == 3
Expand All @@ -174,14 +180,16 @@ def retry_on(response: requests.Response, exception: BaseException) -> bool:
def test_wait_retry_after_int(mock_sleep: mock.MagicMock) -> None:
session = Client(request_backoff_factor=0).session
url = "https://example.com/data"
m = requests_mock.Adapter()
session.mount("https://", m)
m.register_uri("GET", url, text="error")
responses = [
dict(text="error", headers={"retry-after": "4"}, status_code=429),
dict(text="success"),
]

with requests_mock.mock(session=session) as m:
m.get(url, responses)
session.get(url)
m.register_uri("GET", url, responses)
session.get(url)

mock_sleep.assert_called_once()
assert 4 <= mock_sleep.call_args[0][0] <= 5 # Adds jitter up to 1s
Expand Down

0 comments on commit b46e8a6

Please sign in to comment.