pytest_otbr.py 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668
  1. # SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
  2. # SPDX-License-Identifier: Unlicense OR CC0-1.0
  3. # !/usr/bin/env python3
  4. import os.path
  5. import re
  6. import subprocess
  7. import threading
  8. import time
  9. from typing import Tuple
  10. import ot_ci_function as ocf
  11. import pexpect
  12. import pytest
  13. from pytest_embedded_idf.dut import IdfDut
  14. # This file contains the test scripts for Thread:
  15. # Case 1: Thread network formation and attaching
  16. # A Thread Border Router forms a Thread network, Thread devices attache to it, then test ping connection between them.
  17. # Case 2: Bidirectional IPv6 connectivity
  18. # Test IPv6 ping connection between Thread device and Linux Host (via Thread Border Router).
  19. # Case 3: Multicast forwarding from Wi-Fi to Thread network
  20. # Thread device joins the multicast group, then test group communication from Wi-Fi to Thread network.
  21. # Case 4: Multicast forwarding from Thread to Wi-Fi network
  22. # Linux Host joins the multicast group, test group communication from Thread to Wi-Fi network.
  23. # Case 5: discover Serice published by Thread device
  24. # Thread device publishes the service, Linux Host discovers the service on Wi-Fi network.
  25. # Case 6: discover Serice published by W-Fi device
  26. # Linux Host device publishes the service on Wi-Fi network, Thread device discovers the service.
  27. # Case 7: ICMP communication via NAT64
  28. # Thread device (IPV6) ping the host device (IPV4) via NAT64.
  29. # Case 8: UDP communication via NAT64
  30. # Thread device (IPV6) send udp message to the host device (IPV4) via NAT64.
  31. # Case 9: TCP communication via NAT64
  32. # Thread device (IPV6) send tcp message to the host device (IPV4) via NAT64.
  33. @pytest.fixture(scope='module', name='Init_avahi')
  34. def fixture_Init_avahi() -> bool:
  35. print('Init Avahi')
  36. ocf.start_avahi()
  37. time.sleep(10)
  38. return True
  39. @pytest.fixture(name='Init_interface')
  40. def fixture_Init_interface() -> bool:
  41. print('Init interface')
  42. ocf.init_interface_ipv6_address()
  43. ocf.reset_host_interface()
  44. time.sleep(30)
  45. ocf.set_interface_sysctl_options()
  46. return True
  47. default_br_ot_para = ocf.thread_parameter('leader', '', '12', '7766554433221100', True)
  48. default_br_wifi_para = ocf.wifi_parameter('OTCITE', 'otcitest888', 10)
  49. default_cli_ot_para = ocf.thread_parameter('router', '', '', '', False)
  50. # Case 1: Thread network formation and attaching
  51. @pytest.mark.supported_targets
  52. @pytest.mark.esp32h2
  53. @pytest.mark.esp32c6
  54. @pytest.mark.openthread_br
  55. @pytest.mark.flaky(reruns=1, reruns_delay=1)
  56. @pytest.mark.parametrize(
  57. 'config, count, app_path, target', [
  58. ('rcp|cli_h2|br', 3,
  59. f'{os.path.join(os.path.dirname(__file__), "ot_rcp")}'
  60. f'|{os.path.join(os.path.dirname(__file__), "ot_cli")}'
  61. f'|{os.path.join(os.path.dirname(__file__), "ot_br")}',
  62. 'esp32c6|esp32h2|esp32s3'),
  63. ],
  64. indirect=True,
  65. )
  66. def test_thread_connect(dut:Tuple[IdfDut, IdfDut, IdfDut]) -> None:
  67. br = dut[2]
  68. cli_h2 = dut[1]
  69. dut[0].serial.stop_redirect_thread()
  70. cli_list = [cli_h2]
  71. router_extaddr_list = ['7766554433221101']
  72. ocf.init_thread(br)
  73. for cli in cli_list:
  74. ocf.init_thread(cli)
  75. br_ot_para = default_br_ot_para
  76. ocf.joinThreadNetwork(br, br_ot_para)
  77. cli_ot_para = default_cli_ot_para
  78. cli_ot_para.dataset = ocf.getDataset(br)
  79. try:
  80. order = 0
  81. for cli in cli_list:
  82. cli_ot_para.exaddr = router_extaddr_list[order]
  83. order = order + 1
  84. ocf.joinThreadNetwork(cli, cli_ot_para)
  85. for cli in cli_list:
  86. cli_mleid_addr = ocf.get_mleid_addr(cli)
  87. br_mleid_addr = ocf.get_mleid_addr(br)
  88. rx_nums = ocf.ot_ping(cli, br_mleid_addr, 5)[1]
  89. assert rx_nums == 5
  90. rx_nums = ocf.ot_ping(br, cli_mleid_addr, 5)[1]
  91. assert rx_nums == 5
  92. finally:
  93. ocf.execute_command(br, 'factoryreset')
  94. for cli in cli_list:
  95. ocf.execute_command(cli, 'factoryreset')
  96. time.sleep(3)
  97. # Form a Wi-Fi/Thread network with a Wi-Fi host, a border router and a Thread end device
  98. # Topology:
  99. # Border_Router
  100. # / \
  101. # / \
  102. # Wi-FI_Host Thread_End_Device
  103. def formBasicWiFiThreadNetwork(br:IdfDut, cli:IdfDut) -> None:
  104. ocf.init_thread(br)
  105. ocf.init_thread(cli)
  106. ocf.joinWiFiNetwork(br, default_br_wifi_para)
  107. ocf.joinThreadNetwork(br, default_br_ot_para)
  108. ot_para = default_cli_ot_para
  109. ot_para.dataset = ocf.getDataset(br)
  110. ot_para.exaddr = '7766554433221101'
  111. ocf.joinThreadNetwork(cli, ot_para)
  112. ocf.wait(cli,10)
  113. # Case 2: Bidirectional IPv6 connectivity
  114. @pytest.mark.supported_targets
  115. @pytest.mark.esp32h2
  116. @pytest.mark.esp32c6
  117. @pytest.mark.openthread_br
  118. @pytest.mark.flaky(reruns=1, reruns_delay=1)
  119. @pytest.mark.parametrize(
  120. 'config, count, app_path, target', [
  121. ('rcp|cli_h2|br', 3,
  122. f'{os.path.join(os.path.dirname(__file__), "ot_rcp")}'
  123. f'|{os.path.join(os.path.dirname(__file__), "ot_cli")}'
  124. f'|{os.path.join(os.path.dirname(__file__), "ot_br")}',
  125. 'esp32c6|esp32h2|esp32s3'),
  126. ],
  127. indirect=True,
  128. )
  129. def test_Bidirectional_IPv6_connectivity(Init_interface:bool, dut: Tuple[IdfDut, IdfDut, IdfDut]) -> None:
  130. br = dut[2]
  131. cli = dut[1]
  132. assert Init_interface
  133. dut[0].serial.stop_redirect_thread()
  134. formBasicWiFiThreadNetwork(br, cli)
  135. try:
  136. assert ocf.is_joined_wifi_network(br)
  137. cli_global_unicast_addr = ocf.get_global_unicast_addr(cli, br)
  138. print('cli_global_unicast_addr', cli_global_unicast_addr)
  139. command = 'ping ' + str(cli_global_unicast_addr) + ' -c 10'
  140. out_str = subprocess.getoutput(command)
  141. print('ping result:\n', str(out_str))
  142. role = re.findall(r' (\d+)%', str(out_str))[0]
  143. assert role != '100'
  144. interface_name = ocf.get_host_interface_name()
  145. command = 'ifconfig ' + interface_name + ' | grep inet6 | grep global'
  146. out_bytes = subprocess.check_output(command, shell=True, timeout=5)
  147. out_str = out_bytes.decode('utf-8')
  148. onlinkprefix = ocf.get_onlinkprefix(br)
  149. host_global_unicast_addr = re.findall(r'\W+(%s(?:\w+:){3}\w+)\W+' % onlinkprefix, str(out_str))
  150. rx_nums = 0
  151. for ip_addr in host_global_unicast_addr:
  152. txrx_nums = ocf.ot_ping(cli, str(ip_addr), 5)
  153. rx_nums = rx_nums + int(txrx_nums[1])
  154. assert rx_nums != 0
  155. finally:
  156. ocf.execute_command(br, 'factoryreset')
  157. ocf.execute_command(cli, 'factoryreset')
  158. time.sleep(3)
  159. # Case 3: Multicast forwarding from Wi-Fi to Thread network
  160. @pytest.mark.supported_targets
  161. @pytest.mark.esp32h2
  162. @pytest.mark.esp32c6
  163. @pytest.mark.openthread_br
  164. @pytest.mark.flaky(reruns=1, reruns_delay=1)
  165. @pytest.mark.parametrize(
  166. 'config, count, app_path, target', [
  167. ('rcp|cli_h2|br', 3,
  168. f'{os.path.join(os.path.dirname(__file__), "ot_rcp")}'
  169. f'|{os.path.join(os.path.dirname(__file__), "ot_cli")}'
  170. f'|{os.path.join(os.path.dirname(__file__), "ot_br")}',
  171. 'esp32c6|esp32h2|esp32s3'),
  172. ],
  173. indirect=True,
  174. )
  175. def test_multicast_forwarding_A(Init_interface:bool, dut: Tuple[IdfDut, IdfDut, IdfDut]) -> None:
  176. br = dut[2]
  177. cli = dut[1]
  178. assert Init_interface
  179. dut[0].serial.stop_redirect_thread()
  180. formBasicWiFiThreadNetwork(br, cli)
  181. try:
  182. assert ocf.is_joined_wifi_network(br)
  183. ocf.execute_command(br, 'bbr')
  184. br.expect('server16', timeout=5)
  185. assert ocf.thread_is_joined_group(cli)
  186. interface_name = ocf.get_host_interface_name()
  187. command = 'ping -I ' + str(interface_name) + ' -t 64 ff04::125 -c 10'
  188. out_str = subprocess.getoutput(command)
  189. print('ping result:\n', str(out_str))
  190. role = re.findall(r' (\d+)%', str(out_str))[0]
  191. assert role != '100'
  192. ocf.execute_command(cli, 'udp open')
  193. cli.expect('Done', timeout=5)
  194. ocf.execute_command(cli, 'udp bind :: 12350')
  195. cli.expect('Done', timeout=5)
  196. ocf.clean_buffer(cli)
  197. target_udp = ocf.udp_parameter('INET6', 'ff04::125', 12350, '', False, 15.0, b'hello')
  198. ocf.host_udp_send_message(target_udp)
  199. cli.expect('hello', timeout=5)
  200. ocf.execute_command(cli, 'udp close')
  201. cli.expect('Done', timeout=5)
  202. finally:
  203. ocf.execute_command(br, 'factoryreset')
  204. ocf.execute_command(cli, 'factoryreset')
  205. time.sleep(3)
  206. # Case 4: Multicast forwarding from Thread to Wi-Fi network
  207. @pytest.mark.supported_targets
  208. @pytest.mark.esp32h2
  209. @pytest.mark.esp32c6
  210. @pytest.mark.openthread_br
  211. @pytest.mark.flaky(reruns=1, reruns_delay=1)
  212. @pytest.mark.parametrize(
  213. 'config, count, app_path, target', [
  214. ('rcp|cli_h2|br', 3,
  215. f'{os.path.join(os.path.dirname(__file__), "ot_rcp")}'
  216. f'|{os.path.join(os.path.dirname(__file__), "ot_cli")}'
  217. f'|{os.path.join(os.path.dirname(__file__), "ot_br")}',
  218. 'esp32c6|esp32h2|esp32s3'),
  219. ],
  220. indirect=True,
  221. )
  222. def test_multicast_forwarding_B(Init_interface:bool, dut: Tuple[IdfDut, IdfDut, IdfDut]) -> None:
  223. br = dut[2]
  224. cli = dut[1]
  225. assert Init_interface
  226. dut[0].serial.stop_redirect_thread()
  227. formBasicWiFiThreadNetwork(br, cli)
  228. try:
  229. assert ocf.is_joined_wifi_network(br)
  230. ocf.execute_command(br, 'bbr')
  231. br.expect('server16', timeout=5)
  232. ocf.execute_command(cli, 'udp open')
  233. cli.expect('Done', timeout=5)
  234. ocf.wait(cli, 3)
  235. myudp = ocf.udp_parameter('INET6', '::', 5090, 'ff04::125', False, 15.0, b'')
  236. udp_mission = threading.Thread(target=ocf.create_host_udp_server, args=(myudp, ))
  237. udp_mission.start()
  238. start_time = time.time()
  239. while not myudp.init_flag:
  240. if (time.time() - start_time) > 10:
  241. assert False
  242. for num in range(0, 3):
  243. command = 'udp send ff04::125 5090 hello' + str(num)
  244. ocf.execute_command(cli, command)
  245. cli.expect('Done', timeout=5)
  246. ocf.wait(cli, 0.5)
  247. while udp_mission.is_alive():
  248. time.sleep(1)
  249. finally:
  250. ocf.execute_command(br, 'factoryreset')
  251. ocf.execute_command(cli, 'factoryreset')
  252. time.sleep(3)
  253. assert b'hello' in myudp.udp_bytes
  254. # Case 5: discover dervice published by Thread device
  255. @pytest.mark.supported_targets
  256. @pytest.mark.esp32h2
  257. @pytest.mark.esp32c6
  258. @pytest.mark.openthread_br
  259. @pytest.mark.flaky(reruns=1, reruns_delay=1)
  260. @pytest.mark.parametrize(
  261. 'config, count, app_path, target', [
  262. ('rcp|cli_h2|br', 3,
  263. f'{os.path.join(os.path.dirname(__file__), "ot_rcp")}'
  264. f'|{os.path.join(os.path.dirname(__file__), "ot_cli")}'
  265. f'|{os.path.join(os.path.dirname(__file__), "ot_br")}',
  266. 'esp32c6|esp32h2|esp32s3'),
  267. ],
  268. indirect=True,
  269. )
  270. def test_service_discovery_of_Thread_device(Init_interface:bool, Init_avahi:bool, dut: Tuple[IdfDut, IdfDut, IdfDut]) -> None:
  271. br = dut[2]
  272. cli = dut[1]
  273. assert Init_interface
  274. assert Init_avahi
  275. dut[0].serial.stop_redirect_thread()
  276. formBasicWiFiThreadNetwork(br, cli)
  277. try:
  278. assert ocf.is_joined_wifi_network(br)
  279. command = 'avahi-browse -rt _testyyy._udp'
  280. out_str = subprocess.getoutput(command)
  281. print('avahi-browse:\n', str(out_str))
  282. assert 'myTest' not in str(out_str)
  283. hostname = 'myTest'
  284. command = 'srp client host name ' + hostname
  285. ocf.execute_command(cli, command)
  286. cli.expect('Done', timeout=5)
  287. cli_global_unicast_addr = ocf.get_global_unicast_addr(cli, br)
  288. print('cli_global_unicast_addr', cli_global_unicast_addr)
  289. command = 'srp client host address ' + str(cli_global_unicast_addr)
  290. ocf.execute_command(cli, command)
  291. cli.expect('Done', timeout=5)
  292. port = '12348'
  293. command = 'srp client service add my-service _testyyy._udp ' + port
  294. ocf.execute_command(cli, command)
  295. cli.expect('Done', timeout=5)
  296. ocf.execute_command(cli, 'srp client autostart enable')
  297. cli.expect('Done', timeout=5)
  298. ocf.wait(cli, 3)
  299. command = 'avahi-browse -rt _testyyy._udp'
  300. out_str = subprocess.getoutput(command)
  301. print('avahi-browse:\n', str(out_str))
  302. assert 'myTest' in str(out_str)
  303. finally:
  304. ocf.execute_command(br, 'factoryreset')
  305. ocf.execute_command(cli, 'factoryreset')
  306. time.sleep(3)
  307. # Case 6: discover dervice published by Wi-Fi device
  308. @pytest.mark.supported_targets
  309. @pytest.mark.esp32h2
  310. @pytest.mark.esp32c6
  311. @pytest.mark.openthread_br
  312. @pytest.mark.flaky(reruns=1, reruns_delay=1)
  313. @pytest.mark.parametrize(
  314. 'config, count, app_path, target', [
  315. ('rcp|cli_h2|br', 3,
  316. f'{os.path.join(os.path.dirname(__file__), "ot_rcp")}'
  317. f'|{os.path.join(os.path.dirname(__file__), "ot_cli")}'
  318. f'|{os.path.join(os.path.dirname(__file__), "ot_br")}',
  319. 'esp32c6|esp32h2|esp32s3'),
  320. ],
  321. indirect=True,
  322. )
  323. def test_service_discovery_of_WiFi_device(Init_interface:bool, Init_avahi:bool, dut: Tuple[IdfDut, IdfDut, IdfDut]) -> None:
  324. br = dut[2]
  325. cli = dut[1]
  326. assert Init_interface
  327. assert Init_avahi
  328. dut[0].serial.stop_redirect_thread()
  329. formBasicWiFiThreadNetwork(br, cli)
  330. try:
  331. assert ocf.is_joined_wifi_network(br)
  332. br_global_unicast_addr = ocf.get_global_unicast_addr(br, br)
  333. command = 'dns config ' + br_global_unicast_addr
  334. ocf.execute_command(cli, command)
  335. cli.expect('Done', timeout=5)
  336. ocf.wait(cli, 1)
  337. domain_name = ocf.get_domain()
  338. print('domain name is: ', domain_name)
  339. command = 'dns resolve ' + domain_name + '.default.service.arpa.'
  340. ocf.execute_command(cli, command)
  341. cli.expect('TTL', timeout=10)
  342. cli.expect('Done', timeout=10)
  343. command = 'dns browse _testxxx._udp.default.service.arpa'
  344. tmp = ocf.get_ouput_string(cli, command, 5)
  345. assert 'Port:12347' not in str(tmp)
  346. ocf.host_publish_service()
  347. ocf.wait(cli, 5)
  348. command = 'dns browse _testxxx._udp.default.service.arpa'
  349. tmp = ocf.get_ouput_string(cli, command, 5)
  350. assert 'response for _testxxx' in str(tmp)
  351. assert 'Port:12347' in str(tmp)
  352. command = 'dns browse _testxxx._udp.default.service.arpa'
  353. tmp = ocf.get_ouput_string(cli, command, 5)
  354. ocf.execute_command(cli, 'dns service testxxx _testxxx._udp.default.service.arpa.')
  355. tmp = cli.expect(pexpect.TIMEOUT, timeout=5)
  356. assert 'response for testxxx' in str(tmp)
  357. assert 'Port:12347' in str(tmp)
  358. finally:
  359. ocf.host_close_service()
  360. ocf.execute_command(br, 'factoryreset')
  361. ocf.execute_command(cli, 'factoryreset')
  362. time.sleep(3)
  363. # Case 7: ICMP communication via NAT64
  364. @pytest.mark.supported_targets
  365. @pytest.mark.esp32h2
  366. @pytest.mark.esp32c6
  367. @pytest.mark.openthread_br
  368. @pytest.mark.flaky(reruns=1, reruns_delay=1)
  369. @pytest.mark.parametrize(
  370. 'config, count, app_path, target', [
  371. ('rcp|cli_h2|br', 3,
  372. f'{os.path.join(os.path.dirname(__file__), "ot_rcp")}'
  373. f'|{os.path.join(os.path.dirname(__file__), "ot_cli")}'
  374. f'|{os.path.join(os.path.dirname(__file__), "ot_br")}',
  375. 'esp32c6|esp32h2|esp32s3'),
  376. ],
  377. indirect=True,
  378. )
  379. def test_ICMP_NAT64(Init_interface:bool, dut: Tuple[IdfDut, IdfDut, IdfDut]) -> None:
  380. br = dut[2]
  381. cli = dut[1]
  382. assert Init_interface
  383. dut[0].serial.stop_redirect_thread()
  384. formBasicWiFiThreadNetwork(br, cli)
  385. try:
  386. assert ocf.is_joined_wifi_network(br)
  387. host_ipv4_address = ocf.get_host_ipv4_address()
  388. print('host_ipv4_address: ', host_ipv4_address)
  389. rx_nums = ocf.ot_ping(cli, str(host_ipv4_address), 5)[1]
  390. assert rx_nums != 0
  391. finally:
  392. ocf.execute_command(br, 'factoryreset')
  393. ocf.execute_command(cli, 'factoryreset')
  394. time.sleep(3)
  395. # Case 8: UDP communication via NAT64
  396. @pytest.mark.supported_targets
  397. @pytest.mark.esp32h2
  398. @pytest.mark.esp32c6
  399. @pytest.mark.openthread_br
  400. @pytest.mark.flaky(reruns=1, reruns_delay=1)
  401. @pytest.mark.parametrize(
  402. 'config, count, app_path, target', [
  403. ('rcp|cli_h2|br', 3,
  404. f'{os.path.join(os.path.dirname(__file__), "ot_rcp")}'
  405. f'|{os.path.join(os.path.dirname(__file__), "ot_cli")}'
  406. f'|{os.path.join(os.path.dirname(__file__), "ot_br")}',
  407. 'esp32c6|esp32h2|esp32s3'),
  408. ],
  409. indirect=True,
  410. )
  411. def test_UDP_NAT64(Init_interface:bool, dut: Tuple[IdfDut, IdfDut, IdfDut]) -> None:
  412. br = dut[2]
  413. cli = dut[1]
  414. assert Init_interface
  415. dut[0].serial.stop_redirect_thread()
  416. formBasicWiFiThreadNetwork(br, cli)
  417. try:
  418. assert ocf.is_joined_wifi_network(br)
  419. ocf.execute_command(br, 'bbr')
  420. br.expect('server16', timeout=5)
  421. ocf.execute_command(cli, 'udp open')
  422. cli.expect('Done', timeout=5)
  423. ocf.wait(cli, 3)
  424. host_ipv4_address = ocf.get_host_ipv4_address()
  425. print('host_ipv4_address: ', host_ipv4_address)
  426. myudp = ocf.udp_parameter('INET4', host_ipv4_address, 5090, '', False, 15.0, b'')
  427. udp_mission = threading.Thread(target=ocf.create_host_udp_server, args=(myudp, ))
  428. udp_mission.start()
  429. start_time = time.time()
  430. while not myudp.init_flag:
  431. if (time.time() - start_time) > 10:
  432. assert False
  433. for num in range(0, 3):
  434. command = 'udp send ' + host_ipv4_address + ' 5090 hello' + str(num)
  435. ocf.execute_command(cli, command)
  436. cli.expect('Done', timeout=5)
  437. ocf.wait(cli, 0.5)
  438. while udp_mission.is_alive():
  439. time.sleep(1)
  440. finally:
  441. ocf.execute_command(br, 'factoryreset')
  442. ocf.execute_command(cli, 'factoryreset')
  443. time.sleep(3)
  444. assert b'hello' in myudp.udp_bytes
  445. # Case 9: TCP communication via NAT64
  446. @pytest.mark.supported_targets
  447. @pytest.mark.esp32h2
  448. @pytest.mark.esp32c6
  449. @pytest.mark.openthread_br
  450. @pytest.mark.flaky(reruns=1, reruns_delay=1)
  451. @pytest.mark.parametrize(
  452. 'config, count, app_path, target', [
  453. ('rcp|cli_h2|br', 3,
  454. f'{os.path.join(os.path.dirname(__file__), "ot_rcp")}'
  455. f'|{os.path.join(os.path.dirname(__file__), "ot_cli")}'
  456. f'|{os.path.join(os.path.dirname(__file__), "ot_br")}',
  457. 'esp32c6|esp32h2|esp32s3'),
  458. ],
  459. indirect=True,
  460. )
  461. def test_TCP_NAT64(Init_interface:bool, dut: Tuple[IdfDut, IdfDut, IdfDut]) -> None:
  462. br = dut[2]
  463. cli = dut[1]
  464. assert Init_interface
  465. dut[0].serial.stop_redirect_thread()
  466. formBasicWiFiThreadNetwork(br, cli)
  467. try:
  468. assert ocf.is_joined_wifi_network(br)
  469. ocf.execute_command(br, 'bbr')
  470. br.expect('server16', timeout=5)
  471. ocf.execute_command(cli, 'tcpsockclient open')
  472. cli.expect('Done', timeout=5)
  473. ocf.wait(cli, 3)
  474. host_ipv4_address = ocf.get_host_ipv4_address()
  475. connect_address = ocf.get_ipv6_from_ipv4(host_ipv4_address, br)
  476. print('connect_address is: ', connect_address)
  477. mytcp = ocf.tcp_parameter('INET4', host_ipv4_address, 12345, False, False, 15.0, b'')
  478. tcp_mission = threading.Thread(target=ocf.create_host_tcp_server, args=(mytcp, ))
  479. tcp_mission.start()
  480. start_time = time.time()
  481. while not mytcp.listen_flag:
  482. if (time.time() - start_time) > 10:
  483. assert False
  484. command = 'tcpsockclient connect ' + connect_address + ' 12345'
  485. ocf.execute_command(cli, command)
  486. cli.expect('Successfully connected', timeout=10)
  487. start_time = time.time()
  488. while not mytcp.recv_flag:
  489. if (time.time() - start_time) > 10:
  490. assert False
  491. command = 'tcpsockclient send hello'
  492. ocf.execute_command(cli, command)
  493. cli.expect('Done', timeout=5)
  494. while tcp_mission.is_alive():
  495. time.sleep(1)
  496. finally:
  497. ocf.execute_command(br, 'factoryreset')
  498. ocf.execute_command(cli, 'factoryreset')
  499. time.sleep(3)
  500. assert b'hello' in mytcp.tcp_bytes
  501. # Case 10: Sleepy device test
  502. @pytest.mark.esp32h2
  503. @pytest.mark.esp32c6
  504. @pytest.mark.openthread_sleep
  505. @pytest.mark.parametrize(
  506. 'config, count, app_path, target', [
  507. ('cli_c6|sleepy_h2', 2,
  508. f'{os.path.join(os.path.dirname(__file__), "ot_cli")}'
  509. f'|{os.path.join(os.path.dirname(__file__), "ot_sleepy_device")}',
  510. 'esp32c6|esp32h2'),
  511. ],
  512. indirect=True,
  513. )
  514. def test_ot_sleepy_device(dut: Tuple[IdfDut, IdfDut]) -> None:
  515. leader = dut[0]
  516. sleepy_device = dut[1]
  517. try:
  518. ocf.init_thread(leader)
  519. time.sleep(3)
  520. leader_para = ocf.thread_parameter('leader', '', '12', '7766554433221100', False)
  521. leader_para.setnetworkname('OpenThread-ESP')
  522. leader_para.setpanid('0x1234')
  523. leader_para.setextpanid('dead00beef00cafe')
  524. leader_para.setnetworkkey('aabbccddeeff00112233445566778899')
  525. leader_para.setpskc('104810e2315100afd6bc9215a6bfac53')
  526. ocf.joinThreadNetwork(leader, leader_para)
  527. ocf.wait(leader, 5)
  528. ocf.clean_buffer(sleepy_device)
  529. sleepy_device.serial.hard_reset()
  530. sleepy_device.expect('detached -> child', timeout=20)
  531. sleepy_device.expect('PMU_SLEEP_PD_TOP: True', timeout=10)
  532. sleepy_device.expect('PMU_SLEEP_PD_MODEM: True', timeout=20)
  533. output = sleepy_device.expect(pexpect.TIMEOUT, timeout=5)
  534. assert 'rst:' not in str(output) and 'boot:' not in str(output)
  535. finally:
  536. ocf.execute_command(leader, 'factoryreset')
  537. time.sleep(3)
  538. # Case 11: Basic startup Test of BR
  539. @pytest.mark.supported_targets
  540. @pytest.mark.esp32h2
  541. @pytest.mark.esp32c6
  542. @pytest.mark.openthread_br
  543. @pytest.mark.flaky(reruns=1, reruns_delay=1)
  544. @pytest.mark.parametrize(
  545. 'config, count, app_path, target', [
  546. ('rcp|br', 2,
  547. f'{os.path.join(os.path.dirname(__file__), "ot_rcp")}'
  548. f'|{os.path.join(os.path.dirname(__file__), "ot_br")}',
  549. 'esp32c6|esp32s3'),
  550. ],
  551. indirect=True,
  552. )
  553. def test_basic_startup(dut: Tuple[IdfDut, IdfDut]) -> None:
  554. br = dut[1]
  555. dut[0].serial.stop_redirect_thread()
  556. try:
  557. ocf.init_thread(br)
  558. time.sleep(3)
  559. ocf.clean_buffer(br)
  560. ocf.execute_command(br, 'ifconfig up')
  561. br.expect('Done', timeout=5)
  562. ocf.execute_command(br, 'thread start')
  563. br.expect('Done', timeout=5)
  564. assert ocf.wait_for_join(br, 'leader')
  565. ocf.reset_thread(br)
  566. ocf.joinWiFiNetwork(br, default_br_wifi_para)
  567. ocf.execute_command(br, 'ifconfig up')
  568. br.expect('Done', timeout=5)
  569. ocf.execute_command(br, 'thread start')
  570. br.expect('Done', timeout=5)
  571. assert ocf.wait_for_join(br, 'leader')
  572. finally:
  573. ocf.execute_command(br, 'factoryreset')
  574. time.sleep(3)
  575. # Case 12: Curl a website via DNS and NAT64
  576. @pytest.mark.supported_targets
  577. @pytest.mark.esp32h2
  578. @pytest.mark.esp32c6
  579. @pytest.mark.openthread_bbr
  580. @pytest.mark.flaky(reruns=1, reruns_delay=1)
  581. @pytest.mark.parametrize(
  582. 'config, count, app_path, target', [
  583. ('rcp|cli_h2|br', 3,
  584. f'{os.path.join(os.path.dirname(__file__), "ot_rcp")}'
  585. f'|{os.path.join(os.path.dirname(__file__), "ot_cli")}'
  586. f'|{os.path.join(os.path.dirname(__file__), "ot_br")}',
  587. 'esp32c6|esp32h2|esp32s3'),
  588. ],
  589. indirect=True,
  590. )
  591. def test_NAT64_DNS(Init_interface:bool, dut: Tuple[IdfDut, IdfDut, IdfDut]) -> None:
  592. br = dut[2]
  593. cli = dut[1]
  594. assert Init_interface
  595. dut[0].serial.stop_redirect_thread()
  596. formBasicWiFiThreadNetwork(br, cli)
  597. try:
  598. ocf.execute_command(br, 'bbr')
  599. br.expect('server16', timeout=5)
  600. ocf.execute_command(cli, 'dns64server 8.8.8.8')
  601. cli.expect('Done', timeout=5)
  602. command = 'curl http://www.espressif.com'
  603. message = ocf.get_ouput_string(cli, command, 10)
  604. assert '<html>' in str(message)
  605. assert '301 Moved Permanently' in str(message)
  606. finally:
  607. ocf.execute_command(br, 'factoryreset')
  608. ocf.execute_command(cli, 'factoryreset')
  609. time.sleep(3)