blob: 531d9cb83919f8905933c284f3d09ec7ee1dc86b [file] [log] [blame]
Omar El Ayache95eecc2018-02-27 16:12:08 -08001#!/usr/bin/env python3.4
2#
3# Copyright 2018 - The Android Open Source Project
4#
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -07005# Licensed under the Apache License, Version 2.0 (the 'License');
Omar El Ayache95eecc2018-02-27 16:12:08 -08006# 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
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -070012# distributed under the License is distributed on an 'AS IS' BASIS,
Omar El Ayache95eecc2018-02-27 16:12:08 -080013# 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
Omar El Ayach5c9d3d52018-10-17 17:59:09 -070017import collections
Omar El Ayachd05bf022019-07-10 14:09:54 -070018import itertools
Omar El Ayache95eecc2018-02-27 16:12:08 -080019import json
20import logging
21import math
Omar El Ayach3903e342019-09-17 19:17:03 -070022import numpy
Omar El Ayache95eecc2018-02-27 16:12:08 -080023import os
Omar El Ayache84e8742018-03-19 16:42:44 -070024import statistics
Omar El Ayache95eecc2018-02-27 16:12:08 -080025from acts import asserts
26from acts import base_test
Omar El Ayach3903e342019-09-17 19:17:03 -070027from acts import context
Omar El Ayache95eecc2018-02-27 16:12:08 -080028from acts import utils
Omar El Ayach2819be62019-04-11 12:00:00 -070029from acts.controllers.utils_lib import ssh
Omar El Ayach14416ac2019-01-30 14:58:19 -080030from acts.controllers import iperf_server as ipf
Xianyuan Jia976d4042019-09-30 17:19:47 -070031from acts.metrics.loggers.blackbox import BlackboxMappedMetricLogger
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -070032from acts.test_utils.wifi import ota_chamber
Omar El Ayach48533142019-02-20 15:56:34 -080033from acts.test_utils.wifi import wifi_performance_test_utils as wputils
Omar El Ayache95eecc2018-02-27 16:12:08 -080034from acts.test_utils.wifi import wifi_retail_ap as retail_ap
35from acts.test_utils.wifi import wifi_test_utils as wutils
Omar El Ayach14416ac2019-01-30 14:58:19 -080036from concurrent.futures import ThreadPoolExecutor
Omar El Ayachd05bf022019-07-10 14:09:54 -070037from functools import partial
Omar El Ayache95eecc2018-02-27 16:12:08 -080038
39SHORT_SLEEP = 1
40MED_SLEEP = 6
Omar El Ayache95eecc2018-02-27 16:12:08 -080041CONST_3dB = 3.01029995664
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -070042RSSI_ERROR_VAL = float('nan')
Omar El Ayache95eecc2018-02-27 16:12:08 -080043
44
45class WifiRssiTest(base_test.BaseTestClass):
Omar El Ayachbb828982018-08-27 15:47:41 -070046 """Class to test WiFi RSSI reporting.
47
48 This class tests RSSI reporting on android devices. The class tests RSSI
49 accuracy by checking RSSI over a large attenuation range, checks for RSSI
50 stability over time when attenuation is fixed, and checks that RSSI quickly
51 and reacts to changes attenuation by checking RSSI trajectories over
52 configurable attenuation waveforms.For an example config file to run this
53 test class see example_connectivity_performance_ap_sta.json.
54 """
Omar El Ayache95eecc2018-02-27 16:12:08 -080055 def __init__(self, controllers):
56 base_test.BaseTestClass.__init__(self, controllers)
Omar El Ayacha7c3afe2019-09-16 15:58:29 -070057 self.testcase_metric_logger = (
Xianyuan Jia976d4042019-09-30 17:19:47 -070058 BlackboxMappedMetricLogger.for_test_case())
Omar El Ayacha7c3afe2019-09-16 15:58:29 -070059 self.testclass_metric_logger = (
Xianyuan Jia976d4042019-09-30 17:19:47 -070060 BlackboxMappedMetricLogger.for_test_class())
Omar El Ayach02a1cce2019-09-19 17:51:39 -070061 self.publish_test_metrics = True
Omar El Ayache95eecc2018-02-27 16:12:08 -080062
63 def setup_class(self):
64 self.dut = self.android_devices[0]
Omar El Ayach5c9d3d52018-10-17 17:59:09 -070065 req_params = [
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -070066 'RemoteServer', 'RetailAccessPoints', 'rssi_test_params',
67 'main_network', 'testbed_params'
Omar El Ayach5c9d3d52018-10-17 17:59:09 -070068 ]
69 self.unpack_userparams(req_params)
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -070070 self.testclass_params = self.rssi_test_params
Omar El Ayache95eecc2018-02-27 16:12:08 -080071 self.num_atten = self.attenuators[0].instrument.num_atten
72 self.iperf_server = self.iperf_servers[0]
Omar El Ayach14416ac2019-01-30 14:58:19 -080073 self.iperf_client = self.iperf_clients[0]
Omar El Ayach2819be62019-04-11 12:00:00 -070074 self.remote_server = ssh.connection.SshConnection(
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -070075 ssh.settings.from_config(self.RemoteServer[0]['ssh_config']))
Omar El Ayach14416ac2019-01-30 14:58:19 -080076 self.access_point = retail_ap.create(self.RetailAccessPoints)[0]
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -070077 self.log_path = os.path.join(logging.log_path, 'results')
Mark De Ruyter72f8df92020-02-12 13:44:49 -080078 os.makedirs(self.log_path, exist_ok=True)
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -070079 self.log.info('Access Point Configuration: {}'.format(
Omar El Ayache95eecc2018-02-27 16:12:08 -080080 self.access_point.ap_settings))
Omar El Ayach9c56cf32019-09-19 13:07:51 -070081 if hasattr(self, 'bdf'):
82 self.log.info('Pushing WiFi BDF to DUT.')
83 wputils.push_bdf(self.dut, self.bdf)
84 if hasattr(self, 'firmware'):
85 self.log.info('Pushing WiFi firmware to DUT.')
86 wlanmdsp = [
87 file for file in self.firmware if "wlanmdsp.mbn" in file
88 ][0]
89 data_msc = [file for file in self.firmware
90 if "Data.msc" in file][0]
91 wputils.push_firmware(self.dut, wlanmdsp, data_msc)
Omar El Ayache95eecc2018-02-27 16:12:08 -080092 self.testclass_results = []
93
Omar El Ayach9c56cf32019-09-19 13:07:51 -070094 # Turn WiFi ON
Omar El Ayachd7109092019-09-29 18:31:33 -070095 if self.testclass_params.get('airplane_mode', 1):
96 self.log.info('Turning on airplane mode.')
Omar El Ayach35bf3b82019-12-06 19:29:19 -080097 asserts.assert_true(utils.force_airplane_mode(self.dut, True),
98 "Can not turn on airplane mode.")
Omar El Ayach9c56cf32019-09-19 13:07:51 -070099 wutils.wifi_toggle_state(self.dut, True)
100
Omar El Ayache95eecc2018-02-27 16:12:08 -0800101 def teardown_test(self):
102 self.iperf_server.stop()
103
Omar El Ayachd05bf022019-07-10 14:09:54 -0700104 def pass_fail_check_rssi_stability(self, testcase_params,
105 postprocessed_results):
Omar El Ayache84e8742018-03-19 16:42:44 -0700106 """Check the test result and decide if it passed or failed.
107
108 Checks the RSSI test result and fails the test if the standard
109 deviation of signal_poll_rssi is beyond the threshold defined in the
110 config file.
111
112 Args:
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700113 testcase_params: dict containing test-specific parameters
Omar El Ayach8f7f0b22018-06-01 21:20:19 -0700114 postprocessed_results: compiled arrays of RSSI measurements
Omar El Ayache84e8742018-03-19 16:42:44 -0700115 """
Omar El Ayach059c5cf2018-10-26 18:45:25 -0700116 # Set Blackbox metric values
Omar El Ayach02a1cce2019-09-19 17:51:39 -0700117 if self.publish_test_metrics:
118 self.testcase_metric_logger.add_metric(
119 'signal_poll_rssi_stdev',
120 max(postprocessed_results['signal_poll_rssi']['stdev']))
121 self.testcase_metric_logger.add_metric(
122 'chain_0_rssi_stdev',
123 max(postprocessed_results['chain_0_rssi']['stdev']))
124 self.testcase_metric_logger.add_metric(
125 'chain_1_rssi_stdev',
126 max(postprocessed_results['chain_1_rssi']['stdev']))
Omar El Ayacha7c3afe2019-09-16 15:58:29 -0700127
Omar El Ayach059c5cf2018-10-26 18:45:25 -0700128 # Evaluate test pass/fail
Omar El Ayache84e8742018-03-19 16:42:44 -0700129 test_failed = any([
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700130 stdev > self.testclass_params['stdev_tolerance']
131 for stdev in postprocessed_results['signal_poll_rssi']['stdev']
Omar El Ayache84e8742018-03-19 16:42:44 -0700132 ])
Omar El Ayach8f7f0b22018-06-01 21:20:19 -0700133 test_message = (
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700134 'RSSI stability {0}. Standard deviation was {1} dB '
135 '(limit {2}), per chain standard deviation [{3}, {4}] dB'.format(
136 'failed' * test_failed + 'passed' * (not test_failed), [
137 float('{:.2f}'.format(x))
138 for x in postprocessed_results['signal_poll_rssi']['stdev']
139 ], self.testclass_params['stdev_tolerance'], [
140 float('{:.2f}'.format(x))
141 for x in postprocessed_results['chain_0_rssi']['stdev']
Omar El Ayache84e8742018-03-19 16:42:44 -0700142 ], [
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700143 float('{:.2f}'.format(x))
144 for x in postprocessed_results['chain_1_rssi']['stdev']
Omar El Ayache84e8742018-03-19 16:42:44 -0700145 ]))
Omar El Ayach8f7f0b22018-06-01 21:20:19 -0700146 if test_failed:
147 asserts.fail(test_message)
148 asserts.explicit_pass(test_message)
Omar El Ayache84e8742018-03-19 16:42:44 -0700149
Omar El Ayachd05bf022019-07-10 14:09:54 -0700150 def pass_fail_check_rssi_accuracy(self, testcase_params,
151 postprocessed_results):
Omar El Ayache95eecc2018-02-27 16:12:08 -0800152 """Check the test result and decide if it passed or failed.
153
154 Checks the RSSI test result and compares and compute its deviation from
155 the predicted RSSI. This computation is done for all reported RSSI
156 values. The test fails if any of the RSSI values specified in
157 rssi_under_test have an average error beyond what is specified in the
158 configuration file.
159
160 Args:
Omar El Ayach8f7f0b22018-06-01 21:20:19 -0700161 postprocessed_results: compiled arrays of RSSI measurements
Omar El Ayachd05bf022019-07-10 14:09:54 -0700162 testcase_params: dict containing params such as list of RSSIs under
163 test, i.e., can cause test to fail and boolean indicating whether
164 to look at absolute RSSI accuracy, or centered RSSI accuracy.
165 Centered accuracy is computed after systematic RSSI shifts are
166 removed.
Omar El Ayache95eecc2018-02-27 16:12:08 -0800167 """
Omar El Ayache95eecc2018-02-27 16:12:08 -0800168 test_failed = False
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700169 test_message = ''
170 if testcase_params['absolute_accuracy']:
171 error_type = 'absolute'
Omar El Ayach8f7f0b22018-06-01 21:20:19 -0700172 else:
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700173 error_type = 'centered'
Omar El Ayach8f7f0b22018-06-01 21:20:19 -0700174
175 for key, val in postprocessed_results.items():
Omar El Ayache95eecc2018-02-27 16:12:08 -0800176 # Compute the error metrics ignoring invalid RSSI readings
177 # If all readings invalid, set error to RSSI_ERROR_VAL
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700178 if 'rssi' in key and 'predicted' not in key:
179 filtered_error = [x for x in val['error'] if not math.isnan(x)]
Omar El Ayach8f7f0b22018-06-01 21:20:19 -0700180 if filtered_error:
181 avg_shift = statistics.mean(filtered_error)
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700182 if testcase_params['absolute_accuracy']:
Omar El Ayach8f7f0b22018-06-01 21:20:19 -0700183 avg_error = statistics.mean(
184 [abs(x) for x in filtered_error])
185 else:
186 avg_error = statistics.mean(
187 [abs(x - avg_shift) for x in filtered_error])
188 else:
189 avg_error = RSSI_ERROR_VAL
190 avg_shift = RSSI_ERROR_VAL
Omar El Ayach059c5cf2018-10-26 18:45:25 -0700191 # Set Blackbox metric values
Omar El Ayach02a1cce2019-09-19 17:51:39 -0700192 if self.publish_test_metrics:
193 self.testcase_metric_logger.add_metric(
194 '{}_error'.format(key), avg_error)
195 self.testcase_metric_logger.add_metric(
196 '{}_shift'.format(key), avg_shift)
Omar El Ayach059c5cf2018-10-26 18:45:25 -0700197 # Evaluate test pass/fail
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700198 rssi_failure = (avg_error >
199 self.testclass_params['abs_tolerance']
Omar El Ayach8f7f0b22018-06-01 21:20:19 -0700200 ) or math.isnan(avg_error)
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700201 if rssi_failure and key in testcase_params['rssi_under_test']:
Omar El Ayach8f7f0b22018-06-01 21:20:19 -0700202 test_message = test_message + (
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700203 '{} failed ({} error = {:.2f} dB, '
204 'shift = {:.2f} dB)\n').format(key, error_type,
Omar El Ayach5c9d3d52018-10-17 17:59:09 -0700205 avg_error, avg_shift)
Omar El Ayach8f7f0b22018-06-01 21:20:19 -0700206 test_failed = True
207 elif rssi_failure:
208 test_message = test_message + (
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700209 '{} failed (ignored) ({} error = {:.2f} dB, '
210 'shift = {:.2f} dB)\n').format(key, error_type,
Omar El Ayach5c9d3d52018-10-17 17:59:09 -0700211 avg_error, avg_shift)
Omar El Ayach8f7f0b22018-06-01 21:20:19 -0700212 else:
213 test_message = test_message + (
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700214 '{} passed ({} error = {:.2f} dB, '
215 'shift = {:.2f} dB)\n').format(key, error_type,
Omar El Ayach5c9d3d52018-10-17 17:59:09 -0700216 avg_error, avg_shift)
Omar El Ayache95eecc2018-02-27 16:12:08 -0800217 if test_failed:
218 asserts.fail(test_message)
219 asserts.explicit_pass(test_message)
220
Omar El Ayach8f7f0b22018-06-01 21:20:19 -0700221 def post_process_rssi_sweep(self, rssi_result):
222 """Postprocesses and saves JSON formatted results.
Omar El Ayache95eecc2018-02-27 16:12:08 -0800223
224 Args:
225 rssi_result: dict containing attenuation, rssi and other meta
226 data
227 Returns:
Omar El Ayach8f7f0b22018-06-01 21:20:19 -0700228 postprocessed_results: compiled arrays of RSSI data used in
Omar El Ayache95eecc2018-02-27 16:12:08 -0800229 pass/fail check
230 """
231 # Save output as text file
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700232 results_file_path = os.path.join(self.log_path, self.current_test_name)
233 with open(results_file_path, 'w') as results_file:
Omar El Ayache84e8742018-03-19 16:42:44 -0700234 json.dump(rssi_result, results_file, indent=4)
Omar El Ayache95eecc2018-02-27 16:12:08 -0800235 # Compile results into arrays of RSSIs suitable for plotting
Omar El Ayach5c9d3d52018-10-17 17:59:09 -0700236 # yapf: disable
237 postprocessed_results = collections.OrderedDict(
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700238 [('signal_poll_rssi', {}),
239 ('signal_poll_avg_rssi', {}),
240 ('scan_rssi', {}),
241 ('chain_0_rssi', {}),
242 ('chain_1_rssi', {}),
243 ('total_attenuation', []),
244 ('predicted_rssi', [])])
Omar El Ayach5c9d3d52018-10-17 17:59:09 -0700245 # yapf: enable
Omar El Ayach8f7f0b22018-06-01 21:20:19 -0700246 for key, val in postprocessed_results.items():
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700247 if 'scan_rssi' in key:
248 postprocessed_results[key]['data'] = [
249 x for data_point in rssi_result['rssi_result'] for x in
250 data_point[key][rssi_result['connected_bssid']]['data']
Omar El Ayach8f7f0b22018-06-01 21:20:19 -0700251 ]
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700252 postprocessed_results[key]['mean'] = [
253 x[key][rssi_result['connected_bssid']]['mean']
254 for x in rssi_result['rssi_result']
Omar El Ayach8f7f0b22018-06-01 21:20:19 -0700255 ]
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700256 postprocessed_results[key]['stdev'] = [
257 x[key][rssi_result['connected_bssid']]['stdev']
258 for x in rssi_result['rssi_result']
Omar El Ayach8f7f0b22018-06-01 21:20:19 -0700259 ]
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700260 elif 'predicted_rssi' in key:
261 postprocessed_results['total_attenuation'] = [
262 att + rssi_result['fixed_attenuation'] +
263 rssi_result['dut_front_end_loss']
264 for att in rssi_result['attenuation']
Omar El Ayach8f7f0b22018-06-01 21:20:19 -0700265 ]
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700266 postprocessed_results['predicted_rssi'] = [
267 rssi_result['ap_tx_power'] - att
268 for att in postprocessed_results['total_attenuation']
Omar El Ayach8f7f0b22018-06-01 21:20:19 -0700269 ]
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700270 elif 'rssi' in key:
271 postprocessed_results[key]['data'] = [
272 x for data_point in rssi_result['rssi_result']
273 for x in data_point[key]['data']
Omar El Ayach8f7f0b22018-06-01 21:20:19 -0700274 ]
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700275 postprocessed_results[key]['mean'] = [
276 x[key]['mean'] for x in rssi_result['rssi_result']
Omar El Ayach8f7f0b22018-06-01 21:20:19 -0700277 ]
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700278 postprocessed_results[key]['stdev'] = [
279 x[key]['stdev'] for x in rssi_result['rssi_result']
Omar El Ayach8f7f0b22018-06-01 21:20:19 -0700280 ]
281 # Compute RSSI errors
282 for key, val in postprocessed_results.items():
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700283 if 'chain' in key:
284 postprocessed_results[key]['error'] = [
285 postprocessed_results[key]['mean'][idx] + CONST_3dB -
286 postprocessed_results['predicted_rssi'][idx]
Omar El Ayach8f7f0b22018-06-01 21:20:19 -0700287 for idx in range(
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700288 len(postprocessed_results['predicted_rssi']))
Omar El Ayach8f7f0b22018-06-01 21:20:19 -0700289 ]
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700290 elif 'rssi' in key and 'predicted' not in key:
291 postprocessed_results[key]['error'] = [
292 postprocessed_results[key]['mean'][idx] -
293 postprocessed_results['predicted_rssi'][idx]
Omar El Ayach8f7f0b22018-06-01 21:20:19 -0700294 for idx in range(
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700295 len(postprocessed_results['predicted_rssi']))
Omar El Ayach8f7f0b22018-06-01 21:20:19 -0700296 ]
297 return postprocessed_results
298
299 def plot_rssi_vs_attenuation(self, postprocessed_results):
300 """Function to plot RSSI vs attenuation sweeps
301
302 Args:
303 postprocessed_results: compiled arrays of RSSI data.
304 """
Omar El Ayach35bf3b82019-12-06 19:29:19 -0800305 figure = wputils.BokehFigure(self.current_test_name,
306 x_label='Attenuation (dB)',
307 primary_y_label='RSSI (dBm)')
308 figure.add_line(postprocessed_results['total_attenuation'],
309 postprocessed_results['signal_poll_rssi']['mean'],
310 'Signal Poll RSSI',
311 marker='circle')
312 figure.add_line(postprocessed_results['total_attenuation'],
313 postprocessed_results['scan_rssi']['mean'],
314 'Scan RSSI',
315 marker='circle')
316 figure.add_line(postprocessed_results['total_attenuation'],
317 postprocessed_results['chain_0_rssi']['mean'],
318 'Chain 0 RSSI',
319 marker='circle')
320 figure.add_line(postprocessed_results['total_attenuation'],
321 postprocessed_results['chain_1_rssi']['mean'],
322 'Chain 1 RSSI',
323 marker='circle')
324 figure.add_line(postprocessed_results['total_attenuation'],
325 postprocessed_results['predicted_rssi'],
326 'Predicted RSSI',
327 marker='circle')
Omar El Ayach37be28a2019-04-10 16:29:26 -0700328
329 output_file_path = os.path.join(self.log_path,
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700330 self.current_test_name + '.html')
Omar El Ayach37be28a2019-04-10 16:29:26 -0700331 figure.generate_figure(output_file_path)
Omar El Ayach8f7f0b22018-06-01 21:20:19 -0700332
333 def plot_rssi_vs_time(self, rssi_result, postprocessed_results,
334 center_curves):
335 """Function to plot RSSI vs time.
336
337 Args:
338 rssi_result: dict containing raw RSSI data
339 postprocessed_results: compiled arrays of RSSI data
340 center_curvers: boolean indicating whether to shift curves to align
341 them with predicted RSSIs
342 """
Omar El Ayach37be28a2019-04-10 16:29:26 -0700343 figure = wputils.BokehFigure(
344 self.current_test_name,
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700345 x_label='Time (s)',
Omar El Ayach954eb282019-09-30 15:33:32 -0700346 primary_y_label=center_curves * 'Centered' + 'RSSI (dBm)',
Omar El Ayach37be28a2019-04-10 16:29:26 -0700347 )
348
Omar El Ayach5c9d3d52018-10-17 17:59:09 -0700349 # yapf: disable
350 rssi_time_series = collections.OrderedDict(
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700351 [('signal_poll_rssi', []),
352 ('signal_poll_avg_rssi', []),
353 ('scan_rssi', []),
354 ('chain_0_rssi', []),
355 ('chain_1_rssi', []),
356 ('predicted_rssi', [])])
Omar El Ayach5c9d3d52018-10-17 17:59:09 -0700357 # yapf: enable
Omar El Ayach8f7f0b22018-06-01 21:20:19 -0700358 for key, val in rssi_time_series.items():
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700359 if 'predicted_rssi' in key:
Omar El Ayach8f7f0b22018-06-01 21:20:19 -0700360 rssi_time_series[key] = [
361 x for x in postprocessed_results[key] for copies in range(
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700362 len(rssi_result['rssi_result'][0]['signal_poll_rssi']
363 ['data']))
Omar El Ayach8f7f0b22018-06-01 21:20:19 -0700364 ]
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700365 elif 'rssi' in key:
Omar El Ayach8f7f0b22018-06-01 21:20:19 -0700366 if center_curves:
367 filtered_error = [
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700368 x for x in postprocessed_results[key]['error']
Omar El Ayach8f7f0b22018-06-01 21:20:19 -0700369 if not math.isnan(x)
370 ]
371 if filtered_error:
372 avg_shift = statistics.mean(filtered_error)
373 else:
374 avg_shift = 0
375 rssi_time_series[key] = [
376 x - avg_shift
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700377 for x in postprocessed_results[key]['data']
Omar El Ayach8f7f0b22018-06-01 21:20:19 -0700378 ]
379 else:
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700380 rssi_time_series[key] = postprocessed_results[key]['data']
Omar El Ayach48533142019-02-20 15:56:34 -0800381 time_vec = [
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700382 self.testclass_params['polling_frequency'] * x
Omar El Ayach8f7f0b22018-06-01 21:20:19 -0700383 for x in range(len(rssi_time_series[key]))
384 ]
385 if len(rssi_time_series[key]) > 0:
Omar El Ayach37be28a2019-04-10 16:29:26 -0700386 figure.add_line(time_vec, rssi_time_series[key], key)
387
388 output_file_path = os.path.join(self.log_path,
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700389 self.current_test_name + '.html')
Omar El Ayach37be28a2019-04-10 16:29:26 -0700390 figure.generate_figure(output_file_path)
Omar El Ayache95eecc2018-02-27 16:12:08 -0800391
Omar El Ayachd05bf022019-07-10 14:09:54 -0700392 def plot_rssi_distribution(self, postprocessed_results):
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700393 """Function to plot RSSI distributions.
394
395 Args:
396 postprocessed_results: compiled arrays of RSSI data
397 """
398 monitored_rssis = ['signal_poll_rssi', 'chain_0_rssi', 'chain_1_rssi']
Omar El Ayachd05bf022019-07-10 14:09:54 -0700399
400 rssi_dist = collections.OrderedDict()
401 for rssi_key in monitored_rssis:
402 rssi_data = postprocessed_results[rssi_key]
403 rssi_dist[rssi_key] = collections.OrderedDict()
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700404 unique_rssi = sorted(set(rssi_data['data']))
Omar El Ayachd05bf022019-07-10 14:09:54 -0700405 rssi_counts = []
406 for value in unique_rssi:
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700407 rssi_counts.append(rssi_data['data'].count(value))
Omar El Ayachd05bf022019-07-10 14:09:54 -0700408 total_count = sum(rssi_counts)
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700409 rssi_dist[rssi_key]['rssi_values'] = unique_rssi
410 rssi_dist[rssi_key]['rssi_pdf'] = [
Omar El Ayachd05bf022019-07-10 14:09:54 -0700411 x / total_count for x in rssi_counts
412 ]
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700413 rssi_dist[rssi_key]['rssi_cdf'] = []
Omar El Ayachd05bf022019-07-10 14:09:54 -0700414 cum_prob = 0
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700415 for prob in rssi_dist[rssi_key]['rssi_pdf']:
Omar El Ayachd05bf022019-07-10 14:09:54 -0700416 cum_prob += prob
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700417 rssi_dist[rssi_key]['rssi_cdf'].append(cum_prob)
Omar El Ayachd05bf022019-07-10 14:09:54 -0700418
Omar El Ayach35bf3b82019-12-06 19:29:19 -0800419 figure = wputils.BokehFigure(self.current_test_name,
420 x_label='RSSI (dBm)',
421 primary_y_label='p(RSSI = x)',
422 secondary_y_label='p(RSSI <= x)')
Omar El Ayachd05bf022019-07-10 14:09:54 -0700423 for rssi_key, rssi_data in rssi_dist.items():
Omar El Ayach35bf3b82019-12-06 19:29:19 -0800424 figure.add_line(x_data=rssi_data['rssi_values'],
425 y_data=rssi_data['rssi_pdf'],
426 legend='{} PDF'.format(rssi_key),
427 y_axis='default')
428 figure.add_line(x_data=rssi_data['rssi_values'],
429 y_data=rssi_data['rssi_cdf'],
430 legend='{} CDF'.format(rssi_key),
431 y_axis='secondary')
Omar El Ayachd05bf022019-07-10 14:09:54 -0700432 output_file_path = os.path.join(self.log_path,
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700433 self.current_test_name + '_dist.html')
Omar El Ayachd05bf022019-07-10 14:09:54 -0700434 figure.generate_figure(output_file_path)
435
436 def run_rssi_test(self, testcase_params):
Omar El Ayache95eecc2018-02-27 16:12:08 -0800437 """Test function to run RSSI tests.
438
439 The function runs an RSSI test in the current device/AP configuration.
440 Function is called from another wrapper function that sets up the
441 testbed for the RvR test
442
443 Args:
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700444 testcase_params: dict containing test-specific parameters
Omar El Ayache95eecc2018-02-27 16:12:08 -0800445 Returns:
446 rssi_result: dict containing rssi_result and meta data
447 """
Omar El Ayachd05bf022019-07-10 14:09:54 -0700448 # Run test and log result
Omar El Ayach74f78dc2019-07-30 15:15:34 -0700449 rssi_result = collections.OrderedDict()
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700450 rssi_result['test_name'] = self.current_test_name
Omar El Ayach3903e342019-09-17 19:17:03 -0700451 rssi_result['testcase_params'] = testcase_params
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700452 rssi_result['ap_settings'] = self.access_point.ap_settings.copy()
453 rssi_result['attenuation'] = list(testcase_params['rssi_atten_range'])
454 rssi_result['connected_bssid'] = self.main_network[
455 testcase_params['band']].get('BSSID', '00:00:00:00')
Omar El Ayach35bf3b82019-12-06 19:29:19 -0800456 channel_mode_combo = '{}_{}'.format(str(testcase_params['channel']),
457 testcase_params['mode'])
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700458 channel_str = str(testcase_params['channel'])
459 if channel_mode_combo in self.testbed_params['ap_tx_power']:
460 rssi_result['ap_tx_power'] = self.testbed_params['ap_tx_power'][
Omar El Ayachd05bf022019-07-10 14:09:54 -0700461 channel_mode_combo]
462 else:
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700463 rssi_result['ap_tx_power'] = self.testbed_params['ap_tx_power'][
464 str(testcase_params['channel'])]
465 rssi_result['fixed_attenuation'] = self.testbed_params[
466 'fixed_attenuation'][channel_str]
467 rssi_result['dut_front_end_loss'] = self.testbed_params[
468 'dut_front_end_loss'][channel_str]
Omar El Ayachd05bf022019-07-10 14:09:54 -0700469
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700470 self.log.info('Start running RSSI test.')
471 rssi_result['rssi_result'] = []
472 rssi_result['llstats'] = []
Omar El Ayachd05bf022019-07-10 14:09:54 -0700473 llstats_obj = wputils.LinkLayerStats(self.dut)
Omar El Ayache95eecc2018-02-27 16:12:08 -0800474 # Start iperf traffic if required by test
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700475 if testcase_params['active_traffic'] and testcase_params[
476 'traffic_type'] == 'iperf':
Omar El Ayache95eecc2018-02-27 16:12:08 -0800477 self.iperf_server.start(tag=0)
Omar El Ayach14416ac2019-01-30 14:58:19 -0800478 if isinstance(self.iperf_server, ipf.IPerfServerOverAdb):
479 iperf_server_address = self.dut_ip
480 else:
Omar El Ayach2819be62019-04-11 12:00:00 -0700481 iperf_server_address = wputils.get_server_address(
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700482 self.remote_server, self.dut_ip, '255.255.255.0')
Omar El Ayach14416ac2019-01-30 14:58:19 -0800483 executor = ThreadPoolExecutor(max_workers=1)
Omar El Ayach48533142019-02-20 15:56:34 -0800484 thread_future = executor.submit(
Omar El Ayachd05bf022019-07-10 14:09:54 -0700485 self.iperf_client.start, iperf_server_address,
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700486 testcase_params['iperf_args'], 0,
487 testcase_params['traffic_timeout'] + SHORT_SLEEP)
Omar El Ayach48533142019-02-20 15:56:34 -0800488 executor.shutdown(wait=False)
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700489 elif testcase_params['active_traffic'] and testcase_params[
490 'traffic_type'] == 'ping':
Omar El Ayachd05bf022019-07-10 14:09:54 -0700491 thread_future = wputils.get_ping_stats_nb(
492 self.remote_server, self.dut_ip,
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700493 testcase_params['traffic_timeout'], 0.02, 64)
494 for atten in testcase_params['rssi_atten_range']:
Omar El Ayache95eecc2018-02-27 16:12:08 -0800495 # Set Attenuation
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700496 self.log.info('Setting attenuation to {} dB'.format(atten))
Omar El Ayach5c9d3d52018-10-17 17:59:09 -0700497 for attenuator in self.attenuators:
498 attenuator.set_atten(atten)
Omar El Ayachd05bf022019-07-10 14:09:54 -0700499 llstats_obj.update_stats()
Omar El Ayach5c9d3d52018-10-17 17:59:09 -0700500 current_rssi = collections.OrderedDict()
Omar El Ayach48533142019-02-20 15:56:34 -0800501 current_rssi = wputils.get_connected_rssi(
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700502 self.dut, testcase_params['connected_measurements'],
503 self.testclass_params['polling_frequency'],
504 testcase_params['first_measurement_delay'])
505 current_rssi['scan_rssi'] = wputils.get_scan_rssi(
506 self.dut, testcase_params['tracked_bssid'],
507 testcase_params['scan_measurements'])
508 rssi_result['rssi_result'].append(current_rssi)
Omar El Ayachd05bf022019-07-10 14:09:54 -0700509 llstats_obj.update_stats()
510 curr_llstats = llstats_obj.llstats_incremental.copy()
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700511 rssi_result['llstats'].append(curr_llstats)
Omar El Ayachd05bf022019-07-10 14:09:54 -0700512 self.log.info(
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700513 'Connected RSSI at {0:.2f} dB is {1:.2f} [{2:.2f}, {3:.2f}] dB'
514 .format(atten, current_rssi['signal_poll_rssi']['mean'],
515 current_rssi['chain_0_rssi']['mean'],
516 current_rssi['chain_1_rssi']['mean']))
Omar El Ayache95eecc2018-02-27 16:12:08 -0800517 # Stop iperf traffic if needed
Omar El Ayach5c9d3d52018-10-17 17:59:09 -0700518 for attenuator in self.attenuators:
519 attenuator.set_atten(0)
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700520 if testcase_params['active_traffic']:
Omar El Ayach48533142019-02-20 15:56:34 -0800521 thread_future.result()
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700522 if testcase_params['traffic_type'] == 'iperf':
Omar El Ayachd05bf022019-07-10 14:09:54 -0700523 self.iperf_server.stop()
Omar El Ayache95eecc2018-02-27 16:12:08 -0800524 return rssi_result
525
Omar El Ayachd05bf022019-07-10 14:09:54 -0700526 def setup_ap(self, testcase_params):
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700527 """Function that gets devices ready for the test.
528
529 Args:
530 testcase_params: dict containing test-specific parameters
531 """
532 if '2G' in testcase_params['band']:
Omar El Ayachd05bf022019-07-10 14:09:54 -0700533 frequency = wutils.WifiEnums.channel_2G_to_freq[
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700534 testcase_params['channel']]
Omar El Ayach48533142019-02-20 15:56:34 -0800535 else:
Omar El Ayachd05bf022019-07-10 14:09:54 -0700536 frequency = wutils.WifiEnums.channel_5G_to_freq[
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700537 testcase_params['channel']]
Omar El Ayach48533142019-02-20 15:56:34 -0800538 if frequency in wutils.WifiEnums.DFS_5G_FREQUENCIES:
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700539 self.access_point.set_region(self.testbed_params['DFS_region'])
Omar El Ayach48533142019-02-20 15:56:34 -0800540 else:
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700541 self.access_point.set_region(self.testbed_params['default_region'])
542 self.access_point.set_channel(testcase_params['band'],
543 testcase_params['channel'])
544 self.access_point.set_bandwidth(testcase_params['band'],
545 testcase_params['mode'])
546 self.log.info('Access Point Configuration: {}'.format(
Omar El Ayach48533142019-02-20 15:56:34 -0800547 self.access_point.ap_settings))
548
Omar El Ayachd05bf022019-07-10 14:09:54 -0700549 def setup_dut(self, testcase_params):
Omar El Ayach48533142019-02-20 15:56:34 -0800550 """Sets up the DUT in the configuration required by the test."""
Omar El Ayach656bf3d2019-07-31 15:04:53 -0700551 # Check battery level before test
552 if not wputils.health_check(self.dut, 10):
553 asserts.skip('Battery level too low. Skipping test.')
554 # Turn screen off to preserve battery
555 self.dut.go_to_sleep()
Omar El Ayach35bf3b82019-12-06 19:29:19 -0800556 if wputils.validate_network(self.dut,
557 testcase_params['test_network']['SSID']):
Omar El Ayach39acf802019-08-02 17:52:39 -0700558 self.log.info('Already connected to desired network')
559 else:
560 wutils.wifi_toggle_state(self.dut, True)
561 wutils.reset_wifi(self.dut)
562 self.main_network[testcase_params['band']][
563 'channel'] = testcase_params['channel']
Roshan Pius5b19a122019-09-13 08:07:30 -0700564 wutils.set_wifi_country_code(self.dut,
Omar El Ayach39acf802019-08-02 17:52:39 -0700565 self.testclass_params['country_code'])
Omar El Ayach35bf3b82019-12-06 19:29:19 -0800566 wutils.wifi_connect(self.dut,
567 self.main_network[testcase_params['band']],
568 num_of_tries=5)
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700569 self.dut_ip = self.dut.droid.connectivityGetIPv4Addresses('wlan0')[0]
Omar El Ayach48533142019-02-20 15:56:34 -0800570
Omar El Ayachd05bf022019-07-10 14:09:54 -0700571 def setup_rssi_test(self, testcase_params):
Omar El Ayache95eecc2018-02-27 16:12:08 -0800572 """Main function to test RSSI.
573
574 The function sets up the AP in the correct channel and mode
575 configuration and called rssi_test to sweep attenuation and measure
576 RSSI
577
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700578 Args:
579 testcase_params: dict containing test-specific parameters
Omar El Ayache95eecc2018-02-27 16:12:08 -0800580 Returns:
581 rssi_result: dict containing rssi_results and meta data
582 """
Omar El Ayache95eecc2018-02-27 16:12:08 -0800583 # Configure AP
Omar El Ayachd05bf022019-07-10 14:09:54 -0700584 self.setup_ap(testcase_params)
Omar El Ayach48533142019-02-20 15:56:34 -0800585 # Initialize attenuators
Omar El Ayach5c9d3d52018-10-17 17:59:09 -0700586 for attenuator in self.attenuators:
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700587 attenuator.set_atten(testcase_params['rssi_atten_range'][0])
Omar El Ayache95eecc2018-02-27 16:12:08 -0800588 # Connect DUT to Network
Omar El Ayachd05bf022019-07-10 14:09:54 -0700589 self.setup_dut(testcase_params)
Omar El Ayache95eecc2018-02-27 16:12:08 -0800590
Omar El Ayachd05bf022019-07-10 14:09:54 -0700591 def get_traffic_timeout(self, testcase_params):
Omar El Ayach48533142019-02-20 15:56:34 -0800592 """Function to comput iperf session length required in RSSI test.
593
594 Args:
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700595 testcase_params: dict containing test-specific parameters
Omar El Ayach48533142019-02-20 15:56:34 -0800596 Returns:
Omar El Ayachd05bf022019-07-10 14:09:54 -0700597 traffic_timeout: length of iperf session required in rssi test
Omar El Ayach48533142019-02-20 15:56:34 -0800598 """
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700599 atten_step_duration = testcase_params['first_measurement_delay'] + (
600 testcase_params['connected_measurements'] *
601 self.testclass_params['polling_frequency']
602 ) + testcase_params['scan_measurements'] * MED_SLEEP
603 timeout = len(testcase_params['rssi_atten_range']
Omar El Ayachd05bf022019-07-10 14:09:54 -0700604 ) * atten_step_duration + MED_SLEEP
605 return timeout
Omar El Ayach48533142019-02-20 15:56:34 -0800606
Omar El Ayachd05bf022019-07-10 14:09:54 -0700607 def compile_rssi_vs_atten_test_params(self, testcase_params):
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700608 """Function to complete compiling test-specific parameters
609
610 Args:
611 testcase_params: dict containing test-specific parameters
612 """
Omar El Ayachd05bf022019-07-10 14:09:54 -0700613 testcase_params.update(
614 connected_measurements=self.
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700615 testclass_params['rssi_vs_atten_connected_measurements'],
Omar El Ayachd05bf022019-07-10 14:09:54 -0700616 scan_measurements=self.
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700617 testclass_params['rssi_vs_atten_scan_measurements'],
Omar El Ayachd05bf022019-07-10 14:09:54 -0700618 first_measurement_delay=MED_SLEEP,
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700619 rssi_under_test=self.testclass_params['rssi_vs_atten_metrics'],
Omar El Ayachd05bf022019-07-10 14:09:54 -0700620 absolute_accuracy=1)
Omar El Ayache95eecc2018-02-27 16:12:08 -0800621
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700622 testcase_params['band'] = self.access_point.band_lookup_by_channel(
623 testcase_params['channel'])
Omar El Ayach35bf3b82019-12-06 19:29:19 -0800624 testcase_params['test_network'] = self.main_network[
625 testcase_params['band']]
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700626 testcase_params['tracked_bssid'] = [
627 self.main_network[testcase_params['band']].get(
628 'BSSID', '00:00:00:00')
Omar El Ayachd05bf022019-07-10 14:09:54 -0700629 ]
630
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700631 num_atten_steps = int((self.testclass_params['rssi_vs_atten_stop'] -
632 self.testclass_params['rssi_vs_atten_start']) /
633 self.testclass_params['rssi_vs_atten_step'])
634 testcase_params['rssi_atten_range'] = [
635 self.testclass_params['rssi_vs_atten_start'] +
636 x * self.testclass_params['rssi_vs_atten_step']
Omar El Ayache84e8742018-03-19 16:42:44 -0700637 for x in range(0, num_atten_steps)
638 ]
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700639 testcase_params['traffic_timeout'] = self.get_traffic_timeout(
Omar El Ayachd05bf022019-07-10 14:09:54 -0700640 testcase_params)
641
Omar El Ayach48533142019-02-20 15:56:34 -0800642 if isinstance(self.iperf_server, ipf.IPerfServerOverAdb):
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700643 testcase_params['iperf_args'] = '-i 1 -t {} -J'.format(
644 testcase_params['traffic_timeout'])
Omar El Ayach48533142019-02-20 15:56:34 -0800645 else:
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700646 testcase_params['iperf_args'] = '-i 1 -t {} -J -R'.format(
647 testcase_params['traffic_timeout'])
Omar El Ayachd05bf022019-07-10 14:09:54 -0700648 return testcase_params
Omar El Ayache95eecc2018-02-27 16:12:08 -0800649
Omar El Ayachd05bf022019-07-10 14:09:54 -0700650 def compile_rssi_stability_test_params(self, testcase_params):
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700651 """Function to complete compiling test-specific parameters
652
653 Args:
654 testcase_params: dict containing test-specific parameters
655 """
Omar El Ayachd05bf022019-07-10 14:09:54 -0700656 testcase_params.update(
657 connected_measurements=int(
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700658 self.testclass_params['rssi_stability_duration'] /
659 self.testclass_params['polling_frequency']),
Omar El Ayach3903e342019-09-17 19:17:03 -0700660 scan_measurements=0,
Omar El Ayachd05bf022019-07-10 14:09:54 -0700661 first_measurement_delay=MED_SLEEP,
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700662 rssi_atten_range=self.testclass_params['rssi_stability_atten'])
663 testcase_params['band'] = self.access_point.band_lookup_by_channel(
664 testcase_params['channel'])
Omar El Ayach35bf3b82019-12-06 19:29:19 -0800665 testcase_params['test_network'] = self.main_network[
666 testcase_params['band']]
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700667 testcase_params['tracked_bssid'] = [
668 self.main_network[testcase_params['band']].get(
669 'BSSID', '00:00:00:00')
Omar El Ayachd05bf022019-07-10 14:09:54 -0700670 ]
Omar El Ayache95eecc2018-02-27 16:12:08 -0800671
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700672 testcase_params['traffic_timeout'] = self.get_traffic_timeout(
Omar El Ayachd05bf022019-07-10 14:09:54 -0700673 testcase_params)
Omar El Ayach48533142019-02-20 15:56:34 -0800674 if isinstance(self.iperf_server, ipf.IPerfServerOverAdb):
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700675 testcase_params['iperf_args'] = '-i 1 -t {} -J'.format(
676 testcase_params['traffic_timeout'])
Omar El Ayach48533142019-02-20 15:56:34 -0800677 else:
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700678 testcase_params['iperf_args'] = '-i 1 -t {} -J -R'.format(
679 testcase_params['traffic_timeout'])
Omar El Ayachd05bf022019-07-10 14:09:54 -0700680 return testcase_params
Omar El Ayach8f7f0b22018-06-01 21:20:19 -0700681
Omar El Ayachd05bf022019-07-10 14:09:54 -0700682 def compile_rssi_tracking_test_params(self, testcase_params):
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700683 """Function to complete compiling test-specific parameters
684
685 Args:
686 testcase_params: dict containing test-specific parameters
687 """
Omar El Ayach35bf3b82019-12-06 19:29:19 -0800688 testcase_params.update(connected_measurements=int(
689 1 / self.testclass_params['polling_frequency']),
690 scan_measurements=0,
691 first_measurement_delay=0,
692 rssi_under_test=['signal_poll_rssi'],
693 absolute_accuracy=0)
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700694 testcase_params['band'] = self.access_point.band_lookup_by_channel(
695 testcase_params['channel'])
Omar El Ayach35bf3b82019-12-06 19:29:19 -0800696 testcase_params['test_network'] = self.main_network[
697 testcase_params['band']]
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700698 testcase_params['tracked_bssid'] = [
699 self.main_network[testcase_params['band']].get(
700 'BSSID', '00:00:00:00')
Omar El Ayachd05bf022019-07-10 14:09:54 -0700701 ]
Omar El Ayach8f7f0b22018-06-01 21:20:19 -0700702
Omar El Ayachd05bf022019-07-10 14:09:54 -0700703 rssi_atten_range = []
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700704 for waveform in self.testclass_params['rssi_tracking_waveforms']:
Omar El Ayach8f7f0b22018-06-01 21:20:19 -0700705 waveform_vector = []
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700706 for section in range(len(waveform['atten_levels']) - 1):
707 section_limits = waveform['atten_levels'][section:section + 2]
Omar El Ayach319fb892019-02-21 16:10:08 -0800708 up_down = (1 - 2 * (section_limits[1] < section_limits[0]))
709 temp_section = list(
710 range(section_limits[0], section_limits[1] + up_down,
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700711 up_down * waveform['step_size']))
Omar El Ayach319fb892019-02-21 16:10:08 -0800712 temp_section = [
713 temp_section[idx] for idx in range(len(temp_section))
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700714 for n in range(waveform['step_duration'])
Omar El Ayach319fb892019-02-21 16:10:08 -0800715 ]
716 waveform_vector += temp_section
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700717 waveform_vector = waveform_vector * waveform['repetitions']
Omar El Ayachd05bf022019-07-10 14:09:54 -0700718 rssi_atten_range = rssi_atten_range + waveform_vector
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700719 testcase_params['rssi_atten_range'] = rssi_atten_range
720 testcase_params['traffic_timeout'] = self.get_traffic_timeout(
Omar El Ayachd05bf022019-07-10 14:09:54 -0700721 testcase_params)
722
Omar El Ayach48533142019-02-20 15:56:34 -0800723 if isinstance(self.iperf_server, ipf.IPerfServerOverAdb):
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700724 testcase_params['iperf_args'] = '-i 1 -t {} -J'.format(
725 testcase_params['traffic_timeout'])
Omar El Ayach48533142019-02-20 15:56:34 -0800726 else:
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700727 testcase_params['iperf_args'] = '-i 1 -t {} -J -R'.format(
728 testcase_params['traffic_timeout'])
Omar El Ayachd05bf022019-07-10 14:09:54 -0700729 return testcase_params
730
731 def _test_rssi_vs_atten(self, testcase_params):
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700732 """Function that gets called for each test case of rssi_vs_atten
Omar El Ayachd05bf022019-07-10 14:09:54 -0700733
734 The function gets called in each rssi test case. The function
735 customizes the test based on the test name of the test that called it
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700736
737 Args:
738 testcase_params: dict containing test-specific parameters
Omar El Ayachd05bf022019-07-10 14:09:54 -0700739 """
740 testcase_params = self.compile_rssi_vs_atten_test_params(
741 testcase_params)
742
743 self.setup_rssi_test(testcase_params)
744 rssi_result = self.run_rssi_test(testcase_params)
Omar El Ayach3903e342019-09-17 19:17:03 -0700745 rssi_result['postprocessed_results'] = self.post_process_rssi_sweep(
746 rssi_result)
Omar El Ayachd05bf022019-07-10 14:09:54 -0700747 self.testclass_results.append(rssi_result)
Omar El Ayach3903e342019-09-17 19:17:03 -0700748 self.plot_rssi_vs_attenuation(rssi_result['postprocessed_results'])
749 self.pass_fail_check_rssi_accuracy(
750 testcase_params, rssi_result['postprocessed_results'])
Omar El Ayachd05bf022019-07-10 14:09:54 -0700751
752 def _test_rssi_stability(self, testcase_params):
753 """ Function that gets called for each test case of rssi_stability
754
755 The function gets called in each stability test case. The function
756 customizes test based on the test name of the test that called it
757 """
758 testcase_params = self.compile_rssi_stability_test_params(
759 testcase_params)
760
761 self.setup_rssi_test(testcase_params)
762 rssi_result = self.run_rssi_test(testcase_params)
Omar El Ayach3903e342019-09-17 19:17:03 -0700763 rssi_result['postprocessed_results'] = self.post_process_rssi_sweep(
764 rssi_result)
Omar El Ayachd05bf022019-07-10 14:09:54 -0700765 self.testclass_results.append(rssi_result)
Omar El Ayach3903e342019-09-17 19:17:03 -0700766 self.plot_rssi_vs_time(rssi_result,
767 rssi_result['postprocessed_results'], 1)
768 self.plot_rssi_distribution(rssi_result['postprocessed_results'])
769 self.pass_fail_check_rssi_stability(
770 testcase_params, rssi_result['postprocessed_results'])
Omar El Ayachea963392018-03-07 09:31:55 -0800771
Omar El Ayachd05bf022019-07-10 14:09:54 -0700772 def _test_rssi_tracking(self, testcase_params):
773 """ Function that gets called for each test case of rssi_tracking
Omar El Ayache84e8742018-03-19 16:42:44 -0700774
Omar El Ayachd05bf022019-07-10 14:09:54 -0700775 The function gets called in each rssi test case. The function
776 customizes the test based on the test name of the test that called it
777 """
778 testcase_params = self.compile_rssi_tracking_test_params(
779 testcase_params)
Omar El Ayache84e8742018-03-19 16:42:44 -0700780
Omar El Ayachd05bf022019-07-10 14:09:54 -0700781 self.setup_rssi_test(testcase_params)
782 rssi_result = self.run_rssi_test(testcase_params)
Omar El Ayach3903e342019-09-17 19:17:03 -0700783 rssi_result['postprocessed_results'] = self.post_process_rssi_sweep(
784 rssi_result)
Omar El Ayachd05bf022019-07-10 14:09:54 -0700785 self.testclass_results.append(rssi_result)
Omar El Ayach3903e342019-09-17 19:17:03 -0700786 self.plot_rssi_vs_time(rssi_result,
787 rssi_result['postprocessed_results'], 1)
788 self.pass_fail_check_rssi_accuracy(
789 testcase_params, rssi_result['postprocessed_results'])
Omar El Ayache84e8742018-03-19 16:42:44 -0700790
Omar El Ayachd05bf022019-07-10 14:09:54 -0700791 def generate_test_cases(self, test_types, channels, modes, traffic_modes):
792 """Function that auto-generates test cases for a test class."""
793 test_cases = []
794 allowed_configs = {
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700795 'VHT20': [
Omar El Ayachd05bf022019-07-10 14:09:54 -0700796 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 36, 40, 44, 48, 149, 153,
797 157, 161
798 ],
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700799 'VHT40': [36, 44, 149, 157],
800 'VHT80': [36, 149]
Omar El Ayachd05bf022019-07-10 14:09:54 -0700801 }
Omar El Ayache84e8742018-03-19 16:42:44 -0700802
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700803 for channel, mode, traffic_mode, test_type in itertools.product(
Omar El Ayachd05bf022019-07-10 14:09:54 -0700804 channels, modes, traffic_modes, test_types):
805 if channel not in allowed_configs[mode]:
806 continue
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700807 test_name = test_type + '_ch{}_{}_{}'.format(
808 channel, mode, traffic_mode)
809 testcase_params = collections.OrderedDict(
Omar El Ayachd05bf022019-07-10 14:09:54 -0700810 channel=channel,
811 mode=mode,
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700812 active_traffic=(traffic_mode == 'ActiveTraffic'),
813 traffic_type=self.user_params['rssi_test_params']
814 ['traffic_type'],
Omar El Ayachd05bf022019-07-10 14:09:54 -0700815 )
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700816 test_function = getattr(self, '_{}'.format(test_type))
817 setattr(self, test_name, partial(test_function, testcase_params))
Omar El Ayachd05bf022019-07-10 14:09:54 -0700818 test_cases.append(test_name)
819 return test_cases
Omar El Ayach8f7f0b22018-06-01 21:20:19 -0700820
Omar El Ayache84e8742018-03-19 16:42:44 -0700821
822class WifiRssi_2GHz_ActiveTraffic_Test(WifiRssiTest):
823 def __init__(self, controllers):
Omar El Ayach059c5cf2018-10-26 18:45:25 -0700824 super().__init__(controllers)
Omar El Ayachd05bf022019-07-10 14:09:54 -0700825 self.tests = self.generate_test_cases(
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700826 ['test_rssi_stability', 'test_rssi_vs_atten'], [1, 2, 6, 10, 11],
827 ['VHT20'], ['ActiveTraffic'])
Omar El Ayache84e8742018-03-19 16:42:44 -0700828
829
830class WifiRssi_5GHz_ActiveTraffic_Test(WifiRssiTest):
831 def __init__(self, controllers):
Omar El Ayach059c5cf2018-10-26 18:45:25 -0700832 super().__init__(controllers)
Omar El Ayachd05bf022019-07-10 14:09:54 -0700833 self.tests = self.generate_test_cases(
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700834 ['test_rssi_stability', 'test_rssi_vs_atten'],
835 [36, 40, 44, 48, 149, 153, 157, 161], ['VHT20', 'VHT40', 'VHT80'],
836 ['ActiveTraffic'])
Omar El Ayachd05bf022019-07-10 14:09:54 -0700837
838
839class WifiRssi_AllChannels_ActiveTraffic_Test(WifiRssiTest):
840 def __init__(self, controllers):
841 super().__init__(controllers)
842 self.tests = self.generate_test_cases(
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700843 ['test_rssi_stability', 'test_rssi_vs_atten'],
Omar El Ayachd05bf022019-07-10 14:09:54 -0700844 [1, 6, 11, 36, 40, 44, 48, 149, 153, 157, 161],
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700845 ['VHT20', 'VHT40', 'VHT80'], ['ActiveTraffic'])
Omar El Ayach35bc9cb2019-01-23 15:20:13 -0800846
847
Omar El Ayach92bc8fb2019-08-27 17:21:00 -0700848class WifiRssi_SampleChannels_NoTraffic_Test(WifiRssiTest):
849 def __init__(self, controllers):
850 super().__init__(controllers)
851 self.tests = self.generate_test_cases(
852 ['test_rssi_stability', 'test_rssi_vs_atten'], [6, 36, 149],
853 ['VHT20', 'VHT40', 'VHT80'], ['NoTraffic'])
854
855
Omar El Ayach35bc9cb2019-01-23 15:20:13 -0800856class WifiRssiTrackingTest(WifiRssiTest):
857 def __init__(self, controllers):
Omar El Ayach235a49f2019-01-23 15:35:24 -0800858 super().__init__(controllers)
Omar El Ayach35bf3b82019-12-06 19:29:19 -0800859 self.tests = self.generate_test_cases(['test_rssi_tracking'],
860 [6, 36, 149],
861 ['VHT20', 'VHT40', 'VHT80'],
862 ['ActiveTraffic', 'NoTraffic'])
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700863
864
865# Over-the air version of RSSI tests
866class WifiOtaRssiTest(WifiRssiTest):
867 """Class to test over-the-air rssi tests.
868
869 This class implements measures WiFi RSSI tests in an OTA chamber.
870 It allows setting orientation and other chamber parameters to study
871 performance in varying channel conditions
872 """
Omar El Ayach02a1cce2019-09-19 17:51:39 -0700873 def __init__(self, controllers):
874 base_test.BaseTestClass.__init__(self, controllers)
875 self.testcase_metric_logger = (
Xianyuan Jia976d4042019-09-30 17:19:47 -0700876 BlackboxMappedMetricLogger.for_test_case())
Omar El Ayach02a1cce2019-09-19 17:51:39 -0700877 self.testclass_metric_logger = (
Xianyuan Jia976d4042019-09-30 17:19:47 -0700878 BlackboxMappedMetricLogger.for_test_class())
Omar El Ayach02a1cce2019-09-19 17:51:39 -0700879 self.publish_test_metrics = False
880
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700881 def setup_class(self):
882 WifiRssiTest.setup_class(self)
883 self.ota_chamber = ota_chamber.create(
884 self.user_params['OTAChamber'])[0]
885
886 def teardown_class(self):
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700887 self.ota_chamber.reset_chamber()
Omar El Ayach3903e342019-09-17 19:17:03 -0700888 self.process_testclass_results()
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700889
890 def teardown_test(self):
Omar El Ayach3903e342019-09-17 19:17:03 -0700891 if self.ota_chamber.current_mode == 'continuous':
892 self.ota_chamber.reset_chamber()
893
894 def extract_test_id(self, testcase_params, id_fields):
895 test_id = collections.OrderedDict(
896 (param, testcase_params[param]) for param in id_fields)
897 return test_id
898
899 def process_testclass_results(self):
900 """Saves all test results to enable comparison."""
901 testclass_data = collections.OrderedDict()
902 for test_result in self.testclass_results:
903 current_params = test_result['testcase_params']
904
905 channel = current_params['channel']
906 channel_data = testclass_data.setdefault(
907 channel,
Omar El Ayach35bf3b82019-12-06 19:29:19 -0800908 collections.OrderedDict(orientation=[],
909 rssi=collections.OrderedDict(
910 signal_poll_rssi=[],
911 chain_0_rssi=[],
912 chain_1_rssi=[])))
Omar El Ayach3903e342019-09-17 19:17:03 -0700913
914 channel_data['orientation'].append(current_params['orientation'])
915 channel_data['rssi']['signal_poll_rssi'].append(
916 test_result['postprocessed_results']['signal_poll_rssi']
917 ['mean'][0])
918 channel_data['rssi']['chain_0_rssi'].append(
919 test_result['postprocessed_results']['chain_0_rssi']['mean']
920 [0])
921 channel_data['rssi']['chain_1_rssi'].append(
922 test_result['postprocessed_results']['chain_1_rssi']['mean']
923 [0])
924
925 chamber_mode = self.testclass_results[0]['testcase_params'][
926 'chamber_mode']
927 if chamber_mode == 'orientation':
928 x_label = 'Angle (deg)'
929 elif chamber_mode == 'stepped stirrers':
930 x_label = 'Position Index'
931
932 # Publish test class metrics
933 for channel, channel_data in testclass_data.items():
934 for rssi_metric, rssi_metric_value in channel_data['rssi'].items():
935 metric_name = 'ota_summary_ch{}.avg_{}'.format(
936 channel, rssi_metric)
937 metric_value = numpy.mean(rssi_metric_value)
938 self.testclass_metric_logger.add_metric(
939 metric_name, metric_value)
940
941 # Plot test class results
942 plots = []
943 for channel, channel_data in testclass_data.items():
944 current_plot = wputils.BokehFigure(
945 title='Channel {} - Rssi vs. Position'.format(channel),
946 x_label=x_label,
Omar El Ayach954eb282019-09-30 15:33:32 -0700947 primary_y_label='RSSI (dBm)',
Omar El Ayach3903e342019-09-17 19:17:03 -0700948 )
949 for rssi_metric, rssi_metric_value in channel_data['rssi'].items():
950 legend = rssi_metric
951 current_plot.add_line(channel_data['orientation'],
952 rssi_metric_value, legend)
953 current_plot.generate_figure()
954 plots.append(current_plot)
955 current_context = context.get_current_context().get_full_output_path()
956 plot_file_path = os.path.join(current_context, 'results.html')
957 wputils.BokehFigure.save_figures(plots, plot_file_path)
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700958
959 def setup_rssi_test(self, testcase_params):
960 # Test setup
961 WifiRssiTest.setup_rssi_test(self, testcase_params)
962 if testcase_params['chamber_mode'] == 'StirrersOn':
963 self.ota_chamber.start_continuous_stirrers()
964 else:
965 self.ota_chamber.set_orientation(testcase_params['orientation'])
966
Omar El Ayach3903e342019-09-17 19:17:03 -0700967 def compile_ota_rssi_test_params(self, testcase_params):
968 """Function to complete compiling test-specific parameters
969
970 Args:
971 testcase_params: dict containing test-specific parameters
972 """
973 if "rssi_over_orientation" in self.test_name:
974 rssi_test_duration = self.testclass_params[
975 'rssi_over_orientation_duration']
976 elif "rssi_variation" in self.test_name:
977 rssi_test_duration = self.testclass_params[
978 'rssi_variation_duration']
979
980 testcase_params.update(
981 connected_measurements=int(
982 rssi_test_duration /
983 self.testclass_params['polling_frequency']),
984 scan_measurements=0,
985 first_measurement_delay=MED_SLEEP,
986 rssi_atten_range=[
987 self.testclass_params['rssi_ota_test_attenuation']
988 ])
989 testcase_params['band'] = self.access_point.band_lookup_by_channel(
990 testcase_params['channel'])
Omar El Ayachcbf6ba92019-12-07 11:54:06 -0800991 testcase_params['test_network'] = self.main_network[
992 testcase_params['band']]
Omar El Ayach3903e342019-09-17 19:17:03 -0700993 testcase_params['tracked_bssid'] = [
994 self.main_network[testcase_params['band']].get(
995 'BSSID', '00:00:00:00')
996 ]
997
998 testcase_params['traffic_timeout'] = self.get_traffic_timeout(
999 testcase_params)
1000 if isinstance(self.iperf_server, ipf.IPerfServerOverAdb):
1001 testcase_params['iperf_args'] = '-i 1 -t {} -J'.format(
1002 testcase_params['traffic_timeout'])
1003 else:
1004 testcase_params['iperf_args'] = '-i 1 -t {} -J -R'.format(
1005 testcase_params['traffic_timeout'])
1006 return testcase_params
1007
1008 def _test_ota_rssi(self, testcase_params):
1009 testcase_params = self.compile_ota_rssi_test_params(testcase_params)
1010
1011 self.setup_rssi_test(testcase_params)
1012 rssi_result = self.run_rssi_test(testcase_params)
1013 rssi_result['postprocessed_results'] = self.post_process_rssi_sweep(
1014 rssi_result)
1015 self.testclass_results.append(rssi_result)
1016 self.plot_rssi_vs_time(rssi_result,
1017 rssi_result['postprocessed_results'], 1)
1018 self.plot_rssi_distribution(rssi_result['postprocessed_results'])
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -07001019
1020 def generate_test_cases(self, test_types, channels, modes, traffic_modes,
1021 chamber_modes, orientations):
1022 test_cases = []
1023 allowed_configs = {
1024 'VHT20': [
1025 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 36, 40, 44, 48, 149, 153,
1026 157, 161
1027 ],
1028 'VHT40': [36, 44, 149, 157],
1029 'VHT80': [36, 149]
1030 }
1031
Omar El Ayach35bf3b82019-12-06 19:29:19 -08001032 for (channel, mode, traffic, chamber_mode, orientation,
1033 test_type) in itertools.product(channels, modes, traffic_modes,
1034 chamber_modes, orientations,
1035 test_types):
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -07001036 if channel not in allowed_configs[mode]:
1037 continue
Omar El Ayachb7557922019-08-07 17:04:02 -07001038 test_name = test_type + '_ch{}_{}_{}_{}deg'.format(
1039 channel, mode, traffic, orientation)
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -07001040 testcase_params = collections.OrderedDict(
1041 channel=channel,
1042 mode=mode,
1043 active_traffic=(traffic == 'ActiveTraffic'),
1044 traffic_type=self.user_params['rssi_test_params']
1045 ['traffic_type'],
1046 chamber_mode=chamber_mode,
1047 orientation=orientation)
Omar El Ayach3903e342019-09-17 19:17:03 -07001048 test_function = self._test_ota_rssi
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -07001049 setattr(self, test_name, partial(test_function, testcase_params))
1050 test_cases.append(test_name)
1051 return test_cases
1052
1053
Omar El Ayachb7557922019-08-07 17:04:02 -07001054class WifiOtaRssi_Accuracy_Test(WifiOtaRssiTest):
1055 def __init__(self, controllers):
1056 super().__init__(controllers)
Omar El Ayach35bf3b82019-12-06 19:29:19 -08001057 self.tests = self.generate_test_cases(['test_rssi_vs_atten'],
1058 [6, 36, 149], ['VHT20'],
1059 ['ActiveTraffic'],
1060 ['orientation'],
1061 list(range(0, 360, 45)))
Omar El Ayachb7557922019-08-07 17:04:02 -07001062
1063
Omar El Ayach3903e342019-09-17 19:17:03 -07001064class WifiOtaRssi_StirrerVariation_Test(WifiOtaRssiTest):
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -07001065 def __init__(self, controllers):
1066 WifiRssiTest.__init__(self, controllers)
Omar El Ayach35bf3b82019-12-06 19:29:19 -08001067 self.tests = self.generate_test_cases(['test_rssi_variation'],
1068 [6, 36, 149], ['VHT20'],
1069 ['ActiveTraffic'],
1070 ['StirrersOn'], [0])
Omar El Ayacha7c3afe2019-09-16 15:58:29 -07001071
Omar El Ayach3903e342019-09-17 19:17:03 -07001072
Omar El Ayacha7c3afe2019-09-16 15:58:29 -07001073class WifiOtaRssi_TenDegree_Test(WifiOtaRssiTest):
1074 def __init__(self, controllers):
1075 WifiRssiTest.__init__(self, controllers)
Omar El Ayach35bf3b82019-12-06 19:29:19 -08001076 self.tests = self.generate_test_cases(['test_rssi_over_orientation'],
1077 [6, 36, 149], ['VHT20'],
1078 ['ActiveTraffic'],
1079 ['orientation'],
1080 list(range(0, 360, 10)))