From 045d883772108c722e2a483a6e6b3239d4518a05 Mon Sep 17 00:00:00 2001 From: Surya Seetharaman Date: Fri, 15 Feb 2019 09:41:45 +0100 Subject: [PATCH] Add context.target_cell() stub to DownCellFixture This is to give the freedom to simulate down cells for each individual cell targeted function calls. Part of blueprint handling-down-cell Change-Id: Ib5bfa1b6365fb78c7d3beb07c561c62ded5cb0e1 --- nova/tests/fixtures.py | 40 ++++++++++++++++++++++++++------ nova/tests/unit/test_fixtures.py | 36 ++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 7 deletions(-) diff --git a/nova/tests/fixtures.py b/nova/tests/fixtures.py index 73584726cf..6d3631c473 100644 --- a/nova/tests/fixtures.py +++ b/nova/tests/fixtures.py @@ -1951,10 +1951,10 @@ class NoopQuotaDriverFixture(fixtures.Fixture): class DownCellFixture(fixtures.Fixture): """A fixture to simulate when a cell is down either due to error or timeout - This fixture will stub out the scatter_gather_cells routine used in various - cells-related API operations like listing/showing server details to return - a ``oslo_db.exception.DBError`` per cell in the results. Therefore - it is best used with a test scenario like this: + This fixture will stub out the scatter_gather_cells routine and target_cell + used in various cells-related API operations like listing/showing server + details to return a ``oslo_db.exception.DBError`` per cell in the results. + Therefore it is best used with a test scenario like this: 1. Create a server successfully. 2. Using the fixture, list/show servers. Depending on the microversion @@ -2026,11 +2026,37 @@ class DownCellFixture(fixtures.Fixture): } ret2 = {} for cell in up_cell_mappings: - with context.target_cell(ctxt, cell) as cctxt: - ctxt.cell_uuid = cell.uuid - result = fn(cctxt, *args, **kwargs) + ctxt.cell_uuid = cell.uuid + cctxt = context.RequestContext.from_dict(ctxt.to_dict()) + context.set_target_cell(cctxt, cell) + result = fn(cctxt, *args, **kwargs) ret2[cell.uuid] = result return dict(list(ret1.items()) + list(ret2.items())) + @contextmanager + def stub_target_cell(ctxt, cell_mapping): + # This is to give the freedom to simulate down cells for each + # individual cell targeted function calls. + if not self.down_cell_mappings: + # User has not passed any down cells explicitly, so all cells + # are considered as down cells. + self.down_cell_mappings = [cell_mapping] + raise db_exc.DBError() + else: + # if down_cell_mappings are passed, then check if this cell + # is down or up. + down_cell_uuids = [cell.uuid + for cell in self.down_cell_mappings] + if cell_mapping.uuid in down_cell_uuids: + # its a down cell raise the exception straight away + raise db_exc.DBError() + else: + # its an up cell, so yield its context + cctxt = context.RequestContext.from_dict(ctxt.to_dict()) + context.set_target_cell(cctxt, cell_mapping) + yield cctxt + self.useFixture(fixtures.MonkeyPatch( 'nova.context.scatter_gather_cells', stub_scatter_gather_cells)) + self.useFixture(fixtures.MonkeyPatch( + 'nova.context.target_cell', stub_target_cell)) diff --git a/nova/tests/unit/test_fixtures.py b/nova/tests/unit/test_fixtures.py index 00808792b3..1541fe2288 100644 --- a/nova/tests/unit/test_fixtures.py +++ b/nova/tests/unit/test_fixtures.py @@ -576,3 +576,39 @@ class TestDownCellFixture(test.TestCase): self.assertIsInstance(result, objects.InstanceList) self.assertEqual(1, len(result)) self.assertEqual(inst2.uuid, result[0].uuid) + + def test_fixture_for_an_individual_down_cell_targeted_call(self): + # We have cell0 and cell1 by default in the setup. We try targeting + # both the cells. We should get a db error for the down cell and + # the correct result for the up cell. + ctxt = context.get_admin_context() + cell0 = self.cell_mappings['cell0'] + cell1 = self.cell_mappings['cell1'] + with context.target_cell(ctxt, cell0) as cctxt: + inst1 = fake_instance.fake_instance_obj(cctxt) + if 'id' in inst1: + delattr(inst1, 'id') + inst1.create() + with context.target_cell(ctxt, cell1) as cctxt: + inst2 = fake_instance.fake_instance_obj(cctxt) + if 'id' in inst2: + delattr(inst2, 'id') + inst2.create() + + def dummy_tester(ctxt, cell_mapping, uuid): + with context.target_cell(ctxt, cell_mapping) as cctxt: + return objects.Instance.get_by_uuid(cctxt, uuid) + + # Scenario A: We do not pass any down cells, fixture automatically + # assumes the targeted cell is down whether its cell0 or cell1. + with fixtures.DownCellFixture(): + self.assertRaises( + db_exc.DBError, dummy_tester, ctxt, cell1, inst2.uuid) + # Scenario B: We pass cell0 as the down cell. + with fixtures.DownCellFixture([cell0]): + self.assertRaises( + db_exc.DBError, dummy_tester, ctxt, cell0, inst1.uuid) + # Scenario C: We get the correct result from the up cell + # when targeted. + result = dummy_tester(ctxt, cell1, inst2.uuid) + self.assertEqual(inst2.uuid, result.uuid)