Permalink
Browse files

Memcache driver

  • Loading branch information...
1 parent a453c51 commit edbe109820bfce674f72834df4c2e051880100b3 @diogobaeder committed Oct 28, 2011
Showing with 171 additions and 51 deletions.
  1. +57 −23 pycket/driver.py
  2. +97 −11 tests/test_driver.py
  3. +8 −8 tests/test_notification.py
  4. +9 −9 tests/test_session.py
View
@@ -2,54 +2,88 @@
import pickle
-class RedisDriver(object):
+class Driver(object):
+ def _to_dict(self, raw_session):
+ if raw_session is None:
+ return {}
+ else:
+ return pickle.loads(raw_session)
+
+ def _setup_client(self):
+ if self.client is None:
+ self._create_client()
+
+ def get(self, session_id):
+ self._setup_client()
+ raw_session = self.client.get(session_id)
+
+ return self._to_dict(raw_session)
+
+ def set(self, session_id, session):
+ pickled_session = pickle.dumps(session)
+ self._setup_client()
+
+ self._set_and_expire(session_id, pickled_session)
+
+
+class RedisDriver(Driver):
EXPIRE_SECONDS = 24 * 60 * 60
DEFAULT_STORAGE_IDENTIFIERS = {
'db_sessions': 0,
'db_notifications': 1,
}
- dataset = None
+ client = None
def __init__(self, settings):
self.settings = settings
- def set(self, session_id, session):
- pickled_session = pickle.dumps(session)
- self.__setup_dataset()
- self.dataset.set(session_id, pickled_session)
- self.dataset.expire(session_id, self.EXPIRE_SECONDS)
+ def _set_and_expire(self, session_id, pickled_session):
+ self.client.set(session_id, pickled_session)
+ self.client.expire(session_id, self.EXPIRE_SECONDS)
- def get(self, session_id):
- self.__setup_dataset()
- raw_session = self.dataset.get(session_id)
+ def _create_client(self):
+ import redis
+ self.client = redis.Redis(**self.settings)
- return self.__to_dict(raw_session)
- def __to_dict(self, raw_session):
- if raw_session is None:
- return {}
- else:
- return pickle.loads(raw_session)
+class MemcachedDriver(Driver):
+ EXPIRE_SECONDS = 24 * 60 * 60
+
+ client = None
- def __setup_dataset(self):
- if self.dataset is None:
- import redis
- self.dataset = redis.Redis(**self.settings)
+ def __init__(self, settings):
+ self.settings = settings
+
+ def _set_and_expire(self, session_id, pickled_session):
+ self.client.set(session_id, pickled_session, self.EXPIRE_SECONDS)
+
+ def _create_client(self):
+ import memcache
+ settings = copy(self.settings)
+ default_servers = ('localhost:11211',)
+ servers = settings.pop('servers', default_servers)
+ self.client = memcache.Client(servers, **settings)
class DriverFactory(object):
STORAGE_CATEGORIES = ('db_sessions', 'db_notifications')
def create(self, name, storage_settings, storage_category):
- return self.__create_redis(storage_settings, storage_category)
+ method = getattr(self, '_create_%s' % name, None)
+ if method is None:
+ raise ValueError('Engine "%s" is not supported' % name)
+ return method(storage_settings, storage_category)
- def __create_redis(self, storage_settings, storage_category):
+ def _create_redis(self, storage_settings, storage_category):
storage_settings = copy(storage_settings)
default_storage_identifier = RedisDriver.DEFAULT_STORAGE_IDENTIFIERS[storage_category]
storage_settings['db'] = storage_settings.get(storage_category, default_storage_identifier)
for storage_category in self.STORAGE_CATEGORIES:
if storage_category in storage_settings.keys():
del storage_settings[storage_category]
- return RedisDriver(storage_settings)
+ return RedisDriver(storage_settings)
+
+ def _create_memcached(self, storage_settings, storage_category):
+ return MemcachedDriver(storage_settings)
View
@@ -4,16 +4,16 @@
from nose.tools import istest, raises
import redis
-from pycket.driver import DriverFactory, RedisDriver
+from pycket.driver import DriverFactory, MemcachedDriver, RedisDriver
class RedisTestCase(TestCase):
- dataset = None
+ client = None
def setUp(self):
- if self.dataset is None:
- self.dataset = redis.Redis(db=0)
- self.dataset.flushall()
+ if self.client is None:
+ self.client = redis.Redis(db=0)
+ self.client.flushall()
class RedisDriverTest(RedisTestCase):
@@ -25,7 +25,7 @@ def inserts_pickable_object_into_session(self):
driver.set('session-id', foo)
- result = self.dataset.get('session-id')
+ result = self.client.get('session-id')
self.assertEqual(pickle.loads(result), foo)
@@ -35,14 +35,14 @@ def retrieves_a_pickled_object_from_session(self):
foo = dict(foo='bar')
- self.dataset.set('session-id', pickle.dumps(foo))
+ self.client.set('session-id', pickle.dumps(foo))
result = driver.get('session-id')
self.assertEqual(result, foo)
@istest
- def makes_session_expire_in_one_day_in_the_dataset(self):
+ def makes_session_expire_in_one_day_in_the_client(self):
driver = RedisDriver(dict(db=0))
foo = dict(foo='bar')
@@ -56,11 +56,78 @@ def set(self, session_id, pickled_session):
def expire(self, session_id, expiration):
test_case.assertEqual(expiration, RedisDriver.EXPIRE_SECONDS)
- driver.dataset = StubClient()
+ driver.client = StubClient()
driver.set('session-id', foo)
+class MemcachedTestCase(TestCase):
+ client = None
+
+ def setUp(self):
+ if self.client is None:
+ import memcache
+ self.client = memcache.Client(servers=('localhost:11211',))
+ self.client.flush_all()
+
+
+class MemcachedDriverTest(MemcachedTestCase):
+ @istest
+ def inserts_pickable_object_into_session(self):
+ driver = MemcachedDriver({
+ 'servers': ('localhost:11211',)
+ })
+
+ foo = dict(foo='bar')
+
+ driver.set('session-id', foo)
+
+ result = self.client.get('session-id')
+
+ self.assertEqual(pickle.loads(result), foo)
+
+ @istest
+ def retrieves_a_pickled_object_from_session(self):
+ driver = MemcachedDriver({
+ 'servers': ('localhost:11211',)
+ })
+
+ foo = dict(foo='bar')
+
+ self.client.set('session-id', pickle.dumps(foo))
+
+ result = driver.get('session-id')
+
+ self.assertEqual(result, foo)
+
+ @istest
+ def makes_session_expire_in_one_day_in_the_client(self):
+ driver = MemcachedDriver({
+ 'servers': ('localhost:11211',)
+ })
+
+ foo = dict(foo='bar')
+
+ test_case = self
+
+ class StubClient(object):
+ def set(self, session_id, pickled_session, expiration):
+ test_case.assertEqual(expiration, MemcachedDriver.EXPIRE_SECONDS)
+
+ driver.client = StubClient()
+
+ driver.set('session-id', foo)
+
+ @istest
+ @raises(OverflowError)
+ def fails_to_load_if_storage_settings_contain_wrong_host(self):
+ driver = MemcachedDriver({
+ 'servers': ('255.255.255.255:99999',)
+ })
+
+ driver.set('session-id', 'foo')
+
+
class DriverFactoryTest(TestCase):
@istest
def creates_instance_for_redis_session(self):
@@ -70,6 +137,25 @@ def creates_instance_for_redis_session(self):
self.assertIsInstance(instance, RedisDriver)
- instance.get('dataset-is-lazy-loaded')
+ instance.get('client-is-lazy-loaded')
+
+ self.assertEqual(instance.client.connection_pool._available_connections[0].db, 0)
+
+ @istest
+ def creates_instance_for_memcached_session(self):
+ factory = DriverFactory()
+
+ instance = factory.create('memcached', storage_settings={}, storage_category='db_sessions')
+
+ self.assertIsInstance(instance, MemcachedDriver)
+
+ instance.get('client-is-lazy-loaded')
+
+ self.assertIsNotNone(instance.client.get_stats())
+
+ @istest
+ @raises(ValueError)
+ def cannot_create_a_driver_for_not_supported_engine(self):
+ factory = DriverFactory()
- self.assertEqual(instance.dataset.connection_pool._available_connections[0].db, 0)
+ instance = factory.create('cassete-tape', storage_settings={}, storage_category='db_sessions')
View
@@ -11,12 +11,12 @@
class RedisTestCase(TestCase):
- dataset = None
+ client = None
def setUp(self):
- if self.dataset is None:
- self.dataset = redis.Redis(db=RedisDriver.DEFAULT_STORAGE_IDENTIFIERS['db_notifications'])
- self.dataset.flushall()
+ if self.client is None:
+ self.client = redis.Redis(db=RedisDriver.DEFAULT_STORAGE_IDENTIFIERS['db_notifications'])
+ self.client.flushall()
class NotificationMixinTest(TestCase):
@@ -54,20 +54,20 @@ def removes_notification_from_database_after_retrieval(self):
manager.set('foo', 'bar')
- raw_notifications = self.dataset.get(handler.session_id)
+ raw_notifications = self.client.get(handler.session_id)
notifications = pickle.loads(raw_notifications)
self.assertEqual(notifications.keys(), ['foo'])
manager.get('foo')
- raw_notifications = self.dataset.get(handler.session_id)
+ raw_notifications = self.client.get(handler.session_id)
notifications = pickle.loads(raw_notifications)
self.assertEqual(notifications.keys(), [])
@istest
- def gets_default_value_if_provided_and_not_in_dataset(self):
+ def gets_default_value_if_provided_and_not_in_client(self):
handler = StubHandler()
manager = NotificationManager(handler)
@@ -125,7 +125,7 @@ def uses_custom_notifications_database_if_provided(self):
}
manager = NotificationManager(handler)
manager.set('foo', 'bar')
- self.assertEqual(manager.driver.dataset.connection_pool._available_connections[0].db, 11)
+ self.assertEqual(manager.driver.client.connection_pool._available_connections[0].db, 11)
class StubHandler(object):
View
@@ -46,12 +46,12 @@ class StubHandler(SessionMixin):
class RedisTestCase(TestCase):
- dataset = None
+ client = None
def setUp(self):
- if self.dataset is None:
- self.dataset = redis.Redis(db=RedisDriver.DEFAULT_STORAGE_IDENTIFIERS['db_sessions'])
- self.dataset.flushall()
+ if self.client is None:
+ self.client = redis.Redis(db=RedisDriver.DEFAULT_STORAGE_IDENTIFIERS['db_sessions'])
+ self.client.flushall()
class SessionManagerTest(RedisTestCase):
@@ -110,7 +110,7 @@ def saves_session_object_on_redis_with_same_session_id_as_cookie(self):
manager.set('some-object', {'foo': 'bar'})
- raw_session = self.dataset.get(handler.session_id)
+ raw_session = self.client.get(handler.session_id)
session = pickle.loads(raw_session)
self.assertEqual(session['some-object']['foo'], 'bar')
@@ -151,7 +151,7 @@ def deletes_objects_from_session(self):
manager.set('some-object2', {'foo2': 'bar2'})
manager.delete('some-object')
- raw_session = self.dataset.get(handler.session_id)
+ raw_session = self.client.get(handler.session_id)
session = pickle.loads(raw_session)
self.assertEqual(session.keys(), ['some-object2'])
@@ -217,7 +217,7 @@ def sets_object_with_dict_key(self):
self.assertEqual(manager['foo'], 'bar')
@istest
- def gets_default_value_if_provided_and_not_in_dataset(self):
+ def gets_default_value_if_provided_and_not_in_client(self):
handler = StubHandler()
manager = SessionManager(handler)
@@ -329,7 +329,7 @@ def uses_custom_sessions_database_if_provided(self):
}
manager = SessionManager(handler)
manager.set('foo', 'bar')
- self.assertEqual(manager.driver.dataset.connection_pool._available_connections[0].db, 10)
+ self.assertEqual(manager.driver.client.connection_pool._available_connections[0].db, 10)
@istest
def deletes_multiple_session_objects_at_once(self):
@@ -340,7 +340,7 @@ def deletes_multiple_session_objects_at_once(self):
manager.set('some-object2', {'foo2': 'bar2'})
manager.delete('some-object', 'some-object2')
- raw_session = self.dataset.get(handler.session_id)
+ raw_session = self.client.get(handler.session_id)
session = pickle.loads(raw_session)
self.assertEqual(session.keys(), [])

0 comments on commit edbe109

Please sign in to comment.