8
8
import sys
9
9
from typing import cast , Dict
10
10
import unittest
11
+ import pytest_httpserver
12
+ import pytest
11
13
12
14
sys .path .append (".." )
13
-
14
- # httpretty currently doesn't work, but mocket with the compat interface
15
- # does.
16
- from mocket import Mocket # type: ignore
17
- from mocket .plugins .httpretty import httpretty , httprettified # type: ignore
18
15
import geoip2
19
16
from geoip2 .errors import (
20
17
AddressNotFoundError ,
29
26
30
27
31
28
class TestBaseClient (unittest .TestCase ):
32
- base_uri = "https://geoip.maxmind.com/geoip/v2.1/"
33
29
country = {
34
30
"continent" : {"code" : "NA" , "geoname_id" : 42 , "names" : {"en" : "North America" }},
35
31
"country" : {
@@ -64,12 +60,13 @@ def _content_type(self, endpoint):
64
60
+ "+json; charset=UTF-8; version=1.0"
65
61
)
66
62
67
- @httprettified
63
+ @pytest .fixture (autouse = True )
64
+ def setup_httpserver (self , httpserver : pytest_httpserver .HTTPServer ):
65
+ self .httpserver = httpserver
66
+
68
67
def test_country_ok (self ):
69
- httpretty .register_uri (
70
- httpretty .GET ,
71
- self .base_uri + "country/1.2.3.4" ,
72
- body = json .dumps (self .country ),
68
+ self .httpserver .expect_request ("/geoip/v2.1/country/1.2.3.4" ).respond_with_json (
69
+ self .country ,
73
70
status = 200 ,
74
71
content_type = self ._content_type ("country" ),
75
72
)
@@ -111,12 +108,9 @@ def test_country_ok(self):
111
108
self .assertTrue (country .traits .is_anycast )
112
109
self .assertEqual (country .raw , self .country , "raw response is correct" )
113
110
114
- @httprettified
115
111
def test_me (self ):
116
- httpretty .register_uri (
117
- httpretty .GET ,
118
- self .base_uri + "country/me" ,
119
- body = json .dumps (self .country ),
112
+ self .httpserver .expect_request ("/geoip/v2.1/country/me" ).respond_with_json (
113
+ self .country ,
120
114
status = 200 ,
121
115
content_type = self ._content_type ("country" ),
122
116
)
@@ -131,33 +125,29 @@ def test_me(self):
131
125
"country('me') returns Country object" ,
132
126
)
133
127
134
- @httprettified
135
128
def test_200_error (self ):
136
- httpretty .register_uri (
137
- httpretty .GET ,
138
- self .base_uri + "country/1.1.1.1" ,
139
- body = "" ,
129
+ self .httpserver .expect_request ("/geoip/v2.1/country/1.1.1.1" ).respond_with_data (
130
+ "" ,
140
131
status = 200 ,
141
132
content_type = self ._content_type ("country" ),
142
133
)
134
+
143
135
with self .assertRaisesRegex (
144
136
GeoIP2Error , "could not decode the response as JSON"
145
137
):
146
138
self .run_client (self .client .country ("1.1.1.1" ))
147
139
148
- @httprettified
149
140
def test_bad_ip_address (self ):
150
141
with self .assertRaisesRegex (
151
142
ValueError , "'1.2.3' does not appear to be an IPv4 " "or IPv6 address"
152
143
):
153
144
self .run_client (self .client .country ("1.2.3" ))
154
145
155
- @httprettified
156
146
def test_no_body_error (self ):
157
- httpretty . register_uri (
158
- httpretty . GET ,
159
- self . base_uri + "country/" + "1.2.3.7" ,
160
- body = "" ,
147
+ self . httpserver . expect_request (
148
+ "/geoip/v2.1/country/" + "1.2.3.7"
149
+ ). respond_with_data (
150
+ "" ,
161
151
status = 400 ,
162
152
content_type = self ._content_type ("country" ),
163
153
)
@@ -166,27 +156,28 @@ def test_no_body_error(self):
166
156
):
167
157
self .run_client (self .client .country ("1.2.3.7" ))
168
158
169
- @httprettified
170
159
def test_weird_body_error (self ):
171
- httpretty .register_uri (
172
- httpretty .GET ,
173
- self .base_uri + "country/" + "1.2.3.8" ,
174
- body = '{"wierd": 42}' ,
160
+
161
+ self .httpserver .expect_request (
162
+ "/geoip/v2.1/country/" + "1.2.3.8"
163
+ ).respond_with_json (
164
+ {"wierd" : 42 },
175
165
status = 400 ,
176
166
content_type = self ._content_type ("country" ),
177
167
)
168
+
178
169
with self .assertRaisesRegex (
179
170
HTTPError ,
180
171
"Response contains JSON but it does not " "specify code or error keys" ,
181
172
):
182
173
self .run_client (self .client .country ("1.2.3.8" ))
183
174
184
- @httprettified
185
175
def test_bad_body_error (self ):
186
- httpretty .register_uri (
187
- httpretty .GET ,
188
- self .base_uri + "country/" + "1.2.3.9" ,
189
- body = "bad body" ,
176
+
177
+ self .httpserver .expect_request (
178
+ "/geoip/v2.1/country/" + "1.2.3.9"
179
+ ).respond_with_data (
180
+ "bad body" ,
190
181
status = 400 ,
191
182
content_type = self ._content_type ("country" ),
192
183
)
@@ -195,19 +186,23 @@ def test_bad_body_error(self):
195
186
):
196
187
self .run_client (self .client .country ("1.2.3.9" ))
197
188
198
- @httprettified
199
189
def test_500_error (self ):
200
- httpretty .register_uri (
201
- httpretty .GET , self .base_uri + "country/" + "1.2.3.10" , status = 500
190
+ self .httpserver .expect_request (
191
+ "/geoip/v2.1/country/" + "1.2.3.10"
192
+ ).respond_with_data (
193
+ "" ,
194
+ status = 500 ,
195
+ content_type = self ._content_type ("country" ),
202
196
)
203
197
with self .assertRaisesRegex (HTTPError , r"Received a server error \(500\) for" ):
204
198
self .run_client (self .client .country ("1.2.3.10" ))
205
199
206
- @httprettified
207
200
def test_300_error (self ):
208
- httpretty .register_uri (
209
- httpretty .GET ,
210
- self .base_uri + "country/" + "1.2.3.11" ,
201
+
202
+ self .httpserver .expect_request (
203
+ "/geoip/v2.1/country/" + "1.2.3.11"
204
+ ).respond_with_data (
205
+ "" ,
211
206
status = 300 ,
212
207
content_type = self ._content_type ("country" ),
213
208
)
@@ -216,96 +211,86 @@ def test_300_error(self):
216
211
):
217
212
self .run_client (self .client .country ("1.2.3.11" ))
218
213
219
- @httprettified
220
214
def test_ip_address_required (self ):
221
215
self ._test_error (400 , "IP_ADDRESS_REQUIRED" , InvalidRequestError )
222
216
223
- @httprettified
224
217
def test_ip_address_not_found (self ):
225
218
self ._test_error (404 , "IP_ADDRESS_NOT_FOUND" , AddressNotFoundError )
226
219
227
- @httprettified
228
220
def test_ip_address_reserved (self ):
229
221
self ._test_error (400 , "IP_ADDRESS_RESERVED" , AddressNotFoundError )
230
222
231
- @httprettified
232
223
def test_permission_required (self ):
233
224
self ._test_error (403 , "PERMISSION_REQUIRED" , PermissionRequiredError )
234
225
235
- @httprettified
236
226
def test_auth_invalid (self ):
237
227
self ._test_error (400 , "AUTHORIZATION_INVALID" , AuthenticationError )
238
228
239
- @httprettified
240
229
def test_license_key_required (self ):
241
230
self ._test_error (401 , "LICENSE_KEY_REQUIRED" , AuthenticationError )
242
231
243
- @httprettified
244
232
def test_account_id_required (self ):
245
233
self ._test_error (401 , "ACCOUNT_ID_REQUIRED" , AuthenticationError )
246
234
247
- @httprettified
248
235
def test_user_id_required (self ):
249
236
self ._test_error (401 , "USER_ID_REQUIRED" , AuthenticationError )
250
237
251
- @httprettified
252
238
def test_account_id_unkown (self ):
253
239
self ._test_error (401 , "ACCOUNT_ID_UNKNOWN" , AuthenticationError )
254
240
255
- @httprettified
256
241
def test_user_id_unkown (self ):
257
242
self ._test_error (401 , "USER_ID_UNKNOWN" , AuthenticationError )
258
243
259
- @httprettified
260
244
def test_out_of_queries_error (self ):
261
245
self ._test_error (402 , "OUT_OF_QUERIES" , OutOfQueriesError )
262
246
263
247
def _test_error (self , status , error_code , error_class ):
264
248
msg = "Some error message"
265
249
body = {"error" : msg , "code" : error_code }
266
- httpretty . register_uri (
267
- httpretty . GET ,
268
- self . base_uri + "country/1.2.3.18" ,
269
- body = json . dumps ( body ) ,
250
+ self . httpserver . expect_request (
251
+ "/geoip/v2.1/country/" + "1.2.3.18"
252
+ ). respond_with_json (
253
+ body ,
270
254
status = status ,
271
255
content_type = self ._content_type ("country" ),
272
256
)
273
257
with self .assertRaisesRegex (error_class , msg ):
274
258
self .run_client (self .client .country ("1.2.3.18" ))
275
259
276
- @httprettified
277
260
def test_unknown_error (self ):
278
261
msg = "Unknown error type"
279
262
ip = "1.2.3.19"
280
263
body = {"error" : msg , "code" : "UNKNOWN_TYPE" }
281
- httpretty .register_uri (
282
- httpretty .GET ,
283
- self .base_uri + "country/" + ip ,
284
- body = json .dumps (body ),
264
+ self .httpserver .expect_request ("/geoip/v2.1/country/" + ip ).respond_with_json (
265
+ body ,
285
266
status = 400 ,
286
267
content_type = self ._content_type ("country" ),
287
268
)
288
269
with self .assertRaisesRegex (InvalidRequestError , msg ):
289
270
self .run_client (self .client .country (ip ))
290
271
291
- @httprettified
292
272
def test_request (self ):
293
- httpretty .register_uri (
294
- httpretty .GET ,
295
- self .base_uri + "country/" + "1.2.3.4" ,
296
- body = json .dumps (self .country ),
297
- status = 200 ,
298
- content_type = self ._content_type ("country" ),
299
- )
300
- self .run_client (self .client .country ("1.2.3.4" ))
301
- request = httpretty .last_request
273
+
274
+ request = None
275
+
276
+ def custom_handler (r ):
277
+ nonlocal request
278
+ request = r
279
+ return ""
280
+
281
+ self .httpserver .expect_request (
282
+ "/geoip/v2.1/country/" + "1.2.3.4"
283
+ ).respond_with_handler (custom_handler )
284
+ try :
285
+ self .run_client (self .client .country ("1.2.3.4" ))
286
+ except Exception as e :
287
+ # just to avoid the exception
288
+ pass
302
289
303
290
self .assertEqual (
304
291
request .path , "/geoip/v2.1/country/1.2.3.4" , "correct URI is used"
305
292
)
306
293
307
- # This is to prevent breakage if header normalization in Mocket
308
- # changes again in the future.
309
294
headers = {k .lower (): v for k , v in request .headers .items ()}
310
295
self .assertEqual (headers ["accept" ], "application/json" , "correct Accept header" )
311
296
self .assertRegex (
@@ -319,12 +304,9 @@ def test_request(self):
319
304
"correct auth" ,
320
305
)
321
306
322
- @httprettified
323
307
def test_city_ok (self ):
324
- httpretty .register_uri (
325
- httpretty .GET ,
326
- self .base_uri + "city/" + "1.2.3.4" ,
327
- body = json .dumps (self .country ),
308
+ self .httpserver .expect_request ("/geoip/v2.1/city/1.2.3.4" ).respond_with_json (
309
+ self .country ,
328
310
status = 200 ,
329
311
content_type = self ._content_type ("city" ),
330
312
)
@@ -335,14 +317,13 @@ def test_city_ok(self):
335
317
)
336
318
self .assertTrue (city .traits .is_anycast )
337
319
338
- @httprettified
339
320
def test_insights_ok (self ):
340
- httpretty . register_uri (
341
- httpretty . GET ,
342
- self . base_uri + "insights/1.2.3.4" ,
343
- body = json . dumps ( self .insights ) ,
321
+ self . httpserver . expect_request (
322
+ "/geoip/v2.1/insights/" + "1.2.3.4"
323
+ ). respond_with_json (
324
+ self .insights ,
344
325
status = 200 ,
345
- content_type = self ._content_type ("country " ),
326
+ content_type = self ._content_type ("insights " ),
346
327
)
347
328
insights = self .run_client (self .client .insights ("1.2.3.4" ))
348
329
self .assertEqual (
@@ -374,6 +355,7 @@ class TestClient(TestBaseClient):
374
355
def setUp (self ):
375
356
self .client_class = Client
376
357
self .client = Client (42 , "abcdef123456" )
358
+ self .client ._base_uri = self .httpserver .url_for ("/" ) + "geoip/v2.1"
377
359
378
360
def run_client (self , v ):
379
361
return v
@@ -384,6 +366,7 @@ def setUp(self):
384
366
self ._loop = asyncio .new_event_loop ()
385
367
self .client_class = AsyncClient
386
368
self .client = AsyncClient (42 , "abcdef123456" )
369
+ self .client ._base_uri = self .httpserver .url_for ("/" ) + "geoip/v2.1"
387
370
388
371
def tearDown (self ):
389
372
self ._loop .run_until_complete (self .client .close ())
0 commit comments