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