33import os
44from io import open
55from typing import Type , Union
6-
7- # httpretty currently doesn't work, but mocket with the compat interface
8- # does. See, e.g., https://github.com/gabrielfalcao/HTTPretty/issues/220
9- from mocket .plugins .httpretty import httpretty , httprettified # type: ignore
6+ import pytest_httpserver
7+ import pytest
108
119from minfraud .errors import (
1210 HTTPError ,
2523class BaseTest (unittest .TestCase ):
2624 client_class : Union [Type [AsyncClient ], Type [Client ]] = Client
2725
26+ @pytest .fixture (autouse = True )
27+ def setup_httpserver (self , httpserver : pytest_httpserver .HTTPServer ):
28+ self .httpserver = httpserver
29+
2830 def setUp (self ):
2931 self .client = self .client_class (42 , "abcdef123456" )
32+ self .client ._base_uri = self .httpserver .url_for ("/" ) + "minfraud/v2.0"
33+ self .client ._factors_uri = (
34+ self .httpserver .url_for ("/" ) + "minfraud/v2.0/factors"
35+ )
36+ self .client ._insights_uri = (
37+ self .httpserver .url_for ("/" ) + "minfraud/v2.0/insights"
38+ )
39+ self .client ._score_uri = self .httpserver .url_for ("/" ) + "minfraud/v2.0/score"
40+ self .client ._report_uri = (
41+ self .httpserver .url_for ("/" ) + "minfraud/v2.0/transactions/report"
42+ )
43+ self .base_uri = self .client ._base_uri
3044
3145 test_dir = os .path .join (os .path .dirname (__file__ ), "data" )
3246 with open (os .path .join (test_dir , self .request_file ), encoding = "utf-8" ) as file :
@@ -36,9 +50,6 @@ def setUp(self):
3650 with open (os .path .join (test_dir , self .response_file ), encoding = "utf-8" ) as file :
3751 self .response = file .read ()
3852
39- base_uri = "https://minfraud.maxmind.com/minfraud/v2.0"
40-
41- @httprettified
4253 def test_invalid_auth (self ):
4354 for error in (
4455 "ACCOUNT_ID_REQUIRED" ,
@@ -52,27 +63,23 @@ def test_invalid_auth(self):
5263 status_code = 401 ,
5364 )
5465
55- @httprettified
5666 def test_invalid_request (self ):
5767 with self .assertRaisesRegex (InvalidRequestError , "IP invalid" ):
5868 self .create_error (text = '{"code":"IP_ADDRESS_INVALID","error":"IP invalid"}' )
5969
60- @httprettified
6170 def test_300_error (self ):
6271 with self .assertRaisesRegex (
6372 HTTPError , r"Received an unexpected HTTP status \(300\) for"
6473 ):
6574 self .create_error (status_code = 300 )
6675
67- @httprettified
6876 def test_permission_required (self ):
6977 with self .assertRaisesRegex (PermissionRequiredError , "permission" ):
7078 self .create_error (
7179 text = '{"code":"PERMISSION_REQUIRED","error":"permission required"}' ,
7280 status_code = 403 ,
7381 )
7482
75- @httprettified
7683 def test_400_with_invalid_json (self ):
7784 with self .assertRaisesRegex (
7885 HTTPError ,
@@ -81,19 +88,16 @@ def test_400_with_invalid_json(self):
8188 ):
8289 self .create_error (text = "{blah}" )
8390
84- @httprettified
8591 def test_400_with_no_body (self ):
8692 with self .assertRaisesRegex (HTTPError , "Received a 400 error with no body" ):
8793 self .create_error ()
8894
89- @httprettified
9095 def test_400_with_unexpected_content_type (self ):
9196 with self .assertRaisesRegex (
9297 HTTPError , "Received a 400 with the following body: b?'?plain'?"
9398 ):
9499 self .create_error (content_type = "text/plain" , text = "plain" )
95100
96- @httprettified
97101 def test_400_without_json_body (self ):
98102 with self .assertRaisesRegex (
99103 HTTPError ,
@@ -102,7 +106,6 @@ def test_400_without_json_body(self):
102106 ):
103107 self .create_error (text = "plain" )
104108
105- @httprettified
106109 def test_400_with_unexpected_json (self ):
107110 with self .assertRaisesRegex (
108111 HTTPError ,
@@ -111,55 +114,53 @@ def test_400_with_unexpected_json(self):
111114 ):
112115 self .create_error (text = '{"not":"expected"}' )
113116
114- @httprettified
115117 def test_500_error (self ):
116118 with self .assertRaisesRegex (HTTPError , r"Received a server error \(500\) for" ):
117119 self .create_error (status_code = 500 )
118120
119121 def create_error (self , status_code = 400 , text = "" , content_type = None ):
120122 uri = "/" .join (
121- [self . base_uri , "transactions" , "report" ]
123+ ["/minfraud/v2.0" , "transactions" , "report" ]
122124 if self .type == "report"
123- else [self . base_uri , self .type ]
125+ else ["/minfraud/v2.0" , self .type ]
124126 )
125127 if content_type is None :
126128 content_type = (
127129 "application/json"
128130 if self .type == "report"
129131 else "application/vnd.maxmind.com-error+json; charset=UTF-8; version=2.0"
130132 )
131- httpretty .register_uri (
132- httpretty .POST ,
133- uri = uri ,
134- status = status_code ,
135- body = text ,
133+ self .httpserver .expect_request (uri , method = "POST" ).respond_with_data (
134+ text ,
136135 content_type = content_type ,
136+ status = status_code ,
137137 )
138138 return self .run_client (getattr (self .client , self .type )(self .full_request ))
139139
140140 def create_success (self , text = None , client = None , request = None ):
141141 uri = "/" .join (
142- [self . base_uri , "transactions" , "report" ]
142+ ["/minfraud/v2.0" , "transactions" , "report" ]
143143 if self .type == "report"
144- else [self . base_uri , self .type ]
144+ else ["/minfraud/v2.0" , self .type ]
145145 )
146- httpretty .register_uri (
147- httpretty .POST ,
148- uri = uri ,
149- status = 204 if self .type == "report" else 200 ,
150- body = self .response if text is None else text ,
146+ if request is None :
147+ request = self .full_request
148+
149+ response = self .response if text is None else text
150+ status = 204 if self .type == "report" else 200
151+ self .httpserver .expect_request (uri , method = "POST" ).respond_with_data (
152+ response ,
151153 content_type = f"application/vnd.maxmind.com-minfraud-{ self .type } +json; charset=UTF-8; version=2.0" ,
154+ status = status ,
152155 )
153156 if client is None :
154157 client = self .client
155- if request is None :
156- request = self .full_request
158+
157159 return self .run_client (getattr (client , self .type )(request ))
158160
159161 def run_client (self , v ):
160162 return v
161163
162- @httprettified
163164 def test_named_constructor_args (self ):
164165 id = "47"
165166 key = "1234567890ab"
@@ -170,7 +171,6 @@ def test_named_constructor_args(self):
170171 self .assertEqual (client ._account_id , id )
171172 self .assertEqual (client ._license_key , key )
172173
173- @httprettified
174174 def test_missing_constructor_args (self ):
175175 with self .assertRaises (TypeError ):
176176 self .client_class (license_key = "1234567890ab" )
@@ -180,10 +180,10 @@ def test_missing_constructor_args(self):
180180
181181
182182class BaseTransactionTest (BaseTest ):
183+
183184 def has_ip_location (self ):
184185 return self .type in ["factors" , "insights" ]
185186
186- @httprettified
187187 def test_200 (self ):
188188 model = self .create_success ()
189189 response = json .loads (self .response )
@@ -197,7 +197,6 @@ def test_200(self):
197197 self .assertEqual ("004" , model .ip_address .traits .mobile_network_code )
198198 self .assertEqual ("ANONYMOUS_IP" , model .ip_address .risk_reasons [0 ].code )
199199
200- @httprettified
201200 def test_200_on_request_with_nones (self ):
202201 model = self .create_success (
203202 request = {
@@ -215,20 +214,25 @@ def test_200_on_request_with_nones(self):
215214 response = self .response
216215 self .assertEqual (0.01 , model .risk_score )
217216
218- @httprettified
219217 def test_200_with_email_hashing (self ):
220- uri = "/" .join ([self . base_uri , self .type ])
218+ uri = "/" .join (["/minfraud/v2.0" , self .type ])
221219
222- httpretty .register_uri (
223- httpretty .POST ,
224- uri = uri ,
225- status = 200 ,
226- body = self .response ,
227- content_type = f"application/vnd.maxmind.com-minfraud-{ self .type } +json; charset=UTF-8; version=2.0" ,
220+ last = None
221+
222+ def custom_handler (r ):
223+ nonlocal last
224+ last = r
225+ return "hello world"
226+
227+ self .httpserver .expect_request (uri , method = "POST" ).respond_with_handler (
228+ custom_handler
228229 )
229230
230231 request = {"email" : {"address" : "Test+ignore@maxmind.com" }}
231- self .run_client (getattr (self .client , self .type )(request , hash_email = True ))
232+ try :
233+ self .run_client (getattr (self .client , self .type )(request , hash_email = True ))
234+ except Exception as e :
235+ pass
232236
233237 self .assertEqual (
234238 {
@@ -237,14 +241,21 @@ def test_200_with_email_hashing(self):
237241 "domain" : "maxmind.com" ,
238242 }
239243 },
240- json .loads (httpretty . last_request . body ),
244+ json .loads (last . data . decode ( "utf-8" ) ),
241245 )
242246
243247 # This was fixed in https://github.com/maxmind/minfraud-api-python/pull/78
244- @ httprettified
248+
245249 def test_200_with_locales (self ):
246250 locales = ("fr" ,)
247251 client = self .client_class (42 , "abcdef123456" , locales = locales )
252+ client ._base_uri = self .httpserver .url_for ("/" ) + "minfraud/v2.0"
253+ client ._factors_uri = self .httpserver .url_for ("/" ) + "minfraud/v2.0/factors"
254+ client ._insights_uri = self .httpserver .url_for ("/" ) + "minfraud/v2.0/insights"
255+ client ._score_uri = self .httpserver .url_for ("/" ) + "minfraud/v2.0/score"
256+ client ._report_uri = (
257+ self .httpserver .url_for ("/" ) + "minfraud/v2.0/transactions/report"
258+ )
248259 model = self .create_success (client = client )
249260 response = json .loads (self .response )
250261 if self .has_ip_location ():
@@ -254,7 +265,6 @@ def test_200_with_locales(self):
254265 self .assertEqual ("Royaume-Uni" , model .ip_address .country .name )
255266 self .assertEqual ("Londres" , model .ip_address .city .name )
256267
257- @httprettified
258268 def test_200_with_reserved_ip_warning (self ):
259269 model = self .create_success (
260270 """
@@ -275,7 +285,6 @@ def test_200_with_reserved_ip_warning(self):
275285
276286 self .assertEqual (12 , model .risk_score )
277287
278- @httprettified
279288 def test_200_with_no_body (self ):
280289 with self .assertRaisesRegex (
281290 MinFraudError ,
@@ -284,7 +293,6 @@ def test_200_with_no_body(self):
284293 ):
285294 self .create_success (text = "" )
286295
287- @httprettified
288296 def test_200_with_invalid_json (self ):
289297 with self .assertRaisesRegex (
290298 MinFraudError ,
@@ -293,7 +301,6 @@ def test_200_with_invalid_json(self):
293301 ):
294302 self .create_success (text = "{" )
295303
296- @httprettified
297304 def test_insufficient_funds (self ):
298305 with self .assertRaisesRegex (InsufficientFundsError , "out of funds" ):
299306 self .create_error (
@@ -328,11 +335,9 @@ class TestReportTransaction(BaseTest):
328335 request_file = "full-report-request.json"
329336 response_file = "report-response.json"
330337
331- @httprettified
332338 def test_204 (self ):
333339 self .create_success ()
334340
335- @httprettified
336341 def test_204_on_request_with_nones (self ):
337342 self .create_success (
338343 request = {
0 commit comments