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."""
import collections
import contextlib
from contextlib import contextmanager
import functools
import logging as std_logging
@ -28,6 +29,7 @@ import fixtures
import futurist
import mock
from openstack import service_description
from oslo_concurrency import lockutils
from oslo_config import cfg
from oslo_db import exception as db_exc
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
# prevent any other calls to get_context_manager() until we
# reset to the default.
self._cell_lock = utils.ReaderWriterLock()
self._cell_lock = ReaderWriterLock()
def _cache_schema(self, connection_str):
# NOTE(melwitt): See the regular Database fixture for why
@ -1721,3 +1723,37 @@ class PropagateTestCaseIdToChildEventlets(fixtures.Fixture):
# our initialization to the child eventlet
self.useFixture(
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 eventlet
import fixtures
from keystoneauth1 import loading as ks_loading
import netaddr
from openstack import connection
@ -1144,37 +1143,3 @@ def run_once(message, logger, cleanup=None):
wrapper.reset = functools.partial(reset, wrapper)
return 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
dataclasses>=0.7;python_version=='3.6' # Apache 2.0 License
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
coverage!=4.4,>=4.0 # Apache-2.0
ddt>=1.2.1 # MIT
fixtures>=3.0.0 # Apache-2.0/BSD
mock>=3.0.0 # BSD
psycopg2-binary>=2.8 # LGPL/ZPL
PyMySQL>=0.8.0 # MIT License