From 9f0132f82e409005fc4c01996ca9063a4dace323 Mon Sep 17 00:00:00 2001
From: Rodrigo Tobar <rtobar@icrar.org>
Date: Mon, 31 May 2021 11:42:14 +0800
Subject: [PATCH] Fork new test processes sparingly

The test suite of this project is quite extensive, and it can take a
while to run all the tests in the suite. Forking a new process for each
of these executions is an extra cost, and therefore it makes sense to
avoid it when possible. While forking is unavoidable for tests requiring
Tango devices to be started, the rest of the tests (most of them) do not
have this requirements and therefore can be run without forking.

This commit changes the default behavior of all tests to not fork, and
marks those classes containing Tango-dependent tests to fork. This
almost halves the runtime of the full test suite, from ~170 to ~90
seconds when running quietly.

The initial version of these changes explicitly marked all those classes
needing forking with @pytest.mark.forked. Drew Deverux however pointed
out a much smarter way to automatically do this for those cases where
the tango_context fixture is used, which is what's going in in this
final version of the changes. After this there were still a few tests
that needed manual marking.

Signed-off-by: Rodrigo Tobar <rtobar@icrar.org>
---
 setup.cfg                    | 3 +--
 tests/conftest.py            | 4 ++++
 tests/test_csp_master.py     | 1 +
 tests/test_csp_obs_device.py | 1 +
 tests/test_logger_device.py  | 1 +
 tests/test_obs_device.py     | 1 +
 6 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/setup.cfg b/setup.cfg
index df7dadc2..e106b66c 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -7,8 +7,7 @@ source = ska_tango_base
 
 [tool:pytest]
 testpaths = tests
-addopts = --forked
-          --verbose
+addopts = --verbose
           --json-report
           --json-report-file=build/htmlcov/report.json
           --cov-report term
diff --git a/tests/conftest.py b/tests/conftest.py
index 4039cb30..461ee070 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -34,6 +34,10 @@ def tango_context(device_test_config):
     yield tango_context
     tango_context.stop()
 
+def pytest_itemcollected(item):
+    """Make Tango-related tests run in forked mode"""
+    if "tango_context" in item.fixturenames:
+        item.add_marker("forked")
 
 @pytest.fixture(scope="function")
 def initialize_device(tango_context):
diff --git a/tests/test_csp_master.py b/tests/test_csp_master.py
index e911d6d9..954a9778 100644
--- a/tests/test_csp_master.py
+++ b/tests/test_csp_master.py
@@ -366,6 +366,7 @@ class TestCspSubElementMaster(object):
         # PROTECTED REGION END #    //  CspSubelementMaster.test_ReInitDevices_when_in_wrong_state
 
 
+@pytest.mark.forked
 def test_multiple_devices_in_same_process():
 
     # The order here is important - base class last, so that we can
diff --git a/tests/test_csp_obs_device.py b/tests/test_csp_obs_device.py
index 32355164..5ef30ab4 100644
--- a/tests/test_csp_obs_device.py
+++ b/tests/test_csp_obs_device.py
@@ -410,6 +410,7 @@ class TestCspSubElementObsDevice(object):
         # PROTECTED REGION END #    //  CspSubelementObsDevice.test_Abort
 
 
+@pytest.mark.forked
 def test_multiple_devices_in_same_process():
     devices_info = (
         {"class": CspSubElementObsDevice, "devices": [{"name": "test/se/1"}]},
diff --git a/tests/test_logger_device.py b/tests/test_logger_device.py
index 47cde803..ea85f857 100644
--- a/tests/test_logger_device.py
+++ b/tests/test_logger_device.py
@@ -159,6 +159,7 @@ class TestSKALogger(object):
         # PROTECTED REGION END #    //  SKALogger.test_testMode
 
 
+@pytest.mark.forked
 def test_SetLoggingLevel():
     """Test for SetLoggingLevel"""
     logging_level = int(tango.LogLevel.LOG_ERROR)
diff --git a/tests/test_obs_device.py b/tests/test_obs_device.py
index c19adf7e..02eb5432 100644
--- a/tests/test_obs_device.py
+++ b/tests/test_obs_device.py
@@ -187,6 +187,7 @@ class TestSKAObsDevice(object):
         # PROTECTED REGION END #    //  SKAObsDevice.test_testMode
 
 
+@pytest.mark.forked
 def test_multiple_devices_in_same_process():
 
     # The order here is important - base class last, so that we can
-- 
GitLab