class RedisStoreTestCase(TestCase): def setUp(self): server = FakeServer() server.connected = True self.store = RedisStore(prefix='prefix:', redis_class=FakeStrictRedis, server=server) self.redis = FakeStrictRedis(server=server) super(RedisStoreTestCase, self).setUp() def tearDown(self): flexmock_teardown() self.redis.flushdb() def test_get_returns_null_when_not_found(self): self.assertIsNone(self.store.get('foo')) def test_redis_value_is_returned(self): self.redis.set('prefix:foo', self.store.serialize('bar')) self.assertEqual('bar', self.store.get('foo')) def test_redis_value_is_returned_for_numerics(self): self.redis.set('prefix:foo', self.store.serialize(1)) self.assertEqual(1, self.store.get('foo')) def test_put_value_into_redis(self): self.store.put('foo', 'bar', 60) self.assertEqual(self.store.serialize('bar'), self.redis.get('prefix:foo')) self.assertEqual( 60., round(math.ceil(float(self.redis.ttl('prefix:foo')) / 60))) def test_put_numeric_value_into_redis(self): self.store.put('foo', 1, 60) self.assertEqual(self.store.serialize(1), self.redis.get('prefix:foo')) self.assertEqual( 60., round(math.ceil(float(self.redis.ttl('prefix:foo')) / 60))) def test_increment(self): self.redis.set('prefix:foo', 1) self.store.increment('foo', 2) self.assertEqual(3, int(self.redis.get('prefix:foo'))) def test_decrement(self): self.redis.set('prefix:foo', 3) self.store.decrement('foo', 2) self.assertEqual(1, int(self.redis.get('prefix:foo'))) def test_forever(self): self.store.forever('foo', 'bar') self.assertEqual(self.store.serialize('bar'), self.redis.get('prefix:foo')) assert self.redis.ttl('prefix:foo') == -1 def test_forget(self): self.redis.set('prefix:foo', 'bar') self.store.forget('foo') self.assertFalse(self.redis.exists('prefix:foo'))
class CacheRedis(object): redis = None def __init__(self, env, host: str, port: int = 6379, db: int = 0): if env.config.get(ConfigKeys.TESTING, False) or host == 'mock': from fakeredis import FakeStrictRedis as Redis else: from redis import Redis self.redis = Redis(host=host, port=port, db=db) self.cache = MemoryCache() def _flushall(self): self.redis.flushdb() self.cache.flushall() def _set(self, key, val, ttl=None): if ttl is None: self.cache.set(key, val) else: self.cache.set(key, val, ttl=ttl) def _get(self, key): return self.cache.get(key) def _del(self, key): self.cache.delete(key) def set_is_room_ephemeral(self, room_id: str, is_ephemeral: bool) -> None: redis_key = RedisKeys.non_ephemeral_rooms() cache_key = '%s-%s' % (redis_key, room_id) self.cache.set(cache_key, is_ephemeral) def is_room_ephemeral(self, room_id: str) -> bool: redis_key = RedisKeys.non_ephemeral_rooms() cache_key = '%s-%s' % (redis_key, room_id) return self.cache.get(cache_key) def get_black_list(self) -> set: cache_key = RedisKeys.black_list() value = self.cache.get(cache_key) if value is not None: return value values = self.redis.smembers(cache_key) if value is not None: decoded = {str(v, 'utf-8') for v in values} self.cache.set(cache_key, decoded, ttl=60 * 10) return decoded return None def set_black_list(self, the_list: set) -> None: cache_key = RedisKeys.black_list() self.cache.set(cache_key, the_list, ttl=60 * 10) self.redis.delete(cache_key) self.redis.sadd(cache_key, *the_list) def remove_from_black_list(self, word: str) -> None: cache_key = RedisKeys.black_list() the_cached_list = self.cache.get(cache_key) the_cached_list.remove(word) self.cache.set(cache_key, the_cached_list, ttl=60 * 10) self.redis.srem(cache_key, word) def add_to_black_list(self, word: str) -> None: cache_key = RedisKeys.black_list() the_cached_list = self.cache.get(cache_key) the_cached_list.add(word) self.cache.set(cache_key, the_cached_list, ttl=60 * 10) self.redis.sadd(cache_key, word) def _set_ban_timestamp(self, key: str, user_id: str, timestamp: str) -> None: cache_key = '%s-%s' % (key, user_id) self.cache.set(cache_key, timestamp) self.redis.hset(key, user_id, timestamp) def set_global_ban_timestamp(self, user_id: str, duration: str, timestamp: str, username: str) -> None: key = RedisKeys.banned_users() self._set_ban_timestamp(key, user_id, '%s|%s|%s' % (duration, timestamp, username)) def set_channel_ban_timestamp(self, channel_id: str, user_id: str, duration: str, timestamp: str, username: str) -> None: key = RedisKeys.banned_users_channel(channel_id) self._set_ban_timestamp(key, user_id, '%s|%s|%s' % (duration, timestamp, username)) def set_room_ban_timestamp(self, room_id: str, user_id: str, duration: str, timestamp: str, username: str) -> None: key = RedisKeys.banned_users(room_id) self._set_ban_timestamp(key, user_id, '%s|%s|%s' % (duration, timestamp, username)) def get_user_roles(self, user_id: str) -> None: key = RedisKeys.user_roles() cache_key = '%s-%s' % (key, user_id) value = self.cache.get(cache_key) if value is not None: return value value = self.redis.hget(key, user_id) if value is not None: value = json.loads(str(value, 'utf-8')) self.cache.set(cache_key, value, ttl=10) return value def set_user_roles(self, user_id: str, roles: dict) -> None: key = RedisKeys.user_roles() cache_key = '%s-%s' % (key, user_id) self.redis.hset(key, user_id, json.dumps(roles)) self.cache.set(cache_key, roles, ttl=10) def reset_user_roles(self, user_id: str) -> None: key = RedisKeys.user_roles() cache_key = '%s-%s' % (key, user_id) self.redis.hdel(key, user_id) self.cache.delete(cache_key) def get_admin_room(self) -> str: key = RedisKeys.admin_room() value = self.cache.get(key) if value is not None: return value room_id = self.redis.get(key) if room_id is None or len(str(room_id, 'utf-8').strip()) == 0: return None room_id = str(room_id, 'utf-8') self.cache.set(key, room_id, ttl=EIGHT_HOURS_IN_SECONDS) return room_id def set_admin_room(self, room_id: str) -> None: key = RedisKeys.admin_room() self.redis.set(key, room_id) self.cache.set(key, room_id, ttl=EIGHT_HOURS_IN_SECONDS) def _get_ban_timestamp(self, key: str, user_id: str) -> str: cache_key = '%s-%s' % (key, user_id) value = self.cache.get(cache_key) if value is not None: return value.split('|', 2) ban_info = self.redis.hget(key, user_id) if ban_info is None: return None, None, None ban_info = str(ban_info, 'utf-8') return ban_info.split('|', 2) def get_global_ban_timestamp(self, user_id: str) -> str: key = RedisKeys.banned_users() return self._get_ban_timestamp(key, user_id) def get_channel_ban_timestamp(self, channel_id: str, user_id: str) -> str: key = RedisKeys.banned_users_channel(channel_id) return self._get_ban_timestamp(key, user_id) def get_room_ban_timestamp(self, room_id: str, user_id: str) -> str: key = RedisKeys.banned_users(room_id) return self._get_ban_timestamp(key, user_id) def get_room_id_for_name(self, channel_id: str, room_name: str) -> str: key = RedisKeys.room_id_for_name(channel_id) cache_key = '%s-%s' % (key, room_name) value = self.cache.get(cache_key) if value is not None: return value value = self.redis.hget(key, room_name) if value is None: return None value = str(value, 'utf-8') self.cache.set(cache_key, value) return value def set_room_id_for_name(self, channel_id, room_name, room_id): key = RedisKeys.room_id_for_name(channel_id) cache_key = '%s-%s' % (key, room_name) self.cache.set(cache_key, room_id) self.redis.hset(key, room_name, room_id) def get_user_name(self, user_id: str) -> str: key = RedisKeys.user_names() cache_key = '%s-%s' % (key, user_id) value = self.cache.get(cache_key) if value is not None: return value user_name = self.redis.hget(key, user_id) if user_name is not None: user_name = str(user_name, 'utf-8') self.cache.set(cache_key, user_name) return user_name return user_name def set_user_name(self, user_id: str, user_name: str): key = RedisKeys.user_names() cache_key = '%s-%s' % (key, user_id) self.redis.hset(key, user_id, user_name) self.cache.set(cache_key, user_name) def get_room_exists(self, channel_id, room_id): key = RedisKeys.rooms(channel_id) cache_key = '%s-%s' % (key, room_id) value = self.cache.get(cache_key) if value is not None: return True exists = self.redis.hexists(key, room_id) if exists == 1: self.cache.set(cache_key, True) return True return None def remove_room_exists(self, channel_id, room_id): key = RedisKeys.rooms(channel_id) cache_key = '%s-%s' % (key, room_id) self.cache.set(cache_key, None) self.redis.hdel(key, room_id) def set_room_exists(self, channel_id, room_id, room_name): key = RedisKeys.rooms(channel_id) cache_key = '%s-%s' % (key, room_id) self.cache.set(cache_key, room_name) self.redis.hset(key, room_id, room_name) def set_channel_exists(self, channel_id: str) -> None: key = RedisKeys.channel_exists() cache_key = '%s-%s' % (key, channel_id) self.redis.hset(key, channel_id, True) self.cache.set(cache_key, True) def set_channel_for_room(self, channel_id: str, room_id: str) -> None: key = RedisKeys.channel_for_rooms() cache_key = '%s-%s' % (key, room_id) self.redis.hset(key, room_id, channel_id) self.cache.set(cache_key, channel_id) def get_channel_exists(self, channel_id): key = RedisKeys.channel_exists() cache_key = '%s-%s' % (key, channel_id) value = self.cache.get(cache_key) if value is not None: return True value = self.redis.hget(key, channel_id) if value is None: return None self.cache.set(cache_key, True) return True def set_channel_name(self, channel_id: str, channel_name: str) -> None: key = RedisKeys.channels() cache_key = '%s-name-%s' % (key, channel_id) self.cache.set(cache_key, channel_name) self.redis.hset(key, channel_id, channel_name) def get_channel_name(self, channel_id: str) -> str: key = RedisKeys.channels() cache_key = '%s-name-%s' % (key, channel_id) value = self.cache.get(cache_key) if value is not None: return value value = self.redis.hget(key, channel_id) if value is None: return None value = str(value, 'utf-8') self.cache.set(cache_key, value) return value def get_room_name(self, room_id: str) -> str: key = RedisKeys.room_name_for_id() cache_key = '%s-%s-name' % (key, room_id) value = self.cache.get(cache_key) if value is not None: return value value = self.redis.hget(key, room_id) if value is None: return None value = str(value, 'utf-8') self.cache.set(cache_key, value) return value def get_channel_for_room(self, room_id): key = RedisKeys.channel_for_rooms() cache_key = '%s-%s' % (key, room_id) value = self.cache.get(key) if value is not None: return value channel_id = self.redis.hget(key, room_id) if channel_id is None: return None channel_id = str(channel_id, 'utf-8') self.cache.set(cache_key, channel_id) return channel_id def get_user_status(self, user_id: str): key = RedisKeys.user_status(user_id) value = self.cache.get(key) if value is not None: return value status = self.redis.get(key) if status is None or status == '': return None user_status = str(status, 'utf-8') self.cache.set(key, user_status) return user_status def set_user_status(self, user_id: str, status: str) -> None: key = RedisKeys.user_status(user_id) self.redis.set(key, status) self.cache.set(key, status) def user_check_status(self, user_id, other_status): return self.get_user_status(user_id) == other_status def user_is_offline(self, user_id): return self.user_check_status(user_id, UserKeys.STATUS_UNAVAILABLE) def user_is_online(self, user_id): return self.user_check_status(user_id, UserKeys.STATUS_AVAILABLE) def user_is_invisible(self, user_id): return self.user_check_status(user_id, UserKeys.STATUS_INVISIBLE) def set_user_offline(self, user_id: str) -> None: self.cache.set(RedisKeys.user_status(user_id), UserKeys.STATUS_UNAVAILABLE) self.redis.setbit(RedisKeys.online_bitmap(), int(user_id), 0) self.redis.srem(RedisKeys.online_set(), int(user_id)) self.redis.srem(RedisKeys.users_multi_cast(), user_id) self.redis.set(RedisKeys.user_status(user_id), UserKeys.STATUS_UNAVAILABLE) def set_user_online(self, user_id: str) -> None: self.cache.set(RedisKeys.user_status(user_id), UserKeys.STATUS_AVAILABLE) self.redis.setbit(RedisKeys.online_bitmap(), int(user_id), 1) self.redis.sadd(RedisKeys.online_set(), int(user_id)) self.redis.sadd(RedisKeys.users_multi_cast(), user_id) self.redis.set(RedisKeys.user_status(user_id), UserKeys.STATUS_AVAILABLE) def set_user_invisible(self, user_id: str) -> None: self.cache.set(RedisKeys.user_status(user_id), UserKeys.STATUS_INVISIBLE) self.redis.setbit(RedisKeys.online_bitmap(), int(user_id), 0) self.redis.srem(RedisKeys.online_set(), int(user_id)) self.redis.sadd(RedisKeys.users_multi_cast(), user_id) self.redis.set(RedisKeys.user_status(user_id), UserKeys.STATUS_INVISIBLE)
class RedisStoreTestCase(TestCase): def setUp(self): self.redis = FakeStrictRedis() super(RedisStoreTestCase, self).setUp() def tearDown(self): flexmock_teardown() self.redis.flushdb() def test_get_returns_null_when_not_found(self): store = self.get_store() self.assertIsNone(store.get('foo')) def test_redis_value_is_returned(self): store = self.get_store() self.redis.set('prefix:foo', store.serialize('bar')) self.assertEqual('bar', store.get('foo')) def test_redis_value_is_returned_for_numerics(self): store = self.get_store() self.redis.set('prefix:foo', store.serialize(1)) self.assertEqual(1, store.get('foo')) def test_put_value_into_redis(self): store = self.get_store() store.put('foo', 'bar', 60) self.assertEqual(store.serialize('bar'), self.redis.get('prefix:foo')) self.assertEqual(60., round(math.ceil(float(self.redis.ttl('prefix:foo')) / 60))) def test_put_numeric_value_into_redis(self): store = self.get_store() store.put('foo', 1, 60) self.assertEqual(store.serialize(1), self.redis.get('prefix:foo')) self.assertEqual(60., round(math.ceil(float(self.redis.ttl('prefix:foo')) / 60))) def test_increment(self): store = self.get_store() self.redis.set('prefix:foo', 1) store.increment('foo', 2) self.assertEqual(3, int(self.redis.get('prefix:foo'))) def test_decrement(self): store = self.get_store() self.redis.set('prefix:foo', 3) store.decrement('foo', 2) self.assertEqual(1, int(self.redis.get('prefix:foo'))) def test_forever(self): store = self.get_store() store.forever('foo', 'bar') self.assertEqual(store.serialize('bar'), self.redis.get('prefix:foo')) self.assertIsNone(self.redis.ttl('prefix:foo')) def test_forget(self): store = self.get_store() self.redis.set('prefix:foo', 'bar') store.forget('foo') self.assertFalse(self.redis.exists('prefix:foo')) def get_store(self): return RedisStore(prefix='prefix:', redis_class=FakeStrictRedis)