From bf2ad6d1662577faeba3a970273ade742071b8be Mon Sep 17 00:00:00 2001 From: Simon Lin Date: Fri, 20 Sep 2019 14:38:29 +0800 Subject: [PATCH] [posix-sim] add method route_list & route_table to Node (#4142) This commit implements the router_list and router_table methods for Node in simulator. This commit also includes a simple test to verify correctness. --- tests/scripts/thread-cert/node.py | 63 ++++++++++++ tests/scripts/thread-cert/test_route_table.py | 99 +++++++++++++++++++ 2 files changed, 162 insertions(+) create mode 100755 tests/scripts/thread-cert/test_route_table.py diff --git a/tests/scripts/thread-cert/node.py b/tests/scripts/thread-cert/node.py index a86edd8c9..fffb393b5 100755 --- a/tests/scripts/thread-cert/node.py +++ b/tests/scripts/thread-cert/node.py @@ -1077,6 +1077,69 @@ class Node: def udp_check_rx(self, bytes_should_rx): self._expect('%d bytes' % bytes_should_rx) + def router_list(self): + cmd = 'router list' + self.send_command(cmd) + self._expect([r'(\d+)((\s\d+)*)']) + + g = self.pexpect.match.groups() + router_list = g[0] + ' ' + g[1] + router_list = [int(x) for x in router_list.split()] + self._expect('Done') + return router_list + + def router_table(self): + cmd = 'router table' + self.send_command(cmd) + + self._expect(r'(.*)Done') + g = self.pexpect.match.groups() + output = g[0] + lines = output.strip().split('\n') + lines = [l.strip() for l in lines] + router_table = {} + for i, line in enumerate(lines): + if not line.startswith('|') or not line.endswith('|'): + if i not in (0, 2): + # should not happen + print("unexpected line %d: %s" % (i, line)) + + continue + + line = line[1:][:-1] + line = [x.strip() for x in line.split('|')] + if len(line) != 8: + print("unexpected line %d: %s" % (i, line)) + continue + + try: + int(line[0]) + except ValueError: + if i != 1: + print("unexpected line %d: %s" % (i, line)) + continue + + id = int(line[0]) + rloc16 = int(line[1], 16) + nexthop = int(line[2]) + pathcost = int(line[3]) + lqin = int(line[4]) + lqout = int(line[5]) + age = int(line[6]) + emac = str(line[7]) + + router_table[id] = { + 'rloc16': rloc16, + 'nexthop': nexthop, + 'pathcost': pathcost, + 'lqin': lqin, + 'lqout': lqout, + 'age': age, + 'emac': emac, + } + + return router_table + if __name__ == '__main__': unittest.main() diff --git a/tests/scripts/thread-cert/test_route_table.py b/tests/scripts/thread-cert/test_route_table.py new file mode 100755 index 000000000..11c1be51b --- /dev/null +++ b/tests/scripts/thread-cert/test_route_table.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python +# +# Copyright (c) 2019, 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 unittest + +import node +import config + +LEADER = 1 +ROUTER1 = 2 +ROUTER2 = 3 + +# Topology: +# LEADER -- ROUTER1 -- ROUTER2 +# + + +class TestRouteTable(unittest.TestCase): + def setUp(self): + self.simulator = config.create_default_simulator() + + self.nodes = {} + for i in range(1, 4): + self.nodes[i] = node.Node(i, simulator=self.simulator) + + self.nodes[LEADER].set_panid(0xface) + self.nodes[LEADER].set_mode('rsdn') + self.nodes[LEADER].add_whitelist(self.nodes[ROUTER1].get_addr64()) + self.nodes[LEADER].enable_whitelist() + + self.nodes[ROUTER1].set_panid(0xface) + self.nodes[ROUTER1].set_mode('rsdn') + self.nodes[ROUTER1].add_whitelist(self.nodes[LEADER].get_addr64()) + self.nodes[ROUTER1].add_whitelist(self.nodes[ROUTER2].get_addr64()) + self.nodes[ROUTER1].enable_whitelist() + self.nodes[ROUTER1].set_router_selection_jitter(1) + + self.nodes[ROUTER2].set_panid(0xface) + self.nodes[ROUTER2].set_mode('rsdn') + self.nodes[ROUTER2].add_whitelist(self.nodes[ROUTER1].get_addr64()) + self.nodes[ROUTER2].enable_whitelist() + self.nodes[ROUTER2].set_router_selection_jitter(1) + + def tearDown(self): + for n in list(self.nodes.values()): + n.stop() + n.destroy() + self.simulator.stop() + + def test(self): + self.nodes[LEADER].start() + self.simulator.go(5) + self.assertEqual(self.nodes[LEADER].get_state(), 'leader') + + self.nodes[ROUTER1].start() + self.nodes[ROUTER2].start() + self.simulator.go(5) + self.assertEqual(self.nodes[ROUTER1].get_state(), 'router') + self.assertEqual(self.nodes[ROUTER2].get_state(), 'router') + + self.simulator.go(100) + + router_ids = set(_node.get_router_id() for _node in self.nodes.values()) + for _node in self.nodes.values(): + self.assertEqual(set(_node.router_list()), router_ids) + + for _node in self.nodes.values(): + router_table = _node.router_table() + self.assertEqual(set(router_table.keys()), router_ids) + + +if __name__ == '__main__': + unittest.main()