blob: 0130a3a859f0882af61b7ca393dd0fa4ffb371ad [file] [log] [blame]
Omar El Ayach33f80c02018-09-27 15:02:03 -07001#!/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
17import collections
Omar El Ayach96714c82019-01-28 18:51:46 -080018import csv
19import itertools
Omar El Ayach33f80c02018-09-27 15:02:03 -070020import json
21import logging
22import os
Omar El Ayach33f80c02018-09-27 15:02:03 -070023from acts import asserts
24from acts import base_test
25from acts import utils
Omar El Ayacha210d572019-03-14 17:31:38 -070026from acts.controllers import iperf_client
Omar El Ayach14416ac2019-01-30 14:58:19 -080027from acts.controllers.utils_lib import ssh
Omar El Ayach5fbc1222018-12-07 18:10:05 -080028from acts.metrics.loggers.blackbox import BlackboxMetricLogger
Omar El Ayach33f80c02018-09-27 15:02:03 -070029from acts.test_utils.wifi import wifi_test_utils as wutils
30from acts.test_utils.wifi import wifi_retail_ap as retail_ap
Omar El Ayach5fbc1222018-12-07 18:10:05 -080031from WifiRvrTest import WifiRvrTest
32from WifiPingTest import WifiPingTest
Omar El Ayach33f80c02018-09-27 15:02:03 -070033
34
Omar El Ayach5fbc1222018-12-07 18:10:05 -080035class WifiSensitivityTest(WifiRvrTest, WifiPingTest):
Omar El Ayach33f80c02018-09-27 15:02:03 -070036 """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
Omar El Ayacha210d572019-03-14 17:31:38 -070045 RSSI_POLL_INTERVAL = 0.2
Omar El Ayach33f80c02018-09-27 15:02:03 -070046 VALID_TEST_CONFIGS = {
47 1: ["legacy", "VHT20"],
48 2: ["legacy", "VHT20"],
49 6: ["legacy", "VHT20"],
50 10: ["legacy", "VHT20"],
51 11: ["legacy", "VHT20"],
52 36: ["legacy", "VHT20"],
53 40: ["legacy", "VHT20"],
54 44: ["legacy", "VHT20"],
55 48: ["legacy", "VHT20"],
56 149: ["legacy", "VHT20"],
57 153: ["legacy", "VHT20"],
58 157: ["legacy", "VHT20"],
59 161: ["legacy", "VHT20"]
60 }
Omar El Ayacha210d572019-03-14 17:31:38 -070061 RateTuple = collections.namedtuple(("RateTuple"),
62 ["mcs", "streams", "data_rate"])
63 #yapf:disable
Omar El Ayach33f80c02018-09-27 15:02:03 -070064 VALID_RATES = {
Omar El Ayacha210d572019-03-14 17:31:38 -070065 "legacy_2GHz": [
66 RateTuple(54, 1, 54), RateTuple(48, 1, 48),
67 RateTuple(36, 1, 36), RateTuple(24, 1, 24),
68 RateTuple(18, 1, 18), RateTuple(12, 1, 12),
69 RateTuple(11, 1, 11), RateTuple(9, 1, 9),
70 RateTuple(6, 1, 6), RateTuple(5.5, 1, 5.5),
71 RateTuple(2, 1, 2), RateTuple(1, 1, 1)],
72 "legacy_5GHz": [
73 RateTuple(54, 1, 54), RateTuple(48, 1, 48),
74 RateTuple(36, 1, 36), RateTuple(24, 1, 24),
75 RateTuple(18, 1, 18), RateTuple(12, 1, 12),
76 RateTuple(9, 1, 9), RateTuple(6, 1, 6)],
77 "HT20": [
78 RateTuple(7, 1, 72.2), RateTuple(6, 1, 65),
79 RateTuple(5, 1, 57.8), RateTuple(4, 1, 43.3),
80 RateTuple(3, 1, 26), RateTuple(2, 1, 21.7),
81 RateTuple(1, 1, 14.4), RateTuple(0, 1, 7.2),
82 RateTuple(15, 2, 144.4), RateTuple(14, 2, 130),
83 RateTuple(13, 2, 115.6), RateTuple(12, 2, 86.7),
84 RateTuple(11, 2, 57.8), RateTuple(10, 2, 43.4),
85 RateTuple(9, 2, 28.9), RateTuple(8, 2, 14.4)],
86 "VHT20": [
87 RateTuple(9, 1, 96), RateTuple(8, 1, 86.7),
88 RateTuple(7, 1, 72.2), RateTuple(6, 1, 65),
89 RateTuple(5, 1, 57.8), RateTuple(4, 1, 43.3),
90 RateTuple(3, 1, 28.9), RateTuple(2, 1, 21.7),
91 RateTuple(1, 1, 14.4), RateTuple(0, 1, 7.2),
92 RateTuple(9, 2, 192), RateTuple(8, 2, 173.3),
93 RateTuple(7, 2, 144.4), RateTuple(6, 2, 130.3),
94 RateTuple(5, 2, 115.6), RateTuple(4, 2, 86.7),
95 RateTuple(3, 2, 57.8), RateTuple(2, 2, 43.3),
96 RateTuple(1, 2, 28.9), RateTuple(0, 2, 14.4)],
Omar El Ayach33f80c02018-09-27 15:02:03 -070097 }
Omar El Ayacha210d572019-03-14 17:31:38 -070098 #yapf:enable
Omar El Ayach33f80c02018-09-27 15:02:03 -070099
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800100 def __init__(self, controllers):
101 base_test.BaseTestClass.__init__(self, controllers)
102 self.failure_count_metric = BlackboxMetricLogger.for_test_case(
103 metric_name='sensitivity')
104
Omar El Ayach33f80c02018-09-27 15:02:03 -0700105 def setup_class(self):
106 """Initializes common test hardware and parameters.
107
108 This function initializes hardwares and compiles parameters that are
109 common to all tests in this class.
110 """
111 self.client_dut = self.android_devices[-1]
112 req_params = [
Omar El Ayach14416ac2019-01-30 14:58:19 -0800113 "RetailAccessPoints", "sensitivity_test_params", "testbed_params",
114 "RemoteServer"
Omar El Ayach33f80c02018-09-27 15:02:03 -0700115 ]
116 opt_params = ["main_network", "golden_files_list"]
117 self.unpack_userparams(req_params, opt_params)
118 self.testclass_params = self.sensitivity_test_params
119 self.num_atten = self.attenuators[0].instrument.num_atten
Omar El Ayach14416ac2019-01-30 14:58:19 -0800120 self.ping_server = ssh.connection.SshConnection(
121 ssh.settings.from_config(self.RemoteServer[0]["ssh_config"]))
Omar El Ayach33f80c02018-09-27 15:02:03 -0700122 self.iperf_server = self.iperf_servers[0]
Omar El Ayach14416ac2019-01-30 14:58:19 -0800123 self.iperf_client = self.iperf_clients[0]
Omar El Ayacha210d572019-03-14 17:31:38 -0700124 self.access_point = retail_ap.create(self.RetailAccessPoints)[0]
Omar El Ayach33f80c02018-09-27 15:02:03 -0700125 self.log.info("Access Point Configuration: {}".format(
126 self.access_point.ap_settings))
127 self.log_path = os.path.join(logging.log_path, "results")
128 utils.create_dir(self.log_path)
129 if not hasattr(self, "golden_files_list"):
130 self.golden_files_list = [
Omar El Ayacha210d572019-03-14 17:31:38 -0700131 os.path.join(self.testbed_params["golden_results_path"], file)
132 for file in os.listdir(
133 self.testbed_params["golden_results_path"])
Omar El Ayach33f80c02018-09-27 15:02:03 -0700134 ]
135 self.testclass_results = []
136
137 # Turn WiFi ON
138 for dev in self.android_devices:
139 wutils.wifi_toggle_state(dev, True)
140
Omar El Ayach96714c82019-01-28 18:51:46 -0800141 def teardown_class(self):
142 # Turn WiFi OFF
143 for dev in self.android_devices:
144 wutils.wifi_toggle_state(dev, False)
145 self.process_testclass_results()
146
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800147 def pass_fail_check(self, result):
Omar El Ayach33f80c02018-09-27 15:02:03 -0700148 """Checks sensitivity against golden results and decides on pass/fail.
149
150 Args:
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800151 result: dict containing attenuation, throughput and other meta
Omar El Ayach33f80c02018-09-27 15:02:03 -0700152 data
153 """
154 try:
155 golden_path = next(file_name
156 for file_name in self.golden_files_list
157 if "sensitivity_targets" in file_name)
158 with open(golden_path, 'r') as golden_file:
159 golden_results = json.load(golden_file)
Omar El Ayacha210d572019-03-14 17:31:38 -0700160 golden_sensitivity = golden_results[
161 self.current_test_name]["sensitivity"]
Omar El Ayach33f80c02018-09-27 15:02:03 -0700162 except:
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800163 golden_sensitivity = float("nan")
Omar El Ayach33f80c02018-09-27 15:02:03 -0700164
Omar El Ayacha210d572019-03-14 17:31:38 -0700165 result_string = "Througput = {}%, Sensitivity = {}. Target Sensitivity = {}".format(
166 result["peak_throughput_pct"], result["sensitivity"],
Omar El Ayach33f80c02018-09-27 15:02:03 -0700167 golden_sensitivity)
Omar El Ayacha210d572019-03-14 17:31:38 -0700168 if result["peak_throughput_pct"] < 100:
169 self.log.warning("Result unreliable. Peak rate unstable")
170 if result["sensitivity"] - golden_sensitivity < self.testclass_params[
171 "sensitivity_tolerance"]:
Omar El Ayach33f80c02018-09-27 15:02:03 -0700172 asserts.explicit_pass("Test Passed. {}".format(result_string))
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800173 else:
174 asserts.fail("Test Failed. {}".format(result_string))
Omar El Ayach33f80c02018-09-27 15:02:03 -0700175
176 def process_testclass_results(self):
177 """Saves and plots test results from all executed test cases."""
Omar El Ayach96714c82019-01-28 18:51:46 -0800178 # write json output
Omar El Ayach33f80c02018-09-27 15:02:03 -0700179 testclass_results_dict = collections.OrderedDict()
Omar El Ayacha210d572019-03-14 17:31:38 -0700180 id_fields = ["mode", "rate", "num_streams", "chain_mask"]
181 channels_tested = []
Omar El Ayach33f80c02018-09-27 15:02:03 -0700182 for result in self.testclass_results:
Omar El Ayacha210d572019-03-14 17:31:38 -0700183 testcase_params = self.parse_test_params(result["test_name"])
184 test_id = collections.OrderedDict(
185 (key, value) for key, value in testcase_params.items()
186 if key in id_fields)
187 test_id = tuple(test_id.items())
188 channel = testcase_params["channel"]
189 if channel not in channels_tested:
190 channels_tested.append(channel)
191 if result["peak_throughput_pct"] == 100:
192 if test_id in testclass_results_dict:
193 testclass_results_dict[test_id][channel] = result[
194 "sensitivity"]
195 else:
196 testclass_results_dict[test_id] = {
197 channel: result["sensitivity"]
198 }
199
Omar El Ayach96714c82019-01-28 18:51:46 -0800200 # write csv
Omar El Ayacha210d572019-03-14 17:31:38 -0700201 csv_header = ["Mode", "MCS", "Streams", "Chain", "Rate (Mbps)"]
202 for channel in channels_tested:
203 csv_header.append("Ch. " + str(channel))
Omar El Ayach96714c82019-01-28 18:51:46 -0800204 results_file_path = os.path.join(self.log_path, 'results.csv')
205 with open(results_file_path, mode='w') as csv_file:
Omar El Ayach96714c82019-01-28 18:51:46 -0800206 writer = csv.DictWriter(csv_file, fieldnames=csv_header)
207 writer.writeheader()
Omar El Ayacha210d572019-03-14 17:31:38 -0700208 for test_id, test_results in testclass_results_dict.items():
209 test_id_dict = dict(test_id)
210 if "legacy" in test_id_dict["mode"]:
211 rate_list = self.VALID_RATES["legacy_2GHz"]
212 else:
213 rate_list = self.VALID_RATES[test_id_dict["mode"]]
214 data_rate = next(rate.data_rate for rate in rate_list
215 if rate[:-1] == (test_id_dict["rate"],
216 test_id_dict["num_streams"]))
217 row_value = {
218 "Mode": test_id_dict["mode"],
219 "MCS": test_id_dict["rate"],
220 "Streams": test_id_dict["num_streams"],
221 "Chain": test_id_dict["chain_mask"],
222 "Rate (Mbps)": data_rate,
223 }
224 for channel in channels_tested:
225 row_value["Ch. " + str(channel)] = test_results.pop(
226 channel, " ")
227 writer.writerow(row_value)
Omar El Ayach96714c82019-01-28 18:51:46 -0800228
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800229 if not self.testclass_params["traffic_type"].lower() == "ping":
230 WifiRvrTest.process_testclass_results(self)
Omar El Ayach33f80c02018-09-27 15:02:03 -0700231
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800232 def process_rvr_test_results(self, testcase_params, rvr_result):
Omar El Ayach33f80c02018-09-27 15:02:03 -0700233 """Post processes RvR results to compute sensitivity.
234
235 Takes in the results of the RvR tests and computes the sensitivity of
236 the current rate by looking at the point at which throughput drops
237 below the percentage specified in the config file. The function then
238 calls on its parent class process_test_results to plot the result.
239
240 Args:
241 rvr_result: dict containing attenuation, throughput and other meta
242 data
243 """
244 rvr_result["peak_throughput"] = max(rvr_result["throughput_receive"])
Omar El Ayacha210d572019-03-14 17:31:38 -0700245 rvr_result["peak_throughput_pct"] = 100
Omar El Ayach33f80c02018-09-27 15:02:03 -0700246 throughput_check = [
247 throughput < rvr_result["peak_throughput"] *
248 (self.testclass_params["throughput_pct_at_sensitivity"] / 100)
249 for throughput in rvr_result["throughput_receive"]
250 ]
251 consistency_check = [
252 idx for idx in range(len(throughput_check))
253 if all(throughput_check[idx:])
254 ]
255 rvr_result["atten_at_range"] = rvr_result["attenuation"][
256 consistency_check[0] - 1]
257 rvr_result["range"] = rvr_result["fixed_attenuation"] + (
258 rvr_result["atten_at_range"])
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800259 rvr_result["sensitivity"] = self.testclass_params["ap_tx_power"] + (
260 self.testbed_params["ap_tx_power_offset"][str(
261 testcase_params["channel"])] - rvr_result["range"])
262 WifiRvrTest.process_test_results(self, rvr_result)
263
264 def process_ping_test_results(self, testcase_params, ping_result):
265 """Post processes RvR results to compute sensitivity.
266
267 Takes in the results of the RvR tests and computes the sensitivity of
268 the current rate by looking at the point at which throughput drops
269 below the percentage specified in the config file. The function then
270 calls on its parent class process_test_results to plot the result.
271
272 Args:
273 rvr_result: dict containing attenuation, throughput and other meta
274 data
275 """
Omar El Ayacha210d572019-03-14 17:31:38 -0700276 testcase_params["range_ping_loss_threshold"] = 100 - testcase_params[
277 "throughput_pct_at_sensitivity"]
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800278 WifiPingTest.process_ping_results(self, testcase_params, ping_result)
279 ping_result["sensitivity"] = self.testclass_params["ap_tx_power"] + (
280 self.testbed_params["ap_tx_power_offset"][str(
281 testcase_params["channel"])] - ping_result["range"])
Omar El Ayach33f80c02018-09-27 15:02:03 -0700282
283 def setup_ap(self, testcase_params):
Omar El Ayach5a1496bf2019-01-09 11:43:02 -0800284 """Sets up the AP and attenuator to compensate for AP chain imbalance.
Omar El Ayach33f80c02018-09-27 15:02:03 -0700285
286 Args:
287 testcase_params: dict containing AP and other test params
288 """
289 band = self.access_point.band_lookup_by_channel(
290 testcase_params["channel"])
291 if "2G" in band:
Omar El Ayacha210d572019-03-14 17:31:38 -0700292 frequency = wutils.WifiEnums.channel_2G_to_freq[
293 testcase_params["channel"]]
Omar El Ayach33f80c02018-09-27 15:02:03 -0700294 else:
Omar El Ayacha210d572019-03-14 17:31:38 -0700295 frequency = wutils.WifiEnums.channel_5G_to_freq[
296 testcase_params["channel"]]
Omar El Ayach33f80c02018-09-27 15:02:03 -0700297 if frequency in wutils.WifiEnums.DFS_5G_FREQUENCIES:
298 self.access_point.set_region(self.testbed_params["DFS_region"])
299 else:
300 self.access_point.set_region(self.testbed_params["default_region"])
301 self.access_point.set_channel(band, testcase_params["channel"])
302 self.access_point.set_bandwidth(band, testcase_params["mode"])
303 self.access_point.set_power(band, testcase_params["ap_tx_power"])
304 self.access_point.set_rate(
305 band, testcase_params["mode"], testcase_params["num_streams"],
306 testcase_params["rate"], testcase_params["short_gi"])
Omar El Ayach96714c82019-01-28 18:51:46 -0800307 # Set attenuator offsets and set attenuators to initial condition
308 atten_offsets = self.testbed_params['chain_offset'][str(
309 testcase_params['channel'])]
Omar El Ayach5a1496bf2019-01-09 11:43:02 -0800310 for atten in self.attenuators:
Omar El Ayach96714c82019-01-28 18:51:46 -0800311 if 'AP-Chain-0' in atten.path:
312 atten.offset = atten_offsets[0]
313 elif 'AP-Chain-1' in atten.path:
314 atten.offset = atten_offsets[1]
315 if testcase_params["attenuated_chain"] in atten.path:
316 atten.offset = atten.instrument.max_atten
Omar El Ayach33f80c02018-09-27 15:02:03 -0700317 self.log.info("Access Point Configuration: {}".format(
318 self.access_point.ap_settings))
319
320 def get_start_atten(self):
321 """Gets the starting attenuation for this sensitivity test.
322
323 The function gets the starting attenuation by checking whether a test
324 as the next higher MCS has been executed. If so it sets the starting
325 point a configurable number of dBs below the next MCS's sensitivity.
326
327 Returns:
328 start_atten: starting attenuation for current test
329 """
330 # Get the current and reference test config. The reference test is the
331 # one performed at the current MCS+1
332 current_test_params = self.parse_test_params(self.current_test_name)
333 ref_test_params = current_test_params.copy()
Omar El Ayacha210d572019-03-14 17:31:38 -0700334 if "legacy" in current_test_params[
335 "mode"] and current_test_params["rate"] < 54:
Omar El Ayach33f80c02018-09-27 15:02:03 -0700336 if current_test_params["channel"] <= 13:
337 ref_index = self.VALID_RATES["legacy_2GHz"].index(
Omar El Ayacha210d572019-03-14 17:31:38 -0700338 self.RateTuple(current_test_params["rate"], 1,
339 current_test_params["rate"])) - 1
Omar El Ayach33f80c02018-09-27 15:02:03 -0700340 ref_test_params["rate"] = self.VALID_RATES["legacy_2GHz"][
Omar El Ayacha210d572019-03-14 17:31:38 -0700341 ref_index].mcs
Omar El Ayach33f80c02018-09-27 15:02:03 -0700342 else:
343 ref_index = self.VALID_RATES["legacy_5GHz"].index(
Omar El Ayacha210d572019-03-14 17:31:38 -0700344 self.RateTuple(current_test_params["rate"], 1,
345 current_test_params["rate"])) - 1
Omar El Ayach33f80c02018-09-27 15:02:03 -0700346 ref_test_params["rate"] = self.VALID_RATES["legacy_5GHz"][
Omar El Ayacha210d572019-03-14 17:31:38 -0700347 ref_index].mcs
Omar El Ayach33f80c02018-09-27 15:02:03 -0700348 else:
349 ref_test_params["rate"] = ref_test_params["rate"] + 1
350
351 # Check if reference test has been run and set attenuation accordingly
352 previous_params = [
353 self.parse_test_params(result["test_name"])
354 for result in self.testclass_results
355 ]
356 try:
357 ref_index = previous_params.index(ref_test_params)
Omar El Ayacha210d572019-03-14 17:31:38 -0700358 start_atten = self.testclass_results[ref_index][
359 "atten_at_range"] - (
360 self.testclass_params["adjacent_mcs_range_gap"])
Omar El Ayach33f80c02018-09-27 15:02:03 -0700361 except:
362 print("Reference test not found. Starting from {} dB".format(
363 self.testclass_params["atten_start"]))
364 start_atten = self.testclass_params["atten_start"]
365 return start_atten
366
367 def parse_test_params(self, test_name):
368 """Function that generates test params based on the test name."""
369 test_name_params = test_name.split("_")
370 testcase_params = collections.OrderedDict()
371 testcase_params["channel"] = int(test_name_params[2][2:])
372 testcase_params["mode"] = test_name_params[3]
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800373
Omar El Ayach33f80c02018-09-27 15:02:03 -0700374 if "legacy" in testcase_params["mode"].lower():
375 testcase_params["rate"] = float(
376 str(test_name_params[4]).replace("p", "."))
377 else:
378 testcase_params["rate"] = int(test_name_params[4][3:])
379 testcase_params["num_streams"] = int(test_name_params[5][3:])
Omar El Ayacha210d572019-03-14 17:31:38 -0700380 testcase_params["short_gi"] = 1
Omar El Ayach96714c82019-01-28 18:51:46 -0800381 testcase_params["chain_mask"] = test_name_params[6][2:]
382 if testcase_params["chain_mask"] in ["0", "1"]:
383 testcase_params["attenuated_chain"] = "DUT-Chain-{}".format(
384 1 if testcase_params['chain_mask'] == "0" else 0)
385 else:
386 testcase_params["attenuated_chain"] = None
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800387
Omar El Ayach33f80c02018-09-27 15:02:03 -0700388 if self.testclass_params["traffic_type"] == "UDP":
Omar El Ayach14416ac2019-01-30 14:58:19 -0800389 testcase_params["iperf_args"] = '-i 1 -t {} -J -u -b {}'.format(
Omar El Ayach33f80c02018-09-27 15:02:03 -0700390 self.testclass_params["iperf_duration"],
391 self.testclass_params["UDP_rates"][testcase_params["mode"]])
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800392 elif self.testclass_params["traffic_type"] == "TCP":
Omar El Ayach14416ac2019-01-30 14:58:19 -0800393 testcase_params["iperf_args"] = '-i 1 -t {} -J'.format(
Omar El Ayach33f80c02018-09-27 15:02:03 -0700394 self.testclass_params["iperf_duration"])
Omar El Ayach14416ac2019-01-30 14:58:19 -0800395
Omar El Ayacha210d572019-03-14 17:31:38 -0700396 if self.testclass_params["traffic_type"] != "ping" and isinstance(
397 self.iperf_client, iperf_client.IPerfClientOverAdb):
Omar El Ayach14416ac2019-01-30 14:58:19 -0800398 testcase_params["iperf_args"] += ' -R'
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800399 testcase_params["use_client_output"] = True
Omar El Ayach14416ac2019-01-30 14:58:19 -0800400 else:
401 testcase_params["use_client_output"] = False
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800402
Omar El Ayach33f80c02018-09-27 15:02:03 -0700403 return testcase_params
404
405 def _test_sensitivity(self):
406 """ Function that gets called for each test case
407
408 The function gets called in each rvr test case. The function customizes
409 the rvr test based on the test name of the test that called it
410 """
411 # Compile test parameters from config and test name
412 testcase_params = self.parse_test_params(self.current_test_name)
413 testcase_params.update(self.testclass_params)
414 testcase_params["atten_start"] = self.get_start_atten()
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800415 num_atten_steps = int(
416 (testcase_params["atten_stop"] - testcase_params["atten_start"]) /
417 testcase_params["atten_step"])
418 testcase_params["atten_range"] = [
419 testcase_params["atten_start"] + x * testcase_params["atten_step"]
420 for x in range(0, num_atten_steps)
421 ]
Omar El Ayach33f80c02018-09-27 15:02:03 -0700422
423 # Prepare devices and run test
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800424 if testcase_params["traffic_type"].lower() == "ping":
425 self.setup_ping_test(testcase_params)
426 result = self.run_ping_test(testcase_params)
427 self.process_ping_test_results(testcase_params, result)
428 else:
429 self.setup_rvr_test(testcase_params)
430 result = self.run_rvr_test(testcase_params)
Omar El Ayach5a1496bf2019-01-09 11:43:02 -0800431 self.process_rvr_test_results(testcase_params, result)
Omar El Ayach33f80c02018-09-27 15:02:03 -0700432 # Post-process results
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800433 self.testclass_results.append(result)
434 self.pass_fail_check(result)
Omar El Ayach33f80c02018-09-27 15:02:03 -0700435
Omar El Ayach96714c82019-01-28 18:51:46 -0800436 def generate_test_cases(self, channels, chain_mask):
Omar El Ayach33f80c02018-09-27 15:02:03 -0700437 """Function that auto-generates test cases for a test class."""
438 testcase_wrapper = self._test_sensitivity
439 for channel in channels:
440 for mode in self.VALID_TEST_CONFIGS[channel]:
441 if "VHT" in mode:
Omar El Ayacha210d572019-03-14 17:31:38 -0700442 rates = self.VALID_RATES[mode]
Omar El Ayach33f80c02018-09-27 15:02:03 -0700443 elif "HT" in mode:
Omar El Ayacha210d572019-03-14 17:31:38 -0700444 rates = self.VALID_RATES[mode]
Omar El Ayach33f80c02018-09-27 15:02:03 -0700445 elif "legacy" in mode and channel < 14:
446 rates = self.VALID_RATES["legacy_2GHz"]
447 elif "legacy" in mode and channel > 14:
448 rates = self.VALID_RATES["legacy_5GHz"]
449 else:
450 raise ValueError("Invalid test mode.")
Omar El Ayach96714c82019-01-28 18:51:46 -0800451 for chain, rate in itertools.product(chain_mask, rates):
452 if str(chain) in ["0", "1"] and rate[1] == 2:
453 # Do not test 2-stream rates in single chain mode
454 continue
Omar El Ayach33f80c02018-09-27 15:02:03 -0700455 if "legacy" in mode:
Omar El Ayach96714c82019-01-28 18:51:46 -0800456 testcase_name = "test_sensitivity_ch{}_{}_{}_nss{}_ch{}".format(
Omar El Ayach33f80c02018-09-27 15:02:03 -0700457 channel, mode,
Omar El Ayacha210d572019-03-14 17:31:38 -0700458 str(rate.mcs).replace(".", "p"), rate.streams,
459 chain)
Omar El Ayach33f80c02018-09-27 15:02:03 -0700460 else:
Omar El Ayach96714c82019-01-28 18:51:46 -0800461 testcase_name = "test_sensitivity_ch{}_{}_mcs{}_nss{}_ch{}".format(
Omar El Ayacha210d572019-03-14 17:31:38 -0700462 channel, mode, rate.mcs, rate.streams, chain)
Omar El Ayach33f80c02018-09-27 15:02:03 -0700463 setattr(self, testcase_name, testcase_wrapper)
464 self.tests.append(testcase_name)
465
466
467class WifiSensitivity_AllChannels_Test(WifiSensitivityTest):
468 def __init__(self, controllers):
469 base_test.BaseTestClass.__init__(self, controllers)
470 self.generate_test_cases(
Omar El Ayach96714c82019-01-28 18:51:46 -0800471 [1, 2, 6, 10, 11, 36, 40, 44, 48, 149, 153, 157, 161],
472 ["0", "1", "2x2"])
Omar El Ayach33f80c02018-09-27 15:02:03 -0700473
474
475class WifiSensitivity_2GHz_Test(WifiSensitivityTest):
476 def __init__(self, controllers):
477 base_test.BaseTestClass.__init__(self, controllers)
Omar El Ayach96714c82019-01-28 18:51:46 -0800478 self.generate_test_cases([1, 2, 6, 10, 11], ["0", "1", "2x2"])
Omar El Ayach33f80c02018-09-27 15:02:03 -0700479
480
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800481class WifiSensitivity_5GHz_Test(WifiSensitivityTest):
482 def __init__(self, controllers):
483 base_test.BaseTestClass.__init__(self, controllers)
Omar El Ayach96714c82019-01-28 18:51:46 -0800484 self.generate_test_cases([36, 40, 44, 48, 149, 153, 157, 161],
485 ["0", "1", "2x2"])
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800486
487
Omar El Ayach33f80c02018-09-27 15:02:03 -0700488class WifiSensitivity_UNII1_Test(WifiSensitivityTest):
489 def __init__(self, controllers):
490 base_test.BaseTestClass.__init__(self, controllers)
Omar El Ayach96714c82019-01-28 18:51:46 -0800491 self.generate_test_cases([36, 40, 44, 48], ["0", "1", "2x2"])
Omar El Ayach33f80c02018-09-27 15:02:03 -0700492
493
494class WifiSensitivity_UNII3_Test(WifiSensitivityTest):
495 def __init__(self, controllers):
496 base_test.BaseTestClass.__init__(self, controllers)
Omar El Ayach96714c82019-01-28 18:51:46 -0800497 self.generate_test_cases([149, 153, 157, 161], ["0", "1", "2x2"])
Omar El Ayach33f80c02018-09-27 15:02:03 -0700498
499
500class WifiSensitivity_ch1_Test(WifiSensitivityTest):
501 def __init__(self, controllers):
502 base_test.BaseTestClass.__init__(self, controllers)
Omar El Ayach96714c82019-01-28 18:51:46 -0800503 self.generate_test_cases([1], ["0", "1", "2x2"])
Omar El Ayach33f80c02018-09-27 15:02:03 -0700504
505
506class WifiSensitivity_ch2_Test(WifiSensitivityTest):
507 def __init__(self, controllers):
508 base_test.BaseTestClass.__init__(self, controllers)
Omar El Ayach96714c82019-01-28 18:51:46 -0800509 self.generate_test_cases([2], ["0", "1", "2x2"])
Omar El Ayach33f80c02018-09-27 15:02:03 -0700510
511
512class WifiSensitivity_ch6_Test(WifiSensitivityTest):
513 def __init__(self, controllers):
514 base_test.BaseTestClass.__init__(self, controllers)
Omar El Ayach96714c82019-01-28 18:51:46 -0800515 self.generate_test_cases([6], ["0", "1", "2x2"])
Omar El Ayach33f80c02018-09-27 15:02:03 -0700516
517
518class WifiSensitivity_ch10_Test(WifiSensitivityTest):
519 def __init__(self, controllers):
520 base_test.BaseTestClass.__init__(self, controllers)
Omar El Ayach96714c82019-01-28 18:51:46 -0800521 self.generate_test_cases([10], ["0", "1", "2x2"])
Omar El Ayach33f80c02018-09-27 15:02:03 -0700522
523
524class WifiSensitivity_ch11_Test(WifiSensitivityTest):
525 def __init__(self, controllers):
526 base_test.BaseTestClass.__init__(self, controllers)
Omar El Ayach96714c82019-01-28 18:51:46 -0800527 self.generate_test_cases([11], ["0", "1", "2x2"])
Omar El Ayach33f80c02018-09-27 15:02:03 -0700528
529
530class WifiSensitivity_ch36_Test(WifiSensitivityTest):
531 def __init__(self, controllers):
532 base_test.BaseTestClass.__init__(self, controllers)
Omar El Ayach96714c82019-01-28 18:51:46 -0800533 self.generate_test_cases([36], ["0", "1", "2x2"])
Omar El Ayach33f80c02018-09-27 15:02:03 -0700534
535
536class WifiSensitivity_ch40_Test(WifiSensitivityTest):
537 def __init__(self, controllers):
538 base_test.BaseTestClass.__init__(self, controllers)
Omar El Ayach96714c82019-01-28 18:51:46 -0800539 self.generate_test_cases([40], ["0", "1", "2x2"])
Omar El Ayach33f80c02018-09-27 15:02:03 -0700540
541
542class WifiSensitivity_ch44_Test(WifiSensitivityTest):
543 def __init__(self, controllers):
544 base_test.BaseTestClass.__init__(self, controllers)
Omar El Ayach96714c82019-01-28 18:51:46 -0800545 self.generate_test_cases([44], ["0", "1", "2x2"])
Omar El Ayach33f80c02018-09-27 15:02:03 -0700546
547
548class WifiSensitivity_ch48_Test(WifiSensitivityTest):
549 def __init__(self, controllers):
550 base_test.BaseTestClass.__init__(self, controllers)
Omar El Ayach96714c82019-01-28 18:51:46 -0800551 self.generate_test_cases([48], ["0", "1", "2x2"])
Omar El Ayach33f80c02018-09-27 15:02:03 -0700552
553
554class WifiSensitivity_ch149_Test(WifiSensitivityTest):
555 def __init__(self, controllers):
556 base_test.BaseTestClass.__init__(self, controllers)
Omar El Ayach96714c82019-01-28 18:51:46 -0800557 self.generate_test_cases([149], ["0", "1", "2x2"])
Omar El Ayach33f80c02018-09-27 15:02:03 -0700558
559
560class WifiSensitivity_ch153_Test(WifiSensitivityTest):
561 def __init__(self, controllers):
562 base_test.BaseTestClass.__init__(self, controllers)
Omar El Ayach96714c82019-01-28 18:51:46 -0800563 self.generate_test_cases([153], ["0", "1", "2x2"])
Omar El Ayach33f80c02018-09-27 15:02:03 -0700564
565
566class WifiSensitivity_ch157_Test(WifiSensitivityTest):
567 def __init__(self, controllers):
568 base_test.BaseTestClass.__init__(self, controllers)
Omar El Ayach96714c82019-01-28 18:51:46 -0800569 self.generate_test_cases([157], ["0", "1", "2x2"])
Omar El Ayach33f80c02018-09-27 15:02:03 -0700570
571
572class WifiSensitivity_ch161_Test(WifiSensitivityTest):
573 def __init__(self, controllers):
574 base_test.BaseTestClass.__init__(self, controllers)
Omar El Ayach96714c82019-01-28 18:51:46 -0800575 self.generate_test_cases([161], ["0", "1", "2x2"])