From 5dc0330eeb20aa3f208ae50cc2fddb25432b1ac3 Mon Sep 17 00:00:00 2001 From: Bastian Krause Date: Fri, 29 Oct 2021 17:36:54 +0200 Subject: [PATCH] pytestplugin/hooks: combine multiple lg_feature markers instead of overwriting previous ones pytest allows setting markers via function decorators [1], class decorators [2] and "pytestmark" global to mark whole modules [2]. Additionally, each of these variants can specify multiple markers. labgrid's pytest plugin considered only the closest marker. Change that to allow combinations of multiple markers. This allows use cases like: import pytest pytestmark = pytest.mark.lg_feature("watchdog") @pytest.mark.lg_feature("barebox") def test_watchdog_barebox(barebox): .. Tests in this module are only run if the feature flag "watchdog" is available. The specific test "test_watchdog_barebox" is only run if the feature flag "barebox" is available additionally. [1] https://docs.pytest.org/en/latest/example/markers.html#adding-a-custom-marker-from-a-plugin [2] https://docs.pytest.org/en/latest/example/markers.html#marking-whole-classes-or-modules Signed-off-by: Bastian Krause --- CHANGES.rst | 2 ++ labgrid/pytestplugin/hooks.py | 19 +++++----- tests/test_flags.py | 67 +++++++++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+), 10 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index a3d2a5907..548497b49 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -4,6 +4,8 @@ Release 0.5.0 (unreleased) New Features in 0.5.0 ~~~~~~~~~~~~~~~~~~~~~ - Support for Eaton ePDU added, and can be used as a NetworkPowerPort. +- Consider a combination of multiple "lg_feature" markers instead of + considering only the closest marker. Bug fixes in 0.5.0 ~~~~~~~~~~~~~~~~~~ diff --git a/labgrid/pytestplugin/hooks.py b/labgrid/pytestplugin/hooks.py index 69a29c2df..86d2211fd 100644 --- a/labgrid/pytestplugin/hooks.py +++ b/labgrid/pytestplugin/hooks.py @@ -61,17 +61,16 @@ def pytest_collection_modifyitems(config, items): have_feature = env.get_features() | env.get_target_features() for item in items: - marker = item.get_closest_marker("lg_feature") - if not marker: - continue + want_feature = set() - arg = marker.args[0] - if isinstance(arg, str): - want_feature = set([arg]) - elif isinstance(arg, list): - want_feature = set(arg) - else: - raise Exception("Unsupported feature argument type") + for marker in item.iter_markers("lg_feature"): + arg = marker.args[0] + if isinstance(arg, str): + want_feature.add(arg) + elif isinstance(arg, list): + want_feature.update(arg) + else: + raise Exception("Unsupported feature argument type") missing_feature = want_feature - have_feature if missing_feature: if len(missing_feature) == 1: diff --git a/tests/test_flags.py b/tests/test_flags.py index 70d3f272b..745b42110 100644 --- a/tests/test_flags.py +++ b/tests/test_flags.py @@ -112,3 +112,70 @@ def test(env): spawn.expect(pexpect.EOF) spawn.close() assert spawn.exitstatus == 0 + +def test_match_multi_feature_source(tmpdir): + conf = tmpdir.join("config.yaml") + conf.write( +""" +targets: + test1: + features: + - test1 + - test2 + - test3 + drivers: {} +""" + ) + test = tmpdir.join("test.py") + test.write( +""" +import pytest + +pytestmark = pytest.mark.lg_feature("test1") + +@pytest.mark.lg_feature("test2") +class TestMulti: + @pytest.mark.lg_feature("test3") + def test(self, env): + assert True +""" + ) + + with pexpect.spawn(f'pytest --lg-env {conf} {test}') as spawn: + spawn.expect("1 passed") + spawn.expect(pexpect.EOF) + spawn.close() + assert spawn.exitstatus == 0 + +def test_skip_multi_feature_source(tmpdir): + conf = tmpdir.join("config.yaml") + conf.write( +""" +targets: + test1: + features: + - test1 + - test3 + drivers: {} +""" + ) + test = tmpdir.join("test.py") + test.write( +""" +import pytest + +pytestmark = pytest.mark.lg_feature("test1") + +@pytest.mark.lg_feature("test2") +class TestMulti: + @pytest.mark.lg_feature("test3") + def test(self, env): + assert True +""" + ) + + with pexpect.spawn(f'pytest --lg-env {conf} {test}') as spawn: + spawn.expect("1 skipped") + spawn.expect(pexpect.EOF) + spawn.close() + assert spawn.exitstatus == 0