Use unique body content in EC test objects
Avoid ever having two objects in same test with same etag. Refactor some common test helper methods to a common superclass. Change-Id: Ib956c997f8805df1859ebf3582f7ce59c8f65129 Closes-Bug: #1710924
This commit is contained in:
parent
bf09a06708
commit
665e21bbe6
@ -194,6 +194,21 @@ class BaseObjectControllerMixin(object):
|
|||||||
policy = policy or POLICIES.default
|
policy = policy or POLICIES.default
|
||||||
return policy.quorum
|
return policy.quorum
|
||||||
|
|
||||||
|
# Add a few helper methods for EC tests.
|
||||||
|
def _make_ec_archive_bodies(self, test_body, policy=None):
|
||||||
|
policy = policy or self.policy
|
||||||
|
return encode_frag_archive_bodies(policy, test_body)
|
||||||
|
|
||||||
|
def _make_ec_object_stub(self, pattern='test', policy=None,
|
||||||
|
timestamp=None):
|
||||||
|
policy = policy or self.policy
|
||||||
|
test_body = pattern * policy.ec_segment_size
|
||||||
|
test_body = test_body[:-random.randint(1, 1000)]
|
||||||
|
return make_ec_object_stub(test_body, policy, timestamp)
|
||||||
|
|
||||||
|
def _fake_ec_node_response(self, node_frags):
|
||||||
|
return fake_ec_node_response(node_frags, self.policy)
|
||||||
|
|
||||||
def test_iter_nodes_local_first_noops_when_no_affinity(self):
|
def test_iter_nodes_local_first_noops_when_no_affinity(self):
|
||||||
# this test needs a stable node order - most don't
|
# this test needs a stable node order - most don't
|
||||||
self.app.sort_nodes = lambda l, *args, **kwargs: l
|
self.app.sort_nodes = lambda l, *args, **kwargs: l
|
||||||
@ -2375,18 +2390,6 @@ class TestECObjController(BaseObjectControllerMixin, unittest.TestCase):
|
|||||||
resp = req.get_response(self.app)
|
resp = req.get_response(self.app)
|
||||||
self.assertEqual(resp.status_int, 201)
|
self.assertEqual(resp.status_int, 201)
|
||||||
|
|
||||||
def _make_ec_archive_bodies(self, test_body, policy=None):
|
|
||||||
policy = policy or self.policy
|
|
||||||
return encode_frag_archive_bodies(policy, test_body)
|
|
||||||
|
|
||||||
def _make_ec_object_stub(self, test_body=None, policy=None,
|
|
||||||
timestamp=None):
|
|
||||||
policy = policy or self.policy
|
|
||||||
return make_ec_object_stub(test_body, policy, timestamp)
|
|
||||||
|
|
||||||
def _fake_ec_node_response(self, node_frags):
|
|
||||||
return fake_ec_node_response(node_frags, self.policy)
|
|
||||||
|
|
||||||
def test_GET_with_frags_swapped_around(self):
|
def test_GET_with_frags_swapped_around(self):
|
||||||
segment_size = self.policy.ec_segment_size
|
segment_size = self.policy.ec_segment_size
|
||||||
test_data = ('test' * segment_size)[:-657]
|
test_data = ('test' * segment_size)[:-657]
|
||||||
@ -2491,8 +2494,8 @@ class TestECObjController(BaseObjectControllerMixin, unittest.TestCase):
|
|||||||
len(collected_responses[obj1['etag']]))
|
len(collected_responses[obj1['etag']]))
|
||||||
|
|
||||||
def test_GET_with_single_missed_overwrite_does_not_need_handoff(self):
|
def test_GET_with_single_missed_overwrite_does_not_need_handoff(self):
|
||||||
obj1 = self._make_ec_object_stub()
|
obj1 = self._make_ec_object_stub(pattern='obj1')
|
||||||
obj2 = self._make_ec_object_stub()
|
obj2 = self._make_ec_object_stub(pattern='obj2')
|
||||||
|
|
||||||
node_frags = [
|
node_frags = [
|
||||||
{'obj': obj2, 'frag': 0},
|
{'obj': obj2, 'frag': 0},
|
||||||
@ -2541,8 +2544,8 @@ class TestECObjController(BaseObjectControllerMixin, unittest.TestCase):
|
|||||||
len(frags), etag))
|
len(frags), etag))
|
||||||
|
|
||||||
def test_GET_with_many_missed_overwrite_will_need_handoff(self):
|
def test_GET_with_many_missed_overwrite_will_need_handoff(self):
|
||||||
obj1 = self._make_ec_object_stub()
|
obj1 = self._make_ec_object_stub(pattern='obj1')
|
||||||
obj2 = self._make_ec_object_stub()
|
obj2 = self._make_ec_object_stub(pattern='obj2')
|
||||||
|
|
||||||
node_frags = [
|
node_frags = [
|
||||||
{'obj': obj2, 'frag': 0},
|
{'obj': obj2, 'frag': 0},
|
||||||
@ -2592,8 +2595,8 @@ class TestECObjController(BaseObjectControllerMixin, unittest.TestCase):
|
|||||||
len(frags), etag))
|
len(frags), etag))
|
||||||
|
|
||||||
def test_GET_with_missing_and_mixed_frags_will_dig_deep_but_succeed(self):
|
def test_GET_with_missing_and_mixed_frags_will_dig_deep_but_succeed(self):
|
||||||
obj1 = self._make_ec_object_stub(timestamp=self.ts())
|
obj1 = self._make_ec_object_stub(pattern='obj1', timestamp=self.ts())
|
||||||
obj2 = self._make_ec_object_stub(timestamp=self.ts())
|
obj2 = self._make_ec_object_stub(pattern='obj2', timestamp=self.ts())
|
||||||
|
|
||||||
node_frags = [
|
node_frags = [
|
||||||
{'obj': obj1, 'frag': 0},
|
{'obj': obj1, 'frag': 0},
|
||||||
@ -2655,8 +2658,8 @@ class TestECObjController(BaseObjectControllerMixin, unittest.TestCase):
|
|||||||
len(frags), etag))
|
len(frags), etag))
|
||||||
|
|
||||||
def test_GET_with_missing_and_mixed_frags_will_dig_deep_but_stop(self):
|
def test_GET_with_missing_and_mixed_frags_will_dig_deep_but_stop(self):
|
||||||
obj1 = self._make_ec_object_stub()
|
obj1 = self._make_ec_object_stub(pattern='obj1')
|
||||||
obj2 = self._make_ec_object_stub()
|
obj2 = self._make_ec_object_stub(pattern='obj2')
|
||||||
|
|
||||||
node_frags = [
|
node_frags = [
|
||||||
{'obj': obj1, 'frag': 0},
|
{'obj': obj1, 'frag': 0},
|
||||||
@ -2843,8 +2846,8 @@ class TestECObjController(BaseObjectControllerMixin, unittest.TestCase):
|
|||||||
self.assertEqual({obj1['etag'], None}, collected_etags)
|
self.assertEqual({obj1['etag'], None}, collected_etags)
|
||||||
|
|
||||||
def test_GET_with_missing_and_mixed_frags_may_503(self):
|
def test_GET_with_missing_and_mixed_frags_may_503(self):
|
||||||
obj1 = self._make_ec_object_stub()
|
obj1 = self._make_ec_object_stub(pattern='obj1')
|
||||||
obj2 = self._make_ec_object_stub()
|
obj2 = self._make_ec_object_stub(pattern='obj2')
|
||||||
# we get a 503 when all the handoffs return 200
|
# we get a 503 when all the handoffs return 200
|
||||||
node_frags = [[]] * self.replicas() # primaries have no frags
|
node_frags = [[]] * self.replicas() # primaries have no frags
|
||||||
node_frags = node_frags + [ # handoffs all have frags
|
node_frags = node_frags + [ # handoffs all have frags
|
||||||
@ -2883,10 +2886,10 @@ class TestECObjController(BaseObjectControllerMixin, unittest.TestCase):
|
|||||||
# all nodes have a frag but there is no one set that reaches quorum,
|
# all nodes have a frag but there is no one set that reaches quorum,
|
||||||
# which means there is no backend 404 response, but proxy should still
|
# which means there is no backend 404 response, but proxy should still
|
||||||
# return 404 rather than 503
|
# return 404 rather than 503
|
||||||
obj1 = self._make_ec_object_stub()
|
obj1 = self._make_ec_object_stub(pattern='obj1')
|
||||||
obj2 = self._make_ec_object_stub()
|
obj2 = self._make_ec_object_stub(pattern='obj2')
|
||||||
obj3 = self._make_ec_object_stub()
|
obj3 = self._make_ec_object_stub(pattern='obj3')
|
||||||
obj4 = self._make_ec_object_stub()
|
obj4 = self._make_ec_object_stub(pattern='obj4')
|
||||||
|
|
||||||
node_frags = [
|
node_frags = [
|
||||||
{'obj': obj1, 'frag': 0},
|
{'obj': obj1, 'frag': 0},
|
||||||
@ -3057,8 +3060,8 @@ class TestECObjController(BaseObjectControllerMixin, unittest.TestCase):
|
|||||||
self.assertEqual(28, len(log))
|
self.assertEqual(28, len(log))
|
||||||
|
|
||||||
def test_GET_with_missing_durable_files_and_mixed_etags(self):
|
def test_GET_with_missing_durable_files_and_mixed_etags(self):
|
||||||
obj1 = self._make_ec_object_stub()
|
obj1 = self._make_ec_object_stub(pattern='obj1')
|
||||||
obj2 = self._make_ec_object_stub()
|
obj2 = self._make_ec_object_stub(pattern='obj2')
|
||||||
|
|
||||||
# non-quorate durables for another object won't stop us finding the
|
# non-quorate durables for another object won't stop us finding the
|
||||||
# quorate object
|
# quorate object
|
||||||
@ -3147,8 +3150,10 @@ class TestECObjController(BaseObjectControllerMixin, unittest.TestCase):
|
|||||||
# At that point (or before) the proxy knows that a durable set of
|
# At that point (or before) the proxy knows that a durable set of
|
||||||
# frags for obj2 exists so will fetch them, requiring another 10
|
# frags for obj2 exists so will fetch them, requiring another 10
|
||||||
# directed requests.
|
# directed requests.
|
||||||
obj2 = self._make_ec_object_stub(timestamp=self._ts_iter.next())
|
obj2 = self._make_ec_object_stub(pattern='obj2',
|
||||||
obj1 = self._make_ec_object_stub(timestamp=self._ts_iter.next())
|
timestamp=self._ts_iter.next())
|
||||||
|
obj1 = self._make_ec_object_stub(pattern='obj1',
|
||||||
|
timestamp=self._ts_iter.next())
|
||||||
|
|
||||||
node_frags = [
|
node_frags = [
|
||||||
[{'obj': obj1, 'frag': 0, 'durable': False}], # obj2 missing
|
[{'obj': obj1, 'frag': 0, 'durable': False}], # obj2 missing
|
||||||
@ -3197,9 +3202,12 @@ class TestECObjController(BaseObjectControllerMixin, unittest.TestCase):
|
|||||||
# GETs to see all the obj3 frags plus 1 more to GET a durable frag.
|
# GETs to see all the obj3 frags plus 1 more to GET a durable frag.
|
||||||
# The proxy may also do one more GET if the obj2 frag is found.
|
# The proxy may also do one more GET if the obj2 frag is found.
|
||||||
# i.e. 10 + 1 durable for obj3, 2 for obj1 and 1 more if obj2 found
|
# i.e. 10 + 1 durable for obj3, 2 for obj1 and 1 more if obj2 found
|
||||||
obj2 = self._make_ec_object_stub(timestamp=self._ts_iter.next())
|
obj2 = self._make_ec_object_stub(pattern='obj2',
|
||||||
obj3 = self._make_ec_object_stub(timestamp=self._ts_iter.next())
|
timestamp=self._ts_iter.next())
|
||||||
obj1 = self._make_ec_object_stub(timestamp=self._ts_iter.next())
|
obj3 = self._make_ec_object_stub(pattern='obj3',
|
||||||
|
timestamp=self._ts_iter.next())
|
||||||
|
obj1 = self._make_ec_object_stub(pattern='obj1',
|
||||||
|
timestamp=self._ts_iter.next())
|
||||||
|
|
||||||
node_frags = [
|
node_frags = [
|
||||||
[{'obj': obj1, 'frag': 0, 'durable': False}, # obj1 frag
|
[{'obj': obj1, 'frag': 0, 'durable': False}, # obj1 frag
|
||||||
@ -3237,8 +3245,10 @@ class TestECObjController(BaseObjectControllerMixin, unittest.TestCase):
|
|||||||
# scenario: non-durable frags of newer obj1 obscure all frags
|
# scenario: non-durable frags of newer obj1 obscure all frags
|
||||||
# of older obj2, so first 28 requests result in a non-durable set.
|
# of older obj2, so first 28 requests result in a non-durable set.
|
||||||
# There are only 10 frags for obj2 and one is not durable.
|
# There are only 10 frags for obj2 and one is not durable.
|
||||||
obj2 = self._make_ec_object_stub(timestamp=self._ts_iter.next())
|
obj2 = self._make_ec_object_stub(pattern='obj2',
|
||||||
obj1 = self._make_ec_object_stub(timestamp=self._ts_iter.next())
|
timestamp=self._ts_iter.next())
|
||||||
|
obj1 = self._make_ec_object_stub(pattern='obj1',
|
||||||
|
timestamp=self._ts_iter.next())
|
||||||
|
|
||||||
node_frags = [
|
node_frags = [
|
||||||
[{'obj': obj1, 'frag': 0, 'durable': False}], # obj2 missing
|
[{'obj': obj1, 'frag': 0, 'durable': False}], # obj2 missing
|
||||||
@ -3287,8 +3297,8 @@ class TestECObjController(BaseObjectControllerMixin, unittest.TestCase):
|
|||||||
# fragments for different content at the same timestamp then the
|
# fragments for different content at the same timestamp then the
|
||||||
# object controller should handle it gracefully
|
# object controller should handle it gracefully
|
||||||
ts = self.ts() # force equal timestamps for two objects
|
ts = self.ts() # force equal timestamps for two objects
|
||||||
obj1 = self._make_ec_object_stub(timestamp=ts, test_body='obj1')
|
obj1 = self._make_ec_object_stub(timestamp=ts, pattern='obj1')
|
||||||
obj2 = self._make_ec_object_stub(timestamp=ts, test_body='obj2')
|
obj2 = self._make_ec_object_stub(timestamp=ts, pattern='obj2')
|
||||||
self.assertNotEqual(obj1['etag'], obj2['etag']) # sanity
|
self.assertNotEqual(obj1['etag'], obj2['etag']) # sanity
|
||||||
|
|
||||||
node_frags = [
|
node_frags = [
|
||||||
@ -3932,18 +3942,6 @@ class TestECDuplicationObjController(
|
|||||||
|
|
||||||
controller_cls = obj.ECObjectController
|
controller_cls = obj.ECObjectController
|
||||||
|
|
||||||
def _make_ec_object_stub(self, test_body=None, policy=None,
|
|
||||||
timestamp=None):
|
|
||||||
policy = policy or self.policy
|
|
||||||
return make_ec_object_stub(test_body, policy, timestamp)
|
|
||||||
|
|
||||||
def _make_ec_archive_bodies(self, test_body, policy=None):
|
|
||||||
policy = policy or self.policy
|
|
||||||
return encode_frag_archive_bodies(policy, test_body)
|
|
||||||
|
|
||||||
def _fake_ec_node_response(self, node_frags):
|
|
||||||
return fake_ec_node_response(node_frags, self.policy)
|
|
||||||
|
|
||||||
def _test_GET_with_duplication_factor(self, node_frags, obj):
|
def _test_GET_with_duplication_factor(self, node_frags, obj):
|
||||||
# This is basic tests in the healthy backends status
|
# This is basic tests in the healthy backends status
|
||||||
fake_response = self._fake_ec_node_response(node_frags)
|
fake_response = self._fake_ec_node_response(node_frags)
|
||||||
@ -4035,8 +4033,8 @@ class TestECDuplicationObjController(
|
|||||||
self._test_GET_with_duplication_factor(node_frags, obj)
|
self._test_GET_with_duplication_factor(node_frags, obj)
|
||||||
|
|
||||||
def test_GET_with_missing_and_mixed_frags_will_dig_deep_but_stop(self):
|
def test_GET_with_missing_and_mixed_frags_will_dig_deep_but_stop(self):
|
||||||
obj1 = self._make_ec_object_stub()
|
obj1 = self._make_ec_object_stub(pattern='obj1')
|
||||||
obj2 = self._make_ec_object_stub()
|
obj2 = self._make_ec_object_stub(pattern='obj2')
|
||||||
|
|
||||||
# both of obj1 and obj2 has only 9 frags which is not able to decode
|
# both of obj1 and obj2 has only 9 frags which is not able to decode
|
||||||
node_frags = [
|
node_frags = [
|
||||||
@ -4081,7 +4079,8 @@ class TestECDuplicationObjController(
|
|||||||
# default node_iter will exhaust to the last of handoffs
|
# default node_iter will exhaust to the last of handoffs
|
||||||
self.assertEqual(len(log), self.replicas() * 2)
|
self.assertEqual(len(log), self.replicas() * 2)
|
||||||
# we have obj1, obj2, and 404 NotFound in collected_responses
|
# we have obj1, obj2, and 404 NotFound in collected_responses
|
||||||
self.assertEqual(len(collected_responses), 3)
|
self.assertEqual(sorted([obj1['etag'], obj2['etag'], None]),
|
||||||
|
sorted(collected_responses.keys()))
|
||||||
|
|
||||||
# ... regardless we should never need to fetch more than ec_ndata
|
# ... regardless we should never need to fetch more than ec_ndata
|
||||||
# frags for any given etag
|
# frags for any given etag
|
||||||
@ -4134,8 +4133,8 @@ class TestECDuplicationObjController(
|
|||||||
self.assertEqual(len(collected_indexes), self.policy.ec_ndata - 1)
|
self.assertEqual(len(collected_indexes), self.policy.ec_ndata - 1)
|
||||||
|
|
||||||
def test_GET_with_many_missed_overwrite_will_need_handoff(self):
|
def test_GET_with_many_missed_overwrite_will_need_handoff(self):
|
||||||
obj1 = self._make_ec_object_stub()
|
obj1 = self._make_ec_object_stub(pattern='obj1')
|
||||||
obj2 = self._make_ec_object_stub()
|
obj2 = self._make_ec_object_stub(pattern='obj2')
|
||||||
# primaries
|
# primaries
|
||||||
node_frags = [
|
node_frags = [
|
||||||
{'obj': obj2, 'frag': 0},
|
{'obj': obj2, 'frag': 0},
|
||||||
@ -4239,8 +4238,10 @@ class TestECDuplicationObjController(
|
|||||||
self.assertEqual(len(collected_indexes), self.policy.ec_ndata)
|
self.assertEqual(len(collected_indexes), self.policy.ec_ndata)
|
||||||
|
|
||||||
def test_GET_with_missing_and_mixed_frags_will_dig_deep_but_succeed(self):
|
def test_GET_with_missing_and_mixed_frags_will_dig_deep_but_succeed(self):
|
||||||
obj1 = self._make_ec_object_stub(timestamp=self.ts())
|
obj1 = self._make_ec_object_stub(pattern='obj1',
|
||||||
obj2 = self._make_ec_object_stub(timestamp=self.ts())
|
timestamp=self.ts())
|
||||||
|
obj2 = self._make_ec_object_stub(pattern='obj2',
|
||||||
|
timestamp=self.ts())
|
||||||
|
|
||||||
# 28 nodes are here
|
# 28 nodes are here
|
||||||
node_frags = [
|
node_frags = [
|
||||||
@ -4312,13 +4313,13 @@ class TestECDuplicationObjController(
|
|||||||
# which means there is no backend 404 response, but proxy should still
|
# which means there is no backend 404 response, but proxy should still
|
||||||
# return 404 rather than 503
|
# return 404 rather than 503
|
||||||
stub_objects = [
|
stub_objects = [
|
||||||
self._make_ec_object_stub('obj1' * self.policy.ec_segment_size),
|
self._make_ec_object_stub(pattern='obj1'),
|
||||||
self._make_ec_object_stub('obj2' * self.policy.ec_segment_size),
|
self._make_ec_object_stub(pattern='obj2'),
|
||||||
self._make_ec_object_stub('obj3' * self.policy.ec_segment_size),
|
self._make_ec_object_stub(pattern='obj3'),
|
||||||
self._make_ec_object_stub('obj4' * self.policy.ec_segment_size),
|
self._make_ec_object_stub(pattern='obj4'),
|
||||||
self._make_ec_object_stub('obj5' * self.policy.ec_segment_size),
|
self._make_ec_object_stub(pattern='obj5'),
|
||||||
self._make_ec_object_stub('obj6' * self.policy.ec_segment_size),
|
self._make_ec_object_stub(pattern='obj6'),
|
||||||
self._make_ec_object_stub('obj7' * self.policy.ec_segment_size),
|
self._make_ec_object_stub(pattern='obj7'),
|
||||||
]
|
]
|
||||||
etags = collections.Counter(stub['etag'] for stub in stub_objects)
|
etags = collections.Counter(stub['etag'] for stub in stub_objects)
|
||||||
self.assertEqual(len(etags), 7, etags) # sanity
|
self.assertEqual(len(etags), 7, etags) # sanity
|
||||||
@ -4395,10 +4396,10 @@ class TestECDuplicationObjController(
|
|||||||
self.assertEqual(self.replicas() * 2, len(log))
|
self.assertEqual(self.replicas() * 2, len(log))
|
||||||
|
|
||||||
def test_GET_with_missing_and_mixed_frags_may_503(self):
|
def test_GET_with_missing_and_mixed_frags_may_503(self):
|
||||||
obj1 = self._make_ec_object_stub()
|
obj1 = self._make_ec_object_stub(pattern='obj1')
|
||||||
obj2 = self._make_ec_object_stub()
|
obj2 = self._make_ec_object_stub(pattern='obj2')
|
||||||
obj3 = self._make_ec_object_stub()
|
obj3 = self._make_ec_object_stub(pattern='obj3')
|
||||||
obj4 = self._make_ec_object_stub()
|
obj4 = self._make_ec_object_stub(pattern='obj4')
|
||||||
# we get a 503 when all the handoffs return 200
|
# we get a 503 when all the handoffs return 200
|
||||||
node_frags = [[]] * self.replicas() # primaries have no frags
|
node_frags = [[]] * self.replicas() # primaries have no frags
|
||||||
# plus, 4 different objects and 7 indexes will b 28 node responses
|
# plus, 4 different objects and 7 indexes will b 28 node responses
|
||||||
@ -4454,8 +4455,8 @@ class TestECDuplicationObjController(
|
|||||||
# the difference from parent class is only handoff stub length
|
# the difference from parent class is only handoff stub length
|
||||||
|
|
||||||
ts = self.ts() # force equal timestamps for two objects
|
ts = self.ts() # force equal timestamps for two objects
|
||||||
obj1 = self._make_ec_object_stub(timestamp=ts, test_body='obj1')
|
obj1 = self._make_ec_object_stub(timestamp=ts, pattern='obj1')
|
||||||
obj2 = self._make_ec_object_stub(timestamp=ts, test_body='obj2')
|
obj2 = self._make_ec_object_stub(timestamp=ts, pattern='obj2')
|
||||||
self.assertNotEqual(obj1['etag'], obj2['etag']) # sanity
|
self.assertNotEqual(obj1['etag'], obj2['etag']) # sanity
|
||||||
|
|
||||||
node_frags = [
|
node_frags = [
|
||||||
|
Loading…
Reference in New Issue
Block a user