3
3
import os
4
4
from io import open
5
5
from 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
10
8
11
9
from minfraud .errors import (
12
10
HTTPError ,
25
23
class BaseTest (unittest .TestCase ):
26
24
client_class : Union [Type [AsyncClient ], Type [Client ]] = Client
27
25
26
+ @pytest .fixture (autouse = True )
27
+ def setup_httpserver (self , httpserver : pytest_httpserver .HTTPServer ):
28
+ self .httpserver = httpserver
29
+
28
30
def setUp (self ):
29
31
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
30
44
31
45
test_dir = os .path .join (os .path .dirname (__file__ ), "data" )
32
46
with open (os .path .join (test_dir , self .request_file ), encoding = "utf-8" ) as file :
@@ -36,9 +50,6 @@ def setUp(self):
36
50
with open (os .path .join (test_dir , self .response_file ), encoding = "utf-8" ) as file :
37
51
self .response = file .read ()
38
52
39
- base_uri = "https://minfraud.maxmind.com/minfraud/v2.0"
40
-
41
- @httprettified
42
53
def test_invalid_auth (self ):
43
54
for error in (
44
55
"ACCOUNT_ID_REQUIRED" ,
@@ -52,27 +63,23 @@ def test_invalid_auth(self):
52
63
status_code = 401 ,
53
64
)
54
65
55
- @httprettified
56
66
def test_invalid_request (self ):
57
67
with self .assertRaisesRegex (InvalidRequestError , "IP invalid" ):
58
68
self .create_error (text = '{"code":"IP_ADDRESS_INVALID","error":"IP invalid"}' )
59
69
60
- @httprettified
61
70
def test_300_error (self ):
62
71
with self .assertRaisesRegex (
63
72
HTTPError , r"Received an unexpected HTTP status \(300\) for"
64
73
):
65
74
self .create_error (status_code = 300 )
66
75
67
- @httprettified
68
76
def test_permission_required (self ):
69
77
with self .assertRaisesRegex (PermissionRequiredError , "permission" ):
70
78
self .create_error (
71
79
text = '{"code":"PERMISSION_REQUIRED","error":"permission required"}' ,
72
80
status_code = 403 ,
73
81
)
74
82
75
- @httprettified
76
83
def test_400_with_invalid_json (self ):
77
84
with self .assertRaisesRegex (
78
85
HTTPError ,
@@ -81,19 +88,16 @@ def test_400_with_invalid_json(self):
81
88
):
82
89
self .create_error (text = "{blah}" )
83
90
84
- @httprettified
85
91
def test_400_with_no_body (self ):
86
92
with self .assertRaisesRegex (HTTPError , "Received a 400 error with no body" ):
87
93
self .create_error ()
88
94
89
- @httprettified
90
95
def test_400_with_unexpected_content_type (self ):
91
96
with self .assertRaisesRegex (
92
97
HTTPError , "Received a 400 with the following body: b?'?plain'?"
93
98
):
94
99
self .create_error (content_type = "text/plain" , text = "plain" )
95
100
96
- @httprettified
97
101
def test_400_without_json_body (self ):
98
102
with self .assertRaisesRegex (
99
103
HTTPError ,
@@ -102,7 +106,6 @@ def test_400_without_json_body(self):
102
106
):
103
107
self .create_error (text = "plain" )
104
108
105
- @httprettified
106
109
def test_400_with_unexpected_json (self ):
107
110
with self .assertRaisesRegex (
108
111
HTTPError ,
@@ -111,55 +114,53 @@ def test_400_with_unexpected_json(self):
111
114
):
112
115
self .create_error (text = '{"not":"expected"}' )
113
116
114
- @httprettified
115
117
def test_500_error (self ):
116
118
with self .assertRaisesRegex (HTTPError , r"Received a server error \(500\) for" ):
117
119
self .create_error (status_code = 500 )
118
120
119
121
def create_error (self , status_code = 400 , text = "" , content_type = None ):
120
122
uri = "/" .join (
121
- [self . base_uri , "transactions" , "report" ]
123
+ ["/minfraud/v2.0" , "transactions" , "report" ]
122
124
if self .type == "report"
123
- else [self . base_uri , self .type ]
125
+ else ["/minfraud/v2.0" , self .type ]
124
126
)
125
127
if content_type is None :
126
128
content_type = (
127
129
"application/json"
128
130
if self .type == "report"
129
131
else "application/vnd.maxmind.com-error+json; charset=UTF-8; version=2.0"
130
132
)
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 ,
136
135
content_type = content_type ,
136
+ status = status_code ,
137
137
)
138
138
return self .run_client (getattr (self .client , self .type )(self .full_request ))
139
139
140
140
def create_success (self , text = None , client = None , request = None ):
141
141
uri = "/" .join (
142
- [self . base_uri , "transactions" , "report" ]
142
+ ["/minfraud/v2.0" , "transactions" , "report" ]
143
143
if self .type == "report"
144
- else [self . base_uri , self .type ]
144
+ else ["/minfraud/v2.0" , self .type ]
145
145
)
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 ,
151
153
content_type = f"application/vnd.maxmind.com-minfraud-{ self .type } +json; charset=UTF-8; version=2.0" ,
154
+ status = status ,
152
155
)
153
156
if client is None :
154
157
client = self .client
155
- if request is None :
156
- request = self .full_request
158
+
157
159
return self .run_client (getattr (client , self .type )(request ))
158
160
159
161
def run_client (self , v ):
160
162
return v
161
163
162
- @httprettified
163
164
def test_named_constructor_args (self ):
164
165
id = "47"
165
166
key = "1234567890ab"
@@ -170,7 +171,6 @@ def test_named_constructor_args(self):
170
171
self .assertEqual (client ._account_id , id )
171
172
self .assertEqual (client ._license_key , key )
172
173
173
- @httprettified
174
174
def test_missing_constructor_args (self ):
175
175
with self .assertRaises (TypeError ):
176
176
self .client_class (license_key = "1234567890ab" )
@@ -180,10 +180,10 @@ def test_missing_constructor_args(self):
180
180
181
181
182
182
class BaseTransactionTest (BaseTest ):
183
+
183
184
def has_ip_location (self ):
184
185
return self .type in ["factors" , "insights" ]
185
186
186
- @httprettified
187
187
def test_200 (self ):
188
188
model = self .create_success ()
189
189
response = json .loads (self .response )
@@ -197,7 +197,6 @@ def test_200(self):
197
197
self .assertEqual ("004" , model .ip_address .traits .mobile_network_code )
198
198
self .assertEqual ("ANONYMOUS_IP" , model .ip_address .risk_reasons [0 ].code )
199
199
200
- @httprettified
201
200
def test_200_on_request_with_nones (self ):
202
201
model = self .create_success (
203
202
request = {
@@ -215,20 +214,25 @@ def test_200_on_request_with_nones(self):
215
214
response = self .response
216
215
self .assertEqual (0.01 , model .risk_score )
217
216
218
- @httprettified
219
217
def test_200_with_email_hashing (self ):
220
- uri = "/" .join ([self . base_uri , self .type ])
218
+ uri = "/" .join (["/minfraud/v2.0" , self .type ])
221
219
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
228
229
)
229
230
230
231
request = {
"email" : {
"address" :
"[email protected] " }}
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
232
236
233
237
self .assertEqual (
234
238
{
@@ -237,14 +241,21 @@ def test_200_with_email_hashing(self):
237
241
"domain" : "maxmind.com" ,
238
242
}
239
243
},
240
- json .loads (httpretty . last_request . body ),
244
+ json .loads (last . data . decode ( "utf-8" ) ),
241
245
)
242
246
243
247
# This was fixed in https://github.com/maxmind/minfraud-api-python/pull/78
244
- @ httprettified
248
+
245
249
def test_200_with_locales (self ):
246
250
locales = ("fr" ,)
247
251
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
+ )
248
259
model = self .create_success (client = client )
249
260
response = json .loads (self .response )
250
261
if self .has_ip_location ():
@@ -254,7 +265,6 @@ def test_200_with_locales(self):
254
265
self .assertEqual ("Royaume-Uni" , model .ip_address .country .name )
255
266
self .assertEqual ("Londres" , model .ip_address .city .name )
256
267
257
- @httprettified
258
268
def test_200_with_reserved_ip_warning (self ):
259
269
model = self .create_success (
260
270
"""
@@ -275,7 +285,6 @@ def test_200_with_reserved_ip_warning(self):
275
285
276
286
self .assertEqual (12 , model .risk_score )
277
287
278
- @httprettified
279
288
def test_200_with_no_body (self ):
280
289
with self .assertRaisesRegex (
281
290
MinFraudError ,
@@ -284,7 +293,6 @@ def test_200_with_no_body(self):
284
293
):
285
294
self .create_success (text = "" )
286
295
287
- @httprettified
288
296
def test_200_with_invalid_json (self ):
289
297
with self .assertRaisesRegex (
290
298
MinFraudError ,
@@ -293,7 +301,6 @@ def test_200_with_invalid_json(self):
293
301
):
294
302
self .create_success (text = "{" )
295
303
296
- @httprettified
297
304
def test_insufficient_funds (self ):
298
305
with self .assertRaisesRegex (InsufficientFundsError , "out of funds" ):
299
306
self .create_error (
@@ -328,11 +335,9 @@ class TestReportTransaction(BaseTest):
328
335
request_file = "full-report-request.json"
329
336
response_file = "report-response.json"
330
337
331
- @httprettified
332
338
def test_204 (self ):
333
339
self .create_success ()
334
340
335
- @httprettified
336
341
def test_204_on_request_with_nones (self ):
337
342
self .create_success (
338
343
request = {
0 commit comments