| #!/usr/bin/env python3 |
| # |
| # Copyright (c) 2018, 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 wpan |
| from wpan import verify |
| |
| # ----------------------------------------------------------------------------------------------------------------------- |
| # Test description: Parent restoring children after reset |
| # |
| # This test covers the following: |
| # |
| # - A parent node with a given number sleepy and rx-on children. |
| # - Parent node is reset |
| # - It is verified that all children are recovered and are present in the parent's child table |
| # - It is also verified that all children are restored on parent through "Child Update" exchange process and none of |
| # them got detached and needed to attach back. |
| # |
| |
| test_name = __file__[:-3] if __file__.endswith('.py') else __file__ |
| print('-' * 120) |
| print('Starting \'{}\''.format(test_name)) |
| |
| # ----------------------------------------------------------------------------------------------------------------------- |
| # Creating `wpan.Nodes` instances |
| |
| speedup = 2 |
| wpan.Node.set_time_speedup_factor(speedup) |
| |
| NUM_SLEEPY_CHILDREN = 3 |
| NUM_RX_ON_CHILDREN = 2 |
| |
| NUM_CHILDREN = NUM_SLEEPY_CHILDREN + NUM_RX_ON_CHILDREN |
| |
| parent = wpan.Node() |
| |
| sleepy_children = [] |
| for num in range(NUM_SLEEPY_CHILDREN): |
| sleepy_children.append(wpan.Node()) |
| |
| rx_on_children = [] |
| for num in range(NUM_RX_ON_CHILDREN): |
| rx_on_children.append(wpan.Node()) |
| |
| all_children = sleepy_children + rx_on_children |
| |
| # ----------------------------------------------------------------------------------------------------------------------- |
| # Init all nodes |
| |
| wpan.Node.init_all_nodes() |
| |
| # ----------------------------------------------------------------------------------------------------------------------- |
| # Build network topology |
| # |
| |
| parent.form("recovery") |
| |
| for child in sleepy_children: |
| child.join_node(parent, wpan.JOIN_TYPE_SLEEPY_END_DEVICE) |
| child.set(wpan.WPAN_POLL_INTERVAL, '4000') |
| |
| for child in rx_on_children: |
| child.join_node(parent, wpan.JOIN_TYPE_END_DEVICE) |
| |
| # ----------------------------------------------------------------------------------------------------------------------- |
| # Test implementation |
| |
| # The test verifies that all children are recovered after the parent is reset. |
| # |
| # The `wpantund` statistics collector is used to determine if the children are |
| # recovered through "Child Update Request/Response" exchange triggered by parent |
| # after it was reset (child restoration process) or if they got detached and |
| # went through full attach process again. The wpantund stat-collector "stat:ncp" |
| # property keeps track of all NCP state changes on a device: |
| # |
| # Node.wpanctl('get -v stat:ncp'): |
| # [ |
| # "NCP State History" |
| # "-------------------------" |
| # "00:00:03.220 ago -> associated" |
| # "00:00:03.604 ago -> associating" |
| # "00:00:06.027 ago -> offline" |
| # ] |
| # |
| # |
| # In the first case (child being restored through "Child Update" exchange) the |
| # child should never be detached and its "stat:ncp" history should remain the |
| # same. In the second case the child would get detached and we should |
| # observe a wpantund state change "associated:no-parent" before it gets attached |
| # again: |
| # |
| # Node.wpanctl('get -v stat:ncp'): |
| # [ |
| # "NCP State History" |
| # "-------------------------" |
| # "00:00:01.160 ago -> associated" |
| # "00:00:01.814 ago -> associated:no-parent" |
| # "00:00:04.911 ago -> associated" |
| # "00:00:05.298 ago -> associating" |
| # "00:00:06.475 ago -> offline" |
| # ] |
| # |
| |
| |
| def check_child_table(): |
| # Checks the child table includes the expected number of children. |
| child_table = wpan.parse_list(parent.get(wpan.WPAN_THREAD_CHILD_TABLE)) |
| verify(len(child_table) == NUM_CHILDREN) |
| |
| |
| # Verify that all children are present in the child table |
| check_child_table() |
| |
| # Remember number of NCP state changes (using "stat:ncp" property) per child |
| child_num_state_changes = [] |
| for child in all_children: |
| child_num_state_changes.append(len(wpan.parse_list(child.get("stat:ncp")))) |
| |
| # Reset the parent |
| parent.reset() |
| |
| |
| def check_parent_is_associated(): |
| verify(parent.is_associated()) |
| |
| |
| wpan.verify_within(check_parent_is_associated, 5) |
| |
| # Verify that all the children are recovered and present in the parent's |
| # child table again (within 5 seconds). |
| wpan.verify_within(check_child_table, 9) |
| |
| # Verify that number of state changes on all children stays as before |
| # (indicating they did not get detached). |
| for i in range(len(all_children)): |
| verify(child_num_state_changes[i] == len(wpan.parse_list(all_children[i].get("stat:ncp")))) |
| |
| # ----------------------------------------------------------------------------------------------------------------------- |
| # Test finished |
| |
| wpan.Node.finalize_all_nodes() |
| |
| print('\'{}\' passed.'.format(test_name)) |