2023-07-31 00:49:08 -04:00
|
|
|
# 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
|
2023-06-13 05:12:55 -04:00
|
|
|
from .plugin import IdfPytestEmbedded
|
2023-07-31 00:49:08 -04:00
|
|
|
|
|
|
|
|
|
|
|
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:
|
2023-06-13 05:12:55 -04:00
|
|
|
collector = IdfPytestEmbedded(target)
|
2023-07-31 00:49:08 -04:00
|
|
|
|
|
|
|
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])
|
|
|
|
|
2023-06-13 05:12:55 -04:00
|
|
|
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)}\"')
|
2023-07-31 00:49:08 -04:00
|
|
|
|
2023-06-13 05:12:55 -04:00
|
|
|
cases.extend(collector.cases)
|
2023-07-31 00:49:08 -04:00
|
|
|
|
|
|
|
return cases
|