From 87dba379aca6ec4613986cfa4e749a3ada2b44d0 Mon Sep 17 00:00:00 2001 From: melanie witt Date: Fri, 9 Jul 2021 22:22:15 +0000 Subject: [PATCH] Make test_archive_task_logs deterministic The 'nova-manage db archive_deleted_rows --task-log' functional tests involve manipulating time to assert archive behaviors when the --before flag is also used. While timedelta was used, set_time_override was not, so depending on the date the test ran on + the number of days in the current month and next two months, the test could fail. Task log audit periods are one calendar month by default and the compute manager calls last_completed_audit_period() without specifying a unit. This changes the tests to use a time override to ensure predictable behavior with regard to the audit period boundaries. The tests were moved into their own test case classes in order to override the time before services were started, so that the "service up" calculations work as expected. Closes-Bug: #1934519 Change-Id: I9b16a3a849937aba5b90ed1ab9a80b7f0103f673 --- nova/test.py | 5 +- nova/tests/functional/test_nova_manage.py | 80 ++++++++++++++++++++--- 2 files changed, 76 insertions(+), 9 deletions(-) diff --git a/nova/test.py b/nova/test.py index 4fd6c479de38..63562f92206f 100644 --- a/nova/test.py +++ b/nova/test.py @@ -743,9 +743,12 @@ class SubclassSignatureTestCase(testtools.TestCase, metaclass=abc.ABCMeta): class TimeOverride(fixtures.Fixture): """Fixture to start and remove time override.""" + def __init__(self, override_time=None): + self.override_time = override_time + def setUp(self): super(TimeOverride, self).setUp() - timeutils.set_time_override() + timeutils.set_time_override(override_time=self.override_time) self.addCleanup(timeutils.clear_time_override) diff --git a/nova/tests/functional/test_nova_manage.py b/nova/tests/functional/test_nova_manage.py index f20f33e48dc0..0d85a7afdbe2 100644 --- a/nova/tests/functional/test_nova_manage.py +++ b/nova/tests/functional/test_nova_manage.py @@ -1687,6 +1687,26 @@ class TestDBArchiveDeletedRows(integrated_helpers._IntegratedTestBase): self.assertEqual( 1, len(self.api.get_server_group(group['id'])['members'])) + +class TestDBArchiveDeletedRowsTaskLog(integrated_helpers._IntegratedTestBase): + """Functional tests for the + "nova-manage db archive_deleted_rows --task-log" CLI. + """ + api_major_version = 'v2.1' + + def setUp(self): + # Override time to ensure we cross audit period boundaries in a + # predictable way. + faketoday = datetime.datetime(2021, 7, 1) + # This needs to be done before setUp() starts services, else they will + # be considered "down" by the ComputeFilter. + self.useFixture(test.TimeOverride(override_time=faketoday)) + super(TestDBArchiveDeletedRowsTaskLog, self).setUp() + self.enforce_fk_constraints() + self.cli = manage.DbCommands() + self.output = StringIO() + self.useFixture(fixtures.MonkeyPatch('sys.stdout', self.output)) + def test_archive_task_logs(self): # Enable the generation of task_log records by the instance usage audit # nova-compute periodic task. @@ -1702,9 +1722,11 @@ class TestDBArchiveDeletedRows(integrated_helpers._IntegratedTestBase): # The instance usage audit periodic task only processes servers that # were active during the last audit period. The audit period defaults # to 1 month, so the last audit period would be the previous calendar - # month. Advance time 30 days into the future in order to generate a - # task_log record for the servers we created. - for days in (30, 60, 90): + # month. Advance time one month, two months, and three months to + # generate a task_log record for the servers we created, for each of + # three audit periods. + # July has 31 days, August has 31 days, September has 30 days. + for days in (31, 31 + 31, 31 + 31 + 30): future = timeutils.utcnow() + datetime.timedelta(days=days) with osloutils_fixture.TimeFixture(future): # task_log records are generated by the _instance_usage_audit @@ -1725,7 +1747,7 @@ class TestDBArchiveDeletedRows(integrated_helpers._IntegratedTestBase): # Next try archiving with --task-log and --before. # We'll archive records that were last updated before the second audit # period. - before = timeutils.utcnow() + datetime.timedelta(days=30) + before = timeutils.utcnow() + datetime.timedelta(days=31) self.cli.archive_deleted_rows( task_log=True, before=before.isoformat(), verbose=True) # Verify that only 1 task_log record was archived. @@ -1820,6 +1842,46 @@ class TestDBArchiveDeletedRowsMultiCell(integrated_helpers.InstanceHelperMixin, objects.Instance.get_by_uuid, cctxt, server_id) + +class TestDBArchiveDeletedRowsMultiCellTaskLog( + integrated_helpers.InstanceHelperMixin, test.TestCase): + """Functional tests for the "nova-manage db archive_deleted_rows + --all-cells --task-log" CLI. + """ + NUMBER_OF_CELLS = 2 + + def setUp(self): + # Override time to ensure we cross audit period boundaries in a + # predictable way. + faketoday = datetime.datetime(2021, 7, 1) + # This needs to be done before setUp() starts services, else they will + # be considered "down" by the ComputeFilter. + self.useFixture(test.TimeOverride(override_time=faketoday)) + super(TestDBArchiveDeletedRowsMultiCellTaskLog, self).setUp() + self.enforce_fk_constraints() + self.useFixture(nova_fixtures.NeutronFixture(self)) + self.useFixture(nova_fixtures.GlanceFixture(self)) + self.useFixture(func_fixtures.PlacementFixture()) + + api_fixture = self.useFixture(nova_fixtures.OSAPIFixture( + api_version='v2.1')) + # We need the admin api to forced_host for server create + self.api = api_fixture.admin_api + + self.start_service('conductor') + self.start_service('scheduler') + + self.context = context.RequestContext('fake-user', 'fake-project') + self.cli = manage.DbCommands() + self.output = StringIO() + self.useFixture(fixtures.MonkeyPatch('sys.stdout', self.output)) + + # Start two compute services, one per cell + self.compute1 = self.start_service('compute', host='host1', + cell_name='cell1') + self.compute2 = self.start_service('compute', host='host2', + cell_name='cell2') + def test_archive_task_logs(self): # Enable the generation of task_log records by the instance usage audit # nova-compute periodic task. @@ -1840,9 +1902,11 @@ class TestDBArchiveDeletedRowsMultiCell(integrated_helpers.InstanceHelperMixin, # The instance usage audit periodic task only processes servers that # were active during the last audit period. The audit period defaults # to 1 month, so the last audit period would be the previous calendar - # month. Advance time 30 days into the future in order to generate a - # task_log record for the servers we created. - for days in (30, 60, 90): + # month. Advance time one month, two months, and three months to + # generate a task_log record for the servers we created, for each of + # three audit periods. + # July has 31 days, August has 31 days, September has 30 days. + for days in (31, 31 + 31, 31 + 31 + 30): future = timeutils.utcnow() + datetime.timedelta(days=days) with osloutils_fixture.TimeFixture(future): # task_log records are generated by the _instance_usage_audit @@ -1871,7 +1935,7 @@ class TestDBArchiveDeletedRowsMultiCell(integrated_helpers.InstanceHelperMixin, # Next try archiving with --task-log and --before. # We'll archive records that were last updated before the second audit # period. - before = timeutils.utcnow() + datetime.timedelta(days=30) + before = timeutils.utcnow() + datetime.timedelta(days=31) self.cli.archive_deleted_rows( all_cells=True, task_log=True, before=before.isoformat(), verbose=True)