3 # Copyright (c) 2017, The OpenThread Authors.
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.
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.
29 # Test thread commissioning along with openthread.
32 # ./meshcop # test with latest openthread.
33 # NO_CLEAN=1 ./meshcop # test with existing binaries in ${TEST_BASE}.
36 # Get our starting directory and remember it
37 readonly ORIGIN_PWD="$(pwd)"
38 readonly SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
40 #---------------------------------------
42 #---------------------------------------
43 readonly OT_RCP="ot-rcp"
44 readonly OT_CLI="${OT_CLI:-ot-cli-ftd}"
45 readonly ABS_TOP_BUILDDIR="$(cd "${top_builddir:-"${SCRIPT_DIR}"/../../}" && pwd)"
46 readonly ABS_TOP_SRCDIR="$(cd "${top_srcdir:-"${SCRIPT_DIR}"/../../}" && pwd)"
47 readonly NO_CLEAN="${NO_CLEAN:-1}"
48 readonly IGNORE_INSTALLED="${IGNORE_INSTALLED:-0}"
49 readonly OTBR_USE_WEB_COMMISSIONER="${USE_WEB_COMMISSIONER:-0}"
51 #----------------------------------------
53 #----------------------------------------
54 readonly TEST_BASE=/tmp/test-otbr
56 readonly OTBR_AGENT=otbr-agent
57 readonly OTBR_WEB=otbr-web
58 readonly OT_COMMISSIONER_CLI=commissioner-cli
60 readonly STAGE_DIR="${TEST_BASE}/stage"
61 readonly BUILD_DIR="${TEST_BASE}/build"
62 readonly OTBR_PSKC_PATH="${ABS_TOP_BUILDDIR}/tools/pskc"
63 readonly OTBR_AGENT_PATH="${ABS_TOP_BUILDDIR}/src/agent/${OTBR_AGENT}"
64 readonly OTBR_DBUS_CONF="${ABS_TOP_BUILDDIR}/src/agent/otbr-agent.conf"
65 readonly OTBR_WEB_PATH="${ABS_TOP_BUILDDIR}/src/web/${OTBR_WEB}"
68 readonly LEADER_NODE_ID=1
69 readonly JOINER_NODE_ID=2
72 readonly OTBR_WEB_HOST=127.0.0.1
73 readonly OTBR_WEB_PORT=8773
74 readonly OTBR_WEB_URL="http://${OTBR_WEB_HOST}:${OTBR_WEB_PORT}"
77 # NOTE Joiner pass phrase:
78 # Must be at least 6 bytes long
79 # And this example has: J ZERO ONE N E R
80 # We cannot use letter O and I because Q O I Z are not allowed per spec
81 readonly OT_JOINER_PASSPHRASE=J01NER
83 # 18b430 is the nest EUI prefix.
84 readonly OT_JOINER_EUI64="18b430000000000${JOINER_NODE_ID}"
86 # The border agent, and ncp needs a pass phrase.
87 readonly OT_AGENT_PASSPHRASE=MYPASSPHRASE
89 # The network needs a name.
90 readonly OT_NETWORK_NAME=MyTestNetwork
92 # The TUN device for OpenThread border router.
93 readonly TUN_NAME=wpan0
95 echo "ORIGIN_PWD: ${ORIGIN_PWD}"
96 echo "TEST_BASE: ${TEST_BASE}"
97 echo "ABS_TOP_SRCDIR=${ABS_TOP_SRCDIR}"
98 echo "ABS_TOP_BUILDDIR=${ABS_TOP_BUILDDIR}"
100 #----------------------------------------
102 #----------------------------------------
107 echo " *** ERROR: $*"
113 [[ -f $1 ]] || die "Missing file: $1"
118 [[ -x $1 ]] || die "Missing executable: $1"
123 echo $((11 + "${RANDOM}" % 16))
128 printf "0x%04x" "${RANDOM}"
133 printf "%04x%04x%04x%04x" "${RANDOM}" "${RANDOM}" "${RANDOM}" "${RANDOM}"
138 printf "%04x%04x%04x%04x%04x%04x%04x%04x" "${RANDOM}" "${RANDOM}" "${RANDOM}" "${RANDOM}" "${RANDOM}" "${RANDOM}" "${RANDOM}" "${RANDOM}"
143 logger -s -p syslog.alert "OPENTHREAD_TEST: $*"
148 write_syslog 'All apps should be dead now'
153 # On travis (the CI server), we can't see what went into the
154 # syslog. So this is here so we can see the output.
159 # If we run locally, it is sometimes helpful for our victim (you
160 # the developer) to have logs split upto various files to help
161 # that victim, we'll GREP the log files according.
163 # Wait 5 seconds for the "logs to flush"
167 echo 'START_LOG: SYSLOG ==================='
168 tee complete-syslog.log </var/log/syslog
169 echo 'START_LOG: BR-AGENT ================='
170 grep "${OTBR_AGENT}" /var/log/syslog | tee otbr-agent.log
171 echo 'START_LOG: OT-COMISSIONER ========='
172 cat "${OT_COMMISSIONER_LOG}"
173 echo 'START_LOG: OT-RCP ==================='
174 grep "${OT_RCP}" /var/log/syslog | tee "${OT_RCP}.log"
175 echo 'START_LOG: OT-CLI ==================='
176 grep "${OT_CLI}" /var/log/syslog | tee "${OT_CLI}.log"
177 echo '====================================='
178 echo 'Hint, for each log Search backwards for: "START_LOG: <NAME>"'
179 echo '====================================='
185 if [[ ${NO_CLEAN} != 1 ]]; then
186 [[ ! -d ${STAGE_DIR} ]] || rm -rf "${STAGE_DIR}"
187 [[ ! -d ${BUILD_DIR} ]] || rm -rf "${BUILD_DIR}"
190 [[ -d ${STAGE_DIR} ]] || mkdir -p "${STAGE_DIR}"
191 [[ -d ${BUILD_DIR} ]] || mkdir -p "${BUILD_DIR}"
193 # As above, these steps are broken up
194 ot_cli=$(command -v "${OT_CLI}")
195 ot_rcp=$(command -v "${OT_RCP}")
197 if [[ ${OTBR_USE_WEB_COMMISSIONER} != 1 ]]; then
198 ot_commissioner_build
201 write_syslog "TEST: BUILD COMPLETE"
206 # message for general failures
207 exit_message="JOINER FAILED"
209 executable_or_die "${OTBR_AGENT_PATH}"
210 executable_or_die "${OTBR_WEB_PATH}"
213 sudo rm -vrf "${TEST_BASE}/tmp"
214 # OPENTHREAD_POSIX_DAEMON_SOCKET_LOCK
215 sudo rm -vf "/tmp/openthread.lock"
219 # We will be creating a lot of log information
220 # Rotate logs so we have a clean and empty set of logs uncluttered with other stuff
221 if [[ -f /etc/logrotate.conf ]]; then
222 sudo logrotate -f /etc/logrotate.conf || true
225 # From now on - all exits are TRAPPED
226 # When they occur, we call the function: output_logs'.
227 trap test_teardown EXIT
232 # Capture the exit code so we can return it below
233 readonly EXIT_CODE=$?
234 write_syslog "EXIT ${EXIT_CODE} - output logs"
236 sudo pkill -f "${OTBR_AGENT}" || true
237 sudo pkill -f "${OTBR_WEB}" || true
238 sudo pkill -f "${OT_COMMISSIONER_CLI}" || true
239 sudo pkill -f "${OT_CLI}" || true
242 if [[ ${NO_CLEAN} != 1 ]]; then
244 sudo rm /etc/dbus-1/system.d/otbr-agent.conf || true
245 sudo rm -rf "${STAGE_DIR}" || true
246 sudo rm -rf "${BUILD_DIR}" || true
251 echo "EXIT ${EXIT_CODE}: MESSAGE: ${exit_message}"
257 exists_or_die "${OTBR_DBUS_CONF}"
258 sudo cp "${OTBR_DBUS_CONF}" /etc/dbus-1/system.d
260 write_syslog "AGENT: kill old"
261 sudo killall "${OTBR_AGENT}" || true
262 write_syslog "AGENT: starting"
264 # we launch this in the background
272 sudo "${OTBR_AGENT_PATH}" -V
273 # check invalid arguments
274 sudo "${OTBR_AGENT_PATH}" -x && exit $?
276 [[ ! -d tmp ]] || sudo rm -rf tmp
277 sudo "${OTBR_AGENT_PATH}" -I "${TUN_NAME}" -v -d 6 "spinel+hdlc+forkpty://${ot_rcp}?forkpty-arg=${LEADER_NODE_ID}" &
280 # wait for it to complete
283 pidof ${OTBR_AGENT} || die "AGENT: failed to start"
284 write_syslog "AGENT: start complete"
289 write_syslog "WEB: kill old"
290 sudo killall "${OTBR_WEB}" || true
291 write_syslog "WEB: starting"
297 sudo "${OTBR_WEB_PATH}" -I "${TUN_NAME}" -p "${OTBR_WEB_PORT}" -a "${OTBR_WEB_HOST}" &
301 pidof ${OTBR_WEB} || die "WEB: failed to start"
302 write_syslog "WEB: start complete"
307 readonly OT_PANID="$(random_panid)"
308 readonly OT_XPANID="$(random_xpanid)"
309 readonly OT_MASTER_KEY="$(random_masterkey)"
310 readonly OT_CHANNEL="$(random_channel)"
312 curl --header "Content-Type: application/json" --request POST --data "{\"masterKey\":\"${OT_MASTER_KEY}\",\"prefix\":\"fd11:22::\",\"defaultRoute\":true,\"extPanId\":\"${OT_XPANID}\",\"panId\":\"${OT_PANID}\",\"passphrase\":\"${OT_AGENT_PASSPHRASE}\",\"channel\":${OT_CHANNEL},\"networkName\":\"${OT_NETWORK_NAME}\"}" "${OTBR_WEB_URL}"/form_network | grep "success" || die "WEB: form failed"
314 # verify mDNS is working as expected.
315 local mdns_result="${TEST_BASE}"/mdns_result.log
316 avahi-browse -aprt | tee "${mdns_result}"
317 grep -q "${OT_NETWORK_NAME}" "${mdns_result}"
321 ot_commissioner_build()
323 readonly OT_COMMISSIONER_PATH=${BUILD_DIR}/ot-commissioner/build/src/app/cli/commissioner-cli
324 readonly OT_COMMISSIONER_CONFIG=${BUILD_DIR}/ot-commissioner/src/app/etc/commissioner/non-ccm-config.json
326 if [[ -x ${OT_COMMISSIONER_PATH} ]]; then
330 (mkdir -p "${BUILD_DIR}/ot-commissioner" \
331 && cd "${BUILD_DIR}/ot-commissioner" \
332 && (git --git-dir=.git rev-parse --is-inside-work-tree || git --git-dir=.git init .) \
333 && git fetch --depth 1 https://github.com/openthread/ot-commissioner.git master \
334 && git checkout FETCH_HEAD \
335 && ./script/bootstrap.sh \
336 && mkdir build && cd build \
337 && cmake -GNinja -DCMAKE_BUILD_TYPE=Release .. \
341 ot_commissioner_start()
343 write_syslog "COMMISSIONER: kill old"
344 sudo killall "${OT_COMMISSIONER_CLI}" || true
346 readonly OT_PSKC="$("${OTBR_PSKC_PATH}" "${OT_AGENT_PASSPHRASE}" "${OT_XPANID}" "${OT_NETWORK_NAME}")"
347 readonly OT_COMMISSIONER_LOG="${TEST_BASE}"/commissioner.log
349 local commissioner_config_file="${TEST_BASE}"/ot-commissioner.json
351 sed "s/3aa55f91ca47d1e4e71a08cb35e91591/${OT_PSKC}/g" "${OT_COMMISSIONER_CONFIG}" >"${commissioner_config_file}"
354 spawn ${OT_COMMISSIONER_PATH} ${commissioner_config_file}
359 send "start :: 49191\n"
364 send "joiner enable meshcop 0x${OT_JOINER_EUI64} ${OT_JOINER_PASSPHRASE}\n"
372 web_commissioner_start()
374 curl --header "Content-Type: application/json" --request POST --data "{\"pskd\":\"${OT_JOINER_PASSPHRASE}\", \"passphrase\":\"${OT_AGENT_PASSPHRASE}\"}" "${OTBR_WEB_URL}"/commission
380 write_syslog 'JOINER START'
382 sudo expect -f- <<EOF || die 'JOINER FAILED'
383 spawn ${ot_cli} ${JOINER_NODE_ID}
384 send "ifconfig up\r\n"
386 send "joiner start ${OT_JOINER_PASSPHRASE}\r\n"
390 send_user "succeeded to find join success"
394 send_user "Failed to find join success"
399 exit_message="JOINER SUCCESS COMPLETE"
408 if [[ ${OTBR_USE_WEB_COMMISSIONER} == 1 ]]; then
409 web_commissioner_start
411 ot_commissioner_start