Unify expirer unit test task queue
To simplify unit tests for object-expirer, this patch unifies expirer's task queue for each unit tests. In this patch, following changes are applied: 1: Unify expirer's task queue 2: Remove redundant log checking, because some tests checks logs in their speciality 3: Use mocked methods instead of dummy methods which raises specialized message exception Change-Id: I839f0bb43eb827384727356877e33a6be7d9b81d
This commit is contained in:
parent
cb51a0a00b
commit
bac79f2dae
@ -19,6 +19,7 @@ from test.unit import FakeRing, mocked_http_conn, debug_logger
|
|||||||
from tempfile import mkdtemp
|
from tempfile import mkdtemp
|
||||||
from shutil import rmtree
|
from shutil import rmtree
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
from copy import deepcopy
|
||||||
|
|
||||||
import mock
|
import mock
|
||||||
import six
|
import six
|
||||||
@ -68,8 +69,8 @@ class FakeInternalClient(object):
|
|||||||
|
|
||||||
def iter_containers(self, account, prefix=''):
|
def iter_containers(self, account, prefix=''):
|
||||||
acc_dict = self.aco_dict[account]
|
acc_dict = self.aco_dict[account]
|
||||||
return [{'name': six.text_type(container)} for container in
|
return sorted([{'name': six.text_type(container)} for container in
|
||||||
acc_dict if container.startswith(prefix)]
|
acc_dict if container.startswith(prefix)])
|
||||||
|
|
||||||
def delete_container(*a, **kw):
|
def delete_container(*a, **kw):
|
||||||
pass
|
pass
|
||||||
@ -100,6 +101,41 @@ class TestObjectExpirer(TestCase):
|
|||||||
self.conf = {'recon_cache_path': self.rcache}
|
self.conf = {'recon_cache_path': self.rcache}
|
||||||
self.logger = debug_logger('test-expirer')
|
self.logger = debug_logger('test-expirer')
|
||||||
|
|
||||||
|
self.past_time = str(int(time() - 86400))
|
||||||
|
self.future_time = str(int(time() + 86400))
|
||||||
|
# Dummy task queue for test
|
||||||
|
self.fake_swift = FakeInternalClient({
|
||||||
|
'.expiring_objects': {
|
||||||
|
# this task container will be checked
|
||||||
|
self.past_time: [
|
||||||
|
# tasks ready for execution
|
||||||
|
self.past_time + '-a0/c0/o0',
|
||||||
|
self.past_time + '-a1/c1/o1',
|
||||||
|
self.past_time + '-a2/c2/o2',
|
||||||
|
self.past_time + '-a3/c3/o3',
|
||||||
|
self.past_time + '-a4/c4/o4',
|
||||||
|
self.past_time + '-a5/c5/o5',
|
||||||
|
self.past_time + '-a6/c6/o6',
|
||||||
|
self.past_time + '-a7/c7/o7',
|
||||||
|
# task objects for unicode test
|
||||||
|
self.past_time + u'-a8/c8/o8\u2661',
|
||||||
|
self.past_time + u'-a9/c9/o9\xf8',
|
||||||
|
# this task will be skipped
|
||||||
|
self.future_time + '-a10/c10/o10'],
|
||||||
|
# this task container will be skipped
|
||||||
|
self.future_time: [
|
||||||
|
self.future_time + '-a11/c11/o11']}
|
||||||
|
})
|
||||||
|
self.expirer = expirer.ObjectExpirer(self.conf, logger=self.logger,
|
||||||
|
swift=self.fake_swift)
|
||||||
|
|
||||||
|
# target object paths which should be expirerd now
|
||||||
|
self.expired_target_path_list = [
|
||||||
|
'a0/c0/o0', 'a1/c1/o1', 'a2/c2/o2', 'a3/c3/o3', 'a4/c4/o4',
|
||||||
|
'a5/c5/o5', 'a6/c6/o6', 'a7/c7/o7',
|
||||||
|
'a8/c8/o8\xe2\x99\xa1', 'a9/c9/o9\xc3\xb8',
|
||||||
|
]
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
rmtree(self.rcache)
|
rmtree(self.rcache)
|
||||||
internal_client.sleep = self.old_sleep
|
internal_client.sleep = self.old_sleep
|
||||||
@ -220,16 +256,7 @@ class TestObjectExpirer(TestCase):
|
|||||||
self.deleted_objects[task_container] = set()
|
self.deleted_objects[task_container] = set()
|
||||||
self.deleted_objects[task_container].add(task_object)
|
self.deleted_objects[task_container].add(task_object)
|
||||||
|
|
||||||
aco_dict = {
|
x = ObjectExpirer(self.conf, swift=self.fake_swift)
|
||||||
'.expiring_objects': {
|
|
||||||
'0': set('1-a/c/one 2-a/c/two 3-a/c/three'.split()),
|
|
||||||
'1': set('2-a/c/two 3-a/c/three 4-a/c/four'.split()),
|
|
||||||
'2': set('5-a/c/five 6-a/c/six'.split()),
|
|
||||||
'3': set(u'7-a/c/seven\u2661'.split()),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
fake_swift = FakeInternalClient(aco_dict)
|
|
||||||
x = ObjectExpirer(self.conf, swift=fake_swift)
|
|
||||||
|
|
||||||
deleted_objects = defaultdict(set)
|
deleted_objects = defaultdict(set)
|
||||||
for i in range(3):
|
for i in range(3):
|
||||||
@ -240,9 +267,15 @@ class TestObjectExpirer(TestCase):
|
|||||||
for task_container, deleted in x.deleted_objects.items():
|
for task_container, deleted in x.deleted_objects.items():
|
||||||
self.assertFalse(deleted_objects[task_container] & deleted)
|
self.assertFalse(deleted_objects[task_container] & deleted)
|
||||||
deleted_objects[task_container] |= deleted
|
deleted_objects[task_container] |= deleted
|
||||||
self.assertEqual(aco_dict['.expiring_objects']['3'].pop(),
|
|
||||||
deleted_objects['3'].pop().decode('utf8'))
|
# sort for comparison
|
||||||
self.assertEqual(aco_dict['.expiring_objects'], deleted_objects)
|
deleted_objects = {
|
||||||
|
con: sorted(o_set) for con, o_set in deleted_objects.items()}
|
||||||
|
expected = {
|
||||||
|
self.past_time: [
|
||||||
|
self.past_time + '-' + target_path
|
||||||
|
for target_path in self.expired_target_path_list]}
|
||||||
|
self.assertEqual(deleted_objects, expected)
|
||||||
|
|
||||||
def test_delete_object(self):
|
def test_delete_object(self):
|
||||||
x = expirer.ObjectExpirer({}, logger=self.logger)
|
x = expirer.ObjectExpirer({}, logger=self.logger)
|
||||||
@ -341,66 +374,66 @@ class TestObjectExpirer(TestCase):
|
|||||||
assert_parse_task_obj('1000-a/c/o', 1000, 'a', 'c', 'o')
|
assert_parse_task_obj('1000-a/c/o', 1000, 'a', 'c', 'o')
|
||||||
assert_parse_task_obj('0000-acc/con/obj', 0, 'acc', 'con', 'obj')
|
assert_parse_task_obj('0000-acc/con/obj', 0, 'acc', 'con', 'obj')
|
||||||
|
|
||||||
def test_round_robin_order(self):
|
def make_task(self, delete_at, target):
|
||||||
def make_task(delete_at, target):
|
return {
|
||||||
return {
|
'task_account': '.expiring_objects',
|
||||||
'task_account': '.expiring_objects',
|
'task_container': delete_at,
|
||||||
'task_container': delete_at,
|
'task_object': delete_at + '-' + target,
|
||||||
'task_object': delete_at + '-' + target,
|
'delete_timestamp': Timestamp(delete_at),
|
||||||
'delete_timestamp': Timestamp(delete_at),
|
'target_path': target,
|
||||||
'target_path': target,
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
def test_round_robin_order(self):
|
||||||
x = expirer.ObjectExpirer(self.conf, logger=self.logger)
|
x = expirer.ObjectExpirer(self.conf, logger=self.logger)
|
||||||
task_con_obj_list = [
|
task_con_obj_list = [
|
||||||
# objects in 0000 timestamp container
|
# objects in 0000 timestamp container
|
||||||
make_task('0000', 'a/c0/o0'),
|
self.make_task('0000', 'a/c0/o0'),
|
||||||
make_task('0000', 'a/c0/o1'),
|
self.make_task('0000', 'a/c0/o1'),
|
||||||
# objects in 0001 timestamp container
|
# objects in 0001 timestamp container
|
||||||
make_task('0001', 'a/c1/o0'),
|
self.make_task('0001', 'a/c1/o0'),
|
||||||
make_task('0001', 'a/c1/o1'),
|
self.make_task('0001', 'a/c1/o1'),
|
||||||
# objects in 0002 timestamp container
|
# objects in 0002 timestamp container
|
||||||
make_task('0002', 'a/c2/o0'),
|
self.make_task('0002', 'a/c2/o0'),
|
||||||
make_task('0002', 'a/c2/o1'),
|
self.make_task('0002', 'a/c2/o1'),
|
||||||
]
|
]
|
||||||
result = list(x.round_robin_order(task_con_obj_list))
|
result = list(x.round_robin_order(task_con_obj_list))
|
||||||
|
|
||||||
# sorted by popping one object to delete for each target_container
|
# sorted by popping one object to delete for each target_container
|
||||||
expected = [
|
expected = [
|
||||||
make_task('0000', 'a/c0/o0'),
|
self.make_task('0000', 'a/c0/o0'),
|
||||||
make_task('0001', 'a/c1/o0'),
|
self.make_task('0001', 'a/c1/o0'),
|
||||||
make_task('0002', 'a/c2/o0'),
|
self.make_task('0002', 'a/c2/o0'),
|
||||||
make_task('0000', 'a/c0/o1'),
|
self.make_task('0000', 'a/c0/o1'),
|
||||||
make_task('0001', 'a/c1/o1'),
|
self.make_task('0001', 'a/c1/o1'),
|
||||||
make_task('0002', 'a/c2/o1'),
|
self.make_task('0002', 'a/c2/o1'),
|
||||||
]
|
]
|
||||||
self.assertEqual(expected, result)
|
self.assertEqual(expected, result)
|
||||||
|
|
||||||
# task containers have some task objects with invalid target paths
|
# task containers have some task objects with invalid target paths
|
||||||
task_con_obj_list = [
|
task_con_obj_list = [
|
||||||
# objects in 0000 timestamp container
|
# objects in 0000 timestamp container
|
||||||
make_task('0000', 'invalid0'),
|
self.make_task('0000', 'invalid0'),
|
||||||
make_task('0000', 'a/c0/o0'),
|
self.make_task('0000', 'a/c0/o0'),
|
||||||
make_task('0000', 'a/c0/o1'),
|
self.make_task('0000', 'a/c0/o1'),
|
||||||
# objects in 0001 timestamp container
|
# objects in 0001 timestamp container
|
||||||
make_task('0001', 'a/c1/o0'),
|
self.make_task('0001', 'a/c1/o0'),
|
||||||
make_task('0001', 'invalid1'),
|
self.make_task('0001', 'invalid1'),
|
||||||
make_task('0001', 'a/c1/o1'),
|
self.make_task('0001', 'a/c1/o1'),
|
||||||
# objects in 0002 timestamp container
|
# objects in 0002 timestamp container
|
||||||
make_task('0002', 'a/c2/o0'),
|
self.make_task('0002', 'a/c2/o0'),
|
||||||
make_task('0002', 'a/c2/o1'),
|
self.make_task('0002', 'a/c2/o1'),
|
||||||
make_task('0002', 'invalid2'),
|
self.make_task('0002', 'invalid2'),
|
||||||
]
|
]
|
||||||
result = list(x.round_robin_order(task_con_obj_list))
|
result = list(x.round_robin_order(task_con_obj_list))
|
||||||
|
|
||||||
# the invalid task objects are ignored
|
# the invalid task objects are ignored
|
||||||
expected = [
|
expected = [
|
||||||
make_task('0000', 'a/c0/o0'),
|
self.make_task('0000', 'a/c0/o0'),
|
||||||
make_task('0001', 'a/c1/o0'),
|
self.make_task('0001', 'a/c1/o0'),
|
||||||
make_task('0002', 'a/c2/o0'),
|
self.make_task('0002', 'a/c2/o0'),
|
||||||
make_task('0000', 'a/c0/o1'),
|
self.make_task('0000', 'a/c0/o1'),
|
||||||
make_task('0001', 'a/c1/o1'),
|
self.make_task('0001', 'a/c1/o1'),
|
||||||
make_task('0002', 'a/c2/o1'),
|
self.make_task('0002', 'a/c2/o1'),
|
||||||
]
|
]
|
||||||
self.assertEqual(expected, result)
|
self.assertEqual(expected, result)
|
||||||
|
|
||||||
@ -408,51 +441,51 @@ class TestObjectExpirer(TestCase):
|
|||||||
# the same timestamp container
|
# the same timestamp container
|
||||||
task_con_obj_list = [
|
task_con_obj_list = [
|
||||||
# objects in 0000 timestamp container
|
# objects in 0000 timestamp container
|
||||||
make_task('0000', 'a/c0/o0'),
|
self.make_task('0000', 'a/c0/o0'),
|
||||||
make_task('0000', 'a/c0/o1'),
|
self.make_task('0000', 'a/c0/o1'),
|
||||||
make_task('0000', 'a/c2/o2'),
|
self.make_task('0000', 'a/c2/o2'),
|
||||||
make_task('0000', 'a/c2/o3'),
|
self.make_task('0000', 'a/c2/o3'),
|
||||||
# objects in 0001 timestamp container
|
# objects in 0001 timestamp container
|
||||||
make_task('0001', 'a/c0/o2'),
|
self.make_task('0001', 'a/c0/o2'),
|
||||||
make_task('0001', 'a/c0/o3'),
|
self.make_task('0001', 'a/c0/o3'),
|
||||||
make_task('0001', 'a/c1/o0'),
|
self.make_task('0001', 'a/c1/o0'),
|
||||||
make_task('0001', 'a/c1/o1'),
|
self.make_task('0001', 'a/c1/o1'),
|
||||||
# objects in 0002 timestamp container
|
# objects in 0002 timestamp container
|
||||||
make_task('0002', 'a/c2/o0'),
|
self.make_task('0002', 'a/c2/o0'),
|
||||||
make_task('0002', 'a/c2/o1'),
|
self.make_task('0002', 'a/c2/o1'),
|
||||||
]
|
]
|
||||||
result = list(x.round_robin_order(task_con_obj_list))
|
result = list(x.round_robin_order(task_con_obj_list))
|
||||||
|
|
||||||
# so we go around popping by *target* container, not *task* container
|
# so we go around popping by *target* container, not *task* container
|
||||||
expected = [
|
expected = [
|
||||||
make_task('0000', 'a/c0/o0'),
|
self.make_task('0000', 'a/c0/o0'),
|
||||||
make_task('0001', 'a/c1/o0'),
|
self.make_task('0001', 'a/c1/o0'),
|
||||||
make_task('0000', 'a/c2/o2'),
|
self.make_task('0000', 'a/c2/o2'),
|
||||||
make_task('0000', 'a/c0/o1'),
|
self.make_task('0000', 'a/c0/o1'),
|
||||||
make_task('0001', 'a/c1/o1'),
|
self.make_task('0001', 'a/c1/o1'),
|
||||||
make_task('0000', 'a/c2/o3'),
|
self.make_task('0000', 'a/c2/o3'),
|
||||||
make_task('0001', 'a/c0/o2'),
|
self.make_task('0001', 'a/c0/o2'),
|
||||||
make_task('0002', 'a/c2/o0'),
|
self.make_task('0002', 'a/c2/o0'),
|
||||||
make_task('0001', 'a/c0/o3'),
|
self.make_task('0001', 'a/c0/o3'),
|
||||||
make_task('0002', 'a/c2/o1'),
|
self.make_task('0002', 'a/c2/o1'),
|
||||||
]
|
]
|
||||||
self.assertEqual(expected, result)
|
self.assertEqual(expected, result)
|
||||||
|
|
||||||
# all of the work to be done could be for different target containers
|
# all of the work to be done could be for different target containers
|
||||||
task_con_obj_list = [
|
task_con_obj_list = [
|
||||||
# objects in 0000 timestamp container
|
# objects in 0000 timestamp container
|
||||||
make_task('0000', 'a/c0/o'),
|
self.make_task('0000', 'a/c0/o'),
|
||||||
make_task('0000', 'a/c1/o'),
|
self.make_task('0000', 'a/c1/o'),
|
||||||
make_task('0000', 'a/c2/o'),
|
self.make_task('0000', 'a/c2/o'),
|
||||||
make_task('0000', 'a/c3/o'),
|
self.make_task('0000', 'a/c3/o'),
|
||||||
# objects in 0001 timestamp container
|
# objects in 0001 timestamp container
|
||||||
make_task('0001', 'a/c4/o'),
|
self.make_task('0001', 'a/c4/o'),
|
||||||
make_task('0001', 'a/c5/o'),
|
self.make_task('0001', 'a/c5/o'),
|
||||||
make_task('0001', 'a/c6/o'),
|
self.make_task('0001', 'a/c6/o'),
|
||||||
make_task('0001', 'a/c7/o'),
|
self.make_task('0001', 'a/c7/o'),
|
||||||
# objects in 0002 timestamp container
|
# objects in 0002 timestamp container
|
||||||
make_task('0002', 'a/c8/o'),
|
self.make_task('0002', 'a/c8/o'),
|
||||||
make_task('0002', 'a/c9/o'),
|
self.make_task('0002', 'a/c9/o'),
|
||||||
]
|
]
|
||||||
result = list(x.round_robin_order(task_con_obj_list))
|
result = list(x.round_robin_order(task_con_obj_list))
|
||||||
|
|
||||||
@ -500,18 +533,14 @@ class TestObjectExpirer(TestCase):
|
|||||||
"'str' object has no attribute 'get_account_info'")
|
"'str' object has no attribute 'get_account_info'")
|
||||||
|
|
||||||
def test_run_once_calls_report(self):
|
def test_run_once_calls_report(self):
|
||||||
fake_swift = FakeInternalClient({
|
with mock.patch.object(self.expirer, 'pop_queue',
|
||||||
'.expiring_objects': {u'1234': [u'1234-a/c/troms\xf8']}
|
lambda a, c, o: None):
|
||||||
})
|
self.expirer.run_once()
|
||||||
x = expirer.ObjectExpirer(self.conf, logger=self.logger,
|
|
||||||
swift=fake_swift)
|
|
||||||
with mock.patch.object(x, 'pop_queue', lambda a, c, o: None):
|
|
||||||
x.run_once()
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
x.logger.get_lines_for_level('info'), [
|
self.expirer.logger.get_lines_for_level('info'), [
|
||||||
'Pass beginning for task account .expiring_objects; '
|
'Pass beginning for task account .expiring_objects; '
|
||||||
'1 possible containers; 1 possible objects',
|
'2 possible containers; 12 possible objects',
|
||||||
'Pass completed in 0s; 1 objects expired',
|
'Pass completed in 0s; 10 objects expired',
|
||||||
])
|
])
|
||||||
|
|
||||||
def test_skip_task_account_without_task_container(self):
|
def test_skip_task_account_without_task_container(self):
|
||||||
@ -528,62 +557,30 @@ class TestObjectExpirer(TestCase):
|
|||||||
])
|
])
|
||||||
|
|
||||||
def test_iter_task_to_expire(self):
|
def test_iter_task_to_expire(self):
|
||||||
fake_swift = FakeInternalClient({
|
|
||||||
'.expiring_objects': {
|
|
||||||
u'1234': ['1234-a0/c0/o0', '1234-a1/c1/o1'],
|
|
||||||
u'2000': ['2000-a2/c2/o2', '2000-a3/c3/o3'],
|
|
||||||
}
|
|
||||||
})
|
|
||||||
x = expirer.ObjectExpirer(self.conf, logger=self.logger,
|
|
||||||
swift=fake_swift)
|
|
||||||
|
|
||||||
# In this test, all tasks are assigned to the tested expirer
|
# In this test, all tasks are assigned to the tested expirer
|
||||||
my_index = 0
|
my_index = 0
|
||||||
divisor = 1
|
divisor = 1
|
||||||
|
|
||||||
task_account_container_list = [('.expiring_objects', u'1234'),
|
task_account_container_list = [('.expiring_objects', self.past_time)]
|
||||||
('.expiring_objects', u'2000')]
|
|
||||||
|
|
||||||
expected = [{
|
expected = [
|
||||||
'task_account': '.expiring_objects',
|
self.make_task(self.past_time, target_path)
|
||||||
'task_container': u'1234',
|
for target_path in self.expired_target_path_list]
|
||||||
'task_object': '1234-a0/c0/o0',
|
|
||||||
'target_path': 'a0/c0/o0',
|
|
||||||
'delete_timestamp': Timestamp(1234),
|
|
||||||
}, {
|
|
||||||
'task_account': '.expiring_objects',
|
|
||||||
'task_container': u'1234',
|
|
||||||
'task_object': '1234-a1/c1/o1',
|
|
||||||
'target_path': 'a1/c1/o1',
|
|
||||||
'delete_timestamp': Timestamp(1234),
|
|
||||||
}, {
|
|
||||||
'task_account': '.expiring_objects',
|
|
||||||
'task_container': u'2000',
|
|
||||||
'task_object': '2000-a2/c2/o2',
|
|
||||||
'target_path': 'a2/c2/o2',
|
|
||||||
'delete_timestamp': Timestamp(2000),
|
|
||||||
}, {
|
|
||||||
'task_account': '.expiring_objects',
|
|
||||||
'task_container': u'2000',
|
|
||||||
'task_object': '2000-a3/c3/o3',
|
|
||||||
'target_path': 'a3/c3/o3',
|
|
||||||
'delete_timestamp': Timestamp(2000),
|
|
||||||
}]
|
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
list(x.iter_task_to_expire(
|
list(self.expirer.iter_task_to_expire(
|
||||||
task_account_container_list, my_index, divisor)),
|
task_account_container_list, my_index, divisor)),
|
||||||
expected)
|
expected)
|
||||||
|
|
||||||
# the task queue has invalid task object
|
# the task queue has invalid task object
|
||||||
fake_swift = FakeInternalClient({
|
invalid_aco_dict = deepcopy(self.fake_swift.aco_dict)
|
||||||
'.expiring_objects': {
|
invalid_aco_dict['.expiring_objects'][self.past_time].insert(
|
||||||
u'1234': ['1234-invalid', '1234-a0/c0/o0', '1234-a1/c1/o1'],
|
0, self.past_time + '-invalid0')
|
||||||
u'2000': ['2000-a2/c2/o2', '2000-invalid', '2000-a3/c3/o3'],
|
invalid_aco_dict['.expiring_objects'][self.past_time].insert(
|
||||||
}
|
5, self.past_time + '-invalid1')
|
||||||
})
|
invalid_fake_swift = FakeInternalClient(invalid_aco_dict)
|
||||||
x = expirer.ObjectExpirer(self.conf, logger=self.logger,
|
x = expirer.ObjectExpirer(self.conf, logger=self.logger,
|
||||||
swift=fake_swift)
|
swift=invalid_fake_swift)
|
||||||
|
|
||||||
# but the invalid tasks are skipped
|
# but the invalid tasks are skipped
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
@ -592,161 +589,72 @@ class TestObjectExpirer(TestCase):
|
|||||||
expected)
|
expected)
|
||||||
|
|
||||||
def test_run_once_unicode_problem(self):
|
def test_run_once_unicode_problem(self):
|
||||||
fake_swift = FakeInternalClient({
|
|
||||||
'.expiring_objects': {u'1234': [u'1234-a/c/troms\xf8']}
|
|
||||||
})
|
|
||||||
x = expirer.ObjectExpirer(self.conf, logger=self.logger,
|
|
||||||
swift=fake_swift)
|
|
||||||
|
|
||||||
requests = []
|
requests = []
|
||||||
|
|
||||||
def capture_requests(ipaddr, port, method, path, *args, **kwargs):
|
def capture_requests(ipaddr, port, method, path, *args, **kwargs):
|
||||||
requests.append((method, path))
|
requests.append((method, path))
|
||||||
|
|
||||||
with mocked_http_conn(200, 200, 200, give_connect=capture_requests):
|
# 3 DELETE requests for each 10 executed task objects to pop_queue
|
||||||
x.run_once()
|
code_list = [200] * 3 * 10
|
||||||
self.assertEqual(len(requests), 3)
|
with mocked_http_conn(*code_list, give_connect=capture_requests):
|
||||||
|
self.expirer.run_once()
|
||||||
|
self.assertEqual(len(requests), 30)
|
||||||
|
|
||||||
def test_container_timestamp_break(self):
|
def test_container_timestamp_break(self):
|
||||||
def fail_to_iter_objects(*a, **kw):
|
with mock.patch.object(self.fake_swift, 'iter_objects') as mock_method:
|
||||||
raise Exception('This should not have been called')
|
self.expirer.run_once()
|
||||||
|
|
||||||
fake_swift = FakeInternalClient({
|
# iter_objects is called only for past_time, not future_time
|
||||||
'.expiring_objects': {str(int(time() + 86400)): ['1234-a/c/o']}
|
self.assertEqual(mock_method.call_args_list,
|
||||||
})
|
[mock.call('.expiring_objects', self.past_time)])
|
||||||
x = expirer.ObjectExpirer(self.conf, logger=self.logger,
|
|
||||||
swift=fake_swift)
|
|
||||||
with mock.patch.object(fake_swift, 'iter_objects',
|
|
||||||
fail_to_iter_objects):
|
|
||||||
x.run_once()
|
|
||||||
logs = x.logger.all_log_lines()
|
|
||||||
self.assertEqual(logs['info'], [
|
|
||||||
'Pass beginning for task account .expiring_objects; '
|
|
||||||
'1 possible containers; 1 possible objects',
|
|
||||||
'Pass completed in 0s; 0 objects expired',
|
|
||||||
])
|
|
||||||
self.assertNotIn('error', logs)
|
|
||||||
|
|
||||||
# Reverse test to be sure it still would blow up the way expected.
|
|
||||||
fake_swift = FakeInternalClient({
|
|
||||||
'.expiring_objects': {str(int(time() - 86400)): ['1234-a/c/o']}
|
|
||||||
})
|
|
||||||
x = expirer.ObjectExpirer(self.conf, logger=self.logger,
|
|
||||||
swift=fake_swift)
|
|
||||||
with mock.patch.object(fake_swift, 'iter_objects',
|
|
||||||
fail_to_iter_objects):
|
|
||||||
x.run_once()
|
|
||||||
self.assertEqual(
|
|
||||||
x.logger.get_lines_for_level('error'), ['Unhandled exception: '])
|
|
||||||
log_args, log_kwargs = x.logger.log_dict['error'][-1]
|
|
||||||
self.assertEqual(str(log_kwargs['exc_info'][1]),
|
|
||||||
'This should not have been called')
|
|
||||||
|
|
||||||
def test_object_timestamp_break(self):
|
def test_object_timestamp_break(self):
|
||||||
def should_not_be_called(*a, **kw):
|
with mock.patch.object(self.expirer, 'delete_actual_object') \
|
||||||
raise Exception('This should not have been called')
|
as mock_method, \
|
||||||
|
mock.patch.object(self.expirer, 'pop_queue'):
|
||||||
|
self.expirer.run_once()
|
||||||
|
|
||||||
fake_swift = FakeInternalClient({
|
# executed tasks are with past time
|
||||||
'.expiring_objects': {
|
|
||||||
str(int(time() - 86400)): [
|
|
||||||
'%d-a/c/actual-obj' % int(time() + 86400)],
|
|
||||||
},
|
|
||||||
})
|
|
||||||
x = expirer.ObjectExpirer(self.conf, logger=self.logger,
|
|
||||||
swift=fake_swift)
|
|
||||||
x.run_once()
|
|
||||||
self.assertNotIn('error', x.logger.all_log_lines())
|
|
||||||
self.assertEqual(x.logger.get_lines_for_level('info'), [
|
|
||||||
'Pass beginning for task account .expiring_objects; '
|
|
||||||
'1 possible containers; 1 possible objects',
|
|
||||||
'Pass completed in 0s; 0 objects expired',
|
|
||||||
])
|
|
||||||
# Reverse test to be sure it still would blow up the way expected.
|
|
||||||
ts = int(time() - 86400)
|
|
||||||
fake_swift = FakeInternalClient({
|
|
||||||
'.expiring_objects': {
|
|
||||||
str(int(time() - 86400)): ['%d-a/c/actual-obj' % ts],
|
|
||||||
},
|
|
||||||
})
|
|
||||||
x = expirer.ObjectExpirer(self.conf, logger=self.logger,
|
|
||||||
swift=fake_swift)
|
|
||||||
x.delete_actual_object = should_not_be_called
|
|
||||||
x.run_once()
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
x.logger.get_lines_for_level('error'),
|
mock_method.call_args_list,
|
||||||
['Exception while deleting object .expiring_objects '
|
[mock.call(target_path, self.past_time)
|
||||||
'%d %d-a/c/actual-obj This should not have been called: ' %
|
for target_path in self.expired_target_path_list])
|
||||||
(ts, ts)])
|
|
||||||
|
|
||||||
def test_failed_delete_keeps_entry(self):
|
def test_failed_delete_keeps_entry(self):
|
||||||
def deliberately_blow_up(actual_obj, timestamp):
|
def deliberately_blow_up(actual_obj, timestamp):
|
||||||
raise Exception('failed to delete actual object')
|
raise Exception('failed to delete actual object')
|
||||||
|
|
||||||
def should_not_get_called(account, container, obj):
|
# any tasks are not done
|
||||||
raise Exception('This should not have been called')
|
with mock.patch.object(self.expirer, 'delete_actual_object',
|
||||||
|
deliberately_blow_up), \
|
||||||
|
mock.patch.object(self.expirer, 'pop_queue') as mock_method:
|
||||||
|
self.expirer.run_once()
|
||||||
|
|
||||||
ts = int(time() - 86400)
|
# no tasks are popped from the queue
|
||||||
fake_swift = FakeInternalClient({
|
self.assertEqual(mock_method.call_args_list, [])
|
||||||
'.expiring_objects': {
|
|
||||||
str(int(time() - 86400)): ['%d-a/c/actual-obj' % ts],
|
|
||||||
},
|
|
||||||
})
|
|
||||||
x = expirer.ObjectExpirer(self.conf, logger=self.logger,
|
|
||||||
swift=fake_swift)
|
|
||||||
x.delete_actual_object = deliberately_blow_up
|
|
||||||
x.pop_queue = should_not_get_called
|
|
||||||
x.run_once()
|
|
||||||
self.assertEqual(
|
|
||||||
x.logger.get_lines_for_level('error'),
|
|
||||||
['Exception while deleting object .expiring_objects '
|
|
||||||
'%d %d-a/c/actual-obj failed to delete actual object: ' %
|
|
||||||
(ts, ts)])
|
|
||||||
self.assertEqual(
|
|
||||||
x.logger.get_lines_for_level('info'), [
|
|
||||||
'Pass beginning for task account .expiring_objects; '
|
|
||||||
'1 possible containers; 1 possible objects',
|
|
||||||
'Pass completed in 0s; 0 objects expired',
|
|
||||||
])
|
|
||||||
|
|
||||||
# Reverse test to be sure it still would blow up the way expected.
|
# all tasks are done
|
||||||
ts = int(time() - 86400)
|
with mock.patch.object(self.expirer, 'delete_actual_object',
|
||||||
fake_swift = FakeInternalClient({
|
lambda o, t: None), \
|
||||||
'.expiring_objects': {
|
mock.patch.object(self.expirer, 'pop_queue') as mock_method:
|
||||||
str(int(time() - 86400)): ['%d-a/c/actual-obj' % ts],
|
self.expirer.run_once()
|
||||||
},
|
|
||||||
})
|
# all tasks are popped from the queue
|
||||||
self.logger._clear()
|
|
||||||
x = expirer.ObjectExpirer(self.conf, logger=self.logger,
|
|
||||||
swift=fake_swift)
|
|
||||||
x.delete_actual_object = lambda o, t: None
|
|
||||||
x.pop_queue = should_not_get_called
|
|
||||||
x.run_once()
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.logger.get_lines_for_level('error'),
|
mock_method.call_args_list,
|
||||||
['Exception while deleting object .expiring_objects '
|
[mock.call('.expiring_objects', self.past_time,
|
||||||
'%d %d-a/c/actual-obj This should not have been called: ' %
|
self.past_time + '-' + target_path)
|
||||||
(ts, ts)])
|
for target_path in self.expired_target_path_list])
|
||||||
|
|
||||||
def test_success_gets_counted(self):
|
def test_success_gets_counted(self):
|
||||||
fake_swift = FakeInternalClient({
|
self.assertEqual(self.expirer.report_objects, 0)
|
||||||
'.expiring_objects': {
|
with mock.patch('swift.obj.expirer.MAX_OBJECTS_TO_CACHE', 0), \
|
||||||
str(int(time() - 86400)): [
|
mock.patch.object(self.expirer, 'delete_actual_object',
|
||||||
'%d-acc/c/actual-obj' % int(time() - 86400)],
|
lambda o, t: None), \
|
||||||
},
|
mock.patch.object(self.expirer, 'pop_queue',
|
||||||
})
|
lambda a, c, o: None):
|
||||||
x = expirer.ObjectExpirer(self.conf, logger=self.logger,
|
self.expirer.run_once()
|
||||||
swift=fake_swift)
|
self.assertEqual(self.expirer.report_objects, 10)
|
||||||
x.delete_actual_object = lambda o, t: None
|
|
||||||
x.pop_queue = lambda a, c, o: None
|
|
||||||
self.assertEqual(x.report_objects, 0)
|
|
||||||
with mock.patch('swift.obj.expirer.MAX_OBJECTS_TO_CACHE', 0):
|
|
||||||
x.run_once()
|
|
||||||
self.assertEqual(x.report_objects, 1)
|
|
||||||
self.assertEqual(
|
|
||||||
x.logger.get_lines_for_level('info'),
|
|
||||||
['Pass beginning for task account .expiring_objects; '
|
|
||||||
'1 possible containers; 1 possible objects',
|
|
||||||
'Pass completed in 0s; 1 objects expired'])
|
|
||||||
|
|
||||||
def test_delete_actual_object_does_not_get_unicode(self):
|
def test_delete_actual_object_does_not_get_unicode(self):
|
||||||
got_unicode = [False]
|
got_unicode = [False]
|
||||||
@ -755,25 +663,15 @@ class TestObjectExpirer(TestCase):
|
|||||||
if isinstance(actual_obj, six.text_type):
|
if isinstance(actual_obj, six.text_type):
|
||||||
got_unicode[0] = True
|
got_unicode[0] = True
|
||||||
|
|
||||||
fake_swift = FakeInternalClient({
|
self.assertEqual(self.expirer.report_objects, 0)
|
||||||
'.expiring_objects': {
|
|
||||||
str(int(time() - 86400)): [
|
with mock.patch.object(self.expirer, 'delete_actual_object',
|
||||||
'%d-a/c/actual-obj' % int(time() - 86400)],
|
delete_actual_object_test_for_unicode), \
|
||||||
},
|
mock.patch.object(self.expirer, 'pop_queue',
|
||||||
})
|
lambda a, c, o: None):
|
||||||
x = expirer.ObjectExpirer(self.conf, logger=self.logger,
|
self.expirer.run_once()
|
||||||
swift=fake_swift)
|
|
||||||
x.delete_actual_object = delete_actual_object_test_for_unicode
|
self.assertEqual(self.expirer.report_objects, 10)
|
||||||
x.pop_queue = lambda a, c, o: None
|
|
||||||
self.assertEqual(x.report_objects, 0)
|
|
||||||
x.run_once()
|
|
||||||
self.assertEqual(x.report_objects, 1)
|
|
||||||
self.assertEqual(
|
|
||||||
x.logger.get_lines_for_level('info'), [
|
|
||||||
'Pass beginning for task account .expiring_objects; '
|
|
||||||
'1 possible containers; 1 possible objects',
|
|
||||||
'Pass completed in 0s; 1 objects expired',
|
|
||||||
])
|
|
||||||
self.assertFalse(got_unicode[0])
|
self.assertFalse(got_unicode[0])
|
||||||
|
|
||||||
def test_failed_delete_continues_on(self):
|
def test_failed_delete_continues_on(self):
|
||||||
@ -783,42 +681,26 @@ class TestObjectExpirer(TestCase):
|
|||||||
def fail_delete_actual_object(actual_obj, timestamp):
|
def fail_delete_actual_object(actual_obj, timestamp):
|
||||||
raise Exception('failed to delete actual object')
|
raise Exception('failed to delete actual object')
|
||||||
|
|
||||||
cts = int(time() - 86400)
|
with mock.patch.object(self.fake_swift, 'delete_container',
|
||||||
ots = int(time() - 86400)
|
fail_delete_container), \
|
||||||
|
mock.patch.object(self.expirer, 'delete_actual_object',
|
||||||
|
fail_delete_actual_object):
|
||||||
|
self.expirer.run_once()
|
||||||
|
|
||||||
fake_swift = FakeInternalClient({
|
error_lines = self.expirer.logger.get_lines_for_level('error')
|
||||||
'.expiring_objects': {
|
|
||||||
str(cts): [
|
self.assertEqual(error_lines, [
|
||||||
'%d-a/c/actual-obj' % ots, '%d-a/c/next-obj' % ots],
|
'Exception while deleting object %s %s %s '
|
||||||
str(cts + 1): [
|
'failed to delete actual object: ' % (
|
||||||
'%d-a/c/actual-obj' % ots, '%d-a/c/next-obj' % ots],
|
'.expiring_objects', self.past_time,
|
||||||
},
|
self.past_time + '-' + target_path)
|
||||||
})
|
for target_path in self.expired_target_path_list] + [
|
||||||
x = expirer.ObjectExpirer(self.conf, logger=self.logger,
|
'Exception while deleting container %s %s '
|
||||||
swift=fake_swift)
|
'failed to delete container: ' % (
|
||||||
x.delete_actual_object = fail_delete_actual_object
|
'.expiring_objects', self.past_time)])
|
||||||
with mock.patch.object(fake_swift, 'delete_container',
|
self.assertEqual(self.expirer.logger.get_lines_for_level('info'), [
|
||||||
fail_delete_container):
|
|
||||||
x.run_once()
|
|
||||||
error_lines = x.logger.get_lines_for_level('error')
|
|
||||||
self.assertEqual(sorted(error_lines), sorted([
|
|
||||||
'Exception while deleting object .expiring_objects %d '
|
|
||||||
'%d-a/c/actual-obj failed to delete actual object: ' % (cts, ots),
|
|
||||||
'Exception while deleting object .expiring_objects %d '
|
|
||||||
'%d-a/c/next-obj failed to delete actual object: ' % (cts, ots),
|
|
||||||
'Exception while deleting object .expiring_objects %d '
|
|
||||||
'%d-a/c/actual-obj failed to delete actual object: ' %
|
|
||||||
(cts + 1, ots),
|
|
||||||
'Exception while deleting object .expiring_objects %d '
|
|
||||||
'%d-a/c/next-obj failed to delete actual object: ' %
|
|
||||||
(cts + 1, ots),
|
|
||||||
'Exception while deleting container .expiring_objects %d '
|
|
||||||
'failed to delete container: ' % (cts,),
|
|
||||||
'Exception while deleting container .expiring_objects %d '
|
|
||||||
'failed to delete container: ' % (cts + 1,)]))
|
|
||||||
self.assertEqual(x.logger.get_lines_for_level('info'), [
|
|
||||||
'Pass beginning for task account .expiring_objects; '
|
'Pass beginning for task account .expiring_objects; '
|
||||||
'2 possible containers; 4 possible objects',
|
'2 possible containers; 12 possible objects',
|
||||||
'Pass completed in 0s; 0 objects expired',
|
'Pass completed in 0s; 0 objects expired',
|
||||||
])
|
])
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user