class TestRedisString(object): """string tests""" def setUp(self): self.redis = MockRedis() self.redis.flushdb() def test_get(self): eq_(None, self.redis.get('key')) self.redis.redis['key'] = 'value' eq_('value', self.redis.get('key')) def test_set_no_options(self): self.redis.set('key', 'value') eq_('value', self.redis.redis['key']) def _assert_set_with_options(self, test_cases): """ Assert conditions for setting a key on the set function. The set function can take px, ex, nx and xx kwargs, this function asserts various conditions on set depending on the combinations of kwargs: creation mode(nx,xx) and expiration(ex,px). E.g. verifying that a non-existent key does not get set if xx=True or gets set with nx=True iff it is absent. """ category, existing_key, cases = test_cases msg = "Failed in: {}".format(category) if existing_key: self.redis.set('key', 'value') for (key, value, expected_result), config in cases: # set with creation mode and expiry options result = self.redis.set(key, value, **config) eq_(expected_result, result, msg) if expected_result is not None: # if the set was expected to happen self._assert_was_set(key, value, config, msg) else: # if the set was not expected to happen self._assert_not_set(key, value, msg) def _assert_not_set(self, key, value, msg): """Check that the key and its timeout were not set""" # check that the value wasn't updated ok_(value != self.redis.get(key), msg) # check that the expiration was not set ok_(self.redis.ttl(key) is None, msg) def _assert_was_set(self, key, value, config, msg): """Assert that the key was set along with timeout if applicable""" eq_(value, self.redis.get(key)) if 'px' in config: # px should have been preferred over ex if it was specified ok_(int(config['px'] / 1000) == self.redis.ttl(key), msg) elif 'ex' in config: ok_(config['ex'] == self.redis.ttl(key), msg) def test_set_with_options(self): """Test the set function with various combinations of arguments""" test_cases = [( "1. px and ex are set, nx is always true & set on non-existing key", False, [(('key1', 'value1', None), dict(ex=20, px=70000, xx=True, nx=True)), (('key2', 'value1', True), dict(ex=20, px=70000, xx=False, nx=True)), (('key3', 'value2', True), dict(ex=20, px=70000, nx=True))]), ("2. px and ex are set, nx is always true & set on existing key", True, [(('key', 'value1', None), dict(ex=20, px=70000, xx=True, nx=True)), (('key', 'value1', None), dict(ex=20, px=7000, xx=False, nx=True)), (('key', 'value1', None), dict(ex=20, px=70000, nx=True))]), ("3. px and ex are set, xx is always true & set on existing key", True, [(('key', 'value1', None), dict(ex=20, px=70000, xx=True, nx=True)), (('key', 'value1', True), dict(ex=20, px=70000, xx=True, nx=False)), (('key', 'value4', True), dict(ex=20, px=70000, xx=True))]), ("4. px and ex are set, xx is always true & set on non-existing key", False, [(('key1', 'value1', None), dict(ex=20, px=70000, xx=True, nx=True)), (('key2', 'value2', None), dict(ex=20, px=70000, xx=True, nx=False)), (('key3', 'value3', None), dict(ex=20, px=70000, xx=True))]), ("5. either nx or xx defined and set to false or none defined" + " & set on existing key", True, [ (('key', 'value1', True), dict(ex=20, px=70000, xx=False)), (('key', 'value2', True), dict(ex=20, px=70000, nx=False)), (('key', 'value3', True), dict(ex=20, px=70000)) ]), ("6. either nx or xx defined and set to false or none defined" + " & set on non-existing key", False, [ (('key1', 'value1', True), dict(ex=20, px=70000, xx=False)), (('key2', 'value2', True), dict(ex=20, px=70000, nx=False)), (('key3', 'value3', True), dict(ex=20, px=70000)) ]), ("7: where neither px nor ex defined + set on existing key", True, [(('key', 'value2', None), dict(xx=True, nx=True)), (('key', 'value2', None), dict(xx=False, nx=True)), (('key', 'value2', True), dict(xx=True, nx=False)), (('key', 'value3', True), dict(xx=True)), (('key', 'value4', None), dict(nx=True)), (('key', 'value4', True), dict(xx=False)), (('key', 'value5', True), dict(nx=False))]), ("8: where neither px nor ex defined + set on non-existing key", False, [ (('key1', 'value1', None), dict(xx=True, nx=True)), (('key2', 'value1', True), dict(xx=False, nx=True)), (('key3', 'value2', None), dict(xx=True, nx=False)), (('key4', 'value3', None), dict(xx=True)), (('key5', 'value4', True), dict(nx=True)), (('key6', 'value4', True), dict(xx=False)), (('key7', 'value5', True), dict(nx=False)) ]), ("9: where neither nx nor xx defined + set on existing key", True, [(('key', 'value1', True), dict(ex=20, px=70000)), (('key1', 'value12', True), dict(ex=20)), (('key1', 'value11', True), dict(px=20000))]), ("10: where neither nx nor xx is defined + set on non-existing key", False, [(('key1', 'value1', True), dict(ex=20, px=70000)), (('key2', 'value2', True), dict(ex=20)), (('key3', 'value3', True), dict(px=20000))])] for cases in test_cases: yield self._assert_set_with_options, cases def _assert_set_with_timeout(self, seconds): """Assert that setex sets a key with a value along with a timeout""" eq_(None, self.redis.redis.get('key')) ok_(self.redis.setex('key', seconds, 'value')) eq_('value', self.redis.redis.get('key')) ok_(self.redis.ttl('key'), "expiration was not set correctly") if isinstance(seconds, timedelta): seconds = seconds.seconds + seconds.days * 24 * 3600 ok_(0 < self.redis.ttl('key') <= seconds) def test_setex(self): test_cases = [20, timedelta(seconds=20)] for case in test_cases: yield self._assert_set_with_timeout, case def test_setnx(self): """Check whether setnx sets a key iff it does not already exist""" ok_(self.redis.setnx('key', 'value')) ok_(not self.redis.setnx('key', 'different_value')) eq_('value', self.redis.get('key')) def test_delete(self): """Test if delete works""" test_cases = [('1', '1'), (('1', '2'), ('1', '2')), (('1', '2', '3'), ('1', '3')), (('1', '2'), '1'), ('1', '2')] for case in test_cases: yield self._assert_delete, case def _assert_delete(self, data): """Asserts that key(s) deletion along with removing timeouts if any, succeeds as expected""" to_create, to_delete = data for key in to_create: self.redis.set(key, "value", ex=200) eq_(self.redis.delete(*to_delete), len(set(to_create) & set(to_delete))) # verify if the keys that were to be deleted, were deleted along with the timeouts. for key in set(to_create) & set(to_delete): ok_(key not in self.redis.redis and key not in self.redis.timeouts) # verify if the keys not to be deleted, were not deleted and their timeouts not removed. for key in set(to_create) - (set(to_create) & set(to_delete)): ok_(key in self.redis.redis and key in self.redis.timeouts)
class TestRedisList(TestCase): """list tests""" def setUp(self): self.redis = MockRedis() def test_initially_empty(self): """ List is created empty. """ self.assertEqual(0, len(self.redis.redis[LIST1])) def test_llen(self): self.assertEquals(0, self.redis.llen(LIST1)) self.redis.redis[LIST1] = [VAL1, VAL2] self.assertEquals(2, self.redis.llen(LIST1)) self.redis.redis[LIST1].pop(0) self.assertEquals(1, self.redis.llen(LIST1)) self.redis.redis[LIST1].pop(0) self.assertEquals(0, self.redis.llen(LIST1)) def test_lpop(self): self.redis.redis[LIST1] = [VAL1, VAL2] self.assertEquals(VAL1, self.redis.lpop(LIST1)) self.assertEquals(1, len(self.redis.redis[LIST1])) self.assertEquals(VAL2, self.redis.lpop(LIST1)) self.assertEquals(0, len(self.redis.redis[LIST1])) self.assertIsNone(self.redis.lpop(LIST1)) def test_lpush(self): """ Insertion maintains order but not uniqueness. """ # lpush two values self.redis.lpush(LIST1, VAL1) self.redis.lpush(LIST1, VAL2) # validate insertion self.assertEquals("list", self.redis.type(LIST1)) self.assertEquals([VAL2, VAL1], self.redis.redis[LIST1]) # insert two more values with one repeated self.redis.lpush(LIST1, VAL1, VAL3) # validate the update self.assertEquals("list", self.redis.type(LIST1)) self.assertEquals([VAL3, VAL1, VAL2, VAL1], self.redis.redis[LIST1]) def test_rpop(self): self.redis.redis[LIST1] = [VAL1, VAL2] self.assertEquals(VAL2, self.redis.rpop(LIST1)) self.assertEquals(1, len(self.redis.redis[LIST1])) self.assertEquals(VAL1, self.redis.rpop(LIST1)) self.assertEquals(0, len(self.redis.redis[LIST1])) self.assertIsNone(self.redis.lpop(LIST1)) def test_rpush(self): """ Insertion maintains order but not uniqueness. """ # lpush two values self.redis.rpush(LIST1, VAL1) self.redis.rpush(LIST1, VAL2) # validate insertion self.assertEquals("list", self.redis.type(LIST1)) self.assertEquals([VAL1, VAL2], self.redis.redis[LIST1]) # insert two more values with one repeated self.redis.rpush(LIST1, VAL1, VAL3) # validate the update self.assertEquals("list", self.redis.type(LIST1)) self.assertEquals([VAL1, VAL2, VAL1, VAL3], self.redis.redis[LIST1]) def test_lrem(self): self.redis.redis[LIST1] = [VAL1, VAL2, VAL1, VAL3, VAL4, VAL2] count = self.redis.lrem(LIST1, VAL1, 0) self.assertEqual(2, count) self.assertListEqual([VAL2, VAL3, VAL4, VAL2], self.redis.redis[LIST1]) self.redis.redis[LIST1] = [VAL1, VAL2, VAL1, VAL3, VAL4, VAL2] count = self.redis.lrem(LIST1, VAL2, 1) self.assertEqual(1, count) self.assertListEqual([VAL1, VAL1, VAL3, VAL4, VAL2], self.redis.redis[LIST1]) self.redis.redis[LIST1] = [VAL1, VAL2, VAL1, VAL3, VAL4, VAL2] count = self.redis.lrem(LIST1, VAL1, 100) self.assertEqual(2, count) self.assertListEqual([VAL2, VAL3, VAL4, VAL2], self.redis.redis[LIST1]) self.redis.redis[LIST1] = [VAL1, VAL2, VAL1, VAL3, VAL4, VAL2] count = self.redis.lrem(LIST1, VAL3, -1) self.assertEqual(1, count) self.assertListEqual([VAL1, VAL2, VAL1, VAL4, VAL2], self.redis.redis[LIST1]) self.redis.redis[LIST1] = [VAL1, VAL2, VAL1, VAL3, VAL4, VAL2] count = self.redis.lrem(LIST1, VAL2, -1) self.assertEqual(1, count) self.assertListEqual([VAL1, VAL2, VAL1, VAL3, VAL4], self.redis.redis[LIST1]) self.redis.redis[LIST1] = [VAL1, VAL2, VAL1, VAL3, VAL4, VAL2] count = self.redis.lrem(LIST1, VAL2, -2) self.assertEqual(2, count) self.assertListEqual([VAL1, VAL1, VAL3, VAL4], self.redis.redis[LIST1]) count = self.redis.lrem("NON_EXISTENT_LIST", VAL1, 0) self.assertEqual(0, count) def test_rpoplpush(self): self.redis.redis[LIST1] = [VAL1, VAL2] self.redis.redis[LIST2] = [VAL3, VAL4] transfer_item = self.redis.rpoplpush(LIST1, LIST2) self.assertEqual(VAL2, transfer_item) self.assertEqual([VAL1], self.redis.redis[LIST1]) self.assertEqual([VAL2, VAL3, VAL4], self.redis.redis[LIST2]) def test_rpoplpush_with_empty_source(self): # source list is empty self.redis.redis[LIST1] = [] self.redis.redis[LIST2] = [VAL3, VAL4] transfer_item = self.redis.rpoplpush(LIST1, LIST2) self.assertEqual(None, transfer_item) self.assertEqual([], self.redis.redis[LIST1]) # nothing has been added to the destination queue self.assertEqual([VAL3, VAL4], self.redis.redis[LIST2]) def test_rpoplpush_source_with_empty_string(self): # source list contains empty string self.redis.redis[LIST1] = [''] self.redis.redis[LIST2] = [VAL3, VAL4] self.assertEqual(1, self.redis.llen(LIST1)) self.assertEqual(2, self.redis.llen(LIST2)) transfer_item = self.redis.rpoplpush(LIST1, LIST2) self.assertEqual('', transfer_item) self.assertEqual(0, self.redis.llen(LIST1)) self.assertEqual(3, self.redis.llen(LIST2)) self.assertEqual([], self.redis.redis[LIST1]) # empty string is added to the destination queue self.assertEqual(['', VAL3, VAL4], self.redis.redis[LIST2]) def test_lrange_get_all(self): """Cases for returning entire list""" values = [VAL4, VAL3, VAL2, VAL1] self.assertEqual([], self.redis.lrange(LIST1, 0, 6)) self.assertEqual([], self.redis.lrange(LIST1, 0, -1)) self.redis.lpush(LIST1, *reversed(values)) # Check with exact range self.assertEqual(values, self.redis.lrange(LIST1, 0, 3)) # Check with negative index self.assertEqual(values, self.redis.lrange(LIST1, 0, -1)) # Check with range larger than length of list self.assertEqual(values, self.redis.lrange(LIST1, 0, 6)) def test_lrange_get_sublist(self): """Cases for returning partial list""" values = [VAL4, VAL3, VAL2, VAL1] self.assertEqual([], self.redis.lrange(LIST1, 0, 6)) self.assertEqual([], self.redis.lrange(LIST1, 0, -1)) self.redis.lpush(LIST1, *reversed(values)) # Check from left end of the list self.assertEqual(values[:2], self.redis.lrange(LIST1, 0, 1)) # Check from right end of the list self.assertEqual(values[2:4], self.redis.lrange(LIST1, 2, 3)) # Check from right end of the list with negative range self.assertEqual(values[-2:], self.redis.lrange(LIST1, -2, -1)) # Check from middle of the list self.assertEqual(values[1:3], self.redis.lrange(LIST1, 1, 2)) def test_ltrim_retain_all(self): values = [VAL4, VAL3, VAL2, VAL1] self._reinitialize_list(LIST1, *values) self.redis.ltrim(LIST1, 0, -1) self.assertEqual(values, self.redis.lrange(LIST1, 0, -1)) self.redis.ltrim(LIST1, 0, len(values) - 1) self.assertEqual(values, self.redis.lrange(LIST1, 0, -1)) self.redis.ltrim(LIST1, 0, len(values) + 1) self.assertEqual(values, self.redis.lrange(LIST1, 0, -1)) self.redis.ltrim(LIST1, -1 * len(values), -1) self.assertEqual(values, self.redis.lrange(LIST1, 0, -1)) self.redis.ltrim(LIST1, -1 * (len(values) + 1), -1) self.assertEqual(values, self.redis.lrange(LIST1, 0, -1)) def test_ltrim_remove_all(self): values = [VAL4, VAL3, VAL2, VAL1] self._reinitialize_list(LIST1, *values) self.redis.ltrim(LIST1, 2, 1) self.assertEqual([], self.redis.lrange(LIST1, 0, -1)) self._reinitialize_list(LIST1, *values) self.redis.ltrim(LIST1, -1, -2) self.assertEqual([], self.redis.lrange(LIST1, 0, -1)) self._reinitialize_list(LIST1, *values) self.redis.ltrim(LIST1, 2, -3) self.assertEqual([], self.redis.lrange(LIST1, 0, -1)) self._reinitialize_list(LIST1, *values) self.redis.ltrim(LIST1, -1, 2) self.assertEqual([], self.redis.lrange(LIST1, 0, -1)) def test_ltrim(self): values = [VAL4, VAL3, VAL2, VAL1] self._reinitialize_list(LIST1, *values) self.redis.ltrim(LIST1, 1, 2) self.assertEqual(values[1:3], self.redis.lrange(LIST1, 0, -1)) self._reinitialize_list(LIST1, *values) self.redis.ltrim(LIST1, -3, -1) self.assertEqual(values[-3:], self.redis.lrange(LIST1, 0, -1)) self._reinitialize_list(LIST1, *values) self.redis.ltrim(LIST1, 1, 5) self.assertEqual(values[1:5], self.redis.lrange(LIST1, 0, -1)) self._reinitialize_list(LIST1, *values) self.redis.ltrim(LIST1, -100, 2) self.assertEqual(values[-100:3], self.redis.lrange(LIST1, 0, -1)) def test_lset(self): with self.assertRaises(Exception): self.redis.lset(LIST1, 1, VAL1) self.redis.lpush(LIST1, VAL2) self.assertEqual([VAL2], self.redis.lrange(LIST1, 0, -1)) with self.assertRaises(Exception): self.redis.lset(LIST1, 1, VAL1) self.redis.lset(LIST1, 0, VAL1) self.assertEqual([VAL1], self.redis.lrange(LIST1, 0, -1)) def _reinitialize_list(self, key, *values): """ Re-initialize the list """ self.redis.delete(LIST1) self.redis.lpush(LIST1, *reversed(values))
class TestRedisList(TestCase): """list tests""" def setUp(self): self.redis = MockRedis() def test_initially_empty(self): """ List is created empty. """ self.assertEqual(0, len(self.redis.redis[LIST1])) def test_llen(self): self.assertEquals(0, self.redis.llen(LIST1)) self.redis.redis[LIST1] = [VAL1, VAL2] self.assertEquals(2, self.redis.llen(LIST1)) self.redis.redis[LIST1].pop(0) self.assertEquals(1, self.redis.llen(LIST1)) self.redis.redis[LIST1].pop(0) self.assertEquals(0, self.redis.llen(LIST1)) def test_lpop(self): self.redis.redis[LIST1] = [VAL1, VAL2] self.assertEquals(VAL1, self.redis.lpop(LIST1)) self.assertEquals(1, len(self.redis.redis[LIST1])) self.assertEquals(VAL2, self.redis.lpop(LIST1)) self.assertEquals(0, len(self.redis.redis[LIST1])) self.assertIsNone(self.redis.lpop(LIST1)) def test_lpush(self): """ Insertion maintains order but not uniqueness. """ # lpush two values self.redis.lpush(LIST1, VAL1) self.redis.lpush(LIST1, VAL2) # validate insertion self.assertEquals("list", self.redis.type(LIST1)) self.assertEquals([VAL2, VAL1], self.redis.redis[LIST1]) # insert two more values with one repeated self.redis.lpush(LIST1, VAL1, VAL3) # validate the update self.assertEquals("list", self.redis.type(LIST1)) self.assertEquals([VAL3, VAL1, VAL2, VAL1], self.redis.redis[LIST1]) def test_rpop(self): self.redis.redis[LIST1] = [VAL1, VAL2] self.assertEquals(VAL2, self.redis.rpop(LIST1)) self.assertEquals(1, len(self.redis.redis[LIST1])) self.assertEquals(VAL1, self.redis.rpop(LIST1)) self.assertEquals(0, len(self.redis.redis[LIST1])) self.assertIsNone(self.redis.lpop(LIST1)) def test_rpush(self): """ Insertion maintains order but not uniqueness. """ # lpush two values self.redis.rpush(LIST1, VAL1) self.redis.rpush(LIST1, VAL2) # validate insertion self.assertEquals("list", self.redis.type(LIST1)) self.assertEquals([VAL1, VAL2], self.redis.redis[LIST1]) # insert two more values with one repeated self.redis.rpush(LIST1, VAL1, VAL3) # validate the update self.assertEquals("list", self.redis.type(LIST1)) self.assertEquals([VAL1, VAL2, VAL1, VAL3], self.redis.redis[LIST1]) def test_lrem(self): self.redis.redis[LIST1] = [VAL1, VAL2, VAL1, VAL3, VAL4, VAL2] count = self.redis.lrem(LIST1, VAL1, 0) self.assertEqual(2, count) self.assertListEqual([VAL2, VAL3, VAL4, VAL2], self.redis.redis[LIST1]) self.redis.redis[LIST1] = [VAL1, VAL2, VAL1, VAL3, VAL4, VAL2] count = self.redis.lrem(LIST1, VAL2, 1) self.assertEqual(1, count) self.assertListEqual([VAL1, VAL1, VAL3, VAL4, VAL2], self.redis.redis[LIST1]) self.redis.redis[LIST1] = [VAL1, VAL2, VAL1, VAL3, VAL4, VAL2] count = self.redis.lrem(LIST1, VAL1, 100) self.assertEqual(2, count) self.assertListEqual([VAL2, VAL3, VAL4, VAL2], self.redis.redis[LIST1]) self.redis.redis[LIST1] = [VAL1, VAL2, VAL1, VAL3, VAL4, VAL2] count = self.redis.lrem(LIST1, VAL3, -1) self.assertEqual(1, count) self.assertListEqual([VAL1, VAL2, VAL1, VAL4, VAL2], self.redis.redis[LIST1]) self.redis.redis[LIST1] = [VAL1, VAL2, VAL1, VAL3, VAL4, VAL2] count = self.redis.lrem(LIST1, VAL2, -1) self.assertEqual(1, count) self.assertListEqual([VAL1, VAL2, VAL1, VAL3, VAL4], self.redis.redis[LIST1]) self.redis.redis[LIST1] = [VAL1, VAL2, VAL1, VAL3, VAL4, VAL2] count = self.redis.lrem(LIST1, VAL2, -2) self.assertEqual(2, count) self.assertListEqual([VAL1, VAL1, VAL3, VAL4], self.redis.redis[LIST1]) count = self.redis.lrem("NON_EXISTENT_LIST", VAL1, 0) self.assertEqual(0, count) def test_rpoplpush(self): self.redis.redis[LIST1] = [VAL1, VAL2] self.redis.redis[LIST2] = [VAL3, VAL4] transfer_item = self.redis.rpoplpush(LIST1, LIST2) self.assertEqual(VAL2, transfer_item) self.assertEqual([VAL1], self.redis.redis[LIST1]) self.assertEqual([VAL2, VAL3, VAL4], self.redis.redis[LIST2]) def test_lrange_get_all(self): """Cases for returning entire list""" values = [VAL4, VAL3, VAL2, VAL1] self.assertEqual([], self.redis.lrange(LIST1, 0, 6)) self.assertEqual([], self.redis.lrange(LIST1, 0, -1)) self.redis.lpush(LIST1, *reversed(values)) # Check with exact range self.assertEqual(values, self.redis.lrange(LIST1, 0, 3)) # Check with negative index self.assertEqual(values, self.redis.lrange(LIST1, 0, -1)) # Check with range larger than length of list self.assertEqual(values, self.redis.lrange(LIST1, 0, 6)) def test_lrange_get_sublist(self): """Cases for returning partial list""" values = [VAL4, VAL3, VAL2, VAL1] self.assertEqual([], self.redis.lrange(LIST1, 0, 6)) self.assertEqual([], self.redis.lrange(LIST1, 0, -1)) self.redis.lpush(LIST1, *reversed(values)) # Check from left end of the list self.assertEqual(values[:2], self.redis.lrange(LIST1, 0, 1)) # Check from right end of the list self.assertEqual(values[2:4], self.redis.lrange(LIST1, 2, 3)) # Check from right end of the list with negative range self.assertEqual(values[-2:], self.redis.lrange(LIST1, -2, -1)) # Check from middle of the list self.assertEqual(values[1:3], self.redis.lrange(LIST1, 1, 2)) def test_ltrim_retain_all(self): values = [VAL4, VAL3, VAL2, VAL1] self._reinitialize_list(LIST1, *values) self.redis.ltrim(LIST1, 0, -1) self.assertEqual(values, self.redis.lrange(LIST1, 0, -1)) self.redis.ltrim(LIST1, 0, len(values) - 1) self.assertEqual(values, self.redis.lrange(LIST1, 0, -1)) self.redis.ltrim(LIST1, 0, len(values) + 1) self.assertEqual(values, self.redis.lrange(LIST1, 0, -1)) self.redis.ltrim(LIST1, -1 * len(values), -1) self.assertEqual(values, self.redis.lrange(LIST1, 0, -1)) self.redis.ltrim(LIST1, -1 * (len(values) + 1), -1) self.assertEqual(values, self.redis.lrange(LIST1, 0, -1)) def test_ltrim_remove_all(self): values = [VAL4, VAL3, VAL2, VAL1] self._reinitialize_list(LIST1, *values) self.redis.ltrim(LIST1, 2, 1) self.assertEqual([], self.redis.lrange(LIST1, 0, -1)) self._reinitialize_list(LIST1, *values) self.redis.ltrim(LIST1, -1, -2) self.assertEqual([], self.redis.lrange(LIST1, 0, -1)) self._reinitialize_list(LIST1, *values) self.redis.ltrim(LIST1, 2, -3) self.assertEqual([], self.redis.lrange(LIST1, 0, -1)) self._reinitialize_list(LIST1, *values) self.redis.ltrim(LIST1, -1, 2) self.assertEqual([], self.redis.lrange(LIST1, 0, -1)) def test_ltrim(self): values = [VAL4, VAL3, VAL2, VAL1] self._reinitialize_list(LIST1, *values) self.redis.ltrim(LIST1, 1, 2) self.assertEqual(values[1:3], self.redis.lrange(LIST1, 0, -1)) self._reinitialize_list(LIST1, *values) self.redis.ltrim(LIST1, -3, -1) self.assertEqual(values[-3:], self.redis.lrange(LIST1, 0, -1)) self._reinitialize_list(LIST1, *values) self.redis.ltrim(LIST1, 1, 5) self.assertEqual(values[1:5], self.redis.lrange(LIST1, 0, -1)) self._reinitialize_list(LIST1, *values) self.redis.ltrim(LIST1, -100, 2) self.assertEqual(values[-100:3], self.redis.lrange(LIST1, 0, -1)) def test_lset(self): with self.assertRaises(Exception): self.redis.lset(LIST1, 1, VAL1) self.redis.lpush(LIST1, VAL2) self.assertEqual([VAL2], self.redis.lrange(LIST1, 0, -1)) with self.assertRaises(Exception): self.redis.lset(LIST1, 1, VAL1) self.redis.lset(LIST1, 0, VAL1) self.assertEqual([VAL1], self.redis.lrange(LIST1, 0, -1)) def _reinitialize_list(self, key, *values): """ Re-initialize the list """ self.redis.delete(LIST1) self.redis.lpush(LIST1, *reversed(values))
class TestRedisString(object): """string tests""" def setUp(self): self.redis = MockRedis() self.redis.flushdb() def test_get(self): eq_(None, self.redis.get('key')) self.redis.redis['key'] = 'value' eq_('value', self.redis.get('key')) def test_set_no_options(self): self.redis.set('key', 'value') eq_('value', self.redis.redis['key']) def _assert_set_with_options(self, test_cases): """ Assert conditions for setting a key on the set function. The set function can take px, ex, nx and xx kwargs, this function asserts various conditions on set depending on the combinations of kwargs: creation mode(nx,xx) and expiration(ex,px). E.g. verifying that a non-existent key does not get set if xx=True or gets set with nx=True iff it is absent. """ category, existing_key, cases = test_cases msg = "Failed in: {}".format(category) if existing_key: self.redis.set('key', 'value') for (key, value, expected_result), config in cases: # set with creation mode and expiry options result = self.redis.set(key, value, **config) eq_(expected_result, result, msg) if expected_result is not None: # if the set was expected to happen self._assert_was_set(key, value, config, msg) else: # if the set was not expected to happen self._assert_not_set(key, value, msg) def _assert_not_set(self, key, value, msg): """Check that the key and its timeout were not set""" # check that the value wasn't updated ok_(value != self.redis.get(key), msg) # check that the expiration was not set ok_(self.redis.ttl(key) is None, msg) def _assert_was_set(self, key, value, config, msg): """Assert that the key was set along with timeout if applicable""" eq_(value, self.redis.get(key)) if 'px' in config: # px should have been preferred over ex if it was specified ok_(int(config['px'] / 1000) == self.redis.ttl(key), msg) elif 'ex' in config: ok_(config['ex'] == self.redis.ttl(key), msg) def test_set_with_options(self): """Test the set function with various combinations of arguments""" test_cases = [("1. px and ex are set, nx is always true & set on non-existing key", False, [(('key1', 'value1', None), dict(ex=20, px=70000, xx=True, nx=True)), (('key2', 'value1', True), dict(ex=20, px=70000, xx=False, nx=True)), (('key3', 'value2', True), dict(ex=20, px=70000, nx=True))]), ("2. px and ex are set, nx is always true & set on existing key", True, [(('key', 'value1', None), dict(ex=20, px=70000, xx=True, nx=True)), (('key', 'value1', None), dict(ex=20, px=7000, xx=False, nx=True)), (('key', 'value1', None), dict(ex=20, px=70000, nx=True))]), ("3. px and ex are set, xx is always true & set on existing key", True, [(('key', 'value1', None), dict(ex=20, px=70000, xx=True, nx=True)), (('key', 'value1', True), dict(ex=20, px=70000, xx=True, nx=False)), (('key', 'value4', True), dict(ex=20, px=70000, xx=True))]), ("4. px and ex are set, xx is always true & set on non-existing key", False, [(('key1', 'value1', None), dict(ex=20, px=70000, xx=True, nx=True)), (('key2', 'value2', None), dict(ex=20, px=70000, xx=True, nx=False)), (('key3', 'value3', None), dict(ex=20, px=70000, xx=True))]), ("5. either nx or xx defined and set to false or none defined" + " & set on existing key", True, [(('key', 'value1', True), dict(ex=20, px=70000, xx=False)), (('key', 'value2', True), dict(ex=20, px=70000, nx=False)), (('key', 'value3', True), dict(ex=20, px=70000))]), ("6. either nx or xx defined and set to false or none defined" + " & set on non-existing key", False, [(('key1', 'value1', True), dict(ex=20, px=70000, xx=False)), (('key2', 'value2', True), dict(ex=20, px=70000, nx=False)), (('key3', 'value3', True), dict(ex=20, px=70000))]), ("7: where neither px nor ex defined + set on existing key", True, [(('key', 'value2', None), dict(xx=True, nx=True)), (('key', 'value2', None), dict(xx=False, nx=True)), (('key', 'value2', True), dict(xx=True, nx=False)), (('key', 'value3', True), dict(xx=True)), (('key', 'value4', None), dict(nx=True)), (('key', 'value4', True), dict(xx=False)), (('key', 'value5', True), dict(nx=False))]), ("8: where neither px nor ex defined + set on non-existing key", False, [(('key1', 'value1', None), dict(xx=True, nx=True)), (('key2', 'value1', True), dict(xx=False, nx=True)), (('key3', 'value2', None), dict(xx=True, nx=False)), (('key4', 'value3', None), dict(xx=True)), (('key5', 'value4', True), dict(nx=True)), (('key6', 'value4', True), dict(xx=False)), (('key7', 'value5', True), dict(nx=False))]), ("9: where neither nx nor xx defined + set on existing key", True, [(('key', 'value1', True), dict(ex=20, px=70000)), (('key1', 'value12', True), dict(ex=20)), (('key1', 'value11', True), dict(px=20000))]), ("10: where neither nx nor xx is defined + set on non-existing key", False, [(('key1', 'value1', True), dict(ex=20, px=70000)), (('key2', 'value2', True), dict(ex=20)), (('key3', 'value3', True), dict(px=20000))])] for cases in test_cases: yield self._assert_set_with_options, cases def _assert_set_with_timeout(self, seconds): """Assert that setex sets a key with a value along with a timeout""" eq_(None, self.redis.redis.get('key')) ok_(self.redis.setex('key', seconds, 'value')) eq_('value', self.redis.redis.get('key')) ok_(self.redis.ttl('key'), "expiration was not set correctly") if isinstance(seconds, timedelta): seconds = seconds.seconds + seconds.days * 24 * 3600 ok_(0 < self.redis.ttl('key') <= seconds) def test_setex(self): test_cases = [20, timedelta(seconds=20)] for case in test_cases: yield self._assert_set_with_timeout, case def test_setnx(self): """Check whether setnx sets a key iff it does not already exist""" ok_(self.redis.setnx('key', 'value')) ok_(not self.redis.setnx('key', 'different_value')) eq_('value', self.redis.get('key')) def test_delete(self): """Test if delete works""" test_cases = [('1', '1'), (('1', '2'), ('1', '2')), (('1', '2', '3'), ('1', '3')), (('1', '2'), '1'), ('1', '2')] for case in test_cases: yield self._assert_delete, case def _assert_delete(self, data): """Asserts that key(s) deletion along with removing timeouts if any, succeeds as expected""" to_create, to_delete = data for key in to_create: self.redis.set(key, "value", ex=200) eq_(self.redis.delete(*to_delete), len(set(to_create) & set(to_delete))) # verify if the keys that were to be deleted, were deleted along with the timeouts. for key in set(to_create) & set(to_delete): ok_(key not in self.redis.redis and key not in self.redis.timeouts) # verify if the keys not to be deleted, were not deleted and their timeouts not removed. for key in set(to_create) - (set(to_create) & set(to_delete)): ok_(key in self.redis.redis and key in self.redis.timeouts)