ot_ci_function.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475
  1. # SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
  2. # SPDX-License-Identifier: Unlicense OR CC0-1.0
  3. # !/usr/bin/env python3
  4. # this file defines some functions for testing cli and br under pytest framework
  5. import re
  6. import socket
  7. import struct
  8. import subprocess
  9. import time
  10. from typing import Tuple, Union
  11. import netifaces
  12. import pexpect
  13. from pytest_embedded_idf.dut import IdfDut
  14. def reset_thread(dut:IdfDut) -> None:
  15. dut.write(' ')
  16. dut.write('state')
  17. clean_buffer(dut)
  18. wait(dut, 1)
  19. dut.write('factoryreset')
  20. dut.expect('OpenThread attached to netif', timeout=20)
  21. dut.write(' ')
  22. dut.write('state')
  23. # config thread
  24. def config_thread(dut:IdfDut, model:str, dataset:str='0') -> Union[str, None]:
  25. if model == 'random':
  26. dut.write('dataset init new')
  27. dut.expect('Done', timeout=5)
  28. dut.write('dataset commit active')
  29. dut.expect('Done', timeout=5)
  30. dut.write('ifconfig up')
  31. dut.expect('Done', timeout=5)
  32. dut.write('dataset active -x') # get dataset
  33. dut_data = dut.expect(r'\n(\w{212})\r', timeout=5)[1].decode()
  34. return str(dut_data)
  35. if model == 'appointed':
  36. tmp = 'dataset set active ' + str(dataset)
  37. dut.write(tmp)
  38. dut.expect('Done', timeout=5)
  39. dut.write('ifconfig up')
  40. dut.expect('Done', timeout=5)
  41. return None
  42. return None
  43. # get the mleid address of the thread
  44. def get_mleid_addr(dut:IdfDut) -> str:
  45. dut_adress = ''
  46. clean_buffer(dut)
  47. dut.write('ipaddr mleid')
  48. dut_adress = dut.expect(r'\n((?:\w+:){7}\w+)\r', timeout=5)[1].decode()
  49. return dut_adress
  50. # get the rloc address of the thread
  51. def get_rloc_addr(dut:IdfDut) -> str:
  52. dut_adress = ''
  53. clean_buffer(dut)
  54. dut.write('ipaddr rloc')
  55. dut_adress = dut.expect(r'\n((?:\w+:){7}\w+)\r', timeout=5)[1].decode()
  56. return dut_adress
  57. # get the linklocal address of the thread
  58. def get_linklocal_addr(dut:IdfDut) -> str:
  59. dut_adress = ''
  60. clean_buffer(dut)
  61. dut.write('ipaddr linklocal')
  62. dut_adress = dut.expect(r'\n((?:\w+:){7}\w+)\r', timeout=5)[1].decode()
  63. return dut_adress
  64. # get the global unicast address of the thread:
  65. def get_global_unicast_addr(dut:IdfDut, br:IdfDut) -> str:
  66. dut_adress = ''
  67. clean_buffer(br)
  68. br.write('br omrprefix')
  69. omrprefix = br.expect(r'\n((?:\w+:){4}):/\d+\r', timeout=5)[1].decode()
  70. clean_buffer(dut)
  71. dut.write('ipaddr')
  72. dut_adress = dut.expect(r'(%s(?:\w+:){3}\w+)\r' % str(omrprefix), timeout=5)[1].decode()
  73. return dut_adress
  74. # start thread
  75. def start_thread(dut:IdfDut) -> str:
  76. role = ''
  77. dut.write('thread start')
  78. tmp = dut.expect(r'Role detached -> (\w+)\W', timeout=20)[0]
  79. role = re.findall(r'Role detached -> (\w+)\W', str(tmp))[0]
  80. return role
  81. def wait_key_str(leader:IdfDut, child:IdfDut) -> None:
  82. wait(leader, 1)
  83. leader.expect('OpenThread attached to netif', timeout=20)
  84. leader.write(' ')
  85. leader.write('state')
  86. child.expect('OpenThread attached to netif', timeout=20)
  87. child.write(' ')
  88. child.write('state')
  89. def config_network(leader:IdfDut, child:IdfDut, leader_name:str, thread_dataset_model:str,
  90. thread_dataset:str, wifi:IdfDut, wifi_ssid:str, wifi_psk:str) -> str:
  91. wait_key_str(leader, child)
  92. return form_network_using_manual_configuration(leader, child, leader_name, thread_dataset_model,
  93. thread_dataset, wifi, wifi_ssid, wifi_psk)
  94. # config br and cli manually
  95. def form_network_using_manual_configuration(leader:IdfDut, child:IdfDut, leader_name:str, thread_dataset_model:str,
  96. thread_dataset:str, wifi:IdfDut, wifi_ssid:str, wifi_psk:str) -> str:
  97. reset_thread(leader)
  98. clean_buffer(leader)
  99. reset_thread(child)
  100. clean_buffer(child)
  101. leader.write('channel 12')
  102. leader.expect('Done', timeout=5)
  103. child.write('channel 12')
  104. child.expect('Done', timeout=5)
  105. res = '0000'
  106. if wifi_psk != '0000':
  107. res = connect_wifi(wifi, wifi_ssid, wifi_psk, 10)[0]
  108. leader_data = ''
  109. if thread_dataset_model == 'random':
  110. leader_data = str(config_thread(leader, 'random'))
  111. else:
  112. config_thread(leader, 'appointed', thread_dataset)
  113. if leader_name == 'br':
  114. leader.write('bbr enable')
  115. leader.expect('Done', timeout=5)
  116. role = start_thread(leader)
  117. assert role == 'leader'
  118. if thread_dataset_model == 'random':
  119. config_thread(child, 'appointed', leader_data)
  120. else:
  121. config_thread(child, 'appointed', thread_dataset)
  122. if leader_name != 'br':
  123. child.write('bbr enable')
  124. child.expect('Done', timeout=5)
  125. role = start_thread(child)
  126. assert role == 'child'
  127. wait(leader, 10)
  128. return res
  129. # ping of thread
  130. def ot_ping(dut:IdfDut, target:str, times:int) -> Tuple[int, int]:
  131. command = 'ping ' + str(target) + ' 0 ' + str(times)
  132. dut.write(command)
  133. transmitted = dut.expect(r'(\d+) packets transmitted', timeout=30)[1].decode()
  134. tx_count = int(transmitted)
  135. received = dut.expect(r'(\d+) packets received', timeout=30)[1].decode()
  136. rx_count = int(received)
  137. return tx_count, rx_count
  138. # connect Wi-Fi
  139. def connect_wifi(dut:IdfDut, ssid:str, psk:str, nums:int) -> Tuple[str, int]:
  140. clean_buffer(dut)
  141. ip_address = ''
  142. information = ''
  143. for order in range(1, nums):
  144. dut.write('wifi connect -s ' + str(ssid) + ' -p ' + str(psk))
  145. tmp = dut.expect(pexpect.TIMEOUT, timeout=10)
  146. if 'sta ip' in str(tmp):
  147. ip_address = re.findall(r'sta ip: (\w+.\w+.\w+.\w+),', str(tmp))[0]
  148. information = dut.expect(r'wifi sta (\w+ \w+ \w+)\W', timeout=20)[1].decode()
  149. if information == 'is connected successfully':
  150. break
  151. assert information == 'is connected successfully'
  152. return ip_address, order
  153. def reset_host_interface() -> None:
  154. interface_name = get_host_interface_name()
  155. flag = False
  156. try:
  157. command = 'ifconfig ' + interface_name + ' down'
  158. subprocess.call(command, shell=True, timeout=5)
  159. time.sleep(1)
  160. command = 'ifconfig ' + interface_name + ' up'
  161. subprocess.call(command, shell=True, timeout=10)
  162. time.sleep(1)
  163. flag = True
  164. finally:
  165. time.sleep(1)
  166. assert flag
  167. def set_interface_sysctl_options() -> None:
  168. interface_name = get_host_interface_name()
  169. flag = False
  170. try:
  171. command = 'sysctl -w net/ipv6/conf/' + interface_name + '/accept_ra=2'
  172. subprocess.call(command, shell=True, timeout=5)
  173. time.sleep(1)
  174. command = 'sysctl -w net/ipv6/conf/' + interface_name + '/accept_ra_rt_info_max_plen=128'
  175. subprocess.call(command, shell=True, timeout=5)
  176. time.sleep(1)
  177. flag = True
  178. finally:
  179. time.sleep(2)
  180. assert flag
  181. def init_interface_ipv6_address() -> None:
  182. interface_name = get_host_interface_name()
  183. flag = False
  184. try:
  185. command = 'ip -6 route | grep ' + interface_name + " | grep ra | awk {'print $1'} | xargs -I {} ip -6 route del {}"
  186. subprocess.call(command, shell=True, timeout=5)
  187. time.sleep(0.5)
  188. subprocess.call(command, shell=True, timeout=5)
  189. time.sleep(1)
  190. command = 'ip -6 address show dev ' + interface_name + \
  191. " scope global | grep 'inet6' | awk {'print $2'} | xargs -I {} ip -6 addr del {} dev " + interface_name
  192. subprocess.call(command, shell=True, timeout=5)
  193. time.sleep(1)
  194. flag = True
  195. finally:
  196. time.sleep(1)
  197. assert flag
  198. def get_host_interface_name() -> str:
  199. interfaces = netifaces.interfaces()
  200. interface_name = [s for s in interfaces if 'wl' in s][0]
  201. return str(interface_name)
  202. def clean_buffer(dut:IdfDut) -> None:
  203. str_length = str(len(dut.expect(pexpect.TIMEOUT, timeout=0.1)))
  204. dut.expect(r'[\s\S]{%s}' % str(str_length), timeout=10)
  205. def check_if_host_receive_ra(br:IdfDut) -> bool:
  206. interface_name = get_host_interface_name()
  207. clean_buffer(br)
  208. br.write('br omrprefix')
  209. omrprefix = br.expect(r'\n((?:\w+:){4}):/\d+\r', timeout=5)[1].decode()
  210. command = 'ip -6 route | grep ' + str(interface_name)
  211. out_str = subprocess.getoutput(command)
  212. print('br omrprefix: ', str(omrprefix))
  213. print('host route table:\n', str(out_str))
  214. return str(omrprefix) in str(out_str)
  215. def host_connect_wifi() -> None:
  216. command = '. /home/test/wlan_connection_OTTE.sh'
  217. subprocess.call(command, shell=True, timeout=30)
  218. time.sleep(5)
  219. def is_joined_wifi_network(br:IdfDut) -> bool:
  220. return check_if_host_receive_ra(br)
  221. thread_ipv6_group = 'ff04:0:0:0:0:0:0:125'
  222. def check_ipmaddr(dut:IdfDut) -> bool:
  223. clean_buffer(dut)
  224. dut.write('ipmaddr')
  225. info = dut.expect(pexpect.TIMEOUT, timeout=2)
  226. if thread_ipv6_group in str(info):
  227. return True
  228. return False
  229. def thread_is_joined_group(dut:IdfDut) -> bool:
  230. command = 'mcast join ' + thread_ipv6_group
  231. dut.write(command)
  232. dut.expect('Done', timeout=5)
  233. order = 0
  234. while order < 3:
  235. if check_ipmaddr(dut):
  236. return True
  237. dut.write(command)
  238. wait(dut, 2)
  239. order = order + 1
  240. return False
  241. def host_joined_group(group:str='') -> bool:
  242. interface_name = get_host_interface_name()
  243. command = 'netstat -g | grep ' + str(interface_name)
  244. out_str = subprocess.getoutput(command)
  245. print('groups:\n', str(out_str))
  246. return group in str(out_str)
  247. class udp_parameter:
  248. def __init__(self, udp_type:str='', addr:str='::', port:int=5090, group:str='', init_flag:bool=False, timeout:float=15.0, udp_bytes:bytes=b''):
  249. self.udp_type = udp_type
  250. self.addr = addr
  251. self.port = port
  252. self.group = group
  253. self.init_flag = init_flag
  254. self.timeout = timeout
  255. self.udp_bytes = udp_bytes
  256. def create_host_udp_server(myudp:udp_parameter) -> None:
  257. interface_name = get_host_interface_name()
  258. try:
  259. if myudp.udp_type == 'INET6':
  260. AF_INET = socket.AF_INET6
  261. else:
  262. AF_INET = socket.AF_INET
  263. print('The host start to create udp server!')
  264. if_index = socket.if_nametoindex(interface_name)
  265. sock = socket.socket(AF_INET, socket.SOCK_DGRAM)
  266. sock.bind((myudp.addr, myudp.port))
  267. if myudp.udp_type == 'INET6' and myudp.group != '':
  268. sock.setsockopt(
  269. socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP,
  270. struct.pack('16si', socket.inet_pton(socket.AF_INET6, myudp.group),
  271. if_index))
  272. sock.settimeout(myudp.timeout)
  273. myudp.init_flag = True
  274. print('The host start to receive message!')
  275. myudp.udp_bytes = (sock.recvfrom(1024))[0]
  276. print('The host has received message: ', myudp.udp_bytes)
  277. except socket.error:
  278. print('The host did not receive message!')
  279. finally:
  280. print('Close the socket.')
  281. sock.close()
  282. def wait(dut:IdfDut, wait_time:float) -> None:
  283. dut.expect(pexpect.TIMEOUT, timeout=wait_time)
  284. def get_host_ipv4_address() -> str:
  285. interface_name = get_host_interface_name()
  286. command = 'ifconfig ' + interface_name + " | grep -w 'inet' | awk '{print $2}'"
  287. out_bytes = subprocess.check_output(command, shell=True, timeout=5)
  288. out_str = out_bytes.decode('utf-8')
  289. host_ipv4_address = ''
  290. host_ipv4_address = re.findall(r'((?:\d+.){3}\d+)', str(out_str))[0]
  291. return host_ipv4_address
  292. def start_avahi() -> None:
  293. time.sleep(1)
  294. command = '/etc/init.d/dbus start'
  295. subprocess.Popen(command, shell=True)
  296. time.sleep(5)
  297. command = 'avahi-daemon'
  298. subprocess.Popen(command, shell=True)
  299. time.sleep(5)
  300. def host_publish_service() -> None:
  301. command = 'avahi-publish-service testxxx _testxxx._udp 12347 test=1235 dn="for_ci_br_test"'
  302. subprocess.Popen(command, shell=True)
  303. time.sleep(2)
  304. def host_close_service() -> None:
  305. command = "ps | grep avahi-publish-s | awk '{print $1}'"
  306. out_bytes = subprocess.check_output(command, shell=True, timeout=5)
  307. out_str = out_bytes.decode('utf-8')
  308. the_pid = re.findall(r'(\d+)\n', str(out_str))
  309. for pid in the_pid:
  310. command = 'kill -9 ' + pid
  311. subprocess.call(command, shell=True, timeout=5)
  312. time.sleep(1)
  313. def close_host_interface() -> None:
  314. interface_name = get_host_interface_name()
  315. flag = False
  316. try:
  317. command = 'ifconfig ' + interface_name + ' down'
  318. subprocess.call(command, shell=True, timeout=5)
  319. time.sleep(1)
  320. flag = True
  321. finally:
  322. time.sleep(1)
  323. assert flag
  324. def open_host_interface() -> None:
  325. interface_name = get_host_interface_name()
  326. flag = False
  327. try:
  328. command = 'ifconfig ' + interface_name + ' up'
  329. subprocess.call(command, shell=True, timeout=5)
  330. time.sleep(1)
  331. flag = True
  332. finally:
  333. time.sleep(1)
  334. assert flag
  335. def get_domain() -> str:
  336. hostname = socket.gethostname()
  337. print('hostname is: ', hostname)
  338. command = 'ps -aux | grep avahi-daemon | grep running'
  339. out_str = subprocess.getoutput(command)
  340. print('avahi status:\n', out_str)
  341. role = re.findall(r'\[([\w\W]+)\.local\]', str(out_str))[0]
  342. print('active host is: ', role)
  343. return str(role)
  344. class tcp_parameter:
  345. def __init__(self, tcp_type:str='', addr:str='::', port:int=12345, listen_flag:bool=False, recv_flag:bool=False, timeout:float=15.0, tcp_bytes:bytes=b''):
  346. self.tcp_type = tcp_type
  347. self.addr = addr
  348. self.port = port
  349. self.listen_flag = listen_flag
  350. self.recv_flag = recv_flag
  351. self.timeout = timeout
  352. self.tcp_bytes = tcp_bytes
  353. def create_host_tcp_server(mytcp:tcp_parameter) -> None:
  354. try:
  355. if mytcp.tcp_type == 'INET6':
  356. AF_INET = socket.AF_INET6
  357. else:
  358. AF_INET = socket.AF_INET
  359. print('The host start to create a tcp server!')
  360. sock = socket.socket(AF_INET, socket.SOCK_STREAM)
  361. sock.bind((mytcp.addr, mytcp.port))
  362. sock.listen(5)
  363. mytcp.listen_flag = True
  364. print('The tcp server is waiting for connection!')
  365. sock.settimeout(mytcp.timeout)
  366. connfd,addr = sock.accept()
  367. print('The tcp server connected with ',addr)
  368. mytcp.recv_flag = True
  369. mytcp.tcp_bytes = connfd.recv(1024)
  370. print('The tcp server has received message: ', mytcp.tcp_bytes)
  371. except socket.error:
  372. if mytcp.recv_flag:
  373. print('The tcp server did not receive message!')
  374. else:
  375. print('The tcp server fail to connect!')
  376. finally:
  377. print('Close the socket.')
  378. sock.close()
  379. def get_ipv6_from_ipv4(ipv4_address:str, br:IdfDut) -> str:
  380. clean_buffer(br)
  381. br.write('br nat64prefix')
  382. omrprefix = br.expect(r'\n((?:\w+:){6}):/\d+', timeout=5)[1].decode()
  383. ipv4_find = re.findall(r'\d+', ipv4_address)
  384. ipv6_16_1 = decimal_to_hex(ipv4_find[0]) + decimal_to_hex(ipv4_find[1])
  385. ipv6_16_2 = decimal_to_hex(ipv4_find[2]) + decimal_to_hex(ipv4_find[3])
  386. ipv6_get_from_ipv4 = omrprefix + ':' + ipv6_16_1 + ':' + ipv6_16_2
  387. return str(ipv6_get_from_ipv4)
  388. def decimal_to_hex(decimal_str:str) -> str:
  389. decimal_int = int(decimal_str)
  390. hex_str = hex(decimal_int)[2:]
  391. return hex_str