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