From 7641776ae20148db1af14a161514241aabf49b30 Mon Sep 17 00:00:00 2001 From: Fu Hanxi Date: Tue, 12 Mar 2024 11:04:37 +0100 Subject: [PATCH] ci: support filter pytest with sdkconfig name --- conftest.py | 1 + tools/ci/idf_pytest/plugin.py | 16 ++++++- tools/ci/idf_pytest/script.py | 4 +- .../idf_pytest/tests/test_get_pytest_cases.py | 43 +++++++++++++++++++ 4 files changed, 62 insertions(+), 2 deletions(-) diff --git a/conftest.py b/conftest.py index 9d89b06be4..4b502206a9 100644 --- a/conftest.py +++ b/conftest.py @@ -436,6 +436,7 @@ def pytest_configure(config: Config) -> None: if '--collect-only' not in config.invocation_params.args: config.stash[IDF_PYTEST_EMBEDDED_KEY] = IdfPytestEmbedded( + config_name=config.getoption('sdkconfig'), target=target, apps=apps, ) diff --git a/tools/ci/idf_pytest/plugin.py b/tools/ci/idf_pytest/plugin.py index d7e7ea2e25..1d58bc6bbd 100644 --- a/tools/ci/idf_pytest/plugin.py +++ b/tools/ci/idf_pytest/plugin.py @@ -48,6 +48,7 @@ class IdfPytestEmbedded: self, target: t.Union[t.List[str], str], *, + config_name: t.Optional[str] = None, single_target_duplicate_mode: bool = False, apps: t.Optional[t.List[App]] = None, ): @@ -60,6 +61,8 @@ class IdfPytestEmbedded: if not self.target: raise ValueError('`target` should not be empty') + self.config_name = config_name + # these are useful while gathering all the multi-dut test cases # when this mode is activated, # @@ -226,7 +229,18 @@ class IdfPytestEmbedded: and self.get_param(_item, 'target', None) is not None ] - # 4. filter by `self.apps_list`, skip the test case if not listed + # 4. filter according to the sdkconfig, if there's param 'config' defined + if self.config_name: + _items = [] + for item in items: + case = item_to_case_dict[item] + if self.config_name not in set(app.config or DEFAULT_SDKCONFIG for app in case.apps): + self.additional_info[case.name]['skip_reason'] = f'Only run with sdkconfig {self.config_name}' + else: + _items.append(item) + items[:] = _items + + # 5. filter by `self.apps_list`, skip the test case if not listed # should only be used in CI _items = [] for item in items: diff --git a/tools/ci/idf_pytest/script.py b/tools/ci/idf_pytest/script.py index 93dd6b1a67..eed0609e0f 100644 --- a/tools/ci/idf_pytest/script.py +++ b/tools/ci/idf_pytest/script.py @@ -50,6 +50,7 @@ def get_pytest_cases( paths: t.Union[str, t.List[str]], target: str = CollectMode.ALL, *, + config_name: t.Optional[str] = None, marker_expr: t.Optional[str] = None, filter_expr: t.Optional[str] = None, apps: t.Optional[t.List[App]] = None, @@ -67,6 +68,7 @@ def get_pytest_cases( :param paths: paths to search for pytest scripts :param target: target or keywords to get test cases for, detailed above + :param config_name: sdkconfig name :param marker_expr: pytest marker expression, `-m` :param filter_expr: pytest filter expression, `-k` :param apps: built app list, skip the tests required by apps not in the list @@ -81,7 +83,7 @@ def get_pytest_cases( return cases def _get_pytest_cases(_target: str, _single_target_duplicate_mode: bool = False) -> t.List[PytestCase]: - collector = IdfPytestEmbedded(_target, single_target_duplicate_mode=_single_target_duplicate_mode, apps=apps) + collector = IdfPytestEmbedded(_target, config_name=config_name, single_target_duplicate_mode=_single_target_duplicate_mode, apps=apps) with io.StringIO() as buf: with redirect_stdout(buf): diff --git a/tools/ci/idf_pytest/tests/test_get_pytest_cases.py b/tools/ci/idf_pytest/tests/test_get_pytest_cases.py index 07584a60b0..e5a9a10ffc 100644 --- a/tools/ci/idf_pytest/tests/test_get_pytest_cases.py +++ b/tools/ci/idf_pytest/tests/test_get_pytest_cases.py @@ -118,3 +118,46 @@ def test_multi_with_marker_and_app_path(work_dirpath: Path) -> None: cases = get_pytest_cases([str(work_dirpath)], 'esp32c2,esp32c2,esp32c2') assert len(cases) == 1 assert cases[0].targets == ['esp32c2', 'esp32c2', 'esp32c2'] + + +def test_filter_with_sdkconfig_name(work_dirpath: Path) -> None: + script = work_dirpath / 'pytest_filter_with_sdkconfig_name.py' + script.write_text( + textwrap.dedent( + ''' + import pytest + + @pytest.mark.esp32 + @pytest.mark.parametrize( + 'config', [ + 'foo', + 'bar', + ], indirect=True + ) + def test_filter_with_sdkconfig_name_single_dut(dut): + pass + + @pytest.mark.esp32 + @pytest.mark.parametrize( + 'count', [2], indirect=True + ) + @pytest.mark.parametrize( + 'config', [ + 'foo|bar', + 'bar|baz', + ], indirect=True + ) + def test_filter_with_sdkconfig_name_multi_dut(dut): + pass + ''' + ) + ) + + cases = get_pytest_cases([str(work_dirpath)], 'esp32', config_name='foo') + assert len(cases) == 1 + + cases = get_pytest_cases([str(work_dirpath)], 'esp32,esp32', config_name='foo') + assert len(cases) == 1 + + cases = get_pytest_cases([str(work_dirpath)], 'esp32,esp32', config_name='bar') + assert len(cases) == 2