33import arxiv
44from datetime import datetime , timedelta
55from 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
814class 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