Skip to content

Commit

Permalink
Merge pull request #18 from Kyria/new_tests
Browse files Browse the repository at this point in the history
Better caching tests + Fix RedisCache
* Fix coverage
* Fix small bug in RedisCache
* Stronger tests for caching (using multiple types: str, int and namedtuple)
* CI is now using travis services (redis and memcached) instead of mocking them (it's CI, not unit testing)
  • Loading branch information
Kyria authored Aug 17, 2017
2 parents e624a7d + eefa49c commit 010de40
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 33 deletions.
4 changes: 4 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
language: python

services:
- memcached
- redis

python:
- "2.7"
- "3.3"
Expand Down
2 changes: 1 addition & 1 deletion esipy/cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ def get(self, key, default=None):
return pickle.loads(value) if value is not None else default

def set(self, key, value, timeout=300):
return self._r.setex(self._hash(key), timeout, pickle.dumps(value))
return self._r.setex(self._hash(key), pickle.dumps(value), timeout)

def invalidate(self, key):
return self._r.delete(self._hash(key))
144 changes: 112 additions & 32 deletions test/test_cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,54 @@
import shutil
import time
import unittest
import redis

from collections import namedtuple

from esipy.cache import BaseCache
from esipy.cache import DictCache
from esipy.cache import DummyCache
from esipy.cache import FileCache
from esipy.cache import MemcachedCache
from esipy.cache import RedisCache

CachedResponse = namedtuple(
'CachedResponse',
['status_code', 'headers', 'content', 'url']
)


class BaseTest(unittest.TestCase):

def __init__(self, *args, **kwargs):
super(BaseTest, self).__init__(*args, **kwargs)

# example of simple data
self.ex_str = ('eve', 'online')
self.ex_int = ('int', 12345)
# tuple of frozenset in key, namedtuple in value
self.ex_cpx = (
(
frozenset([('foo', 'bar'), ('int', 2)]),
frozenset([('header', 'bla')]),
),
CachedResponse(
status_code=200,
headers={'foo', 'bar'},
content='SomeContent'.encode('latin-1'),
url='http://example.com'
)
)

def check_complex(self, cplx):
self.assertTrue(isinstance(cplx, CachedResponse))
self.assertEqual(cplx.status_code, self.ex_cpx[1].status_code)
self.assertEqual(cplx.headers, self.ex_cpx[1].headers)
self.assertEqual(cplx.content, self.ex_cpx[1].content)
self.assertEqual(cplx.url, self.ex_cpx[1].url)


class TestBaseCache(unittest.TestCase):
class TestBaseCache(BaseTest):
""" BaseCache test class """

def setUp(self):
Expand All @@ -32,32 +71,35 @@ def test_base_cache_invalidate(self):
self.assertRaises(NotImplementedError, self.c.invalidate, 'key')


class TestDictCache(unittest.TestCase):
class TestDictCache(BaseTest):
""" DictCache test class """

def setUp(self):
self.c = DictCache()
self.c.set('key', True)
self.c.set(*self.ex_str)
self.c.set(*self.ex_int)
self.c.set(*self.ex_cpx)

def test_dict_cache_set(self):
self.assertEqual(self.c._dict['key'][0], True)
self.assertEqual(self.c._dict[self.ex_str[0]][0], self.ex_str[1])
self.assertEqual(self.c._dict[self.ex_int[0]][0], self.ex_int[1])
self.assertEqual(self.c._dict[self.ex_cpx[0]][0], self.ex_cpx[1])

def test_dict_cache_get(self):
self.assertEqual(self.c.get('key'), True)
self.check_complex(self.c.get(self.ex_cpx[0]))

def test_dict_cache_invalidate(self):
self.c.invalidate('key')
self.assertIsNone(self.c.get('key'))
self.c.invalidate(self.ex_cpx[0])
self.assertIsNone(self.c.get(self.ex_cpx[0]))

def test_dict_cache_expiry(self):
self.assertEqual(self.c._dict['key'][0], True)
self.assertEqual(self.c.get('key'), True)
self.c._dict['key'] = (True, time.time() - 1)
self.assertIsNone(self.c.get('key'))
self.assertNotIn('key', self.c._dict)
self.check_complex(self.c.get(self.ex_cpx[0]))
self.c._dict[self.ex_cpx[0]] = (self.ex_cpx[1], time.time() - 1)
self.assertIsNone(self.c.get(self.ex_cpx[0]))
self.assertNotIn(self.ex_cpx[0], self.c._dict)


class TestDummyCache(unittest.TestCase):
class TestDummyCache(BaseTest):
""" DummyCache test class. """

def setUp(self):
Expand All @@ -75,7 +117,7 @@ def test_dummy_cache_invalidate(self):
self.assertIsNone(self.c.get('never_stored'))


class TestFileCache(unittest.TestCase):
class TestFileCache(BaseTest):
""" Class for testing the filecache """

def setUp(self):
Expand All @@ -86,13 +128,13 @@ def tearDown(self):
del self.c
shutil.rmtree('tmp', ignore_errors=True)

def test_file_cache_set(self):
self.c.set('key', 'bar')
self.assertEqual(self.c.get('key'), 'bar')

def test_file_cache_get(self):
self.c.set('key', 'bar')
self.assertEqual(self.c.get('key'), 'bar')
def test_file_cache_get_set(self):
self.c.set(*self.ex_str)
self.c.set(*self.ex_int)
self.c.set(*self.ex_cpx)
self.assertEqual(self.c.get(self.ex_str[0]), self.ex_str[1])
self.assertEqual(self.c.get(self.ex_int[0]), self.ex_int[1])
self.check_complex(self.c.get(self.ex_cpx[0]))

self.c.set('expired', 'baz', -1)
self.assertEqual(
Expand All @@ -108,25 +150,63 @@ def test_file_cache_invalidate(self):
self.assertEqual(self.c.get('key'), None)


class TestMemcachedCache(unittest.TestCase):
"""A very basic MemcachedCache TestCase
Primairy goal of this unittest is to get the coverage up
to spec. Should probably make use of `mockcache` in the future"""
class TestMemcachedCache(BaseTest):
""" Memcached tests """

def setUp(self):
memcached = memcache.Client(['127.0.0.1:11211'], debug=0)
memcached.get = mock.MagicMock(return_value='value')
memcached = memcache.Client(['localhost:11211'], debug=0)
self.c = MemcachedCache(memcached)

def test_memcached_set(self):
self.c.set('key', 'value')
def tearDown(self):
self.c._mc.disconnect_all()

def test_memcached_get_set(self):
self.c.set(*self.ex_str)
self.c.set(*self.ex_int)
self.c.set(*self.ex_cpx)
self.assertEqual(self.c.get(self.ex_str[0]), self.ex_str[1])
self.assertEqual(self.c.get(self.ex_int[0]), self.ex_int[1])
self.check_complex(self.c.get(self.ex_cpx[0]))

def test_memcached_get(self):
self.assertEqual(self.c.get('key'), 'value')
self.c.set('expired', 'baz', -1)
self.assertEqual(self.c.get('expired'), None)

def test_memcached_invalidate(self):
self.c.invalidate('key')
self.c.set(*self.ex_str)
self.assertEqual(self.c.get(self.ex_str[0]), self.ex_str[1])
self.c.invalidate(self.ex_str[0])
self.assertEqual(self.c.get(self.ex_str[0]), None)

def test_memcached_invalid_argument(self):
with self.assertRaises(TypeError):
MemcachedCache(None)


class TestRedisCache(BaseTest):
"""RedisCache tests"""

def setUp(self):
redis_client = redis.Redis(host='localhost', port=6379, db=0)
self.c = RedisCache(redis_client)

def test_redis_get_set(self):
self.c.set(*self.ex_str)
self.c.set(*self.ex_int)
self.c.set(*self.ex_cpx)
self.assertEqual(self.c.get(self.ex_str[0]), self.ex_str[1])
self.assertEqual(self.c.get(self.ex_int[0]), self.ex_int[1])
self.check_complex(self.c.get(self.ex_cpx[0]))

self.c.set('expired', 'baz', 1)
time.sleep(2)
self.assertEqual(self.c.get('expired'), None)

def test_redis_invalidate(self):
self.c.set(*self.ex_str)
self.assertEqual(self.c.get(self.ex_str[0]), self.ex_str[1])
self.c.invalidate(self.ex_str[0])
self.assertEqual(self.c.get(self.ex_str[0]), None)

def test_redis_invalid_argument(self):
with self.assertRaises(TypeError):
RedisCache(None)

0 comments on commit 010de40

Please sign in to comment.