def setUp(self): super().setUp() # Populate the cache with three hits: for redis_key, timeout in { (self._KEY_EXPIRATION, _DEFAULT_TIMEOUT), (self._KEY_NO_EXPIRATION, None), }: cache = CachedOrderedDict( redis_client=self.redis, redis_key=redis_key, dict_keys=('hit1', 'hit2', 'hit3'), timeout=timeout, ) cache['hit1'] = 'value1' cache['hit2'] = 'value2' cache['hit3'] = 'value3' # Instantiate the cache again with the three hits and three misses: self.cache_expiration = CachedOrderedDict( redis_client=self.redis, redis_key=self._KEY_EXPIRATION, dict_keys=('hit1', 'miss1', 'hit2', 'miss2', 'hit3', 'miss3'), ) self.cache_no_expiration = CachedOrderedDict( redis_client=self.redis, redis_key=self._KEY_NO_EXPIRATION, dict_keys=('hit1', 'miss1', 'hit2', 'miss2', 'hit3', 'miss3'), timeout=None, )
def test_cachedorderedict(self): # Populate the cache with three hits: with CachedOrderedDict( redis=self.redis, key=self._KEY, keys=('hit1', 'hit2', 'hit3'), ) as cache: cache['hit1'] = 'value1' cache['hit2'] = 'value2' cache['hit3'] = 'value3' # Instantiate the cache again with the three hits and three misses: cache = CachedOrderedDict( redis=self.redis, key=self._KEY, keys=('hit1', 'miss1', 'hit2', 'miss2', 'hit3', 'miss3'), ) # Ensure that the hits are hits, the misses are misses, and the cache # is ordered: assert tuple(cache.items()) == ( ('hit1', 'value1'), ('miss1', CachedOrderedDict._SENTINEL), ('hit2', 'value2'), ('miss2', CachedOrderedDict._SENTINEL), ('hit3', 'value3'), ('miss3', CachedOrderedDict._SENTINEL), )
def setUp(self): super().setUp() # Populate the cache with three hits: cache = CachedOrderedDict( redis=self.redis, key=self._KEY, keys=('hit1', 'hit2', 'hit3'), ) cache['hit1'] = 'value1' cache['hit2'] = 'value2' cache['hit3'] = 'value3' # Instantiate the cache again with the three hits and three misses: self.cache = CachedOrderedDict( redis=self.redis, key=self._KEY, keys=('hit1', 'miss1', 'hit2', 'miss2', 'hit3', 'miss3'), )
def test_no_keys(self): cache = CachedOrderedDict(redis_client=self.redis) assert cache == {} assert cache.misses() == set()
class CachedOrderedDictTests(TestCase): _KEY_EXPIRATION = 'cached-ordereddict-expiration' _KEY_NO_EXPIRATION = 'cached-ordereddict-no-expiration' def setUp(self): super().setUp() # Populate the cache with three hits: for redis_key, timeout in { (self._KEY_EXPIRATION, _DEFAULT_TIMEOUT), (self._KEY_NO_EXPIRATION, None), }: cache = CachedOrderedDict( redis_client=self.redis, redis_key=redis_key, dict_keys=('hit1', 'hit2', 'hit3'), timeout=timeout, ) cache['hit1'] = 'value1' cache['hit2'] = 'value2' cache['hit3'] = 'value3' # Instantiate the cache again with the three hits and three misses: self.cache_expiration = CachedOrderedDict( redis_client=self.redis, redis_key=self._KEY_EXPIRATION, dict_keys=('hit1', 'miss1', 'hit2', 'miss2', 'hit3', 'miss3'), ) self.cache_no_expiration = CachedOrderedDict( redis_client=self.redis, redis_key=self._KEY_NO_EXPIRATION, dict_keys=('hit1', 'miss1', 'hit2', 'miss2', 'hit3', 'miss3'), timeout=None, ) def test_setitem(self): assert self.cache_expiration == collections.OrderedDict(( ('hit1', 'value1'), ('miss1', CachedOrderedDict._SENTINEL), ('hit2', 'value2'), ('miss2', CachedOrderedDict._SENTINEL), ('hit3', 'value3'), ('miss3', CachedOrderedDict._SENTINEL), )) assert self.cache_expiration._cache == { 'hit1': 'value1', 'hit2': 'value2', 'hit3': 'value3', } assert self.cache_expiration.misses() == {'miss1', 'miss2', 'miss3'} self.cache_expiration['hit4'] = 'value4' assert self.cache_expiration == collections.OrderedDict(( ('hit1', 'value1'), ('miss1', CachedOrderedDict._SENTINEL), ('hit2', 'value2'), ('miss2', CachedOrderedDict._SENTINEL), ('hit3', 'value3'), ('miss3', CachedOrderedDict._SENTINEL), ('hit4', 'value4'), )) assert self.cache_expiration._cache == { 'hit1': 'value1', 'hit2': 'value2', 'hit3': 'value3', 'hit4': 'value4', } assert self.cache_expiration.misses() == {'miss1', 'miss2', 'miss3'} self.cache_expiration['miss1'] = 'value1' assert self.cache_expiration == collections.OrderedDict(( ('hit1', 'value1'), ('miss1', 'value1'), ('hit2', 'value2'), ('miss2', CachedOrderedDict._SENTINEL), ('hit3', 'value3'), ('miss3', CachedOrderedDict._SENTINEL), ('hit4', 'value4'), )) assert self.cache_expiration._cache == { 'hit1': 'value1', 'hit2': 'value2', 'hit3': 'value3', 'hit4': 'value4', 'miss1': 'value1', } assert self.cache_expiration.misses() == {'miss2', 'miss3'} def test_setdefault(self): 'Ensure setdefault() sets the key iff the key does not exist.' for default in ('rajiv', 'raj'): with self.subTest(default=default): self.cache_expiration.setdefault('first', default=default) assert self.cache_expiration == collections.OrderedDict(( ('hit1', 'value1'), ('miss1', CachedOrderedDict._SENTINEL), ('hit2', 'value2'), ('miss2', CachedOrderedDict._SENTINEL), ('hit3', 'value3'), ('miss3', CachedOrderedDict._SENTINEL), ('first', 'rajiv'), )) assert self.cache_expiration._cache == { 'hit1': 'value1', 'hit2': 'value2', 'hit3': 'value3', 'first': 'rajiv', } assert self.cache_expiration.misses() == { 'miss1', 'miss2', 'miss3', } self.cache_expiration.setdefault('miss1', default='value1') assert self.cache_expiration == collections.OrderedDict(( ('hit1', 'value1'), ('miss1', 'value1'), ('hit2', 'value2'), ('miss2', CachedOrderedDict._SENTINEL), ('hit3', 'value3'), ('miss3', CachedOrderedDict._SENTINEL), ('first', 'rajiv'), )) assert self.cache_expiration._cache == { 'hit1': 'value1', 'hit2': 'value2', 'hit3': 'value3', 'first': 'rajiv', 'miss1': 'value1', } assert self.cache_expiration.misses() == {'miss2', 'miss3'} def test_update(self): self.cache_expiration.update() assert self.cache_expiration == collections.OrderedDict(( ('hit1', 'value1'), ('miss1', CachedOrderedDict._SENTINEL), ('hit2', 'value2'), ('miss2', CachedOrderedDict._SENTINEL), ('hit3', 'value3'), ('miss3', CachedOrderedDict._SENTINEL), )) assert self.cache_expiration._cache == { 'hit1': 'value1', 'hit2': 'value2', 'hit3': 'value3', } assert self.cache_expiration.misses() == {'miss1', 'miss2', 'miss3'} self.cache_expiration.update(( ('miss1', 'value1'), ('miss2', 'value2'), ('hit4', 'value4'), ('hit5', 'value5'), )) assert self.cache_expiration == collections.OrderedDict(( ('hit1', 'value1'), ('miss1', 'value1'), ('hit2', 'value2'), ('miss2', 'value2'), ('hit3', 'value3'), ('miss3', CachedOrderedDict._SENTINEL), ('hit4', 'value4'), ('hit5', 'value5'), )) assert self.cache_expiration._cache == { 'hit1': 'value1', 'hit2': 'value2', 'hit3': 'value3', 'miss1': 'value1', 'miss2': 'value2', 'hit4': 'value4', 'hit5': 'value5', } assert self.cache_expiration.misses() == {'miss3'} self.cache_expiration.update({'miss3': CachedOrderedDict._SENTINEL}) assert self.cache_expiration == collections.OrderedDict(( ('hit1', 'value1'), ('miss1', 'value1'), ('hit2', 'value2'), ('miss2', 'value2'), ('hit3', 'value3'), ('miss3', CachedOrderedDict._SENTINEL), ('hit4', 'value4'), ('hit5', 'value5'), )) assert self.cache_expiration._cache == { 'hit1': 'value1', 'hit2': 'value2', 'hit3': 'value3', 'miss1': 'value1', 'miss2': 'value2', 'hit4': 'value4', 'hit5': 'value5', } assert self.cache_expiration.misses() == {'miss3'} self.cache_expiration.update(miss3='value3') assert self.cache_expiration == collections.OrderedDict(( ('hit1', 'value1'), ('miss1', 'value1'), ('hit2', 'value2'), ('miss2', 'value2'), ('hit3', 'value3'), ('miss3', 'value3'), ('hit4', 'value4'), ('hit5', 'value5'), )) assert self.cache_expiration._cache == { 'hit1': 'value1', 'hit2': 'value2', 'hit3': 'value3', 'miss1': 'value1', 'miss2': 'value2', 'hit4': 'value4', 'hit5': 'value5', 'miss3': 'value3', } assert self.cache_expiration.misses() == set() def test_non_string_keys(self): assert self.cache_expiration == collections.OrderedDict(( ('hit1', 'value1'), ('miss1', CachedOrderedDict._SENTINEL), ('hit2', 'value2'), ('miss2', CachedOrderedDict._SENTINEL), ('hit3', 'value3'), ('miss3', CachedOrderedDict._SENTINEL), )) self.cache_expiration[None] = None assert self.cache_expiration == collections.OrderedDict(( ('hit1', 'value1'), ('miss1', CachedOrderedDict._SENTINEL), ('hit2', 'value2'), ('miss2', CachedOrderedDict._SENTINEL), ('hit3', 'value3'), ('miss3', CachedOrderedDict._SENTINEL), (None, None), )) self.cache_expiration[False] = False self.cache_expiration[True] = True assert self.cache_expiration == collections.OrderedDict(( ('hit1', 'value1'), ('miss1', CachedOrderedDict._SENTINEL), ('hit2', 'value2'), ('miss2', CachedOrderedDict._SENTINEL), ('hit3', 'value3'), ('miss3', CachedOrderedDict._SENTINEL), (None, None), (False, False), (True, True), )) self.cache_expiration[0] = 0 assert self.cache_expiration == collections.OrderedDict(( ('hit1', 'value1'), ('miss1', CachedOrderedDict._SENTINEL), ('hit2', 'value2'), ('miss2', CachedOrderedDict._SENTINEL), ('hit3', 'value3'), ('miss3', CachedOrderedDict._SENTINEL), (None, None), (False, False), (True, True), (0, 0), )) self.cache_expiration[0.0] = 0.0 assert self.cache_expiration == collections.OrderedDict(( ('hit1', 'value1'), ('miss1', CachedOrderedDict._SENTINEL), ('hit2', 'value2'), ('miss2', CachedOrderedDict._SENTINEL), ('hit3', 'value3'), ('miss3', CachedOrderedDict._SENTINEL), (None, None), (False, False), (True, True), (0, 0), (0.0, 0.0), )) def test_no_keys(self): cache = CachedOrderedDict(redis_client=self.redis) assert cache == {} assert cache.misses() == set() def test_expiration(self): futures = [] with concurrent.futures.ThreadPoolExecutor() as executor: for test_method in { self._test_expiration, self._test_no_expiration, }: future = executor.submit(test_method) futures.append(future) for future in futures: future.result() def _test_expiration(self): assert self.redis.ttl(self._KEY_EXPIRATION) == _DEFAULT_TIMEOUT time.sleep(1) assert self.redis.ttl(self._KEY_EXPIRATION) == _DEFAULT_TIMEOUT - 1 self.cache_expiration['hit4'] = 'value4' assert self.redis.ttl(self._KEY_EXPIRATION) == _DEFAULT_TIMEOUT def _test_no_expiration(self): assert self.redis.ttl(self._KEY_NO_EXPIRATION) == -1 time.sleep(1) assert self.redis.ttl(self._KEY_NO_EXPIRATION) == -1 self.cache_no_expiration['hit4'] = 'value4' assert self.redis.ttl(self._KEY_NO_EXPIRATION) == -1
class CachedOrderedDictTests(TestCase): _KEY = '{}cached-ordereddict'.format(TestCase._TEST_KEY_PREFIX) def setUp(self): super().setUp() # Populate the cache with three hits: cache = CachedOrderedDict( redis=self.redis, key=self._KEY, keys=('hit1', 'hit2', 'hit3'), ) cache['hit1'] = 'value1' cache['hit2'] = 'value2' cache['hit3'] = 'value3' # Instantiate the cache again with the three hits and three misses: self.cache = CachedOrderedDict( redis=self.redis, key=self._KEY, keys=('hit1', 'miss1', 'hit2', 'miss2', 'hit3', 'miss3'), ) def test_setitem(self): assert self.cache == collections.OrderedDict(( ('hit1', 'value1'), ('miss1', CachedOrderedDict._SENTINEL), ('hit2', 'value2'), ('miss2', CachedOrderedDict._SENTINEL), ('hit3', 'value3'), ('miss3', CachedOrderedDict._SENTINEL), )) assert self.cache._cache == { 'hit1': 'value1', 'hit2': 'value2', 'hit3': 'value3', } assert self.cache.misses() == {'miss1', 'miss2', 'miss3'} self.cache['hit4'] = 'value4' assert self.cache == collections.OrderedDict(( ('hit1', 'value1'), ('miss1', CachedOrderedDict._SENTINEL), ('hit2', 'value2'), ('miss2', CachedOrderedDict._SENTINEL), ('hit3', 'value3'), ('miss3', CachedOrderedDict._SENTINEL), ('hit4', 'value4'), )) assert self.cache._cache == { 'hit1': 'value1', 'hit2': 'value2', 'hit3': 'value3', 'hit4': 'value4', } assert self.cache.misses() == {'miss1', 'miss2', 'miss3'} self.cache['miss1'] = 'value1' assert self.cache == collections.OrderedDict(( ('hit1', 'value1'), ('miss1', 'value1'), ('hit2', 'value2'), ('miss2', CachedOrderedDict._SENTINEL), ('hit3', 'value3'), ('miss3', CachedOrderedDict._SENTINEL), ('hit4', 'value4'), )) assert self.cache._cache == { 'hit1': 'value1', 'hit2': 'value2', 'hit3': 'value3', 'hit4': 'value4', 'miss1': 'value1', } assert self.cache.misses() == {'miss2', 'miss3'} def test_setdefault(self): 'Ensure setdefault() sets the key iff the key does not exist.' for default in ('rajiv', 'raj'): with self.subTest(default=default): self.cache.setdefault('first', default=default) assert self.cache == collections.OrderedDict(( ('hit1', 'value1'), ('miss1', CachedOrderedDict._SENTINEL), ('hit2', 'value2'), ('miss2', CachedOrderedDict._SENTINEL), ('hit3', 'value3'), ('miss3', CachedOrderedDict._SENTINEL), ('first', 'rajiv'), )) assert self.cache._cache == { 'hit1': 'value1', 'hit2': 'value2', 'hit3': 'value3', 'first': 'rajiv', } assert self.cache.misses() == {'miss1', 'miss2', 'miss3'} self.cache.setdefault('miss1', default='value1') assert self.cache == collections.OrderedDict(( ('hit1', 'value1'), ('miss1', 'value1'), ('hit2', 'value2'), ('miss2', CachedOrderedDict._SENTINEL), ('hit3', 'value3'), ('miss3', CachedOrderedDict._SENTINEL), ('first', 'rajiv'), )) assert self.cache._cache == { 'hit1': 'value1', 'hit2': 'value2', 'hit3': 'value3', 'first': 'rajiv', 'miss1': 'value1', } assert self.cache.misses() == {'miss2', 'miss3'} def test_update(self): self.cache.update() assert self.cache == collections.OrderedDict(( ('hit1', 'value1'), ('miss1', CachedOrderedDict._SENTINEL), ('hit2', 'value2'), ('miss2', CachedOrderedDict._SENTINEL), ('hit3', 'value3'), ('miss3', CachedOrderedDict._SENTINEL), )) assert self.cache._cache == { 'hit1': 'value1', 'hit2': 'value2', 'hit3': 'value3', } assert self.cache.misses() == {'miss1', 'miss2', 'miss3'} self.cache.update(( ('miss1', 'value1'), ('miss2', 'value2'), ('hit4', 'value4'), ('hit5', 'value5'), )) assert self.cache == collections.OrderedDict(( ('hit1', 'value1'), ('miss1', 'value1'), ('hit2', 'value2'), ('miss2', 'value2'), ('hit3', 'value3'), ('miss3', CachedOrderedDict._SENTINEL), ('hit4', 'value4'), ('hit5', 'value5'), )) assert self.cache._cache == { 'hit1': 'value1', 'hit2': 'value2', 'hit3': 'value3', 'miss1': 'value1', 'miss2': 'value2', 'hit4': 'value4', 'hit5': 'value5', } assert self.cache.misses() == {'miss3'}