blob: aa537a25052d71a5685a5ab017f4548487961912 [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"],
Omar El Ayach03e40612019-05-01 16:25:39 -070052 36: ["legacy", "VHT20", "VHT40", "VHT80"],
Omar El Ayach33f80c02018-09-27 15:02:03 -070053 40: ["legacy", "VHT20"],
54 44: ["legacy", "VHT20"],
55 48: ["legacy", "VHT20"],
Omar El Ayach03e40612019-05-01 16:25:39 -070056 149: ["legacy", "VHT20", "VHT40", "VHT80"],
Omar El Ayach33f80c02018-09-27 15:02:03 -070057 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 Ayach03e40612019-05-01 16:25:39 -070097 "VHT40": [
98 RateTuple(9, 1, 96), RateTuple(8, 1, 86.7),
99 RateTuple(7, 1, 72.2), RateTuple(6, 1, 65),
100 RateTuple(5, 1, 57.8), RateTuple(4, 1, 43.3),
101 RateTuple(3, 1, 28.9), RateTuple(2, 1, 21.7),
102 RateTuple(1, 1, 14.4), RateTuple(0, 1, 7.2),
103 RateTuple(9, 2, 192), RateTuple(8, 2, 173.3),
104 RateTuple(7, 2, 144.4), RateTuple(6, 2, 130.3),
105 RateTuple(5, 2, 115.6), RateTuple(4, 2, 86.7),
106 RateTuple(3, 2, 57.8), RateTuple(2, 2, 43.3),
107 RateTuple(1, 2, 28.9), RateTuple(0, 2, 14.4)],
108 "VHT80": [
109 RateTuple(9, 1, 96), RateTuple(8, 1, 86.7),
110 RateTuple(7, 1, 72.2), RateTuple(6, 1, 65),
111 RateTuple(5, 1, 57.8), RateTuple(4, 1, 43.3),
112 RateTuple(3, 1, 28.9), RateTuple(2, 1, 21.7),
113 RateTuple(1, 1, 14.4), RateTuple(0, 1, 7.2),
114 RateTuple(9, 2, 192), RateTuple(8, 2, 173.3),
115 RateTuple(7, 2, 144.4), RateTuple(6, 2, 130.3),
116 RateTuple(5, 2, 115.6), RateTuple(4, 2, 86.7),
117 RateTuple(3, 2, 57.8), RateTuple(2, 2, 43.3),
118 RateTuple(1, 2, 28.9), RateTuple(0, 2, 14.4)],
Omar El Ayach33f80c02018-09-27 15:02:03 -0700119 }
Omar El Ayacha210d572019-03-14 17:31:38 -0700120 #yapf:enable
Omar El Ayach33f80c02018-09-27 15:02:03 -0700121
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800122 def __init__(self, controllers):
123 base_test.BaseTestClass.__init__(self, controllers)
124 self.failure_count_metric = BlackboxMetricLogger.for_test_case(
125 metric_name='sensitivity')
126
Omar El Ayach33f80c02018-09-27 15:02:03 -0700127 def setup_class(self):
128 """Initializes common test hardware and parameters.
129
130 This function initializes hardwares and compiles parameters that are
131 common to all tests in this class.
132 """
133 self.client_dut = self.android_devices[-1]
134 req_params = [
Omar El Ayach14416ac2019-01-30 14:58:19 -0800135 "RetailAccessPoints", "sensitivity_test_params", "testbed_params",
136 "RemoteServer"
Omar El Ayach33f80c02018-09-27 15:02:03 -0700137 ]
138 opt_params = ["main_network", "golden_files_list"]
139 self.unpack_userparams(req_params, opt_params)
140 self.testclass_params = self.sensitivity_test_params
141 self.num_atten = self.attenuators[0].instrument.num_atten
Omar El Ayach14416ac2019-01-30 14:58:19 -0800142 self.ping_server = ssh.connection.SshConnection(
143 ssh.settings.from_config(self.RemoteServer[0]["ssh_config"]))
Omar El Ayach33f80c02018-09-27 15:02:03 -0700144 self.iperf_server = self.iperf_servers[0]
Omar El Ayach14416ac2019-01-30 14:58:19 -0800145 self.iperf_client = self.iperf_clients[0]
Omar El Ayacha210d572019-03-14 17:31:38 -0700146 self.access_point = retail_ap.create(self.RetailAccessPoints)[0]
Omar El Ayach33f80c02018-09-27 15:02:03 -0700147 self.log.info("Access Point Configuration: {}".format(
148 self.access_point.ap_settings))
149 self.log_path = os.path.join(logging.log_path, "results")
150 utils.create_dir(self.log_path)
151 if not hasattr(self, "golden_files_list"):
152 self.golden_files_list = [
Omar El Ayacha210d572019-03-14 17:31:38 -0700153 os.path.join(self.testbed_params["golden_results_path"], file)
154 for file in os.listdir(
155 self.testbed_params["golden_results_path"])
Omar El Ayach33f80c02018-09-27 15:02:03 -0700156 ]
157 self.testclass_results = []
158
159 # Turn WiFi ON
160 for dev in self.android_devices:
161 wutils.wifi_toggle_state(dev, True)
162
Omar El Ayach96714c82019-01-28 18:51:46 -0800163 def teardown_class(self):
164 # Turn WiFi OFF
165 for dev in self.android_devices:
166 wutils.wifi_toggle_state(dev, False)
167 self.process_testclass_results()
168
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800169 def pass_fail_check(self, result):
Omar El Ayach33f80c02018-09-27 15:02:03 -0700170 """Checks sensitivity against golden results and decides on pass/fail.
171
172 Args:
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800173 result: dict containing attenuation, throughput and other meta
Omar El Ayach33f80c02018-09-27 15:02:03 -0700174 data
175 """
176 try:
177 golden_path = next(file_name
178 for file_name in self.golden_files_list
179 if "sensitivity_targets" in file_name)
180 with open(golden_path, 'r') as golden_file:
181 golden_results = json.load(golden_file)
Omar El Ayacha210d572019-03-14 17:31:38 -0700182 golden_sensitivity = golden_results[
183 self.current_test_name]["sensitivity"]
Omar El Ayach33f80c02018-09-27 15:02:03 -0700184 except:
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800185 golden_sensitivity = float("nan")
Omar El Ayach33f80c02018-09-27 15:02:03 -0700186
Omar El Ayach03e40612019-05-01 16:25:39 -0700187 result_string = ("Througput = {}%, Sensitivity = {}."
188 "Target Sensitivity = {}".format(
189 result["peak_throughput_pct"],
190 result["sensitivity"], golden_sensitivity))
Omar El Ayacha210d572019-03-14 17:31:38 -0700191 if result["peak_throughput_pct"] < 100:
192 self.log.warning("Result unreliable. Peak rate unstable")
193 if result["sensitivity"] - golden_sensitivity < self.testclass_params[
194 "sensitivity_tolerance"]:
Omar El Ayach33f80c02018-09-27 15:02:03 -0700195 asserts.explicit_pass("Test Passed. {}".format(result_string))
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800196 else:
197 asserts.fail("Test Failed. {}".format(result_string))
Omar El Ayach33f80c02018-09-27 15:02:03 -0700198
199 def process_testclass_results(self):
200 """Saves and plots test results from all executed test cases."""
Omar El Ayach96714c82019-01-28 18:51:46 -0800201 # write json output
Omar El Ayach33f80c02018-09-27 15:02:03 -0700202 testclass_results_dict = collections.OrderedDict()
Omar El Ayacha210d572019-03-14 17:31:38 -0700203 id_fields = ["mode", "rate", "num_streams", "chain_mask"]
204 channels_tested = []
Omar El Ayach33f80c02018-09-27 15:02:03 -0700205 for result in self.testclass_results:
Omar El Ayacha210d572019-03-14 17:31:38 -0700206 testcase_params = self.parse_test_params(result["test_name"])
207 test_id = collections.OrderedDict(
208 (key, value) for key, value in testcase_params.items()
209 if key in id_fields)
210 test_id = tuple(test_id.items())
211 channel = testcase_params["channel"]
212 if channel not in channels_tested:
213 channels_tested.append(channel)
214 if result["peak_throughput_pct"] == 100:
215 if test_id in testclass_results_dict:
216 testclass_results_dict[test_id][channel] = result[
217 "sensitivity"]
218 else:
219 testclass_results_dict[test_id] = {
220 channel: result["sensitivity"]
221 }
222
Omar El Ayach96714c82019-01-28 18:51:46 -0800223 # write csv
Omar El Ayacha210d572019-03-14 17:31:38 -0700224 csv_header = ["Mode", "MCS", "Streams", "Chain", "Rate (Mbps)"]
225 for channel in channels_tested:
226 csv_header.append("Ch. " + str(channel))
Omar El Ayach96714c82019-01-28 18:51:46 -0800227 results_file_path = os.path.join(self.log_path, 'results.csv')
228 with open(results_file_path, mode='w') as csv_file:
Omar El Ayach96714c82019-01-28 18:51:46 -0800229 writer = csv.DictWriter(csv_file, fieldnames=csv_header)
230 writer.writeheader()
Omar El Ayacha210d572019-03-14 17:31:38 -0700231 for test_id, test_results in testclass_results_dict.items():
232 test_id_dict = dict(test_id)
233 if "legacy" in test_id_dict["mode"]:
234 rate_list = self.VALID_RATES["legacy_2GHz"]
235 else:
236 rate_list = self.VALID_RATES[test_id_dict["mode"]]
237 data_rate = next(rate.data_rate for rate in rate_list
238 if rate[:-1] == (test_id_dict["rate"],
239 test_id_dict["num_streams"]))
240 row_value = {
241 "Mode": test_id_dict["mode"],
242 "MCS": test_id_dict["rate"],
243 "Streams": test_id_dict["num_streams"],
244 "Chain": test_id_dict["chain_mask"],
245 "Rate (Mbps)": data_rate,
246 }
247 for channel in channels_tested:
248 row_value["Ch. " + str(channel)] = test_results.pop(
249 channel, " ")
250 writer.writerow(row_value)
Omar El Ayach96714c82019-01-28 18:51:46 -0800251
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800252 if not self.testclass_params["traffic_type"].lower() == "ping":
253 WifiRvrTest.process_testclass_results(self)
Omar El Ayach33f80c02018-09-27 15:02:03 -0700254
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800255 def process_rvr_test_results(self, testcase_params, rvr_result):
Omar El Ayach33f80c02018-09-27 15:02:03 -0700256 """Post processes RvR results to compute sensitivity.
257
258 Takes in the results of the RvR tests and computes the sensitivity of
259 the current rate by looking at the point at which throughput drops
260 below the percentage specified in the config file. The function then
261 calls on its parent class process_test_results to plot the result.
262
263 Args:
264 rvr_result: dict containing attenuation, throughput and other meta
265 data
266 """
267 rvr_result["peak_throughput"] = max(rvr_result["throughput_receive"])
Omar El Ayacha210d572019-03-14 17:31:38 -0700268 rvr_result["peak_throughput_pct"] = 100
Omar El Ayach33f80c02018-09-27 15:02:03 -0700269 throughput_check = [
270 throughput < rvr_result["peak_throughput"] *
271 (self.testclass_params["throughput_pct_at_sensitivity"] / 100)
272 for throughput in rvr_result["throughput_receive"]
273 ]
274 consistency_check = [
275 idx for idx in range(len(throughput_check))
276 if all(throughput_check[idx:])
277 ]
278 rvr_result["atten_at_range"] = rvr_result["attenuation"][
279 consistency_check[0] - 1]
280 rvr_result["range"] = rvr_result["fixed_attenuation"] + (
281 rvr_result["atten_at_range"])
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800282 rvr_result["sensitivity"] = self.testclass_params["ap_tx_power"] + (
283 self.testbed_params["ap_tx_power_offset"][str(
284 testcase_params["channel"])] - rvr_result["range"])
285 WifiRvrTest.process_test_results(self, rvr_result)
286
287 def process_ping_test_results(self, testcase_params, ping_result):
288 """Post processes RvR results to compute sensitivity.
289
290 Takes in the results of the RvR tests and computes the sensitivity of
291 the current rate by looking at the point at which throughput drops
292 below the percentage specified in the config file. The function then
293 calls on its parent class process_test_results to plot the result.
294
295 Args:
296 rvr_result: dict containing attenuation, throughput and other meta
297 data
298 """
Omar El Ayacha210d572019-03-14 17:31:38 -0700299 testcase_params["range_ping_loss_threshold"] = 100 - testcase_params[
300 "throughput_pct_at_sensitivity"]
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800301 WifiPingTest.process_ping_results(self, testcase_params, ping_result)
302 ping_result["sensitivity"] = self.testclass_params["ap_tx_power"] + (
303 self.testbed_params["ap_tx_power_offset"][str(
304 testcase_params["channel"])] - ping_result["range"])
Omar El Ayach33f80c02018-09-27 15:02:03 -0700305
Omar El Ayach03e40612019-05-01 16:25:39 -0700306 def setup_sensitivity_test(self, testcase_params):
307 if testcase_params["traffic_type"].lower() == "ping":
308 self.setup_ping_test(testcase_params)
309 self.run_sensitivity_test = self.run_ping_test
310 self.process_sensitivity_test_results = (
311 self.process_ping_test_results)
312 else:
313 self.setup_rvr_test(testcase_params)
314 self.run_sensitivity_test = self.run_rvr_test
315 self.process_sensitivity_test_results = (
316 self.process_rvr_test_results)
317
Omar El Ayach33f80c02018-09-27 15:02:03 -0700318 def setup_ap(self, testcase_params):
Omar El Ayach5a1496bf2019-01-09 11:43:02 -0800319 """Sets up the AP and attenuator to compensate for AP chain imbalance.
Omar El Ayach33f80c02018-09-27 15:02:03 -0700320
321 Args:
322 testcase_params: dict containing AP and other test params
323 """
324 band = self.access_point.band_lookup_by_channel(
325 testcase_params["channel"])
326 if "2G" in band:
Omar El Ayacha210d572019-03-14 17:31:38 -0700327 frequency = wutils.WifiEnums.channel_2G_to_freq[
328 testcase_params["channel"]]
Omar El Ayach33f80c02018-09-27 15:02:03 -0700329 else:
Omar El Ayacha210d572019-03-14 17:31:38 -0700330 frequency = wutils.WifiEnums.channel_5G_to_freq[
331 testcase_params["channel"]]
Omar El Ayach33f80c02018-09-27 15:02:03 -0700332 if frequency in wutils.WifiEnums.DFS_5G_FREQUENCIES:
333 self.access_point.set_region(self.testbed_params["DFS_region"])
334 else:
335 self.access_point.set_region(self.testbed_params["default_region"])
336 self.access_point.set_channel(band, testcase_params["channel"])
337 self.access_point.set_bandwidth(band, testcase_params["mode"])
338 self.access_point.set_power(band, testcase_params["ap_tx_power"])
339 self.access_point.set_rate(
340 band, testcase_params["mode"], testcase_params["num_streams"],
341 testcase_params["rate"], testcase_params["short_gi"])
Omar El Ayach96714c82019-01-28 18:51:46 -0800342 # Set attenuator offsets and set attenuators to initial condition
343 atten_offsets = self.testbed_params['chain_offset'][str(
344 testcase_params['channel'])]
Omar El Ayach5a1496bf2019-01-09 11:43:02 -0800345 for atten in self.attenuators:
Omar El Ayach96714c82019-01-28 18:51:46 -0800346 if 'AP-Chain-0' in atten.path:
347 atten.offset = atten_offsets[0]
348 elif 'AP-Chain-1' in atten.path:
349 atten.offset = atten_offsets[1]
350 if testcase_params["attenuated_chain"] in atten.path:
351 atten.offset = atten.instrument.max_atten
Omar El Ayach33f80c02018-09-27 15:02:03 -0700352 self.log.info("Access Point Configuration: {}".format(
353 self.access_point.ap_settings))
354
355 def get_start_atten(self):
356 """Gets the starting attenuation for this sensitivity test.
357
358 The function gets the starting attenuation by checking whether a test
359 as the next higher MCS has been executed. If so it sets the starting
360 point a configurable number of dBs below the next MCS's sensitivity.
361
362 Returns:
363 start_atten: starting attenuation for current test
364 """
365 # Get the current and reference test config. The reference test is the
366 # one performed at the current MCS+1
367 current_test_params = self.parse_test_params(self.current_test_name)
Omar El Ayach03e40612019-05-01 16:25:39 -0700368 current_rate = current_test_params["rate"]
Omar El Ayach33f80c02018-09-27 15:02:03 -0700369 ref_test_params = current_test_params.copy()
Omar El Ayach03e40612019-05-01 16:25:39 -0700370 if "legacy" in current_test_params["mode"]:
Omar El Ayach33f80c02018-09-27 15:02:03 -0700371 if current_test_params["channel"] <= 13:
Omar El Ayach03e40612019-05-01 16:25:39 -0700372 rate_list = self.VALID_RATES["legacy_2GHz"]
Omar El Ayach33f80c02018-09-27 15:02:03 -0700373 else:
Omar El Ayach03e40612019-05-01 16:25:39 -0700374 rate_list = self.VALID_RATES["legacy_5GHz"]
375 ref_index = max(
376 0,
377 rate_list.index(self.RateTuple(current_rate, 1, current_rate))
378 - 1)
379 ref_test_params["rate"] = rate_list[ref_index].mcs
Omar El Ayach33f80c02018-09-27 15:02:03 -0700380 else:
Omar El Ayach03e40612019-05-01 16:25:39 -0700381 ref_test_params["rate"] = current_rate + 1
Omar El Ayach33f80c02018-09-27 15:02:03 -0700382
383 # Check if reference test has been run and set attenuation accordingly
384 previous_params = [
385 self.parse_test_params(result["test_name"])
386 for result in self.testclass_results
387 ]
388 try:
389 ref_index = previous_params.index(ref_test_params)
Omar El Ayacha210d572019-03-14 17:31:38 -0700390 start_atten = self.testclass_results[ref_index][
391 "atten_at_range"] - (
392 self.testclass_params["adjacent_mcs_range_gap"])
Omar El Ayach03e40612019-05-01 16:25:39 -0700393 except ValueError:
Omar El Ayach33f80c02018-09-27 15:02:03 -0700394 print("Reference test not found. Starting from {} dB".format(
395 self.testclass_params["atten_start"]))
396 start_atten = self.testclass_params["atten_start"]
397 return start_atten
398
399 def parse_test_params(self, test_name):
400 """Function that generates test params based on the test name."""
401 test_name_params = test_name.split("_")
402 testcase_params = collections.OrderedDict()
403 testcase_params["channel"] = int(test_name_params[2][2:])
404 testcase_params["mode"] = test_name_params[3]
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800405
Omar El Ayach33f80c02018-09-27 15:02:03 -0700406 if "legacy" in testcase_params["mode"].lower():
407 testcase_params["rate"] = float(
408 str(test_name_params[4]).replace("p", "."))
409 else:
410 testcase_params["rate"] = int(test_name_params[4][3:])
411 testcase_params["num_streams"] = int(test_name_params[5][3:])
Omar El Ayacha210d572019-03-14 17:31:38 -0700412 testcase_params["short_gi"] = 1
Omar El Ayach96714c82019-01-28 18:51:46 -0800413 testcase_params["chain_mask"] = test_name_params[6][2:]
414 if testcase_params["chain_mask"] in ["0", "1"]:
415 testcase_params["attenuated_chain"] = "DUT-Chain-{}".format(
416 1 if testcase_params['chain_mask'] == "0" else 0)
417 else:
418 testcase_params["attenuated_chain"] = None
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800419
Omar El Ayach33f80c02018-09-27 15:02:03 -0700420 if self.testclass_params["traffic_type"] == "UDP":
Omar El Ayach14416ac2019-01-30 14:58:19 -0800421 testcase_params["iperf_args"] = '-i 1 -t {} -J -u -b {}'.format(
Omar El Ayach33f80c02018-09-27 15:02:03 -0700422 self.testclass_params["iperf_duration"],
423 self.testclass_params["UDP_rates"][testcase_params["mode"]])
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800424 elif self.testclass_params["traffic_type"] == "TCP":
Omar El Ayach14416ac2019-01-30 14:58:19 -0800425 testcase_params["iperf_args"] = '-i 1 -t {} -J'.format(
Omar El Ayach33f80c02018-09-27 15:02:03 -0700426 self.testclass_params["iperf_duration"])
Omar El Ayach14416ac2019-01-30 14:58:19 -0800427
Omar El Ayacha210d572019-03-14 17:31:38 -0700428 if self.testclass_params["traffic_type"] != "ping" and isinstance(
429 self.iperf_client, iperf_client.IPerfClientOverAdb):
Omar El Ayach14416ac2019-01-30 14:58:19 -0800430 testcase_params["iperf_args"] += ' -R'
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800431 testcase_params["use_client_output"] = True
Omar El Ayach14416ac2019-01-30 14:58:19 -0800432 else:
433 testcase_params["use_client_output"] = False
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800434
Omar El Ayach33f80c02018-09-27 15:02:03 -0700435 return testcase_params
436
437 def _test_sensitivity(self):
438 """ Function that gets called for each test case
439
440 The function gets called in each rvr test case. The function customizes
441 the rvr test based on the test name of the test that called it
442 """
443 # Compile test parameters from config and test name
444 testcase_params = self.parse_test_params(self.current_test_name)
445 testcase_params.update(self.testclass_params)
446 testcase_params["atten_start"] = self.get_start_atten()
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800447 num_atten_steps = int(
448 (testcase_params["atten_stop"] - testcase_params["atten_start"]) /
449 testcase_params["atten_step"])
450 testcase_params["atten_range"] = [
451 testcase_params["atten_start"] + x * testcase_params["atten_step"]
452 for x in range(0, num_atten_steps)
453 ]
Omar El Ayach33f80c02018-09-27 15:02:03 -0700454
455 # Prepare devices and run test
Omar El Ayach03e40612019-05-01 16:25:39 -0700456 self.setup_sensitivity_test(testcase_params)
457 result = self.run_sensitivity_test(testcase_params)
458 self.process_sensitivity_test_results(testcase_params, result)
459
Omar El Ayach33f80c02018-09-27 15:02:03 -0700460 # Post-process results
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800461 self.testclass_results.append(result)
462 self.pass_fail_check(result)
Omar El Ayach33f80c02018-09-27 15:02:03 -0700463
Omar El Ayach96714c82019-01-28 18:51:46 -0800464 def generate_test_cases(self, channels, chain_mask):
Omar El Ayach33f80c02018-09-27 15:02:03 -0700465 """Function that auto-generates test cases for a test class."""
466 testcase_wrapper = self._test_sensitivity
467 for channel in channels:
468 for mode in self.VALID_TEST_CONFIGS[channel]:
469 if "VHT" in mode:
Omar El Ayacha210d572019-03-14 17:31:38 -0700470 rates = self.VALID_RATES[mode]
Omar El Ayach33f80c02018-09-27 15:02:03 -0700471 elif "HT" in mode:
Omar El Ayacha210d572019-03-14 17:31:38 -0700472 rates = self.VALID_RATES[mode]
Omar El Ayach33f80c02018-09-27 15:02:03 -0700473 elif "legacy" in mode and channel < 14:
474 rates = self.VALID_RATES["legacy_2GHz"]
475 elif "legacy" in mode and channel > 14:
476 rates = self.VALID_RATES["legacy_5GHz"]
477 else:
478 raise ValueError("Invalid test mode.")
Omar El Ayach96714c82019-01-28 18:51:46 -0800479 for chain, rate in itertools.product(chain_mask, rates):
480 if str(chain) in ["0", "1"] and rate[1] == 2:
481 # Do not test 2-stream rates in single chain mode
482 continue
Omar El Ayach33f80c02018-09-27 15:02:03 -0700483 if "legacy" in mode:
Omar El Ayach03e40612019-05-01 16:25:39 -0700484 testcase_name = ("test_sensitivity_ch{}_{}_{}_nss{}"
485 "_ch{}".format(
486 channel, mode,
487 str(rate.mcs).replace(".", "p"),
488 rate.streams, chain))
Omar El Ayach33f80c02018-09-27 15:02:03 -0700489 else:
Omar El Ayach03e40612019-05-01 16:25:39 -0700490 testcase_name = ("test_sensitivity_ch{}_{}_mcs{}_nss{}"
491 "_ch{}".format(
492 channel, mode, rate.mcs,
493 rate.streams, chain))
Omar El Ayach33f80c02018-09-27 15:02:03 -0700494 setattr(self, testcase_name, testcase_wrapper)
495 self.tests.append(testcase_name)
496
497
498class WifiSensitivity_AllChannels_Test(WifiSensitivityTest):
499 def __init__(self, controllers):
500 base_test.BaseTestClass.__init__(self, controllers)
501 self.generate_test_cases(
Omar El Ayach96714c82019-01-28 18:51:46 -0800502 [1, 2, 6, 10, 11, 36, 40, 44, 48, 149, 153, 157, 161],
503 ["0", "1", "2x2"])
Omar El Ayach33f80c02018-09-27 15:02:03 -0700504
505
506class WifiSensitivity_2GHz_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([1, 2, 6, 10, 11], ["0", "1", "2x2"])
Omar El Ayach33f80c02018-09-27 15:02:03 -0700510
511
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800512class WifiSensitivity_5GHz_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([36, 40, 44, 48, 149, 153, 157, 161],
516 ["0", "1", "2x2"])
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800517
518
Omar El Ayach33f80c02018-09-27 15:02:03 -0700519class WifiSensitivity_UNII1_Test(WifiSensitivityTest):
520 def __init__(self, controllers):
521 base_test.BaseTestClass.__init__(self, controllers)
Omar El Ayach96714c82019-01-28 18:51:46 -0800522 self.generate_test_cases([36, 40, 44, 48], ["0", "1", "2x2"])
Omar El Ayach33f80c02018-09-27 15:02:03 -0700523
524
525class WifiSensitivity_UNII3_Test(WifiSensitivityTest):
526 def __init__(self, controllers):
527 base_test.BaseTestClass.__init__(self, controllers)
Omar El Ayach96714c82019-01-28 18:51:46 -0800528 self.generate_test_cases([149, 153, 157, 161], ["0", "1", "2x2"])
Omar El Ayach33f80c02018-09-27 15:02:03 -0700529
530
531class WifiSensitivity_ch1_Test(WifiSensitivityTest):
532 def __init__(self, controllers):
533 base_test.BaseTestClass.__init__(self, controllers)
Omar El Ayach96714c82019-01-28 18:51:46 -0800534 self.generate_test_cases([1], ["0", "1", "2x2"])
Omar El Ayach33f80c02018-09-27 15:02:03 -0700535
536
537class WifiSensitivity_ch2_Test(WifiSensitivityTest):
538 def __init__(self, controllers):
539 base_test.BaseTestClass.__init__(self, controllers)
Omar El Ayach96714c82019-01-28 18:51:46 -0800540 self.generate_test_cases([2], ["0", "1", "2x2"])
Omar El Ayach33f80c02018-09-27 15:02:03 -0700541
542
543class WifiSensitivity_ch6_Test(WifiSensitivityTest):
544 def __init__(self, controllers):
545 base_test.BaseTestClass.__init__(self, controllers)
Omar El Ayach96714c82019-01-28 18:51:46 -0800546 self.generate_test_cases([6], ["0", "1", "2x2"])
Omar El Ayach33f80c02018-09-27 15:02:03 -0700547
548
549class WifiSensitivity_ch10_Test(WifiSensitivityTest):
550 def __init__(self, controllers):
551 base_test.BaseTestClass.__init__(self, controllers)
Omar El Ayach96714c82019-01-28 18:51:46 -0800552 self.generate_test_cases([10], ["0", "1", "2x2"])
Omar El Ayach33f80c02018-09-27 15:02:03 -0700553
554
555class WifiSensitivity_ch11_Test(WifiSensitivityTest):
556 def __init__(self, controllers):
557 base_test.BaseTestClass.__init__(self, controllers)
Omar El Ayach96714c82019-01-28 18:51:46 -0800558 self.generate_test_cases([11], ["0", "1", "2x2"])
Omar El Ayach33f80c02018-09-27 15:02:03 -0700559
560
561class WifiSensitivity_ch36_Test(WifiSensitivityTest):
562 def __init__(self, controllers):
563 base_test.BaseTestClass.__init__(self, controllers)
Omar El Ayach96714c82019-01-28 18:51:46 -0800564 self.generate_test_cases([36], ["0", "1", "2x2"])
Omar El Ayach33f80c02018-09-27 15:02:03 -0700565
566
567class WifiSensitivity_ch40_Test(WifiSensitivityTest):
568 def __init__(self, controllers):
569 base_test.BaseTestClass.__init__(self, controllers)
Omar El Ayach96714c82019-01-28 18:51:46 -0800570 self.generate_test_cases([40], ["0", "1", "2x2"])
Omar El Ayach33f80c02018-09-27 15:02:03 -0700571
572
573class WifiSensitivity_ch44_Test(WifiSensitivityTest):
574 def __init__(self, controllers):
575 base_test.BaseTestClass.__init__(self, controllers)
Omar El Ayach96714c82019-01-28 18:51:46 -0800576 self.generate_test_cases([44], ["0", "1", "2x2"])
Omar El Ayach33f80c02018-09-27 15:02:03 -0700577
578
579class WifiSensitivity_ch48_Test(WifiSensitivityTest):
580 def __init__(self, controllers):
581 base_test.BaseTestClass.__init__(self, controllers)
Omar El Ayach96714c82019-01-28 18:51:46 -0800582 self.generate_test_cases([48], ["0", "1", "2x2"])
Omar El Ayach33f80c02018-09-27 15:02:03 -0700583
584
585class WifiSensitivity_ch149_Test(WifiSensitivityTest):
586 def __init__(self, controllers):
587 base_test.BaseTestClass.__init__(self, controllers)
Omar El Ayach96714c82019-01-28 18:51:46 -0800588 self.generate_test_cases([149], ["0", "1", "2x2"])
Omar El Ayach33f80c02018-09-27 15:02:03 -0700589
590
591class WifiSensitivity_ch153_Test(WifiSensitivityTest):
592 def __init__(self, controllers):
593 base_test.BaseTestClass.__init__(self, controllers)
Omar El Ayach96714c82019-01-28 18:51:46 -0800594 self.generate_test_cases([153], ["0", "1", "2x2"])
Omar El Ayach33f80c02018-09-27 15:02:03 -0700595
596
597class WifiSensitivity_ch157_Test(WifiSensitivityTest):
598 def __init__(self, controllers):
599 base_test.BaseTestClass.__init__(self, controllers)
Omar El Ayach96714c82019-01-28 18:51:46 -0800600 self.generate_test_cases([157], ["0", "1", "2x2"])
Omar El Ayach33f80c02018-09-27 15:02:03 -0700601
602
603class WifiSensitivity_ch161_Test(WifiSensitivityTest):
604 def __init__(self, controllers):
605 base_test.BaseTestClass.__init__(self, controllers)
Omar El Ayach96714c82019-01-28 18:51:46 -0800606 self.generate_test_cases([161], ["0", "1", "2x2"])