Skip to content

Commit adefc72

Browse files
authored
Mocket raises exceptions (#126)
* Mocket raises exceptions. * Fix for Python 2. * Documentation and bump version.
1 parent e723252 commit adefc72

File tree

10 files changed

+248
-179
lines changed

10 files changed

+248
-179
lines changed

.gitignore

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@
77
.*.sw[po]
88
dist/
99
*.egg-info
10-
*.egg
11-
*.egg/
10+
*.egg*
1211
doc/__build/*
1312
docs/_build/
1413
build/

README.rst

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,20 @@ Let's fire our example test::
143143

144144
$ py.test example.py
145145

146+
Example of how to fake a socket errors
147+
======================================
148+
149+
It's very important that we test non-happy paths.
150+
151+
.. code-block:: python
152+
153+
@mocketize
154+
def test_raise_exception(self):
155+
url = "http://github.com/fluidicon.png"
156+
Entry.single_register(Entry.GET, url, exception=socket.error())
157+
with self.assertRaises(requests.exceptions.ConnectionError):
158+
requests.get(url)
159+
146160
Example of how to record real socket traffic
147161
============================================
148162

mocket/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@
77

88
__all__ = ("mocketize", "Mocket", "MocketEntry", "Mocketizer")
99

10-
__version__ = "3.9.1"
10+
__version__ = "3.9.2"

mocket/mocket.py

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -472,7 +472,6 @@ def enable(namespace=None, truesocket_recording_dir=None):
472472
(2, 1, 6, "", (host, port))
473473
]
474474
ssl.wrap_socket = ssl.__dict__["wrap_socket"] = FakeSSLContext.wrap_socket
475-
# ssl.SSLSocket = ssl.__dict__["SSLSocket"] = MocketSocket
476475
ssl.SSLContext = ssl.__dict__["SSLContext"] = FakeSSLContext
477476
socket.inet_pton = socket.__dict__["inet_pton"] = lambda family, ip: byte_type(
478477
"\x7f\x00\x00\x01", "utf-8"
@@ -502,7 +501,6 @@ def disable():
502501
socket.gethostbyname = socket.__dict__["gethostbyname"] = true_gethostbyname
503502
socket.getaddrinfo = socket.__dict__["getaddrinfo"] = true_getaddrinfo
504503
ssl.wrap_socket = ssl.__dict__["wrap_socket"] = true_ssl_wrap_socket
505-
# ssl.SSLSocket = ssl.__dict__["SSLSocket"] = true_ssl_socket
506504
ssl.SSLContext = ssl.__dict__["SSLContext"] = true_ssl_context
507505
socket.inet_pton = socket.__dict__["inet_pton"] = true_inet_pton
508506
urllib3.util.ssl_.wrap_socket = urllib3.util.ssl_.__dict__[
@@ -548,7 +546,9 @@ def __init__(self, location, responses):
548546

549547
lresponses = []
550548
for r in responses:
551-
if not getattr(r, "data", False):
549+
if isinstance(r, BaseException):
550+
pass
551+
elif not getattr(r, "data", False):
552552
if isinstance(r, text_type):
553553
r = encode_to_bytes(r)
554554
r = self.response_cls(r)
@@ -569,6 +569,10 @@ def get_response(self):
569569
response = self.responses[self.response_index]
570570
if self.response_index < len(self.responses) - 1:
571571
self.response_index += 1
572+
573+
if isinstance(response, BaseException):
574+
raise response
575+
572576
return response.data
573577

574578

@@ -600,9 +604,15 @@ def check_and_call(self, method):
600604
def wrap(test=None, truesocket_recording_dir=None):
601605
def wrapper(t, *args, **kw):
602606
instance = args[0] if args else None
603-
namespace = ".".join(
604-
(instance.__class__.__module__, instance.__class__.__name__, t.__name__)
605-
)
607+
namespace = None
608+
if truesocket_recording_dir:
609+
namespace = ".".join(
610+
(
611+
instance.__class__.__module__,
612+
instance.__class__.__name__,
613+
t.__name__,
614+
)
615+
)
606616
with Mocketizer(
607617
instance,
608618
namespace=namespace,

mocket/mockhttp.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -231,11 +231,22 @@ def register(cls, method, uri, *responses, **config):
231231

232232
@classmethod
233233
def single_register(
234-
cls, method, uri, body="", status=200, headers=None, match_querystring=True
234+
cls,
235+
method,
236+
uri,
237+
body="",
238+
status=200,
239+
headers=None,
240+
match_querystring=True,
241+
exception=None,
235242
):
243+
244+
response = (
245+
exception
246+
if exception
247+
else cls.response_cls(body=body, status=status, headers=headers)
248+
)
249+
236250
cls.register(
237-
method,
238-
uri,
239-
cls.response_cls(body=body, status=status, headers=headers),
240-
match_querystring=match_querystring,
251+
method, uri, response, match_querystring=match_querystring,
241252
)

mocket/mockredis.py

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22

33
from itertools import chain
44

5-
from .compat import (byte_type, decode_from_bytes, encode_to_bytes, shsplit,
6-
text_type)
5+
from .compat import byte_type, decode_from_bytes, encode_to_bytes, shsplit, text_type
76
from .mocket import Mocket, MocketEntry
87

98

@@ -21,38 +20,45 @@ class Redisizer(byte_type):
2120
@staticmethod
2221
def tokens(iterable):
2322
iterable = [encode_to_bytes(x) for x in iterable]
24-
return [
25-
'*{0}'.format(len(iterable)).encode('utf-8')
26-
] + list(
27-
chain(*zip(['${0}'.format(len(x)).encode('utf-8') for x in iterable], iterable))
23+
return ["*{0}".format(len(iterable)).encode("utf-8")] + list(
24+
chain(
25+
*zip(
26+
["${0}".format(len(x)).encode("utf-8") for x in iterable], iterable
27+
)
28+
)
2829
)
2930

3031
@staticmethod
3132
def redisize(data):
3233
def get_conversion(t):
3334
return {
34-
dict: lambda x: b'\r\n'.join(Redisizer.tokens(list(chain(*tuple(x.items()))))),
35-
int: lambda x: ':{0}'.format(x).encode('utf-8'),
36-
text_type: lambda x: '${0}\r\n{1}'.format(len(x.encode('utf-8')), x).encode('utf-8'),
37-
list: lambda x: b'\r\n'.join(Redisizer.tokens(x)),
35+
dict: lambda x: b"\r\n".join(
36+
Redisizer.tokens(list(chain(*tuple(x.items()))))
37+
),
38+
int: lambda x: ":{0}".format(x).encode("utf-8"),
39+
text_type: lambda x: "${0}\r\n{1}".format(
40+
len(x.encode("utf-8")), x
41+
).encode("utf-8"),
42+
list: lambda x: b"\r\n".join(Redisizer.tokens(x)),
3843
}[t]
44+
3945
if isinstance(data, Redisizer):
4046
return data
4147
if isinstance(data, byte_type):
4248
data = decode_from_bytes(data)
43-
return Redisizer(get_conversion(data.__class__)(data) + b'\r\n')
49+
return Redisizer(get_conversion(data.__class__)(data) + b"\r\n")
4450

4551
@staticmethod
46-
def command(description, _type='+'):
47-
return Redisizer('{0}{1}{2}'.format(_type, description, '\r\n').encode('utf-8'))
52+
def command(description, _type="+"):
53+
return Redisizer("{0}{1}{2}".format(_type, description, "\r\n").encode("utf-8"))
4854

4955
@staticmethod
5056
def error(description):
51-
return Redisizer.command(description, _type='-')
57+
return Redisizer.command(description, _type="-")
5258

5359

54-
OK = Redisizer.command('OK')
55-
QUEUED = Redisizer.command('QUEUED')
60+
OK = Redisizer.command("OK")
61+
QUEUED = Redisizer.command("QUEUED")
5662
ERROR = Redisizer.error
5763

5864

@@ -61,7 +67,7 @@ class Entry(MocketEntry):
6167
response_cls = Response
6268

6369
def __init__(self, addr, command, responses):
64-
super(Entry, self).__init__(addr or ('localhost', 6379), responses)
70+
super(Entry, self).__init__(addr or ("localhost", 6379), responses)
6571
d = shsplit(command)
6672
d[0] = d[0].upper()
6773
self.command = Redisizer.tokens(d)
@@ -71,7 +77,10 @@ def can_handle(self, data):
7177

7278
@classmethod
7379
def register(cls, addr, command, *responses):
74-
responses = [cls.response_cls(r) for r in responses]
80+
responses = [
81+
r if isinstance(r, BaseException) else cls.response_cls(r)
82+
for r in responses
83+
]
7584
Mocket.register(cls(addr, command, responses))
7685

7786
@classmethod

tests/main/test_http.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,13 @@ def test_post_file_object(self):
323323
r = requests.post(url, files=files, data={}, verify=False)
324324
self.assertEqual(r.status_code, 201)
325325

326+
@mocketize
327+
def test_raise_exception(self):
328+
url = "http://github.com/fluidicon.png"
329+
Entry.single_register(Entry.GET, url, exception=socket.error())
330+
with self.assertRaises(requests.exceptions.ConnectionError):
331+
requests.get(url)
332+
326333
@mocketize
327334
def test_sockets(self):
328335
"""
@@ -355,5 +362,4 @@ def test_sockets(self):
355362
sock.close()
356363

357364
# Proof that worked.
358-
print(Mocket.last_request().__dict__)
359-
assert Mocket.last_request().body == '{"hello": "world"}'
365+
self.assertEqual(Mocket.last_request().body, '{"hello": "world"}')

tests/main/test_https.py

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@
55

66
import pytest
77
import requests
8-
from tests import urlopen
98

10-
from mocket import Mocket, mocketize, Mocketizer
9+
from mocket import Mocket, Mocketizer, mocketize
1110
from mocket.mockhttp import Entry
11+
from tests import urlopen
1212

1313

1414
@pytest.fixture
@@ -22,18 +22,19 @@ def response():
2222

2323
@mocketize
2424
def test_json(response):
25-
url_to_mock = 'https://testme.org/json'
25+
url_to_mock = "https://testme.org/json"
2626

2727
Entry.single_register(
2828
Entry.GET,
2929
url_to_mock,
3030
body=json.dumps(response),
31-
headers={'content-type': 'application/json'})
31+
headers={"content-type": "application/json"},
32+
)
3233

3334
mocked_response = requests.get(url_to_mock).json()
3435
assert response == mocked_response
3536

36-
mocked_response = json.loads(urlopen(url_to_mock).read().decode('utf-8'))
37+
mocked_response = json.loads(urlopen(url_to_mock).read().decode("utf-8"))
3738
assert response == mocked_response
3839

3940

@@ -43,29 +44,27 @@ def test_json(response):
4344
@pytest.mark.skipif('os.getenv("SKIP_TRUE_HTTP", False)')
4445
@mocketize(truesocket_recording_dir=recording_directory)
4546
def test_truesendall_with_recording_https():
46-
url = 'https://httpbin.org/ip'
47+
url = "https://httpbin.org/ip"
4748

4849
requests.get(url, headers={"Accept": "application/json"})
4950
resp = requests.get(url, headers={"Accept": "application/json"})
50-
print(resp.content)
5151
assert resp.status_code == 200
5252

5353
dump_filename = os.path.join(
54-
Mocket.get_truesocket_recording_dir(),
55-
Mocket.get_namespace() + '.json',
54+
Mocket.get_truesocket_recording_dir(), Mocket.get_namespace() + ".json",
5655
)
5756
with io.open(dump_filename) as f:
5857
responses = json.load(f)
5958

60-
assert len(responses['httpbin.org']['443'].keys()) == 1
59+
assert len(responses["httpbin.org"]["443"].keys()) == 1
6160

6261

6362
@pytest.mark.skipif('os.getenv("SKIP_TRUE_HTTP", False)')
6463
def test_truesendall_after_mocket_session():
6564
Mocket.enable()
6665
Mocket.disable()
6766

68-
url = 'https://httpbin.org/ip'
67+
url = "https://httpbin.org/ip"
6968
resp = requests.get(url)
7069
assert resp.status_code == 200
7170

@@ -74,8 +73,8 @@ def test_truesendall_after_mocket_session():
7473
def test_real_request_session():
7574
session = requests.Session()
7675

77-
url1 = 'https://httpbin.org/ip'
78-
url2 = 'http://httpbin.org/headers'
76+
url1 = "https://httpbin.org/ip"
77+
url2 = "http://httpbin.org/headers"
7978

8079
with Mocketizer():
8180
assert len(session.get(url1).content) < len(session.get(url2).content)

0 commit comments

Comments
 (0)