Merge branch 'feature/size_info_artifacts_for_apps' into 'master'

CI: add size info for binaries

Closes IDF-1709

See merge request espressif/esp-idf!8962
This commit is contained in:
Ivan Grokhotkov
2020-07-21 16:00:07 +08:00
19 changed files with 387 additions and 399 deletions

View File

@@ -107,7 +107,7 @@ void ets_secure_boot_verify_boot_bootloader(void);
* @return true if is Secure boot v2 has been enabled * @return true if is Secure boot v2 has been enabled
* False if Secure boot v2 has not been enabled. * False if Secure boot v2 has not been enabled.
*/ */
bool ets_use_secure_boot_v2(); bool ets_use_secure_boot_v2(void);
#endif /* CONFIG_ESP32_REV_MIN_3 */ #endif /* CONFIG_ESP32_REV_MIN_3 */

View File

@@ -0,0 +1,22 @@
#!/usr/bin/env python
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import ttfw_idf
@ttfw_idf.idf_example_test(env_tag="Example_GENERIC", target=['esp32', 'esp32s2'], ci_target=['esp32'])
def test_examples_hello_world(env, extra_data):
app_name = 'hello_world'
dut = env.get_dut(app_name, "examples/get-started/hello_world")
dut.start_app()
res = dut.expect(ttfw_idf.MINIMUM_FREE_HEAP_SIZE_RE)
if not res:
raise ValueError('Maximum heap size info not found')
ttfw_idf.print_heap_size(app_name, dut.app.config_name, dut.TARGET, res[0])
if __name__ == '__main__':
test_examples_hello_world()

View File

@@ -31,7 +31,7 @@ void app_main(void)
printf("%dMB %s flash\n", spi_flash_get_chip_size() / (1024 * 1024), printf("%dMB %s flash\n", spi_flash_get_chip_size() / (1024 * 1024),
(chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded" : "external"); (chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded" : "external");
printf("Free heap: %d\n", esp_get_free_heap_size()); printf("Minimum free heap size: %d bytes\n", esp_get_minimum_free_heap_size());
for (int i = 10; i >= 0; i--) { for (int i = 10; i >= 0; i--) {
printf("Restarting in %d seconds...\n", i); printf("Restarting in %d seconds...\n", i);

View File

@@ -0,0 +1,22 @@
#!/usr/bin/env python
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import ttfw_idf
@ttfw_idf.idf_example_test(env_tag="Example_TWAI1", target=['esp32', 'esp32s2'], ci_target=['esp32'])
def test_examples_gpio(env, extra_data):
app_name = "gpio"
dut = env.get_dut(app_name, "examples/peripherals/gpio")
dut.start_app()
res = dut.expect(ttfw_idf.MINIMUM_FREE_HEAP_SIZE_RE)
if not res:
raise ValueError('Maximum heap size info not found')
ttfw_idf.print_heap_size(app_name, dut.app.config_name, dut.TARGET, res[0])
if __name__ == '__main__':
test_examples_gpio()

View File

@@ -103,6 +103,8 @@ void app_main(void)
//hook isr handler for specific gpio pin again //hook isr handler for specific gpio pin again
gpio_isr_handler_add(GPIO_INPUT_IO_0, gpio_isr_handler, (void*) GPIO_INPUT_IO_0); gpio_isr_handler_add(GPIO_INPUT_IO_0, gpio_isr_handler, (void*) GPIO_INPUT_IO_0);
printf("Minimum free heap size: %d bytes\n", esp_get_minimum_free_heap_size());
int cnt = 0; int cnt = 0;
while(1) { while(1) {
printf("cnt: %d\n", cnt++); printf("cnt: %d\n", cnt++);

View File

@@ -65,6 +65,11 @@ def main():
type=argparse.FileType("w"), type=argparse.FileType("w"),
help="If specified, the list of builds (with all the placeholders expanded) will be written to this file.", help="If specified, the list of builds (with all the placeholders expanded) will be written to this file.",
) )
parser.add_argument(
"--size-info",
type=argparse.FileType("a"),
help="If specified, the test case name and size info json will be written to this file"
)
parser.add_argument( parser.add_argument(
"build_list", "build_list",
type=argparse.FileType("r"), type=argparse.FileType("r"),
@@ -119,6 +124,8 @@ def main():
else: else:
raise SystemExit(1) raise SystemExit(1)
else: else:
if args.size_info:
build_info.write_size_info(args.size_info)
if not build_info.preserve: if not build_info.preserve:
logging.info("Removing build directory {}".format(build_info.build_dir)) logging.info("Removing build directory {}".format(build_info.build_dir))
# we only remove binaries here, log files are still needed by check_build_warnings.py # we only remove binaries here, log files are still needed by check_build_warnings.py

View File

@@ -1,105 +0,0 @@
#!/usr/bin/env bash
#
# Build all examples from the examples directory, in BUILD_PATH to
# ensure they can run when copied to a new directory.
#
# Runs as part of CI process.
#
# -----------------------------------------------------------------------------
# Safety settings (see https://gist.github.com/ilg-ul/383869cbb01f61a51c4d).
if [[ ! -z ${DEBUG_SHELL} ]]
then
set -x # Activate the expand mode if DEBUG is anything but empty.
fi
set -o errexit # Exit if command failed.
set -o pipefail # Exit if pipe failed.
export PATH="$IDF_PATH/tools/ci:$IDF_PATH/tools:$PATH"
# -----------------------------------------------------------------------------
die() {
echo "${1:-"Unknown Error"}" 1>&2
exit 1
}
[ -z ${IDF_PATH} ] && die "IDF_PATH is not set"
[ -z ${LOG_PATH} ] && die "LOG_PATH is not set"
[ -z ${BUILD_PATH} ] && die "BUILD_PATH is not set"
[ -z ${IDF_TARGET} ] && die "IDF_TARGET is not set"
[ -z ${EXAMPLE_TEST_BUILD_SYSTEM} ] && die "EXAMPLE_TEST_BUILD_SYSTEM is not set"
[ -z ${SCAN_EXAMPLE_TEST_JSON} ] && die "SCAN_EXAMPLE_TEST_JSON is not set"
[ -d ${LOG_PATH} ] || mkdir -p ${LOG_PATH}
[ -d ${BUILD_PATH} ] || mkdir -p ${BUILD_PATH}
if [ -z ${CI_NODE_TOTAL} ]; then
CI_NODE_TOTAL=1
echo "Assuming CI_NODE_TOTAL=${CI_NODE_TOTAL}"
fi
if [ -z ${CI_NODE_INDEX} ]; then
# Gitlab uses a 1-based index
CI_NODE_INDEX=1
echo "Assuming CI_NODE_INDEX=${CI_NODE_INDEX}"
fi
export EXTRA_CFLAGS="${PEDANTIC_CFLAGS:-}"
export EXTRA_CXXFLAGS="${PEDANTIC_CXXFLAGS:-}"
set -o nounset # Exit if variable not set.
export REALPATH=realpath
if [ "$(uname -s)" = "Darwin" ]; then
export REALPATH=grealpath
fi
# Convert LOG_PATH and BUILD_PATH to relative, to make the json file less verbose.
LOG_PATH=$(${REALPATH} --relative-to ${IDF_PATH} ${LOG_PATH})
BUILD_PATH=$(${REALPATH} --relative-to ${IDF_PATH} ${BUILD_PATH})
ALL_BUILD_LIST_JSON="${BUILD_PATH}/list.json"
JOB_BUILD_LIST_JSON="${BUILD_PATH}/list_job_${CI_NODE_INDEX}.json"
echo "build_examples running for target $IDF_TARGET"
cd ${IDF_PATH}
# This part of the script produces the same result for all the example build jobs. It may be moved to a separate stage
# (pre-build) later, then the build jobs will receive ${BUILD_LIST_JSON} file as an artifact.
# If changing the work-dir or build-dir format, remember to update the "artifacts" in gitlab-ci configs, and IDFApp.py.
${IDF_PATH}/tools/find_apps.py \
-vv \
--format json \
--work-dir "${BUILD_PATH}/@f/@w/@t" \
--build-dir build \
--build-log "${LOG_PATH}/@f_@w.txt" \
--output ${ALL_BUILD_LIST_JSON} \
--config 'sdkconfig.ci=default' \
--config 'sdkconfig.ci.*=' \
--config '=default' \
--app-list ${SCAN_EXAMPLE_TEST_JSON}
# --config rules above explained:
# 1. If sdkconfig.ci exists, use it build the example with configuration name "default"
# 2. If sdkconfig.ci.* exists, use it to build the "*" configuration
# 3. If none of the above exist, build the default configuration under the name "default"
# The part below is where the actual builds happen
${IDF_PATH}/tools/build_apps.py \
-vv \
--format json \
--keep-going \
--parallel-count ${CI_NODE_TOTAL} \
--parallel-index ${CI_NODE_INDEX} \
--output-build-list ${JOB_BUILD_LIST_JSON} \
${ALL_BUILD_LIST_JSON}\
# Check for build warnings
${IDF_PATH}/tools/ci/check_build_warnings.py -vv ${JOB_BUILD_LIST_JSON}

View File

@@ -1,100 +0,0 @@
#!/usr/bin/env bash
#
# Build test apps
#
# Runs as part of CI process.
#
# -----------------------------------------------------------------------------
# Safety settings (see https://gist.github.com/ilg-ul/383869cbb01f61a51c4d).
if [[ ! -z ${DEBUG_SHELL} ]]
then
set -x # Activate the expand mode if DEBUG is anything but empty.
fi
set -o errexit # Exit if command failed.
set -o pipefail # Exit if pipe failed.
export PATH="$IDF_PATH/tools/ci:$IDF_PATH/tools:$PATH"
# -----------------------------------------------------------------------------
die() {
echo "${1:-"Unknown Error"}" 1>&2
exit 1
}
[ -z ${IDF_PATH} ] && die "IDF_PATH is not set"
[ -z ${LOG_PATH} ] && die "LOG_PATH is not set"
[ -z ${BUILD_PATH} ] && die "BUILD_PATH is not set"
[ -z ${IDF_TARGET} ] && die "IDF_TARGET is not set"
[ -z ${SCAN_CUSTOM_TEST_JSON} ] && die "SCAN_CUSTOM_TEST_JSON is not set"
[ -d ${LOG_PATH} ] || mkdir -p ${LOG_PATH}
[ -d ${BUILD_PATH} ] || mkdir -p ${BUILD_PATH}
if [ -z ${CI_NODE_TOTAL} ]; then
CI_NODE_TOTAL=1
echo "Assuming CI_NODE_TOTAL=${CI_NODE_TOTAL}"
fi
if [ -z ${CI_NODE_INDEX} ]; then
# Gitlab uses a 1-based index
CI_NODE_INDEX=1
echo "Assuming CI_NODE_INDEX=${CI_NODE_INDEX}"
fi
set -o nounset # Exit if variable not set.
# Convert LOG_PATH to relative, to make the json file less verbose.
LOG_PATH=$(realpath --relative-to ${IDF_PATH} ${LOG_PATH})
BUILD_PATH=$(realpath --relative-to ${IDF_PATH} ${BUILD_PATH})
ALL_BUILD_LIST_JSON="${BUILD_PATH}/list.json"
JOB_BUILD_LIST_JSON="${BUILD_PATH}/list_job_${CI_NODE_INDEX}.json"
echo "build_test_apps running for target $IDF_TARGET"
cd ${IDF_PATH}
# This part of the script produces the same result for all the test app build jobs. It may be moved to a separate stage
# (pre-build) later, then the build jobs will receive ${BUILD_LIST_JSON} file as an artifact.
# If changing the work-dir or build-dir, remember to update the "artifacts" in gitlab-ci configs, and IDFApp.py.
${IDF_PATH}/tools/find_apps.py \
-vv \
--format json \
--work-dir "${BUILD_PATH}/@f/@w/@t" \
--build-dir build \
--build-log "${LOG_PATH}/@f_@w.txt" \
--output ${ALL_BUILD_LIST_JSON} \
--config 'sdkconfig.ci=default' \
--config 'sdkconfig.ci.*=' \
--config '=default' \
--app-list ${SCAN_CUSTOM_TEST_JSON}
# --config rules above explained:
# 1. If sdkconfig.ci exists, use it build the example with configuration name "default"
# 2. If sdkconfig.ci.* exists, use it to build the "*" configuration
# 3. If none of the above exist, build the default configuration under the name "default"
# --work-dir and --build-log above uses "placeholders" @x:
# - @f: full path to the test with slashes replaced with underscores
# - @w: wildcard used as config name
# - @t: target name
# so the workdir .../@f/@w/@t would expand to e.g. tools_test_apps_system_startup/default/esp32
# The part below is where the actual builds happen
${IDF_PATH}/tools/build_apps.py \
-vv \
--format json \
--keep-going \
--parallel-count ${CI_NODE_TOTAL} \
--parallel-index ${CI_NODE_INDEX} \
--output-build-list ${JOB_BUILD_LIST_JSON} \
${ALL_BUILD_LIST_JSON}\
# Check for build warnings
${IDF_PATH}/tools/ci/check_build_warnings.py -vv ${JOB_BUILD_LIST_JSON}

View File

@@ -1,108 +0,0 @@
#!/bin/bash
#
# Build unit test app
#
# Runs as part of CI process.
#
# -----------------------------------------------------------------------------
# Safety settings (see https://gist.github.com/ilg-ul/383869cbb01f61a51c4d).
if [[ ! -z ${DEBUG_SHELL} ]]
then
set -x # Activate the expand mode if DEBUG is anything but empty.
fi
set -o errexit # Exit if command failed.
set -o pipefail # Exit if pipe failed.
export PATH="$IDF_PATH/tools/ci:$IDF_PATH/tools:$PATH"
# -----------------------------------------------------------------------------
die() {
echo "${1:-"Unknown Error"}" 1>&2
exit 1
}
[ -z ${IDF_PATH} ] && die "IDF_PATH is not set"
[ -z ${LOG_PATH} ] && die "LOG_PATH is not set"
[ -z ${IDF_TARGET} ] && die "IDF_TARGET is not set"
[ -d ${LOG_PATH} ] || mkdir -p ${LOG_PATH}
# Relative to IDF_PATH
# If changing the BUILD_PATH, remember to update the "artifacts" in gitlab-ci configs, and IDFApp.py.
BUILD_PATH=${IDF_PATH}/tools/unit-test-app/builds
OUTPUT_PATH=${IDF_PATH}/tools/unit-test-app/output
mkdir -p ${BUILD_PATH}/${IDF_TARGET}
mkdir -p ${OUTPUT_PATH}/${IDF_TARGET}
if [ -z ${CI_NODE_TOTAL} ]; then
CI_NODE_TOTAL=1
echo "Assuming CI_NODE_TOTAL=${CI_NODE_TOTAL}"
fi
if [ -z ${CI_NODE_INDEX} ]; then
# Gitlab uses a 1-based index
CI_NODE_INDEX=1
echo "Assuming CI_NODE_INDEX=${CI_NODE_INDEX}"
fi
set -o nounset # Exit if variable not set.
# Convert LOG_PATH to relative, to make the json file less verbose.
LOG_PATH=$(realpath --relative-to ${IDF_PATH} ${LOG_PATH})
ALL_BUILD_LIST_JSON="${BUILD_PATH}/${IDF_TARGET}/list.json"
JOB_BUILD_LIST_JSON="${BUILD_PATH}/${IDF_TARGET}/list_job_${CI_NODE_INDEX}.json"
echo "build_unit_test running for target $IDF_TARGET"
cd ${IDF_PATH}
# This part of the script produces the same result for all the unit test app build jobs. It may be moved to a separate stage
# (pre-build) later, then the build jobs will receive ${BUILD_LIST_JSON} file as an artifact.
${IDF_PATH}/tools/find_apps.py \
-p tools/unit-test-app \
-vv \
--format json \
--build-system cmake \
--target ${IDF_TARGET} \
--recursive \
--build-dir "builds/@t/@w" \
--build-log "${LOG_PATH}/@w.txt" \
--output ${ALL_BUILD_LIST_JSON} \
--config 'configs/*='
# The part below is where the actual builds happen
${IDF_PATH}/tools/build_apps.py \
-vv \
--format json \
--keep-going \
--parallel-count ${CI_NODE_TOTAL} \
--parallel-index ${CI_NODE_INDEX} \
--output-build-list ${JOB_BUILD_LIST_JSON} \
${ALL_BUILD_LIST_JSON}\
# Copy build artifacts to output directory
build_names=$(cd ${BUILD_PATH}/${IDF_TARGET}; find . -maxdepth 1 \! -name . -prune -type d | cut -c 3-)
for build_name in $build_names; do
src=${BUILD_PATH}/${IDF_TARGET}/${build_name}
dst=${OUTPUT_PATH}/${IDF_TARGET}/${build_name}
echo "Copying artifacts from ${src} to ${dst}"
rm -rf ${dst}
mkdir -p ${dst}
cp ${src}/{*.bin,*.elf,*.map,sdkconfig,flasher_args.json} ${dst}/
mkdir -p ${dst}/bootloader
cp ${src}/bootloader/*.bin ${dst}/bootloader/
mkdir -p ${dst}/partition_table
cp ${src}/partition_table/*.bin ${dst}/partition_table/
done
# Check for build warnings
${IDF_PATH}/tools/ci/check_build_warnings.py -vv ${JOB_BUILD_LIST_JSON}

View File

@@ -6,6 +6,7 @@
variables: variables:
BATCH_BUILD: "1" BATCH_BUILD: "1"
V: "0" V: "0"
SIZE_INFO_LOCATION: "$CI_PROJECT_DIR/size_info.txt"
.build_ssc_template: .build_ssc_template:
extends: .build_template extends: .build_template
@@ -45,8 +46,10 @@ build_ssc_esp32s2:
paths: paths:
- tools/unit-test-app/output/${IDF_TARGET} - tools/unit-test-app/output/${IDF_TARGET}
- tools/unit-test-app/builds/${IDF_TARGET}/*.json - tools/unit-test-app/builds/${IDF_TARGET}/*.json
- tools/unit-test-app/builds/${IDF_TARGET}/*/size.json
- components/idf_test/unit_test/*.yml - components/idf_test/unit_test/*.yml
- ${LOG_PATH} - $LOG_PATH
- $SIZE_INFO_LOCATION
when: always when: always
expire_in: 4 days expire_in: 4 days
only: only:
@@ -58,16 +61,17 @@ build_ssc_esp32s2:
- $BOT_LABEL_REGULAR_TEST - $BOT_LABEL_REGULAR_TEST
variables: variables:
LOG_PATH: "$CI_PROJECT_DIR/log_ut_cmake" LOG_PATH: "$CI_PROJECT_DIR/log_ut_cmake"
BUILD_PATH: ${CI_PROJECT_DIR}/tools/unit-test-app/builds
OUTPUT_PATH: ${CI_PROJECT_DIR}/tools/unit-test-app/output
BUILD_SYSTEM: "cmake"
TEST_TYPE: "unit_test"
script: script:
# RISC-V toolchain is optional but ULP may need it, so install: # RISC-V toolchain is optional but ULP may need it, so install:
- $IDF_PATH/tools/idf_tools.py install riscv-none-embed-gcc - $IDF_PATH/tools/idf_tools.py install riscv-none-embed-gcc
- . $IDF_PATH/export.sh - . $IDF_PATH/export.sh
- export EXTRA_CFLAGS=${PEDANTIC_CFLAGS} - ${IDF_PATH}/tools/ci/find_apps_build_apps.sh
- export EXTRA_CXXFLAGS=${PEDANTIC_CXXFLAGS}
- mkdir -p ${LOG_PATH}
- ${CI_PROJECT_DIR}/tools/ci/build_unit_test.sh
- cd $CI_PROJECT_DIR/tools/unit-test-app - cd $CI_PROJECT_DIR/tools/unit-test-app
- python tools/UnitTestParser.py - python tools/UnitTestParser.py ${BUILD_PATH}
build_esp_idf_tests_cmake_esp32: build_esp_idf_tests_cmake_esp32:
extends: .build_esp_idf_tests_cmake extends: .build_esp_idf_tests_cmake
@@ -85,8 +89,6 @@ build_esp_idf_tests_cmake_esp32s2:
artifacts: artifacts:
when: always when: always
expire_in: 4 days expire_in: 4 days
variables:
SCAN_EXAMPLE_TEST_JSON: ${CI_PROJECT_DIR}/examples/test_configs/scan_${IDF_TARGET}_${EXAMPLE_TEST_BUILD_SYSTEM}.json
only: only:
# Here both 'variables' and 'refs' conditions are given. They are combined with "AND" logic. # Here both 'variables' and 'refs' conditions are given. They are combined with "AND" logic.
variables: variables:
@@ -95,15 +97,16 @@ build_esp_idf_tests_cmake_esp32s2:
- $BOT_LABEL_EXAMPLE_TEST - $BOT_LABEL_EXAMPLE_TEST
- $BOT_LABEL_REGULAR_TEST - $BOT_LABEL_REGULAR_TEST
- $BOT_LABEL_WEEKEND_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"
script: script:
# RISC-V toolchain is optional but ULP may need it, so install: # RISC-V toolchain is optional but ULP may need it, so install:
- $IDF_PATH/tools/idf_tools.py install riscv-none-embed-gcc - $IDF_PATH/tools/idf_tools.py install riscv-none-embed-gcc
- . $IDF_PATH/export.sh - . $IDF_PATH/export.sh
# it's not possible to build 100% out-of-tree and have the "artifacts" # it's not possible to build 100% out-of-tree and have the "artifacts"
# mechanism work, but this is the next best thing # mechanism work, but this is the next best thing
- mkdir ${BUILD_PATH} - ${IDF_PATH}/tools/ci/find_apps_build_apps.sh
- mkdir -p ${LOG_PATH}
- ${IDF_PATH}/tools/ci/build_examples.sh
build_examples_make: build_examples_make:
extends: .build_examples_template extends: .build_examples_template
@@ -113,10 +116,12 @@ build_examples_make:
artifacts: artifacts:
paths: paths:
- $LOG_PATH - $LOG_PATH
- build_examples/*/*/*/build/size.json
- $SIZE_INFO_LOCATION
variables: variables:
LOG_PATH: "${CI_PROJECT_DIR}/log_examples_make" LOG_PATH: "${CI_PROJECT_DIR}/log_examples_make"
BUILD_PATH: "${CI_PROJECT_DIR}/build_examples_make" BUILD_PATH: "${CI_PROJECT_DIR}/build_examples_make"
EXAMPLE_TEST_BUILD_SYSTEM: "make" BUILD_SYSTEM: "make"
IDF_TARGET: "esp32" # currently we only support esp32 IDF_TARGET: "esp32" # currently we only support esp32
only: only:
refs: refs:
@@ -138,6 +143,7 @@ build_examples_make:
- build_examples/list.json - build_examples/list.json
- build_examples/list_job_*.json - build_examples/list_job_*.json
- build_examples/*/*/*/sdkconfig - build_examples/*/*/*/sdkconfig
- build_examples/*/*/*/build/size.json
- build_examples/*/*/*/build/*.bin - build_examples/*/*/*/build/*.bin
- build_examples/*/*/*/build/*.elf - build_examples/*/*/*/build/*.elf
- build_examples/*/*/*/build/*.map - build_examples/*/*/*/build/*.map
@@ -145,10 +151,11 @@ build_examples_make:
- build_examples/*/*/*/build/bootloader/*.bin - build_examples/*/*/*/build/bootloader/*.bin
- build_examples/*/*/*/build/partition_table/*.bin - build_examples/*/*/*/build/partition_table/*.bin
- $LOG_PATH - $LOG_PATH
- $SIZE_INFO_LOCATION
variables: variables:
LOG_PATH: "${CI_PROJECT_DIR}/log_examples" LOG_PATH: "${CI_PROJECT_DIR}/log_examples"
BUILD_PATH: "${CI_PROJECT_DIR}/build_examples" BUILD_PATH: "${CI_PROJECT_DIR}/build_examples"
EXAMPLE_TEST_BUILD_SYSTEM: "cmake" BUILD_SYSTEM: "cmake"
build_examples_cmake_esp32: build_examples_cmake_esp32:
extends: .build_examples_cmake extends: .build_examples_cmake
@@ -170,20 +177,23 @@ build_examples_cmake_esp32s2:
paths: paths:
- build_test_apps/list.json - build_test_apps/list.json
- build_test_apps/list_job_*.json - build_test_apps/list_job_*.json
- build_test_apps/*/*/*/build/*.bin
- build_test_apps/*/*/*/sdkconfig - build_test_apps/*/*/*/sdkconfig
- build_test_apps/*/*/*/build/size.json
- build_test_apps/*/*/*/build/*.bin
- build_test_apps/*/*/*/build/*.elf - build_test_apps/*/*/*/build/*.elf
- build_test_apps/*/*/*/build/*.map - build_test_apps/*/*/*/build/*.map
- build_test_apps/*/*/*/build/flasher_args.json - build_test_apps/*/*/*/build/flasher_args.json
- build_test_apps/*/*/*/build/bootloader/*.bin - build_test_apps/*/*/*/build/bootloader/*.bin
- build_test_apps/*/*/*/build/partition_table/*.bin - build_test_apps/*/*/*/build/partition_table/*.bin
- $LOG_PATH - $LOG_PATH
- $SIZE_INFO_LOCATION
expire_in: 3 days expire_in: 3 days
variables: variables:
LOG_PATH: "${CI_PROJECT_DIR}/log_test_apps" LOG_PATH: "${CI_PROJECT_DIR}/log_test_apps"
BUILD_PATH: "${CI_PROJECT_DIR}/build_test_apps" BUILD_PATH: "${CI_PROJECT_DIR}/build_test_apps"
CUSTOM_TEST_BUILD_SYSTEM: "cmake" BUILD_SYSTEM: "cmake"
SCAN_CUSTOM_TEST_JSON: ${CI_PROJECT_DIR}/tools/test_apps/test_configs/scan_${IDF_TARGET}_${CUSTOM_TEST_BUILD_SYSTEM}.json SCAN_TEST_JSON: ${CI_PROJECT_DIR}/tools/test_apps/test_configs/scan_${IDF_TARGET}_${BUILD_SYSTEM}.json
TEST_TYPE: custom_test
only: only:
variables: variables:
- $BOT_TRIGGER_WITH_LABEL == null - $BOT_TRIGGER_WITH_LABEL == null
@@ -192,9 +202,7 @@ build_examples_cmake_esp32s2:
- $BOT_LABEL_CUSTOM_TEST - $BOT_LABEL_CUSTOM_TEST
- $BOT_LABEL_WEEKEND_TEST - $BOT_LABEL_WEEKEND_TEST
script: script:
- mkdir -p ${BUILD_PATH} - ${IDF_PATH}/tools/ci/find_apps_build_apps.sh
- mkdir -p ${LOG_PATH}
- ${IDF_PATH}/tools/ci/build_test_apps.sh
build_test_apps_esp32: build_test_apps_esp32:
extends: .build_test_apps extends: .build_test_apps

View File

@@ -224,7 +224,7 @@ example_test_001B:
example_test_001C: example_test_001C:
extends: .example_test_template extends: .example_test_template
parallel: 2 parallel: 3
tags: tags:
- ESP32 - ESP32
- Example_GENERIC - Example_GENERIC

View File

@@ -33,10 +33,6 @@ tools/build_apps.py
tools/check_kconfigs.py tools/check_kconfigs.py
tools/check_python_dependencies.py tools/check_python_dependencies.py
tools/ci/apply_bot_filter.py tools/ci/apply_bot_filter.py
tools/ci/build_examples.sh
tools/ci/build_examples_cmake.sh
tools/ci/build_test_apps.sh
tools/ci/build_unit_test.sh
tools/ci/check-executable.sh tools/ci/check-executable.sh
tools/ci/check-line-endings.sh tools/ci/check-line-endings.sh
tools/ci/check_build_warnings.py tools/ci/check_build_warnings.py
@@ -50,6 +46,7 @@ tools/ci/check_ut_cmake_make.sh
tools/ci/checkout_project_ref.py tools/ci/checkout_project_ref.py
tools/ci/deploy_docs.py tools/ci/deploy_docs.py
tools/ci/envsubst.py tools/ci/envsubst.py
tools/ci/find_apps_build_apps.sh
tools/ci/fix_empty_prototypes.sh tools/ci/fix_empty_prototypes.sh
tools/ci/get-full-sources.sh tools/ci/get-full-sources.sh
tools/ci/get_supported_examples.sh tools/ci/get_supported_examples.sh

172
tools/ci/find_apps_build_apps.sh Executable file
View File

@@ -0,0 +1,172 @@
#!/usr/bin/env bash
#
# Find apps and build apps for example_test, custom_test, and unit_test
#
# Runs as part of CI process.
#
# -----------------------------------------------------------------------------
# Safety settings (see https://gist.github.com/ilg-ul/383869cbb01f61a51c4d).
if [[ -n ${DEBUG_SHELL} ]]; then
set -x # Activate the expand mode if DEBUG is anything but empty.
fi
if [ -z ${CI_NODE_TOTAL} ]; then
CI_NODE_TOTAL=1
echo "Assuming CI_NODE_TOTAL=${CI_NODE_TOTAL}"
fi
if [ -z ${CI_NODE_INDEX} ]; then
# Gitlab uses a 1-based index
CI_NODE_INDEX=1
echo "Assuming CI_NODE_INDEX=${CI_NODE_INDEX}"
fi
set -o errexit # Exit if command failed.
set -o pipefail # Exit if pipe failed.
set -o nounset # Exit if variable not set.
export PATH="$IDF_PATH/tools/ci:$IDF_PATH/tools:$PATH"
# -----------------------------------------------------------------------------
die() {
echo "${1:-"Unknown Error"}" 1>&2
exit 1
}
[ -d ${BUILD_PATH} ] || mkdir -p ${BUILD_PATH}
[ -d ${LOG_PATH} ] || mkdir -p ${LOG_PATH}
[ -f ${SIZE_INFO_LOCATION} ] && rm ${SIZE_INFO_LOCATION}
export REALPATH=realpath
if [ "$(uname -s)" = "Darwin" ]; then
export REALPATH=grealpath
fi
# Convert LOG_PATH and BUILD_PATH to relative, to make the json file less verbose.
BUILD_PATH=$(${REALPATH} --relative-to ${IDF_PATH} ${BUILD_PATH})
LOG_PATH=$(${REALPATH} --relative-to ${IDF_PATH} ${LOG_PATH})
ALL_BUILD_LIST_JSON="${BUILD_PATH}/list.json"
JOB_BUILD_LIST_JSON="${BUILD_PATH}/list_job_${CI_NODE_INDEX}.json"
# -----------------------------------------------------------------------------
# common variables, will specify special cases later
WORK_DIR="--work-dir ${BUILD_PATH}/@f/@w/@t"
BUILD_DIR="build"
BUILD_LOG="${LOG_PATH}/@f_@w.txt"
CONFIG="--config sdkconfig.ci=default
--config sdkconfig.ci.*=
--config =default"
export EXTRA_CFLAGS="${PEDANTIC_CFLAGS}"
export EXTRA_CXXFLAGS="${PEDANTIC_CXXFLAGS}"
# --config rules above explained:
# 1. If sdkconfig.ci exists, use it build the example with configuration name "default"
# 2. If sdkconfig.ci.* exists, use it to build the "*" configuration
# 3. If none of the above exist, build the default configuration under the name "default"
# --work-dir and --build-log above uses "placeholders" @x:
# - @f: full path to the test with slashes replaced with underscores
# - @w: wildcard used as config name
# - @t: target name
# so the workdir .../@f/@w/@t would expand to e.g. tools_test_apps_system_startup/default/esp32
# -----------------------------------------------------------------------------
# Example tests specific settings
if [ "${TEST_TYPE}" = "example_test" ]; then
export EXTRA_CFLAGS="${PEDANTIC_CFLAGS:-}"
export EXTRA_CXXFLAGS="${PEDANTIC_CXXFLAGS:-}"
EXTRA_ARGS="--app-list ${SCAN_TEST_JSON}"
# -----------------------------------------------------------------------------
# Custom tests specific settings
elif [ "${TEST_TYPE}" = "custom_test" ]; then
EXTRA_ARGS="--app-list ${SCAN_TEST_JSON}"
# -----------------------------------------------------------------------------
# Unit tests specific settings
elif [ "${TEST_TYPE}" = "unit_test" ]; then
ALL_BUILD_LIST_JSON="${BUILD_PATH}/${IDF_TARGET}/list.json"
JOB_BUILD_LIST_JSON="${BUILD_PATH}/${IDF_TARGET}/list_job_${CI_NODE_INDEX}.json"
mkdir -p ${BUILD_PATH}/${IDF_TARGET}
mkdir -p ${OUTPUT_PATH}/${IDF_TARGET}
WORK_DIR=""
BUILD_DIR="builds/@t/@w"
BUILD_LOG="${LOG_PATH}/@w.txt"
APP_FOLDER="tools/unit-test-app"
EXTRA_ARGS="
-p ${APP_FOLDER}
--build-system ${BUILD_SYSTEM}
--target ${IDF_TARGET}
--recursive
"
CONFIG="--config configs/*="
# -----------------------------------------------------------------------------
else
die "TEST_TYPE should only be one of {example_test, custom_test, unit_test}"
fi
echo "$TEST_TYPE running for target $IDF_TARGET"
cd ${IDF_PATH}
# This part of the script produces the same result for all the build jobs.
#
# It may be moved to a separate stage (pre-build) later, then the build jobs
# will receive ${BUILD_LIST_JSON} file as an artifact.
#
# If changing the work-dir or build-dir, remember to update the "artifacts" in
# gitlab-ci configs, and IDFApp.py.
${IDF_PATH}/tools/find_apps.py \
-vv \
--format json \
${WORK_DIR} \
--build-dir ${BUILD_DIR} \
--build-log ${BUILD_LOG} \
--output ${ALL_BUILD_LIST_JSON} \
${EXTRA_ARGS} \
${CONFIG}
# The part below is where the actual builds happen
${IDF_PATH}/tools/build_apps.py \
-vv \
--format json \
--keep-going \
--parallel-count ${CI_NODE_TOTAL} \
--parallel-index ${CI_NODE_INDEX} \
--output-build-list ${JOB_BUILD_LIST_JSON} \
--size-info ${SIZE_INFO_LOCATION} \
${ALL_BUILD_LIST_JSON}
# Check for build warnings
${IDF_PATH}/tools/ci/check_build_warnings.py -vv ${JOB_BUILD_LIST_JSON}
if [ "${TEST_TYPE}" = "unit_test" ]; then
# Copy build artifacts to output directory
build_names=$(
cd ${BUILD_PATH}/${IDF_TARGET}
find . -maxdepth 1 \! -name . -prune -type d | cut -c 3-
)
for build_name in $build_names; do
src=${BUILD_PATH}/${IDF_TARGET}/${build_name}
dst=${OUTPUT_PATH}/${IDF_TARGET}/${build_name}
echo "Copying artifacts from ${src} to ${dst}"
rm -rf ${dst}
mkdir -p ${dst}
cp ${src}/{*.bin,*.elf,*.map,sdkconfig,flasher_args.json} ${dst}/
mkdir -p ${dst}/bootloader
cp ${src}/bootloader/*.bin ${dst}/bootloader/
mkdir -p ${dst}/partition_table
cp ${src}/partition_table/*.bin ${dst}/partition_table/
done
fi

View File

@@ -63,6 +63,7 @@ def local_test_check(decorator_target):
if os.getenv('CI_JOB_ID'): # Only auto-detect target when running locally if os.getenv('CI_JOB_ID'): # Only auto-detect target when running locally
return idf_target return idf_target
decorator_target = upper_list_or_str(decorator_target)
expected_json_path = os.path.join('build', 'config', 'sdkconfig.json') expected_json_path = os.path.join('build', 'config', 'sdkconfig.json')
if os.path.exists(expected_json_path): if os.path.exists(expected_json_path):
sdkconfig = json.load(open(expected_json_path)) sdkconfig = json.load(open(expected_json_path))
@@ -262,3 +263,22 @@ def check_performance(item, value, target):
_check_perf(op, value) _check_perf(op, value)
# if no exception was thrown then the performance is met and no need to continue # if no exception was thrown then the performance is met and no need to continue
break break
MINIMUM_FREE_HEAP_SIZE_RE = re.compile(r'Minimum free heap size: (\d+) bytes')
def print_heap_size(app_name, config_name, target, minimum_free_heap_size):
"""
Do not change the print output in case you really need to.
The result is parsed by ci-dashboard project
"""
print('------ heap size info ------\n'
'[app_name] {}\n'
'[config_name] {}\n'
'[target] {}\n'
'[minimum_free_heap_size] {} Bytes\n'
'------ heap size end ------'.format(app_name,
'' if not config_name else config_name,
target,
minimum_free_heap_size))

View File

@@ -1,14 +1,14 @@
import os
import sys
import subprocess
import logging import logging
import shutil import os
import re import re
import shutil
import subprocess
import sys
from .common import BuildSystem, BuildItem, BuildError from .common import BuildSystem, BuildItem, BuildError
BUILD_SYSTEM_CMAKE = "cmake" BUILD_SYSTEM_CMAKE = "cmake"
IDF_PY = "idf.py" IDF_PY = os.path.join(os.environ["IDF_PATH"], "tools", "idf.py")
# While ESP-IDF component CMakeLists files can be identified by the presence of 'idf_component_register' string, # While ESP-IDF component CMakeLists files can be identified by the presence of 'idf_component_register' string,
# there is no equivalent for the project CMakeLists files. This seems to be the best option... # there is no equivalent for the project CMakeLists files. This seems to be the best option...
@@ -30,8 +30,7 @@ class CMakeBuildSystem(BuildSystem):
build_path, work_path, extra_cmakecache_items = cls.build_prepare(build_item) build_path, work_path, extra_cmakecache_items = cls.build_prepare(build_item)
# Prepare the build arguments # Prepare the build arguments
args = [ args = [
# Assume it is the responsibility of the caller to sys.executable,
# set up the environment (run . ./export.sh)
IDF_PY, IDF_PY,
"-B", "-B",
build_path, build_path,
@@ -73,6 +72,7 @@ class CMakeBuildSystem(BuildSystem):
os.path.join(work_path, "sdkconfig"), os.path.join(work_path, "sdkconfig"),
os.path.join(build_path, "sdkconfig"), os.path.join(build_path, "sdkconfig"),
) )
build_item.size_json_fp = build_item.get_size_json_fp()
finally: finally:
if log_file: if log_file:
log_file.close() log_file.close()

View File

@@ -1,15 +1,18 @@
# coding=utf-8 # coding=utf-8
import fnmatch
import json
import logging
import os
import re import re
import shutil import shutil
import subprocess
import sys import sys
import os
from abc import abstractmethod from abc import abstractmethod
from collections import namedtuple from collections import namedtuple
import logging
import json
import typing
from io import open from io import open
import typing
DEFAULT_TARGET = "esp32" DEFAULT_TARGET = "esp32"
TARGET_PLACEHOLDER = "@t" TARGET_PLACEHOLDER = "@t"
@@ -18,6 +21,8 @@ NAME_PLACEHOLDER = "@n"
FULL_NAME_PLACEHOLDER = "@f" FULL_NAME_PLACEHOLDER = "@f"
INDEX_PLACEHOLDER = "@i" INDEX_PLACEHOLDER = "@i"
IDF_SIZE_PY = os.path.join(os.environ["IDF_PATH"], "tools", "idf_size.py")
SDKCONFIG_LINE_REGEX = re.compile(r"^([^=]+)=\"?([^\"\n]*)\"?\n*$") SDKCONFIG_LINE_REGEX = re.compile(r"^([^=]+)=\"?([^\"\n]*)\"?\n*$")
# If these keys are present in sdkconfig.defaults, they will be extracted and passed to CMake # If these keys are present in sdkconfig.defaults, they will be extracted and passed to CMake
@@ -55,6 +60,14 @@ def config_rules_from_str(rule_strings): # type: (typing.List[str]) -> typing.L
return rules return rules
def find_first_match(pattern, path):
for root, _, files in os.walk(path):
res = fnmatch.filter(files, pattern)
if res:
return os.path.join(root, res[0])
return None
class BuildItem(object): class BuildItem(object):
""" """
Instance of this class represents one build of an application. Instance of this class represents one build of an application.
@@ -88,6 +101,7 @@ class BuildItem(object):
self.preserve = preserve_artifacts self.preserve = preserve_artifacts
self._app_name = os.path.basename(os.path.normpath(app_path)) self._app_name = os.path.basename(os.path.normpath(app_path))
self.size_json_fp = None
# Some miscellaneous build properties which are set later, at the build stage # Some miscellaneous build properties which are set later, at the build stage
self.index = None self.index = None
@@ -95,6 +109,14 @@ class BuildItem(object):
self.dry_run = False self.dry_run = False
self.keep_going = False self.keep_going = False
self.work_path = self.work_dir or self.app_dir
if not self.build_dir:
self.build_path = os.path.join(self.work_path, "build")
elif os.path.isabs(self.build_dir):
self.build_path = self.build_dir
else:
self.build_path = os.path.normpath(os.path.join(self.work_path, self.build_dir))
@property @property
def app_dir(self): def app_dir(self):
""" """
@@ -208,6 +230,39 @@ class BuildItem(object):
path = os.path.expandvars(path) path = os.path.expandvars(path)
return path return path
def get_size_json_fp(self):
if self.size_json_fp and os.path.exists(self.size_json_fp):
return self.size_json_fp
assert os.path.exists(self.build_path)
assert os.path.exists(self.work_path)
map_file = find_first_match('*.map', self.build_path)
if not map_file:
raise ValueError('.map file not found under "{}"'.format(self.build_path))
size_json_fp = os.path.join(self.build_path, 'size.json')
idf_size_args = [
sys.executable,
IDF_SIZE_PY,
'--json',
'-o', size_json_fp,
map_file
]
subprocess.check_call(idf_size_args)
return size_json_fp
def write_size_info(self, size_info_fs):
if not self.size_json_fp or (not os.path.exists(self.size_json_fp)):
raise OSError('Run get_size_json_fp() for app {} after built binary'.format(self.app_dir))
size_info_dict = {
'app_name': self._app_name,
'config_name': self.config_name,
'target': self.target,
'path': self.size_json_fp,
}
size_info_fs.write(json.dumps(size_info_dict) + '\n')
class BuildSystem(object): class BuildSystem(object):
""" """
@@ -221,13 +276,8 @@ class BuildSystem(object):
@classmethod @classmethod
def build_prepare(cls, build_item): def build_prepare(cls, build_item):
app_path = build_item.app_dir app_path = build_item.app_dir
work_path = build_item.work_dir or app_path work_path = build_item.work_path
if not build_item.build_dir: build_path = build_item.build_path
build_path = os.path.join(work_path, "build")
elif os.path.isabs(build_item.build_dir):
build_path = build_item.build_dir
else:
build_path = os.path.join(work_path, build_item.build_dir)
if work_path != app_path: if work_path != app_path:
if os.path.exists(work_path): if os.path.exists(work_path):

View File

@@ -48,6 +48,8 @@ class MakeBuildSystem(BuildSystem):
log_file.close() log_file.close()
raise BuildError("Build failed with exit code {}".format(e.returncode)) raise BuildError("Build failed with exit code {}".format(e.returncode))
build_item.size_json_fp = build_item.get_size_json_fp()
@staticmethod @staticmethod
def is_app(path): def is_app(path):
makefile_path = os.path.join(path, "Makefile") makefile_path = os.path.join(path, "Makefile")

View File

@@ -10,18 +10,18 @@
/* utility functions */ /* utility functions */
static void die(const char* msg) __attribute__ ((noreturn)); static void die(const char* msg) __attribute__ ((noreturn));
static const char* get_test_name(); static const char* get_test_name(void);
/* functions which cause an exception/panic in different ways */ /* functions which cause an exception/panic in different ways */
static void test_abort(); static void test_abort(void);
static void test_int_wdt(); static void test_int_wdt(void);
static void test_task_wdt(); static void test_task_wdt(void);
static void test_storeprohibited(); static void test_storeprohibited(void);
static void test_cache_error(); static void test_cache_error(void);
static void test_int_wdt_cache_disabled(); static void test_int_wdt_cache_disabled(void);
static void test_stack_overflow(); static void test_stack_overflow(void);
static void test_illegal_instruction(); static void test_illegal_instruction(void);
static void test_instr_fetch_prohibited(); static void test_instr_fetch_prohibited(void);
void app_main(void) void app_main(void)
@@ -60,12 +60,12 @@ void app_main(void)
/* implementations of the test functions */ /* implementations of the test functions */
static void test_abort() static void test_abort(void)
{ {
abort(); abort();
} }
static void test_int_wdt() static void test_int_wdt(void)
{ {
portDISABLE_INTERRUPTS(); portDISABLE_INTERRUPTS();
while (true) { while (true) {
@@ -73,25 +73,25 @@ static void test_int_wdt()
} }
} }
static void test_task_wdt() static void test_task_wdt(void)
{ {
while (true) { while (true) {
; ;
} }
} }
static void test_storeprohibited() static void test_storeprohibited(void)
{ {
*(int*) 0x1 = 0; *(int*) 0x1 = 0;
} }
static IRAM_ATTR void test_cache_error() static IRAM_ATTR void test_cache_error(void)
{ {
esp_flash_default_chip->os_func->start(esp_flash_default_chip->os_func_data); esp_flash_default_chip->os_func->start(esp_flash_default_chip->os_func_data);
die("this should not be printed"); die("this should not be printed");
} }
static void IRAM_ATTR test_int_wdt_cache_disabled() static void IRAM_ATTR test_int_wdt_cache_disabled(void)
{ {
esp_flash_default_chip->os_func->start(esp_flash_default_chip->os_func_data); esp_flash_default_chip->os_func->start(esp_flash_default_chip->os_func_data);
portDISABLE_INTERRUPTS(); portDISABLE_INTERRUPTS();
@@ -100,7 +100,7 @@ static void IRAM_ATTR test_int_wdt_cache_disabled()
} }
} }
static void test_stack_overflow() static void test_stack_overflow(void)
{ {
volatile uint8_t stuff[CONFIG_ESP_MAIN_TASK_STACK_SIZE * 2]; volatile uint8_t stuff[CONFIG_ESP_MAIN_TASK_STACK_SIZE * 2];
for (int i = 0; i < sizeof(stuff); ++i) { for (int i = 0; i < sizeof(stuff); ++i) {
@@ -108,12 +108,12 @@ static void test_stack_overflow()
} }
} }
static void test_illegal_instruction() static void test_illegal_instruction(void)
{ {
__asm__ __volatile__("ill"); __asm__ __volatile__("ill");
} }
static void test_instr_fetch_prohibited() static void test_instr_fetch_prohibited(void)
{ {
typedef void (*fptr_t)(void); typedef void (*fptr_t)(void);
volatile fptr_t fptr = (fptr_t) 0x4; volatile fptr_t fptr = (fptr_t) 0x4;
@@ -124,7 +124,7 @@ static void test_instr_fetch_prohibited()
#define BOOT_CMD_MAX_LEN (128) #define BOOT_CMD_MAX_LEN (128)
static const char* get_test_name() static const char* get_test_name(void)
{ {
static char test_name_str[BOOT_CMD_MAX_LEN] = {0}; static char test_name_str[BOOT_CMD_MAX_LEN] = {0};

View File

@@ -1,10 +1,12 @@
from __future__ import print_function from __future__ import print_function
import argparse
import yaml import yaml
import os import os
import re import re
import shutil import shutil
import subprocess import subprocess
import sys
from copy import deepcopy from copy import deepcopy
import CreateSectionTable import CreateSectionTable
@@ -45,7 +47,6 @@ class Parser(object):
CONFIG_DEPENDENCY_FILE = os.path.join("tools", "unit-test-app", "tools", "ConfigDependency.yml") CONFIG_DEPENDENCY_FILE = os.path.join("tools", "unit-test-app", "tools", "ConfigDependency.yml")
MODULE_ARTIFACT_FILE = os.path.join("components", "idf_test", "ModuleDefinition.yml") MODULE_ARTIFACT_FILE = os.path.join("components", "idf_test", "ModuleDefinition.yml")
TEST_CASE_FILE_DIR = os.path.join("components", "idf_test", "unit_test") TEST_CASE_FILE_DIR = os.path.join("components", "idf_test", "unit_test")
UT_BIN_FOLDER = os.path.join("tools", "unit-test-app", "output")
UT_CONFIG_FOLDER = os.path.join("tools", "unit-test-app", "configs") UT_CONFIG_FOLDER = os.path.join("tools", "unit-test-app", "configs")
ELF_FILE = "unit-test-app.elf" ELF_FILE = "unit-test-app.elf"
SDKCONFIG_FILE = "sdkconfig" SDKCONFIG_FILE = "sdkconfig"
@@ -55,12 +56,15 @@ class Parser(object):
"esp32s2": "xtensa-esp32s2-elf-", "esp32s2": "xtensa-esp32s2-elf-",
} }
def __init__(self, idf_path=os.getenv("IDF_PATH"), idf_target=os.getenv("IDF_TARGET")): def __init__(self, binary_folder):
idf_path = os.getenv('IDF_PATH')
idf_target = os.getenv('IDF_TARGET')
self.test_env_tags = {} self.test_env_tags = {}
self.unit_jobs = {} self.unit_jobs = {}
self.file_name_cache = {} self.file_name_cache = {}
self.idf_path = idf_path self.idf_path = idf_path
self.idf_target = idf_target self.idf_target = idf_target
self.ut_bin_folder = binary_folder
self.objdump = Parser.TOOLCHAIN_FOR_TARGET.get(idf_target, "") + "objdump" self.objdump = Parser.TOOLCHAIN_FOR_TARGET.get(idf_target, "") + "objdump"
self.tag_def = yaml.load(open(os.path.join(idf_path, self.TAG_DEF_FILE), "r"), Loader=Loader) self.tag_def = yaml.load(open(os.path.join(idf_path, self.TAG_DEF_FILE), "r"), Loader=Loader)
self.module_map = yaml.load(open(os.path.join(idf_path, self.MODULE_DEF_FILE), "r"), Loader=Loader) self.module_map = yaml.load(open(os.path.join(idf_path, self.MODULE_DEF_FILE), "r"), Loader=Loader)
@@ -300,19 +304,19 @@ class Parser(object):
""" parse test cases from multiple built unit test apps """ """ parse test cases from multiple built unit test apps """
test_cases = [] test_cases = []
output_folder = os.path.join(self.idf_path, self.UT_BIN_FOLDER, self.idf_target) output_folder = os.path.join(self.idf_path, self.ut_bin_folder, self.idf_target)
configs_folder = os.path.join(self.idf_path, self.UT_CONFIG_FOLDER) configs_folder = os.path.join(self.idf_path, self.UT_CONFIG_FOLDER)
test_configs = os.listdir(output_folder) test_configs = os.listdir(output_folder)
for config in test_configs: for config in test_configs:
config_output_folder = os.path.join(output_folder, config) config_output_folder = os.path.join(output_folder, 'build', config)
if os.path.exists(config_output_folder): if os.path.exists(config_output_folder):
test_cases.extend(self.parse_test_cases_for_one_config(configs_folder, config_output_folder, config)) test_cases.extend(self.parse_test_cases_for_one_config(configs_folder, config_output_folder, config))
test_cases.sort(key=lambda x: x["config"] + x["summary"]) test_cases.sort(key=lambda x: x["config"] + x["summary"])
self.dump_test_cases(test_cases) self.dump_test_cases(test_cases)
def test_parser(): def test_parser(binary_folder):
parser = Parser() parser = Parser(binary_folder)
# test parsing tags # test parsing tags
# parsing module only and module in module list # parsing module only and module in module list
prop = parser.parse_case_properities("[esp32]") prop = parser.parse_case_properities("[esp32]")
@@ -353,20 +357,12 @@ def test_parser():
assert sorted(tags) == ['a', 'd', 'f'] # sorted is required for older Python3, e.g. 3.4.8 assert sorted(tags) == ['a', 'd', 'f'] # sorted is required for older Python3, e.g. 3.4.8
def main(): def main(binary_folder):
test_parser() assert os.getenv('IDF_PATH'), 'IDF_PATH must be set to use this script'
assert os.getenv('IDF_TARGET'), 'IDF_TARGET must be set to use this script'
test_parser(binary_folder)
idf_path = os.getenv("IDF_PATH") parser = Parser(binary_folder)
if not idf_path:
print("IDF_PATH must be set to use this script", file=sys.stderr)
raise SystemExit(1)
idf_target = os.getenv("IDF_TARGET")
if not idf_target:
print("IDF_TARGET must be set to use this script", file=sys.stderr)
raise SystemExit(1)
parser = Parser(idf_path, idf_target)
parser.parse_test_cases() parser.parse_test_cases()
parser.copy_module_def_file() parser.copy_module_def_file()
if len(parser.parsing_errors) > 0: if len(parser.parsing_errors) > 0:
@@ -376,4 +372,7 @@ def main():
if __name__ == '__main__': if __name__ == '__main__':
main() parser = argparse.ArgumentParser()
parser.add_argument('bin_dir', help='Binary Folder')
args = parser.parse_args()
main(args.bin_dir)