From 874a5865b8e7a1ffe253fcab5b5eb7febfaa4cbf Mon Sep 17 00:00:00 2001 From: Tim Burke Date: Thu, 6 Jan 2022 10:10:40 -0800 Subject: [PATCH] tests: Improve FakeMemcache call tracking Make it much more like mock tracking, so we can easily add new kwargs. Change-Id: Ib29816c4626bb0d914929783bd676e8b6cb19bbf --- test/unit/__init__.py | 28 +++++--- test/unit/proxy/controllers/test_container.py | 67 +++++++++---------- 2 files changed, 51 insertions(+), 44 deletions(-) diff --git a/test/unit/__init__.py b/test/unit/__init__.py index 7b9c811312..40d6069337 100644 --- a/test/unit/__init__.py +++ b/test/unit/__init__.py @@ -401,6 +401,13 @@ class FabricatedRing(Ring): self._update_bookkeeping() +def track(f): + def wrapper(self, *a, **kw): + self.calls.append(getattr(mocklib.call, f.__name__)(*a, **kw)) + return f(self, *a, **kw) + return wrapper + + class FakeMemcache(object): def __init__(self): @@ -412,19 +419,16 @@ class FakeMemcache(object): def clear_calls(self): del self.calls[:] - def _called(self, method, key=None, value=None, time=None): - self.calls.append((method, key, value, time)) - + @track def get(self, key): - self._called('get', key) return self.store.get(key) + @property def keys(self): - self._called('keys') - return self.store.keys() + return self.store.keys + @track def set(self, key, value, serialize=True, time=0): - self._called('set', key, value, time) if serialize: value = json.loads(json.dumps(value)) else: @@ -432,8 +436,8 @@ class FakeMemcache(object): self.store[key] = value return True + @track def incr(self, key, delta=1, time=0): - self._called('incr', key, time=time) if self.error_on_incr: raise MemcacheConnectionError('Memcache restarting') if self.init_incr_return_neg: @@ -445,6 +449,7 @@ class FakeMemcache(object): self.store[key] = 0 return self.store[key] + # tracked via incr() def decr(self, key, delta=1, time=0): return self.incr(key, delta=-delta, time=time) @@ -452,8 +457,8 @@ class FakeMemcache(object): def soft_lock(self, key, timeout=0, retries=5): yield True + @track def delete(self, key): - self._called('delete', key) try: del self.store[key] except Exception: @@ -464,6 +469,11 @@ class FakeMemcache(object): self.store.clear() +# This decorator only makes sense in the context of FakeMemcache; +# may as well clean it up now +del track + + class FakeIterable(object): def __init__(self, values): self.next_call_count = 0 diff --git a/test/unit/proxy/controllers/test_container.py b/test/unit/proxy/controllers/test_container.py index 5bc27a7e51..c26bbd2664 100644 --- a/test/unit/proxy/controllers/test_container.py +++ b/test/unit/proxy/controllers/test_container.py @@ -2110,14 +2110,13 @@ class TestContainerController(TestRingBase): 'X-Backend-Record-Type': 'shard', 'X-Backend-Sharding-State': sharding_state}) self.assertEqual( - [('get', 'container/a/c', None, None), - ('set', 'shard-listing/a/c', self.sr_dicts, - exp_recheck_listing), - ('set', 'container/a/c', mock.ANY, 60)], + [mock.call.get('container/a/c'), + mock.call.set('shard-listing/a/c', self.sr_dicts, + time=exp_recheck_listing), + mock.call.set('container/a/c', mock.ANY, time=60)], self.memcache.calls) - self.assertEqual(self.sr_dicts, self.memcache.calls[1][2]) self.assertEqual(sharding_state, - self.memcache.calls[2][2]['sharding_state']) + self.memcache.calls[2][1][1]['sharding_state']) self.assertIn('swift.infocache', req.environ) self.assertIn('shard-listing/a/c', req.environ['swift.infocache']) self.assertEqual(tuple(self.sr_dicts), @@ -2134,8 +2133,8 @@ class TestContainerController(TestRingBase): 'X-Backend-Record-Type': 'shard', 'X-Backend-Sharding-State': sharding_state}) self.assertEqual( - [('get', 'container/a/c', None, None), - ('get', 'shard-listing/a/c', None, None)], + [mock.call.get('container/a/c'), + mock.call.get('shard-listing/a/c')], self.memcache.calls) self.assertIn('swift.infocache', req.environ) self.assertIn('shard-listing/a/c', req.environ['swift.infocache']) @@ -2151,8 +2150,8 @@ class TestContainerController(TestRingBase): self._capture_backend_request(req, 204, b'', {}, num_resp=self.CONTAINER_REPLICAS) self.assertEqual( - [('delete', 'container/a/c', None, None), - ('delete', 'shard-listing/a/c', None, None)], + [mock.call.delete('container/a/c'), + mock.call.delete('shard-listing/a/c')], self.memcache.calls) def test_get_from_shards_add_root_spi(self): @@ -2281,11 +2280,11 @@ class TestContainerController(TestRingBase): # Note: container metadata is updated in cache but shard ranges are not # deleted from cache self.assertEqual( - [('get', 'container/a/c', None, None), - ('get', 'shard-listing/a/c', None, None), - ('set', 'container/a/c', mock.ANY, 6.0)], + [mock.call.get('container/a/c'), + mock.call.get('shard-listing/a/c'), + mock.call.set('container/a/c', mock.ANY, time=6.0)], self.memcache.calls) - self.assertEqual(404, self.memcache.calls[2][2]['status']) + self.assertEqual(404, self.memcache.calls[2][1][1]['status']) self.assertEqual(b'', resp.body) self.assertEqual(404, resp.status_int) @@ -2304,8 +2303,8 @@ class TestContainerController(TestRingBase): req = self._build_request(req_hdrs, params, {}) resp = req.get_response(self.app) self.assertEqual( - [('get', 'container/a/c', None, None), - ('get', 'shard-listing/a/c', None, None)], + [mock.call.get('container/a/c'), + mock.call.get('shard-listing/a/c')], self.memcache.calls) return resp @@ -2387,14 +2386,13 @@ class TestContainerController(TestRingBase): expected_hdrs = {'X-Backend-Recheck-Container-Existence': '60'} expected_hdrs.update(resp_hdrs) self.assertEqual( - [('get', 'container/a/c', None, None), - ('set', 'shard-listing/a/c', self.sr_dicts, 600), - ('set', 'container/a/c', mock.ANY, 60)], + [mock.call.get('container/a/c'), + mock.call.set('shard-listing/a/c', self.sr_dicts, time=600), + mock.call.set('container/a/c', mock.ANY, time=60)], self.memcache.calls) # shards were cached - self.assertEqual(self.sr_dicts, self.memcache.calls[1][2]) self.assertEqual('sharded', - self.memcache.calls[2][2]['sharding_state']) + self.memcache.calls[2][1][1]['sharding_state']) return resp def test_GET_shard_ranges_write_to_cache(self): @@ -2480,12 +2478,11 @@ class TestContainerController(TestRingBase): expected_hdrs.update(resp_hdrs) self._check_response(resp, self.sr_dicts, expected_hdrs) self.assertEqual( - [('set', 'shard-listing/a/c', self.sr_dicts, 600), - ('set', 'container/a/c', mock.ANY, 60)], + [mock.call.set('shard-listing/a/c', self.sr_dicts, time=600), + mock.call.set('container/a/c', mock.ANY, time=60)], self.memcache.calls) - self.assertEqual(self.sr_dicts, self.memcache.calls[0][2]) self.assertEqual('sharded', - self.memcache.calls[1][2]['sharding_state']) + self.memcache.calls[1][1][1]['sharding_state']) def _do_test_GET_shard_ranges_no_cache_write(self, resp_hdrs): # verify that there is a cache lookup to check container info but then @@ -2516,11 +2513,11 @@ class TestContainerController(TestRingBase): # container metadata is looked up in memcache for sharding state # container metadata is set in memcache self.assertEqual( - [('get', 'container/a/c', None, None), - ('set', 'container/a/c', mock.ANY, 60)], + [mock.call.get('container/a/c'), + mock.call.set('container/a/c', mock.ANY, time=60)], self.memcache.calls) self.assertEqual(resp.headers.get('X-Backend-Sharding-State'), - self.memcache.calls[1][2]['sharding_state']) + self.memcache.calls[1][1][1]['sharding_state']) self.memcache.delete_all() def test_GET_shard_ranges_no_cache_write_with_cached_container_info(self): @@ -2650,11 +2647,11 @@ class TestContainerController(TestRingBase): # container metadata is looked up in memcache for sharding state # container metadata is set in memcache self.assertEqual( - [('get', 'container/a/c', None, None), - ('set', 'container/a/c', mock.ANY, 60)], + [mock.call.get('container/a/c'), + mock.call.set('container/a/c', mock.ANY, time=60)], self.memcache.calls) self.assertEqual(resp.headers.get('X-Backend-Sharding-State'), - self.memcache.calls[1][2]['sharding_state']) + self.memcache.calls[1][1][1]['sharding_state']) self.memcache.delete_all() def test_GET_shard_ranges_bad_response_body(self): @@ -2703,10 +2700,10 @@ class TestContainerController(TestRingBase): 'X-Backend-Sharding-State': sharding_state}) # container metadata from backend response is set in memcache self.assertEqual( - [('set', 'container/a/c', mock.ANY, 60)], + [mock.call.set('container/a/c', mock.ANY, time=60)], self.memcache.calls) self.assertEqual(sharding_state, - self.memcache.calls[0][2]['sharding_state']) + self.memcache.calls[0][1][1]['sharding_state']) def test_GET_shard_ranges_no_cache_recheck_listing_shard_ranges(self): # verify that a GET for shards does not lookup or store in cache when @@ -2773,10 +2770,10 @@ class TestContainerController(TestRingBase): 'X-Backend-Sharding-State': 'sharded'}) # container metadata from backend response is set in memcache self.assertEqual( - [('set', 'container/a/c', mock.ANY, 60)], + [mock.call.set('container/a/c', mock.ANY, time=60)], self.memcache.calls) self.assertEqual('sharded', - self.memcache.calls[0][2]['sharding_state']) + self.memcache.calls[0][1][1]['sharding_state']) def test_GET_shard_ranges_no_memcache_available(self): self._setup_shard_range_stubs()