1#!/bin/bash 2# 3# Copyright (c) 2024, 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# Test basic functionality of otbr-agent under NCP mode. 30# 31# Usage: 32# ./ncp_mode 33set -euxo pipefail 34 35SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" 36readonly SCRIPT_DIR 37EXPECT_SCRIPT_DIR="${SCRIPT_DIR}/expect" 38readonly EXPECT_SCRIPT_DIR 39 40#--------------------------------------- 41# Configurations 42#--------------------------------------- 43OT_CLI="${OT_CLI:-ot-cli-ftd}" 44readonly OT_CLI 45 46OT_NCP="${OT_NCP:-ot-ncp-ftd}" 47readonly OT_NCP 48 49OTBR_DOCKER_IMAGE="${OTBR_DOCKER_IMAGE:-otbr-ncp}" 50readonly OTBR_DOCKER_IMAGE 51 52ABS_TOP_BUILDDIR="$(cd "${top_builddir:-"${SCRIPT_DIR}"/../../}" && pwd)" 53readonly ABS_TOP_BUILDDIR 54 55ABS_TOP_SRCDIR="$(cd "${top_srcdir:-"${SCRIPT_DIR}"/../../}" && pwd)" 56readonly ABS_TOP_SRCDIR 57 58ABS_TOP_OT_SRCDIR="${ABS_TOP_SRCDIR}/third_party/openthread/repo" 59readonly ABS_TOP_OT_SRCDIR 60 61ABS_TOP_OT_BUILDDIR="${ABS_TOP_BUILDDIR}/../simulation" 62readonly ABS_TOP_BUILDDIR 63 64OTBR_COLOR_PASS='\033[0;32m' 65readonly OTBR_COLOR_PASS 66 67OTBR_COLOR_FAIL='\033[0;31m' 68readonly OTBR_COLOR_FAIL 69 70OTBR_COLOR_NONE='\033[0m' 71readonly OTBR_COLOR_NONE 72 73readonly OTBR_VERBOSE="${OTBR_VERBOSE:-0}" 74 75#---------------------------------------- 76# Helper functions 77#---------------------------------------- 78die() 79{ 80 exit_message="$*" 81 echo " *** ERROR: $*" 82 exit 1 83} 84 85exists_or_die() 86{ 87 [[ -f $1 ]] || die "Missing file: $1" 88} 89 90executable_or_die() 91{ 92 [[ -x $1 ]] || die "Missing executable: $1" 93} 94 95write_syslog() 96{ 97 logger -s -p syslog.alert "OTBR_TEST: $*" 98} 99 100#---------------------------------------- 101# Test constants 102#---------------------------------------- 103TEST_BASE=/tmp/test-otbr 104readonly TEST_BASE 105 106OTBR_AGENT=otbr-agent 107readonly OTBR_AGENT 108 109STAGE_DIR="${TEST_BASE}/stage" 110readonly STAGE_DIR 111 112BUILD_DIR="${TEST_BASE}/build" 113readonly BUILD_DIR 114 115OTBR_DBUS_CONF="${ABS_TOP_BUILDDIR}/src/agent/otbr-agent.conf" 116readonly OTBR_DBUS_CONF 117 118OTBR_AGENT_PATH="${ABS_TOP_BUILDDIR}/src/agent/${OTBR_AGENT}" 119readonly OTBR_AGENT_PATH 120 121# The node ids 122LEADER_NODE_ID=1 123readonly LEADER_NODE_ID 124 125# The TUN device for OpenThread border router. 126TUN_NAME=wpan0 127readonly TUN_NAME 128 129#---------------------------------------- 130# Test steps 131#---------------------------------------- 132do_build_ot_simulation() 133{ 134 sudo rm -rf "${ABS_TOP_OT_BUILDDIR}/ncp" 135 sudo rm -rf "${ABS_TOP_OT_BUILDDIR}/cli" 136 OT_CMAKE_BUILD_DIR=${ABS_TOP_OT_BUILDDIR}/ncp "${ABS_TOP_OT_SRCDIR}"/script/cmake-build simulation \ 137 -DOT_MTD=OFF -DOT_RCP=OFF -DOT_APP_CLI=OFF -DOT_APP_RCP=OFF \ 138 -DOT_BORDER_ROUTING=ON -DOT_NCP_INFRA_IF=ON -DOT_SIMULATION_INFRA_IF=OFF \ 139 -DOT_SRP_SERVER=ON -DOT_SRP_ADV_PROXY=ON -DOT_PLATFORM_DNSSD=ON -DOT_SIMULATION_DNSSD=OFF -DOT_NCP_DNSSD=ON \ 140 -DBUILD_TESTING=OFF 141 OT_CMAKE_BUILD_DIR=${ABS_TOP_OT_BUILDDIR}/cli "${ABS_TOP_OT_SRCDIR}"/script/cmake-build simulation \ 142 -DOT_MTD=OFF -DOT_RCP=OFF -DOT_APP_NCP=OFF -DOT_APP_RCP=OFF \ 143 -DOT_BORDER_ROUTING=OFF \ 144 -DBUILD_TESTING=OFF 145} 146 147do_build_otbr_docker() 148{ 149 otbr_docker_options=( 150 "-DOT_THREAD_VERSION=1.4" 151 "-DOTBR_DBUS=ON" 152 "-DOTBR_FEATURE_FLAGS=ON" 153 "-DOTBR_TELEMETRY_DATA_API=ON" 154 "-DOTBR_TREL=ON" 155 "-DOTBR_LINK_METRICS_TELEMETRY=ON" 156 "-DOTBR_SRP_ADVERTISING_PROXY=ON" 157 ) 158 sudo docker build -t "${OTBR_DOCKER_IMAGE}" \ 159 -f ./etc/docker/Dockerfile . \ 160 --build-arg NAT64=0 \ 161 --build-arg NAT64_SERVICE=0 \ 162 --build-arg DNS64=0 \ 163 --build-arg WEB_GUI=0 \ 164 --build-arg REST_API=0 \ 165 --build-arg FIREWALL=0 \ 166 --build-arg OTBR_OPTIONS="${otbr_docker_options[*]}" 167} 168 169setup_infraif() 170{ 171 if ! ip link show backbone1 >/dev/null 2>&1; then 172 echo "Creating backbone1 with Docker..." 173 docker network create --driver bridge --ipv6 --subnet 9101::/64 -o "com.docker.network.bridge.name"="backbone1" backbone1 174 else 175 echo "backbone1 already exists." 176 fi 177 sudo sysctl -w net.ipv6.conf.backbone1.accept_ra=2 178 sudo sysctl -w net.ipv6.conf.backbone1.accept_ra_rt_info_max_plen=64 179} 180 181test_setup() 182{ 183 executable_or_die "${OTBR_AGENT_PATH}" 184 185 # Remove flashes 186 sudo rm -vrf "${TEST_BASE}/tmp" 187 # OPENTHREAD_POSIX_DAEMON_SOCKET_LOCK 188 sudo rm -vf "/tmp/openthread.lock" 189 190 ot_cli=$(find "${ABS_TOP_OT_BUILDDIR}" -name "${OT_CLI}") 191 ot_ncp=$(find "${ABS_TOP_OT_BUILDDIR}" -name "${OT_NCP}") 192 executable_or_die "${ot_cli}" 193 executable_or_die "${ot_ncp}" 194 195 export EXP_OTBR_AGENT_PATH="${OTBR_AGENT_PATH}" 196 export EXP_OT_CLI_PATH="${ot_cli}" 197 export EXP_OT_NCP_PATH="${ot_ncp}" 198 199 # We will be creating a lot of log information 200 # Rotate logs so we have a clean and empty set of logs uncluttered with other stuff 201 if [[ -f /etc/logrotate.conf ]]; then 202 sudo logrotate -f /etc/logrotate.conf || true 203 fi 204 205 # Preparation for otbr-agent 206 exists_or_die "${OTBR_DBUS_CONF}" 207 sudo cp "${OTBR_DBUS_CONF}" /etc/dbus-1/system.d 208 209 write_syslog "AGENT: kill old" 210 sudo killall "${OTBR_AGENT}" || true 211 212 setup_infraif 213 214 # From now on - all exits are TRAPPED 215 # When they occur, we call the function: output_logs'. 216 trap test_teardown EXIT 217} 218 219test_teardown() 220{ 221 # Capture the exit code so we can return it below 222 EXIT_CODE=$? 223 readonly EXIT_CODE 224 write_syslog "EXIT ${EXIT_CODE} - output logs" 225 226 sudo pkill -f "${OTBR_AGENT}" || true 227 sudo pkill -f "${OT_CLI}" || true 228 sudo pkill -f "${OT_NCP}" || true 229 wait 230 231 echo 'clearing all' 232 sudo rm /etc/dbus-1/system.d/otbr-agent.conf || true 233 sudo rm -rf "${STAGE_DIR}" || true 234 sudo rm -rf "${BUILD_DIR}" || true 235 236 exit_message="Test teardown" 237 echo "EXIT ${EXIT_CODE}: MESSAGE: ${exit_message}" 238 exit ${EXIT_CODE} 239} 240 241otbr_exec_expect_script() 242{ 243 local log_file="tmp/log_expect" 244 245 for script in "$@"; do 246 echo -e "\n${OTBR_COLOR_PASS}EXEC${OTBR_COLOR_NONE} ${script}" 247 sudo killall ot-rcp || true 248 sudo killall ot-cli || true 249 sudo killall ot-cli-ftd || true 250 sudo killall ot-cli-mtd || true 251 sudo killall ot-ncp-ftd || true 252 sudo killall ot-ncp-mtd || true 253 sudo rm -rf tmp 254 mkdir tmp 255 { 256 sudo -E expect -df "${script}" 2>"${log_file}" 257 } || { 258 local EXIT_CODE=$? 259 260 echo -e "\n${OTBR_COLOR_FAIL}FAIL${OTBR_COLOR_NONE} ${script}" 261 cat "${log_file}" >&2 262 return "${EXIT_CODE}" 263 } 264 echo -e "\n${OTBR_COLOR_PASS}PASS${OTBR_COLOR_NONE} ${script}" 265 if [[ ${OTBR_VERBOSE} == 1 ]]; then 266 cat "${log_file}" >&2 267 fi 268 done 269} 270 271do_expect() 272{ 273 if [[ $# != 0 ]]; then 274 otbr_exec_expect_script "$@" 275 else 276 mapfile -t test_files < <(find "${EXPECT_SCRIPT_DIR}" -type f -name "ncp_*.exp") 277 otbr_exec_expect_script "${test_files[@]}" || die "ncp expect script failed!" 278 fi 279 280 exit 0 281} 282 283print_usage() 284{ 285 cat <<EOF 286USAGE: $0 COMMAND 287 288COMMAND: 289 build_ot_sim Build simulated ot-cli-ftd and ot-ncp-ftd for testing. 290 build_otbr_docker Build otbr docker image for testing. 291 expect Run expect tests for otbr NCP mode. 292 help Print this help. 293 294EXAMPLES: 295 $0 build_ot_sim build_otbr_docker expect 296EOF 297 exit 0 298} 299 300main() 301{ 302 if [[ $# == 0 ]]; then 303 print_usage 304 fi 305 306 export EXP_TUN_NAME="${TUN_NAME}" 307 export EXP_LEADER_NODE_ID="${LEADER_NODE_ID}" 308 export EXP_OTBR_DOCKER_IMAGE="${OTBR_DOCKER_IMAGE}" 309 310 while [[ $# != 0 ]]; do 311 case "$1" in 312 build_ot_sim) 313 do_build_ot_simulation 314 ;; 315 build_otbr_docker) 316 do_build_otbr_docker 317 ;; 318 expect) 319 shift 320 test_setup 321 do_expect "$@" 322 ;; 323 help) 324 print_usage 325 ;; 326 *) 327 echo 328 echo -e "${OTBR_COLOR_FAIL}Warning:${OTBR_COLOR_NONE} Ignoring: '$1'" 329 ;; 330 esac 331 shift 332 done 333} 334 335main "$@" 336