ot_ci_function.py 14 KB

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