Skip to content

Commit f65ddfd

Browse files
authored
Merge pull request #148 from maxmind/sromani/remove-mocket
Remove mocket
2 parents 0b86283 + 65627ff commit f65ddfd

File tree

5 files changed

+58
-69
lines changed

5 files changed

+58
-69
lines changed

.github/workflows/test.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@ jobs:
1111

1212
strategy:
1313
matrix:
14-
# We don't test on Windows currently as it appears mocket may not
15-
# work there.
14+
# TODO: add windows-latest
1615
platform: [ubuntu-latest, macos-latest]
1716
python-version: [3.8, 3.9, "3.10", 3.11, 3.12]
1817

minfraud/webservice.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232

3333
_REQUEST_UA = f"minFraud-API/{__version__} {requests.utils.default_user_agent()}"
3434

35+
_SCHEME = "https"
36+
3537

3638
# pylint: disable=too-many-instance-attributes, missing-class-docstring
3739
class BaseClient:
@@ -57,8 +59,7 @@ def __init__(
5759
self._account_id = str(account_id)
5860
self._license_key = license_key
5961
self._timeout = timeout
60-
61-
base_uri = f"https://{host}/minfraud/v2.0"
62+
base_uri = f"{_SCHEME}://{host}/minfraud/v2.0"
6263
self._score_uri = "/".join([base_uri, "score"])
6364
self._insights_uri = "/".join([base_uri, "insights"])
6465
self._factors_uri = "/".join([base_uri, "factors"])

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ classifiers = [
3434

3535
[project.optional-dependencies]
3636
test = [
37-
"mocket>=3.12.8",
37+
"pytest-httpserver>=1.0.10",
3838
]
3939

4040
[tool.setuptools.package-data]

setup.cfg

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ python =
1515

1616
[testenv:{py38,py39,py310,py311,py312}-test]
1717
deps =
18-
mocket
18+
pytest-httpserver
1919
pytest
2020

2121
commands = pytest tests
@@ -35,6 +35,8 @@ commands = flake8 minfraud
3535
[testenv:py312-mypy]
3636
deps =
3737
mypy
38+
pytest_httpserver
39+
pytest
3840
types-requests
3941
voluptuous-stubs
4042
commands = mypy minfraud tests

tests/test_webservice.py

Lines changed: 50 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,8 @@
33
import os
44
from io import open
55
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+
from pytest_httpserver import HTTPServer
7+
import pytest
108

119
from minfraud.errors import (
1210
HTTPError,
@@ -19,15 +17,25 @@
1917
from minfraud.models import Factors, Insights, Score
2018
from minfraud.webservice import AsyncClient, Client
2119

20+
import minfraud.webservice
2221
import unittest
2322

23+
minfraud.webservice._SCHEME = "http"
24+
2425

2526
class 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

182176
class 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

Comments
 (0)