Skip to content

Commit b40bd1b

Browse files
gibizerSeanMooney
authored andcommitted
Remove double mocking
In py310 unittest.mock does not allow to mock the same function twice as the second mocking will fail to autospec the Mock object created by the first mocking. This patch manually fixes the double mocking. Fixed cases: 1) one of the mock was totally unnecessary so it was removed 2) the second mock specialized the behavior of the first generic mock. In this case the second mock is replaced with the configuration of the first mock 3) a test case with two test steps mocked the same function for each step with overlapping mocks. Here the overlap was removed to have the two mock exists independently The get_connection injection in the libvirt functional test needed a further tweak (yeah I know it has many already) to act like a single mock (basically case #2) instead of a temporary re-mocking. Still the globalness of the get_connection mocking warrant the special set / reset logic there. Conflicts: nova/tests/functional/regressions/test_bug_1781286.py nova/tests/unit/api/openstack/compute/test_shelve.py Change-Id: I3998d0d49583806ac1c3ae64f1b1fe343cefd20d (cherry picked from commit f8cf050)
1 parent 8133770 commit b40bd1b

File tree

20 files changed

+540
-669
lines changed

20 files changed

+540
-669
lines changed

nova/test.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,7 @@ def stub_out(self, old, new):
355355
self.useFixture(fixtures.MonkeyPatch(old, new))
356356

357357
@staticmethod
358-
def patch_exists(patched_path, result):
358+
def patch_exists(patched_path, result, other=None):
359359
"""Provide a static method version of patch_exists(), which if you
360360
haven't already imported nova.test can be slightly easier to
361361
use as a context manager within a test method via:
@@ -364,7 +364,7 @@ def test_something(self):
364364
with self.patch_exists(path, True):
365365
...
366366
"""
367-
return patch_exists(patched_path, result)
367+
return patch_exists(patched_path, result, other)
368368

369369
@staticmethod
370370
def patch_open(patched_path, read_data):
@@ -848,10 +848,12 @@ def __repr__(self):
848848

849849

850850
@contextlib.contextmanager
851-
def patch_exists(patched_path, result):
851+
def patch_exists(patched_path, result, other=None):
852852
"""Selectively patch os.path.exists() so that if it's called with
853853
patched_path, return result. Calls with any other path are passed
854-
through to the real os.path.exists() function.
854+
through to the real os.path.exists() function if other is not provided.
855+
If other is provided then that will be the result of the call on paths
856+
other than patched_path.
855857
856858
Either import and use as a decorator / context manager, or use the
857859
nova.TestCase.patch_exists() static method as a context manager.
@@ -885,7 +887,10 @@ def test_my_code(self, mock_exists):
885887
def fake_exists(path):
886888
if path == patched_path:
887889
return result
888-
return real_exists(path)
890+
elif other is not None:
891+
return other
892+
else:
893+
return real_exists(path)
889894

890895
with mock.patch.object(os.path, "exists") as mock_exists:
891896
mock_exists.side_effect = fake_exists

nova/tests/functional/libvirt/base.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -142,15 +142,15 @@ def _start_compute(hostname, host_info):
142142
pci_info.get_pci_address_mac_mapping())
143143
# This is fun. Firstly we need to do a global'ish mock so we can
144144
# actually start the service.
145-
with mock.patch('nova.virt.libvirt.host.Host.get_connection',
146-
return_value=fake_connection):
147-
compute = self.start_service('compute', host=hostname)
148-
# Once that's done, we need to tweak the compute "service" to
149-
# make sure it returns unique objects. We do this inside the
150-
# mock context to avoid a small window between the end of the
151-
# context and the tweaking where get_connection would revert to
152-
# being an autospec mock.
153-
compute.driver._host.get_connection = lambda: fake_connection
145+
orig_con = self.mock_conn.return_value
146+
self.mock_conn.return_value = fake_connection
147+
compute = self.start_service('compute', host=hostname)
148+
# Once that's done, we need to tweak the compute "service" to
149+
# make sure it returns unique objects.
150+
compute.driver._host.get_connection = lambda: fake_connection
151+
# Then we revert the local mock tweaking so the next compute can
152+
# get its own
153+
self.mock_conn.return_value = orig_con
154154
return compute
155155

156156
# ensure we haven't already registered services with these hostnames

nova/tests/functional/libvirt/test_vtpm.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ def setUp(self):
128128
# the presence of users on the host, none of which makes sense here
129129
_p = mock.patch(
130130
'nova.virt.libvirt.driver.LibvirtDriver._check_vtpm_support')
131-
self.mock_conn = _p.start()
131+
_p.start()
132132
self.addCleanup(_p.stop)
133133

134134
self.key_mgr = crypto._get_key_manager()

nova/tests/functional/regressions/test_bug_1781286.py

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
# License for the specific language governing permissions and limitations
1111
# under the License.
1212

13-
import fixtures
1413
import mock
1514
from oslo_db import exception as oslo_db_exc
1615

@@ -67,11 +66,11 @@ def test_server_create_reschedule_blocked_az_up_call(self):
6766
def wrap_bari(*args, **kwargs):
6867
# Poison the AZ query to blow up as if the cell conductor does not
6968
# have access to the API DB.
70-
self.useFixture(
71-
fixtures.MockPatch(
72-
'nova.objects.AggregateList.get_by_host',
73-
side_effect=oslo_db_exc.CantStartEngineError))
74-
return original_bari(*args, **kwargs)
69+
with mock.patch(
70+
'nova.objects.AggregateList.get_by_host',
71+
side_effect=oslo_db_exc.CantStartEngineError
72+
):
73+
return original_bari(*args, **kwargs)
7574

7675
self.stub_out('nova.compute.manager.ComputeManager.'
7776
'build_and_run_instance', wrap_bari)
@@ -81,10 +80,6 @@ def wrap_bari(*args, **kwargs):
8180
# compute service we have to wait for the notification that the build
8281
# is complete and then stop the mock so we can use the API again.
8382
self.notifier.wait_for_versioned_notifications('instance.create.end')
84-
# Note that we use stopall here because we actually called
85-
# build_and_run_instance twice so we have more than one instance of
86-
# the mock that needs to be stopped.
87-
mock.patch.stopall()
8883
server = self._wait_for_state_change(server, 'ACTIVE')
8984
# We should have rescheduled and the instance AZ should be set from the
9085
# Selection object. Since neither compute host is in an AZ, the server
@@ -128,19 +123,20 @@ def test_migrate_reschedule_blocked_az_up_call(self):
128123
self.rescheduled = None
129124

130125
def wrap_prep_resize(_self, *args, **kwargs):
131-
# Poison the AZ query to blow up as if the cell conductor does not
132-
# have access to the API DB.
133-
self.agg_mock = self.useFixture(
134-
fixtures.MockPatch(
135-
'nova.objects.AggregateList.get_by_host',
136-
side_effect=oslo_db_exc.CantStartEngineError)).mock
137126
if self.rescheduled is None:
138127
# Track the first host that we rescheduled from.
139128
self.rescheduled = _self.host
140129
# Trigger a reschedule.
141130
raise exception.ComputeResourcesUnavailable(
142131
reason='test_migrate_reschedule_blocked_az_up_call')
143-
return original_prep_resize(_self, *args, **kwargs)
132+
# Poison the AZ query to blow up as if the cell conductor does not
133+
# have access to the API DB.
134+
with mock.patch(
135+
'nova.objects.AggregateList.get_by_host',
136+
side_effect=oslo_db_exc.CantStartEngineError,
137+
) as agg_mock:
138+
self.agg_mock = agg_mock
139+
return original_prep_resize(_self, *args, **kwargs)
144140

145141
self.stub_out('nova.compute.manager.ComputeManager._prep_resize',
146142
wrap_prep_resize)

0 commit comments

Comments
 (0)