summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel P. Berrangé <berrange@redhat.com>2022-05-17 15:01:19 +0100
committerDaniel P. Berrangé <berrange@redhat.com>2022-06-08 16:43:52 +0100
commite3fab09382d4a6c439820ed5e6930e57716dcb50 (patch)
tree75bd89dbae775c6e0b255453a67dbde3a824f879
parentb9f79758c973db088b5c687425c6613796fdb250 (diff)
downloadlibvirt-python-e3fab09382d4a6c439820ed5e6930e57716dcb50.tar.gz
tests: use mocks to allow calling virEventRegisterImpl many times
We currently have to run each of the test_aio.py test cases in a separate process, because libvirt.virEventRegisterImpl can only be called once per process. This leads to quite unpleasant console output when running tests. By introducing a mock for libvirt.virEventRegisterImpl we can regain the ability to run everything in a single process. The only caveat is that it relies on tests to fully cleanup, but in practice this is ok for our current tests. Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
-rw-r--r--pytest.ini3
-rwxr-xr-xsetup.py14
-rw-r--r--tests/eventmock.py82
-rw-r--r--tests/test_aio.py28
4 files changed, 102 insertions, 25 deletions
diff --git a/pytest.ini b/pytest.ini
deleted file mode 100644
index b23017c..0000000
--- a/pytest.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[pytest]
-markers =
- separate_process: mark test as requiring its own process
diff --git a/setup.py b/setup.py
index 3e99ac4..33f6187 100755
--- a/setup.py
+++ b/setup.py
@@ -310,19 +310,7 @@ class my_test(Command):
os.environ["PYTHONPATH"] = self.build_platlib
pytest = self.find_pytest_path()
-
- # Run the normal tests.
- subprocess.check_call([pytest, "-m", "not separate_process"])
-
- # Run the tests that require their own process.
- testlist = subprocess.run(
- [pytest, "--collect-only", "--quiet", "-m", "separate_process"],
- check=True, stdout=subprocess.PIPE)
- testlist = testlist.stdout.decode("utf-8").splitlines()
- testlist = filter(
- lambda test: test and "tests collected" not in test, testlist)
- for test in testlist:
- subprocess.check_call([pytest, test])
+ subprocess.check_call([pytest])
class my_clean(Command):
def run(self):
diff --git a/tests/eventmock.py b/tests/eventmock.py
new file mode 100644
index 0000000..7298086
--- /dev/null
+++ b/tests/eventmock.py
@@ -0,0 +1,82 @@
+
+import libvirt
+import libvirtmod
+
+_add_handle_impl = None
+_update_handle_impl = None
+_remove_handle_impl = None
+
+_add_timeout_impl = None
+_update_timeout_impl = None
+_remove_timeout_impl = None
+
+_registered = False
+
+def _add_handle(fd: int, event: int, cb: libvirt._EventCB, opaque: libvirt._T) -> int:
+ global _add_handle_impl
+ assert _add_handle_impl != None
+ return _add_handle_impl(fd, event, cb, opaque)
+
+def _update_handle(watch: int, event: int) -> None:
+ global _update_handle_impl
+ assert _update_handle_impl != None
+ _update_handle_impl(watch, event)
+
+def _remove_handle(watch: int) -> int:
+ global _remove_handle_impl
+ assert _remove_handle_impl != None
+ return _remove_handle_impl(watch)
+
+def _add_timeout(timeout: int, cb: libvirt._TimerCB, opaque: libvirt._T) -> int:
+ global _add_timeout_impl
+ assert _add_timeout_impl != None
+ return _add_timeout_impl(timeout, cb, opaque)
+
+def _update_timeout(timer: int, timeout: int) -> None:
+ global _update_timeout_impl
+ assert _update_timeout_impl != None
+ _update_timeout_impl(timer, timeout)
+
+def _remove_timeout(timer: int) -> int:
+ global _remove_timeout_impl
+ assert _remove_timeout_impl != None
+ return _remove_timeout_impl(timer)
+
+# libvirt.virEventRegisterImpl() is a one time call per process
+# This method is intended to be used with mock patching, so that
+# tests can get the appearance of being able to call
+# virEventRegisterImpl many times.
+#
+# Note, this relies on the tests closing all connection objects
+# and not leaving any handles/timers pending when they stop
+# running their event loop impl.
+
+def virEventRegisterImplMock(add_handle_impl,
+ update_handle_impl,
+ remove_handle_impl,
+ add_timeout_impl,
+ update_timeout_impl,
+ remove_timeout_impl):
+ global _add_handle_impl
+ global _update_handle_impl
+ global _remove_handle_impl
+ global _add_timeout_impl
+ global _update_timeout_impl
+ global _remove_timeout_impl
+
+ _add_handle_impl = add_handle_impl
+ _update_handle_impl = update_handle_impl
+ _remove_handle_impl = remove_handle_impl
+ _add_timeout_impl = add_timeout_impl
+ _update_timeout_impl = update_timeout_impl
+ _remove_timeout_impl = remove_timeout_impl
+
+ global _registered
+ if not _registered:
+ libvirtmod.virEventRegisterImpl(_add_handle,
+ _update_handle,
+ _remove_timeout,
+ _add_timeout,
+ _update_timeout,
+ _remove_timeout)
+ _registered = True
diff --git a/tests/test_aio.py b/tests/test_aio.py
index fb8c6b6..c90934d 100644
--- a/tests/test_aio.py
+++ b/tests/test_aio.py
@@ -3,7 +3,9 @@ import libvirt
import libvirtaio
import sys
import unittest
-import pytest
+from unittest import mock
+
+import eventmock
class TestLibvirtAio(unittest.TestCase):
@@ -70,8 +72,9 @@ class TestLibvirtAio(unittest.TestCase):
if domainStopped:
dom.create()
- @pytest.mark.separate_process
- def testEventsWithManualLoopSetup(self):
+ @mock.patch('libvirt.virEventRegisterImpl',
+ side_effect=eventmock.virEventRegisterImplMock)
+ def testEventsWithManualLoopSetup(self, mock_event_register):
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
@@ -79,15 +82,19 @@ class TestLibvirtAio(unittest.TestCase):
loop.close()
asyncio.set_event_loop(None)
+ mock_event_register.assert_called_once()
- @pytest.mark.separate_process
+ @mock.patch('libvirt.virEventRegisterImpl',
+ side_effect=eventmock.virEventRegisterImplMock)
@unittest.skipIf(sys.version_info < (3,7), "test requires Python 3.7+")
- def testEventsWithAsyncioRun(self):
+ def testEventsWithAsyncioRun(self, mock_event_register):
asyncio.run(self._run(register=True))
+ mock_event_register.assert_called_once()
- @pytest.mark.separate_process
+ @mock.patch('libvirt.virEventRegisterImpl',
+ side_effect=eventmock.virEventRegisterImplMock)
@unittest.skipIf(sys.version_info >= (3,10), "test not compatible with Python 3.10+")
- def testEventsPreInit(self):
+ def testEventsPreInit(self, mock_event_register):
# Initialize libvirt events before setting the event loop. This is not recommended.
# But is supported in older version of Python for the sake of back-compat.
loop = asyncio.new_event_loop()
@@ -98,9 +105,11 @@ class TestLibvirtAio(unittest.TestCase):
loop.close()
asyncio.set_event_loop(None)
+ mock_event_register.assert_called_once()
- @pytest.mark.separate_process
- def testEventsImplicitLoopInit(self):
+ @mock.patch('libvirt.virEventRegisterImpl',
+ side_effect=eventmock.virEventRegisterImplMock)
+ def testEventsImplicitLoopInit(self, mock_event_register):
# Allow virEventRegisterAsyncIOImpl() to init the event loop by calling
# asyncio.get_event_loop(). This is not recommended and probably only works by
# accident. But is supported for now for the sake of back-compat. For Python
@@ -112,3 +121,4 @@ class TestLibvirtAio(unittest.TestCase):
loop.close()
asyncio.set_event_loop(None)
+ mock_event_register.assert_called_once()