mirror of
https://github.com/espressif/esp-idf.git
synced 2026-09-22 13:01:16 +03:00
ci: apply idf-ci 1.x
(cherry picked from commit 21d772a24da646bfb672418cf056199cad9b17e4)
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# Checks all public headers in IDF in the ci
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-FileCopyrightText: 2020-2026 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
import argparse
|
||||
@@ -309,6 +309,10 @@ class PublicHeaderChecker:
|
||||
idf_path = os.getenv('IDF_PATH')
|
||||
if idf_path is None:
|
||||
raise RuntimeError("Environment variable 'IDF_PATH' wasn't set.")
|
||||
|
||||
idf_tools_path = os.getenv('IDF_TOOLS_PATH') or os.path.expanduser(os.path.join('~', '.espressif'))
|
||||
idf_root_dep_path = os.path.join(idf_tools_path, 'root_managed_components')
|
||||
|
||||
project_dir = os.path.join(idf_path, 'examples', 'get-started', 'blink')
|
||||
sdkconfig = os.path.join(self.build_dir, 'sdkconfig')
|
||||
if self.libc_type == 'picolibc':
|
||||
@@ -371,7 +375,11 @@ class PublicHeaderChecker:
|
||||
if os.path.relpath(d, idf_path).startswith(tuple(ignore_dirs)):
|
||||
self.log('{} - directory ignored'.format(d))
|
||||
continue
|
||||
for root, dirnames, filenames in os.walk(d):
|
||||
for root, _, filenames in os.walk(d):
|
||||
if root.startswith(idf_root_dep_path):
|
||||
self.log(f'{root} - directory ignored (inside IDF_TOOLS_PATH/root_managed_components)')
|
||||
continue
|
||||
|
||||
for filename in fnmatch.filter(filenames, '*.h'):
|
||||
all_include_files.append(os.path.join(root, filename))
|
||||
self.main_c = main_c
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
# set while generating the pipeline
|
||||
nodes: ""
|
||||
INSTALL_EXTRA_TOOLS: "xtensa-esp-elf-gdb riscv32-esp-elf-gdb openocd-esp32 esp-rom-elfs"
|
||||
PYTEST_EXTRA_FLAGS: "--dev-passwd ${ETHERNET_TEST_PASSWORD} --dev-user ${ETHERNET_TEST_USER} --capture=fd --verbosity=0 --unity-test-report-mode merge"
|
||||
PYTEST_EXTRA_FLAGS: "--capture=fd --verbosity=0 --unity-test-report-mode merge"
|
||||
needs:
|
||||
- pipeline: $PARENT_PIPELINE_ID
|
||||
job: pipeline_variables
|
||||
@@ -77,7 +77,6 @@
|
||||
- run_cmd python $CHECKOUT_REF_SCRIPT ci-test-runner-configs ci-test-runner-configs
|
||||
# CI specific options start from "--known-failure-cases-file xxx". could ignore when running locally
|
||||
- run_cmd pytest $nodes
|
||||
--pipeline-id $PARENT_PIPELINE_ID
|
||||
--junitxml=XUNIT_RESULT_${CI_JOB_ID}.xml
|
||||
--ignore-result-files ${KNOWN_FAILURE_CASES_FILE_NAME}
|
||||
--parallel-count ${CI_NODE_TOTAL:-1}
|
||||
|
||||
@@ -4,17 +4,16 @@ import os
|
||||
import subprocess
|
||||
import sys
|
||||
import typing as t
|
||||
from pathlib import Path
|
||||
|
||||
from dynamic_pipelines.constants import BINARY_SIZE_METRIC_NAME
|
||||
from idf_build_apps import App
|
||||
from idf_build_apps import CMakeApp
|
||||
from idf_build_apps.constants import BuildStatus
|
||||
from idf_build_apps.utils import rmdir
|
||||
from idf_ci_utils import APP_EXTRA_S3_ARTIFACT_TYPE
|
||||
from idf_ci_utils import idf_relpath
|
||||
from metrics.size_metrics import collect_build_metrics
|
||||
|
||||
if t.TYPE_CHECKING:
|
||||
pass
|
||||
_SIZE_METRICS_CONFIG_PATH = Path(__file__).parent.parent / 'metrics' / 'size_metrics' / 'size_metrics_config.yml'
|
||||
|
||||
|
||||
class IdfCMakeApp(CMakeApp):
|
||||
@@ -37,6 +36,8 @@ class IdfCMakeApp(CMakeApp):
|
||||
'gitlab',
|
||||
'upload-artifacts',
|
||||
self.app_dir,
|
||||
'--build-dir',
|
||||
self.build_dir,
|
||||
],
|
||||
[
|
||||
'idf-ci',
|
||||
@@ -63,103 +64,3 @@ class IdfCMakeApp(CMakeApp):
|
||||
self.build_path,
|
||||
exclude_file_patterns=['build_log.txt', 'size*.json'],
|
||||
)
|
||||
|
||||
|
||||
class Metrics:
|
||||
"""
|
||||
Represents a metric and its values for source, target, and the differences.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
source_value: t.Optional[float] = None,
|
||||
target_value: t.Optional[float] = None,
|
||||
difference: t.Optional[float] = None,
|
||||
difference_percentage: t.Optional[float] = None,
|
||||
) -> None:
|
||||
self.source_value = source_value or 0.0
|
||||
self.target_value = target_value or 0.0
|
||||
self.difference = difference or 0.0
|
||||
self.difference_percentage = difference_percentage or 0.0
|
||||
|
||||
def to_dict(self) -> t.Dict[str, t.Any]:
|
||||
"""
|
||||
Converts the Metrics object to a dictionary.
|
||||
"""
|
||||
return {
|
||||
'source_value': self.source_value,
|
||||
'target_value': self.target_value,
|
||||
'difference': self.difference,
|
||||
'difference_percentage': self.difference_percentage,
|
||||
}
|
||||
|
||||
|
||||
class AppWithMetricsInfo(IdfCMakeApp):
|
||||
metrics: t.Dict[str, Metrics]
|
||||
is_new_app: bool
|
||||
|
||||
def __init__(self, **kwargs: t.Any) -> None:
|
||||
super().__init__(**kwargs)
|
||||
|
||||
self.metrics = {metric_name: metric_data for metric_name, metric_data in kwargs.get('metrics', {}).items()}
|
||||
self.is_new_app = kwargs.get('is_new_app', False)
|
||||
|
||||
class Config:
|
||||
arbitrary_types_allowed = True
|
||||
|
||||
|
||||
def enrich_apps_with_metrics_info(
|
||||
app_metrics_info_map: t.Dict[str, t.Dict[str, t.Any]], apps: t.List[App]
|
||||
) -> t.List[AppWithMetricsInfo]:
|
||||
def _get_full_attributes(obj: App) -> t.Dict[str, t.Any]:
|
||||
"""
|
||||
Retrieves all attributes of an object, including properties and computed fields.
|
||||
"""
|
||||
attributes: t.Dict[str, t.Any] = obj.__dict__.copy()
|
||||
for attr in dir(obj):
|
||||
if not attr.startswith('_'): # Skip private/internal attributes
|
||||
try:
|
||||
value = getattr(obj, attr)
|
||||
# Include only if it's not already in __dict__
|
||||
if attr not in attributes:
|
||||
attributes[attr] = value
|
||||
except Exception:
|
||||
# Skip attributes that raise exceptions (e.g., methods needing args)
|
||||
pass
|
||||
return attributes
|
||||
|
||||
default_metrics_structure = {
|
||||
BINARY_SIZE_METRIC_NAME: Metrics(
|
||||
source_value=0,
|
||||
target_value=0,
|
||||
difference=0,
|
||||
difference_percentage=0.0,
|
||||
),
|
||||
}
|
||||
|
||||
apps_with_metrics_info = []
|
||||
for app in apps:
|
||||
app.app_dir = idf_relpath(app.app_dir)
|
||||
key = f'{app.app_dir}_{app.config_name}_{app.target}'
|
||||
app_attributes = _get_full_attributes(app)
|
||||
|
||||
metrics = {metric_name: default_metric for metric_name, default_metric in default_metrics_structure.items()}
|
||||
is_new_app = False
|
||||
|
||||
if key in app_metrics_info_map:
|
||||
info = app_metrics_info_map[key]
|
||||
for metric_name, metric_data in info.get('metrics', {}).items():
|
||||
metrics[metric_name] = Metrics(
|
||||
source_value=metric_data.get('source_value', 0),
|
||||
target_value=metric_data.get('target_value', 0),
|
||||
difference=metric_data.get('difference', 0),
|
||||
difference_percentage=metric_data.get('difference_percentage', 0.0),
|
||||
)
|
||||
|
||||
is_new_app = info.get('is_new_app', False)
|
||||
|
||||
app_attributes.update({'metrics': metrics, 'is_new_app': is_new_app})
|
||||
|
||||
apps_with_metrics_info.append(AppWithMetricsInfo(**app_attributes))
|
||||
|
||||
return apps_with_metrics_info
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
import os
|
||||
import typing as t
|
||||
@@ -9,6 +9,7 @@ import pytest
|
||||
import yaml
|
||||
from _pytest.config import Config
|
||||
from _pytest.python import Function
|
||||
from _pytest.python import Metafunc
|
||||
from _pytest.runner import CallInfo
|
||||
from dynamic_pipelines.constants import KNOWN_GENERATE_TEST_CHILD_PIPELINE_WARNINGS_FILEPATH
|
||||
from idf_ci import IdfPytestPlugin
|
||||
@@ -114,6 +115,55 @@ class IdfLocalPlugin:
|
||||
|
||||
return item.callspec.params.get(key, default) or default
|
||||
|
||||
@staticmethod
|
||||
def _has_parametrized_arg(metafunc: Metafunc, arg_name: str) -> bool:
|
||||
for marker in metafunc.definition.iter_markers(name='parametrize'):
|
||||
if not marker.args:
|
||||
continue
|
||||
|
||||
argnames = marker.args[0]
|
||||
if isinstance(argnames, str):
|
||||
names = [name.strip() for name in argnames.split(',')]
|
||||
else:
|
||||
names = list(argnames)
|
||||
|
||||
if arg_name in names:
|
||||
return True
|
||||
|
||||
for callspec in getattr(metafunc, '_calls', []):
|
||||
if arg_name in callspec.params:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def _is_linux_target_run(config: Config) -> bool:
|
||||
target = config.getoption('target')
|
||||
if not target:
|
||||
return False
|
||||
|
||||
if isinstance(target, str):
|
||||
targets = [_t.strip() for _t in target.split(',')]
|
||||
else:
|
||||
targets = [str(_t).strip() for _t in target]
|
||||
|
||||
return 'linux' in targets
|
||||
|
||||
@pytest.hookimpl(trylast=True)
|
||||
def pytest_generate_tests(self, metafunc: Metafunc) -> None:
|
||||
if 'embedded_services' not in metafunc.fixturenames:
|
||||
return
|
||||
|
||||
if self._has_parametrized_arg(metafunc, 'embedded_services'):
|
||||
return
|
||||
|
||||
if metafunc.definition.get_closest_marker('qemu') is not None:
|
||||
metafunc.parametrize('embedded_services', ['idf,qemu'], indirect=True)
|
||||
return
|
||||
|
||||
if self._is_linux_target_run(metafunc.config):
|
||||
metafunc.parametrize('embedded_services', ['idf'], indirect=True)
|
||||
|
||||
@pytest.hookimpl(wrapper=True)
|
||||
def pytest_collection_modifyitems(self, config: Config, items: t.List[Function]) -> t.Generator[None, None, None]:
|
||||
yield # throw it back to idf-ci
|
||||
|
||||
@@ -661,6 +661,21 @@ macro(idf_build_process target)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
idf_build_get_property(prefix __PREFIX)
|
||||
|
||||
file(GLOB root_dep_component_dirs
|
||||
${IDF_TOOLS_PATH}/root_managed_components/idf${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}.${IDF_VERSION_PATCH}/*)
|
||||
list(SORT root_dep_component_dirs)
|
||||
foreach(component_dir ${root_dep_component_dirs})
|
||||
# A potential component must be a directory
|
||||
if(IS_DIRECTORY ${component_dir})
|
||||
__component_dir_quick_check(is_component ${component_dir})
|
||||
if(is_component)
|
||||
__component_add(${component_dir} ${prefix} "idf_managed_components")
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Perform early expansion of component CMakeLists.txt in CMake scripting mode.
|
||||
# It is here we retrieve the public and private requirements of each component.
|
||||
# It is also here we add the common component requirements to each component's
|
||||
|
||||
@@ -52,6 +52,13 @@ if(NOT __idf_env_set)
|
||||
include(prefix_map)
|
||||
include(openocd)
|
||||
|
||||
# ESP-IDF extra dependencies defined in tools/idf_extra_components.yml
|
||||
if(WIN32)
|
||||
set_default(IDF_TOOLS_PATH "$ENV{USERPROFILE}/.espressif")
|
||||
else()
|
||||
set_default(IDF_TOOLS_PATH "$ENV{HOME}/.espressif")
|
||||
endif()
|
||||
|
||||
__build_init("${idf_path}")
|
||||
|
||||
# Check if IDF_ENV_FPGA environment is set
|
||||
|
||||
@@ -131,6 +131,8 @@ foreach(__component_target ${__component_targets})
|
||||
|
||||
if("${__component_source}" STREQUAL "idf_components")
|
||||
list(APPEND __TARGETS_IDF_COMPONENTS ${__component_target})
|
||||
elseif("${__component_source}" STREQUAL "idf_managed_components")
|
||||
list(APPEND __TARGETS_IDF_MANAGED_COMPONENTS ${__component_target})
|
||||
elseif("${__component_source}" STREQUAL "project_managed_components")
|
||||
list(APPEND __TARGETS_PROJECT_MANAGED_COMPONENTS ${__component_target})
|
||||
elseif("${__component_source}" STREQUAL "project_extra_components")
|
||||
@@ -147,6 +149,7 @@ set(__sorted_component_targets "")
|
||||
foreach(__target IN LISTS __TARGETS_PROJECT_COMPONENTS
|
||||
__TARGETS_PROJECT_EXTRA_COMPONENTS
|
||||
__TARGETS_PROJECT_MANAGED_COMPONENTS
|
||||
__TARGETS_IDF_MANAGED_COMPONENTS
|
||||
__TARGETS_IDF_COMPONENTS)
|
||||
__component_get_property(__component_name ${__target} COMPONENT_NAME)
|
||||
list(APPEND __sorted_component_targets ${__target})
|
||||
|
||||
11
tools/idf_extra_components.yml
Normal file
11
tools/idf_extra_components.yml
Normal file
@@ -0,0 +1,11 @@
|
||||
# This file defines extra dependencies for ESP-IDF
|
||||
# the dependencies defined here will be downloaded to
|
||||
# $IDF_TOOLS_PATH/root_managed_components
|
||||
# Each major.minor version of ESP-IDF can have its own subdirectory
|
||||
# For example, for ESP-IDF v6.0, the dependencies will be installed to
|
||||
# $IDF_TOOLS_PATH/root_managed_components/idf6.0
|
||||
|
||||
# The syntax is defined in:
|
||||
# https://docs.espressif.com/projects/idf-component-manager/en/latest/reference/manifest_file.html#dependencies
|
||||
|
||||
#dependencies:
|
||||
@@ -6,7 +6,7 @@
|
||||
# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/tools/idf-tools.html
|
||||
|
||||
# ci
|
||||
idf-ci>=0.3,<1
|
||||
idf-ci
|
||||
|
||||
coverage
|
||||
jsonschema
|
||||
|
||||
@@ -166,7 +166,6 @@ def test_examples_security_secure_boot_ecdsa(dut: Dut) -> None:
|
||||
|
||||
# Test secure boot flow.
|
||||
# Correctly signed bootloader + correctly signed app should work
|
||||
@pytest.mark.host_test
|
||||
@pytest.mark.qemu
|
||||
@pytest.mark.parametrize(
|
||||
'qemu_extra_args',
|
||||
|
||||
@@ -6,7 +6,6 @@ from pytest_embedded import Dut
|
||||
from pytest_embedded_idf.utils import idf_parametrize
|
||||
|
||||
|
||||
@pytest.mark.host_test
|
||||
@pytest.mark.qemu
|
||||
@pytest.mark.parametrize('config', ['secure_update_with_fe'], indirect=True)
|
||||
@idf_parametrize('target', ['esp32c3'], indirect=['target'])
|
||||
|
||||
@@ -6,7 +6,6 @@ from pytest_embedded_idf.utils import idf_parametrize
|
||||
|
||||
|
||||
@pytest.mark.qemu
|
||||
@pytest.mark.host_test
|
||||
@idf_parametrize('target', ['esp32', 'esp32c3'], indirect=['target'])
|
||||
def test_std_filesystem(dut: Dut) -> None:
|
||||
dut.expect_exact('All tests passed', timeout=200)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
import os
|
||||
|
||||
@@ -10,7 +10,6 @@ PROMPT = 'test_intr_dump>'
|
||||
|
||||
|
||||
@pytest.mark.qemu
|
||||
@pytest.mark.host_test
|
||||
@idf_parametrize('target', ['esp32'], indirect=['target'])
|
||||
def test_esp_intr_dump_nonshared(dut: Dut) -> None:
|
||||
dut.expect_exact(PROMPT, timeout=30)
|
||||
@@ -24,7 +23,6 @@ def test_esp_intr_dump_nonshared(dut: Dut) -> None:
|
||||
|
||||
|
||||
@pytest.mark.qemu
|
||||
@pytest.mark.host_test
|
||||
@idf_parametrize('target', ['esp32'], indirect=['target'])
|
||||
def test_esp_intr_dump_shared(dut: Dut) -> None:
|
||||
dut.expect_exact(PROMPT, timeout=30)
|
||||
@@ -54,5 +52,5 @@ def test_esp_intr_dump_expected_output(dut: Dut) -> None:
|
||||
dut.expect_exact(PROMPT, timeout=30)
|
||||
dut.write('intr_dump\n')
|
||||
exp_out_file = os.path.join(os.path.dirname(__file__), 'expected_output', f'{dut.target}.txt')
|
||||
for line in open(exp_out_file, 'r').readlines():
|
||||
for line in open(exp_out_file).readlines():
|
||||
dut.expect_exact(line.strip())
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
import os
|
||||
|
||||
import pytest
|
||||
from idf_ci_utils import IDF_PATH
|
||||
from pytest_embedded import Dut
|
||||
from pytest_embedded_idf.utils import idf_parametrize
|
||||
|
||||
@@ -16,12 +15,12 @@ def test_app_mmu_page_size_32k_and_bootloader_mmu_page_size_64k(dut: Dut, app_do
|
||||
|
||||
assert '32K' in config
|
||||
app_config = config.replace('32K', '64K')
|
||||
build_dir = f'build_{dut.target}_{app_config}'
|
||||
|
||||
path_to_mmu_page_size_64k_build = os.path.join(dut.app.app_path, f'build_{dut.target}_{app_config}')
|
||||
if app_downloader:
|
||||
app_downloader.download_app(os.path.relpath(path_to_mmu_page_size_64k_build, IDF_PATH), 'flash')
|
||||
app_downloader.download_app(dut.app.app_path, build_dir, 'flash')
|
||||
|
||||
dut.serial.bootloader_flash(path_to_mmu_page_size_64k_build)
|
||||
dut.serial.bootloader_flash(os.path.join(dut.app.app_path, build_dir))
|
||||
dut.expect('MMU page size mismatch')
|
||||
dut.expect('App is running')
|
||||
dut.expect('Partition test done')
|
||||
@@ -36,12 +35,12 @@ def test_app_mmu_page_size_64k_and_bootloader_mmu_page_size_32k(dut: Dut, app_do
|
||||
|
||||
assert '64K' in config
|
||||
app_config = config.replace('64K', '32K')
|
||||
build_dir = f'build_{dut.target}_{app_config}'
|
||||
|
||||
path_to_mmu_page_size_32k_build = os.path.join(dut.app.app_path, f'build_{dut.target}_{app_config}')
|
||||
if app_downloader:
|
||||
app_downloader.download_app(os.path.relpath(path_to_mmu_page_size_32k_build, IDF_PATH), 'flash')
|
||||
app_downloader.download_app(dut.app.app_path, build_dir, 'flash')
|
||||
|
||||
dut.serial.bootloader_flash(path_to_mmu_page_size_32k_build)
|
||||
dut.serial.bootloader_flash(os.path.join(dut.app.app_path, build_dir))
|
||||
dut.expect('MMU page size mismatch')
|
||||
dut.expect('App is running')
|
||||
dut.expect('Partition test done')
|
||||
|
||||
@@ -4,7 +4,6 @@ import os
|
||||
import re
|
||||
|
||||
import pytest
|
||||
from idf_ci_utils import IDF_PATH
|
||||
from pytest_embedded import Dut
|
||||
from pytest_embedded_idf.utils import idf_parametrize
|
||||
|
||||
@@ -19,12 +18,12 @@ def test_multicore_app_and_unicore_bootloader(dut: Dut, app_downloader, config)
|
||||
|
||||
assert 'multicore' in config
|
||||
app_config = config.replace('multicore', 'unicore')
|
||||
build_dir = f'build_{dut.target}_{app_config}'
|
||||
|
||||
path_to_unicore_build = os.path.join(dut.app.app_path, f'build_{dut.target}_{app_config}')
|
||||
if app_downloader:
|
||||
app_downloader.download_app(os.path.relpath(path_to_unicore_build, IDF_PATH), 'flash')
|
||||
app_downloader.download_app(dut.app.app_path, build_dir, 'flash')
|
||||
|
||||
dut.serial.bootloader_flash(path_to_unicore_build)
|
||||
dut.serial.bootloader_flash(os.path.join(dut.app.app_path, build_dir))
|
||||
dut.expect('Unicore bootloader')
|
||||
dut.expect('Multicore app')
|
||||
if 'psram' in config:
|
||||
@@ -43,12 +42,12 @@ def test_unicore_app_and_multicore_bootloader(dut: Dut, app_downloader, config)
|
||||
|
||||
assert 'unicore' in config
|
||||
app_config = config.replace('unicore', 'multicore')
|
||||
build_dir = f'build_{dut.target}_{app_config}'
|
||||
|
||||
path_to_multicore_build = os.path.join(dut.app.app_path, f'build_{dut.target}_{app_config}')
|
||||
if app_downloader:
|
||||
app_downloader.download_app(os.path.relpath(path_to_multicore_build, IDF_PATH), 'flash')
|
||||
app_downloader.download_app(dut.app.app_path, build_dir, 'flash')
|
||||
|
||||
dut.serial.bootloader_flash(path_to_multicore_build)
|
||||
dut.serial.bootloader_flash(os.path.join(dut.app.app_path, build_dir))
|
||||
dut.expect('Multicore bootloader')
|
||||
dut.expect('Unicore app')
|
||||
if 'psram' in config:
|
||||
|
||||
@@ -14,6 +14,9 @@ junit_family = xunit1
|
||||
junit_logging = stdout
|
||||
junit_log_passing_tests = False
|
||||
|
||||
filterwarnings =
|
||||
ignore::pytest.PytestExperimentalApiWarning
|
||||
|
||||
## !! When adding new markers, don't forget to update also the tools\test_build_system\README.md !!
|
||||
markers =
|
||||
test_app_copy: specify relative path of the app to copy, and the prefix of the destination directory name
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
# SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
import json
|
||||
import os.path
|
||||
import textwrap
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
from test_build_system_helpers import EXT_IDF_PATH
|
||||
from test_build_system_helpers import IdfPyFunc
|
||||
from test_build_system_helpers import replace_in_file
|
||||
|
||||
@@ -192,3 +195,84 @@ class TestOptionalDependencyWithKconfig:
|
||||
data = json.load(open(test_app_copy / 'build' / 'project_description.json'))
|
||||
assert ['example__cmp'] == data['build_component_info']['foo']['priv_reqs']
|
||||
assert ['espressif__mdns'] == data['build_component_info']['foo']['reqs']
|
||||
|
||||
|
||||
@pytest.mark.revert_later(['tools/idf_extra_components.yml'])
|
||||
class TestIdfRootDependency:
|
||||
def test_basic_build(self, idf_py: IdfPyFunc, test_app_copy: Path) -> None:
|
||||
with open(os.path.join(EXT_IDF_PATH, 'tools', 'idf_extra_components.yml'), 'w') as fw:
|
||||
fw.write(
|
||||
textwrap.dedent("""
|
||||
dependencies:
|
||||
espressif/mdns: "*"
|
||||
""")
|
||||
)
|
||||
|
||||
replace_in_file(
|
||||
(test_app_copy / 'main' / 'build_test_app.c'),
|
||||
'// placeholder_before_main',
|
||||
'#include "mdns.h"',
|
||||
)
|
||||
|
||||
replace_in_file(
|
||||
(test_app_copy / 'main' / 'CMakeLists.txt'),
|
||||
'# placeholder_inside_idf_component_register',
|
||||
'REQUIRES mdns',
|
||||
)
|
||||
|
||||
idf_py('build')
|
||||
|
||||
def test_build_only_when_required(self, idf_py: IdfPyFunc, test_app_copy: Path) -> None:
|
||||
with open(os.path.join(EXT_IDF_PATH, 'tools', 'idf_extra_components.yml'), 'w') as fw:
|
||||
fw.write(
|
||||
textwrap.dedent("""
|
||||
dependencies:
|
||||
espressif/mdns: "*"
|
||||
example/cmp: "*"
|
||||
""")
|
||||
)
|
||||
|
||||
idf_py('reconfigure')
|
||||
|
||||
data = json.load(open(test_app_copy / 'build' / 'project_description.json'))
|
||||
assert 'espressif__mdns' not in data['build_components']
|
||||
assert 'example__cmp' not in data['build_components']
|
||||
|
||||
replace_in_file(
|
||||
(test_app_copy / 'main' / 'CMakeLists.txt'),
|
||||
'# placeholder_inside_idf_component_register',
|
||||
'REQUIRES mdns',
|
||||
)
|
||||
|
||||
idf_py('reconfigure')
|
||||
data = json.load(open(test_app_copy / 'build' / 'project_description.json'))
|
||||
assert 'espressif__mdns' in data['build_components']
|
||||
assert 'example__cmp' not in data['build_components']
|
||||
|
||||
def test_cleanup_unused(self, idf_py: IdfPyFunc, test_app_copy: Path) -> None:
|
||||
with open(os.path.join(EXT_IDF_PATH, 'tools', 'idf_extra_components.yml'), 'w') as fw:
|
||||
fw.write(
|
||||
textwrap.dedent("""
|
||||
dependencies:
|
||||
espressif/mdns: "*"
|
||||
""")
|
||||
)
|
||||
|
||||
idf_py('reconfigure')
|
||||
data = json.load(open(test_app_copy / 'build' / 'project_description.json'))
|
||||
assert 'espressif__mdns' in data['all_component_info']
|
||||
|
||||
with open(os.path.join(EXT_IDF_PATH, 'tools', 'idf_extra_components.yml'), 'w') as fw:
|
||||
fw.write(
|
||||
textwrap.dedent("""
|
||||
dependencies:
|
||||
espressif/led_strip: "*"
|
||||
example/cmp: "*"
|
||||
""")
|
||||
)
|
||||
|
||||
idf_py('reconfigure')
|
||||
data = json.load(open(test_app_copy / 'build' / 'project_description.json'))
|
||||
assert 'espressif__led_strip' in data['all_component_info']
|
||||
assert 'example__cmp' in data['all_component_info']
|
||||
assert 'espressif__mdns' not in data['all_component_info']
|
||||
|
||||
@@ -27,9 +27,9 @@ except ImportError:
|
||||
import idf
|
||||
|
||||
current_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
idf_py_path = os.path.join(current_dir, '..', 'idf.py')
|
||||
idf_py_path = os.path.normpath(os.path.join(current_dir, '..', 'idf.py'))
|
||||
extension_path = os.path.join(current_dir, 'test_idf_extensions', 'test_ext')
|
||||
py_actions_path = os.path.join(current_dir, '..', 'idf_py_actions')
|
||||
py_actions_path = os.path.normpath(os.path.join(current_dir, '..', 'idf_py_actions'))
|
||||
link_path = os.path.join(py_actions_path, 'test_ext')
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user