summaryrefslogtreecommitdiff
path: root/nova
diff options
context:
space:
mode:
authorZuul <zuul@review.opendev.org>2023-05-17 09:20:59 +0000
committerGerrit Code Review <review@openstack.org>2023-05-17 09:20:59 +0000
commit02a63e0f1b46bc2616d02c1742523b09936e7dd6 (patch)
tree642e56859dcd9bc79b29155c9ea9e47c20f111e2 /nova
parentb3fdd7ccf01bafb68e37a457f703b79119dbfa86 (diff)
parentc095cfe04e2c71efcfbfdd95948af080a98065e6 (diff)
downloadnova-master.tar.gz
Merge "tests: Use GreenThreadPoolExecutor.shutdown(wait=True)"HEADmaster
Diffstat (limited to 'nova')
-rw-r--r--nova/test.py7
-rw-r--r--nova/tests/fixtures/nova.py35
2 files changed, 42 insertions, 0 deletions
diff --git a/nova/test.py b/nova/test.py
index e37967b06d..1cf605f10a 100644
--- a/nova/test.py
+++ b/nova/test.py
@@ -317,6 +317,13 @@ class TestCase(base.BaseTestCase):
# all other tests.
scheduler_utils.reset_globals()
+ # Wait for bare greenlets spawn_n()'ed from a GreenThreadPoolExecutor
+ # to finish before moving on from the test. When greenlets from a
+ # previous test remain running, they may attempt to access structures
+ # (like the database) that have already been torn down and can cause
+ # the currently running test to fail.
+ self.useFixture(nova_fixtures.GreenThreadPoolShutdownWait())
+
def _setup_cells(self):
"""Setup a normal cellsv2 environment.
diff --git a/nova/tests/fixtures/nova.py b/nova/tests/fixtures/nova.py
index abfc3ecc6c..be0691f7aa 100644
--- a/nova/tests/fixtures/nova.py
+++ b/nova/tests/fixtures/nova.py
@@ -1938,3 +1938,38 @@ class ComputeNodeIdFixture(fixtures.Fixture):
'nova.compute.manager.ComputeManager.'
'_ensure_existing_node_identity',
mock.DEFAULT))
+
+
+class GreenThreadPoolShutdownWait(fixtures.Fixture):
+ """Always wait for greenlets in greenpool to finish.
+
+ We use the futurist.GreenThreadPoolExecutor, for example, in compute
+ manager to run live migration jobs. It runs those jobs in bare greenlets
+ created by eventlet.spawn_n(). Bare greenlets cannot be killed the same
+ way as GreenThreads created by eventlet.spawn().
+
+ Because they cannot be killed, in the test environment we must either let
+ them run to completion or move on while they are still running (which can
+ cause test failures as the leaked greenlets attempt to access structures
+ that have already been torn down).
+
+ When a compute service is stopped by Service.stop(), the compute manager's
+ cleanup_host() method is called and while cleaning up, the compute manager
+ calls the GreenThreadPoolExecutor.shutdown() method with wait=False. This
+ means that a test running GreenThreadPoolExecutor jobs will not wait for
+ the bare greenlets to finish running -- it will instead move on immediately
+ while greenlets are still running.
+
+ This fixture will ensure GreenThreadPoolExecutor.shutdown() is always
+ called with wait=True in an effort to reduce the number of leaked bare
+ greenlets.
+
+ See https://bugs.launchpad.net/nova/+bug/1946339 for details.
+ """
+
+ def setUp(self):
+ super().setUp()
+ real_shutdown = futurist.GreenThreadPoolExecutor.shutdown
+ self.useFixture(fixtures.MockPatch(
+ 'futurist.GreenThreadPoolExecutor.shutdown',
+ lambda self, wait: real_shutdown(self, wait=True)))