From 8d6923fe8bc02dc1278f167c40bf7d5c93c2c182 Mon Sep 17 00:00:00 2001 From: Jonathan Hui Date: Fri, 23 Sep 2016 15:45:07 -0700 Subject: [PATCH] Add initial thread-cert tests for commissioning. (#680) --- tests/scripts/Makefile.am | 14 +++- .../thread-cert/Cert_8_1_01_Commissioning.py | 73 +++++++++++++++++++ .../thread-cert/Cert_8_1_02_Commissioning.py | 69 ++++++++++++++++++ tests/scripts/thread-cert/node.py | 41 ++++++++++- 4 files changed, 190 insertions(+), 7 deletions(-) create mode 100755 tests/scripts/thread-cert/Cert_8_1_01_Commissioning.py create mode 100755 tests/scripts/thread-cert/Cert_8_1_02_Commissioning.py diff --git a/tests/scripts/Makefile.am b/tests/scripts/Makefile.am index c476595e1..21d21389f 100644 --- a/tests/scripts/Makefile.am +++ b/tests/scripts/Makefile.am @@ -102,6 +102,8 @@ EXTRA_DIST = \ thread-cert/Cert_7_1_03_BorderRouterAsLeader.py \ thread-cert/Cert_7_1_04_BorderRouterAsRouter.py \ thread-cert/Cert_7_1_05_BorderRouterAsRouter.py \ + thread-cert/Cert_8_1_01_Commissioning.py \ + thread-cert/Cert_8_1_02_Commissioning.py \ thread-cert/Cert_9_2_13_EnergyScan.py \ thread-cert/Cert_9_2_14_PanIdQuery.py \ thread-cert/node.py \ @@ -218,6 +220,8 @@ check_SCRIPTS += \ thread-cert/Cert_7_1_03_BorderRouterAsLeader.py \ thread-cert/Cert_7_1_04_BorderRouterAsRouter.py \ thread-cert/Cert_7_1_05_BorderRouterAsRouter.py \ + thread-cert/Cert_8_1_01_Commissioning.py \ + thread-cert/Cert_8_1_02_Commissioning.py \ thread-cert/Cert_9_2_13_EnergyScan.py \ thread-cert/Cert_9_2_14_PanIdQuery.py \ $(NULL) @@ -235,10 +239,12 @@ TESTS = \ $(check_SCRIPTS) \ $(NULL) -XFAIL_NCP_TESTS = \ - thread-cert/Cert_9_2_13_EnergyScan.py \ - thread-cert/Cert_9_2_14_PanIdQuery.py \ - $(NULL) +XFAIL_NCP_TESTS = \ + thread-cert/Cert_8_1_01_Commissioning.py \ + thread-cert/Cert_8_1_02_Commissioning.py \ + thread-cert/Cert_9_2_13_EnergyScan.py \ + thread-cert/Cert_9_2_14_PanIdQuery.py \ + $(NULL) XFAIL_TESTS = $(if $(filter $(NODE_TYPE),ncp-sim),$(XFAIL_NCP_TESTS)) diff --git a/tests/scripts/thread-cert/Cert_8_1_01_Commissioning.py b/tests/scripts/thread-cert/Cert_8_1_01_Commissioning.py new file mode 100755 index 000000000..ac9389e96 --- /dev/null +++ b/tests/scripts/thread-cert/Cert_8_1_01_Commissioning.py @@ -0,0 +1,73 @@ +#!/usr/bin/python +# +# Copyright (c) 2016, The OpenThread Authors. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the copyright holder nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +import time +import unittest + +import node + +COMMISSIONER = 1 +JOINER = 2 + +class Cert_8_1_01_Commissioning(unittest.TestCase): + def setUp(self): + self.nodes = {} + for i in range(1,3): + self.nodes[i] = node.Node(i) + + self.nodes[COMMISSIONER].set_panid(0xface) + self.nodes[COMMISSIONER].set_mode('rsdn') + self.nodes[COMMISSIONER].set_masterkey('deadbeefdeadbeefdeadbeefdeadbeef') + + self.nodes[JOINER].set_mode('rsdn') + self.nodes[JOINER].set_masterkey('00112233445566778899aabbccddeeff') + + def tearDown(self): + for node in list(self.nodes.values()): + node.stop() + del self.nodes + + def test(self): + self.nodes[COMMISSIONER].interface_up() + self.nodes[COMMISSIONER].thread_start() + time.sleep(4) + self.assertEqual(self.nodes[COMMISSIONER].get_state(), 'leader') + self.nodes[COMMISSIONER].commissioner_start('openthread') + + self.nodes[JOINER].interface_up() + self.nodes[JOINER].joiner_start('openthread') + time.sleep(10) + self.assertEqual(self.nodes[JOINER].get_masterkey(), self.nodes[COMMISSIONER].get_masterkey()) + + self.nodes[JOINER].thread_start() + time.sleep(3) + self.assertEqual(self.nodes[JOINER].get_state(), 'router') + +if __name__ == '__main__': + unittest.main() diff --git a/tests/scripts/thread-cert/Cert_8_1_02_Commissioning.py b/tests/scripts/thread-cert/Cert_8_1_02_Commissioning.py new file mode 100755 index 000000000..52e9a5fea --- /dev/null +++ b/tests/scripts/thread-cert/Cert_8_1_02_Commissioning.py @@ -0,0 +1,69 @@ +#!/usr/bin/python +# +# Copyright (c) 2016, The OpenThread Authors. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the copyright holder nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +import time +import unittest + +import node + +COMMISSIONER = 1 +JOINER = 2 + +class Cert_8_1_02_Commissioning(unittest.TestCase): + def setUp(self): + self.nodes = {} + for i in range(1,3): + self.nodes[i] = node.Node(i) + + self.nodes[COMMISSIONER].set_panid(0xface) + self.nodes[COMMISSIONER].set_mode('rsdn') + self.nodes[COMMISSIONER].set_masterkey('deadbeefdeadbeefdeadbeefdeadbeef') + + self.nodes[JOINER].set_mode('rsdn') + self.nodes[JOINER].set_masterkey('00112233445566778899aabbccddeeff') + + def tearDown(self): + for node in list(self.nodes.values()): + node.stop() + del self.nodes + + def test(self): + self.nodes[COMMISSIONER].interface_up() + self.nodes[COMMISSIONER].thread_start() + time.sleep(4) + self.assertEqual(self.nodes[COMMISSIONER].get_state(), 'leader') + self.nodes[COMMISSIONER].commissioner_start('openthread') + + self.nodes[JOINER].interface_up() + self.nodes[JOINER].joiner_start('daerhtnepo') + time.sleep(10) + self.assertNotEqual(self.nodes[JOINER].get_masterkey(), self.nodes[COMMISSIONER].get_masterkey()) + +if __name__ == '__main__': + unittest.main() diff --git a/tests/scripts/thread-cert/node.py b/tests/scripts/thread-cert/node.py index 0c2290043..032c83781 100755 --- a/tests/scripts/thread-cert/node.py +++ b/tests/scripts/thread-cert/node.py @@ -128,18 +128,40 @@ class Node: def debug(self, level): self.send_command('debug '+str(level)) - def start(self): + def interface_up(self): self.send_command('ifconfig up') self.pexpect.expect('Done') + + def interface_down(self): + self.send_command('ifconfig down') + self.pexpect.expect('Done') + + def thread_start(self): self.send_command('thread start') self.pexpect.expect('Done') - def stop(self): + def thread_stop(self): self.send_command('thread stop') self.pexpect.expect('Done') - self.send_command('ifconfig down') + + def commissioner_start(self, pskd='', provisioning_url=''): + cmd = 'commissioner start ' + pskd + ' ' + provisioning_url + self.send_command(cmd) self.pexpect.expect('Done') + def joiner_start(self, pskd='', provisioning_url=''): + cmd = 'joiner start ' + pskd + ' ' + provisioning_url + self.send_command(cmd) + self.pexpect.expect('Done') + + def start(self): + self.interface_up() + self.thread_start() + + def stop(self): + self.thread_stop() + self.interface_down() + def clear_whitelist(self): self.send_command('whitelist clear') self.pexpect.expect('Done') @@ -185,6 +207,19 @@ class Node: self.send_command(cmd) self.pexpect.expect('Done') + def get_masterkey(self): + self.send_command('masterkey') + i = self.pexpect.expect('([0-9a-fA-F]{32})') + if i == 0: + masterkey = self.pexpect.match.groups()[0].decode("utf-8") + self.pexpect.expect('Done') + return masterkey + + def set_masterkey(self, masterkey): + cmd = 'masterkey ' + masterkey + self.send_command(cmd) + self.pexpect.expect('Done') + def get_key_sequence(self): self.send_command('keysequence') i = self.pexpect.expect('(\d+)\r\n')