#!/usr/bin/env bash # # Copyright (c) 2020 Project CHIP Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # Don't warn about unreachable commands in this file: # shellcheck disable=SC2317 SOURCE=${BASH_SOURCE[0]} SOURCE_DIR=$(cd "$(dirname "$SOURCE")" >/dev/null 2>&1 && pwd) REPO_DIR=$SOURCE_DIR/../../ TEST_DIR=$REPO_DIR/src/test_driver/linux-cirque LOG_DIR=${LOG_DIR:-$(mktemp -d)} GITHUB_ACTION_RUN=${GITHUB_ACTION_RUN:-"0"} # The image build will clone its own ot-br-posix checkout due to limitations of git submodule. # Using the same ot-br-posix version as chip OPENTHREAD=$REPO_DIR/third_party/openthread/repo OPENTHREAD_CHECKOUT=$(cd "$REPO_DIR" && git rev-parse :third_party/openthread/repo) OT_BR_POSIX_CHECKOUT=$(cd "$REPO_DIR" && git rev-parse :third_party/ot-br-posix/repo) CIRQUE_CACHE_PATH=${GITHUB_CACHE_PATH:-"/tmp/cirque-cache/"} OT_SIMULATION_CACHE="$CIRQUE_CACHE_PATH/ot-simulation-cmake.tgz" OT_SIMULATION_CACHE_STAMP_FILE="$CIRQUE_CACHE_PATH/ot-simulation.commit" # Append test name here to add more tests for run_all_tests # # NOTE: # "InteractionModelTest" is currently disabled due to it overriding # internal data model methods (for example it says "CommandExists" for # paths where endpoint/cluster do not) CIRQUE_TESTS=( "EchoTest" "EchoOverTcpTest" "FailsafeTest" "MobileDeviceTest" "CommissioningTest" "IcdWaitForActiveTest" "SplitCommissioningTest" "CommissioningFailureTest" "CommissioningFailureOnReportTest" "PythonCommissioningTest" "CommissioningWindowTest" "SubscriptionResumptionTest" "SubscriptionResumptionCapacityTest" "SubscriptionResumptionTimeoutTest" ) BOLD_GREEN_TEXT="\033[1;32m" BOLD_YELLOW_TEXT="\033[1;33m" BOLD_RED_TEXT="\033[1;31m" RESET_COLOR="\033[0m" function __cirquetest_start_flask() { echo 'Start Flask' cd "$REPO_DIR"/third_party/cirque/repo # When running the ManualTests, if Ctrl-C is send to the shell, it will stop flask as well. # This is not expected. Start a new session to prevent it from receiving signals setsid bash -c 'FLASK_APP=cirque/restservice/service.py \ PATH="'"$PATH"'":"'"$REPO_DIR"'"/third_party/openthread/repo/build/simulation/examples/apps/ncp/ \ python3 -m flask run >"'"$LOG_DIR"'"/"'"$CURRENT_TEST"'"/flask.log 2>&1' & FLASK_PID=$! echo "Flask running in backgroud with pid $FLASK_PID" } function __cirquetest_clean_flask() { echo "Cleanup Flask pid $FLASK_PID" kill -SIGTERM -"$FLASK_PID" mv "$LOG_DIR/$CURRENT_TEST"/flask.log "$LOG_DIR/$CURRENT_TEST"/flask.log.old cat "$LOG_DIR/$CURRENT_TEST"/flask.log.old | sed 's/\\n/\n/g' | sed 's/\\t/ /g' >"$LOG_DIR/$CURRENT_TEST"/flask.log rm "$LOG_DIR/$CURRENT_TEST"/flask.log.old } function __cirquetest_build_ot() { echo -e "[$BOLD_YELLOW_TEXT""INFO""$RESET_COLOR] Cache miss, build openthread simulation." script/cmake-build simulation -DOT_THREAD_VERSION=1.2 -DOT_MTD=OFF -DOT_FTD=OFF -DWEB_GUI=0 -DNETWORK_MANAGER=0 -DREST_API=0 -DNAT64=0 -DOT_LOG_OUTPUT=PLATFORM_DEFINED -DOT_LOG_LEVEL=DEBG mkdir -p "$(dirname "$OT_SIMULATION_CACHE")" tar czf "$OT_SIMULATION_CACHE" build echo "$OPENTHREAD_CHECKOUT" >"$OT_SIMULATION_CACHE_STAMP_FILE" } function __cirquetest_build_ot_lazy() { pushd . cd "$REPO_DIR"/third_party/openthread/repo ([[ -f "$OT_SIMULATION_CACHE_STAMP_FILE" ]] && [[ "$(cat "$OT_SIMULATION_CACHE_STAMP_FILE")" = "$OPENTHREAD_CHECKOUT" ]] && [[ -f "$OT_SIMULATION_CACHE" ]] && tar zxf "$OT_SIMULATION_CACHE") || __cirquetest_build_ot popd } function __cirquetest_self_hash() { shasum "$SOURCE" | awk '{ print $1 }' } function cirquetest_cachekey() { echo "$("$REPO_DIR"/integrations/docker/images/stage-2/chip-cirque-device-base/cachekey.sh).openthread.$OPENTHREAD_CHECKOUT.cirque_test.$(__cirquetest_self_hash)" } function cirquetest_cachekeyhash() { cirquetest_cachekey | shasum | awk '{ print $1 }' } function cirquetest_bootstrap() { set -ex cd "$REPO_DIR"/third_party/cirque/repo pip3 install --break-system-packages pycodestyle==2.5.0 wheel make NO_GRPC=1 install -j git config --global --add safe.directory /home/runner/work/connectedhomeip/connectedhomeip "$REPO_DIR"/integrations/docker/images/stage-2/chip-cirque-device-base/build.sh --build-arg OT_BR_POSIX_CHECKOUT="$OT_BR_POSIX_CHECKOUT" __cirquetest_build_ot_lazy pip3 install --break-system-packages -r requirements_nogrpc.txt echo "OpenThread Version: $OPENTHREAD_CHECKOUT" echo "ot-br-posix Version: $OT_BR_POSIX_CHECKOUT" } function cirquetest_run_test() { # Start Cirque flash server export CURRENT_TEST="$1" export DEVICE_LOG_DIR="$LOG_DIR/$CURRENT_TEST"/device_logs shift mkdir -p "$DEVICE_LOG_DIR" __cirquetest_start_flask sleep 5 CHIP_CIRQUE_BASE_IMAGE="ghcr.io/project-chip/chip-cirque-device-base" "$TEST_DIR/$CURRENT_TEST.py" "$@" exitcode=$? __cirquetest_clean_flask # TODO: Do docker system prune, we cannot filter which container # is created by cirque now. This will be implemented later. Currently, only do this on CI # After test finished, the container is perserved and networks will not be deleted # This is useful when running tests on local workstation, but not for CI. if [[ "$CLEANUP_DOCKER_FOR_CI" = "1" ]]; then echo "Do docker container and network prune" # TODO: Filter cirque containers ? if ! grep docker.sock /proc/1/mountinfo; then docker ps -aq | xargs docker stop >/dev/null 2>&1 fi docker container prune -f >/dev/null 2>&1 docker network prune -f >/dev/null 2>&1 fi echo "Test log can be found at $DEVICE_LOG_DIR" return "$exitcode" } function cirquetest_run_all_tests() { # shellharden requires quotes around variables, which will break for-each loops # This is the workaround echo "Logs will be stored at $LOG_DIR" test_pass=1 mkdir -p "$LOG_DIR" for test_name in "${CIRQUE_TESTS[@]}"; do echo "[ RUN] $test_name" if cirquetest_run_test "$test_name" >"$LOG_DIR/$test_name.log" 2>&1; then echo -e "[$BOLD_GREEN_TEXT""PASS""$RESET_COLOR] $test_name" else echo -e "[$BOLD_RED_TEXT""FAIL""$RESET_COLOR] $test_name (Exitcode: $exitcode)" test_pass=0 fi done if [[ "$GITHUB_ACTION_RUN" = "1" ]]; then echo -e "[$BOLD_YELLOW_TEXT""INFO""$RESET_COLOR] Logs will be uploaded to artifacts." fi if ((test_pass)); then echo -e "[$BOLD_GREEN_TEXT""PASS""$RESET_COLOR] Test finished, test log can be found at $LOG_DIR" return 0 else echo -e "[$BOLD_RED_TEXT""FAIL""$RESET_COLOR] Test failed, test log can be found at $LOG_DIR" return 1 fi } subcommand=$1 shift case $subcommand in *) cirquetest_"$subcommand" "$@" exitcode=$? if ((exitcode == 127)); then echo "Unknown command: $subcommand" >&2 fi exit "$exitcode" ;; esac