1#!/bin/bash
2#
3#  Copyright (c) 2018, The OpenThread Authors.
4#  All rights reserved.
5#
6#  Redistribution and use in source and binary forms, with or without
7#  modification, are permitted provided that the following conditions are met:
8#  1. Redistributions of source code must retain the above copyright
9#     notice, this list of conditions and the following disclaimer.
10#  2. Redistributions in binary form must reproduce the above copyright
11#     notice, this list of conditions and the following disclaimer in the
12#     documentation and/or other materials provided with the distribution.
13#  3. Neither the name of the copyright holder nor the
14#     names of its contributors may be used to endorse or promote products
15#     derived from this software without specific prior written permission.
16#
17#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27#  POSSIBILITY OF SUCH DAMAGE.
28#
29#    Description:
30#      This file runs various tests of OpenThread.
31#
32
33set -euo pipefail
34
35OT_BUILDDIR="${OT_BUILDDIR:-${PWD}/build}"
36readonly OT_BUILDDIR
37
38OT_SRCDIR="${PWD}"
39readonly OT_SRCDIR
40
41OT_COLOR_PASS='\033[0;32m'
42readonly OT_COLOR_PASS
43
44OT_COLOR_FAIL='\033[0;31m'
45readonly OT_COLOR_FAIL
46
47OT_COLOR_SKIP='\033[0;33m'
48readonly OT_COLOR_SKIP
49
50OT_COLOR_NONE='\033[0m'
51readonly OT_COLOR_NONE
52
53OT_NODE_TYPE="${OT_NODE_TYPE:-cli}"
54readonly OT_NODE_TYPE
55
56OT_NATIVE_IP="${OT_NATIVE_IP:-0}"
57readonly OT_NATIVE_IP
58
59THREAD_VERSION="${THREAD_VERSION:-1.4}"
60readonly THREAD_VERSION
61
62INTER_OP="${INTER_OP:-0}"
63readonly INTER_OP
64
65VERBOSE="${VERBOSE:-0}"
66readonly VERBOSE
67
68BORDER_ROUTING="${BORDER_ROUTING:-1}"
69readonly BORDER_ROUTING
70
71NAT64="${NAT64:-0}"
72readonly NAT64
73
74NAT64_SERVICE="${NAT64_SERVICE:-openthread}"
75readonly NAT64_SERVICE
76
77INTER_OP_BBR="${INTER_OP_BBR:-0}"
78readonly INTER_OP_BBR
79
80OT_COREDUMP_DIR="${PWD}/ot-core-dump"
81readonly OT_COREDUMP_DIR
82
83FULL_LOGS=${FULL_LOGS:-0}
84readonly FULL_LOGS
85
86TREL=${TREL:-0}
87readonly TREL
88
89LOCAL_OTBR_DIR=${LOCAL_OTBR_DIR:-""}
90readonly LOCAL_OTBR_DIR
91
92build_simulation()
93{
94    local version="$1"
95    local options=(
96        "-DBUILD_TESTING=ON"
97        "-DOT_ANYCAST_LOCATOR=ON"
98        "-DOT_DNS_CLIENT=ON"
99        "-DOT_DNS_DSO=ON"
100        "-DOT_DNSSD_SERVER=ON"
101        "-DOT_ECDSA=ON"
102        "-DOT_EXTERNAL_HEAP=ON"
103        "-DOT_HISTORY_TRACKER=ON"
104        "-DOT_MESSAGE_USE_HEAP=OFF"
105        "-DOT_NETDATA_PUBLISHER=ON"
106        "-DOT_PING_SENDER=ON"
107        "-DOT_PLATFORM_LOG_CRASH_DUMP=ON"
108        "-DOT_REFERENCE_DEVICE=ON"
109        "-DOT_SERVICE=ON"
110        "-DOT_SRP_CLIENT=ON"
111        "-DOT_SRP_SERVER=ON"
112        "-DOT_UPTIME=ON"
113        "-DOT_THREAD_VERSION=${version}"
114    )
115
116    if [[ ${FULL_LOGS} == 1 ]]; then
117        options+=("-DOT_FULL_LOGS=ON")
118    fi
119
120    if [[ ${version} != "1.1" ]]; then
121        options+=("-DOT_DUA=ON")
122        options+=("-DOT_MLR=ON")
123    fi
124
125    if [[ ${VIRTUAL_TIME} == 1 ]]; then
126        options+=("-DOT_SIMULATION_VIRTUAL_TIME=ON")
127    fi
128
129    if [[ ${version} != "1.1" ]]; then
130        options+=("-DOT_CSL_RECEIVER=ON")
131        options+=("-DOT_LINK_METRICS_INITIATOR=ON")
132        options+=("-DOT_LINK_METRICS_SUBJECT=ON")
133        options+=("-DOT_LINK_METRICS_MANAGER=ON")
134        options+=("-DOT_WAKEUP_COORDINATOR=ON")
135        options+=("-DOT_WAKEUP_END_DEVICE=ON")
136    fi
137
138    if [[ ${OT_NODE_TYPE} == cli* ]]; then
139        # Only enable OT_PLATFORM_BOOTLOADER_MODE when testing cli.
140        # This is intended to test that the "reset bootloader" CLI command returns a "NotCapable" error
141
142        # Note: Setting this option to ON for all OT_NODE_TYPEs will cause the posix/expects CI check to fail.
143        #       This is because the simulation RCP will have the SPINEL_CAP_RCP_RESET_TO_BOOTLOADER capability,
144        #       causing the ot-cli POSIX app to send the reset to simulation RCP successfully instead of printing
145        #       the expected error.
146        options+=("-DOT_PLATFORM_BOOTLOADER_MODE=ON")
147    fi
148
149    if [[ ${ot_extra_options[*]+x} ]]; then
150        options+=("${ot_extra_options[@]}")
151    fi
152
153    if [[ ${OT_NODE_TYPE} == rcp* ]]; then
154        options+=("-DOT_SIMULATION_INFRA_IF=OFF")
155    fi
156
157    OT_CMAKE_BUILD_DIR="${OT_BUILDDIR}/openthread-simulation-${version}" "${OT_SRCDIR}"/script/cmake-build simulation "${options[@]}"
158
159    if [[ ${VIRTUAL_TIME} == 1 ]] && [[ ${OT_NODE_TYPE} == rcp* ]]; then
160        OT_CMAKE_NINJA_TARGET=ot-rcp OT_CMAKE_BUILD_DIR="${OT_BUILDDIR}/openthread-simulation-${version}" "${OT_SRCDIR}"/script/cmake-build simulation "${options[@]}" "-DOT_SIMULATION_VIRTUAL_TIME_UART=ON"
161    fi
162
163    if [[ ${version} != "1.1" && ${INTER_OP_BBR} == 1 ]]; then
164
165        options+=("-DOT_BACKBONE_ROUTER=ON")
166
167        OT_CMAKE_BUILD_DIR="${OT_BUILDDIR}/openthread-simulation-${version}-bbr" "${OT_SRCDIR}"/script/cmake-build simulation "${options[@]}"
168
169        if [[ ${VIRTUAL_TIME} == 1 ]] && [[ ${OT_NODE_TYPE} == rcp* ]]; then
170            OT_CMAKE_NINJA_TARGET=ot-rcp OT_CMAKE_BUILD_DIR="${OT_BUILDDIR}/openthread-simulation-${version}-bbr" "${OT_SRCDIR}"/script/cmake-build simulation "${options[@]}" "-DOT_SIMULATION_VIRTUAL_TIME_UART=ON"
171        fi
172
173    fi
174}
175
176build_posix()
177{
178    local version="$1"
179    local options=(
180        "-DBUILD_TESTING=ON"
181        "-DOT_MESSAGE_USE_HEAP=ON"
182        "-DOT_PLATFORM_BOOTLOADER_MODE=ON"
183        "-DOT_PLATFORM_LOG_CRASH_DUMP=ON"
184        "-DOT_THREAD_VERSION=${version}"
185    )
186
187    if [[ ${version} != "1.1" ]]; then
188        options+=("-DOT_DUA=ON")
189        options+=("-DOT_MLR=ON")
190        options+=("-DOT_LINK_METRICS_INITIATOR=ON")
191        options+=("-DOT_LINK_METRICS_SUBJECT=ON")
192        options+=("-DOT_LINK_METRICS_MANAGER=ON")
193    fi
194
195    if [[ ${FULL_LOGS} == 1 ]]; then
196        options+=("-DOT_FULL_LOGS=ON")
197    fi
198
199    if [[ ${VIRTUAL_TIME} == 1 ]]; then
200        options+=("-DOT_POSIX_VIRTUAL_TIME=ON")
201    fi
202
203    if [[ ${OT_NATIVE_IP} == 1 ]]; then
204        options+=("-DOT_PLATFORM_UDP=ON" "-DOT_PLATFORM_NETIF=ON")
205    fi
206
207    if [[ ${ot_extra_options[*]+x} ]]; then
208        options+=("${ot_extra_options[@]}")
209    fi
210
211    OT_CMAKE_BUILD_DIR="${OT_BUILDDIR}/openthread-posix-${version}" "${OT_SRCDIR}"/script/cmake-build posix "${options[@]}"
212
213    if [[ ${version} != "1.1" && ${INTER_OP_BBR} == 1 ]]; then
214
215        options+=("-DOT_BACKBONE_ROUTER=ON")
216
217        OT_CMAKE_BUILD_DIR="${OT_BUILDDIR}/openthread-posix-${version}-bbr" "${OT_SRCDIR}"/script/cmake-build posix "${options[@]}"
218    fi
219}
220
221build_for_one_version()
222{
223    local version="$1"
224
225    build_simulation "${version}"
226
227    if [[ ${OT_NODE_TYPE} == rcp* ]]; then
228        build_posix "${version}"
229    fi
230}
231
232do_build()
233{
234    build_for_one_version "${THREAD_VERSION}"
235
236    if [[ ${THREAD_VERSION} != "1.1" && ${INTER_OP} == "1" ]]; then
237        build_for_one_version 1.1
238    fi
239}
240
241do_clean()
242{
243    ./script/gcda-tool clean
244    rm -rfv "${OT_BUILDDIR}" || sudo rm -rfv "${OT_BUILDDIR}"
245}
246
247do_unit_version()
248{
249    local version=$1
250    local builddir="${OT_BUILDDIR}/openthread-simulation-${version}"
251
252    if [[ ! -d ${builddir} ]]; then
253        echo "Cannot find build directory: ${builddir}"
254        exit 1
255    fi
256
257    (
258        cd "${builddir}"
259        ninja test
260    )
261}
262
263do_unit()
264{
265    do_unit_version "${THREAD_VERSION}"
266
267    if [[ ${THREAD_VERSION} != "1.1" && ${INTER_OP_BBR} == 1 ]]; then
268        do_unit_version "1.4-bbr"
269    fi
270}
271
272do_cert()
273{
274    export top_builddir="${OT_BUILDDIR}/openthread-simulation-${THREAD_VERSION}"
275    export top_srcdir="${OT_SRCDIR}"
276
277    case "${OT_NODE_TYPE}" in
278        rcp | rcp-cli | cli)
279            export NODE_TYPE=sim
280            ;;
281        rcp-ncp | ncp)
282            export NODE_TYPE=ncp-sim
283            ;;
284    esac
285
286    if [[ ${THREAD_VERSION} != "1.1" ]]; then
287        export top_builddir_1_4_bbr="${OT_BUILDDIR}/openthread-simulation-1.4-bbr"
288        if [[ ${INTER_OP} == "1" ]]; then
289            export top_builddir_1_1="${OT_BUILDDIR}/openthread-simulation-1.1"
290        fi
291    fi
292
293    export PYTHONPATH=tests/scripts/thread-cert
294
295    [[ ! -d tmp ]] || rm -rvf tmp
296    PYTHONUNBUFFERED=1 "$@"
297    exit 0
298}
299
300do_cert_suite()
301{
302    export top_builddir="${OT_BUILDDIR}/openthread-simulation-${THREAD_VERSION}"
303    export top_srcdir="${OT_SRCDIR}"
304
305    if [[ ${THREAD_VERSION} != "1.1" ]]; then
306        export top_builddir_1_4_bbr="${OT_BUILDDIR}/openthread-simulation-1.4-bbr"
307        if [[ ${INTER_OP} == "1" ]]; then
308            export top_builddir_1_1="${OT_BUILDDIR}/openthread-simulation-1.1"
309        fi
310    fi
311
312    export PYTHONPATH=tests/scripts/thread-cert
313    export VIRTUAL_TIME
314
315    sudo modprobe ip6table_filter
316
317    mkdir -p ot_testing
318    ./tests/scripts/thread-cert/run_cert_suite.py --run-directory ot_testing --multiply "${MULTIPLY:-1}" "$@"
319    exit 0
320}
321
322do_get_thread_wireshark()
323{
324    echo "Downloading thread-wireshark from https://github.com/openthread/wireshark/releases ..."
325    local download_url=https://github.com/openthread/wireshark/releases/download/ot-pktverify-20200727/thread-wireshark.tar.gz
326    local save_file=/tmp/thread-wireshark.tar.gz
327
328    rm -rf /tmp/thread-wireshark || true
329    rm -rf "${save_file}" || true
330    curl -L "${download_url}" -o "${save_file}"
331    tar -C /tmp -xvzf "${save_file}"
332
333    LD_LIBRARY_PATH=/tmp/thread-wireshark /tmp/thread-wireshark/tshark -v
334    LD_LIBRARY_PATH=/tmp/thread-wireshark /tmp/thread-wireshark/dumpcap -v
335    rm -rf "${save_file}"
336}
337
338do_build_otbr_docker()
339{
340    echo "Building OTBR Docker ..."
341    local otdir
342    local otbrdir
343    local otbr_options=(
344        "-DOT_ANYCAST_LOCATOR=ON"
345        "-DOT_COVERAGE=ON"
346        "-DOT_DNS_CLIENT=ON"
347        "-DOT_DUA=ON"
348        "-DOT_MLR=ON"
349        "-DOT_NETDATA_PUBLISHER=ON"
350        "-DOT_SLAAC=ON"
351        "-DOT_SRP_CLIENT=ON"
352        "-DOT_FULL_LOGS=ON"
353        "-DOT_UPTIME=ON"
354        "-DOTBR_DNS_UPSTREAM_QUERY=ON"
355        "-DOTBR_DUA_ROUTING=ON"
356        "-DOTBR_DHCP6_PD=ON"
357    )
358    local args=(
359        "BORDER_ROUTING=${BORDER_ROUTING}"
360        "INFRA_IF_NAME=eth0"
361        "BACKBONE_ROUTER=1"
362        "REFERENCE_DEVICE=1"
363        "OT_BACKBONE_CI=1"
364        "NAT64=${NAT64}"
365        "NAT64_SERVICE=${NAT64_SERVICE}"
366        "DNS64=${NAT64}"
367        "REST_API=0"
368        "WEB_GUI=0"
369        "MDNS=${OTBR_MDNS:-mDNSResponder}"
370        "FIREWALL=${FIREWALL:-1}"
371    )
372
373    if [[ ${NAT64} != 1 ]]; then
374        # We are testing upstream DNS forwarding in the NAT64 tests, and OPENTHREAD_CONFIG_DNSSD_SERVER_BIND_UNSPECIFIED_NETIF will block OpenThread's DNSSD server since we already have bind9 running.
375        otbr_options+=("-DCMAKE_CXX_FLAGS='-DOPENTHREAD_CONFIG_DNSSD_SERVER_BIND_UNSPECIFIED_NETIF=1'")
376    fi
377
378    if [[ ${TREL} == 1 ]]; then
379        otbr_options+=("-DOTBR_TREL=ON")
380    else
381        otbr_options+=("-DOTBR_TREL=OFF")
382    fi
383
384    local otbr_docker_image=${OTBR_DOCKER_IMAGE:-otbr-ot12-backbone-ci}
385    local docker_build_args=()
386
387    for arg in "${args[@]}"; do
388        docker_build_args+=("--build-arg" "$arg")
389    done
390
391    otbrdir=$(mktemp -d -t otbr_XXXXXX)
392    otdir=$(pwd)
393
394    (
395        if [[ -z ${LOCAL_OTBR_DIR} ]]; then
396            ./script/git-tool clone https://github.com/openthread/ot-br-posix.git --depth 1 "${otbrdir}"
397        else
398            rsync -r \
399                --exclude=third_party/openthread/repo \
400                --exclude=.git \
401                --exclude=build \
402                "${LOCAL_OTBR_DIR}/." \
403                "${otbrdir}"
404        fi
405
406        cd "${otbrdir}"
407        rm -rf third_party/openthread/repo
408        rsync -r \
409            --exclude=build \
410            --exclude=ot_testing \
411            --exclude=__pycache__ \
412            "${otdir}/." \
413            third_party/openthread/repo
414        rm -rf .git
415
416        docker build -t "${otbr_docker_image}" -f etc/docker/Dockerfile . \
417            "${docker_build_args[@]}" \
418            --build-arg OTBR_OPTIONS="${otbr_options[*]}"
419    )
420
421    rm -rf "${otbrdir}"
422}
423
424do_pktverify()
425{
426    ./tests/scripts/thread-cert/pktverify/verify.py "$1"
427}
428
429ot_exec_expect_script()
430{
431    local log_file="tmp/log_expect"
432
433    for script in "$@"; do
434        echo -e "\n${OT_COLOR_PASS}EXEC${OT_COLOR_NONE} ${script}"
435        sudo killall ot-rcp || true
436        sudo killall ot-cli || true
437        sudo killall ot-cli-ftd || true
438        sudo killall ot-cli-mtd || true
439        sudo rm -rf tmp
440        mkdir tmp
441        {
442            if [[ ${OT_NATIVE_IP} == 1 ]]; then
443                sudo -E expect -df "${script}" 2>"${log_file}"
444            else
445                expect -df "${script}" 2>"${log_file}"
446            fi
447        } || {
448            local EXIT_CODE=$?
449
450            # The exit status 77 for skipping is inherited from automake's test driver for script-based testsuites
451            if [[ ${EXIT_CODE} == 77 ]]; then
452                echo -e "\n${OT_COLOR_SKIP}SKIP${OT_COLOR_NONE} ${script}"
453                return 0
454            else
455                echo -e "\n${OT_COLOR_FAIL}FAIL${OT_COLOR_NONE} ${script}"
456                cat "${log_file}" >&2
457                return "${EXIT_CODE}"
458            fi
459        }
460        echo -e "\n${OT_COLOR_PASS}PASS${OT_COLOR_NONE} ${script}"
461        if [[ ${VERBOSE} == 1 ]]; then
462            cat "${log_file}" >&2
463        fi
464    done
465}
466
467do_expect()
468{
469    local test_patterns
470
471    if [[ ${OT_NODE_TYPE} == rcp* ]]; then
472        if [[ ${OT_NATIVE_IP} == 1 ]]; then
473            test_patterns=(-name 'tun-*.exp')
474        else
475            test_patterns=(-name 'posix-*.exp' -o -name 'cli-*.exp')
476            if [[ ${THREAD_VERSION} != "1.1" ]]; then
477                test_patterns+=(-o -name 'v1_2-*.exp')
478            fi
479        fi
480    else
481        test_patterns=(-name 'cli-*.exp' -o -name 'simulation-*.exp' -o -name 'cli_non_rcp-*.exp')
482    fi
483
484    if [[ $# != 0 ]]; then
485        ot_exec_expect_script "$@"
486    else
487        export OT_COLOR_PASS OT_COLOR_FAIL OT_COLOR_SKIP OT_COLOR_NONE OT_NATIVE_IP VERBOSE
488        export -f ot_exec_expect_script
489
490        find tests/scripts/expect -type f -perm "$([[ $OSTYPE == darwin* ]] && echo '+' || echo '/')"111 \( "${test_patterns[@]}" \) -exec bash -c 'set -euo pipefail;ot_exec_expect_script "$@"' _ {} +
491    fi
492
493    exit 0
494}
495
496print_usage()
497{
498    echo "USAGE: [ENVIRONMENTS] $0 COMMANDS
499
500ENVIRONMENTS:
501    OT_NODE_TYPE    'cli' for CLI simulation, 'ncp' for NCP simulation.
502                    'rcp' or 'rcp-cli' for CLI on POSIX platform.
503                    'rcp-ncp' for NCP on POSIX platform.
504                    The default is 'cli'.
505    OT_NATIVE_IP    1 to enable platform UDP and netif on POSIX platform. The default is 0.
506    OT_BUILDDIR     The output directory for cmake build. By default the directory is './build'. For example,
507                    'OT_BUILDDIR=\${PWD}/my_awesome_build ./script/test clean build'.
508    VERBOSE         1 to build or test verbosely. The default is 0.
509    VIRTUAL_TIME    1 for virtual time, otherwise real time. The default value is 0 when running expect tests,
510                    otherwise default value is 1.
511    THREAD_VERSION  1.1 for Thread 1.1 stack, 1.4 for Thread 1.4 stack. The default is 1.4.
512    INTER_OP        1 to build 1.1 together. Only works when THREAD_VERSION is 1.4. The default is 0.
513    INTER_OP_BBR    1 to build bbr version together. Only works when THREAD_VERSION is 1.4. The default is 1.
514
515COMMANDS:
516    clean           Clean built files to prepare for new build.
517    build           Build project for running tests. This can be used to rebuild the project for changes.
518    cert            Run a single thread-cert test. ENVIRONMENTS should be the same as those given to build or update.
519    cert_suite      Run a batch of thread-cert tests and summarize the test results. Only echo logs for failing tests.
520    unit            Run all the unit tests. This should be called after simulation is built.
521    expect          Run expect tests.
522    help            Print this help.
523
524EXAMPLES:
525    # Test CLI with default settings
526    $0 clean build cert tests/scripts/thread-cert/Cert_5_1_01_RouterAttach.py
527    $0 cert tests/scripts/thread-cert/Cert_5_1_02_ChildAddressTimeout.py
528
529    # Test NCP with default settings
530    $0 clean build cert tests/scripts/thread-cert/Cert_5_1_01_RouterAttach.py
531    $0 cert tests/scripts/thread-cert/Cert_5_1_02_ChildAddressTimeout.py
532
533    # Test CLI with radio only
534    $0 clean build cert tests/scripts/thread-cert/Cert_5_1_01_RouterAttach.py
535    $0 cert tests/scripts/thread-cert/Cert_5_1_02_ChildAddressTimeout.py
536
537    # Test CLI with real time
538    VIRTUAL_TIME=0 $0 clean build cert tests/scripts/thread-cert/Cert_5_1_01_RouterAttach.py
539    VIRTUAL_TIME=0 $0 cert tests/scripts/thread-cert/Cert_5_1_02_ChildAddressTimeout.py
540
541    # Test Thread 1.1 CLI with real time
542    THREAD_VERSION=1.1 VIRTUAL_TIME=0 $0 clean build cert tests/scripts/thread-cert/Cert_5_1_01_RouterAttach.py
543    THREAD_VERSION=1.1 VIRTUAL_TIME=0 $0 cert tests/scripts/thread-cert/Cert_5_1_02_ChildAddressTimeout.py
544
545    # Test Thread 1.4 with real time, use 'INTER_OP=1' when the case needs both versions.
546    VIRTUAL_TIME=0 $0 clean build cert tests/scripts/thread-cert/v1_2_test_enhanced_keep_alive.py
547    INTER_OP=1 VIRTUAL_TIME=0 $0 clean build cert tests/scripts/thread-cert/v1_2_router_5_1_1.py
548    INTER_OP=1 VIRTUAL_TIME=0 $0 clean build cert_suite tests/scripts/thread-cert/v1_2_*
549
550    # Run a single expect test
551    $0 clean build expect tests/scripts/expect/cli-log-level.exp
552
553    # Run all expect tests
554    $0 clean build expect
555    "
556
557    exit "$1"
558}
559
560do_prepare_coredump_upload()
561{
562    echo "$OT_COREDUMP_DIR/corefile-%e-%p-%t" | sudo tee /proc/sys/kernel/core_pattern
563    rm -rf "$OT_COREDUMP_DIR"
564    mkdir -p "$OT_COREDUMP_DIR"
565}
566
567do_copy_so_lib()
568{
569    mkdir -p "$OT_COREDUMP_DIR/so-lib"
570    cp /lib/x86_64-linux-gnu/libgcc_s.so.1 "$OT_COREDUMP_DIR/so-lib"
571    cp /lib/x86_64-linux-gnu/libc.so.6 "$OT_COREDUMP_DIR/so-lib"
572    cp /lib64/ld-linux-x86-64.so.2 "$OT_COREDUMP_DIR/so-lib"
573}
574
575do_check_crash()
576{
577    shopt -s nullglob
578
579    # Scan core dumps and collect binaries which crashed
580    declare -A bin_list=([dummy]='')
581    for f in "$OT_COREDUMP_DIR"/core*; do
582        bin=$(file "$f" | grep -E -o "execfn: '(.*')," | sed -r "s/execfn: '(.*)',/\1/")
583        bin_list[$bin]=''
584    done
585
586    for key in "${!bin_list[@]}"; do
587        if [ "$key" != "dummy" ]; then
588            # Add postfix for binaries to avoid conflicts caused by different Thread version
589            postfix=""
590            if [[ $key =~ openthread-(simulation|posix)-([0-9]\.[0-9]) ]]; then
591                postfix="-$(echo "$key" | sed -r "s/.*openthread-(simulation|posix)-([0-9]\.[0-9]).*/\2/")"
592            fi
593            bin_name=$(basename "$key")
594            cp "$key" "$OT_COREDUMP_DIR"/"$bin_name""$postfix"
595        fi
596    done
597
598    # echo 1 and copy so libs if crash found, echo 0 otherwise
599    [[ ${#bin_list[@]} -gt 1 ]] && (
600        echo 1
601        do_copy_so_lib
602    ) || echo 0
603}
604
605do_generate_coverage()
606{
607    mkdir -p tmp/
608    sudo chmod 777 tmp/
609    rm -f tmp/coverage.lcov
610    if [[ $1 == "llvm" ]]; then
611        local llvm_gcov
612        llvm_gcov="$(mktemp -d)/llvm-gcov"
613        echo '#!/bin/bash' >>"$llvm_gcov"
614        echo 'exec llvm-cov gcov "$@"' >>"$llvm_gcov"
615        chmod +x "$llvm_gcov"
616        lcov --gcov-tool "$llvm_gcov" --directory . --capture --output-file tmp/coverage.info
617    else
618        ./script/gcda-tool collect
619        ./script/gcda-tool install
620
621        lcov --directory . --capture --output-file tmp/coverage.info
622    fi
623    lcov --list tmp/coverage.info
624    lcov --extract tmp/coverage.info "$PWD/src/core/common/message.cpp" | c++filt
625}
626
627do_combine_coverage()
628{
629    ls -R coverage/
630
631    readarray -d '' files < <(find coverage/ -type f -name 'coverage*.info' -print0)
632
633    local args=()
634    for i in "${files[@]}"; do
635        args+=('-a')
636        args+=("$i")
637    done
638    lcov "${args[@]}" -o final.info
639}
640
641envsetup()
642{
643    export THREAD_VERSION
644
645    if [[ ${OT_NODE_TYPE} == rcp* ]]; then
646        export RADIO_DEVICE="${OT_BUILDDIR}/openthread-simulation-${THREAD_VERSION}/examples/apps/ncp/ot-rcp"
647        export OT_CLI_PATH="${OT_BUILDDIR}/openthread-posix-${THREAD_VERSION}/src/posix/ot-cli"
648
649        if [[ ${THREAD_VERSION} != "1.1" ]]; then
650            export RADIO_DEVICE_1_1="${OT_BUILDDIR}/openthread-simulation-1.1/examples/apps/ncp/ot-rcp"
651            export OT_CLI_PATH_1_1="${OT_BUILDDIR}/openthread-posix-1.1/src/posix/ot-cli"
652            export OT_CLI_PATH_BBR="${OT_BUILDDIR}/openthread-posix-1.4-bbr/src/posix/ot-cli"
653        fi
654    fi
655
656    export OT_SIMULATION_APPS="${OT_BUILDDIR}/openthread-simulation-${THREAD_VERSION}/examples/apps"
657    export OT_POSIX_APPS="${OT_BUILDDIR}/openthread-posix-${THREAD_VERSION}/src/posix"
658
659    if [[ ! ${VIRTUAL_TIME+x} ]]; then
660        # All expect tests only works in real time mode.
661        VIRTUAL_TIME=1
662        for arg in "$@"; do
663            if [[ $arg == expect ]]; then
664                VIRTUAL_TIME=0
665                break
666            fi
667        done
668    fi
669
670    readonly VIRTUAL_TIME
671    export OT_NODE_TYPE VIRTUAL_TIME
672
673    # CMake always works in verbose mode if VERBOSE exists in environments.
674    if [[ ${VERBOSE} == 1 ]]; then
675        export VERBOSE
676    else
677        export -n VERBOSE
678    fi
679
680    if [[ ${OT_OPTIONS+x} ]]; then
681        read -r -a ot_extra_options <<<"${OT_OPTIONS}"
682    else
683        ot_extra_options=()
684    fi
685}
686
687main()
688{
689    envsetup "$@"
690
691    if [[ -z ${1-} ]]; then
692        print_usage 1
693    fi
694
695    [[ ${VIRTUAL_TIME} == 1 ]] && echo "Using virtual time" || echo "Using real time"
696    [[ ${THREAD_VERSION} != "1.1" ]] && echo "Using Thread 1.4 stack" || echo "Using Thread 1.1 stack"
697
698    while [[ $# != 0 ]]; do
699        case "$1" in
700            clean)
701                do_clean
702                ;;
703            build)
704                do_build
705                ;;
706            cert)
707                shift
708                do_cert "$@"
709                ;;
710            cert_suite)
711                shift
712                do_cert_suite "$@"
713                ;;
714            get_thread_wireshark)
715                do_get_thread_wireshark
716                ;;
717            build_otbr_docker)
718                do_build_otbr_docker
719                ;;
720            pktverify)
721                shift
722                do_pktverify "$1"
723                ;;
724            unit)
725                do_unit
726                ;;
727            help)
728                print_usage
729                ;;
730            package)
731                ./script/package "${ot_extra_options[@]}"
732                ;;
733            expect)
734                shift
735                do_expect "$@"
736                ;;
737            prepare_coredump_upload)
738                do_prepare_coredump_upload
739                ;;
740            check_crash)
741                do_check_crash
742                ;;
743            generate_coverage)
744                shift
745                do_generate_coverage "$1"
746                ;;
747            combine_coverage)
748                do_combine_coverage
749                ;;
750            *)
751                echo
752                echo -e "${OT_COLOR_FAIL}Warning:${OT_COLOR_NONE} Ignoring: '$1'"
753                ;;
754        esac
755        shift
756    done
757}
758
759main "$@"
760