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+ from pytest_httpserver import HTTPServer
7+ import pytest
108
119from minfraud .errors import (
1210 HTTPError ,
1917from minfraud .models import Factors , Insights , Score
2018from minfraud .webservice import AsyncClient , Client
2119
20+ import minfraud .webservice
2221import unittest
2322
23+ minfraud .webservice ._SCHEME = "http"
24+
2425
2526class BaseTest (unittest .TestCase ):
2627 client_class : Union [Type [AsyncClient ], Type [Client ]] = Client
2728
28- def setUp (self ):
29- self .client = self .client_class (42 , "abcdef123456" )
29+ @pytest .fixture (autouse = True )
30+ def setup_httpserver (self , httpserver : HTTPServer ):
31+ self .httpserver = httpserver
3032
33+ def setUp (self ):
34+ self .client = self .client_class (
35+ 42 ,
36+ "abcdef123456" ,
37+ host = "{0}:{1}" .format (self .httpserver .host , self .httpserver .port ),
38+ )
3139 test_dir = os .path .join (os .path .dirname (__file__ ), "data" )
3240 with open (os .path .join (test_dir , self .request_file ), encoding = "utf-8" ) as file :
3341 content = file .read ()
@@ -36,9 +44,6 @@ def setUp(self):
3644 with open (os .path .join (test_dir , self .response_file ), encoding = "utf-8" ) as file :
3745 self .response = file .read ()
3846
39- base_uri = "https://minfraud.maxmind.com/minfraud/v2.0"
40-
41- @httprettified
4247 def test_invalid_auth (self ):
4348 for error in (
4449 "ACCOUNT_ID_REQUIRED" ,
@@ -52,27 +57,23 @@ def test_invalid_auth(self):
5257 status_code = 401 ,
5358 )
5459
55- @httprettified
5660 def test_invalid_request (self ):
5761 with self .assertRaisesRegex (InvalidRequestError , "IP invalid" ):
5862 self .create_error (text = '{"code":"IP_ADDRESS_INVALID","error":"IP invalid"}' )
5963
60- @httprettified
6164 def test_300_error (self ):
6265 with self .assertRaisesRegex (
6366 HTTPError , r"Received an unexpected HTTP status \(300\) for"
6467 ):
6568 self .create_error (status_code = 300 )
6669
67- @httprettified
6870 def test_permission_required (self ):
6971 with self .assertRaisesRegex (PermissionRequiredError , "permission" ):
7072 self .create_error (
7173 text = '{"code":"PERMISSION_REQUIRED","error":"permission required"}' ,
7274 status_code = 403 ,
7375 )
7476
75- @httprettified
7677 def test_400_with_invalid_json (self ):
7778 with self .assertRaisesRegex (
7879 HTTPError ,
@@ -81,19 +82,16 @@ def test_400_with_invalid_json(self):
8182 ):
8283 self .create_error (text = "{blah}" )
8384
84- @httprettified
8585 def test_400_with_no_body (self ):
8686 with self .assertRaisesRegex (HTTPError , "Received a 400 error with no body" ):
8787 self .create_error ()
8888
89- @httprettified
9089 def test_400_with_unexpected_content_type (self ):
9190 with self .assertRaisesRegex (
9291 HTTPError , "Received a 400 with the following body: b?'?plain'?"
9392 ):
9493 self .create_error (content_type = "text/plain" , text = "plain" )
9594
96- @httprettified
9795 def test_400_without_json_body (self ):
9896 with self .assertRaisesRegex (
9997 HTTPError ,
@@ -102,7 +100,6 @@ def test_400_without_json_body(self):
102100 ):
103101 self .create_error (text = "plain" )
104102
105- @httprettified
106103 def test_400_with_unexpected_json (self ):
107104 with self .assertRaisesRegex (
108105 HTTPError ,
@@ -111,55 +108,53 @@ def test_400_with_unexpected_json(self):
111108 ):
112109 self .create_error (text = '{"not":"expected"}' )
113110
114- @httprettified
115111 def test_500_error (self ):
116112 with self .assertRaisesRegex (HTTPError , r"Received a server error \(500\) for" ):
117113 self .create_error (status_code = 500 )
118114
119115 def create_error (self , status_code = 400 , text = "" , content_type = None ):
120116 uri = "/" .join (
121- [self . base_uri , "transactions" , "report" ]
117+ ["/minfraud/v2.0" , "transactions" , "report" ]
122118 if self .type == "report"
123- else [self . base_uri , self .type ]
119+ else ["/minfraud/v2.0" , self .type ]
124120 )
125121 if content_type is None :
126122 content_type = (
127123 "application/json"
128124 if self .type == "report"
129125 else "application/vnd.maxmind.com-error+json; charset=UTF-8; version=2.0"
130126 )
131- httpretty .register_uri (
132- httpretty .POST ,
133- uri = uri ,
134- status = status_code ,
135- body = text ,
127+ self .httpserver .expect_request (uri , method = "POST" ).respond_with_data (
128+ text ,
136129 content_type = content_type ,
130+ status = status_code ,
137131 )
138132 return self .run_client (getattr (self .client , self .type )(self .full_request ))
139133
140134 def create_success (self , text = None , client = None , request = None ):
141135 uri = "/" .join (
142- [self . base_uri , "transactions" , "report" ]
136+ ["/minfraud/v2.0" , "transactions" , "report" ]
143137 if self .type == "report"
144- else [self . base_uri , self .type ]
138+ else ["/minfraud/v2.0" , self .type ]
145139 )
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 ,
140+ if request is None :
141+ request = self .full_request
142+
143+ response = self .response if text is None else text
144+ status = 204 if self .type == "report" else 200
145+ self .httpserver .expect_request (uri , method = "POST" ).respond_with_data (
146+ response ,
151147 content_type = f"application/vnd.maxmind.com-minfraud-{ self .type } +json; charset=UTF-8; version=2.0" ,
148+ status = status ,
152149 )
153150 if client is None :
154151 client = self .client
155- if request is None :
156- request = self .full_request
152+
157153 return self .run_client (getattr (client , self .type )(request ))
158154
159155 def run_client (self , v ):
160156 return v
161157
162- @httprettified
163158 def test_named_constructor_args (self ):
164159 id = "47"
165160 key = "1234567890ab"
@@ -170,7 +165,6 @@ def test_named_constructor_args(self):
170165 self .assertEqual (client ._account_id , id )
171166 self .assertEqual (client ._license_key , key )
172167
173- @httprettified
174168 def test_missing_constructor_args (self ):
175169 with self .assertRaises (TypeError ):
176170 self .client_class (license_key = "1234567890ab" )
@@ -180,10 +174,10 @@ def test_missing_constructor_args(self):
180174
181175
182176class BaseTransactionTest (BaseTest ):
177+
183178 def has_ip_location (self ):
184179 return self .type in ["factors" , "insights" ]
185180
186- @httprettified
187181 def test_200 (self ):
188182 model = self .create_success ()
189183 response = json .loads (self .response )
@@ -197,7 +191,6 @@ def test_200(self):
197191 self .assertEqual ("004" , model .ip_address .traits .mobile_network_code )
198192 self .assertEqual ("ANONYMOUS_IP" , model .ip_address .risk_reasons [0 ].code )
199193
200- @httprettified
201194 def test_200_on_request_with_nones (self ):
202195 model = self .create_success (
203196 request = {
@@ -215,36 +208,36 @@ def test_200_on_request_with_nones(self):
215208 response = self .response
216209 self .assertEqual (0.01 , model .risk_score )
217210
218- @httprettified
219211 def test_200_with_email_hashing (self ):
220- uri = "/" .join ([self .base_uri , self .type ])
221-
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" ,
228- )
229-
230- request = {"email" : {"address" : "Test+ignore@maxmind.com" }}
231- self .run_client (getattr (self .client , self .type )(request , hash_email = True ))
232-
233- self .assertEqual (
234- {
212+ uri = "/" .join (["/minfraud/v2.0" , self .type ])
213+ self .httpserver .expect_request (
214+ uri ,
215+ method = "POST" ,
216+ json = {
235217 "email" : {
236218 "address" : "977577b140bfb7c516e4746204fbdb01" ,
237219 "domain" : "maxmind.com" ,
238220 }
239221 },
240- json .loads (httpretty .last_request .body ),
222+ ).respond_with_data (
223+ self .response ,
224+ content_type = f"application/vnd.maxmind.com-minfraud-{ self .type } +json; charset=UTF-8; version=2.0" ,
225+ status = 200 ,
241226 )
242227
228+ request = {"email" : {"address" : "Test+ignore@maxmind.com" }}
229+ self .run_client (getattr (self .client , self .type )(request , hash_email = True ))
230+
243231 # This was fixed in https://github.com/maxmind/minfraud-api-python/pull/78
244- @ httprettified
232+
245233 def test_200_with_locales (self ):
246234 locales = ("fr" ,)
247- client = self .client_class (42 , "abcdef123456" , locales = locales )
235+ client = self .client_class (
236+ 42 ,
237+ "abcdef123456" ,
238+ locales = locales ,
239+ host = "{0}:{1}" .format (self .httpserver .host , self .httpserver .port ),
240+ )
248241 model = self .create_success (client = client )
249242 response = json .loads (self .response )
250243 if self .has_ip_location ():
@@ -254,7 +247,6 @@ def test_200_with_locales(self):
254247 self .assertEqual ("Royaume-Uni" , model .ip_address .country .name )
255248 self .assertEqual ("Londres" , model .ip_address .city .name )
256249
257- @httprettified
258250 def test_200_with_reserved_ip_warning (self ):
259251 model = self .create_success (
260252 """
@@ -275,7 +267,6 @@ def test_200_with_reserved_ip_warning(self):
275267
276268 self .assertEqual (12 , model .risk_score )
277269
278- @httprettified
279270 def test_200_with_no_body (self ):
280271 with self .assertRaisesRegex (
281272 MinFraudError ,
@@ -284,7 +275,6 @@ def test_200_with_no_body(self):
284275 ):
285276 self .create_success (text = "" )
286277
287- @httprettified
288278 def test_200_with_invalid_json (self ):
289279 with self .assertRaisesRegex (
290280 MinFraudError ,
@@ -293,7 +283,6 @@ def test_200_with_invalid_json(self):
293283 ):
294284 self .create_success (text = "{" )
295285
296- @httprettified
297286 def test_insufficient_funds (self ):
298287 with self .assertRaisesRegex (InsufficientFundsError , "out of funds" ):
299288 self .create_error (
@@ -328,11 +317,9 @@ class TestReportTransaction(BaseTest):
328317 request_file = "full-report-request.json"
329318 response_file = "report-response.json"
330319
331- @httprettified
332320 def test_204 (self ):
333321 self .create_success ()
334322
335- @httprettified
336323 def test_204_on_request_with_nones (self ):
337324 self .create_success (
338325 request = {
0 commit comments