729 lines
30 KiB
Python
729 lines
30 KiB
Python
|
|
#!/usr/bin/env python3
|
||
|
|
#
|
||
|
|
# Copyright (c) 2020, 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 ipaddress
|
||
|
|
import json
|
||
|
|
import logging
|
||
|
|
import os
|
||
|
|
import subprocess
|
||
|
|
import unittest
|
||
|
|
|
||
|
|
import otci
|
||
|
|
from otci import OTCI
|
||
|
|
from otci.errors import CommandError
|
||
|
|
from otci import NetifIdentifier
|
||
|
|
|
||
|
|
logging.basicConfig(level=logging.DEBUG)
|
||
|
|
|
||
|
|
TEST_CHANNEL = 22
|
||
|
|
TEST_NETWORK_NAME = 'OT CI'
|
||
|
|
TEST_PANID = 0xeeee
|
||
|
|
TEST_NETWORKKEY = 'ffeeddccbbaa99887766554433221100'
|
||
|
|
|
||
|
|
REAL_DEVICE = int(os.getenv('REAL_DEVICE', '0'))
|
||
|
|
|
||
|
|
|
||
|
|
class TestOTCI(unittest.TestCase):
|
||
|
|
|
||
|
|
def testCliRealDevice(self):
|
||
|
|
if not REAL_DEVICE:
|
||
|
|
self.skipTest('not for virtual device')
|
||
|
|
|
||
|
|
if os.getenv('OTBR_SSH'):
|
||
|
|
node = otci.connect_otbr_ssh(os.getenv('OTBR_SSH'))
|
||
|
|
elif os.getenv('OT_CLI_SERIAL'):
|
||
|
|
node = otci.connect_cli_serial(os.getenv('OT_CLI_SERIAL'))
|
||
|
|
else:
|
||
|
|
self.fail("Please set OT_CLI_SERIAL or OTBR_SSH to test the real device.")
|
||
|
|
|
||
|
|
node.factory_reset()
|
||
|
|
|
||
|
|
self._test_otci_single_node(node)
|
||
|
|
|
||
|
|
def testCliSimRealTime(self):
|
||
|
|
if REAL_DEVICE:
|
||
|
|
self.skipTest('not for real device')
|
||
|
|
|
||
|
|
subprocess.check_call('rm -rf tmp/', shell=True)
|
||
|
|
VIRTUAL_TIME = int(os.getenv('VIRTUAL_TIME', "1"))
|
||
|
|
|
||
|
|
import simulator
|
||
|
|
|
||
|
|
if VIRTUAL_TIME:
|
||
|
|
sim = simulator.VirtualTime(use_message_factory=False)
|
||
|
|
else:
|
||
|
|
sim = None
|
||
|
|
|
||
|
|
if os.getenv('OT_CLI'):
|
||
|
|
executable = os.getenv('OT_CLI')
|
||
|
|
connector = otci.connect_cli_sim
|
||
|
|
elif os.getenv('OT_NCP'):
|
||
|
|
executable = os.getenv('OT_NCP')
|
||
|
|
connector = otci.connect_ncp_sim
|
||
|
|
else:
|
||
|
|
self.fail("Please set OT_CLI to test virtual device")
|
||
|
|
|
||
|
|
node1 = connector(executable, 1, simulator=sim)
|
||
|
|
self._test_otci_single_node(node1)
|
||
|
|
|
||
|
|
node1.factory_reset()
|
||
|
|
|
||
|
|
node2 = connector(executable, 2, simulator=sim)
|
||
|
|
node3 = connector(executable, 3, simulator=sim)
|
||
|
|
node4 = connector(executable, 4, simulator=sim)
|
||
|
|
|
||
|
|
self._test_otci_example(node1, node2)
|
||
|
|
|
||
|
|
node1.factory_reset()
|
||
|
|
node2.factory_reset()
|
||
|
|
|
||
|
|
self._test_otci_multi_nodes(node1, node2, node3, node4)
|
||
|
|
|
||
|
|
def _test_otci_single_node(self, leader):
|
||
|
|
logging.info('leader version: %r', leader.version)
|
||
|
|
logging.info('leader thread version: %r', leader.thread_version)
|
||
|
|
logging.info('API version: %r', leader.api_version)
|
||
|
|
logging.info('log level: %r', leader.get_log_level())
|
||
|
|
|
||
|
|
leader.enable_promiscuous()
|
||
|
|
self.assertTrue(leader.get_promiscuous())
|
||
|
|
leader.disable_promiscuous()
|
||
|
|
self.assertFalse(leader.get_promiscuous())
|
||
|
|
try:
|
||
|
|
logging.info("RCP version: %r", leader.get_rcp_version())
|
||
|
|
except CommandError:
|
||
|
|
pass
|
||
|
|
|
||
|
|
self.assertTrue(leader.get_router_eligible())
|
||
|
|
leader.disable_router_eligible()
|
||
|
|
self.assertFalse(leader.get_router_eligible())
|
||
|
|
leader.enable_router_eligible()
|
||
|
|
|
||
|
|
self.assertFalse(leader.get_ifconfig_state())
|
||
|
|
# ifconfig up
|
||
|
|
leader.ifconfig_up()
|
||
|
|
self.assertTrue(leader.get_ifconfig_state())
|
||
|
|
|
||
|
|
logging.info('leader eui64 = %r', leader.get_eui64())
|
||
|
|
logging.info('leader extpanid = %r', leader.get_extpanid())
|
||
|
|
logging.info('leader networkkey = %r', leader.get_network_key())
|
||
|
|
|
||
|
|
extaddr = leader.get_extaddr()
|
||
|
|
self.assertEqual(16, len(extaddr))
|
||
|
|
int(extaddr, 16)
|
||
|
|
new_extaddr = 'aabbccddeeff0011'
|
||
|
|
leader.set_extaddr(new_extaddr)
|
||
|
|
self.assertEqual(new_extaddr, leader.get_extaddr())
|
||
|
|
|
||
|
|
leader.set_network_name(TEST_NETWORK_NAME)
|
||
|
|
|
||
|
|
leader.set_network_key(TEST_NETWORKKEY)
|
||
|
|
self.assertEqual(TEST_NETWORKKEY, leader.get_network_key())
|
||
|
|
|
||
|
|
leader.set_panid(TEST_PANID)
|
||
|
|
self.assertEqual(TEST_PANID, leader.get_panid())
|
||
|
|
|
||
|
|
leader.set_channel(TEST_CHANNEL)
|
||
|
|
self.assertEqual(TEST_CHANNEL, leader.get_channel())
|
||
|
|
|
||
|
|
leader.set_network_name(TEST_NETWORK_NAME)
|
||
|
|
self.assertEqual(TEST_NETWORK_NAME, leader.get_network_name())
|
||
|
|
|
||
|
|
self.assertEqual('rdn', leader.get_mode())
|
||
|
|
leader.set_mode('-')
|
||
|
|
self.assertEqual('-', leader.get_mode())
|
||
|
|
leader.set_mode('rdn')
|
||
|
|
self.assertEqual('rdn', leader.get_mode())
|
||
|
|
|
||
|
|
logging.info('leader weight: %d', leader.get_leader_weight())
|
||
|
|
leader.set_leader_weight(72)
|
||
|
|
|
||
|
|
logging.info('domain name: %r', leader.get_domain_name())
|
||
|
|
leader.set_domain_name("DefaultDomain2")
|
||
|
|
self.assertEqual("DefaultDomain2", leader.get_domain_name())
|
||
|
|
|
||
|
|
self.assertEqual(leader.get_preferred_partition_id(), 0)
|
||
|
|
leader.set_preferred_partition_id(0xabcddead)
|
||
|
|
self.assertEqual(leader.get_preferred_partition_id(), 0xabcddead)
|
||
|
|
|
||
|
|
leader.thread_start()
|
||
|
|
leader.wait(10)
|
||
|
|
self.assertEqual('leader', leader.get_state())
|
||
|
|
self.assertEqual(0xabcddead, leader.get_leader_data()['partition_id'])
|
||
|
|
logging.info('leader key sequence counter = %d', leader.get_key_sequence_counter())
|
||
|
|
|
||
|
|
rloc16 = leader.get_rloc16()
|
||
|
|
leader_id = leader.get_router_id()
|
||
|
|
self.assertEqual(rloc16, leader_id << 10)
|
||
|
|
|
||
|
|
self.assertFalse(leader.get_child_list())
|
||
|
|
self.assertEqual({}, leader.get_child_table())
|
||
|
|
|
||
|
|
leader.enable_allowlist()
|
||
|
|
leader.add_allowlist(leader.get_extaddr())
|
||
|
|
leader.remove_allowlist(leader.get_extaddr())
|
||
|
|
leader.set_allowlist([leader.get_extaddr()])
|
||
|
|
leader.disable_allowlist()
|
||
|
|
|
||
|
|
self.assertEqual([], leader.backbone_router_get_multicast_listeners())
|
||
|
|
|
||
|
|
leader.add_ipmaddr('ff04::1')
|
||
|
|
leader.del_ipmaddr('ff04::1')
|
||
|
|
leader.add_ipmaddr('ff04::2')
|
||
|
|
logging.info('leader ipmaddrs: %r', leader.get_ipmaddrs())
|
||
|
|
self.assertFalse(leader.has_ipmaddr('ff04::1'))
|
||
|
|
self.assertTrue(leader.has_ipmaddr('ff04::2'))
|
||
|
|
self.assertTrue(leader.get_ipaddr_rloc())
|
||
|
|
self.assertTrue(leader.get_ipaddr_linklocal())
|
||
|
|
self.assertTrue(leader.get_ipaddr_mleid())
|
||
|
|
self.assertTrue(leader.get_ipmaddr_llatn())
|
||
|
|
self.assertTrue(leader.get_ipmaddr_rlatn())
|
||
|
|
|
||
|
|
leader.add_ipaddr('2001::1')
|
||
|
|
leader.del_ipaddr('2001::1')
|
||
|
|
leader.add_ipaddr('2001::2')
|
||
|
|
logging.info('leader ipaddrs: %r', leader.get_ipaddrs())
|
||
|
|
self.assertFalse(leader.has_ipaddr('2001::1'))
|
||
|
|
self.assertTrue(leader.has_ipaddr('2001::2'))
|
||
|
|
|
||
|
|
logging.info('leader bbr state: %r', leader.get_backbone_router_state())
|
||
|
|
bbr_config = leader.get_backbone_router_config()
|
||
|
|
logging.info('leader bbr config: %r', bbr_config)
|
||
|
|
logging.info('leader PBBR: %r', leader.get_primary_backbone_router_info())
|
||
|
|
|
||
|
|
new_bbr_seqno = (bbr_config['seqno'] + 1) % 256
|
||
|
|
leader.set_backbone_router_config(seqno=new_bbr_seqno, delay=10, timeout=301)
|
||
|
|
self.assertEqual({'seqno': new_bbr_seqno, 'delay': 10, 'timeout': 301}, leader.get_backbone_router_config())
|
||
|
|
|
||
|
|
leader.enable_backbone_router()
|
||
|
|
leader.wait(3)
|
||
|
|
|
||
|
|
logging.info('leader bbr state: %r', leader.get_backbone_router_state())
|
||
|
|
logging.info('leader bbr config: %r', leader.get_backbone_router_config())
|
||
|
|
logging.info('leader PBBR: %r', leader.get_primary_backbone_router_info())
|
||
|
|
|
||
|
|
leader.wait(10)
|
||
|
|
self.assertEqual(1, len(leader.backbone_router_get_multicast_listeners()))
|
||
|
|
self.assertEqual('ff04::2', leader.backbone_router_get_multicast_listeners()[0][0])
|
||
|
|
|
||
|
|
logging.info('leader bufferinfo: %r', leader.get_message_buffer_info())
|
||
|
|
|
||
|
|
logging.info('child ipaddrs: %r', leader.get_child_ipaddrs())
|
||
|
|
logging.info('child ipmax: %r', leader.get_child_ip_max())
|
||
|
|
leader.set_child_ip_max(2)
|
||
|
|
self.assertEqual(2, leader.get_child_ip_max())
|
||
|
|
logging.info('childmax: %r', leader.get_max_children())
|
||
|
|
|
||
|
|
logging.info('counter names: %r', leader.counter_names)
|
||
|
|
for counter_name in leader.counter_names:
|
||
|
|
logging.info('counter %s: %r', counter_name, leader.get_counter(counter_name))
|
||
|
|
leader.reset_counter(counter_name)
|
||
|
|
self.assertTrue(all(x == 0 for x in leader.get_counter(counter_name).values()))
|
||
|
|
|
||
|
|
logging.info("CSL config: %r", leader.get_csl_config())
|
||
|
|
leader.config_csl(channel=13, period=100, timeout=200)
|
||
|
|
logging.info("CSL config: %r", leader.get_csl_config())
|
||
|
|
|
||
|
|
logging.info("EID-to-RLOC cache: %r", leader.get_eidcache())
|
||
|
|
|
||
|
|
logging.info("ipmaddr promiscuous: %r", leader.get_ipmaddr_promiscuous())
|
||
|
|
leader.enable_ipmaddr_promiscuous()
|
||
|
|
self.assertTrue(leader.get_ipmaddr_promiscuous())
|
||
|
|
leader.disable_ipmaddr_promiscuous()
|
||
|
|
self.assertFalse(leader.get_ipmaddr_promiscuous())
|
||
|
|
|
||
|
|
logging.info("leader data: %r", leader.get_leader_data())
|
||
|
|
logging.info("leader neighbor list: %r", leader.get_neighbor_list())
|
||
|
|
logging.info("leader neighbor table: %r", leader.get_neighbor_table())
|
||
|
|
logging.info("Leader external routes: %r", leader.get_local_routes())
|
||
|
|
leader.add_route('2002::/64')
|
||
|
|
leader.register_network_data()
|
||
|
|
logging.info("Leader external routes: %r", leader.get_local_routes())
|
||
|
|
|
||
|
|
self.assertEqual(1, len(leader.get_router_list()))
|
||
|
|
self.assertEqual(1, len(leader.get_router_table()))
|
||
|
|
logging.info("Leader router table: %r", leader.get_router_table())
|
||
|
|
self.assertFalse(list(leader.get_router_table().values())[0].is_link_established)
|
||
|
|
|
||
|
|
logging.info('discover: %r', leader.discover())
|
||
|
|
logging.info('scan: %r', leader.scan())
|
||
|
|
logging.info('scan energy: %r', leader.scan_energy())
|
||
|
|
|
||
|
|
leader.add_service(44970, '112233', 'aabbcc')
|
||
|
|
leader.register_network_data()
|
||
|
|
leader.add_service(44971, b'\x11\x22\x33', b'\xaa\xbb\xcc\xdd')
|
||
|
|
|
||
|
|
leader.add_prefix("2001::/64")
|
||
|
|
|
||
|
|
logging.info("network data: %r", leader.get_network_data())
|
||
|
|
logging.info("network data raw: %r", leader.get_network_data_bytes())
|
||
|
|
self.assertEqual(leader.get_network_data()['prefixes'], leader.get_prefixes())
|
||
|
|
self.assertEqual(leader.get_network_data()['routes'], leader.get_routes())
|
||
|
|
self.assertEqual(leader.get_network_data()['services'], leader.get_services())
|
||
|
|
|
||
|
|
logging.info("local prefixes: %r", leader.get_local_prefixes())
|
||
|
|
logging.info("local routes: %r", leader.get_local_routes())
|
||
|
|
|
||
|
|
logging.info('txpower %r', leader.get_txpower())
|
||
|
|
leader.set_txpower(-10)
|
||
|
|
self.assertEqual(-10, leader.get_txpower())
|
||
|
|
|
||
|
|
self.assertTrue(leader.is_singleton())
|
||
|
|
|
||
|
|
leader.coap_start()
|
||
|
|
leader.coap_set_test_resource_path('test')
|
||
|
|
leader.coap_test_set_resource_content('helloworld')
|
||
|
|
leader.coap_get(leader.get_ipaddr_rloc(), 'test')
|
||
|
|
leader.coap_put(leader.get_ipaddr_rloc(), 'test', 'con', 'xxx')
|
||
|
|
leader.coap_post(leader.get_ipaddr_rloc(), 'test', 'con', 'xxx')
|
||
|
|
leader.coap_delete(leader.get_ipaddr_rloc(), 'test', 'con', 'xxx')
|
||
|
|
leader.wait(1)
|
||
|
|
leader.coap_stop()
|
||
|
|
|
||
|
|
for netif in (NetifIdentifier.THERAD, NetifIdentifier.UNSPECIFIED, NetifIdentifier.BACKBONE):
|
||
|
|
leader.udp_open()
|
||
|
|
leader.udp_bind("::", 1234, netif=netif)
|
||
|
|
leader.udp_send(leader.get_ipaddr_rloc(), 1234, text='hello')
|
||
|
|
leader.udp_send(leader.get_ipaddr_rloc(), 1234, random_bytes=3)
|
||
|
|
leader.udp_send(leader.get_ipaddr_rloc(), 1234, hex='112233')
|
||
|
|
leader.wait(1)
|
||
|
|
leader.udp_close()
|
||
|
|
|
||
|
|
logging.info('dataset: %r', leader.get_dataset())
|
||
|
|
logging.info('dataset active: %r', leader.get_dataset('active'))
|
||
|
|
|
||
|
|
leader.dataset_init_buffer()
|
||
|
|
leader.dataset_commit_buffer('pending')
|
||
|
|
leader.dataset_init_buffer(get_active_dataset=True)
|
||
|
|
leader.dataset_init_buffer(get_pending_dataset=True)
|
||
|
|
|
||
|
|
logging.info('dataset: %r', leader.get_dataset())
|
||
|
|
logging.info('dataset active: %r', leader.get_dataset('active'))
|
||
|
|
logging.info('dataset pending: %r', leader.get_dataset('pending'))
|
||
|
|
|
||
|
|
logging.info('dataset active -x: %r', leader.get_dataset_bytes('active'))
|
||
|
|
logging.info('dataset pending -x: %r', leader.get_dataset_bytes('pending'))
|
||
|
|
|
||
|
|
# Test SRP server & client
|
||
|
|
self._test_otci_srp(leader, leader)
|
||
|
|
|
||
|
|
# Test DNS client and server
|
||
|
|
self._test_otci_dns(leader, leader)
|
||
|
|
|
||
|
|
self._test_otci_srp_remove(leader, leader)
|
||
|
|
|
||
|
|
def _test_otci_dns(self, client: OTCI, server: OTCI):
|
||
|
|
dns_cfg = client.dns_get_config()
|
||
|
|
self.assertTrue(dns_cfg['server'])
|
||
|
|
self.assertIn('response_timeout', dns_cfg)
|
||
|
|
self.assertIn('max_tx_attempts', dns_cfg)
|
||
|
|
self.assertIn('recursion_desired', dns_cfg)
|
||
|
|
|
||
|
|
client.dns_set_config(server=(server.get_ipaddr_rloc(), 53),
|
||
|
|
response_timeout=10000,
|
||
|
|
max_tx_attempts=4,
|
||
|
|
recursion_desired=False)
|
||
|
|
self.assertEqual(
|
||
|
|
{
|
||
|
|
'server': (server.get_ipaddr_rloc(), 53),
|
||
|
|
'response_timeout': 10000,
|
||
|
|
'max_tx_attempts': 4,
|
||
|
|
'recursion_desired': False
|
||
|
|
}, client.dns_get_config())
|
||
|
|
|
||
|
|
self.assertTrue(client.dns_get_compression())
|
||
|
|
client.dns_disable_compression()
|
||
|
|
self.assertFalse(client.dns_get_compression())
|
||
|
|
client.dns_enable_compression()
|
||
|
|
self.assertTrue(client.dns_get_compression())
|
||
|
|
|
||
|
|
logging.info('dns browse: %r', client.dns_browse('_ipps._tcp.default.service.arpa.'))
|
||
|
|
logging.info('dns browse: %r', client.dns_browse('_meshcop._udp.default.service.arpa.'))
|
||
|
|
logging.info('dns resolve: %r', client.dns_resolve_service('ins1', '_ipps._tcp.default.service.arpa.'))
|
||
|
|
logging.info('dns resolve: %r', client.dns_resolve('host1.default.service.arpa.'))
|
||
|
|
|
||
|
|
def _test_otci_srp(self, client: OTCI, server: OTCI):
|
||
|
|
self.assertEqual('disabled', server.srp_server_get_state())
|
||
|
|
self.assertEqual('default.service.arpa.', server.srp_server_get_domain())
|
||
|
|
server.srp_server_set_domain('example1.com')
|
||
|
|
self.assertEqual('example1.com.', server.srp_server_get_domain())
|
||
|
|
server.srp_server_set_domain('example2.com.')
|
||
|
|
self.assertEqual('example2.com.', server.srp_server_get_domain())
|
||
|
|
server.srp_server_set_domain('default.service.arpa.')
|
||
|
|
self.assertEqual('default.service.arpa.', server.srp_server_get_domain())
|
||
|
|
|
||
|
|
default_leases = server.srp_server_get_lease()
|
||
|
|
self.assertEqual(default_leases, (1800, 7200, 86400, 1209600))
|
||
|
|
server.srp_server_set_lease(1801, 7201, 86401, 1209601)
|
||
|
|
leases = server.srp_server_get_lease()
|
||
|
|
self.assertEqual(leases, (1801, 7201, 86401, 1209601))
|
||
|
|
|
||
|
|
self.assertFalse(client.srp_client_get_state())
|
||
|
|
self.assertEqual('Removed', client.srp_client_get_host_state())
|
||
|
|
self.assertEqual(('::', 0), client.srp_client_get_server())
|
||
|
|
|
||
|
|
self.assertFalse(client.srp_client_get_service_key())
|
||
|
|
client.srp_client_enable_service_key()
|
||
|
|
self.assertTrue(client.srp_client_get_service_key())
|
||
|
|
client.srp_client_disable_service_key()
|
||
|
|
self.assertFalse(client.srp_client_get_service_key())
|
||
|
|
|
||
|
|
server.srp_server_disable()
|
||
|
|
client.wait(3)
|
||
|
|
server.srp_server_enable()
|
||
|
|
client.wait(10)
|
||
|
|
self.assertEqual([], server.srp_server_get_hosts())
|
||
|
|
self.assertEqual('running', server.srp_server_get_state())
|
||
|
|
|
||
|
|
self.assertFalse(client.srp_client_get_autostart())
|
||
|
|
client.srp_client_enable_autostart()
|
||
|
|
self.assertTrue(client.srp_client_get_autostart())
|
||
|
|
client.wait(3)
|
||
|
|
self.assertTrue(client.srp_client_get_state())
|
||
|
|
self.assertNotEqual(('::', 0), client.srp_client_get_server())
|
||
|
|
|
||
|
|
self.assertEqual('', client.srp_client_get_host_name())
|
||
|
|
client.srp_client_set_host_name('host1')
|
||
|
|
self.assertEqual('host1', client.srp_client_get_host_name())
|
||
|
|
|
||
|
|
self.assertEqual([], client.srp_client_get_host_addresses())
|
||
|
|
client.srp_client_set_host_addresses('2001::1')
|
||
|
|
self.assertEqual(['2001::1'], client.srp_client_get_host_addresses())
|
||
|
|
client.srp_client_set_host_addresses('2001::1', '2001::2')
|
||
|
|
self.assertEqual(['2001::1', '2001::2'], client.srp_client_get_host_addresses())
|
||
|
|
srp_client_host = client.srp_client_get_host()
|
||
|
|
self.assertEqual('host1', srp_client_host['host'])
|
||
|
|
self.assertEqual('ToAdd', srp_client_host['state'])
|
||
|
|
self.assertEqual(
|
||
|
|
{ipaddress.IPv6Address('2001::1'), ipaddress.IPv6Address('2001::2')}, set(srp_client_host['addresses']))
|
||
|
|
|
||
|
|
self.assertEqual([], client.srp_client_get_services())
|
||
|
|
client.srp_client_add_service('ins1',
|
||
|
|
'_ipps._tcp',
|
||
|
|
1000,
|
||
|
|
1,
|
||
|
|
1,
|
||
|
|
txt={
|
||
|
|
'txt11': 'val11',
|
||
|
|
'txt12': b'val12',
|
||
|
|
'txt13': True
|
||
|
|
})
|
||
|
|
client.srp_client_add_service('ins2',
|
||
|
|
'_meshcop._udp',
|
||
|
|
2000,
|
||
|
|
2,
|
||
|
|
2,
|
||
|
|
txt={
|
||
|
|
'txt21': 'val21',
|
||
|
|
'txt22': b'val22',
|
||
|
|
'txt23': True
|
||
|
|
})
|
||
|
|
self.assertEqual(2, len(client.srp_client_get_services()))
|
||
|
|
self.assertIn(
|
||
|
|
{
|
||
|
|
'instance': 'ins1',
|
||
|
|
'service': '_ipps._tcp',
|
||
|
|
'state': 'ToAdd',
|
||
|
|
'port': 1000,
|
||
|
|
'priority': 1,
|
||
|
|
'weight': 1,
|
||
|
|
}, client.srp_client_get_services())
|
||
|
|
self.assertIn(
|
||
|
|
{
|
||
|
|
'instance': 'ins2',
|
||
|
|
'service': '_meshcop._udp',
|
||
|
|
'state': 'ToAdd',
|
||
|
|
'port': 2000,
|
||
|
|
'priority': 2,
|
||
|
|
'weight': 2,
|
||
|
|
}, client.srp_client_get_services())
|
||
|
|
|
||
|
|
client.wait(3)
|
||
|
|
|
||
|
|
self.assertEqual('Registered', client.srp_client_get_host()['state'])
|
||
|
|
|
||
|
|
srp_server_hosts = server.srp_server_get_hosts()
|
||
|
|
logging.info('srp_server_hosts %r', srp_server_hosts)
|
||
|
|
self.assertEqual(1, len(srp_server_hosts))
|
||
|
|
self.assertEqual('host1.default.service.arpa.', srp_server_hosts[0]['host'])
|
||
|
|
self.assertEqual(False, srp_server_hosts[0]['deleted'])
|
||
|
|
self.assertEqual(
|
||
|
|
{ipaddress.IPv6Address('2001::1'), ipaddress.IPv6Address('2001::2')},
|
||
|
|
set(srp_server_hosts[0]['addresses']))
|
||
|
|
|
||
|
|
srp_server_services = server.srp_server_get_services()
|
||
|
|
logging.info('srp_server_services %r', srp_server_services)
|
||
|
|
self.assertEqual(2, len(srp_server_services))
|
||
|
|
for service in srp_server_services:
|
||
|
|
if service['instance'] == 'ins1._ipps._tcp.default.service.arpa.':
|
||
|
|
self.assertEqual(False, service['deleted'])
|
||
|
|
self.assertEqual(1000, service['port'])
|
||
|
|
self.assertEqual(1, service['priority'])
|
||
|
|
self.assertEqual(1, service['weight'])
|
||
|
|
self.assertEqual('host1.default.service.arpa.', service['host'])
|
||
|
|
self.assertEqual({ipaddress.IPv6Address('2001::1'),
|
||
|
|
ipaddress.IPv6Address('2001::2')}, set(service['addresses']))
|
||
|
|
self.assertEqual({'txt11': b'val11', 'txt12': b'val12', 'txt13': True}, service['txt'])
|
||
|
|
elif service['instance'] == 'ins2._meshcop._udp.default.service.arpa.':
|
||
|
|
self.assertEqual(False, service['deleted'])
|
||
|
|
self.assertEqual(2000, service['port'])
|
||
|
|
self.assertEqual(2, service['priority'])
|
||
|
|
self.assertEqual(2, service['weight'])
|
||
|
|
self.assertEqual('host1.default.service.arpa.', service['host'])
|
||
|
|
self.assertEqual({ipaddress.IPv6Address('2001::1'),
|
||
|
|
ipaddress.IPv6Address('2001::2')}, set(service['addresses']))
|
||
|
|
self.assertEqual({'txt21': b'val21', 'txt22': b'val22', 'txt23': True}, service['txt'])
|
||
|
|
else:
|
||
|
|
self.fail(service)
|
||
|
|
|
||
|
|
def _test_otci_srp_remove(self, client: OTCI, server: OTCI):
|
||
|
|
client.srp_client_remove_host(remove_key_lease=True)
|
||
|
|
client.wait(3)
|
||
|
|
self.assertEqual([], client.srp_client_get_services())
|
||
|
|
self.assertEqual('Removed', client.srp_client_get_host()['state'])
|
||
|
|
self.assertEqual([], server.srp_server_get_hosts())
|
||
|
|
self.assertEqual([], server.srp_server_get_services())
|
||
|
|
|
||
|
|
def _test_otci_example(self, node1, node2):
|
||
|
|
node1.dataset_init_buffer()
|
||
|
|
node1.dataset_set_buffer(network_name='test',
|
||
|
|
network_key='00112233445566778899aabbccddeeff',
|
||
|
|
panid=0xface,
|
||
|
|
channel=11)
|
||
|
|
node1.dataset_commit_buffer('active')
|
||
|
|
|
||
|
|
node1.ifconfig_up()
|
||
|
|
node1.thread_start()
|
||
|
|
node1.wait(10)
|
||
|
|
assert node1.get_state() == "leader"
|
||
|
|
|
||
|
|
node1.commissioner_start()
|
||
|
|
node1.wait(3)
|
||
|
|
|
||
|
|
node1.commissioner_add_joiner("TEST123", eui64='*')
|
||
|
|
|
||
|
|
node2.ifconfig_up()
|
||
|
|
node2.set_router_selection_jitter(1)
|
||
|
|
|
||
|
|
node2.joiner_start("TEST123")
|
||
|
|
node2.wait(10, expect_line="Join success")
|
||
|
|
node2.thread_start()
|
||
|
|
node2.wait(10)
|
||
|
|
assert node2.get_state() == "router"
|
||
|
|
|
||
|
|
def _test_otci_multi_nodes(self, leader, commissioner, child1, child2):
|
||
|
|
self.assertFalse(leader.get_ifconfig_state())
|
||
|
|
|
||
|
|
# ifconfig up
|
||
|
|
leader.ifconfig_up()
|
||
|
|
self.assertTrue(leader.get_ifconfig_state())
|
||
|
|
|
||
|
|
logging.info('leader eui64 = %r', leader.get_eui64())
|
||
|
|
logging.info('leader extpanid = %r', leader.get_extpanid())
|
||
|
|
logging.info('leader networkkey = %r', leader.get_network_key())
|
||
|
|
|
||
|
|
extaddr = leader.get_extaddr()
|
||
|
|
self.assertEqual(16, len(extaddr))
|
||
|
|
int(extaddr, 16)
|
||
|
|
new_extaddr = 'aabbccddeeff0011'
|
||
|
|
leader.set_extaddr(new_extaddr)
|
||
|
|
self.assertEqual(new_extaddr, leader.get_extaddr())
|
||
|
|
|
||
|
|
leader.set_network_name(TEST_NETWORK_NAME)
|
||
|
|
|
||
|
|
leader.set_network_key(TEST_NETWORKKEY)
|
||
|
|
self.assertEqual(TEST_NETWORKKEY, leader.get_network_key())
|
||
|
|
|
||
|
|
leader.set_panid(TEST_PANID)
|
||
|
|
self.assertEqual(TEST_PANID, leader.get_panid())
|
||
|
|
|
||
|
|
leader.set_channel(TEST_CHANNEL)
|
||
|
|
self.assertEqual(TEST_CHANNEL, leader.get_channel())
|
||
|
|
|
||
|
|
leader.set_network_name(TEST_NETWORK_NAME)
|
||
|
|
self.assertEqual(TEST_NETWORK_NAME, leader.get_network_name())
|
||
|
|
|
||
|
|
self.assertEqual('rdn', leader.get_mode())
|
||
|
|
|
||
|
|
leader.thread_start()
|
||
|
|
leader.wait(10)
|
||
|
|
self.assertEqual('leader', leader.get_state())
|
||
|
|
logging.info('leader key sequence counter = %d', leader.get_key_sequence_counter())
|
||
|
|
|
||
|
|
rloc16 = leader.get_rloc16()
|
||
|
|
leader_id = leader.get_router_id()
|
||
|
|
self.assertEqual(rloc16, leader_id << 10)
|
||
|
|
|
||
|
|
commissioner.ifconfig_up()
|
||
|
|
commissioner.set_channel(TEST_CHANNEL)
|
||
|
|
commissioner.set_panid(TEST_PANID)
|
||
|
|
commissioner.set_network_name(TEST_NETWORK_NAME)
|
||
|
|
commissioner.set_router_selection_jitter(1)
|
||
|
|
commissioner.set_network_key(TEST_NETWORKKEY)
|
||
|
|
commissioner.thread_start()
|
||
|
|
|
||
|
|
commissioner.wait(10)
|
||
|
|
|
||
|
|
self.assertEqual('router', commissioner.get_state())
|
||
|
|
|
||
|
|
for dst_ip in leader.get_ipaddrs():
|
||
|
|
statistics = commissioner.ping(dst_ip, size=10, count=10, interval=2, hoplimit=3)
|
||
|
|
self.assertEqual(statistics['transmitted_packets'], 10)
|
||
|
|
self.assertEqual(statistics['received_packets'], 10)
|
||
|
|
self.assertAlmostEqual(statistics['packet_loss'], 0.0, delta=1e-9)
|
||
|
|
rtt = statistics['round_trip_time']
|
||
|
|
self.assertTrue(rtt['min'] - 1e-9 <= rtt['avg'] <= rtt['max'] + 1e-9)
|
||
|
|
commissioner.wait(1)
|
||
|
|
|
||
|
|
self.assertEqual('disabled', commissioner.get_commissioiner_state())
|
||
|
|
commissioner.commissioner_start()
|
||
|
|
commissioner.wait(5)
|
||
|
|
self.assertEqual('active', commissioner.get_commissioiner_state())
|
||
|
|
|
||
|
|
logging.info('commissioner.get_network_id_timeout() = %d', commissioner.get_network_id_timeout())
|
||
|
|
commissioner.set_network_id_timeout(60)
|
||
|
|
self.assertEqual(60, commissioner.get_network_id_timeout())
|
||
|
|
|
||
|
|
commissioner.commissioner_add_joiner('TEST123', eui64='*')
|
||
|
|
commissioner.wait(3)
|
||
|
|
|
||
|
|
child1.ifconfig_up()
|
||
|
|
|
||
|
|
logging.info("child1 discover: %r", child1.discover())
|
||
|
|
logging.info("child1 scan: %r", child1.scan())
|
||
|
|
logging.info("child1 scan energy: %r", child1.scan_energy())
|
||
|
|
|
||
|
|
child1.set_mode('rn')
|
||
|
|
child1.set_router_selection_jitter(1)
|
||
|
|
|
||
|
|
child1.joiner_start('TEST123')
|
||
|
|
logging.info('joiner id = %r', child1.get_joiner_id())
|
||
|
|
child1.wait(10, expect_line="Join success")
|
||
|
|
|
||
|
|
child1.enable_allowlist()
|
||
|
|
child1.disable_allowlist()
|
||
|
|
child1.add_allowlist(commissioner.get_extaddr())
|
||
|
|
child1.remove_allowlist(commissioner.get_extaddr())
|
||
|
|
child1.set_allowlist([commissioner.get_extaddr()])
|
||
|
|
|
||
|
|
child1.thread_start()
|
||
|
|
child1.wait(3)
|
||
|
|
self.assertEqual('child', child1.get_state())
|
||
|
|
|
||
|
|
child1.thread_stop()
|
||
|
|
|
||
|
|
child1.set_mode('n')
|
||
|
|
child1.set_poll_period(1000)
|
||
|
|
self.assertEqual(1000, child1.get_poll_period())
|
||
|
|
|
||
|
|
child1.thread_start()
|
||
|
|
child1.wait(3)
|
||
|
|
self.assertEqual('child', child1.get_state())
|
||
|
|
|
||
|
|
child2.ifconfig_up()
|
||
|
|
child2.set_mode('rn')
|
||
|
|
child2.set_router_selection_jitter(1)
|
||
|
|
|
||
|
|
child2.joiner_start('TEST123')
|
||
|
|
logging.info('joiner id = %r', child2.get_joiner_id())
|
||
|
|
child2.wait(10, expect_line="Join success")
|
||
|
|
|
||
|
|
child2.enable_allowlist()
|
||
|
|
child2.disable_allowlist()
|
||
|
|
child2.add_allowlist(commissioner.get_extaddr())
|
||
|
|
child2.remove_allowlist(commissioner.get_extaddr())
|
||
|
|
child2.set_allowlist([commissioner.get_extaddr()])
|
||
|
|
|
||
|
|
child2.thread_start()
|
||
|
|
child2.wait(3)
|
||
|
|
self.assertEqual('child', child2.get_state())
|
||
|
|
|
||
|
|
child_table = commissioner.get_child_table()
|
||
|
|
logging.info('commissioiner child table: \n%s\n', json.dumps(child_table, indent=True))
|
||
|
|
child_list = commissioner.get_child_list()
|
||
|
|
logging.info('commissioiner child list: %r', child_list)
|
||
|
|
for child_id in child_list:
|
||
|
|
logging.info('child %s info: %r', child_id, commissioner.get_child_info(child_id))
|
||
|
|
|
||
|
|
logging.info('child1 info: %r', commissioner.get_child_info(child1.get_rloc16()))
|
||
|
|
logging.info('child2 info: %r', commissioner.get_child_info(child2.get_rloc16()))
|
||
|
|
|
||
|
|
self.assertEqual(set(commissioner.get_child_list()), set(commissioner.get_child_table().keys()))
|
||
|
|
|
||
|
|
child1.add_ipmaddr('ff04::1')
|
||
|
|
child1.del_ipmaddr('ff04::1')
|
||
|
|
child1.add_ipmaddr('ff04::2')
|
||
|
|
logging.info('child1 ipmaddrs: %r', child1.get_ipmaddrs())
|
||
|
|
self.assertFalse(child1.has_ipmaddr('ff04::1'))
|
||
|
|
self.assertTrue(child1.has_ipmaddr('ff04::2'))
|
||
|
|
|
||
|
|
child1.add_ipaddr('2001::1')
|
||
|
|
child1.del_ipaddr('2001::1')
|
||
|
|
child1.add_ipaddr('2001::2')
|
||
|
|
logging.info('child1 ipaddrs: %r', child1.get_ipaddrs())
|
||
|
|
self.assertFalse(child1.has_ipaddr('2001::1'))
|
||
|
|
self.assertTrue(child1.has_ipaddr('2001::2'))
|
||
|
|
|
||
|
|
logging.info('child ipaddrs: %r', commissioner.get_child_ipaddrs())
|
||
|
|
|
||
|
|
logging.info("EID-to-RLOC cache: %r", leader.get_eidcache())
|
||
|
|
|
||
|
|
logging.info("leader neighbor list: %r", leader.get_neighbor_list())
|
||
|
|
logging.info("leader neighbor table: %r", leader.get_neighbor_table())
|
||
|
|
logging.info("prefixes: %r", commissioner.get_local_prefixes())
|
||
|
|
commissioner.add_prefix('2001::/64')
|
||
|
|
commissioner.register_network_data()
|
||
|
|
commissioner.wait(1)
|
||
|
|
logging.info("prefixes: %r", commissioner.get_local_prefixes())
|
||
|
|
|
||
|
|
self.assertEqual(2, len(leader.get_router_list()))
|
||
|
|
self.assertEqual(2, len(leader.get_router_table()))
|
||
|
|
logging.info('leader router table: %r', leader.get_router_table())
|
||
|
|
self.assertEqual({False, True},
|
||
|
|
set(router.is_link_established for router in leader.get_router_table().values()))
|
||
|
|
|
||
|
|
self.assertFalse(leader.is_singleton())
|
||
|
|
|
||
|
|
statistics = commissioner.ping("ff02::1", size=1, count=10, interval=1, hoplimit=255)
|
||
|
|
self.assertEqual(statistics['transmitted_packets'], 10)
|
||
|
|
self.assertEqual(statistics['received_packets'], 20)
|
||
|
|
rtt = statistics['round_trip_time']
|
||
|
|
self.assertTrue(rtt['min'] - 1e-9 <= rtt['avg'] <= rtt['max'] + 1e-9)
|
||
|
|
|
||
|
|
# Shutdown
|
||
|
|
leader.thread_stop()
|
||
|
|
logging.info("node state: %s", leader.get_state())
|
||
|
|
leader.ifconfig_down()
|
||
|
|
self.assertFalse(leader.get_ifconfig_state())
|
||
|
|
|
||
|
|
leader.close()
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == '__main__':
|
||
|
|
unittest.main()
|