Merge branch 'ci/fixes' into 'master'

ci: a few fixes

Closes IDFCI-3018

See merge request espressif/esp-idf!40610
This commit is contained in:
Fu Hanxi
2025-07-17 03:13:52 +02:00
14 changed files with 48 additions and 27 deletions

View File

@@ -51,6 +51,8 @@
/.github/workflows/ @esp-idf-codeowners/ci /.github/workflows/ @esp-idf-codeowners/ci
/.gitlab-ci.yml @esp-idf-codeowners/ci /.gitlab-ci.yml @esp-idf-codeowners/ci
/.gitlab/ci/ @esp-idf-codeowners/ci /.gitlab/ci/ @esp-idf-codeowners/ci
/.idf_build_apps.toml @esp-idf-codeowners/ci
/.idf_ci.toml @esp-idf-codeowners/ci
/.pre-commit-config.yaml @esp-idf-codeowners/ci /.pre-commit-config.yaml @esp-idf-codeowners/ci
/.readthedocs.yml @esp-idf-codeowners/docs /.readthedocs.yml @esp-idf-codeowners/docs
/.vale.ini @esp-idf-codeowners/docs /.vale.ini @esp-idf-codeowners/docs

View File

@@ -300,13 +300,11 @@ test_pytest_qemu:
- run_cmd idf-ci build run - run_cmd idf-ci build run
--build-system cmake --build-system cmake
--target $IDF_TARGET --target $IDF_TARGET
--only-test-related
-m qemu -m qemu
--modified-files ${MR_MODIFIED_FILES} --modified-files ${MR_MODIFIED_FILES}
- run_cmd idf-ci gitlab download-known-failure-cases-file ${KNOWN_FAILURE_CASES_FILE_NAME} - run_cmd idf-ci gitlab download-known-failure-cases-file ${KNOWN_FAILURE_CASES_FILE_NAME}
- run_cmd pytest - run_cmd pytest
--target $IDF_TARGET --target $IDF_TARGET
--log-cli-level DEBUG
-m qemu -m qemu
--embedded-services idf,qemu --embedded-services idf,qemu
--junitxml=XUNIT_RESULT.xml --junitxml=XUNIT_RESULT.xml

View File

@@ -21,13 +21,12 @@ ignore_warning_files = [
build_dir = "build_@t_@w" build_dir = "build_@t_@w"
build_log_filename = "build_log.txt" build_log_filename = "build_log.txt"
size_json_filename = "size.json" size_json_filename = "size_${CI_JOB_ID}.json"
verbose = 1 # INFO verbose = 1 # INFO
# collect # collect
collect_app_info_filename = "app_info_${CI_JOB_NAME_SLUG}.txt" collect_app_info_filename = "app_info_${CI_JOB_NAME_SLUG}.txt"
collect_size_info_filename = "size_info_${CI_JOB_NAME_SLUG}.txt" # TODO remove this file when ci-dashboard is ready
junitxml = "build_summary_${CI_JOB_NAME_SLUG}.xml" junitxml = "build_summary_${CI_JOB_NAME_SLUG}.xml"
# manifest # manifest

View File

@@ -74,7 +74,7 @@ patterns = [
bucket = "idf-artifacts" bucket = "idf-artifacts"
patterns = [ patterns = [
'**/build*/build_log.txt', '**/build*/build_log.txt',
'**/build*/size.json', '**/build*/size*.json',
] ]
[gitlab.artifacts.s3.junit] [gitlab.artifacts.s3.junit]

View File

@@ -13,9 +13,10 @@ from pytest_embedded_idf.utils import idf_parametrize
], ],
indirect=True, indirect=True,
) )
@pytest.mark.parametrize('test_message', ['test123456789!@#%^&*'])
@idf_parametrize('target', ['esp32s3', 'esp32c3', 'esp32c6', 'esp32h2'], indirect=['target']) @idf_parametrize('target', ['esp32s3', 'esp32c3', 'esp32c6', 'esp32h2'], indirect=['target'])
def test_usj_vfs_select(dut: Dut, test_message: list) -> None: def test_usj_vfs_select(dut: Dut) -> None:
test_message = 'test123456789!@#%^&*'
dut.expect_exact('Press ENTER to see the list of tests') dut.expect_exact('Press ENTER to see the list of tests')
dut.write('"test select read, write and timeout"') dut.write('"test select read, write and timeout"')
dut.expect_exact('select timed out', timeout=2) dut.expect_exact('select timed out', timeout=2)
@@ -32,9 +33,10 @@ def test_usj_vfs_select(dut: Dut, test_message: list) -> None:
], ],
indirect=True, indirect=True,
) )
@pytest.mark.parametrize('test_message', ['!(@*#&(!*@&#((SDasdkjhad\nce'])
@idf_parametrize('target', ['esp32s3', 'esp32c3', 'esp32c6', 'esp32h2'], indirect=['target']) @idf_parametrize('target', ['esp32s3', 'esp32c3', 'esp32c6', 'esp32h2'], indirect=['target'])
def test_usj_vfs_read_return(dut: Dut, test_message: list) -> None: def test_usj_vfs_read_return(dut: Dut) -> None:
test_message = '!(@*#&(!*@&#((SDasdkjhad\nce'
dut.expect_exact('Press ENTER to see the list of tests') dut.expect_exact('Press ENTER to see the list of tests')
dut.write('"read does not return on new line character"') dut.write('"read does not return on new line character"')
dut.expect_exact('ready to receive', timeout=2) dut.expect_exact('ready to receive', timeout=2)
@@ -50,9 +52,10 @@ def test_usj_vfs_read_return(dut: Dut, test_message: list) -> None:
], ],
indirect=True, indirect=True,
) )
@pytest.mark.parametrize('test_message', ['testdata'])
@idf_parametrize('target', ['esp32s3', 'esp32c3', 'esp32c6', 'esp32h2'], indirect=['target']) @idf_parametrize('target', ['esp32s3', 'esp32c3', 'esp32c6', 'esp32h2'], indirect=['target'])
def test_usj_vfs_read_blocking(dut: Dut, test_message: list) -> None: def test_usj_vfs_read_blocking(dut: Dut) -> None:
test_message = 'testdata'
dut.expect_exact('Press ENTER to see the list of tests') dut.expect_exact('Press ENTER to see the list of tests')
dut.write('"blocking read returns with available data"') dut.write('"blocking read returns with available data"')
dut.expect_exact('ready to receive', timeout=2) dut.expect_exact('ready to receive', timeout=2)

View File

@@ -13,9 +13,10 @@ from pytest_embedded_idf.utils import idf_parametrize
], ],
indirect=True, indirect=True,
) )
@pytest.mark.parametrize('test_message', ['test123456789!@#%^&*'])
@idf_parametrize('target', ['esp32s3'], indirect=['target']) @idf_parametrize('target', ['esp32s3'], indirect=['target'])
def test_usb_cdc_vfs_default(dut: Dut, test_message: str) -> None: def test_usb_cdc_vfs_default(dut: Dut) -> None:
test_message = 'test123456789!@#%^&*'
# test run: test_usb_cdc_select # test run: test_usb_cdc_select
dut.expect_exact('test_usb_cdc_select', timeout=2) dut.expect_exact('test_usb_cdc_select', timeout=2)
dut.expect_exact('select timed out', timeout=2) dut.expect_exact('select timed out', timeout=2)

View File

@@ -26,7 +26,6 @@ import signal
import time import time
import typing as t import typing as t
from copy import deepcopy from copy import deepcopy
from telnetlib import Telnet
from urllib.parse import quote from urllib.parse import quote
import common_test_methods # noqa: F401 import common_test_methods # noqa: F401
@@ -48,6 +47,7 @@ from pytest_embedded.utils import to_bytes
from pytest_embedded.utils import to_str from pytest_embedded.utils import to_str
from pytest_embedded_idf.dut import IdfDut from pytest_embedded_idf.dut import IdfDut
from pytest_embedded_idf.unity_tester import CaseTester from pytest_embedded_idf.unity_tester import CaseTester
from pytest_embedded_jtag._telnetlib.telnetlib import Telnet # python 3.13 removed telnetlib, use this instead
############ ############
@@ -300,13 +300,19 @@ def build_dir(
""" """
# download from minio on CI # download from minio on CI
case: PytestCase = request.node.stash[IDF_CI_PYTEST_CASE_KEY] case: PytestCase = request.node.stash[IDF_CI_PYTEST_CASE_KEY]
if app_downloader: if 'skip_app_downloader' in case.all_markers:
logging.debug('skip_app_downloader marker found, skip downloading app')
downloader = None
else:
downloader = app_downloader
if downloader:
# somehow hardcoded... # somehow hardcoded...
app_build_path = os.path.join(idf_relpath(app_path), f'build_{target}_{config}') app_build_path = os.path.join(idf_relpath(app_path), f'build_{target}_{config}')
if requires_elf_or_map(case): if requires_elf_or_map(case):
app_downloader.download_app(app_build_path) downloader.download_app(app_build_path)
else: else:
app_downloader.download_app(app_build_path, 'flash') downloader.download_app(app_build_path, 'flash')
check_dirs = [f'build_{target}_{config}'] check_dirs = [f'build_{target}_{config}']
else: else:
check_dirs = [] check_dirs = []

View File

@@ -7,10 +7,12 @@ import random
import re import re
import secrets import secrets
import subprocess import subprocess
import sys
import threading import threading
import time import time
from typing import Tuple from typing import Tuple
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
import ot_ci_function as ocf import ot_ci_function as ocf
import pexpect import pexpect
import pytest import pytest

View File

@@ -109,9 +109,6 @@ def test_examples_protocol_esp_http_client_dynamic_buffer(dut: Dut) -> None:
@pytest.mark.host_test @pytest.mark.host_test
# Currently we are just testing the build for esp_http_client on Linux target. So skipping the test run.
# Later we will enable the test run for Linux target as well.
@pytest.mark.skipif('config.getvalue("target") == "linux"', reason='Do not run on Linux')
@pytest.mark.parametrize( @pytest.mark.parametrize(
'config', 'config',
[ [
@@ -121,5 +118,11 @@ def test_examples_protocol_esp_http_client_dynamic_buffer(dut: Dut) -> None:
indirect=True, indirect=True,
) )
@idf_parametrize('target', ['linux'], indirect=['target']) @idf_parametrize('target', ['linux'], indirect=['target'])
def test_examples_protocol_esp_http_client_linux(dut: Dut) -> None: def test_examples_protocol_esp_http_client_linux(target: str, dut: Dut) -> None:
if target == 'linux':
pytest.skip(
'Currently we are just testing the build for esp_http_client on Linux target. '
'So skipping the test run. Later we will enable the test run for Linux target as well.'
)
dut.expect('Finish http example', timeout=60) dut.expect('Finish http example', timeout=60)

View File

@@ -39,6 +39,7 @@ junit_log_passing_tests = False
markers = markers =
temp_skip_ci: mark test to be skipped in CI temp_skip_ci: mark test to be skipped in CI
temp_skip: mark test to be skipped in CI and locally temp_skip: mark test to be skipped in CI and locally
skip_app_downloader: mark test required apps built locally, not downloaded from CI
require_elf: mark test to be skipped if no elf file is found require_elf: mark test to be skipped if no elf file is found
env_markers = env_markers =

View File

@@ -82,7 +82,7 @@
# CI specific options start from "--known-failure-cases-file xxx". could ignore when running locally # CI specific options start from "--known-failure-cases-file xxx". could ignore when running locally
- run_cmd pytest $nodes - run_cmd pytest $nodes
--pipeline-id $PARENT_PIPELINE_ID --pipeline-id $PARENT_PIPELINE_ID
--junitxml=XUNIT_RESULT_${CI_JOB_NAME_SLUG}.xml --junitxml=XUNIT_RESULT_${CI_JOB_ID}.xml
--ignore-result-files ${KNOWN_FAILURE_CASES_FILE_NAME} --ignore-result-files ${KNOWN_FAILURE_CASES_FILE_NAME}
--parallel-count ${CI_NODE_TOTAL:-1} --parallel-count ${CI_NODE_TOTAL:-1}
--parallel-index ${CI_NODE_INDEX:-1} --parallel-index ${CI_NODE_INDEX:-1}

View File

@@ -47,7 +47,11 @@ generate_pytest_child_pipeline:
- build - build
- shiny - shiny
needs: needs:
- build_test_related_apps # won't work if the parallel count exceeds 100, now it's around 50 - job: build_test_related_apps
optional: true
- job: build_non_test_related_apps # make sure all build jobs are passed
optional: true
artifacts: false
- pipeline: $PARENT_PIPELINE_ID - pipeline: $PARENT_PIPELINE_ID
job: pipeline_variables job: pipeline_variables
artifacts: artifacts:

View File

@@ -150,6 +150,9 @@ class IdfLocalPlugin:
if 'esp32c2' in case.targets and 'xtal_26mhz' not in case.all_markers: if 'esp32c2' in case.targets and 'xtal_26mhz' not in case.all_markers:
item.add_marker('xtal_40mhz') item.add_marker('xtal_40mhz')
if 'host_test' in case.all_markers:
item.add_marker('skip_app_downloader') # host_test jobs will build the apps itself
def pytest_custom_test_case_name(self, item: Function) -> str: def pytest_custom_test_case_name(self, item: Function) -> str:
return item.funcargs.get('test_case_name', item.nodeid) # type: ignore return item.funcargs.get('test_case_name', item.nodeid) # type: ignore

View File

@@ -936,11 +936,10 @@ def test_rtc_fast_reg1_execute_violation(dut: PanicTestDut, test_func_name: str)
@pytest.mark.generic @pytest.mark.generic
@pytest.mark.skipif( @pytest.mark.temp_skip(
'config.getvalue("target") in ["esp32c5", "esp32c6", "esp32h2", "esp32p4", "esp32h21"]', targets=['esp32c5', 'esp32c6', 'esp32h2', 'esp32p4', 'esp32h21'],
reason='Not a violation condition, no PMS peripheral case', reason='Not a violation condition, no PMS peripheral cases',
) )
@pytest.mark.temp_skip_ci(targets=['esp32h21'], reason='lack of runners')
@idf_parametrize('config, target', CONFIGS_MEMPROT_RTC_FAST_MEM, indirect=['config', 'target']) @idf_parametrize('config, target', CONFIGS_MEMPROT_RTC_FAST_MEM, indirect=['config', 'target'])
def test_rtc_fast_reg2_execute_violation(dut: PanicTestDut, test_func_name: str) -> None: def test_rtc_fast_reg2_execute_violation(dut: PanicTestDut, test_func_name: str) -> None:
dut.run_test_func(test_func_name) dut.run_test_func(test_func_name)