1#!/bin/bash 2# 3# Copyright (c) 2020, 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 build and run otbr dbus server 30# 31 32set -euxo pipefail 33 34OTBR_DBUS_SERVER_CONF=otbr-test-agent.conf 35readonly OTBR_DBUS_SERVER_CONF 36 37on_exit() 38{ 39 local status=$? 40 41 sudo systemctl stop test-otbr-agent || true 42 if [[ -v LEADER_PID ]]; then 43 kill "$LEADER_PID" || true 44 fi 45 if [[ -v CHILD_PID ]]; then 46 kill "$CHILD_PID" || true 47 fi 48 sudo killall dbus-monitor || true 49 sudo rm "/etc/dbus-1/system.d/${OTBR_DBUS_SERVER_CONF}" || true 50 51 sed -n "/$TEST_HELLO/,\$p" /var/log/syslog | grep 'ot-cli\|otbr' 52 53 return "${status}" 54} 55 56ot_ctl() 57{ 58 sudo "${CMAKE_BINARY_DIR}"/third_party/openthread/repo/src/posix/ot-ctl "$@" 59} 60 61otbr_factoryreset() 62{ 63 ot_ctl factoryreset 64 timeout 2 bash -c "while ! ot_ctl state; do sleep 1; done" 65} 66 67scan_meshcop_service() 68{ 69 if command -v dns-sd; then 70 timeout 5 dns-sd -Z _meshcop._udp local. || true 71 else 72 avahi-browse -aprt || true 73 fi 74} 75 76update_meshcop_txt_and_check() 77{ 78 sudo gdbus call --system --dest io.openthread.BorderRouter.wpan0 --method=io.openthread.BorderRouter.UpdateVendorMeshCopTxtEntries --object-path /io/openthread/BorderRouter/wpan0 "[('nn',[97])]" || true 79 sleep 5 80 service="$(scan_meshcop_service)" 81 grep --binary-files=text "nn=OpenThread" <<<"${service}" 82 83 sudo gdbus call --system --dest io.openthread.BorderRouter.wpan0 --method=io.openthread.BorderRouter.UpdateVendorMeshCopTxtEntries --object-path /io/openthread/BorderRouter/wpan0 "[('vn',[118,101,110,100,111,114])]" 84 sleep 5 85 service="$(scan_meshcop_service)" 86 grep --binary-files=text "vn=vendor" <<<"${service}" 87 88 sudo gdbus call --system --dest io.openthread.BorderRouter.wpan0 --method=io.openthread.BorderRouter.UpdateVendorMeshCopTxtEntries --object-path /io/openthread/BorderRouter/wpan0 "[]" 89 sleep 5 90 service="$(scan_meshcop_service)" 91 grep --binary-files=text "vn=OpenThread" <<<"${service}" 92 93 sudo gdbus call --system --dest io.openthread.BorderRouter.wpan0 --method=io.openthread.BorderRouter.UpdateVendorMeshCopTxtEntries --object-path /io/openthread/BorderRouter/wpan0 "[('A',[97,98,99]),('B',[49,50])]" 94 sleep 5 95 service="$(scan_meshcop_service)" 96 grep --binary-files=text "A=abc" <<<"${service}" 97 grep --binary-files=text "B=12" <<<"${service}" 98 99 sudo gdbus call --system --dest io.openthread.BorderRouter.wpan0 --method=io.openthread.BorderRouter.Reset --object-path /io/openthread/BorderRouter/wpan0 100 sleep 5 101 service="$(scan_meshcop_service)" 102 grep --binary-files=text "A=abc" <<<"${service}" 103 grep --binary-files=text "B=12" <<<"${service}" 104 105 sudo gdbus call --system --dest io.openthread.BorderRouter.wpan0 --method=io.openthread.BorderRouter.UpdateVendorMeshCopTxtEntries --object-path /io/openthread/BorderRouter/wpan0 "[('A',[97,99]),('B',[49,50])]" 106 sleep 5 107 service="$(scan_meshcop_service)" 108 grep --binary-files=text "A=ac" <<<"${service}" 109 grep --binary-files=text "B=12" <<<"${service}" 110} 111 112test_get_properties() 113{ 114 local ot_version 115 local rcp_version 116 local thread_version 117 118 ot_version=$(ot_ctl version | grep -oE '^OPENTHREAD.*$' | tr -d '\r\n') 119 rcp_version=$(ot_ctl rcp version | grep -oE '^OPENTHREAD.*$' | tr -d '\r\n') 120 thread_version=$(ot_ctl thread version | grep -oE '^[0-9]+' | tr -d '\r\n') 121 122 local property_names="array:string:" 123 property_names+="OtHostVersion," 124 property_names+="OtRcpVersion," 125 property_names+="ThreadVersion," 126 property_names+="Uptime," 127 property_names+="RadioCoexMetrics," 128 property_names+="RadioSpinelMetrics," 129 property_names+="RcpInterfaceMetrics" 130 local result_pattern="\s+variant\s+string\s+\"${ot_version}\"" 131 result_pattern+="\s+variant\s+string\s+\"${rcp_version}\"" 132 result_pattern+="\s+variant\s+uint16\s+${thread_version}" 133 result_pattern+="\s+variant\s+uint64\s+\d+" # Uptime 134 result_pattern+="\s+variant\s+struct\s+{(\s+uint32\s+\d+){18}\s+boolean\s+(true|false)\s+}" # RadioCoexMetrics 135 result_pattern+="\s+variant\s+struct\s+{(\s+uint32\s+\d+){4}\s+}" # RadioSpinelMetrics 136 result_pattern+="\s+variant\s+struct\s+{\s+byte\s+\d+(\s+uint64\s+\d+){7}\s+}" # RcpInterfaceMetrics 137 sudo dbus-send --system --dest=io.openthread.BorderRouter.wpan0 --print-reply \ 138 /io/openthread/BorderRouter/wpan0 \ 139 io.openthread.BorderRouter.GetProperties \ 140 "${property_names}" \ 141 | grep -oPz "${result_pattern}" 142} 143 144otbr_agent_service_start() 145{ 146 local -r EXIT_CODE_SHOULD_RESTART=7 147 148 sudo systemd-run --collect --no-ask-password -u test-otbr-agent -p "RestartForceExitStatus=$EXIT_CODE_SHOULD_RESTART" "${CMAKE_BINARY_DIR}"/src/agent/otbr-agent -d7 -I wpan0 -B lo "spinel+hdlc+forkpty://$(command -v ot-rcp)?forkpty-arg=1" 149 timeout 2 bash -c "while ! ot_ctl state; do sleep 1; done" 150} 151 152suite_setup() 153{ 154 TEST_HELLO="$(basename "$0") started at $(date +%s)" 155 logger "$TEST_HELLO" 156 [[ -f /etc/dbus-1/system.d/"${OTBR_DBUS_SERVER_CONF}" ]] || { 157 local CONFIG_FILE_PATH="third_party/openthread/repo/src/posix/platform" 158 mkdir -p "${PWD}/${CONFIG_FILE_PATH}" && cp "${PROJECT_SOURCE_DIR}/${CONFIG_FILE_PATH}/openthread.conf.example" "${PWD}/${CONFIG_FILE_PATH}" 159 160 sudo rm -rf tmp 161 sudo install -m 644 "${CMAKE_BINARY_DIR}"/src/agent/otbr-agent.conf /etc/dbus-1/system.d/"${OTBR_DBUS_SERVER_CONF}" 162 sudo service dbus reload 163 } 164 trap on_exit EXIT 165 166 sudo systemctl start avahi-daemon 167 168 export -f ot_ctl 169} 170 171test_ready_signal() 172{ 173 # Because we do want to run the command as root but redirect as the normal user. 174 # shellcheck disable=SC2024 175 sudo expect <<EOF 176spawn dbus-monitor --system path=/io/openthread/BorderRouter/wpan0,member=Ready 177set dbus_monitor \$spawn_id 178spawn ${CMAKE_BINARY_DIR}/src/agent/otbr-agent -d7 -I wpan0 -B lo spinel+hdlc+forkpty://$(command -v ot-rcp)?forkpty-arg=1 179set spawn_id \$dbus_monitor 180expect { 181 "member=Ready" { exit } 182 timeout { error "Failed to find Ready signal\n" } 183} 184EOF 185 timeout 2 bash -c "while pidof ot-rcp; do logger -t otbr-test-dbus-client; sleep 1; done" 186} 187 188main() 189{ 190 suite_setup 191 192 sudo "${CMAKE_BINARY_DIR}"/src/agent/otbr-agent -d7 -I wpan0 --radio-version "spinel+hdlc+forkpty://$(command -v ot-rcp)?forkpty-arg=1" | grep "OPENTHREAD" 193 194 test_ready_signal 195 196 otbr_agent_service_start 197 198 otbr_factoryreset 199 200 test_get_properties 201 202 ot_ctl ifconfig up 203 ot_ctl thread start 204 205 update_meshcop_txt_and_check 206 207 otbr_factoryreset 208 209 sudo dbus-send --system --dest=io.openthread.BorderRouter.wpan0 \ 210 --type=method_call --print-reply /io/openthread/BorderRouter/wpan0 \ 211 org.freedesktop.DBus.Introspectable.Introspect | grep JoinerStart 212 (sudo dbus-send --system --dest=io.openthread.BorderRouter.wpan0 \ 213 --type=method_call --print-reply /io/openthread/BorderRouter/wpan0 \ 214 io.openthread.BorderRouter.JoinerStart \ 215 string:ABCDEF string:mock string:mock \ 216 string:mock string:mock string:mock 2>&1 || true) | grep NotFound 217 218 # Verify Eui64 property. 0x18b4300000000001 = 1780100529276321793 219 sudo dbus-send --system --dest=io.openthread.BorderRouter.wpan0 --print-reply /io/openthread/BorderRouter/wpan0 org.freedesktop.DBus.Properties.Get string:io.openthread.BorderRouter string:Eui64 \ 220 | grep '1780100529276321793' 221 222 # The ot-cli-ftd node is used to test Thread attach. 223 expect <<EOF & 224spawn ot-cli-ftd 3 225send "dataset init new\r\n" 226expect "Done" 227send "dataset panid 0x7890\r\n" 228expect "Done" 229send "dataset networkname Test1\r\n" 230expect "Done" 231send "dataset channel 15\r\n" 232expect "Done" 233send "dataset commit active\r\n" 234expect "Done" 235send "ifconfig up\r\n" 236expect "Done" 237send "thread start\r\n" 238expect "Done" 239sleep 12 240send "state\r\n" 241expect "leader" 242expect "Done" 243send "commissioner start\r\n" 244expect "Commissioner: active" 245send "commissioner joiner add * ABCDEF\r\n" 246expect "Done" 247expect "Joiner end" 248send "commissioner stop\r\n" 249set timeout -1 250expect eof 251EOF 252 LEADER_PID=$! 253 254 # The ot-cli-mtd node is used to test the child and neighbor table. 255 expect <<EOF & 256spawn ot-cli-mtd 2 257send "dataset clear" 258expect "Done" 259send "dataset panid 0x3456\r\n" 260expect "Done" 261send "dataset networkkey 00112233445566778899aabbccddeeff\r\n" 262expect "Done" 263send "dataset networkname Test\r\n" 264expect "Done" 265send "dataset channel 11\r\n" 266expect "Done" 267send "dataset commit active\r\n" 268expect "Done" 269send "ifconfig up\r\n" 270expect "Done" 271send "thread start\r\n" 272expect "Done" 273set timeout -1 274expect eof 275EOF 276 CHILD_PID=$! 277 278 sleep 12 279 ot_ctl routerselectionjitter 1 280 sudo dbus-send --system --dest=io.openthread.BorderRouter.wpan0 \ 281 --type=method_call --print-reply /io/openthread/BorderRouter/wpan0 \ 282 io.openthread.BorderRouter.JoinerStart \ 283 string:ABCDEF string:mock string:mock \ 284 string:mock string:mock string:mock 285 sleep 10 286 ot_ctl state | grep router 287 288 result_pattern="array\s+\[\s+variant\s+array\s+\[\s+struct\s+{\s+" 289 result_pattern+="uint64\s+\d+\s+" 290 result_pattern+="uint32\s+\d+\s+" 291 result_pattern+="uint16\s+\d+\s+" 292 result_pattern+="uint32\s+\d+\s+" 293 result_pattern+="uint32\s+\d+\s+" 294 result_pattern+="byte\s+\d+\s+" 295 result_pattern+="byte\s+\d+\s+" 296 result_pattern+="byte\s+\d+\s+" 297 result_pattern+="uint16\s+\d+\s+" 298 result_pattern+="uint16\s+\d+\s+" 299 result_pattern+="uint16\s+\d+\s+" 300 result_pattern+="boolean\s+(true|false)\s+" 301 result_pattern+="boolean\s+(true|false)\s+" 302 result_pattern+="boolean\s+(true|false)\s+" 303 result_pattern+="boolean\s+(true|false)\s+" 304 result_pattern+="}\s+\]\s+\]" 305 sudo dbus-send --system --dest=io.openthread.BorderRouter.wpan0 --print-reply \ 306 /io/openthread/BorderRouter/wpan0 \ 307 io.openthread.BorderRouter.GetProperties \ 308 "array:string:NeighborTable" \ 309 | grep -oPz "${result_pattern}" 310 311 sudo dbus-send --system --dest=io.openthread.BorderRouter.wpan0 \ 312 --type=method_call --print-reply /io/openthread/BorderRouter/wpan0 \ 313 io.openthread.BorderRouter.Detach 314 ot_ctl state | grep disabled 315 316 otbr_factoryreset 317 318 sudo "${CMAKE_BINARY_DIR}"/tests/dbus/otbr-test-dbus-client 319 320 otbr_factoryreset 321 322 sudo dbus-send --system --dest=io.openthread.BorderRouter.wpan0 \ 323 --type=method_call --print-reply /io/openthread/BorderRouter/wpan0 \ 324 io.openthread.BorderRouter.Attach \ 325 array:byte: \ 326 uint16:0xffff \ 327 string:OpenThread \ 328 uint64:0xffffffffffffffff \ 329 array:byte: \ 330 uint32:0xffffffff 331 332 local dataset="0x0e,0x08,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x03,0x00,0x00,0x18," 333 dataset+="0x35,0x06,0x00,0x04,0x00,0x1f,0xff,0xe0,0x02,0x08,0xef,0x18,0xe6,0xa1,0xf3,0xd6," 334 dataset+="0x86,0xc4,0x07,0x08,0xfd,0x16,0x72,0x24,0xc2,0x4e,0x16,0x00,0x05,0x10,0xbe,0x3b," 335 dataset+="0xd2,0x44,0xae,0x6d,0x99,0x70,0x20,0xa8,0x82,0xa2,0x4a,0x80,0x40,0xe2,0x03,0x0f," 336 dataset+="0x4f,0x70,0x65,0x6e,0x54,0x68,0x72,0x65,0x61,0x64,0x2d,0x30,0x36,0x62,0x37,0x01," 337 dataset+="0x02,0x06,0xb7,0x04,0x10,0xf9,0xc9,0x1b,0x11,0x45,0x02,0x54,0x67,0xbf,0x11,0xed," 338 dataset+="0xf9,0x01,0x1a,0x58,0x12,0x0c,0x04,0x02,0xa0,0xff,0xf8" 339 340 sudo dbus-send --system --dest=io.openthread.BorderRouter.wpan0 \ 341 --type=method_call --print-reply /io/openthread/BorderRouter/wpan0 \ 342 io.openthread.BorderRouter.AttachAllNodesTo \ 343 "array:byte:${dataset}" \ 344 | grep "int64 300000" 345 346 ot_ctl dataset pending | grep "Active Timestamp: 2" 347 348 sleep 310 349 350 ot_ctl dataset active | grep "Active Timestamp: 2" 351 ot_ctl networkkey | grep be3bd244ae6d997020a882a24a8040e2 352 353 otbr_factoryreset 354 355 sudo dbus-send --system --dest=io.openthread.BorderRouter.wpan0 \ 356 --type=method_call --print-reply /io/openthread/BorderRouter/wpan0 \ 357 io.openthread.BorderRouter.AttachAllNodesTo \ 358 "array:byte:${dataset}" \ 359 | grep "int64 0" 360 ot_ctl state | grep "leader" 361 362 ot_ctl factoryreset 363 sleep 1 364 365 sudo dbus-send --system --dest=io.openthread.BorderRouter.wpan0 \ 366 --type=method_call --print-reply /io/openthread/BorderRouter/wpan0 \ 367 io.openthread.BorderRouter.Attach \ 368 array:byte: \ 369 uint16:0xffff \ 370 string:OpenThread \ 371 uint64:0xffffffffffffffff \ 372 array:byte: \ 373 uint32:0xffffffff 374 375 ot_ctl state | grep "leader" 376 ot_ctl thread stop 377 ot_ctl state | grep "disabled" 378 ot_ctl dataset active | grep "Done" 379 380 sudo dbus-send --system --dest=io.openthread.BorderRouter.wpan0 \ 381 --type=method_call --print-reply /io/openthread/BorderRouter/wpan0 \ 382 io.openthread.BorderRouter.AttachAllNodesTo \ 383 "array:byte:${dataset}" \ 384 | grep "int64 300000" 385 386 ot_ctl state | grep "leader" 387 ot_ctl dataset pending | grep "Active Timestamp: 2" 388 389 sleep 310 390 391 ot_ctl dataset active | grep "Active Timestamp: 2" 392 ot_ctl networkkey | grep be3bd244ae6d997020a882a24a8040e2 393 394 ot_ctl dataset init new 395 ot_ctl dataset commit pending 396 397 sudo dbus-send --system --dest=io.openthread.BorderRouter.wpan0 \ 398 --type=method_call --print-reply /io/openthread/BorderRouter/wpan0 \ 399 io.openthread.BorderRouter.LeaveNetwork 400 sleep 10 401 402 ot_ctl state | grep disabled 403 ot_ctl dataset active | grep NotFound 404 ot_ctl dataset pending | grep NotFound 405} 406 407main "$@" 408