Kaynağa Gözat

CI:add openthread ipv6 ra check in openthread CI

Xu Si Yu 3 yıl önce
ebeveyn
işleme
0a7e204d2e

+ 1 - 0
.gitlab/ci/rules.yml

@@ -88,6 +88,7 @@
   - "components/esp_phy/**/*"
   - "components/ieee802154/**/*"
   - "components/lwip/**/*"
+  - "components/openthread/**/*"
   - "examples/common_components/iperf/**/*"
   - "examples/openthread/**/*"
 

+ 129 - 16
examples/openthread/ot_ci_function.py

@@ -4,6 +4,8 @@
 # this file defines some functions for testing cli and br under pytest framework
 
 import re
+import socket
+import struct
 import subprocess
 import time
 from typing import Tuple, Union
@@ -14,10 +16,12 @@ from pytest_embedded_idf.dut import IdfDut
 
 
 def reset_thread(dut:IdfDut) -> None:
-    time.sleep(1)
+    dut.write(' ')
+    dut.write('state')
+    clean_buffer(dut)
+    wait(dut, 1)
     dut.write('factoryreset')
-    time.sleep(3)
-    dut.expect('OpenThread attached to netif', timeout=10)
+    dut.expect('OpenThread attached to netif', timeout=20)
     dut.write(' ')
     dut.write('state')
 
@@ -92,18 +96,30 @@ def start_thread(dut:IdfDut) -> str:
     return role
 
 
-# config br and cli manually
-def form_network_using_manual_configuration(leader:IdfDut, child:IdfDut, leader_name:str, thread_dataset_model:str,
-                                            thread_dataset:str, wifi:IdfDut, wifi_ssid:str, wifi_psk:str) -> str:
-    time.sleep(3)
-    leader.expect('OpenThread attached to netif', timeout=10)
+def wait_key_str(leader:IdfDut, child:IdfDut) -> None:
+    wait(leader, 1)
+    leader.expect('OpenThread attached to netif', timeout=20)
     leader.write(' ')
     leader.write('state')
-    child.expect('OpenThread attached to netif', timeout=10)
+    child.expect('OpenThread attached to netif', timeout=20)
     child.write(' ')
     child.write('state')
+
+
+def config_network(leader:IdfDut, child:IdfDut, leader_name:str, thread_dataset_model:str,
+                   thread_dataset:str, wifi:IdfDut, wifi_ssid:str, wifi_psk:str) -> str:
+    wait_key_str(leader, child)
+    return form_network_using_manual_configuration(leader, child, leader_name, thread_dataset_model,
+                                                   thread_dataset, wifi, wifi_ssid, wifi_psk)
+
+
+# config br and cli manually
+def form_network_using_manual_configuration(leader:IdfDut, child:IdfDut, leader_name:str, thread_dataset_model:str,
+                                            thread_dataset:str, wifi:IdfDut, wifi_ssid:str, wifi_psk:str) -> str:
     reset_thread(leader)
+    clean_buffer(leader)
     reset_thread(child)
+    clean_buffer(child)
     leader.write('channel 12')
     leader.expect('Done', timeout=2)
     child.write('channel 12')
@@ -130,6 +146,7 @@ def form_network_using_manual_configuration(leader:IdfDut, child:IdfDut, leader_
         child.expect('Done', timeout=2)
     role = start_thread(child)
     assert role == 'child'
+    wait(leader, 10)
     return res
 
 
@@ -152,7 +169,8 @@ def connect_wifi(dut:IdfDut, ssid:str, psk:str, nums:int) -> Tuple[str, int]:
     for order in range(1, nums):
         dut.write('wifi connect -s ' + str(ssid) + ' -p ' + str(psk))
         tmp = dut.expect(pexpect.TIMEOUT, timeout=5)
-        ip_address = re.findall(r'sta ip: (\w+.\w+.\w+.\w+),', str(tmp))[0]
+        if 'sta ip' in str(tmp):
+            ip_address = re.findall(r'sta ip: (\w+.\w+.\w+.\w+),', str(tmp))[0]
         information = dut.expect(r'wifi sta (\w+ \w+ \w+)\W', timeout=5)[1].decode()
         if information == 'is connected successfully':
             break
@@ -166,13 +184,13 @@ def reset_host_interface() -> None:
     try:
         command = 'ifconfig ' + interface_name + ' down'
         subprocess.call(command, shell=True, timeout=5)
-        time.sleep(10)
+        time.sleep(1)
         command = 'ifconfig ' + interface_name + ' up'
         subprocess.call(command, shell=True, timeout=10)
-        time.sleep(20)
+        time.sleep(1)
         flag = True
     finally:
-        time.sleep(10)
+        time.sleep(1)
         assert flag
 
 
@@ -185,10 +203,10 @@ def set_interface_sysctl_options() -> None:
         time.sleep(1)
         command = 'sysctl -w net/ipv6/conf/' + interface_name + '/accept_ra_rt_info_max_plen=128'
         subprocess.call(command, shell=True, timeout=5)
-        time.sleep(5)
+        time.sleep(1)
         flag = True
     finally:
-        time.sleep(5)
+        time.sleep(2)
         assert flag
 
 
@@ -207,7 +225,7 @@ def init_interface_ipv6_address() -> None:
         time.sleep(1)
         flag = True
     finally:
-        time.sleep(5)
+        time.sleep(1)
         assert flag
 
 
@@ -220,3 +238,98 @@ def get_host_interface_name() -> str:
 def clean_buffer(dut:IdfDut) -> None:
     str_length = str(len(dut.expect(pexpect.TIMEOUT, timeout=0.1)))
     dut.expect(r'[\s\S]{%s}' % str(str_length), timeout=10)
+
+
+def check_if_host_receive_ra(br:IdfDut) -> bool:
+    interface_name = get_host_interface_name()
+    clean_buffer(br)
+    br.write('br omrprefix')
+    omrprefix = br.expect(r'\n((?:\w+:){4}):/\d+\r', timeout=5)[1].decode()
+    command = 'ip -6 route | grep ' + str(interface_name)
+    out_str = subprocess.getoutput(command)
+    print('br omrprefix: ', str(omrprefix))
+    print('host route table:\n', str(out_str))
+    return str(omrprefix) in str(out_str)
+
+
+def host_connect_wifi() -> None:
+    command = '. /home/test/wlan_connection_OTTE.sh'
+    subprocess.call(command, shell=True, timeout=30)
+    time.sleep(5)
+
+
+def is_joined_wifi_network(br:IdfDut) -> bool:
+    return check_if_host_receive_ra(br)
+
+
+thread_ipv6_group = 'ff04:0:0:0:0:0:0:125'
+
+
+def check_ipmaddr(dut:IdfDut) -> bool:
+    clean_buffer(dut)
+    dut.write('ipmaddr')
+    info = dut.expect(pexpect.TIMEOUT, timeout=2)
+    if thread_ipv6_group in str(info):
+        return True
+    return False
+
+
+def thread_is_joined_group(dut:IdfDut) -> bool:
+    command = 'mcast join ' + thread_ipv6_group
+    dut.write(command)
+    dut.expect('Done', timeout=2)
+    order = 0
+    while order < 3:
+        if check_ipmaddr(dut):
+            return True
+        dut.write(command)
+        wait(dut, 2)
+        order = order + 1
+    return False
+
+
+host_ipv6_group = 'ff04::125'
+
+
+def host_joined_group() -> bool:
+    interface_name = get_host_interface_name()
+    command = 'netstat -g | grep ' + str(interface_name)
+    out_str = subprocess.getoutput(command)
+    print('groups:\n', str(out_str))
+    return host_ipv6_group in str(out_str)
+
+
+class udp_parameter:
+
+    def __init__(self, group:str='', try_join_udp_group:bool=False, timeout:float=15.0, udp_bytes:bytes=b''):
+        self.group = group
+        self.try_join_udp_group = try_join_udp_group
+        self.timeout = timeout
+        self.udp_bytes = udp_bytes
+
+
+def create_host_udp_server(myudp:udp_parameter) -> None:
+    interface_name = get_host_interface_name()
+    try:
+        print('The host start to create udp server!')
+        if_index = socket.if_nametoindex(interface_name)
+        sock = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
+        sock.bind(('::', 5090))
+        sock.setsockopt(
+            socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP,
+            struct.pack('16si', socket.inet_pton(socket.AF_INET6, myudp.group),
+                        if_index))
+        myudp.try_join_udp_group = True
+        sock.settimeout(myudp.timeout)
+        print('The host start to receive message!')
+        myudp.udp_bytes = (sock.recvfrom(1024))[0]
+        print('The host has received message: ', myudp.udp_bytes)
+    except socket.error:
+        print('The host did not receive message!')
+    finally:
+        print('Close the socket.')
+        sock.close()
+
+
+def wait(dut:IdfDut, wait_time:float) -> None:
+    dut.expect(pexpect.TIMEOUT, timeout=wait_time)

+ 75 - 70
examples/openthread/pytest_otbr.py

@@ -5,9 +5,8 @@
 
 import os.path
 import re
-import socket
-import struct
 import subprocess
+import threading
 import time
 from typing import Tuple
 
@@ -34,32 +33,37 @@ from pytest_embedded_idf.dut import IdfDut
 def fixture_Init_interface() -> bool:
     ocf.init_interface_ipv6_address()
     ocf.reset_host_interface()
+    time.sleep(30)
     ocf.set_interface_sysctl_options()
     return True
 
 
+wifi_ssid = 'OTCITE'
+wifi_psk = 'otcitest888'
+
+
 # Case 1: Thread network formation and attaching
 @pytest.mark.esp32s3
 @pytest.mark.esp32h2
+@pytest.mark.timeout(40 * 60)
 @pytest.mark.i154_multi_dut
-@pytest.mark.flaky(reruns=2, reruns_delay=10)
 @pytest.mark.parametrize(
     'port, config, count, app_path, beta_target, target', [
-        ('/dev/USB_BR|/dev/USB_CLI|/dev/USB_RCP', 'br|cli|rcp', 3,
-         f'{os.path.join(os.path.dirname(__file__), "ot_br")}'
+        ('/dev/USB_RCP|/dev/USB_CLI|/dev/USB_BR', 'rcp|cli|br', 3,
+         f'{os.path.join(os.path.dirname(__file__), "ot_rcp")}'
          f'|{os.path.join(os.path.dirname(__file__), "ot_cli")}'
-         f'|{os.path.join(os.path.dirname(__file__), "ot_rcp")}',
-         'esp32s3|esp32h2beta2|esp32h2beta2', 'esp32s3|esp32h2|esp32h2'),
+         f'|{os.path.join(os.path.dirname(__file__), "ot_br")}',
+         'esp32h2beta2|esp32h2beta2|esp32s3', 'esp32h2|esp32h2|esp32s3'),
     ],
     indirect=True,
 )
-def test_thread_connect(dut:Tuple[IdfDut, IdfDut]) -> None:
-    br = dut[0]
+def test_thread_connect(dut:Tuple[IdfDut, IdfDut, IdfDut]) -> None:
+    br = dut[2]
     cli  = dut[1]
+    dut[0].close()
 
     dataset = '-1'
-    ocf.form_network_using_manual_configuration(br, cli, 'br', 'random', dataset, br, 'OTCITE', '0000')
-    time.sleep(1)
+    ocf.config_network(br, cli, 'br', 'random', dataset, br, wifi_ssid, '0000')
     flag = False
     try:
         cli_mleid_addr = ocf.get_mleid_addr(cli)
@@ -79,32 +83,34 @@ def test_thread_connect(dut:Tuple[IdfDut, IdfDut]) -> None:
 # Case 2: Bidirectional IPv6 connectivity
 @pytest.mark.esp32s3
 @pytest.mark.esp32h2
+@pytest.mark.timeout(40 * 60)
 @pytest.mark.i154_multi_dut
-@pytest.mark.flaky(reruns=5, reruns_delay=10)
 @pytest.mark.parametrize(
     'port, config, count, app_path, beta_target, target', [
-        ('/dev/USB_BR|/dev/USB_CLI|/dev/USB_RCP', 'br|cli|rcp', 3,
-         f'{os.path.join(os.path.dirname(__file__), "ot_br")}'
+        ('/dev/USB_RCP|/dev/USB_CLI|/dev/USB_BR', 'rcp|cli|br', 3,
+         f'{os.path.join(os.path.dirname(__file__), "ot_rcp")}'
          f'|{os.path.join(os.path.dirname(__file__), "ot_cli")}'
-         f'|{os.path.join(os.path.dirname(__file__), "ot_rcp")}',
-         'esp32s3|esp32h2beta2|esp32h2beta2', 'esp32s3|esp32h2|esp32h2'),
+         f'|{os.path.join(os.path.dirname(__file__), "ot_br")}',
+         'esp32h2beta2|esp32h2beta2|esp32s3', 'esp32h2|esp32h2|esp32s3'),
     ],
     indirect=True,
 )
-def test_Bidirectional_IPv6_connectivity(Init_interface:bool, dut: Tuple[IdfDut, IdfDut]) -> None:
-    br = dut[0]
+def test_Bidirectional_IPv6_connectivity(Init_interface:bool, dut: Tuple[IdfDut, IdfDut, IdfDut]) -> None:
+    br = dut[2]
     cli  = dut[1]
     assert Init_interface
+    dut[0].close()
 
     dataset = '-1'
-    ocf.form_network_using_manual_configuration(br, cli, 'br', 'random', dataset, br, 'OTCITE', 'otcitest888')
-    time.sleep(5)
-    cli_global_unicast_addr = ocf.get_global_unicast_addr(cli, br)
+    ocf.config_network(br, cli, 'br', 'random', dataset, br, wifi_ssid, wifi_psk)
     flag = False
     try:
+        assert ocf.is_joined_wifi_network(br)
+        cli_global_unicast_addr = ocf.get_global_unicast_addr(cli, br)
+        print('cli_global_unicast_addr', cli_global_unicast_addr)
         command = 'ping ' + str(cli_global_unicast_addr) + ' -c 10'
-        out_bytes = subprocess.check_output(command, shell=True, timeout=60)
-        out_str = out_bytes.decode('utf-8')
+        out_str = subprocess.getoutput(command)
+        print('ping result:\n', str(out_str))
         role = re.findall(r' (\d+)%', str(out_str))[0]
         assert role != '100'
         interface_name = ocf.get_host_interface_name()
@@ -128,37 +134,36 @@ def test_Bidirectional_IPv6_connectivity(Init_interface:bool, dut: Tuple[IdfDut,
 # Case 3: Multicast forwarding from Wi-Fi to Thread network
 @pytest.mark.esp32s3
 @pytest.mark.esp32h2
+@pytest.mark.timeout(40 * 60)
 @pytest.mark.i154_multi_dut
-@pytest.mark.flaky(reruns=5, reruns_delay=10)
 @pytest.mark.parametrize(
     'port, config, count, app_path, beta_target, target', [
-        ('/dev/USB_BR|/dev/USB_CLI|/dev/USB_RCP', 'br|cli|rcp', 3,
-         f'{os.path.join(os.path.dirname(__file__), "ot_br")}'
+        ('/dev/USB_RCP|/dev/USB_CLI|/dev/USB_BR', 'rcp|cli|br', 3,
+         f'{os.path.join(os.path.dirname(__file__), "ot_rcp")}'
          f'|{os.path.join(os.path.dirname(__file__), "ot_cli")}'
-         f'|{os.path.join(os.path.dirname(__file__), "ot_rcp")}',
-         'esp32s3|esp32h2beta2|esp32h2beta2', 'esp32s3|esp32h2|esp32h2'),
+         f'|{os.path.join(os.path.dirname(__file__), "ot_br")}',
+         'esp32h2beta2|esp32h2beta2|esp32s3', 'esp32h2|esp32h2|esp32s3'),
     ],
     indirect=True,
 )
-def test_multicast_forwarding_A(Init_interface:bool, dut: Tuple[IdfDut, IdfDut]) -> None:
-    br = dut[0]
+def test_multicast_forwarding_A(Init_interface:bool, dut: Tuple[IdfDut, IdfDut, IdfDut]) -> None:
+    br = dut[2]
     cli  = dut[1]
     assert Init_interface
+    dut[0].close()
 
     dataset = '-1'
-    ocf.form_network_using_manual_configuration(br, cli, 'br', 'random', dataset, br, 'OTCITE', 'otcitest888')
-    time.sleep(5)
+    ocf.config_network(br, cli, 'br', 'random', dataset, br, wifi_ssid, wifi_psk)
     flag = False
     try:
+        assert ocf.is_joined_wifi_network(br)
         br.write('bbr')
         br.expect('server16', timeout=2)
-        cli.write('mcast join ff04::125')
-        cli.expect('Done', timeout=2)
-        time.sleep(1)
+        assert ocf.thread_is_joined_group(cli)
         interface_name = ocf.get_host_interface_name()
         command = 'ping -I ' + str(interface_name) + ' -t 64 ff04::125 -c 10'
-        out_bytes = subprocess.check_output(command, shell=True, timeout=60)
-        out_str = out_bytes.decode('utf-8')
+        out_str = subprocess.getoutput(command)
+        print('ping result:\n', str(out_str))
         role = re.findall(r' (\d+)%', str(out_str))[0]
         assert role != '100'
         flag = True
@@ -172,52 +177,52 @@ def test_multicast_forwarding_A(Init_interface:bool, dut: Tuple[IdfDut, IdfDut])
 # Case 4: Multicast forwarding from Thread to Wi-Fi network
 @pytest.mark.esp32s3
 @pytest.mark.esp32h2
+@pytest.mark.timeout(40 * 60)
 @pytest.mark.i154_multi_dut
-@pytest.mark.flaky(reruns=5, reruns_delay=5)
 @pytest.mark.parametrize(
     'port, config, count, app_path, beta_target, target', [
-        ('/dev/USB_BR|/dev/USB_CLI|/dev/USB_RCP', 'br|cli|rcp', 3,
-         f'{os.path.join(os.path.dirname(__file__), "ot_br")}'
+        ('/dev/USB_RCP|/dev/USB_CLI|/dev/USB_BR', 'rcp|cli|br', 3,
+         f'{os.path.join(os.path.dirname(__file__), "ot_rcp")}'
          f'|{os.path.join(os.path.dirname(__file__), "ot_cli")}'
-         f'|{os.path.join(os.path.dirname(__file__), "ot_rcp")}',
-         'esp32s3|esp32h2beta2|esp32h2beta2', 'esp32s3|esp32h2|esp32h2'),
+         f'|{os.path.join(os.path.dirname(__file__), "ot_br")}',
+         'esp32h2beta2|esp32h2beta2|esp32s3', 'esp32h2|esp32h2|esp32s3'),
     ],
     indirect=True,
 )
-def test_multicast_forwarding_B(Init_interface:bool, dut: Tuple[IdfDut, IdfDut]) -> None:
-    br = dut[0]
+def test_multicast_forwarding_B(Init_interface:bool, dut: Tuple[IdfDut, IdfDut, IdfDut]) -> None:
+    br = dut[2]
     cli  = dut[1]
     assert Init_interface
+    dut[0].close()
 
     dataset = '-1'
-    ocf.form_network_using_manual_configuration(br, cli, 'br', 'random', dataset, br, 'OTCITE', 'otcitest888')
-    time.sleep(5)
-    br.write('bbr')
-    br.expect('server16', timeout=2)
-    interface_name = ocf.get_host_interface_name()
-    if_index = socket.if_nametoindex(interface_name)
-    sock = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
-    sock.bind(('::', 5090))
-    sock.setsockopt(
-        socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP,
-        struct.pack('16si', socket.inet_pton(socket.AF_INET6, 'ff04::125'),
-                    if_index))
-    time.sleep(1)
-    cli.write('udp open')
-    cli.expect('Done', timeout=2)
-    cli.write('udp send ff04::125 5090 hello')
-    cli.expect('Done', timeout=2)
-    data = b''
+    ocf.config_network(br, cli, 'br', 'random', dataset, br, wifi_ssid, wifi_psk)
     try:
-        print('The host start to receive message!')
-        sock.settimeout(5)
-        data = (sock.recvfrom(1024))[0]
-        print('The host has received message!')
-    except socket.error:
-        print('The host did not received message!')
+        assert ocf.is_joined_wifi_network(br)
+        br.write('bbr')
+        br.expect('server16', timeout=2)
+        cli.write('udp open')
+        cli.expect('Done', timeout=2)
+        ocf.wait(cli, 1)
+        cli.write('udp open')
+        cli.expect('Already', timeout=2)
+        myudp = ocf.udp_parameter('ff04::125', False, 15.0, b'')
+        udp_mission = threading.Thread(target=ocf.create_host_udp_server, args=(myudp, ))
+        udp_mission.start()
+        start_time = time.time()
+        while not myudp.try_join_udp_group:
+            if (time.time() - start_time) > 10:
+                assert False
+        assert ocf.host_joined_group()
+        for num in range(0, 3):
+            command = 'udp send ff04::125 5090 hello' + str(num)
+            cli.write(command)
+            cli.expect('Done', timeout=2)
+            ocf.wait(cli, 0.5)
+        while udp_mission.is_alive():
+            time.sleep(1)
     finally:
-        sock.close()
         br.write('factoryreset')
         cli.write('factoryreset')
         time.sleep(3)
-    assert data == b'hello'
+    assert b'hello' in myudp.udp_bytes