xref: /aosp_15_r20/external/ot-br-posix/tests/dbus/test-client (revision 4a64e381480ef79f0532b2421e44e6ee336b8e0d)
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