[toranj] add test-case for child table and child recovery (#2776)

This commit is contained in:
Abtin Keshavarzian
2018-06-11 09:19:50 -07:00
committed by Jonathan Hui
parent 70154b1f4d
commit 139b2da408
3 changed files with 199 additions and 31 deletions
+1
View File
@@ -123,6 +123,7 @@ run test-007-traffic-router-sleepy.py
run test-008-permit-join.py
run test-009-insecure-traffic-join.py
run test-010-on-mesh-prefix-config-gateway.py
run test-011-child-table.py
run test-100-mcu-power-state.py
run test-600-channel-manager-properties.py
run test-601-channel-manager-channel-change.py
+113
View File
@@ -0,0 +1,113 @@
#!/usr/bin/env python
#
# 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 time
import wpan
from wpan import verify
#-----------------------------------------------------------------------------------------------------------------------
# Test description: Child-table and child recovery
#
test_name = __file__[:-3] if __file__.endswith('.py') else __file__
print '-' * 120
print 'Starting \'{}\''.format(test_name)
#-----------------------------------------------------------------------------------------------------------------------
# Creating `wpan.Nodes` instances
speedup = 4
wpan.Node.set_time_speedup_factor(speedup)
NUM_CHILDREN = 7
router = wpan.Node()
children = []
for i in range(NUM_CHILDREN):
children.append(wpan.Node())
all_nodes = [router] + children
#-----------------------------------------------------------------------------------------------------------------------
# Init all nodes
wpan.Node.init_all_nodes()
for node in all_nodes:
node.set(wpan.WPAN_OT_LOG_LEVEL, '0')
#-----------------------------------------------------------------------------------------------------------------------
# Build network topology
router.form('child-table')
for child in children:
child.join_node(router, node_type=wpan.JOIN_TYPE_SLEEPY_END_DEVICE)
child.set(wpan.WPAN_POLL_INTERVAL, '300')
#-----------------------------------------------------------------------------------------------------------------------
# Test implementation
# Get the child table and verify all children are in the table.
child_table = wpan.parse_child_table_result(router.get(wpan.WPAN_THREAD_CHILD_TABLE))
verify(len(child_table) == len(children))
for child in children:
ext_addr = child.get(wpan.WPAN_EXT_ADDRESS)[1:-1]
for entry in child_table:
if entry.ext_address == ext_addr:
break;
else:
print 'Failed to find a child entry for extended address {} in table'.format(ext_addr)
exit(1)
verify(int(entry.rloc16, 16) == int(child.get(wpan.WPAN_THREAD_RLOC16), 16))
verify(int(entry.timeout, 0) == 120)
verify(entry.is_rx_on_when_idle() == False)
verify(entry.is_ffd() == False)
# Reset router and ensure all children are restored.
router.reset()
start_time = time.time()
wait_time = 5
while time.time() - start_time < wait_time:
time.sleep(0.25)
child_table = wpan.parse_child_table_result(router.get(wpan.WPAN_THREAD_CHILD_TABLE))
if (len(child_table) == len(children)):
break
else:
print 'Took too long for node to recover after reset ({}>{} sec)'.format(time.time() - start_time, wait_time)
exit(1)
#-----------------------------------------------------------------------------------------------------------------------
# Test finished
print '\'{}\' passed.'.format(test_name)
+85 -31
View File
@@ -63,36 +63,36 @@ WPAN_IP6_MESH_LOCAL_PREFIX = "IPv6:MeshLocalPrefix"
WPAN_IP6_ALL_ADDRESSES = "IPv6:AllAddresses"
WPAN_IP6_MULTICAST_ADDRESSES = "IPv6:MulticastAddresses"
WPAN_THREAD_RLOC16 = "Thread:RLOC16"
WPAN_THREAD_ROUTER_ID = "Thread:RouterID"
WPAN_THREAD_LEADER_ADDRESS = "Thread:Leader:Address"
WPAN_THREAD_LEADER_ROUTER_ID = "Thread:Leader:RouterID"
WPAN_THREAD_LEADER_WEIGHT = "Thread:Leader:Weight"
WPAN_THREAD_LEADER_LOCAL_WEIGHT = "Thread:Leader:LocalWeight"
WPAN_THREAD_LEADER_NETWORK_DATA = "Thread:Leader:NetworkData"
WPAN_THREAD_STABLE_LEADER_NETWORK_DATA = "Thread:Leader:StableNetworkData"
WPAN_THREAD_NETWORK_DATA = "Thread:NetworkData"
WPAN_THREAD_CHILD_TABLE = "Thread:ChildTable"
WPAN_THREAD_CHILD_TABLE_ASVALMAP = "Thread:ChildTable:AsValMap"
WPAN_THREAD_CHILD_TABLE_ADDRESSES = "Thread:ChildTable:Addresses"
WPAN_THREAD_NEIGHBOR_TABLE = "Thread:NeighborTable"
WPAN_THREAD_NEIGHBOR_TABLE_ASVALMAP = "Thread:NeighborTable:AsValMap"
WPAN_THREAD_ROUTER_TABLE = "Thread:RouterTable"
WPAN_THREAD_ROUTER_TABLE_ASVALMAP = "Thread:RouterTable:AsValMap"
WPAN_THREAD_NETWORK_DATA_VERSION = "Thread:NetworkDataVersion"
WPAN_THREAD_STABLE_NETWORK_DATA = "Thread:StableNetworkData"
WPAN_THREAD_STABLE_NETWORK_DATA_VERSION = "Thread:StableNetworkDataVersion"
WPAN_THREAD_PREFERRED_ROUTER_ID = "Thread:PreferredRouterID"
WPAN_THREAD_COMMISSIONER_ENABLED = "Thread:Commissioner:Enabled"
WPAN_THREAD_DEVICE_MODE = "Thread:DeviceMode"
WPAN_THREAD_OFF_MESH_ROUTES = "Thread:OffMeshRoutes"
WPAN_THREAD_ON_MESH_PREFIXES = "Thread:OnMeshPrefixes"
WPAN_THREAD_ROUTER_ROLE_ENABLED = "Thread:RouterRole:Enabled"
WPAN_THREAD_CONFIG_FILTER_RLOC_ADDRESSES = "Thread:Config:FilterRLOCAddresses"
WPAN_THREAD_ACTIVE_DATASET = "Thread:ActiveDataset"
WPAN_THREAD_ACTIVE_DATASET_ASVALMAP = "Thread:ActiveDataset:AsValMap"
WPAN_THREAD_PENDING_DATASET = "Thread:PendingDataset"
WPAN_THREAD_PENDING_DATASET_ASVALMAP = "Thread:PendingDataset:AsValMap"
WPAN_THREAD_RLOC16 = "Thread:RLOC16"
WPAN_THREAD_ROUTER_ID = "Thread:RouterID"
WPAN_THREAD_LEADER_ADDRESS = "Thread:Leader:Address"
WPAN_THREAD_LEADER_ROUTER_ID = "Thread:Leader:RouterID"
WPAN_THREAD_LEADER_WEIGHT = "Thread:Leader:Weight"
WPAN_THREAD_LEADER_LOCAL_WEIGHT = "Thread:Leader:LocalWeight"
WPAN_THREAD_LEADER_NETWORK_DATA = "Thread:Leader:NetworkData"
WPAN_THREAD_STABLE_LEADER_NETWORK_DATA = "Thread:Leader:StableNetworkData"
WPAN_THREAD_NETWORK_DATA = "Thread:NetworkData"
WPAN_THREAD_CHILD_TABLE = "Thread:ChildTable"
WPAN_THREAD_CHILD_TABLE_ASVALMAP = "Thread:ChildTable:AsValMap"
WPAN_THREAD_CHILD_TABLE_ADDRESSES = "Thread:ChildTable:Addresses"
WPAN_THREAD_NEIGHBOR_TABLE = "Thread:NeighborTable"
WPAN_THREAD_NEIGHBOR_TABLE_ASVALMAP = "Thread:NeighborTable:AsValMap"
WPAN_THREAD_ROUTER_TABLE = "Thread:RouterTable"
WPAN_THREAD_ROUTER_TABLE_ASVALMAP = "Thread:RouterTable:AsValMap"
WPAN_THREAD_NETWORK_DATA_VERSION = "Thread:NetworkDataVersion"
WPAN_THREAD_STABLE_NETWORK_DATA = "Thread:StableNetworkData"
WPAN_THREAD_STABLE_NETWORK_DATA_VERSION = "Thread:StableNetworkDataVersion"
WPAN_THREAD_PREFERRED_ROUTER_ID = "Thread:PreferredRouterID"
WPAN_THREAD_COMMISSIONER_ENABLED = "Thread:Commissioner:Enabled"
WPAN_THREAD_DEVICE_MODE = "Thread:DeviceMode"
WPAN_THREAD_OFF_MESH_ROUTES = "Thread:OffMeshRoutes"
WPAN_THREAD_ON_MESH_PREFIXES = "Thread:OnMeshPrefixes"
WPAN_THREAD_ROUTER_ROLE_ENABLED = "Thread:RouterRole:Enabled"
WPAN_THREAD_CONFIG_FILTER_RLOC_ADDRESSES = "Thread:Config:FilterRLOCAddresses"
WPAN_THREAD_ACTIVE_DATASET = "Thread:ActiveDataset"
WPAN_THREAD_ACTIVE_DATASET_ASVALMAP = "Thread:ActiveDataset:AsValMap"
WPAN_THREAD_PENDING_DATASET = "Thread:PendingDataset"
WPAN_THREAD_PENDING_DATASET_ASVALMAP = "Thread:PendingDataset:AsValMap"
WPAN_OT_LOG_LEVEL = "OpenThread:LogLevel"
WPAN_OT_STEERING_DATA_ADDRESS = "OpenThread:SteeringData:Address"
@@ -755,6 +755,7 @@ def verify(condition):
#-----------------------------------------------------------------------------------------------------------------------
# Parsing `wpanctl` output
#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
class ScanResult(object):
""" This object encapsulates a scan result (active/discover/energy scan)"""
@@ -850,6 +851,7 @@ def parse_list(list_string):
#
return [line[2:-1].split()[0] for line in list_string.split('\n')[1:-1]]
#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
class OnMeshPrefix(object):
""" This object encapsulates an on-mesh prefix"""
@@ -920,4 +922,56 @@ class OnMeshPrefix(object):
def parse_on_mesh_prefix_result(on_mesh_prefix_list):
""" Parses on-mesh prefix list string and returns an array of `OnMeshPrefix` objects"""
return [ OnMeshPrefix(item) for item in on_mesh_prefix_list.split('\n')[1:-1] ]
return [ OnMeshPrefix(item) for item in on_mesh_prefix_list.split('\n')[1:-1] ]
#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
class ChildEntry(object):
""" This object encapsulates an child entry"""
def __init__(self, text):
# Example of expected text:
#
# `\t"E24C5F67F4B8CBB9, RLOC16:d402, NetDataVer:175, LQIn:3, AveRssi:-20, LastRssi:-20, Timeout:120, Age:0, `
# `RxOnIdle:no, FFD:no, SecDataReq:yes, FullNetData:yes"`
#
# We get rid of the first two chars `\t"' and last char '"', split the rest using whitespace as seperator.
# Then remove any ',' at end of items in the list.
items = [item[:-1] if item[-1] ==',' else item for item in text[2:-1].split()]
# First item in the extended address
self._ext_address = items[0]
# Convert the rest into a dictionary by splitting using ':' as seperator
dict = {item.split(':')[0] : item.split(':')[1] for item in items[1:]}
self._rloc16 = dict['RLOC16']
self._timeout = dict['Timeout']
self._rx_on_idle = (dict['RxOnIdle'] == 'yes')
self._ffd = (dict['FFD'] == 'yes')
@property
def ext_address(self):
return self._ext_address
@property
def rloc16(self):
return self._rloc16
@property
def timeout(self):
return self._timeout
def is_rx_on_when_idle(self):
return self._rx_on_idle
def is_ffd(self):
return self._ffd
def __repr__(self):
return 'ChildEntry({})'.format(self.__dict__)
def parse_child_table_result(child_table_list):
""" Parses child table list string and returns an array of `ChildEntry` objects"""
return [ ChildEntry(item) for item in child_table_list.split('\n')[1:-1] ]