Skip to content

Commit 8ef0759

Browse files
authored
Mock requests.Session.get in TestClient (#150)
1 parent ece3022 commit 8ef0759

File tree

1 file changed

+35
-33
lines changed

1 file changed

+35
-33
lines changed

tests/test_client.py

Lines changed: 35 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,13 @@
33
import arxiv
44
from datetime import datetime, timedelta
55
from pytest import approx
6+
from requests import Response
67

8+
def empty_response(code: int) -> Response:
9+
r = Response()
10+
r.status_code = code
11+
r._content = b''
12+
return r
713

814
class TestClient(unittest.TestCase):
915
def test_invalid_format_id(self):
@@ -90,10 +96,10 @@ def test_no_duplicates(self):
9096
self.assertFalse(r.entry_id in ids)
9197
ids.add(r.entry_id)
9298

99+
@patch('requests.Session.get', return_value=empty_response(500))
93100
@patch("time.sleep", return_value=None)
94-
def test_retry(self, patched_time_sleep):
95-
broken_client = TestClient.get_code_client(500)
96-
101+
def test_retry(self, mock_sleep, mock_get):
102+
broken_client = arxiv.Client()
97103
def broken_get():
98104
search = arxiv.Search(query="quantum")
99105
return next(broken_client.results(search))
@@ -109,77 +115,73 @@ def broken_get():
109115
self.assertEqual(e.status, 500)
110116
self.assertEqual(e.retry, broken_client.num_retries)
111117

118+
@patch('requests.Session.get', return_value=empty_response(200))
112119
@patch("time.sleep", return_value=None)
113-
def test_sleep_standard(self, patched_time_sleep):
114-
client = TestClient.get_code_client(200)
120+
def test_sleep_standard(self, mock_sleep, mock_get):
121+
client = arxiv.Client()
115122
url = client._format_url(arxiv.Search(query="quantum"), 0, 1)
116123
# A client should sleep until delay_seconds have passed.
117124
client._parse_feed(url)
118-
patched_time_sleep.assert_not_called()
125+
mock_sleep.assert_not_called()
119126
# Overwrite _last_request_dt to minimize flakiness: different
120127
# environments will have different page fetch times.
121128
client._last_request_dt = datetime.now()
122129
client._parse_feed(url)
123-
patched_time_sleep.assert_called_once_with(approx(client.delay_seconds, rel=1e-3))
130+
mock_sleep.assert_called_once_with(approx(client.delay_seconds, rel=1e-3))
124131

132+
@patch('requests.Session.get', return_value=empty_response(200))
125133
@patch("time.sleep", return_value=None)
126-
def test_sleep_multiple_requests(self, patched_time_sleep):
127-
client = TestClient.get_code_client(200)
134+
def test_sleep_multiple_requests(self, mock_sleep, mock_get):
135+
client = arxiv.Client()
128136
url1 = client._format_url(arxiv.Search(query="quantum"), 0, 1)
129137
url2 = client._format_url(arxiv.Search(query="testing"), 0, 1)
130138
# Rate limiting is URL-independent; expect same behavior as in
131139
# `test_sleep_standard`.
132140
client._parse_feed(url1)
133-
patched_time_sleep.assert_not_called()
141+
mock_sleep.assert_not_called()
134142
client._last_request_dt = datetime.now()
135143
client._parse_feed(url2)
136-
patched_time_sleep.assert_called_once_with(approx(client.delay_seconds, rel=1e-3))
144+
mock_sleep.assert_called_once_with(approx(client.delay_seconds, rel=1e-3))
137145

146+
@patch('requests.Session.get', return_value=empty_response(200))
138147
@patch("time.sleep", return_value=None)
139-
def test_sleep_elapsed(self, patched_time_sleep):
140-
client = TestClient.get_code_client(200)
148+
def test_sleep_elapsed(self, mock_sleep, mock_get):
149+
client = arxiv.Client()
141150
url = client._format_url(arxiv.Search(query="quantum"), 0, 1)
142151
# If _last_request_dt is less than delay_seconds ago, sleep.
143152
client._last_request_dt = datetime.now() - timedelta(seconds=client.delay_seconds - 1)
144153
client._parse_feed(url)
145-
patched_time_sleep.assert_called_once()
146-
patched_time_sleep.reset_mock()
154+
mock_sleep.assert_called_once()
155+
mock_sleep.reset_mock()
147156
# If _last_request_dt is at least delay_seconds ago, don't sleep.
148157
client._last_request_dt = datetime.now() - timedelta(seconds=client.delay_seconds)
149158
client._parse_feed(url)
150-
patched_time_sleep.assert_not_called()
159+
mock_sleep.assert_not_called()
151160

161+
@patch('requests.Session.get', return_value=empty_response(200))
152162
@patch("time.sleep", return_value=None)
153-
def test_sleep_zero_delay(self, patched_time_sleep):
154-
client = TestClient.get_code_client(code=200, delay_seconds=0)
163+
def test_sleep_zero_delay(self, mock_sleep, mock_get):
164+
client = arxiv.Client(delay_seconds=0)
155165
url = client._format_url(arxiv.Search(query="quantum"), 0, 1)
156166
client._parse_feed(url)
157167
client._parse_feed(url)
158-
patched_time_sleep.assert_not_called()
168+
mock_sleep.assert_not_called()
159169

170+
@patch('requests.Session.get', return_value=empty_response(500))
160171
@patch("time.sleep", return_value=None)
161-
def test_sleep_between_errors(self, patched_time_sleep):
162-
client = TestClient.get_code_client(500)
172+
def test_sleep_between_errors(self, mock_sleep, mock_get):
173+
client = arxiv.Client()
163174
url = client._format_url(arxiv.Search(query="quantum"), 0, 1)
164175
try:
165176
client._parse_feed(url)
166177
except arxiv.HTTPError:
167178
pass
168179
# Should sleep between retries.
169-
patched_time_sleep.assert_called()
170-
self.assertEqual(patched_time_sleep.call_count, client.num_retries)
171-
patched_time_sleep.assert_has_calls(
180+
mock_sleep.assert_called()
181+
self.assertEqual(mock_sleep.call_count, client.num_retries)
182+
mock_sleep.assert_has_calls(
172183
[
173184
call(approx(client.delay_seconds, abs=1e-2)),
174185
]
175186
* client.num_retries
176187
)
177-
178-
def get_code_client(code: int, delay_seconds=0.1, num_retries=3) -> arxiv.Client:
179-
"""
180-
get_code_client returns an arxiv.Cient with HTTP requests routed to
181-
httpstat.us.
182-
"""
183-
client = arxiv.Client(delay_seconds=delay_seconds, num_retries=num_retries)
184-
client.query_url_format = "https://teapot.fly.dev/{}?".format(code) + "{}"
185-
return client

0 commit comments

Comments
 (0)