diff --git a/tools/ci/component_ut_dirs.txt b/tools/ci/component_ut_dirs.txt new file mode 100644 index 0000000000..3ce65b5f4c --- /dev/null +++ b/tools/ci/component_ut_dirs.txt @@ -0,0 +1 @@ +components/esp_netif/test_app diff --git a/tools/ci/config/build.yml b/tools/ci/config/build.yml index cc27f2bdff..00b51e13bd 100644 --- a/tools/ci/config/build.yml +++ b/tools/ci/config/build.yml @@ -85,12 +85,10 @@ build_esp_idf_tests_cmake_esp32s2: .build_examples_template: extends: .build_template - parallel: 8 artifacts: when: always expire_in: 4 days only: - # Here both 'variables' and 'refs' conditions are given. They are combined with "AND" logic. variables: - $BOT_TRIGGER_WITH_LABEL == null - $BOT_LABEL_BUILD @@ -98,8 +96,12 @@ build_esp_idf_tests_cmake_esp32s2: - $BOT_LABEL_REGULAR_TEST - $BOT_LABEL_WEEKEND_TEST variables: - SCAN_TEST_JSON: ${CI_PROJECT_DIR}/examples/test_configs/scan_${IDF_TARGET}_${BUILD_SYSTEM}.json - TEST_TYPE: "example_test" + TEST_PREFIX: examples + TEST_RELATIVE_DIR: examples + SCAN_TEST_JSON: ${CI_PROJECT_DIR}/${TEST_RELATIVE_DIR}/test_configs/scan_${IDF_TARGET}_${BUILD_SYSTEM}.json + TEST_TYPE: example_test + LOG_PATH: ${CI_PROJECT_DIR}/log_${TEST_PREFIX} + BUILD_PATH: ${CI_PROJECT_DIR}/build_${TEST_PREFIX} script: # RISC-V toolchain is optional but ULP may need it, so install: - $IDF_PATH/tools/idf_tools.py install riscv-none-embed-gcc @@ -113,16 +115,15 @@ build_examples_make: # This is a workaround for a rarely encountered issue with building examples in CI. # Probably related to building of Kconfig in 'make clean' stage retry: 1 + parallel: 8 artifacts: paths: - $LOG_PATH - - build_examples/*/*/*/build/size.json + - build_${TEST_PREFIX}/*/*/*/build/size.json - $SIZE_INFO_LOCATION variables: - LOG_PATH: "${CI_PROJECT_DIR}/log_examples_make" - BUILD_PATH: "${CI_PROJECT_DIR}/build_examples_make" - BUILD_SYSTEM: "make" - IDF_TARGET: "esp32" # currently we only support esp32 + BUILD_SYSTEM: make + IDF_TARGET: esp32 # currently we only support esp32 only: refs: - master @@ -140,22 +141,20 @@ build_examples_make: - scan_tests artifacts: paths: - - build_examples/list.json - - build_examples/list_job_*.json - - build_examples/*/*/*/sdkconfig - - build_examples/*/*/*/build/size.json - - build_examples/*/*/*/build/*.bin - - build_examples/*/*/*/build/*.elf - - build_examples/*/*/*/build/*.map - - build_examples/*/*/*/build/flasher_args.json - - build_examples/*/*/*/build/bootloader/*.bin - - build_examples/*/*/*/build/partition_table/*.bin + - build_${TEST_PREFIX}/list.json + - build_${TEST_PREFIX}/list_job_*.json + - build_${TEST_PREFIX}/*/*/*/sdkconfig + - build_${TEST_PREFIX}/*/*/*/build/size.json + - build_${TEST_PREFIX}/*/*/*/build/*.bin + - build_${TEST_PREFIX}/*/*/*/build/*.elf + - build_${TEST_PREFIX}/*/*/*/build/*.map + - build_${TEST_PREFIX}/*/*/*/build/flasher_args.json + - build_${TEST_PREFIX}/*/*/*/build/bootloader/*.bin + - build_${TEST_PREFIX}/*/*/*/build/partition_table/*.bin - $LOG_PATH - $SIZE_INFO_LOCATION variables: - LOG_PATH: "${CI_PROJECT_DIR}/log_examples" - BUILD_PATH: "${CI_PROJECT_DIR}/build_examples" - BUILD_SYSTEM: "cmake" + BUILD_SYSTEM: cmake build_examples_cmake_esp32: extends: .build_examples_cmake @@ -165,35 +164,15 @@ build_examples_cmake_esp32: build_examples_cmake_esp32s2: extends: .build_examples_cmake + parallel: 8 variables: IDF_TARGET: esp32s2 -.build_test_apps: &build_test_apps - extends: .build_template - stage: build - dependencies: - - scan_tests - artifacts: - when: always - paths: - - build_test_apps/list.json - - build_test_apps/list_job_*.json - - build_test_apps/*/*/*/sdkconfig - - build_test_apps/*/*/*/build/size.json - - build_test_apps/*/*/*/build/*.bin - - build_test_apps/*/*/*/build/*.elf - - build_test_apps/*/*/*/build/*.map - - build_test_apps/*/*/*/build/flasher_args.json - - build_test_apps/*/*/*/build/bootloader/*.bin - - build_test_apps/*/*/*/build/partition_table/*.bin - - $LOG_PATH - - $SIZE_INFO_LOCATION - expire_in: 3 days +.build_test_apps: + extends: .build_examples_cmake variables: - LOG_PATH: "${CI_PROJECT_DIR}/log_test_apps" - BUILD_PATH: "${CI_PROJECT_DIR}/build_test_apps" - BUILD_SYSTEM: "cmake" - SCAN_TEST_JSON: ${CI_PROJECT_DIR}/tools/test_apps/test_configs/scan_${IDF_TARGET}_${BUILD_SYSTEM}.json + TEST_PREFIX: test_apps + TEST_RELATIVE_DIR: tools/test_apps TEST_TYPE: custom_test only: variables: @@ -207,14 +186,38 @@ build_examples_cmake_esp32s2: build_test_apps_esp32: extends: .build_test_apps + parallel: 8 variables: IDF_TARGET: esp32 build_test_apps_esp32s2: extends: .build_test_apps + parallel: 8 variables: IDF_TARGET: esp32s2 +.build_component_ut: + extends: .build_test_apps + variables: + TEST_PREFIX: component_ut + TEST_RELATIVE_DIR: component_ut + only: + variables: + - $BOT_TRIGGER_WITH_LABEL == null + - $BOT_LABEL_BUILD + - $BOT_LABEL_REGULAR_TEST + - $BOT_LABEL_UNIT_TEST + - $BOT_LABEL_UNIT_TEST_S2 + +build_component_ut_esp32: + extends: .build_component_ut + variables: + IDF_TARGET: esp32 + +build_component_ut_esp32s2: + extends: .build_component_ut + variables: + IDF_TARGET: esp32s2 # If you want to add new build example jobs, please add it into dependencies of `.example_test_template` diff --git a/tools/ci/config/pre_check.yml b/tools/ci/config/pre_check.yml index c51b6c722c..f89430a818 100644 --- a/tools/ci/config/pre_check.yml +++ b/tools/ci/config/pre_check.yml @@ -146,19 +146,27 @@ scan_tests: - $BOT_LABEL_REGULAR_TEST - $BOT_LABEL_EXAMPLE_TEST - $BOT_LABEL_CUSTOM_TEST + - $BOT_LABEL_UNIT_TEST + - $BOT_LABEL_UNIT_TEST_S2 artifacts: paths: - $EXAMPLE_TEST_OUTPUT_DIR - $TEST_APPS_OUTPUT_DIR + - $COMPONENT_UT_OUTPUT_DIR variables: EXAMPLE_TEST_DIR: ${CI_PROJECT_DIR}/examples EXAMPLE_TEST_OUTPUT_DIR: ${CI_PROJECT_DIR}/examples/test_configs TEST_APPS_TEST_DIR: ${CI_PROJECT_DIR}/tools/test_apps TEST_APPS_OUTPUT_DIR: ${CI_PROJECT_DIR}/tools/test_apps/test_configs + COMPONENT_UT_DIR_TXT: ${CI_PROJECT_DIR}/tools/ci/component_ut_dirs.txt + COMPONENT_UT_OUTPUT_DIR: ${CI_PROJECT_DIR}/component_ut/test_configs script: - - python $CI_SCAN_TESTS_PY example_test -b make $EXAMPLE_TEST_DIR --exclude examples/build_system/idf_as_lib -c $TEST_CONFIG_FILE -o $EXAMPLE_TEST_OUTPUT_DIR - - python $CI_SCAN_TESTS_PY example_test -b cmake $EXAMPLE_TEST_DIR --exclude examples/build_system/idf_as_lib -c $TEST_CONFIG_FILE -o $EXAMPLE_TEST_OUTPUT_DIR + - *export_component_ut_dirs + - python $CI_SCAN_TESTS_PY example_test $EXAMPLE_TEST_DIR -b make --exclude examples/build_system/idf_as_lib -c $TEST_CONFIG_FILE -o $EXAMPLE_TEST_OUTPUT_DIR + - python $CI_SCAN_TESTS_PY example_test $EXAMPLE_TEST_DIR -b cmake --exclude examples/build_system/idf_as_lib -c $TEST_CONFIG_FILE -o $EXAMPLE_TEST_OUTPUT_DIR - python $CI_SCAN_TESTS_PY test_apps $TEST_APPS_TEST_DIR -c $TEST_CONFIG_FILE -o $TEST_APPS_OUTPUT_DIR + # template python test file not generated yet. preserve binary files for component UT + - python $CI_SCAN_TESTS_PY component_ut $COMPONENT_UT_DIRS -c $TEST_CONFIG_FILE -o $COMPONENT_UT_OUTPUT_DIR --preserve check_readme_links: extends: .check_job_template diff --git a/tools/ci/python_packages/ttfw_idf/CIScanTests.py b/tools/ci/python_packages/ttfw_idf/CIScanTests.py index 5c2e9004ef..21dd73dd13 100644 --- a/tools/ci/python_packages/ttfw_idf/CIScanTests.py +++ b/tools/ci/python_packages/ttfw_idf/CIScanTests.py @@ -8,18 +8,16 @@ from collections import defaultdict from find_apps import find_apps from find_build_apps import BUILD_SYSTEMS, BUILD_SYSTEM_CMAKE from ttfw_idf.IDFAssignTest import ExampleAssignTest, TestAppsAssignTest - -VALID_TARGETS = [ - 'esp32', - 'esp32s2', -] +from idf_py_actions.constants import SUPPORTED_TARGETS TEST_LABELS = { 'example_test': 'BOT_LABEL_EXAMPLE_TEST', 'test_apps': 'BOT_LABEL_CUSTOM_TEST', + 'component_ut': ['BOT_LABEL_UNIT_TEST', 'BOT_LABEL_UNIT_TEST_S2'], } BUILD_ALL_LABELS = [ + 'BOT_LABEL_BUILD', 'BOT_LABEL_BUILD_ALL_APPS', 'BOT_LABEL_REGULAR_TEST', ] @@ -40,12 +38,17 @@ def _judge_build_or_not(action, build_all): # type: (str, bool) -> (bool, bool) logging.info('Build all apps') return True, True - if os.getenv(TEST_LABELS[action]): - logging.info('Build test cases apps') - return True, False - else: - logging.info('Skip all') - return False, False + labels = TEST_LABELS[action] + if not isinstance(labels, list): + labels = [labels] + + for label in labels: + if os.getenv(label): + logging.info('Build test cases apps') + return True, False + else: + logging.info('Skip all') + return False, False def output_json(apps_dict_list, target, build_system, output_dir): @@ -59,8 +62,8 @@ def main(): parser.add_argument('test_type', choices=TEST_LABELS.keys(), help='Scan test type') - parser.add_argument('paths', - nargs='+', + parser.add_argument('-p', '--paths', nargs='+', + required=True, help='One or more app paths') parser.add_argument('-b', '--build-system', choices=BUILD_SYSTEMS.keys(), @@ -90,15 +93,17 @@ def main(): raise e if (not build_standalone_apps) and (not build_test_case_apps): - for target in VALID_TARGETS: + for target in SUPPORTED_TARGETS: output_json([], target, args.build_system, args.output_path) SystemExit(0) + paths = set([os.path.join(os.getenv('IDF_PATH'), path) if not os.path.isabs(path) else path for path in args.paths]) + test_cases = [] - for path in set(args.paths): + for path in paths: if args.test_type == 'example_test': assign = ExampleAssignTest(path, args.ci_config_file) - elif args.test_type == 'test_apps': + elif args.test_type in ['test_apps', 'component_ut']: assign = TestAppsAssignTest(path, args.ci_config_file) else: raise SystemExit(1) # which is impossible @@ -123,7 +128,7 @@ def main(): build_system_class = BUILD_SYSTEMS[build_system] if build_test_case_apps: - for target in VALID_TARGETS: + for target in SUPPORTED_TARGETS: target_dict = scan_info_dict[target] test_case_apps = target_dict['test_case_apps'] = set() for case in test_cases: @@ -134,21 +139,21 @@ def main(): test_case_apps.update(find_apps(build_system_class, app_dir, True, default_exclude, target.lower())) exclude_apps.append(app_dir) else: - for target in VALID_TARGETS: + for target in SUPPORTED_TARGETS: scan_info_dict[target]['test_case_apps'] = set() if build_standalone_apps: - for target in VALID_TARGETS: + for target in SUPPORTED_TARGETS: target_dict = scan_info_dict[target] standalone_apps = target_dict['standalone_apps'] = set() - for path in args.paths: + for path in paths: standalone_apps.update(find_apps(build_system_class, path, True, exclude_apps, target.lower())) else: - for target in VALID_TARGETS: + for target in SUPPORTED_TARGETS: scan_info_dict[target]['standalone_apps'] = set() test_case_apps_preserve_default = True if build_system == 'cmake' else False - for target in VALID_TARGETS: + for target in SUPPORTED_TARGETS: apps = [] for app_dir in scan_info_dict[target]['test_case_apps']: apps.append({ diff --git a/tools/ci/python_packages/ttfw_idf/IDFAssignTest.py b/tools/ci/python_packages/ttfw_idf/IDFAssignTest.py index 28e568ebb4..0fd1322122 100644 --- a/tools/ci/python_packages/ttfw_idf/IDFAssignTest.py +++ b/tools/ci/python_packages/ttfw_idf/IDFAssignTest.py @@ -17,6 +17,8 @@ except ImportError: import gitlab_api from tiny_test_fw.Utility import CIAssignTest +from idf_py_actions.constants import SUPPORTED_TARGETS + IDF_PATH_FROM_ENV = os.getenv("IDF_PATH") @@ -35,6 +37,9 @@ class IDFCaseGroup(CIAssignTest.Group): class IDFAssignTest(CIAssignTest.AssignTest): + def __init__(self, test_case_path, ci_config_file, case_group=IDFCaseGroup): + super(IDFAssignTest, self).__init__(test_case_path, ci_config_file, case_group) + def format_build_log_path(self, parallel_num): return "{}/list_job_{}.json".format(self.case_group.LOCAL_BUILD_DIR, parallel_num) @@ -67,12 +72,6 @@ class IDFAssignTest(CIAssignTest.AssignTest): json.dump(artifact_index_list, f) -SUPPORTED_TARGETS = [ - 'esp32', - 'esp32s2', -] - - class ExampleGroup(IDFCaseGroup): SORT_KEYS = CI_JOB_MATCH_KEYS = ["env_tag", "target"] @@ -210,22 +209,29 @@ class UnitTestGroup(IDFCaseGroup): class ExampleAssignTest(IDFAssignTest): CI_TEST_JOB_PATTERN = re.compile(r'^example_test_.+') - def __init__(self, est_case_path, ci_config_file): - super(ExampleAssignTest, self).__init__(est_case_path, ci_config_file, case_group=ExampleGroup) + def __init__(self, test_case_path, ci_config_file): + super(ExampleAssignTest, self).__init__(test_case_path, ci_config_file, case_group=ExampleGroup) class TestAppsAssignTest(IDFAssignTest): CI_TEST_JOB_PATTERN = re.compile(r'^test_app_test_.+') - def __init__(self, est_case_path, ci_config_file): - super(TestAppsAssignTest, self).__init__(est_case_path, ci_config_file, case_group=TestAppsGroup) + def __init__(self, test_case_path, ci_config_file): + super(TestAppsAssignTest, self).__init__(test_case_path, ci_config_file, case_group=TestAppsGroup) + + +class ComponentUTAssignTest(IDFAssignTest): + CI_TEST_JOB_PATTERN = re.compile(r'^component_ut_test_.+') + + def __init__(self, test_case_path, ci_config_file): + super(ComponentUTAssignTest, self).__init__(test_case_path, ci_config_file, case_group=ComponentUTGroup) class UnitTestAssignTest(IDFAssignTest): CI_TEST_JOB_PATTERN = re.compile(r'^UT_.+') - def __init__(self, est_case_path, ci_config_file): - super(UnitTestAssignTest, self).__init__(est_case_path, ci_config_file, case_group=UnitTestGroup) + def __init__(self, test_case_path, ci_config_file): + super(UnitTestAssignTest, self).__init__(test_case_path, ci_config_file, case_group=UnitTestGroup) def search_cases(self, case_filter=None): """