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.3}"
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_REFERENCE_DEVICE=ON"
108        "-DOT_SERVICE=ON"
109        "-DOT_SRP_CLIENT=ON"
110        "-DOT_SRP_SERVER=ON"
111        "-DOT_UPTIME=ON"
112        "-DOT_THREAD_VERSION=${version}"
113    )
114
115    if [[ ${FULL_LOGS} == 1 ]]; then
116        options+=("-DOT_FULL_LOGS=ON")
117    fi
118
119    if [[ ${version} != "1.1" ]]; then
120        options+=("-DOT_DUA=ON")
121        options+=("-DOT_MLR=ON")
122    fi
123
124    if [[ ${VIRTUAL_TIME} == 1 ]]; then
125        options+=("-DOT_SIMULATION_VIRTUAL_TIME=ON")
126    fi
127
128    if [[ ${version} != "1.1" ]]; then
129        options+=("-DOT_CSL_RECEIVER=ON")
130        options+=("-DOT_LINK_METRICS_INITIATOR=ON")
131        options+=("-DOT_LINK_METRICS_SUBJECT=ON")
132        options+=("-DOT_LINK_METRICS_MANAGER=ON")
133    fi
134
135    if [[ ${ot_extra_options[*]+x} ]]; then
136        options+=("${ot_extra_options[@]}")
137    fi
138
139    OT_CMAKE_BUILD_DIR="${OT_BUILDDIR}/openthread-simulation-${version}" "${OT_SRCDIR}"/script/cmake-build simulation "${options[@]}"
140
141    if [[ ${VIRTUAL_TIME} == 1 ]] && [[ ${OT_NODE_TYPE} == rcp* ]]; then
142        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"
143    fi
144
145    if [[ ${version} != "1.1" && ${INTER_OP_BBR} == 1 ]]; then
146
147        options+=("-DOT_BACKBONE_ROUTER=ON")
148
149        OT_CMAKE_BUILD_DIR="${OT_BUILDDIR}/openthread-simulation-${version}-bbr" "${OT_SRCDIR}"/script/cmake-build simulation "${options[@]}"
150
151        if [[ ${VIRTUAL_TIME} == 1 ]] && [[ ${OT_NODE_TYPE} == rcp* ]]; then
152            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"
153        fi
154
155    fi
156}
157
158build_posix()
159{
160    local version="$1"
161    local options=("-DOT_MESSAGE_USE_HEAP=ON" "-DOT_THREAD_VERSION=${version}" "-DBUILD_TESTING=ON")
162
163    if [[ ${version} != "1.1" ]]; then
164        options+=("-DOT_DUA=ON")
165        options+=("-DOT_MLR=ON")
166        options+=("-DOT_LINK_METRICS_INITIATOR=ON")
167        options+=("-DOT_LINK_METRICS_SUBJECT=ON")
168        options+=("-DOT_LINK_METRICS_MANAGER=ON")
169    fi
170
171    if [[ ${FULL_LOGS} == 1 ]]; then
172        options+=("-DOT_FULL_LOGS=ON")
173    fi
174
175    if [[ ${VIRTUAL_TIME} == 1 ]]; then
176        options+=("-DOT_POSIX_VIRTUAL_TIME=ON")
177    fi
178
179    if [[ ${OT_NATIVE_IP} == 1 ]]; then
180        options+=("-DOT_PLATFORM_UDP=ON" "-DOT_PLATFORM_NETIF=ON")
181    fi
182
183    if [[ ${ot_extra_options[*]+x} ]]; then
184        options+=("${ot_extra_options[@]}")
185    fi
186
187    OT_CMAKE_BUILD_DIR="${OT_BUILDDIR}/openthread-posix-${version}" "${OT_SRCDIR}"/script/cmake-build posix "${options[@]}"
188
189    if [[ ${version} != "1.1" && ${INTER_OP_BBR} == 1 ]]; then
190
191        options+=("-DOT_BACKBONE_ROUTER=ON")
192
193        OT_CMAKE_BUILD_DIR="${OT_BUILDDIR}/openthread-posix-${version}-bbr" "${OT_SRCDIR}"/script/cmake-build posix "${options[@]}"
194    fi
195}
196
197build_for_one_version()
198{
199    local version="$1"
200
201    build_simulation "${version}"
202
203    if [[ ${OT_NODE_TYPE} == rcp* ]]; then
204        build_posix "${version}"
205    fi
206}
207
208do_build()
209{
210    build_for_one_version "${THREAD_VERSION}"
211
212    if [[ ${THREAD_VERSION} != "1.1" && ${INTER_OP} == "1" ]]; then
213        build_for_one_version 1.1
214    fi
215}
216
217do_clean()
218{
219    ./script/gcda-tool clean
220    rm -rfv "${OT_BUILDDIR}" || sudo rm -rfv "${OT_BUILDDIR}"
221}
222
223do_unit_version()
224{
225    local version=$1
226    local builddir="${OT_BUILDDIR}/openthread-simulation-${version}"
227
228    if [[ ! -d ${builddir} ]]; then
229        echo "Cannot find build directory: ${builddir}"
230        exit 1
231    fi
232
233    (
234        cd "${builddir}"
235        ninja test
236    )
237}
238
239do_unit()
240{
241    do_unit_version "${THREAD_VERSION}"
242
243    if [[ ${THREAD_VERSION} != "1.1" && ${INTER_OP_BBR} == 1 ]]; then
244        do_unit_version "1.3-bbr"
245    fi
246}
247
248do_cert()
249{
250    export top_builddir="${OT_BUILDDIR}/openthread-simulation-${THREAD_VERSION}"
251    export top_srcdir="${OT_SRCDIR}"
252
253    case "${OT_NODE_TYPE}" in
254        rcp | rcp-cli | cli)
255            export NODE_TYPE=sim
256            ;;
257        rcp-ncp | ncp)
258            export NODE_TYPE=ncp-sim
259            ;;
260    esac
261
262    if [[ ${THREAD_VERSION} != "1.1" ]]; then
263        export top_builddir_1_3_bbr="${OT_BUILDDIR}/openthread-simulation-1.3-bbr"
264        if [[ ${INTER_OP} == "1" ]]; then
265            export top_builddir_1_1="${OT_BUILDDIR}/openthread-simulation-1.1"
266        fi
267    fi
268
269    export PYTHONPATH=tests/scripts/thread-cert
270
271    [[ ! -d tmp ]] || rm -rvf tmp
272    PYTHONUNBUFFERED=1 "$@"
273    exit 0
274}
275
276do_cert_suite()
277{
278    export top_builddir="${OT_BUILDDIR}/openthread-simulation-${THREAD_VERSION}"
279    export top_srcdir="${OT_SRCDIR}"
280
281    if [[ ${THREAD_VERSION} != "1.1" ]]; then
282        export top_builddir_1_3_bbr="${OT_BUILDDIR}/openthread-simulation-1.3-bbr"
283        if [[ ${INTER_OP} == "1" ]]; then
284            export top_builddir_1_1="${OT_BUILDDIR}/openthread-simulation-1.1"
285        fi
286    fi
287
288    export PYTHONPATH=tests/scripts/thread-cert
289    export VIRTUAL_TIME
290
291    sudo modprobe ip6table_filter
292
293    mkdir -p ot_testing
294    ./tests/scripts/thread-cert/run_cert_suite.py --run-directory ot_testing --multiply "${MULTIPLY:-1}" "$@"
295    exit 0
296}
297
298do_get_thread_wireshark()
299{
300    echo "Downloading thread-wireshark from https://github.com/openthread/wireshark/releases ..."
301    local download_url=https://github.com/openthread/wireshark/releases/download/ot-pktverify-20200727/thread-wireshark.tar.gz
302    local save_file=/tmp/thread-wireshark.tar.gz
303
304    rm -rf /tmp/thread-wireshark || true
305    rm -rf "${save_file}" || true
306    curl -L "${download_url}" -o "${save_file}"
307    tar -C /tmp -xvzf "${save_file}"
308
309    LD_LIBRARY_PATH=/tmp/thread-wireshark /tmp/thread-wireshark/tshark -v
310    LD_LIBRARY_PATH=/tmp/thread-wireshark /tmp/thread-wireshark/dumpcap -v
311    rm -rf "${save_file}"
312}
313
314do_build_otbr_docker()
315{
316    echo "Building OTBR Docker ..."
317    local otdir
318    local otbrdir
319    local otbr_options=(
320        "-DOT_ANYCAST_LOCATOR=ON"
321        "-DOT_COVERAGE=ON"
322        "-DOT_DNS_CLIENT=ON"
323        "-DOT_DUA=ON"
324        "-DOT_MLR=ON"
325        "-DOT_NETDATA_PUBLISHER=ON"
326        "-DOT_SLAAC=ON"
327        "-DOT_SRP_CLIENT=ON"
328        "-DOT_FULL_LOGS=ON"
329        "-DOT_UPTIME=ON"
330        "-DOTBR_DNS_UPSTREAM_QUERY=ON"
331        "-DOTBR_DUA_ROUTING=ON"
332    )
333    local args=(
334        "BORDER_ROUTING=${BORDER_ROUTING}"
335        "INFRA_IF_NAME=eth0"
336        "BACKBONE_ROUTER=1"
337        "REFERENCE_DEVICE=1"
338        "OT_BACKBONE_CI=1"
339        "NAT64=${NAT64}"
340        "NAT64_SERVICE=${NAT64_SERVICE}"
341        "DNS64=${NAT64}"
342        "REST_API=0"
343        "WEB_GUI=0"
344        "MDNS=${OTBR_MDNS:-mDNSResponder}"
345    )
346
347    if [[ ${NAT64} != 1 ]]; then
348        # 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.
349        otbr_options+=("-DCMAKE_CXX_FLAGS='-DOPENTHREAD_CONFIG_DNSSD_SERVER_BIND_UNSPECIFIED_NETIF=1'")
350    fi
351
352    if [[ ${TREL} == 1 ]]; then
353        otbr_options+=("-DOTBR_TREL=ON")
354    else
355        otbr_options+=("-DOTBR_TREL=OFF")
356    fi
357
358    local otbr_docker_image=${OTBR_DOCKER_IMAGE:-otbr-ot12-backbone-ci}
359    local docker_build_args=()
360
361    for arg in "${args[@]}"; do
362        docker_build_args+=("--build-arg" "$arg")
363    done
364
365    otbrdir=$(mktemp -d -t otbr_XXXXXX)
366    otdir=$(pwd)
367
368    (
369        if [[ -z ${LOCAL_OTBR_DIR} ]]; then
370            ./script/git-tool clone https://github.com/openthread/ot-br-posix.git --depth 1 "${otbrdir}"
371        else
372            rsync -r \
373                --exclude=third_party/openthread/repo \
374                --exclude=.git \
375                --exclude=build \
376                "${LOCAL_OTBR_DIR}/." \
377                "${otbrdir}"
378        fi
379
380        cd "${otbrdir}"
381        rm -rf third_party/openthread/repo
382        rsync -r \
383            --exclude=build \
384            "${otdir}/." \
385            third_party/openthread/repo
386        rm -rf .git
387
388        docker build -t "${otbr_docker_image}" -f etc/docker/Dockerfile . \
389            "${docker_build_args[@]}" \
390            --build-arg OTBR_OPTIONS="${otbr_options[*]}"
391    )
392
393    rm -rf "${otbrdir}"
394}
395
396do_pktverify()
397{
398    ./tests/scripts/thread-cert/pktverify/verify.py "$1"
399}
400
401ot_exec_expect_script()
402{
403    local log_file="tmp/log_expect"
404
405    for script in "$@"; do
406        echo -e "\n${OT_COLOR_PASS}EXEC${OT_COLOR_NONE} ${script}"
407        sudo killall ot-rcp || true
408        sudo killall ot-cli || true
409        sudo killall ot-cli-ftd || true
410        sudo killall ot-cli-mtd || true
411        sudo rm -rf tmp
412        mkdir tmp
413        {
414            if [[ ${OT_NATIVE_IP} == 1 ]]; then
415                sudo -E expect -df "${script}" 2>"${log_file}"
416            else
417                expect -df "${script}" 2>"${log_file}"
418            fi
419        } || {
420            local EXIT_CODE=$?
421
422            # The exit status 77 for skipping is inherited from automake's test driver for script-based testsuites
423            if [[ ${EXIT_CODE} == 77 ]]; then
424                echo -e "\n${OT_COLOR_SKIP}SKIP${OT_COLOR_NONE} ${script}"
425                return 0
426            else
427                echo -e "\n${OT_COLOR_FAIL}FAIL${OT_COLOR_NONE} ${script}"
428                cat "${log_file}" >&2
429                return "${EXIT_CODE}"
430            fi
431        }
432        echo -e "\n${OT_COLOR_PASS}PASS${OT_COLOR_NONE} ${script}"
433        if [[ ${VERBOSE} == 1 ]]; then
434            cat "${log_file}" >&2
435        fi
436    done
437}
438
439do_expect()
440{
441    local test_patterns
442
443    if [[ ${OT_NODE_TYPE} == rcp* ]]; then
444        if [[ ${OT_NATIVE_IP} == 1 ]]; then
445            test_patterns=(-name 'tun-*.exp')
446        else
447            test_patterns=(-name 'posix-*.exp' -o -name 'cli-*.exp')
448            if [[ ${THREAD_VERSION} != "1.1" ]]; then
449                test_patterns+=(-o -name 'v1_2-*.exp')
450            fi
451        fi
452    else
453        test_patterns=(-name 'cli-*.exp' -o -name 'simulation-*.exp' -o -name 'cli_non_rcp-*.exp')
454    fi
455
456    if [[ $# != 0 ]]; then
457        ot_exec_expect_script "$@"
458    else
459        export OT_COLOR_PASS OT_COLOR_FAIL OT_COLOR_SKIP OT_COLOR_NONE OT_NATIVE_IP VERBOSE
460        export -f ot_exec_expect_script
461
462        find tests/scripts/expect -type f -perm "$([[ $OSTYPE == darwin* ]] && echo '+' || echo '/')"111 \( "${test_patterns[@]}" \) -exec bash -c 'set -euo pipefail;ot_exec_expect_script "$@"' _ {} +
463    fi
464
465    exit 0
466}
467
468print_usage()
469{
470    echo "USAGE: [ENVIRONMENTS] $0 COMMANDS
471
472ENVIRONMENTS:
473    OT_NODE_TYPE    'cli' for CLI simulation, 'ncp' for NCP simulation.
474                    'rcp' or 'rcp-cli' for CLI on POSIX platform.
475                    'rcp-ncp' for NCP on POSIX platform.
476                    The default is 'cli'.
477    OT_NATIVE_IP    1 to enable platform UDP and netif on POSIX platform. The default is 0.
478    OT_BUILDDIR     The output directory for cmake build. By default the directory is './build'. For example,
479                    'OT_BUILDDIR=\${PWD}/my_awesome_build ./script/test clean build'.
480    VERBOSE         1 to build or test verbosely. The default is 0.
481    VIRTUAL_TIME    1 for virtual time, otherwise real time. The default value is 0 when running expect tests,
482                    otherwise default value is 1.
483    THREAD_VERSION  1.1 for Thread 1.1 stack, 1.3 for Thread 1.3 stack. The default is 1.3.
484    INTER_OP        1 to build 1.1 together. Only works when THREAD_VERSION is 1.3. The default is 0.
485    INTER_OP_BBR    1 to build bbr version together. Only works when THREAD_VERSION is 1.3. The default is 1.
486
487COMMANDS:
488    clean           Clean built files to prepare for new build.
489    build           Build project for running tests. This can be used to rebuild the project for changes.
490    cert            Run a single thread-cert test. ENVIRONMENTS should be the same as those given to build or update.
491    cert_suite      Run a batch of thread-cert tests and summarize the test results. Only echo logs for failing tests.
492    unit            Run all the unit tests. This should be called after simulation is built.
493    expect          Run expect tests.
494    help            Print this help.
495
496EXAMPLES:
497    # Test CLI with default settings
498    $0 clean build cert tests/scripts/thread-cert/Cert_5_1_01_RouterAttach.py
499    $0 cert tests/scripts/thread-cert/Cert_5_1_02_ChildAddressTimeout.py
500
501    # Test NCP with default settings
502    $0 clean build cert tests/scripts/thread-cert/Cert_5_1_01_RouterAttach.py
503    $0 cert tests/scripts/thread-cert/Cert_5_1_02_ChildAddressTimeout.py
504
505    # Test CLI with radio only
506    $0 clean build cert tests/scripts/thread-cert/Cert_5_1_01_RouterAttach.py
507    $0 cert tests/scripts/thread-cert/Cert_5_1_02_ChildAddressTimeout.py
508
509    # Test CLI with real time
510    VIRTUAL_TIME=0 $0 clean build cert tests/scripts/thread-cert/Cert_5_1_01_RouterAttach.py
511    VIRTUAL_TIME=0 $0 cert tests/scripts/thread-cert/Cert_5_1_02_ChildAddressTimeout.py
512
513    # Test Thread 1.1 CLI with real time
514    THREAD_VERSION=1.1 VIRTUAL_TIME=0 $0 clean build cert tests/scripts/thread-cert/Cert_5_1_01_RouterAttach.py
515    THREAD_VERSION=1.1 VIRTUAL_TIME=0 $0 cert tests/scripts/thread-cert/Cert_5_1_02_ChildAddressTimeout.py
516
517    # Test Thread 1.3 with real time, use 'INTER_OP=1' when the case needs both versions.
518    VIRTUAL_TIME=0 $0 clean build cert tests/scripts/thread-cert/v1_2_test_enhanced_keep_alive.py
519    INTER_OP=1 VIRTUAL_TIME=0 $0 clean build cert tests/scripts/thread-cert/v1_2_router_5_1_1.py
520    INTER_OP=1 VIRTUAL_TIME=0 $0 clean build cert_suite tests/scripts/thread-cert/v1_2_*
521
522    # Run a single expect test
523    $0 clean build expect tests/scripts/expect/cli-log-level.exp
524
525    # Run all expect tests
526    $0 clean build expect
527    "
528
529    exit "$1"
530}
531
532do_prepare_coredump_upload()
533{
534    echo "$OT_COREDUMP_DIR/corefile-%e-%p-%t" | sudo tee /proc/sys/kernel/core_pattern
535    rm -rf "$OT_COREDUMP_DIR"
536    mkdir -p "$OT_COREDUMP_DIR"
537}
538
539do_copy_so_lib()
540{
541    mkdir -p "$OT_COREDUMP_DIR/so-lib"
542    cp /lib/x86_64-linux-gnu/libgcc_s.so.1 "$OT_COREDUMP_DIR/so-lib"
543    cp /lib/x86_64-linux-gnu/libc.so.6 "$OT_COREDUMP_DIR/so-lib"
544    cp /lib64/ld-linux-x86-64.so.2 "$OT_COREDUMP_DIR/so-lib"
545}
546
547do_check_crash()
548{
549    shopt -s nullglob
550
551    # Scan core dumps and collect binaries which crashed
552    declare -A bin_list=([dummy]='')
553    for f in "$OT_COREDUMP_DIR"/core*; do
554        bin=$(file "$f" | grep -E -o "execfn: '(.*')," | sed -r "s/execfn: '(.*)',/\1/")
555        bin_list[$bin]=''
556    done
557
558    for key in "${!bin_list[@]}"; do
559        if [ "$key" != "dummy" ]; then
560            # Add postfix for binaries to avoid conflicts caused by different Thread version
561            postfix=""
562            if [[ $key =~ openthread-(simulation|posix)-([0-9]\.[0-9]) ]]; then
563                postfix="-$(echo "$key" | sed -r "s/.*openthread-(simulation|posix)-([0-9]\.[0-9]).*/\2/")"
564            fi
565            bin_name=$(basename "$key")
566            cp "$key" "$OT_COREDUMP_DIR"/"$bin_name""$postfix"
567        fi
568    done
569
570    # echo 1 and copy so libs if crash found, echo 0 otherwise
571    [[ ${#bin_list[@]} -gt 1 ]] && (
572        echo 1
573        do_copy_so_lib
574    ) || echo 0
575}
576
577do_generate_coverage()
578{
579    mkdir -p tmp/
580    sudo chmod 777 tmp/
581    rm -f tmp/coverage.lcov
582    if [[ $1 == "llvm" ]]; then
583        local llvm_gcov
584        llvm_gcov="$(mktemp -d)/llvm-gcov"
585        echo '#!/bin/bash' >>"$llvm_gcov"
586        echo 'exec llvm-cov gcov "$@"' >>"$llvm_gcov"
587        chmod +x "$llvm_gcov"
588        lcov --gcov-tool "$llvm_gcov" --directory . --capture --output-file tmp/coverage.info
589    else
590        ./script/gcda-tool collect
591        ./script/gcda-tool install
592
593        lcov --directory . --capture --output-file tmp/coverage.info
594    fi
595    lcov --list tmp/coverage.info
596    lcov --extract tmp/coverage.info "$PWD/src/core/common/message.cpp" | c++filt
597}
598
599do_combine_coverage()
600{
601    ls -R coverage/
602
603    readarray -d '' files < <(find coverage/ -type f -name 'coverage*.info' -print0)
604
605    local args=()
606    for i in "${files[@]}"; do
607        args+=('-a')
608        args+=("$i")
609    done
610    lcov "${args[@]}" -o final.info
611}
612
613envsetup()
614{
615    export THREAD_VERSION
616
617    if [[ ${OT_NODE_TYPE} == rcp* ]]; then
618        export RADIO_DEVICE="${OT_BUILDDIR}/openthread-simulation-${THREAD_VERSION}/examples/apps/ncp/ot-rcp"
619        export OT_CLI_PATH="${OT_BUILDDIR}/openthread-posix-${THREAD_VERSION}/src/posix/ot-cli"
620
621        if [[ ${THREAD_VERSION} != "1.1" ]]; then
622            export RADIO_DEVICE_1_1="${OT_BUILDDIR}/openthread-simulation-1.1/examples/apps/ncp/ot-rcp"
623            export OT_CLI_PATH_1_1="${OT_BUILDDIR}/openthread-posix-1.1/src/posix/ot-cli"
624            export OT_CLI_PATH_BBR="${OT_BUILDDIR}/openthread-posix-1.3-bbr/src/posix/ot-cli"
625        fi
626    fi
627
628    export OT_SIMULATION_APPS="${OT_BUILDDIR}/openthread-simulation-${THREAD_VERSION}/examples/apps"
629    export OT_POSIX_APPS="${OT_BUILDDIR}/openthread-posix-${THREAD_VERSION}/src/posix"
630
631    if [[ ! ${VIRTUAL_TIME+x} ]]; then
632        # All expect tests only works in real time mode.
633        VIRTUAL_TIME=1
634        for arg in "$@"; do
635            if [[ $arg == expect ]]; then
636                VIRTUAL_TIME=0
637                break
638            fi
639        done
640    fi
641
642    readonly VIRTUAL_TIME
643    export OT_NODE_TYPE VIRTUAL_TIME
644
645    # CMake always works in verbose mode if VERBOSE exists in environments.
646    if [[ ${VERBOSE} == 1 ]]; then
647        export VERBOSE
648    else
649        export -n VERBOSE
650    fi
651
652    if [[ ${OT_OPTIONS+x} ]]; then
653        read -r -a ot_extra_options <<<"${OT_OPTIONS}"
654    else
655        ot_extra_options=()
656    fi
657}
658
659main()
660{
661    envsetup "$@"
662
663    if [[ -z ${1-} ]]; then
664        print_usage 1
665    fi
666
667    [[ ${VIRTUAL_TIME} == 1 ]] && echo "Using virtual time" || echo "Using real time"
668    [[ ${THREAD_VERSION} != "1.1" ]] && echo "Using Thread 1.3 stack" || echo "Using Thread 1.1 stack"
669
670    while [[ $# != 0 ]]; do
671        case "$1" in
672            clean)
673                do_clean
674                ;;
675            build)
676                do_build
677                ;;
678            cert)
679                shift
680                do_cert "$@"
681                shift $#
682                ;;
683            cert_suite)
684                shift
685                do_cert_suite "$@"
686                shift $#
687                ;;
688            get_thread_wireshark)
689                do_get_thread_wireshark
690                ;;
691            build_otbr_docker)
692                do_build_otbr_docker
693                ;;
694            pktverify)
695                shift
696                do_pktverify "$1"
697                ;;
698            unit)
699                do_unit
700                ;;
701            help)
702                print_usage
703                ;;
704            package)
705                ./script/package "${ot_extra_options[@]}"
706                ;;
707            expect)
708                shift
709                do_expect "$@"
710                ;;
711            prepare_coredump_upload)
712                do_prepare_coredump_upload
713                ;;
714            check_crash)
715                do_check_crash
716                ;;
717            generate_coverage)
718                shift
719                do_generate_coverage "$1"
720                ;;
721            combine_coverage)
722                do_combine_coverage
723                ;;
724            *)
725                echo
726                echo -e "${OT_COLOR_FAIL}Warning:${OT_COLOR_NONE} Ignoring: '$1'"
727                ;;
728        esac
729        shift
730    done
731}
732
733main "$@"
734