Omar El Ayach | 33f80c0 | 2018-09-27 15:02:03 -0700 | [diff] [blame] | 1 | #!/usr/bin/env python3.4 |
| 2 | # |
| 3 | # Copyright 2017 - The Android Open Source Project |
| 4 | # |
| 5 | # Licensed under the Apache License, Version 2.0 (the "License"); |
| 6 | # you may not use this file except in compliance with the License. |
| 7 | # You may obtain a copy of the License at |
| 8 | # |
| 9 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 10 | # |
| 11 | # Unless required by applicable law or agreed to in writing, software |
| 12 | # distributed under the License is distributed on an "AS IS" BASIS, |
| 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 14 | # See the License for the specific language governing permissions and |
| 15 | # limitations under the License. |
| 16 | |
| 17 | import collections |
Omar El Ayach | 96714c8 | 2019-01-28 18:51:46 -0800 | [diff] [blame] | 18 | import csv |
| 19 | import itertools |
Omar El Ayach | 33f80c0 | 2018-09-27 15:02:03 -0700 | [diff] [blame] | 20 | import json |
| 21 | import logging |
| 22 | import os |
Omar El Ayach | 33f80c0 | 2018-09-27 15:02:03 -0700 | [diff] [blame] | 23 | from acts import asserts |
| 24 | from acts import base_test |
| 25 | from acts import utils |
Omar El Ayach | 14416ac | 2019-01-30 14:58:19 -0800 | [diff] [blame^] | 26 | from acts.controllers import iperf_server as ipf |
| 27 | from acts.controllers.utils_lib import ssh |
Omar El Ayach | 5fbc122 | 2018-12-07 18:10:05 -0800 | [diff] [blame] | 28 | from acts.metrics.loggers.blackbox import BlackboxMetricLogger |
Omar El Ayach | 33f80c0 | 2018-09-27 15:02:03 -0700 | [diff] [blame] | 29 | from acts.test_utils.wifi import wifi_test_utils as wutils |
| 30 | from acts.test_utils.wifi import wifi_retail_ap as retail_ap |
Omar El Ayach | 5fbc122 | 2018-12-07 18:10:05 -0800 | [diff] [blame] | 31 | from WifiRvrTest import WifiRvrTest |
| 32 | from WifiPingTest import WifiPingTest |
Omar El Ayach | 33f80c0 | 2018-09-27 15:02:03 -0700 | [diff] [blame] | 33 | |
| 34 | |
Omar El Ayach | 5fbc122 | 2018-12-07 18:10:05 -0800 | [diff] [blame] | 35 | class WifiSensitivityTest(WifiRvrTest, WifiPingTest): |
Omar El Ayach | 33f80c0 | 2018-09-27 15:02:03 -0700 | [diff] [blame] | 36 | """Class to test WiFi sensitivity tests. |
| 37 | |
| 38 | This class implements measures WiFi sensitivity per rate. It heavily |
| 39 | leverages the WifiRvrTest class and introduced minor differences to set |
| 40 | specific rates and the access point, and implements a different pass/fail |
| 41 | check. For an example config file to run this test class see |
| 42 | example_connectivity_performance_ap_sta.json. |
| 43 | """ |
| 44 | |
| 45 | VALID_TEST_CONFIGS = { |
| 46 | 1: ["legacy", "VHT20"], |
| 47 | 2: ["legacy", "VHT20"], |
| 48 | 6: ["legacy", "VHT20"], |
| 49 | 10: ["legacy", "VHT20"], |
| 50 | 11: ["legacy", "VHT20"], |
| 51 | 36: ["legacy", "VHT20"], |
| 52 | 40: ["legacy", "VHT20"], |
| 53 | 44: ["legacy", "VHT20"], |
| 54 | 48: ["legacy", "VHT20"], |
| 55 | 149: ["legacy", "VHT20"], |
| 56 | 153: ["legacy", "VHT20"], |
| 57 | 157: ["legacy", "VHT20"], |
| 58 | 161: ["legacy", "VHT20"] |
| 59 | } |
| 60 | VALID_RATES = { |
| 61 | "legacy_2GHz": [[54, 1], [48, 1], [36, 1], [24, 1], [18, 1], [12, 1], |
| 62 | [11, 1], [9, 1], [6, 1], [5.5, 1], [2, 1], [1, 1]], |
| 63 | "legacy_5GHz": [[54, 1], [48, 1], [36, 1], [24, 1], [18, 1], [12, 1], |
| 64 | [9, 1], [6, 1]], |
| 65 | "HT": [[8, 1], [7, 1], [6, 1], [5, 1], [4, 1], [3, 1], [2, 1], [1, 1], |
| 66 | [0, 1], [15, 2], [14, 2], [13, 2], [12, 2], [11, 2], [10, 2], |
| 67 | [9, 2], [8, 2]], |
| 68 | "VHT": [[9, 1], [8, 1], [7, 1], [6, 1], [5, 1], [4, 1], [3, 1], [2, 1], |
| 69 | [1, 1], [0, 1], [9, 2], [8, 2], [7, 2], [6, 2], [5, 2], [4, 2], |
| 70 | [3, 2], [2, 2], [1, 2], [0, 2]] |
| 71 | } |
| 72 | |
Omar El Ayach | 5fbc122 | 2018-12-07 18:10:05 -0800 | [diff] [blame] | 73 | def __init__(self, controllers): |
| 74 | base_test.BaseTestClass.__init__(self, controllers) |
| 75 | self.failure_count_metric = BlackboxMetricLogger.for_test_case( |
| 76 | metric_name='sensitivity') |
| 77 | |
Omar El Ayach | 33f80c0 | 2018-09-27 15:02:03 -0700 | [diff] [blame] | 78 | def setup_class(self): |
| 79 | """Initializes common test hardware and parameters. |
| 80 | |
| 81 | This function initializes hardwares and compiles parameters that are |
| 82 | common to all tests in this class. |
| 83 | """ |
| 84 | self.client_dut = self.android_devices[-1] |
| 85 | req_params = [ |
Omar El Ayach | 14416ac | 2019-01-30 14:58:19 -0800 | [diff] [blame^] | 86 | "RetailAccessPoints", "sensitivity_test_params", "testbed_params", |
| 87 | "RemoteServer" |
Omar El Ayach | 33f80c0 | 2018-09-27 15:02:03 -0700 | [diff] [blame] | 88 | ] |
| 89 | opt_params = ["main_network", "golden_files_list"] |
| 90 | self.unpack_userparams(req_params, opt_params) |
| 91 | self.testclass_params = self.sensitivity_test_params |
| 92 | self.num_atten = self.attenuators[0].instrument.num_atten |
Omar El Ayach | 14416ac | 2019-01-30 14:58:19 -0800 | [diff] [blame^] | 93 | self.ping_server = ssh.connection.SshConnection( |
| 94 | ssh.settings.from_config(self.RemoteServer[0]["ssh_config"])) |
Omar El Ayach | 33f80c0 | 2018-09-27 15:02:03 -0700 | [diff] [blame] | 95 | self.iperf_server = self.iperf_servers[0] |
Omar El Ayach | 14416ac | 2019-01-30 14:58:19 -0800 | [diff] [blame^] | 96 | self.iperf_client = self.iperf_clients[0] |
| 97 | if isinstance(self.iperf_server, ipf.IPerfServerOverSsh): |
| 98 | self.ping_server = self.iperf_server |
| 99 | else: |
| 100 | self.ping_server = self.iperf_client |
Omar El Ayach | 33f80c0 | 2018-09-27 15:02:03 -0700 | [diff] [blame] | 101 | self.access_points = retail_ap.create(self.RetailAccessPoints) |
| 102 | self.access_point = self.access_points[0] |
| 103 | self.log.info("Access Point Configuration: {}".format( |
| 104 | self.access_point.ap_settings)) |
| 105 | self.log_path = os.path.join(logging.log_path, "results") |
| 106 | utils.create_dir(self.log_path) |
| 107 | if not hasattr(self, "golden_files_list"): |
| 108 | self.golden_files_list = [ |
| 109 | os.path.join(self.testbed_params["golden_results_path"], |
| 110 | file) for file in os.listdir( |
| 111 | self.testbed_params["golden_results_path"]) |
| 112 | ] |
| 113 | self.testclass_results = [] |
| 114 | |
| 115 | # Turn WiFi ON |
| 116 | for dev in self.android_devices: |
| 117 | wutils.wifi_toggle_state(dev, True) |
| 118 | |
Omar El Ayach | 96714c8 | 2019-01-28 18:51:46 -0800 | [diff] [blame] | 119 | def teardown_class(self): |
| 120 | # Turn WiFi OFF |
| 121 | for dev in self.android_devices: |
| 122 | wutils.wifi_toggle_state(dev, False) |
| 123 | self.process_testclass_results() |
| 124 | |
Omar El Ayach | 5fbc122 | 2018-12-07 18:10:05 -0800 | [diff] [blame] | 125 | def pass_fail_check(self, result): |
Omar El Ayach | 33f80c0 | 2018-09-27 15:02:03 -0700 | [diff] [blame] | 126 | """Checks sensitivity against golden results and decides on pass/fail. |
| 127 | |
| 128 | Args: |
Omar El Ayach | 5fbc122 | 2018-12-07 18:10:05 -0800 | [diff] [blame] | 129 | result: dict containing attenuation, throughput and other meta |
Omar El Ayach | 33f80c0 | 2018-09-27 15:02:03 -0700 | [diff] [blame] | 130 | data |
| 131 | """ |
| 132 | try: |
| 133 | golden_path = next(file_name |
| 134 | for file_name in self.golden_files_list |
| 135 | if "sensitivity_targets" in file_name) |
| 136 | with open(golden_path, 'r') as golden_file: |
| 137 | golden_results = json.load(golden_file) |
Omar El Ayach | 5fbc122 | 2018-12-07 18:10:05 -0800 | [diff] [blame] | 138 | golden_sensitivity = golden_results[self.current_test_name][ |
| 139 | "sensitivity"] |
Omar El Ayach | 33f80c0 | 2018-09-27 15:02:03 -0700 | [diff] [blame] | 140 | except: |
Omar El Ayach | 5fbc122 | 2018-12-07 18:10:05 -0800 | [diff] [blame] | 141 | golden_sensitivity = float("nan") |
Omar El Ayach | 33f80c0 | 2018-09-27 15:02:03 -0700 | [diff] [blame] | 142 | |
Omar El Ayach | 33f80c0 | 2018-09-27 15:02:03 -0700 | [diff] [blame] | 143 | result_string = "Througput = {}, Sensitivity = {}. Target Sensitivity = {}".format( |
Omar El Ayach | 5fbc122 | 2018-12-07 18:10:05 -0800 | [diff] [blame] | 144 | result["peak_throughput"], result["sensitivity"], |
Omar El Ayach | 33f80c0 | 2018-09-27 15:02:03 -0700 | [diff] [blame] | 145 | golden_sensitivity) |
Omar El Ayach | 5fbc122 | 2018-12-07 18:10:05 -0800 | [diff] [blame] | 146 | if result["sensitivity"] - golden_sensitivity < self.testclass_params["sensitivity_tolerance"]: |
Omar El Ayach | 33f80c0 | 2018-09-27 15:02:03 -0700 | [diff] [blame] | 147 | asserts.explicit_pass("Test Passed. {}".format(result_string)) |
Omar El Ayach | 5fbc122 | 2018-12-07 18:10:05 -0800 | [diff] [blame] | 148 | else: |
| 149 | asserts.fail("Test Failed. {}".format(result_string)) |
Omar El Ayach | 33f80c0 | 2018-09-27 15:02:03 -0700 | [diff] [blame] | 150 | |
| 151 | def process_testclass_results(self): |
| 152 | """Saves and plots test results from all executed test cases.""" |
Omar El Ayach | 96714c8 | 2019-01-28 18:51:46 -0800 | [diff] [blame] | 153 | # write json output |
Omar El Ayach | 33f80c0 | 2018-09-27 15:02:03 -0700 | [diff] [blame] | 154 | testclass_results_dict = collections.OrderedDict() |
| 155 | for result in self.testclass_results: |
| 156 | testclass_results_dict[result["test_name"]] = { |
| 157 | "peak_throughput": result["peak_throughput"], |
| 158 | "range": result["range"], |
| 159 | "sensitivity": result["sensitivity"] |
| 160 | } |
| 161 | results_file_path = os.path.join(self.log_path, 'results.json') |
| 162 | with open(results_file_path, 'w') as results_file: |
| 163 | json.dump(testclass_results_dict, results_file, indent=4) |
Omar El Ayach | 96714c8 | 2019-01-28 18:51:46 -0800 | [diff] [blame] | 164 | # write csv |
| 165 | results_file_path = os.path.join(self.log_path, 'results.csv') |
| 166 | with open(results_file_path, mode='w') as csv_file: |
| 167 | csv_header = [ |
| 168 | "Channel", "Mode", "MCS", "Streams", "Chain", "Sensitivity", |
| 169 | "Range", "Peak Throughput" |
| 170 | ] |
| 171 | writer = csv.DictWriter(csv_file, fieldnames=csv_header) |
| 172 | writer.writeheader() |
| 173 | for result in self.testclass_results: |
| 174 | testcase_params = self.parse_test_params(result["test_name"]) |
| 175 | writer.writerow({ |
| 176 | "Channel": testcase_params["channel"], |
| 177 | "Mode": testcase_params["mode"], |
| 178 | "MCS": testcase_params["rate"], |
| 179 | "Streams": testcase_params["num_streams"], |
| 180 | "Chain": testcase_params["chain_mask"], |
| 181 | "Sensitivity": result["sensitivity"], |
| 182 | "Range": result["range"], |
| 183 | "Peak Throughput": result["peak_throughput"] |
| 184 | }) |
| 185 | |
Omar El Ayach | 5fbc122 | 2018-12-07 18:10:05 -0800 | [diff] [blame] | 186 | if not self.testclass_params["traffic_type"].lower() == "ping": |
| 187 | WifiRvrTest.process_testclass_results(self) |
Omar El Ayach | 33f80c0 | 2018-09-27 15:02:03 -0700 | [diff] [blame] | 188 | |
Omar El Ayach | 5fbc122 | 2018-12-07 18:10:05 -0800 | [diff] [blame] | 189 | def process_rvr_test_results(self, testcase_params, rvr_result): |
Omar El Ayach | 33f80c0 | 2018-09-27 15:02:03 -0700 | [diff] [blame] | 190 | """Post processes RvR results to compute sensitivity. |
| 191 | |
| 192 | Takes in the results of the RvR tests and computes the sensitivity of |
| 193 | the current rate by looking at the point at which throughput drops |
| 194 | below the percentage specified in the config file. The function then |
| 195 | calls on its parent class process_test_results to plot the result. |
| 196 | |
| 197 | Args: |
| 198 | rvr_result: dict containing attenuation, throughput and other meta |
| 199 | data |
| 200 | """ |
| 201 | rvr_result["peak_throughput"] = max(rvr_result["throughput_receive"]) |
| 202 | throughput_check = [ |
| 203 | throughput < rvr_result["peak_throughput"] * |
| 204 | (self.testclass_params["throughput_pct_at_sensitivity"] / 100) |
| 205 | for throughput in rvr_result["throughput_receive"] |
| 206 | ] |
| 207 | consistency_check = [ |
| 208 | idx for idx in range(len(throughput_check)) |
| 209 | if all(throughput_check[idx:]) |
| 210 | ] |
| 211 | rvr_result["atten_at_range"] = rvr_result["attenuation"][ |
| 212 | consistency_check[0] - 1] |
| 213 | rvr_result["range"] = rvr_result["fixed_attenuation"] + ( |
| 214 | rvr_result["atten_at_range"]) |
Omar El Ayach | 5fbc122 | 2018-12-07 18:10:05 -0800 | [diff] [blame] | 215 | rvr_result["sensitivity"] = self.testclass_params["ap_tx_power"] + ( |
| 216 | self.testbed_params["ap_tx_power_offset"][str( |
| 217 | testcase_params["channel"])] - rvr_result["range"]) |
| 218 | WifiRvrTest.process_test_results(self, rvr_result) |
| 219 | |
| 220 | def process_ping_test_results(self, testcase_params, ping_result): |
| 221 | """Post processes RvR results to compute sensitivity. |
| 222 | |
| 223 | Takes in the results of the RvR tests and computes the sensitivity of |
| 224 | the current rate by looking at the point at which throughput drops |
| 225 | below the percentage specified in the config file. The function then |
| 226 | calls on its parent class process_test_results to plot the result. |
| 227 | |
| 228 | Args: |
| 229 | rvr_result: dict containing attenuation, throughput and other meta |
| 230 | data |
| 231 | """ |
| 232 | testcase_params[ |
| 233 | "range_ping_loss_threshold"] = 100 - testcase_params["throughput_pct_at_sensitivity"] |
| 234 | WifiPingTest.process_ping_results(self, testcase_params, ping_result) |
| 235 | ping_result["sensitivity"] = self.testclass_params["ap_tx_power"] + ( |
| 236 | self.testbed_params["ap_tx_power_offset"][str( |
| 237 | testcase_params["channel"])] - ping_result["range"]) |
Omar El Ayach | 33f80c0 | 2018-09-27 15:02:03 -0700 | [diff] [blame] | 238 | |
| 239 | def setup_ap(self, testcase_params): |
Omar El Ayach | 5a1496bf | 2019-01-09 11:43:02 -0800 | [diff] [blame] | 240 | """Sets up the AP and attenuator to compensate for AP chain imbalance. |
Omar El Ayach | 33f80c0 | 2018-09-27 15:02:03 -0700 | [diff] [blame] | 241 | |
| 242 | Args: |
| 243 | testcase_params: dict containing AP and other test params |
| 244 | """ |
| 245 | band = self.access_point.band_lookup_by_channel( |
| 246 | testcase_params["channel"]) |
| 247 | if "2G" in band: |
| 248 | frequency = wutils.WifiEnums.channel_2G_to_freq[testcase_params[ |
| 249 | "channel"]] |
| 250 | else: |
| 251 | frequency = wutils.WifiEnums.channel_5G_to_freq[testcase_params[ |
| 252 | "channel"]] |
| 253 | if frequency in wutils.WifiEnums.DFS_5G_FREQUENCIES: |
| 254 | self.access_point.set_region(self.testbed_params["DFS_region"]) |
| 255 | else: |
| 256 | self.access_point.set_region(self.testbed_params["default_region"]) |
| 257 | self.access_point.set_channel(band, testcase_params["channel"]) |
| 258 | self.access_point.set_bandwidth(band, testcase_params["mode"]) |
| 259 | self.access_point.set_power(band, testcase_params["ap_tx_power"]) |
| 260 | self.access_point.set_rate( |
| 261 | band, testcase_params["mode"], testcase_params["num_streams"], |
| 262 | testcase_params["rate"], testcase_params["short_gi"]) |
Omar El Ayach | 96714c8 | 2019-01-28 18:51:46 -0800 | [diff] [blame] | 263 | # Set attenuator offsets and set attenuators to initial condition |
| 264 | atten_offsets = self.testbed_params['chain_offset'][str( |
| 265 | testcase_params['channel'])] |
Omar El Ayach | 5a1496bf | 2019-01-09 11:43:02 -0800 | [diff] [blame] | 266 | for atten in self.attenuators: |
Omar El Ayach | 96714c8 | 2019-01-28 18:51:46 -0800 | [diff] [blame] | 267 | if 'AP-Chain-0' in atten.path: |
| 268 | atten.offset = atten_offsets[0] |
| 269 | elif 'AP-Chain-1' in atten.path: |
| 270 | atten.offset = atten_offsets[1] |
| 271 | if testcase_params["attenuated_chain"] in atten.path: |
| 272 | atten.offset = atten.instrument.max_atten |
Omar El Ayach | 33f80c0 | 2018-09-27 15:02:03 -0700 | [diff] [blame] | 273 | self.log.info("Access Point Configuration: {}".format( |
| 274 | self.access_point.ap_settings)) |
| 275 | |
| 276 | def get_start_atten(self): |
| 277 | """Gets the starting attenuation for this sensitivity test. |
| 278 | |
| 279 | The function gets the starting attenuation by checking whether a test |
| 280 | as the next higher MCS has been executed. If so it sets the starting |
| 281 | point a configurable number of dBs below the next MCS's sensitivity. |
| 282 | |
| 283 | Returns: |
| 284 | start_atten: starting attenuation for current test |
| 285 | """ |
| 286 | # Get the current and reference test config. The reference test is the |
| 287 | # one performed at the current MCS+1 |
| 288 | current_test_params = self.parse_test_params(self.current_test_name) |
| 289 | ref_test_params = current_test_params.copy() |
| 290 | if "legacy" in current_test_params["mode"] and current_test_params["rate"] < 54: |
| 291 | if current_test_params["channel"] <= 13: |
| 292 | ref_index = self.VALID_RATES["legacy_2GHz"].index( |
| 293 | [current_test_params["rate"], 1]) - 1 |
| 294 | ref_test_params["rate"] = self.VALID_RATES["legacy_2GHz"][ |
| 295 | ref_index][0] |
| 296 | else: |
| 297 | ref_index = self.VALID_RATES["legacy_5GHz"].index( |
| 298 | [current_test_params["rate"], 1]) - 1 |
| 299 | ref_test_params["rate"] = self.VALID_RATES["legacy_5GHz"][ |
| 300 | ref_index][0] |
| 301 | else: |
| 302 | ref_test_params["rate"] = ref_test_params["rate"] + 1 |
| 303 | |
| 304 | # Check if reference test has been run and set attenuation accordingly |
| 305 | previous_params = [ |
| 306 | self.parse_test_params(result["test_name"]) |
| 307 | for result in self.testclass_results |
| 308 | ] |
| 309 | try: |
| 310 | ref_index = previous_params.index(ref_test_params) |
| 311 | start_atten = self.testclass_results[ref_index]["atten_at_range"] - ( |
| 312 | self.testclass_params["adjacent_mcs_range_gap"]) |
| 313 | except: |
| 314 | print("Reference test not found. Starting from {} dB".format( |
| 315 | self.testclass_params["atten_start"])) |
| 316 | start_atten = self.testclass_params["atten_start"] |
| 317 | return start_atten |
| 318 | |
| 319 | def parse_test_params(self, test_name): |
| 320 | """Function that generates test params based on the test name.""" |
| 321 | test_name_params = test_name.split("_") |
| 322 | testcase_params = collections.OrderedDict() |
| 323 | testcase_params["channel"] = int(test_name_params[2][2:]) |
| 324 | testcase_params["mode"] = test_name_params[3] |
Omar El Ayach | 5fbc122 | 2018-12-07 18:10:05 -0800 | [diff] [blame] | 325 | |
Omar El Ayach | 33f80c0 | 2018-09-27 15:02:03 -0700 | [diff] [blame] | 326 | if "legacy" in testcase_params["mode"].lower(): |
| 327 | testcase_params["rate"] = float( |
| 328 | str(test_name_params[4]).replace("p", ".")) |
| 329 | else: |
| 330 | testcase_params["rate"] = int(test_name_params[4][3:]) |
| 331 | testcase_params["num_streams"] = int(test_name_params[5][3:]) |
| 332 | testcase_params["short_gi"] = 0 |
Omar El Ayach | 96714c8 | 2019-01-28 18:51:46 -0800 | [diff] [blame] | 333 | testcase_params["chain_mask"] = test_name_params[6][2:] |
| 334 | if testcase_params["chain_mask"] in ["0", "1"]: |
| 335 | testcase_params["attenuated_chain"] = "DUT-Chain-{}".format( |
| 336 | 1 if testcase_params['chain_mask'] == "0" else 0) |
| 337 | else: |
| 338 | testcase_params["attenuated_chain"] = None |
Omar El Ayach | 5fbc122 | 2018-12-07 18:10:05 -0800 | [diff] [blame] | 339 | |
Omar El Ayach | 33f80c0 | 2018-09-27 15:02:03 -0700 | [diff] [blame] | 340 | if self.testclass_params["traffic_type"] == "UDP": |
Omar El Ayach | 14416ac | 2019-01-30 14:58:19 -0800 | [diff] [blame^] | 341 | testcase_params["iperf_args"] = '-i 1 -t {} -J -u -b {}'.format( |
Omar El Ayach | 33f80c0 | 2018-09-27 15:02:03 -0700 | [diff] [blame] | 342 | self.testclass_params["iperf_duration"], |
| 343 | self.testclass_params["UDP_rates"][testcase_params["mode"]]) |
Omar El Ayach | 5fbc122 | 2018-12-07 18:10:05 -0800 | [diff] [blame] | 344 | elif self.testclass_params["traffic_type"] == "TCP": |
Omar El Ayach | 14416ac | 2019-01-30 14:58:19 -0800 | [diff] [blame^] | 345 | testcase_params["iperf_args"] = '-i 1 -t {} -J'.format( |
Omar El Ayach | 33f80c0 | 2018-09-27 15:02:03 -0700 | [diff] [blame] | 346 | self.testclass_params["iperf_duration"]) |
Omar El Ayach | 14416ac | 2019-01-30 14:58:19 -0800 | [diff] [blame^] | 347 | |
| 348 | if not isinstance(self.iperf_server, ipf.IPerfServerOverAdb): |
| 349 | testcase_params["iperf_args"] += ' -R' |
Omar El Ayach | 5fbc122 | 2018-12-07 18:10:05 -0800 | [diff] [blame] | 350 | testcase_params["use_client_output"] = True |
Omar El Ayach | 14416ac | 2019-01-30 14:58:19 -0800 | [diff] [blame^] | 351 | else: |
| 352 | testcase_params["use_client_output"] = False |
Omar El Ayach | 5fbc122 | 2018-12-07 18:10:05 -0800 | [diff] [blame] | 353 | |
Omar El Ayach | 33f80c0 | 2018-09-27 15:02:03 -0700 | [diff] [blame] | 354 | return testcase_params |
| 355 | |
| 356 | def _test_sensitivity(self): |
| 357 | """ Function that gets called for each test case |
| 358 | |
| 359 | The function gets called in each rvr test case. The function customizes |
| 360 | the rvr test based on the test name of the test that called it |
| 361 | """ |
| 362 | # Compile test parameters from config and test name |
| 363 | testcase_params = self.parse_test_params(self.current_test_name) |
| 364 | testcase_params.update(self.testclass_params) |
| 365 | testcase_params["atten_start"] = self.get_start_atten() |
Omar El Ayach | 5fbc122 | 2018-12-07 18:10:05 -0800 | [diff] [blame] | 366 | num_atten_steps = int( |
| 367 | (testcase_params["atten_stop"] - testcase_params["atten_start"]) / |
| 368 | testcase_params["atten_step"]) |
| 369 | testcase_params["atten_range"] = [ |
| 370 | testcase_params["atten_start"] + x * testcase_params["atten_step"] |
| 371 | for x in range(0, num_atten_steps) |
| 372 | ] |
Omar El Ayach | 33f80c0 | 2018-09-27 15:02:03 -0700 | [diff] [blame] | 373 | |
| 374 | # Prepare devices and run test |
Omar El Ayach | 5fbc122 | 2018-12-07 18:10:05 -0800 | [diff] [blame] | 375 | if testcase_params["traffic_type"].lower() == "ping": |
| 376 | self.setup_ping_test(testcase_params) |
| 377 | result = self.run_ping_test(testcase_params) |
| 378 | self.process_ping_test_results(testcase_params, result) |
| 379 | else: |
| 380 | self.setup_rvr_test(testcase_params) |
| 381 | result = self.run_rvr_test(testcase_params) |
Omar El Ayach | 5a1496bf | 2019-01-09 11:43:02 -0800 | [diff] [blame] | 382 | self.process_rvr_test_results(testcase_params, result) |
Omar El Ayach | 33f80c0 | 2018-09-27 15:02:03 -0700 | [diff] [blame] | 383 | # Post-process results |
Omar El Ayach | 5fbc122 | 2018-12-07 18:10:05 -0800 | [diff] [blame] | 384 | self.testclass_results.append(result) |
| 385 | self.pass_fail_check(result) |
Omar El Ayach | 33f80c0 | 2018-09-27 15:02:03 -0700 | [diff] [blame] | 386 | |
Omar El Ayach | 96714c8 | 2019-01-28 18:51:46 -0800 | [diff] [blame] | 387 | def generate_test_cases(self, channels, chain_mask): |
Omar El Ayach | 33f80c0 | 2018-09-27 15:02:03 -0700 | [diff] [blame] | 388 | """Function that auto-generates test cases for a test class.""" |
| 389 | testcase_wrapper = self._test_sensitivity |
| 390 | for channel in channels: |
| 391 | for mode in self.VALID_TEST_CONFIGS[channel]: |
| 392 | if "VHT" in mode: |
| 393 | rates = self.VALID_RATES["VHT"] |
| 394 | elif "HT" in mode: |
| 395 | rates = self.VALID_RATES["HT"] |
| 396 | elif "legacy" in mode and channel < 14: |
| 397 | rates = self.VALID_RATES["legacy_2GHz"] |
| 398 | elif "legacy" in mode and channel > 14: |
| 399 | rates = self.VALID_RATES["legacy_5GHz"] |
| 400 | else: |
| 401 | raise ValueError("Invalid test mode.") |
Omar El Ayach | 96714c8 | 2019-01-28 18:51:46 -0800 | [diff] [blame] | 402 | for chain, rate in itertools.product(chain_mask, rates): |
| 403 | if str(chain) in ["0", "1"] and rate[1] == 2: |
| 404 | # Do not test 2-stream rates in single chain mode |
| 405 | continue |
Omar El Ayach | 33f80c0 | 2018-09-27 15:02:03 -0700 | [diff] [blame] | 406 | if "legacy" in mode: |
Omar El Ayach | 96714c8 | 2019-01-28 18:51:46 -0800 | [diff] [blame] | 407 | testcase_name = "test_sensitivity_ch{}_{}_{}_nss{}_ch{}".format( |
Omar El Ayach | 33f80c0 | 2018-09-27 15:02:03 -0700 | [diff] [blame] | 408 | channel, mode, |
Omar El Ayach | 96714c8 | 2019-01-28 18:51:46 -0800 | [diff] [blame] | 409 | str(rate[0]).replace(".", "p"), rate[1], chain) |
Omar El Ayach | 33f80c0 | 2018-09-27 15:02:03 -0700 | [diff] [blame] | 410 | else: |
Omar El Ayach | 96714c8 | 2019-01-28 18:51:46 -0800 | [diff] [blame] | 411 | testcase_name = "test_sensitivity_ch{}_{}_mcs{}_nss{}_ch{}".format( |
| 412 | channel, mode, rate[0], rate[1], chain) |
Omar El Ayach | 33f80c0 | 2018-09-27 15:02:03 -0700 | [diff] [blame] | 413 | setattr(self, testcase_name, testcase_wrapper) |
| 414 | self.tests.append(testcase_name) |
| 415 | |
| 416 | |
| 417 | class WifiSensitivity_AllChannels_Test(WifiSensitivityTest): |
| 418 | def __init__(self, controllers): |
| 419 | base_test.BaseTestClass.__init__(self, controllers) |
| 420 | self.generate_test_cases( |
Omar El Ayach | 96714c8 | 2019-01-28 18:51:46 -0800 | [diff] [blame] | 421 | [1, 2, 6, 10, 11, 36, 40, 44, 48, 149, 153, 157, 161], |
| 422 | ["0", "1", "2x2"]) |
Omar El Ayach | 33f80c0 | 2018-09-27 15:02:03 -0700 | [diff] [blame] | 423 | |
| 424 | |
| 425 | class WifiSensitivity_2GHz_Test(WifiSensitivityTest): |
| 426 | def __init__(self, controllers): |
| 427 | base_test.BaseTestClass.__init__(self, controllers) |
Omar El Ayach | 96714c8 | 2019-01-28 18:51:46 -0800 | [diff] [blame] | 428 | self.generate_test_cases([1, 2, 6, 10, 11], ["0", "1", "2x2"]) |
Omar El Ayach | 33f80c0 | 2018-09-27 15:02:03 -0700 | [diff] [blame] | 429 | |
| 430 | |
Omar El Ayach | 5fbc122 | 2018-12-07 18:10:05 -0800 | [diff] [blame] | 431 | class WifiSensitivity_5GHz_Test(WifiSensitivityTest): |
| 432 | def __init__(self, controllers): |
| 433 | base_test.BaseTestClass.__init__(self, controllers) |
Omar El Ayach | 96714c8 | 2019-01-28 18:51:46 -0800 | [diff] [blame] | 434 | self.generate_test_cases([36, 40, 44, 48, 149, 153, 157, 161], |
| 435 | ["0", "1", "2x2"]) |
Omar El Ayach | 5fbc122 | 2018-12-07 18:10:05 -0800 | [diff] [blame] | 436 | |
| 437 | |
Omar El Ayach | 33f80c0 | 2018-09-27 15:02:03 -0700 | [diff] [blame] | 438 | class WifiSensitivity_UNII1_Test(WifiSensitivityTest): |
| 439 | def __init__(self, controllers): |
| 440 | base_test.BaseTestClass.__init__(self, controllers) |
Omar El Ayach | 96714c8 | 2019-01-28 18:51:46 -0800 | [diff] [blame] | 441 | self.generate_test_cases([36, 40, 44, 48], ["0", "1", "2x2"]) |
Omar El Ayach | 33f80c0 | 2018-09-27 15:02:03 -0700 | [diff] [blame] | 442 | |
| 443 | |
| 444 | class WifiSensitivity_UNII3_Test(WifiSensitivityTest): |
| 445 | def __init__(self, controllers): |
| 446 | base_test.BaseTestClass.__init__(self, controllers) |
Omar El Ayach | 96714c8 | 2019-01-28 18:51:46 -0800 | [diff] [blame] | 447 | self.generate_test_cases([149, 153, 157, 161], ["0", "1", "2x2"]) |
Omar El Ayach | 33f80c0 | 2018-09-27 15:02:03 -0700 | [diff] [blame] | 448 | |
| 449 | |
| 450 | class WifiSensitivity_ch1_Test(WifiSensitivityTest): |
| 451 | def __init__(self, controllers): |
| 452 | base_test.BaseTestClass.__init__(self, controllers) |
Omar El Ayach | 96714c8 | 2019-01-28 18:51:46 -0800 | [diff] [blame] | 453 | self.generate_test_cases([1], ["0", "1", "2x2"]) |
Omar El Ayach | 33f80c0 | 2018-09-27 15:02:03 -0700 | [diff] [blame] | 454 | |
| 455 | |
| 456 | class WifiSensitivity_ch2_Test(WifiSensitivityTest): |
| 457 | def __init__(self, controllers): |
| 458 | base_test.BaseTestClass.__init__(self, controllers) |
Omar El Ayach | 96714c8 | 2019-01-28 18:51:46 -0800 | [diff] [blame] | 459 | self.generate_test_cases([2], ["0", "1", "2x2"]) |
Omar El Ayach | 33f80c0 | 2018-09-27 15:02:03 -0700 | [diff] [blame] | 460 | |
| 461 | |
| 462 | class WifiSensitivity_ch6_Test(WifiSensitivityTest): |
| 463 | def __init__(self, controllers): |
| 464 | base_test.BaseTestClass.__init__(self, controllers) |
Omar El Ayach | 96714c8 | 2019-01-28 18:51:46 -0800 | [diff] [blame] | 465 | self.generate_test_cases([6], ["0", "1", "2x2"]) |
Omar El Ayach | 33f80c0 | 2018-09-27 15:02:03 -0700 | [diff] [blame] | 466 | |
| 467 | |
| 468 | class WifiSensitivity_ch10_Test(WifiSensitivityTest): |
| 469 | def __init__(self, controllers): |
| 470 | base_test.BaseTestClass.__init__(self, controllers) |
Omar El Ayach | 96714c8 | 2019-01-28 18:51:46 -0800 | [diff] [blame] | 471 | self.generate_test_cases([10], ["0", "1", "2x2"]) |
Omar El Ayach | 33f80c0 | 2018-09-27 15:02:03 -0700 | [diff] [blame] | 472 | |
| 473 | |
| 474 | class WifiSensitivity_ch11_Test(WifiSensitivityTest): |
| 475 | def __init__(self, controllers): |
| 476 | base_test.BaseTestClass.__init__(self, controllers) |
Omar El Ayach | 96714c8 | 2019-01-28 18:51:46 -0800 | [diff] [blame] | 477 | self.generate_test_cases([11], ["0", "1", "2x2"]) |
Omar El Ayach | 33f80c0 | 2018-09-27 15:02:03 -0700 | [diff] [blame] | 478 | |
| 479 | |
| 480 | class WifiSensitivity_ch36_Test(WifiSensitivityTest): |
| 481 | def __init__(self, controllers): |
| 482 | base_test.BaseTestClass.__init__(self, controllers) |
Omar El Ayach | 96714c8 | 2019-01-28 18:51:46 -0800 | [diff] [blame] | 483 | self.generate_test_cases([36], ["0", "1", "2x2"]) |
Omar El Ayach | 33f80c0 | 2018-09-27 15:02:03 -0700 | [diff] [blame] | 484 | |
| 485 | |
| 486 | class WifiSensitivity_ch40_Test(WifiSensitivityTest): |
| 487 | def __init__(self, controllers): |
| 488 | base_test.BaseTestClass.__init__(self, controllers) |
Omar El Ayach | 96714c8 | 2019-01-28 18:51:46 -0800 | [diff] [blame] | 489 | self.generate_test_cases([40], ["0", "1", "2x2"]) |
Omar El Ayach | 33f80c0 | 2018-09-27 15:02:03 -0700 | [diff] [blame] | 490 | |
| 491 | |
| 492 | class WifiSensitivity_ch44_Test(WifiSensitivityTest): |
| 493 | def __init__(self, controllers): |
| 494 | base_test.BaseTestClass.__init__(self, controllers) |
Omar El Ayach | 96714c8 | 2019-01-28 18:51:46 -0800 | [diff] [blame] | 495 | self.generate_test_cases([44], ["0", "1", "2x2"]) |
Omar El Ayach | 33f80c0 | 2018-09-27 15:02:03 -0700 | [diff] [blame] | 496 | |
| 497 | |
| 498 | class WifiSensitivity_ch48_Test(WifiSensitivityTest): |
| 499 | def __init__(self, controllers): |
| 500 | base_test.BaseTestClass.__init__(self, controllers) |
Omar El Ayach | 96714c8 | 2019-01-28 18:51:46 -0800 | [diff] [blame] | 501 | self.generate_test_cases([48], ["0", "1", "2x2"]) |
Omar El Ayach | 33f80c0 | 2018-09-27 15:02:03 -0700 | [diff] [blame] | 502 | |
| 503 | |
| 504 | class WifiSensitivity_ch149_Test(WifiSensitivityTest): |
| 505 | def __init__(self, controllers): |
| 506 | base_test.BaseTestClass.__init__(self, controllers) |
Omar El Ayach | 96714c8 | 2019-01-28 18:51:46 -0800 | [diff] [blame] | 507 | self.generate_test_cases([149], ["0", "1", "2x2"]) |
Omar El Ayach | 33f80c0 | 2018-09-27 15:02:03 -0700 | [diff] [blame] | 508 | |
| 509 | |
| 510 | class WifiSensitivity_ch153_Test(WifiSensitivityTest): |
| 511 | def __init__(self, controllers): |
| 512 | base_test.BaseTestClass.__init__(self, controllers) |
Omar El Ayach | 96714c8 | 2019-01-28 18:51:46 -0800 | [diff] [blame] | 513 | self.generate_test_cases([153], ["0", "1", "2x2"]) |
Omar El Ayach | 33f80c0 | 2018-09-27 15:02:03 -0700 | [diff] [blame] | 514 | |
| 515 | |
| 516 | class WifiSensitivity_ch157_Test(WifiSensitivityTest): |
| 517 | def __init__(self, controllers): |
| 518 | base_test.BaseTestClass.__init__(self, controllers) |
Omar El Ayach | 96714c8 | 2019-01-28 18:51:46 -0800 | [diff] [blame] | 519 | self.generate_test_cases([157], ["0", "1", "2x2"]) |
Omar El Ayach | 33f80c0 | 2018-09-27 15:02:03 -0700 | [diff] [blame] | 520 | |
| 521 | |
| 522 | class WifiSensitivity_ch161_Test(WifiSensitivityTest): |
| 523 | def __init__(self, controllers): |
| 524 | base_test.BaseTestClass.__init__(self, controllers) |
Omar El Ayach | 96714c8 | 2019-01-28 18:51:46 -0800 | [diff] [blame] | 525 | self.generate_test_cases([161], ["0", "1", "2x2"]) |