pytest_iperf.py 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. # SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
  2. # SPDX-License-Identifier: Unlicense OR CC0-1.0
  3. """
  4. Test case for iperf example.
  5. This test case might have problem running on windows:
  6. - use `sudo killall iperf` to force kill iperf, didn't implement windows version
  7. The test env Example_ShieldBox_Basic do need the following config::
  8. Example_ShieldBox_Basic:
  9. ap_ssid: "myssid"
  10. ap_password: "mypassword"
  11. pc_nic: "eth1"
  12. """
  13. import os
  14. import time
  15. from typing import Any, Callable, Tuple
  16. import pexpect
  17. import pytest
  18. from common_test_methods import get_env_config_variable, get_host_ip_by_interface
  19. from idf_iperf_test_util import IperfUtility
  20. from idf_iperf_test_util.IperfUtility import SCAN_RETRY_COUNT, SCAN_TIMEOUT, TEST_TIME
  21. from pytest_embedded import Dut
  22. # configurations
  23. RETRY_COUNT_FOR_BEST_PERFORMANCE = 2
  24. NO_BANDWIDTH_LIMIT = -1 # iperf send bandwith is not limited
  25. # Use default value `99` for config with best performance.
  26. BEST_PERFORMANCE_CONFIG = '99'
  27. class IperfTestUtilitySoftap(IperfUtility.IperfTestUtility):
  28. """ iperf test implementation """
  29. def __init__(self, dut: Dut, softap_dut: Dut, config_name:str, test_result:Any=None) -> None:
  30. IperfUtility.IperfTestUtility.__init__(self, dut, config_name, 'softap', '1234567890', None, None, test_result)
  31. self.softap_dut = softap_dut
  32. self.softap_ip = '192.168.4.1'
  33. def setup(self) -> Tuple[str,int]:
  34. """
  35. setup iperf test:
  36. 1. kill current iperf process
  37. 2. reboot DUT (currently iperf is not very robust, need to reboot DUT)
  38. 3. scan to get AP RSSI
  39. 4. connect to AP
  40. """
  41. self.softap_dut.write('restart')
  42. self.softap_dut.expect_exact("Type 'help' to get the list of commands.")
  43. self.softap_dut.expect('iperf>', timeout=30)
  44. self.softap_dut.write('ap {} {}'.format(self.ap_ssid, self.ap_password))
  45. self.dut.write('restart')
  46. self.dut.expect_exact("Type 'help' to get the list of commands.")
  47. self.dut.expect('iperf>', timeout=30)
  48. self.dut.write('scan {}'.format(self.ap_ssid))
  49. for _ in range(SCAN_RETRY_COUNT):
  50. try:
  51. rssi = int(self.dut.expect(r'\[{}]\[rssi=(-\d+)]'.format(self.ap_ssid),
  52. timeout=SCAN_TIMEOUT).group(1))
  53. break
  54. except pexpect.TIMEOUT:
  55. continue
  56. else:
  57. raise AssertionError('Failed to scan AP')
  58. self.dut.write('sta {} {}'.format(self.ap_ssid, self.ap_password))
  59. dut_ip = self.dut.expect(r'sta ip: ([\d.]+), mask: ([\d.]+), gw: ([\d.]+)').group(1).decode('utf-8')
  60. return dut_ip, rssi
  61. def _test_once(self, proto:str, direction:str, bw_limit:int) -> Tuple[str, int, int]:
  62. """ do measure once for one type """
  63. # connect and scan to get RSSI
  64. dut_ip, rssi = self.setup()
  65. assert direction in ['rx', 'tx']
  66. assert proto in ['tcp', 'udp']
  67. # run iperf test
  68. if direction == 'tx':
  69. if proto == 'tcp':
  70. self.softap_dut.write('iperf -s -i 1 -t {}'.format(TEST_TIME))
  71. # wait until DUT TCP server created
  72. try:
  73. self.softap_dut.expect('iperf tcp server create successfully', timeout=1)
  74. except pexpect.TIMEOUT:
  75. # compatible with old iperf example binary
  76. pass
  77. if bw_limit > 0:
  78. self.dut.write('iperf -c {} -i 1 -t {} -b {}'.format(self.softap_ip, TEST_TIME, bw_limit))
  79. else:
  80. self.dut.write('iperf -c {} -i 1 -t {}'.format(self.softap_ip, TEST_TIME))
  81. else:
  82. self.softap_dut.write('iperf -s -u -i 1 -t {}'.format(TEST_TIME))
  83. if bw_limit > 0:
  84. self.dut.write('iperf -c {} -u -i 1 -t {} -b {}'.format(self.softap_ip, TEST_TIME, bw_limit))
  85. else:
  86. self.dut.write('iperf -c {} -u -i 1 -t {}'.format(self.softap_ip, TEST_TIME))
  87. else:
  88. if proto == 'tcp':
  89. self.dut.write('iperf -s -i 1 -t {}'.format(TEST_TIME))
  90. # wait until DUT TCP server created
  91. try:
  92. self.dut.expect('iperf tcp server create successfully', timeout=1)
  93. except pexpect.TIMEOUT:
  94. # compatible with old iperf example binary
  95. pass
  96. if bw_limit > 0:
  97. self.softap_dut.write('iperf -c {} -i 1 -t {} -b {}'.format(dut_ip, TEST_TIME, bw_limit))
  98. else:
  99. self.softap_dut.write('iperf -c {} -i 1 -t {}'.format(dut_ip, TEST_TIME))
  100. else:
  101. self.dut.write('iperf -s -u -i 1 -t {}'.format(TEST_TIME))
  102. if bw_limit > 0:
  103. self.softap_dut.write('iperf -c {} -u -i 1 -t {} -b {}'.format(dut_ip, TEST_TIME, bw_limit))
  104. else:
  105. self.softap_dut.write('iperf -c {} -u -i 1 -t {}'.format(dut_ip, TEST_TIME))
  106. time.sleep(TEST_TIME + 5)
  107. if direction == 'tx':
  108. server_raw_data = self.dut.expect(pexpect.TIMEOUT, timeout=0).decode('utf-8')
  109. else:
  110. server_raw_data = self.dut.expect(pexpect.TIMEOUT, timeout=0).decode('utf-8')
  111. self.dut.write('iperf -a')
  112. self.softap_dut.write('iperf -a')
  113. self.dut.write('heap')
  114. heap_size = self.dut.expect(r'min heap size: (\d+)\D').group(1)
  115. # return server raw data (for parsing test results) and RSSI
  116. return server_raw_data, rssi, heap_size
  117. @pytest.mark.esp32
  118. @pytest.mark.esp32s2
  119. @pytest.mark.esp32c3
  120. @pytest.mark.esp32s3
  121. @pytest.mark.temp_skip_ci(targets=['esp32s2', 'esp32c3', 'esp32s3'], reason='lack of runners (run only for ESP32)')
  122. @pytest.mark.timeout(1200)
  123. @pytest.mark.Example_ShieldBox_Basic
  124. @pytest.mark.parametrize('config', [
  125. BEST_PERFORMANCE_CONFIG
  126. ], indirect=True)
  127. def test_wifi_throughput_basic(
  128. dut: Dut,
  129. log_performance: Callable[[str, str], None],
  130. check_performance: Callable[[str, float, str], None],
  131. ) -> None:
  132. """
  133. steps: |
  134. 1. test TCP tx rx and UDP tx rx throughput
  135. 2. compare with the pre-defined pass standard
  136. """
  137. # 1. wait for DUT
  138. dut.expect('iperf>')
  139. # 2. preparing
  140. env_name = 'Example_ShieldBox_Basic'
  141. pc_nic = get_env_config_variable(env_name, 'pc_nic')
  142. pc_nic_ip = get_host_ip_by_interface(pc_nic)
  143. pc_iperf_log_file = os.path.join(dut.logdir, 'pc_iperf_log.md')
  144. ap_info = {
  145. 'ssid': get_env_config_variable(env_name, 'ap_ssid'),
  146. 'password': get_env_config_variable(env_name, 'ap_password'),
  147. }
  148. test_result = {
  149. 'tcp_tx': IperfUtility.TestResult('tcp', 'tx', BEST_PERFORMANCE_CONFIG),
  150. 'tcp_rx': IperfUtility.TestResult('tcp', 'rx', BEST_PERFORMANCE_CONFIG),
  151. 'udp_tx': IperfUtility.TestResult('udp', 'tx', BEST_PERFORMANCE_CONFIG),
  152. 'udp_rx': IperfUtility.TestResult('udp', 'rx', BEST_PERFORMANCE_CONFIG),
  153. }
  154. test_utility = IperfUtility.IperfTestUtility(dut, BEST_PERFORMANCE_CONFIG, ap_info['ssid'], ap_info['password'],
  155. pc_nic_ip, pc_iperf_log_file, test_result)
  156. # 3. run test for TCP Tx, Rx and UDP Tx, Rx
  157. for _ in range(RETRY_COUNT_FOR_BEST_PERFORMANCE):
  158. test_utility.run_all_cases(0, NO_BANDWIDTH_LIMIT)
  159. # 4. log performance and compare with pass standard
  160. for throughput_type in test_result:
  161. log_performance('{}_throughput'.format(throughput_type),
  162. '{:.02f} Mbps'.format(test_result[throughput_type].get_best_throughput()))
  163. # do check after logging, otherwise test will exit immediately if check fail, some performance can't be logged.
  164. for throughput_type in test_result:
  165. check_performance('{}_throughput'.format(throughput_type),
  166. test_result[throughput_type].get_best_throughput(), dut.target)