| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576 |
- # SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
- # SPDX-License-Identifier: Apache-2.0
- import io
- import typing as t
- from contextlib import redirect_stdout
- from pathlib import Path
- import pytest
- from _pytest.config import ExitCode
- from idf_py_actions.constants import PREVIEW_TARGETS as TOOLS_PREVIEW_TARGETS
- from idf_py_actions.constants import SUPPORTED_TARGETS as TOOLS_SUPPORTED_TARGETS
- from pytest_embedded.utils import to_list
- from .constants import PytestCase
- from .plugin import IdfPytestEmbedded
- def get_pytest_files(paths: t.List[str]) -> t.List[str]:
- # this is a workaround to solve pytest collector super slow issue
- # benchmark with
- # - time pytest -m esp32 --collect-only
- # user=15.57s system=1.35s cpu=95% total=17.741
- # - time { find -name 'pytest_*.py'; } | xargs pytest -m esp32 --collect-only
- # user=0.11s system=0.63s cpu=36% total=2.044
- # user=1.76s system=0.22s cpu=43% total=4.539
- # use glob.glob would also save a bunch of time
- pytest_scripts: t.Set[str] = set()
- for p in paths:
- path = Path(p)
- pytest_scripts.update(str(_p) for _p in path.glob('**/pytest_*.py') if 'managed_components' not in _p.parts)
- return list(pytest_scripts)
- def get_pytest_cases(
- paths: t.Union[str, t.List[str]],
- target: str = 'all',
- marker_expr: t.Optional[str] = None,
- filter_expr: t.Optional[str] = None,
- ) -> t.List[PytestCase]:
- if target == 'all':
- targets = TOOLS_SUPPORTED_TARGETS + TOOLS_PREVIEW_TARGETS
- else:
- targets = [target]
- paths = to_list(paths)
- cases: t.List[PytestCase] = []
- pytest_scripts = get_pytest_files(paths) # type: ignore
- if not pytest_scripts:
- print(f'WARNING: no pytest scripts found for target {target} under paths {", ".join(paths)}')
- return cases
- for target in targets:
- collector = IdfPytestEmbedded(target)
- with io.StringIO() as buf:
- with redirect_stdout(buf):
- cmd = ['--collect-only', *pytest_scripts, '--target', target, '-q']
- if marker_expr:
- cmd.extend(['-m', marker_expr])
- if filter_expr:
- cmd.extend(['-k', filter_expr])
- res = pytest.main(cmd, plugins=[collector])
- if res.value != ExitCode.OK:
- if res.value == ExitCode.NO_TESTS_COLLECTED:
- print(f'WARNING: no pytest app found for target {target} under paths {", ".join(paths)}')
- else:
- print(buf.getvalue())
- raise RuntimeError(f'pytest collection failed at {", ".join(paths)} with command \"{" ".join(cmd)}\"')
- cases.extend(collector.cases)
- return cases
|