Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mock connection error #197

Merged
merged 25 commits into from
Jul 27, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
bb70bcd
Started implementing connection error throws
Amertz08 Jan 10, 2018
6aea29c
updated test cases
Amertz08 Jan 10, 2018
5359bdf
Updated ConnectionError test cases
Amertz08 Jan 10, 2018
f940176
Updated test case to actually fail when decorator does not exist inst…
Amertz08 Jan 10, 2018
17a98dd
Merge branch 'master' into 102-mock-connection-error
Amertz08 Jul 7, 2018
ffb6205
Added venv to ignore file
Amertz08 Jul 7, 2018
4263daa
Added missing check_conn so tests work
Amertz08 Jul 7, 2018
2164cb6
Updated tests and added check decorator as needed
Amertz08 Jul 7, 2018
cbaba98
finished remaining tests
Amertz08 Jul 7, 2018
ef97612
flake8
Amertz08 Jul 7, 2018
269fc1c
Fixed issue with decorator not playing well with _lua_reply
Amertz08 Jul 7, 2018
49db0a3
Modified _patch_responses to take the decorator as a parameter
Amertz08 Jul 10, 2018
5dccd2a
Made connection check decorator private function. Adjusted for use th…
Amertz08 Jul 10, 2018
c1a80b3
Removed decorator from methods
Amertz08 Jul 10, 2018
fa63151
Adjusted patch_responses call for FakePubSub class
Amertz08 Jul 10, 2018
0fa4e3c
Adjusted test cases for access to connected attribute
Amertz08 Jul 10, 2018
ed56f4a
Connection error decorator should be patched to response regardless o…
Amertz08 Jul 11, 2018
dc3e59e
ConnectionError message
Amertz08 Jul 11, 2018
bfe919b
Updated README with documentation on mocking connection errors
Amertz08 Jul 11, 2018
03615de
Proper indentation in README
Amertz08 Jul 11, 2018
71e89ba
_check_conn should be patched on before decode_responses
Amertz08 Jul 11, 2018
8412e25
Spacing fix on documentation
Amertz08 Jul 11, 2018
6f301b3
Patched connection error decorator to PubSub class. Added test cases
Amertz08 Jul 26, 2018
75dced3
Connected arg after decode arg in FakePubSub
Amertz08 Jul 27, 2018
28cae30
Renamed test attribute redis to pubsub
Amertz08 Jul 27, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ dump.rdb
extras/*
.tox
*.pyc
.idea
venv/
18 changes: 18 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,24 @@ test you run, be sure to call `r.flushall()` in your
Alternatively, you can create an instance that does not share data with other
instances, by passing `singleton=False` to the constructor.

It is also possible to mock connection errors so you can effectively test
your error handling. Simply pass `connected=False` to the constructor or
set the connected attribute to `False` after initialization.

.. code-block:: python

>>> import fakeredis
>>> r = fakeredis.FakeStrictRedis(connected=False)
>>> r.set('foo', 'bar')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "~/fakeredis/fakeredis.py", line 339, in func_wrapper
raise redis.ConnectionError("FakeRedis is emulating a connection error.")
redis.exceptions.ConnectionError: FakeRedis is emulating a connection error.
>>> r.connected = True
>>> r.set('foo', 'bar')
True

Fakeredis implements the same interface as `redis-py`_, the
popular redis client for python, and models the responses
of redis 2.6.
Expand Down
27 changes: 21 additions & 6 deletions fakeredis.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,12 +221,12 @@ def decode_response(*args, **kwargs):
return decode_response


def _patch_responses(obj):
def _patch_responses(obj, decorator):
for attr_name in dir(obj):
attr = getattr(obj, attr_name)
if not callable(attr) or attr_name.startswith('_'):
continue
func = _make_decode_func(attr)
func = decorator(attr)
setattr(obj, attr_name, func)


Expand Down Expand Up @@ -331,6 +331,16 @@ def release(self):
self.redis.delete(self.name)


def _check_conn(func):
"""Used to mock connection errors"""
@functools.wraps(func)
def func_wrapper(*args, **kwargs):
if not func.__self__.connected:
raise redis.ConnectionError("FakeRedis is emulating a connection error.")
return func(*args, **kwargs)
return func_wrapper


class FakeStrictRedis(object):
@classmethod
def from_url(cls, url, db=None, **kwargs):
Expand All @@ -343,7 +353,7 @@ def from_url(cls, url, db=None, **kwargs):
return cls(db=db, **kwargs)

def __init__(self, db=0, charset='utf-8', errors='strict',
decode_responses=False, singleton=True, **kwargs):
decode_responses=False, singleton=True, connected=True, **kwargs):
if singleton:
self._dbs = DATABASES
else:
Expand All @@ -356,8 +366,11 @@ def __init__(self, db=0, charset='utf-8', errors='strict',
self._encoding_errors = errors
self._pubsubs = []
self._decode_responses = decode_responses
self.connected = connected
_patch_responses(self, _check_conn)

if decode_responses:
_patch_responses(self)
_patch_responses(self, _make_decode_func)

@_lua_reply(_lua_bool_ok)
def flushdb(self):
Expand Down Expand Up @@ -2218,13 +2231,15 @@ class FakePubSub(object):
PATTERN_MESSAGE_TYPES = ['psubscribe', 'punsubscribe']
LISTEN_DELAY = 0.1 # delay between listen loops (seconds)

def __init__(self, decode_responses=False, *args, **kwargs):
def __init__(self, decode_responses=False, connected=True, *args, **kwargs):
self.channels = {}
self.patterns = {}
self._q = Queue()
self.subscribed = False
self.connected = connected
_patch_responses(self, _check_conn)
if decode_responses:
_patch_responses(self)
_patch_responses(self, _make_decode_func)
self._decode_responses = decode_responses
self.ignore_subscribe_messages = kwargs.get(
'ignore_subscribe_messages', False)
Expand Down
Loading