Move ReaderWriterLock to the test tree

The commit I168fffac8002f274a905cfd53ac4f6c9abe18803 added a wrapper
around fasteners.ReaderWriterLock to fix up an issue with eventlet. But
the wrapper was added to nova.utils module that is use not only by the
nova tests but also the nova production code. This made the fixture
library a dependency of the nova production code. While the current
ReaderWriterLock usage only limited to the nova test sub tree. The
I712f88fc1b6053fe6d1f13e708f3bd8874452a8f commit fix the issue of not
having fixtures in the nova requirements.txt. However I think a better
fix is to move the wrapper to the test subtree instead. This patch does
that and restores the state of the requirements.txt

Change-Id: I6903ce53b9b91325f7268cf2ebd02e4488579560
Related-Bug: #1958075
This commit is contained in:
Balazs Gibizer 2022-01-17 13:29:35 +01:00
parent 1ddb8f83ad
commit a341851f15
4 changed files with 38 additions and 37 deletions

View File

@ -17,6 +17,7 @@
"""Fixtures for Nova tests.""" """Fixtures for Nova tests."""
import collections import collections
import contextlib
from contextlib import contextmanager from contextlib import contextmanager
import functools import functools
import logging as std_logging import logging as std_logging
@ -28,6 +29,7 @@ import fixtures
import futurist import futurist
import mock import mock
from openstack import service_description from openstack import service_description
from oslo_concurrency import lockutils
from oslo_config import cfg from oslo_config import cfg
from oslo_db import exception as db_exc from oslo_db import exception as db_exc
from oslo_db.sqlalchemy import enginefacade from oslo_db.sqlalchemy import enginefacade
@ -405,7 +407,7 @@ class CellDatabases(fixtures.Fixture):
# to point to a cell, we need to take an exclusive lock to # to point to a cell, we need to take an exclusive lock to
# prevent any other calls to get_context_manager() until we # prevent any other calls to get_context_manager() until we
# reset to the default. # reset to the default.
self._cell_lock = utils.ReaderWriterLock() self._cell_lock = ReaderWriterLock()
def _cache_schema(self, connection_str): def _cache_schema(self, connection_str):
# NOTE(melwitt): See the regular Database fixture for why # NOTE(melwitt): See the regular Database fixture for why
@ -1721,3 +1723,37 @@ class PropagateTestCaseIdToChildEventlets(fixtures.Fixture):
# our initialization to the child eventlet # our initialization to the child eventlet
self.useFixture( self.useFixture(
fixtures.MonkeyPatch('nova.utils.spawn_n', wrapped_spawn_n)) fixtures.MonkeyPatch('nova.utils.spawn_n', wrapped_spawn_n))
class ReaderWriterLock(lockutils.ReaderWriterLock):
"""Wrap oslo.concurrency lockutils.ReaderWriterLock to support eventlet.
As of fasteners >= 0.15, the workaround code to use eventlet.getcurrent()
if eventlet patching is detected has been removed and
threading.current_thread is being used instead. Although we are running in
a greenlet in our test environment, we are not running in a greenlet of
type GreenThread. A GreenThread is created by calling eventlet.spawn() and
spawn() is not used to run our tests. At the time of this writing, the
eventlet patched threading.current_thread() method falls back to the
original unpatched current_thread() method if it is not called from a
GreenThead [1] and that breaks our tests involving this fixture.
We can work around this by patching threading.current_thread() with
eventlet.getcurrent() during creation of the lock object, if we detect we
are eventlet patched. If we are not eventlet patched, we use a no-op
context manager.
Note: this wrapper should be used for any ReaderWriterLock because any lock
may possibly be running inside a plain greenlet created by spawn_n().
See https://github.com/eventlet/eventlet/issues/731 for details.
[1] https://github.com/eventlet/eventlet/blob/v0.32.0/eventlet/green/threading.py#L128 # noqa
"""
def __init__(self, *a, **kw):
eventlet_patched = eventlet.patcher.is_monkey_patched('thread')
mpatch = fixtures.MonkeyPatch(
'threading.current_thread', eventlet.getcurrent)
with mpatch if eventlet_patched else contextlib.ExitStack():
super().__init__(*a, **kw)

View File

@ -29,7 +29,6 @@ import shutil
import tempfile import tempfile
import eventlet import eventlet
import fixtures
from keystoneauth1 import loading as ks_loading from keystoneauth1 import loading as ks_loading
import netaddr import netaddr
from openstack import connection from openstack import connection
@ -1144,37 +1143,3 @@ def run_once(message, logger, cleanup=None):
wrapper.reset = functools.partial(reset, wrapper) wrapper.reset = functools.partial(reset, wrapper)
return wrapper return wrapper
return outer_wrapper return outer_wrapper
class ReaderWriterLock(lockutils.ReaderWriterLock):
"""Wrap oslo.concurrency lockutils.ReaderWriterLock to support eventlet.
As of fasteners >= 0.15, the workaround code to use eventlet.getcurrent()
if eventlet patching is detected has been removed and
threading.current_thread is being used instead. Although we are running in
a greenlet in our test environment, we are not running in a greenlet of
type GreenThread. A GreenThread is created by calling eventlet.spawn() and
spawn() is not used to run our tests. At the time of this writing, the
eventlet patched threading.current_thread() method falls back to the
original unpatched current_thread() method if it is not called from a
GreenThead [1] and that breaks our tests involving this fixture.
We can work around this by patching threading.current_thread() with
eventlet.getcurrent() during creation of the lock object, if we detect we
are eventlet patched. If we are not eventlet patched, we use a no-op
context manager.
Note: this wrapper should be used for any ReaderWriterLock because any lock
may possibly be running inside a plain greenlet created by spawn_n().
See https://github.com/eventlet/eventlet/issues/731 for details.
[1] https://github.com/eventlet/eventlet/blob/v0.32.0/eventlet/green/threading.py#L128 # noqa
"""
def __init__(self, *a, **kw):
eventlet_patched = eventlet.patcher.is_monkey_patched('thread')
mpatch = fixtures.MonkeyPatch(
'threading.current_thread', eventlet.getcurrent)
with mpatch if eventlet_patched else contextlib.ExitStack():
return super().__init__(*a, **kw)

View File

@ -68,4 +68,3 @@ futurist>=1.8.0 # Apache-2.0
openstacksdk>=0.35.0 # Apache-2.0 openstacksdk>=0.35.0 # Apache-2.0
dataclasses>=0.7;python_version=='3.6' # Apache 2.0 License dataclasses>=0.7;python_version=='3.6' # Apache 2.0 License
PyYAML>=5.1 # MIT PyYAML>=5.1 # MIT
fixtures>=3.0.0 # Apache-2.0/BSD

View File

@ -7,6 +7,7 @@ mypy>=0.761 # MIT
types-paramiko>=0.1.3 # Apache-2.0 types-paramiko>=0.1.3 # Apache-2.0
coverage!=4.4,>=4.0 # Apache-2.0 coverage!=4.4,>=4.0 # Apache-2.0
ddt>=1.2.1 # MIT ddt>=1.2.1 # MIT
fixtures>=3.0.0 # Apache-2.0/BSD
mock>=3.0.0 # BSD mock>=3.0.0 # BSD
psycopg2-binary>=2.8 # LGPL/ZPL psycopg2-binary>=2.8 # LGPL/ZPL
PyMySQL>=0.8.0 # MIT License PyMySQL>=0.8.0 # MIT License