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