forked from espressif/esp-idf
ci: build and test only modified components related test cases
This commit is contained in:
89
conftest.py
89
conftest.py
@ -13,6 +13,8 @@
|
||||
# This is an experimental feature, and if you found any bug or have any question, please report to
|
||||
# https://github.com/espressif/pytest-embedded/issues
|
||||
|
||||
import glob
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
@ -36,11 +38,11 @@ from pytest_embedded.utils import find_by_suffix
|
||||
from pytest_embedded_idf.dut import IdfDut
|
||||
|
||||
try:
|
||||
from idf_ci_utils import to_list
|
||||
from idf_ci_utils import IDF_PATH, to_list
|
||||
from idf_unity_tester import CaseTester
|
||||
except ImportError:
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__), 'tools', 'ci'))
|
||||
from idf_ci_utils import to_list
|
||||
from idf_ci_utils import IDF_PATH, to_list
|
||||
from idf_unity_tester import CaseTester
|
||||
|
||||
try:
|
||||
@ -252,7 +254,7 @@ def test_case_name(request: FixtureRequest, target: str, config: str) -> str:
|
||||
|
||||
@pytest.fixture
|
||||
@multi_dut_fixture
|
||||
def build_dir(app_path: str, target: Optional[str], config: Optional[str]) -> str:
|
||||
def build_dir(request: FixtureRequest, app_path: str, target: Optional[str], config: Optional[str]) -> str:
|
||||
"""
|
||||
Check local build dir with the following priority:
|
||||
|
||||
@ -261,11 +263,6 @@ def build_dir(app_path: str, target: Optional[str], config: Optional[str]) -> st
|
||||
3. build_<config>
|
||||
4. build
|
||||
|
||||
Args:
|
||||
app_path: app path
|
||||
target: target
|
||||
config: config
|
||||
|
||||
Returns:
|
||||
valid build directory
|
||||
"""
|
||||
@ -278,6 +275,25 @@ def build_dir(app_path: str, target: Optional[str], config: Optional[str]) -> st
|
||||
check_dirs.append(f'build_{config}')
|
||||
check_dirs.append('build')
|
||||
|
||||
idf_pytest_embedded = request.config.stash[_idf_pytest_embedded_key]
|
||||
|
||||
build_dir = None
|
||||
if idf_pytest_embedded.apps_list is not None:
|
||||
for check_dir in check_dirs:
|
||||
binary_path = os.path.join(app_path, check_dir)
|
||||
if binary_path in idf_pytest_embedded.apps_list:
|
||||
build_dir = check_dir
|
||||
break
|
||||
|
||||
if build_dir is None:
|
||||
pytest.skip(
|
||||
f'app path {app_path} with target {target} and config {config} is not listed in app info list files'
|
||||
)
|
||||
return '' # not reachable, to fool mypy
|
||||
|
||||
if build_dir:
|
||||
check_dirs = [build_dir]
|
||||
|
||||
for check_dir in check_dirs:
|
||||
binary_path = os.path.join(app_path, check_dir)
|
||||
if os.path.isdir(binary_path):
|
||||
@ -286,9 +302,8 @@ def build_dir(app_path: str, target: Optional[str], config: Optional[str]) -> st
|
||||
|
||||
logging.warning('checking binary path: %s... missing... try another place', binary_path)
|
||||
|
||||
recommend_place = check_dirs[0]
|
||||
raise ValueError(
|
||||
f'no build dir valid. Please build the binary via "idf.py -B {recommend_place} build" and run pytest again'
|
||||
f'no build dir valid. Please build the binary via "idf.py -B {check_dirs[0]} build" and run pytest again'
|
||||
)
|
||||
|
||||
|
||||
@ -412,20 +427,32 @@ def dev_user(request: FixtureRequest) -> str:
|
||||
# Hook functions #
|
||||
##################
|
||||
def pytest_addoption(parser: pytest.Parser) -> None:
|
||||
base_group = parser.getgroup('idf')
|
||||
base_group.addoption(
|
||||
idf_group = parser.getgroup('idf')
|
||||
idf_group.addoption(
|
||||
'--sdkconfig',
|
||||
help='sdkconfig postfix, like sdkconfig.ci.<config>. (Default: None, which would build all found apps)',
|
||||
)
|
||||
base_group.addoption('--known-failure-cases-file', help='known failure cases file path')
|
||||
base_group.addoption(
|
||||
idf_group.addoption('--known-failure-cases-file', help='known failure cases file path')
|
||||
idf_group.addoption(
|
||||
'--dev-user',
|
||||
help='user name associated with some specific device/service used during the test execution',
|
||||
)
|
||||
base_group.addoption(
|
||||
idf_group.addoption(
|
||||
'--dev-passwd',
|
||||
help='password associated with some specific device/service used during the test execution',
|
||||
)
|
||||
idf_group.addoption(
|
||||
'--app-info-basedir',
|
||||
default=IDF_PATH,
|
||||
help='app info base directory. specify this value when you\'re building under a '
|
||||
'different IDF_PATH. (Default: $IDF_PATH)',
|
||||
)
|
||||
idf_group.addoption(
|
||||
'--app-info-filepattern',
|
||||
help='glob pattern to specify the files that include built app info generated by '
|
||||
'`idf-build-apps --collect-app-info ...`. will not raise ValueError when binary '
|
||||
'paths not exist in local file system if not listed recorded in the app info.',
|
||||
)
|
||||
|
||||
|
||||
_idf_pytest_embedded_key = pytest.StashKey['IdfPytestEmbedded']()
|
||||
@ -446,10 +473,34 @@ def pytest_configure(config: Config) -> None:
|
||||
if not target: # also could specify through markexpr via "-m"
|
||||
target = get_target_marker_from_expr(config.getoption('markexpr') or '')
|
||||
|
||||
apps_list = None
|
||||
app_info_basedir = config.getoption('app_info_basedir')
|
||||
app_info_filepattern = config.getoption('app_info_filepattern')
|
||||
if app_info_filepattern:
|
||||
apps_list = []
|
||||
for file in glob.glob(os.path.join(IDF_PATH, app_info_filepattern)):
|
||||
with open(file) as fr:
|
||||
for line in fr.readlines():
|
||||
if not line.strip():
|
||||
continue
|
||||
|
||||
# each line is a valid json
|
||||
app_info = json.loads(line.strip())
|
||||
if app_info_basedir and app_info['app_dir'].startswith(app_info_basedir):
|
||||
relative_app_dir = os.path.relpath(app_info['app_dir'], app_info_basedir)
|
||||
apps_list.append(os.path.join(IDF_PATH, os.path.join(relative_app_dir, app_info['build_dir'])))
|
||||
print('Detected app: ', apps_list[-1])
|
||||
else:
|
||||
print(
|
||||
f'WARNING: app_info base dir {app_info_basedir} not recognizable in {app_info["app_dir"]}, skipping...'
|
||||
)
|
||||
continue
|
||||
|
||||
config.stash[_idf_pytest_embedded_key] = IdfPytestEmbedded(
|
||||
target=target,
|
||||
sdkconfig=config.getoption('sdkconfig'),
|
||||
known_failure_cases_file=config.getoption('known_failure_cases_file'),
|
||||
apps_list=apps_list,
|
||||
)
|
||||
config.pluginmanager.register(config.stash[_idf_pytest_embedded_key])
|
||||
|
||||
@ -470,11 +521,13 @@ class IdfPytestEmbedded:
|
||||
target: str,
|
||||
sdkconfig: Optional[str] = None,
|
||||
known_failure_cases_file: Optional[str] = None,
|
||||
apps_list: Optional[List[str]] = None,
|
||||
):
|
||||
# CLI options to filter the test cases
|
||||
self.target = target.lower()
|
||||
self.sdkconfig = sdkconfig
|
||||
self.known_failure_patterns = self._parse_known_failure_cases_file(known_failure_cases_file)
|
||||
self.apps_list = apps_list
|
||||
|
||||
self._failed_cases: List[Tuple[str, bool, bool]] = [] # (test_case_name, is_known_failure_cases, is_xfail)
|
||||
|
||||
@ -599,7 +652,11 @@ class IdfPytestEmbedded:
|
||||
test_case_name = item.funcargs.get('test_case_name', '')
|
||||
if test_case_name:
|
||||
self._failed_cases.append(
|
||||
(test_case_name, self._is_known_failure(test_case_name), report.keywords.get('xfail', False))
|
||||
(
|
||||
test_case_name,
|
||||
self._is_known_failure(test_case_name),
|
||||
report.keywords.get('xfail', False),
|
||||
)
|
||||
)
|
||||
|
||||
return report
|
||||
|
Reference in New Issue
Block a user