blob: 25c944be2665e608ce71142f875a11f665d54a3e [file] [log] [blame]
Omar El Ayacheb226db2018-09-04 15:28:45 -07001#!/usr/bin/env python3.4
2#
3# Copyright 2017 - 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 Ayacheb226db2018-09-04 15:28:45 -07006# 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 Ayacheb226db2018-09-04 15:28:45 -070013# 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 Ayach5fbc1222018-12-07 18:10:05 -080017import collections
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -070018import itertools
Omar El Ayacheb226db2018-09-04 15:28:45 -070019import json
20import logging
21import os
22import statistics
Omar El Ayacheb226db2018-09-04 15:28:45 -070023from acts import asserts
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -070024from acts import context
Omar El Ayacheb226db2018-09-04 15:28:45 -070025from acts import base_test
26from acts import utils
Omar El Ayach14416ac2019-01-30 14:58:19 -080027from acts.controllers.utils_lib import ssh
Xianyuan Jia976d4042019-09-30 17:19:47 -070028from acts.metrics.loggers.blackbox import BlackboxMappedMetricLogger
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -070029from acts.test_utils.wifi import ota_chamber
Omar El Ayach4a02f7e2019-10-14 14:37:30 -070030from acts.test_utils.wifi import ota_sniffer
Omar El Ayach698b4bd2019-02-12 15:33:55 -080031from acts.test_utils.wifi import wifi_performance_test_utils as wputils
Omar El Ayacheb226db2018-09-04 15:28:45 -070032from acts.test_utils.wifi import wifi_retail_ap as retail_ap
33from acts.test_utils.wifi import wifi_test_utils as wutils
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -070034from functools import partial
Omar El Ayacheb226db2018-09-04 15:28:45 -070035
36
37class WifiPingTest(base_test.BaseTestClass):
38 """Class for ping-based Wifi performance tests.
39
40 This class implements WiFi ping performance tests such as range and RTT.
41 The class setups up the AP in the desired configurations, configures
42 and connects the phone to the AP, and runs For an example config file to
43 run this test class see example_connectivity_performance_ap_sta.json.
44 """
45
46 TEST_TIMEOUT = 10
Omar El Ayach698b4bd2019-02-12 15:33:55 -080047 RSSI_POLL_INTERVAL = 0.2
Omar El Ayacheb226db2018-09-04 15:28:45 -070048 SHORT_SLEEP = 1
49 MED_SLEEP = 5
Omar El Ayach5fbc1222018-12-07 18:10:05 -080050 MAX_CONSECUTIVE_ZEROS = 5
51 DISCONNECTED_PING_RESULT = {
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -070052 'connected': 0,
53 'rtt': [],
54 'time_stamp': [],
55 'ping_interarrivals': [],
56 'packet_loss_percentage': 100
Omar El Ayach5fbc1222018-12-07 18:10:05 -080057 }
Omar El Ayacheb226db2018-09-04 15:28:45 -070058
59 def __init__(self, controllers):
60 base_test.BaseTestClass.__init__(self, controllers)
Omar El Ayach02a1cce2019-09-19 17:51:39 -070061 self.testcase_metric_logger = (
Xianyuan Jia976d4042019-09-30 17:19:47 -070062 BlackboxMappedMetricLogger.for_test_case())
Omar El Ayach02a1cce2019-09-19 17:51:39 -070063 self.testclass_metric_logger = (
Xianyuan Jia976d4042019-09-30 17:19:47 -070064 BlackboxMappedMetricLogger.for_test_class())
Omar El Ayach02a1cce2019-09-19 17:51:39 -070065 self.publish_testcase_metrics = True
66
Omar El Ayacheb226db2018-09-04 15:28:45 -070067 def setup_class(self):
Omar El Ayach74f78dc2019-07-30 15:15:34 -070068 self.dut = self.android_devices[-1]
Omar El Ayachafe47cf2018-11-02 14:17:14 -070069 req_params = [
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -070070 'ping_test_params', 'testbed_params', 'main_network',
71 'RetailAccessPoints', 'RemoteServer'
Omar El Ayacheb226db2018-09-04 15:28:45 -070072 ]
Omar El Ayach6e96e132020-04-02 10:21:09 -070073 opt_params = ['OTASniffer']
Omar El Ayacheb226db2018-09-04 15:28:45 -070074 self.unpack_userparams(req_params, opt_params)
Omar El Ayach5fbc1222018-12-07 18:10:05 -080075 self.testclass_params = self.ping_test_params
Omar El Ayacheb226db2018-09-04 15:28:45 -070076 self.num_atten = self.attenuators[0].instrument.num_atten
Omar El Ayach14416ac2019-01-30 14:58:19 -080077 self.ping_server = ssh.connection.SshConnection(
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -070078 ssh.settings.from_config(self.RemoteServer[0]['ssh_config']))
79 self.access_point = retail_ap.create(self.RetailAccessPoints)[0]
Omar El Ayach61968132020-03-24 21:47:50 -070080 if hasattr(self,
81 'OTASniffer') and self.testbed_params['sniffer_enable']:
Omar El Ayach4a02f7e2019-10-14 14:37:30 -070082 self.sniffer = ota_sniffer.create(self.OTASniffer)[0]
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -070083 self.log.info('Access Point Configuration: {}'.format(
Omar El Ayachafe47cf2018-11-02 14:17:14 -070084 self.access_point.ap_settings))
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -070085 self.log_path = os.path.join(logging.log_path, 'results')
Mark De Ruyter72f8df92020-02-12 13:44:49 -080086 os.makedirs(self.log_path, exist_ok=True)
Omar El Ayach9c56cf32019-09-19 13:07:51 -070087 if hasattr(self, 'bdf'):
88 self.log.info('Pushing WiFi BDF to DUT.')
89 wputils.push_bdf(self.dut, self.bdf)
90 if hasattr(self, 'firmware'):
91 self.log.info('Pushing WiFi firmware to DUT.')
92 wlanmdsp = [
93 file for file in self.firmware if "wlanmdsp.mbn" in file
94 ][0]
95 data_msc = [file for file in self.firmware
96 if "Data.msc" in file][0]
97 wputils.push_firmware(self.dut, wlanmdsp, data_msc)
Omar El Ayachc27b7f92019-12-04 15:46:43 -080098 self.atten_dut_chain_map = {}
Omar El Ayacheb226db2018-09-04 15:28:45 -070099 self.testclass_results = []
100
101 # Turn WiFi ON
Omar El Ayachd7109092019-09-29 18:31:33 -0700102 if self.testclass_params.get('airplane_mode', 1):
103 self.log.info('Turning on airplane mode.')
Omar El Ayachd80a7ca2019-10-16 16:57:05 -0700104 asserts.assert_true(utils.force_airplane_mode(self.dut, True),
105 "Can not turn on airplane mode.")
Omar El Ayach9c56cf32019-09-19 13:07:51 -0700106 wutils.wifi_toggle_state(self.dut, True)
Omar El Ayacheb226db2018-09-04 15:28:45 -0700107
Omar El Ayach87222062020-03-25 19:34:12 -0700108 # Configure test retries
109 self.user_params['retry_tests'] = [self.__class__.__name__]
110
Omar El Ayach6bde6dc2019-02-25 14:24:21 -0800111 def teardown_class(self):
Omar El Ayach00ff4a42020-04-06 11:43:41 -0700112 # Turn WiFi OFF and reset AP
Omar El Ayach6bde6dc2019-02-25 14:24:21 -0800113 for dev in self.android_devices:
114 wutils.wifi_toggle_state(dev, False)
Omar El Ayach00ff4a42020-04-06 11:43:41 -0700115 self.access_point.reset()
Omar El Ayach6bde6dc2019-02-25 14:24:21 -0800116 self.process_testclass_results()
117
Omar El Ayach87222062020-03-25 19:34:12 -0700118 def setup_test(self):
119 self.retry_flag = False
120
121 def teardown_test(self):
122 self.retry_flag = False
123
124 def on_retry(self):
125 """Function to control test logic on retried tests.
126
127 This function is automatically executed on tests that are being
128 retried. In this case the function resets wifi, toggles it off and on
129 and sets a retry_flag to enable further tweaking the test logic on
130 second attempts.
131 """
132 self.retry_flag = True
133 for dev in self.android_devices:
134 wutils.reset_wifi(dev)
135 wutils.toggle_wifi_off_and_on(dev)
136
Omar El Ayach6bde6dc2019-02-25 14:24:21 -0800137 def process_testclass_results(self):
138 """Saves all test results to enable comparison."""
139 testclass_summary = {}
140 for test in self.testclass_results:
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700141 if 'range' in test['test_name']:
142 testclass_summary[test['test_name']] = test['range']
Omar El Ayach6bde6dc2019-02-25 14:24:21 -0800143 # Save results
Omar El Ayach383d61f2019-04-05 17:22:02 -0700144 results_file_path = os.path.join(self.log_path,
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700145 'testclass_summary.json')
146 with open(results_file_path, 'w') as results_file:
Omar El Ayach6bde6dc2019-02-25 14:24:21 -0800147 json.dump(testclass_summary, results_file, indent=4)
148
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700149 def pass_fail_check_ping_rtt(self, result):
Omar El Ayacheb226db2018-09-04 15:28:45 -0700150 """Check the test result and decide if it passed or failed.
151
152 The function computes RTT statistics and fails any tests in which the
153 tail of the ping latency results exceeds the threshold defined in the
154 configuration file.
155
156 Args:
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700157 result: dict containing ping results and other meta data
Omar El Ayacheb226db2018-09-04 15:28:45 -0700158 """
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700159 ignored_fraction = (self.testclass_params['rtt_ignored_interval'] /
160 self.testclass_params['rtt_ping_duration'])
Omar El Ayacheb226db2018-09-04 15:28:45 -0700161 sorted_rtt = [
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700162 sorted(x['rtt'][round(ignored_fraction * len(x['rtt'])):])
163 for x in result['ping_results']
Omar El Ayacheb226db2018-09-04 15:28:45 -0700164 ]
Omar El Ayachd80a7ca2019-10-16 16:57:05 -0700165 disconnected = any([len(x) == 0 for x in sorted_rtt])
166 if disconnected:
167 asserts.fail('Test failed. DUT disconnected at least once.')
168
Omar El Ayacheb226db2018-09-04 15:28:45 -0700169 rtt_at_test_percentile = [
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700170 x[int((1 - self.testclass_params['rtt_test_percentile'] / 100) *
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800171 len(x))] for x in sorted_rtt
Omar El Ayacheb226db2018-09-04 15:28:45 -0700172 ]
Omar El Ayachafe47cf2018-11-02 14:17:14 -0700173 # Set blackbox metric
Omar El Ayach02a1cce2019-09-19 17:51:39 -0700174 if self.publish_testcase_metrics:
175 self.testcase_metric_logger.add_metric('ping_rtt',
176 max(rtt_at_test_percentile))
Omar El Ayachafe47cf2018-11-02 14:17:14 -0700177 # Evaluate test pass/fail
Omar El Ayachd80a7ca2019-10-16 16:57:05 -0700178 rtt_failed = any([
179 rtt > self.testclass_params['rtt_threshold'] * 1000
180 for rtt in rtt_at_test_percentile
181 ])
182 if rtt_failed:
Omar El Ayach87222062020-03-25 19:34:12 -0700183 #TODO: figure out how to cleanly exclude RTT tests from retry
184 asserts.explicit_pass(
185 'Test failed. RTTs at test percentile = {}'.format(
186 rtt_at_test_percentile))
Omar El Ayacheb226db2018-09-04 15:28:45 -0700187 else:
188 asserts.explicit_pass(
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700189 'Test Passed. RTTs at test percentile = {}'.format(
Omar El Ayacheb226db2018-09-04 15:28:45 -0700190 rtt_at_test_percentile))
191
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700192 def pass_fail_check_ping_range(self, result):
Omar El Ayacheb226db2018-09-04 15:28:45 -0700193 """Check the test result and decide if it passed or failed.
194
195 Checks whether the attenuation at which ping packet losses begin to
196 exceed the threshold matches the range derived from golden
197 rate-vs-range result files. The test fails is ping range is
198 range_gap_threshold worse than RvR range.
199
200 Args:
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700201 result: dict containing ping results and meta data
Omar El Ayacheb226db2018-09-04 15:28:45 -0700202 """
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800203 # Get target range
Omar El Ayach87222062020-03-25 19:34:12 -0700204 #rvr_range = self.get_range_from_rvr()
Omar El Ayachafe47cf2018-11-02 14:17:14 -0700205 # Set Blackbox metric
Omar El Ayach02a1cce2019-09-19 17:51:39 -0700206 if self.publish_testcase_metrics:
207 self.testcase_metric_logger.add_metric('ping_range',
208 result['range'])
Omar El Ayachafe47cf2018-11-02 14:17:14 -0700209 # Evaluate test pass/fail
Omar El Ayach87222062020-03-25 19:34:12 -0700210 test_message = ('Attenuation at range is {}dB. '
Omar El Ayach00ecc862019-09-28 13:31:17 -0700211 'LLStats at Range: {}'.format(
Omar El Ayach87222062020-03-25 19:34:12 -0700212 result['range'], result['llstats_at_range']))
213 if result['peak_throughput_pct'] < 95:
214 asserts.fail("(RESULT NOT RELIABLE) {}".format(test_message))
Omar El Ayacheb226db2018-09-04 15:28:45 -0700215 else:
Omar El Ayach00ecc862019-09-28 13:31:17 -0700216 asserts.explicit_pass(test_message)
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700217
218 def pass_fail_check(self, result):
219 if 'range' in result['testcase_params']['test_type']:
220 self.pass_fail_check_ping_range(result)
221 else:
222 self.pass_fail_check_ping_rtt(result)
Omar El Ayacheb226db2018-09-04 15:28:45 -0700223
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800224 def process_ping_results(self, testcase_params, ping_range_result):
Omar El Ayacheb226db2018-09-04 15:28:45 -0700225 """Saves and plots ping results.
226
227 Args:
228 ping_range_result: dict containing ping results and metadata
229 """
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800230 # Compute range
231 ping_loss_over_att = [
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700232 x['packet_loss_percentage']
233 for x in ping_range_result['ping_results']
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800234 ]
235 ping_loss_above_threshold = [
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700236 x > self.testclass_params['range_ping_loss_threshold']
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800237 for x in ping_loss_over_att
238 ]
239 for idx in range(len(ping_loss_above_threshold)):
240 if all(ping_loss_above_threshold[idx:]):
241 range_index = max(idx, 1) - 1
242 break
243 else:
244 range_index = -1
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700245 ping_range_result['atten_at_range'] = testcase_params['atten_range'][
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800246 range_index]
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700247 ping_range_result['peak_throughput_pct'] = 100 - min(
Omar El Ayacha210d572019-03-14 17:31:38 -0700248 ping_loss_over_att)
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700249 ping_range_result['range'] = (ping_range_result['atten_at_range'] +
250 ping_range_result['fixed_attenuation'])
Omar El Ayach00ecc862019-09-28 13:31:17 -0700251 ping_range_result['llstats_at_range'] = (
252 'TX MCS = {0} ({1:.1f}%). '
253 'RX MCS = {2} ({3:.1f}%)'.format(
254 ping_range_result['llstats'][range_index]['summary']
255 ['common_tx_mcs'], ping_range_result['llstats'][range_index]
256 ['summary']['common_tx_mcs_freq'] * 100,
257 ping_range_result['llstats'][range_index]['summary']
258 ['common_rx_mcs'], ping_range_result['llstats'][range_index]
259 ['summary']['common_rx_mcs_freq'] * 100))
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800260
261 # Save results
Omar El Ayach383d61f2019-04-05 17:22:02 -0700262 results_file_path = os.path.join(
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700263 self.log_path, '{}.json'.format(self.current_test_name))
264 with open(results_file_path, 'w') as results_file:
Omar El Ayacheb226db2018-09-04 15:28:45 -0700265 json.dump(ping_range_result, results_file, indent=4)
266
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800267 # Plot results
Omar El Ayach00ecc862019-09-28 13:31:17 -0700268 if 'range' not in self.current_test_name:
269 figure = wputils.BokehFigure(
270 self.current_test_name,
271 x_label='Timestamp (s)',
Omar El Ayach954eb282019-09-30 15:33:32 -0700272 primary_y_label='Round Trip Time (ms)')
Omar El Ayach00ecc862019-09-28 13:31:17 -0700273 for idx, result in enumerate(ping_range_result['ping_results']):
274 if len(result['rtt']) > 1:
275 x_data = [
276 t - result['time_stamp'][0]
277 for t in result['time_stamp']
278 ]
279 figure.add_line(
280 x_data, result['rtt'], 'RTT @ {}dB'.format(
281 ping_range_result['attenuation'][idx]))
Omar El Ayacheb226db2018-09-04 15:28:45 -0700282
Omar El Ayach00ecc862019-09-28 13:31:17 -0700283 output_file_path = os.path.join(
284 self.log_path, '{}.html'.format(self.current_test_name))
285 figure.generate_figure(output_file_path)
Omar El Ayacheb226db2018-09-04 15:28:45 -0700286
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800287 def run_ping_test(self, testcase_params):
Omar El Ayacheb226db2018-09-04 15:28:45 -0700288 """Main function to test ping.
289
290 The function sets up the AP in the correct channel and mode
291 configuration and calls get_ping_stats while sweeping attenuation
292
293 Args:
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800294 testcase_params: dict containing all test parameters
Omar El Ayacheb226db2018-09-04 15:28:45 -0700295 Returns:
296 test_result: dict containing ping results and other meta data
297 """
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800298 # Prepare results dict
Omar El Ayach00ecc862019-09-28 13:31:17 -0700299 llstats_obj = wputils.LinkLayerStats(self.dut)
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800300 test_result = collections.OrderedDict()
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700301 test_result['testcase_params'] = testcase_params.copy()
302 test_result['test_name'] = self.current_test_name
303 test_result['ap_config'] = self.access_point.ap_settings.copy()
304 test_result['attenuation'] = testcase_params['atten_range']
305 test_result['fixed_attenuation'] = self.testbed_params[
306 'fixed_attenuation'][str(testcase_params['channel'])]
307 test_result['rssi_results'] = []
308 test_result['ping_results'] = []
Omar El Ayach00ecc862019-09-28 13:31:17 -0700309 test_result['llstats'] = []
Omar El Ayach4a02f7e2019-10-14 14:37:30 -0700310 # Setup sniffer
311 if self.testbed_params['sniffer_enable']:
312 self.sniffer.start_capture(
313 testcase_params['test_network'],
314 testcase_params['ping_duration'] *
315 len(testcase_params['atten_range']) + self.TEST_TIMEOUT)
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800316 # Run ping and sweep attenuation as needed
317 zero_counter = 0
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700318 for atten in testcase_params['atten_range']:
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800319 for attenuator in self.attenuators:
Omar El Ayach96714c82019-01-28 18:51:46 -0800320 attenuator.set_atten(atten, strict=False)
Omar El Ayach698b4bd2019-02-12 15:33:55 -0800321 rssi_future = wputils.get_connected_rssi_nb(
Omar El Ayach74f78dc2019-07-30 15:15:34 -0700322 self.dut,
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700323 int(testcase_params['ping_duration'] / 2 /
Omar El Ayach698b4bd2019-02-12 15:33:55 -0800324 self.RSSI_POLL_INTERVAL), self.RSSI_POLL_INTERVAL,
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700325 testcase_params['ping_duration'] / 2)
Omar El Ayach00ecc862019-09-28 13:31:17 -0700326 # Refresh link layer stats
327 llstats_obj.update_stats()
Omar El Ayach698b4bd2019-02-12 15:33:55 -0800328 current_ping_stats = wputils.get_ping_stats(
329 self.ping_server, self.dut_ip,
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700330 testcase_params['ping_duration'],
331 testcase_params['ping_interval'], testcase_params['ping_size'])
Omar El Ayach22460ae2019-09-10 13:29:48 -0700332 current_rssi = rssi_future.result()
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700333 test_result['rssi_results'].append(current_rssi)
Omar El Ayach00ecc862019-09-28 13:31:17 -0700334 llstats_obj.update_stats()
335 curr_llstats = llstats_obj.llstats_incremental.copy()
336 test_result['llstats'].append(curr_llstats)
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700337 if current_ping_stats['connected']:
Omar El Ayach22460ae2019-09-10 13:29:48 -0700338 self.log.info(
339 'Attenuation = {0}dB\tPacket Loss = {1}%\t'
340 'Avg RTT = {2:.2f}ms\tRSSI = {3} [{4},{5}]\t'.format(
341 atten, current_ping_stats['packet_loss_percentage'],
342 statistics.mean(current_ping_stats['rtt']),
343 current_rssi['signal_poll_rssi']['mean'],
344 current_rssi['chain_0_rssi']['mean'],
345 current_rssi['chain_1_rssi']['mean']))
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700346 if current_ping_stats['packet_loss_percentage'] == 100:
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800347 zero_counter = zero_counter + 1
348 else:
349 zero_counter = 0
350 else:
351 self.log.info(
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700352 'Attenuation = {}dB. Disconnected.'.format(atten))
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800353 zero_counter = zero_counter + 1
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700354 test_result['ping_results'].append(current_ping_stats.as_dict())
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800355 if zero_counter == self.MAX_CONSECUTIVE_ZEROS:
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700356 self.log.info('Ping loss stable at 100%. Stopping test now.')
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800357 for idx in range(
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700358 len(testcase_params['atten_range']) -
359 len(test_result['ping_results'])):
360 test_result['ping_results'].append(
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800361 self.DISCONNECTED_PING_RESULT)
362 break
Omar El Ayach4a02f7e2019-10-14 14:37:30 -0700363 if self.testbed_params['sniffer_enable']:
364 self.sniffer.stop_capture()
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800365 return test_result
366
367 def setup_ap(self, testcase_params):
368 """Sets up the access point in the configuration required by the test.
369
370 Args:
371 testcase_params: dict containing AP and other test params
372 """
373 band = self.access_point.band_lookup_by_channel(
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700374 testcase_params['channel'])
375 if '2G' in band:
Omar El Ayachb503ae82019-02-13 09:36:36 -0800376 frequency = wutils.WifiEnums.channel_2G_to_freq[
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700377 testcase_params['channel']]
Omar El Ayacheb226db2018-09-04 15:28:45 -0700378 else:
Omar El Ayachb503ae82019-02-13 09:36:36 -0800379 frequency = wutils.WifiEnums.channel_5G_to_freq[
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700380 testcase_params['channel']]
Omar El Ayacheb226db2018-09-04 15:28:45 -0700381 if frequency in wutils.WifiEnums.DFS_5G_FREQUENCIES:
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700382 self.access_point.set_region(self.testbed_params['DFS_region'])
Omar El Ayacheb226db2018-09-04 15:28:45 -0700383 else:
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700384 self.access_point.set_region(self.testbed_params['default_region'])
385 self.access_point.set_channel(band, testcase_params['channel'])
386 self.access_point.set_bandwidth(band, testcase_params['mode'])
Omar El Ayach22460ae2019-09-10 13:29:48 -0700387 if 'low' in testcase_params['ap_power']:
388 self.log.info('Setting low AP power.')
Omar El Ayachf84d3a62020-03-24 11:12:55 -0700389 self.access_point.set_power(
390 band, self.testclass_params['low_ap_tx_power'])
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700391 self.log.info('Access Point Configuration: {}'.format(
Omar El Ayacheb226db2018-09-04 15:28:45 -0700392 self.access_point.ap_settings))
393
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800394 def setup_dut(self, testcase_params):
395 """Sets up the DUT in the configuration required by the test.
396
397 Args:
398 testcase_params: dict containing AP and other test params
399 """
Omar El Ayach656bf3d2019-07-31 15:04:53 -0700400 # Check battery level before test
401 if not wputils.health_check(self.dut, 10):
402 asserts.skip('Battery level too low. Skipping test.')
403 # Turn screen off to preserve battery
404 self.dut.go_to_sleep()
Omar El Ayach35bf3b82019-12-06 19:29:19 -0800405 if wputils.validate_network(self.dut,
406 testcase_params['test_network']['SSID']):
Omar El Ayach39acf802019-08-02 17:52:39 -0700407 self.log.info('Already connected to desired network')
408 else:
409 wutils.reset_wifi(self.dut)
Roshan Pius5b19a122019-09-13 08:07:30 -0700410 wutils.set_wifi_country_code(self.dut,
Omar El Ayachf84d3a62020-03-24 11:12:55 -0700411 self.testclass_params['country_code'])
Omar El Ayach4a02f7e2019-10-14 14:37:30 -0700412 testcase_params['test_network']['channel'] = testcase_params[
413 'channel']
Omar El Ayachd80a7ca2019-10-16 16:57:05 -0700414 wutils.wifi_connect(self.dut,
Omar El Ayach4a02f7e2019-10-14 14:37:30 -0700415 testcase_params['test_network'],
Omar El Ayachd80a7ca2019-10-16 16:57:05 -0700416 num_of_tries=5,
Omar El Ayachd8343082019-12-19 02:41:15 -0800417 check_connectivity=True)
Omar El Ayach74f78dc2019-07-30 15:15:34 -0700418 self.dut_ip = self.dut.droid.connectivityGetIPv4Addresses('wlan0')[0]
Omar El Ayachc27b7f92019-12-04 15:46:43 -0800419 if testcase_params['channel'] not in self.atten_dut_chain_map.keys():
420 self.atten_dut_chain_map[testcase_params[
421 'channel']] = wputils.get_current_atten_dut_chain_map(
422 self.attenuators, self.dut, self.ping_server)
423 self.log.info("Current Attenuator-DUT Chain Map: {}".format(
424 self.atten_dut_chain_map[testcase_params['channel']]))
425 for idx, atten in enumerate(self.attenuators):
426 if self.atten_dut_chain_map[testcase_params['channel']][
427 idx] == testcase_params['attenuated_chain']:
428 atten.offset = atten.instrument.max_atten
429 else:
430 atten.offset = 0
Omar El Ayacheb226db2018-09-04 15:28:45 -0700431
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800432 def setup_ping_test(self, testcase_params):
433 """Function that gets devices ready for the test.
434
435 Args:
436 testcase_params: dict containing test-specific parameters
437 """
438 # Configure AP
439 self.setup_ap(testcase_params)
440 # Set attenuator to 0 dB
441 for attenuator in self.attenuators:
Omar El Ayach96714c82019-01-28 18:51:46 -0800442 attenuator.set_atten(0, strict=False)
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800443 # Reset, configure, and connect DUT
444 self.setup_dut(testcase_params)
445
Omar El Ayach10c67b72019-09-16 15:14:54 -0700446 def get_range_start_atten(self, testcase_params):
447 """Gets the starting attenuation for this ping test.
448
449 This function is used to get the starting attenuation for ping range
450 tests. This implementation returns the default starting attenuation,
451 however, defining this function enables a more involved configuration
452 for over-the-air test classes.
453
454 Args:
455 testcase_params: dict containing all test params
456 """
457 return self.testclass_params['range_atten_start']
458
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700459 def compile_test_params(self, testcase_params):
Omar El Ayach4a02f7e2019-10-14 14:37:30 -0700460 band = self.access_point.band_lookup_by_channel(
461 testcase_params['channel'])
462 testcase_params['test_network'] = self.main_network[band]
Omar El Ayachc27b7f92019-12-04 15:46:43 -0800463 if testcase_params['chain_mask'] in ['0', '1']:
464 testcase_params['attenuated_chain'] = 'DUT-Chain-{}'.format(
465 1 if testcase_params['chain_mask'] == '0' else 0)
466 else:
467 # Set attenuated chain to -1. Do not set to None as this will be
468 # compared to RF chain map which may include None
469 testcase_params['attenuated_chain'] = -1
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700470 if testcase_params['test_type'] == 'test_ping_range':
471 testcase_params.update(
472 ping_interval=self.testclass_params['range_ping_interval'],
473 ping_duration=self.testclass_params['range_ping_duration'],
474 ping_size=self.testclass_params['ping_size'],
475 )
476 elif testcase_params['test_type'] == 'test_fast_ping_rtt':
477 testcase_params.update(
478 ping_interval=self.testclass_params['rtt_ping_interval']
479 ['fast'],
480 ping_duration=self.testclass_params['rtt_ping_duration'],
481 ping_size=self.testclass_params['ping_size'],
482 )
483 elif testcase_params['test_type'] == 'test_slow_ping_rtt':
484 testcase_params.update(
485 ping_interval=self.testclass_params['rtt_ping_interval']
486 ['slow'],
487 ping_duration=self.testclass_params['rtt_ping_duration'],
488 ping_size=self.testclass_params['ping_size'])
489
490 if testcase_params['test_type'] == 'test_ping_range':
Omar El Ayach10c67b72019-09-16 15:14:54 -0700491 start_atten = self.get_range_start_atten(testcase_params)
Omar El Ayach9c56cf32019-09-19 13:07:51 -0700492 num_atten_steps = int(
493 (self.testclass_params['range_atten_stop'] - start_atten) /
494 self.testclass_params['range_atten_step'])
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700495 testcase_params['atten_range'] = [
Omar El Ayach10c67b72019-09-16 15:14:54 -0700496 start_atten + x * self.testclass_params['range_atten_step']
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800497 for x in range(0, num_atten_steps)
498 ]
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800499 else:
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700500 testcase_params['atten_range'] = self.testclass_params[
501 'rtt_test_attenuation']
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800502 return testcase_params
Omar El Ayacheb226db2018-09-04 15:28:45 -0700503
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700504 def _test_ping(self, testcase_params):
Omar El Ayacheb226db2018-09-04 15:28:45 -0700505 """ Function that gets called for each range test case
506
507 The function gets called in each range test case. It customizes the
508 range test based on the test name of the test that called it
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700509
510 Args:
511 testcase_params: dict containing preliminary set of parameters
Omar El Ayacheb226db2018-09-04 15:28:45 -0700512 """
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800513 # Compile test parameters from config and test name
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700514 testcase_params = self.compile_test_params(testcase_params)
Omar El Ayach5fbc1222018-12-07 18:10:05 -0800515 # Run ping test
516 self.setup_ping_test(testcase_params)
517 ping_result = self.run_ping_test(testcase_params)
518 # Postprocess results
519 self.process_ping_results(testcase_params, ping_result)
Omar El Ayach87222062020-03-25 19:34:12 -0700520 self.testclass_results.append(ping_result)
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700521 self.pass_fail_check(ping_result)
Omar El Ayacheb226db2018-09-04 15:28:45 -0700522
Omar El Ayachc27b7f92019-12-04 15:46:43 -0800523 def generate_test_cases(self, ap_power, channels, modes, chain_mask,
524 test_types):
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700525 test_cases = []
526 allowed_configs = {
527 'VHT20': [
528 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 36, 40, 44, 48, 149, 153,
529 157, 161
530 ],
531 'VHT40': [36, 44, 149, 157],
532 'VHT80': [36, 149]
533 }
Omar El Ayachc27b7f92019-12-04 15:46:43 -0800534 for channel, mode, chain, test_type in itertools.product(
535 channels, modes, chain_mask, test_types):
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700536 if channel not in allowed_configs[mode]:
537 continue
Omar El Ayachc27b7f92019-12-04 15:46:43 -0800538 testcase_name = '{}_ch{}_{}_ch{}'.format(test_type, channel, mode,
539 chain)
540 testcase_params = collections.OrderedDict(test_type=test_type,
541 ap_power=ap_power,
542 channel=channel,
543 mode=mode,
544 chain_mask=chain)
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700545 setattr(self, testcase_name,
546 partial(self._test_ping, testcase_params))
547 test_cases.append(testcase_name)
548 return test_cases
Omar El Ayacheb226db2018-09-04 15:28:45 -0700549
Omar El Ayacheb226db2018-09-04 15:28:45 -0700550
Omar El Ayachc27b7f92019-12-04 15:46:43 -0800551class WifiPing_TwoChain_Test(WifiPingTest):
552 def __init__(self, controllers):
553 super().__init__(controllers)
554 self.tests = self.generate_test_cases(
555 ap_power='standard',
556 channels=[1, 6, 11, 36, 40, 44, 48, 149, 153, 157, 161],
557 modes=['VHT20', 'VHT40', 'VHT80'],
558 test_types=[
559 'test_ping_range', 'test_fast_ping_rtt', 'test_slow_ping_rtt'
560 ],
561 chain_mask=['2x2'])
562
563
564class WifiPing_PerChainRange_Test(WifiPingTest):
565 def __init__(self, controllers):
566 super().__init__(controllers)
567 self.tests = self.generate_test_cases(
568 ap_power='standard',
569 chain_mask=['0', '1', '2x2'],
570 channels=[1, 6, 11, 36, 40, 44, 48, 149, 153, 157, 161],
571 modes=['VHT20', 'VHT40', 'VHT80'],
572 test_types=['test_ping_range'])
573
574
Omar El Ayach22460ae2019-09-10 13:29:48 -0700575class WifiPing_LowPowerAP_Test(WifiPingTest):
576 def __init__(self, controllers):
Omar El Ayach0c29b7c2019-11-28 17:30:26 -0800577 super().__init__(controllers)
Omar El Ayach22460ae2019-09-10 13:29:48 -0700578 self.tests = self.generate_test_cases(
579 ap_power='low_power',
Omar El Ayachc27b7f92019-12-04 15:46:43 -0800580 chain_mask=['0', '1', '2x2'],
Omar El Ayach22460ae2019-09-10 13:29:48 -0700581 channels=[1, 6, 11, 36, 40, 44, 48, 149, 153, 157, 161],
582 modes=['VHT20', 'VHT40', 'VHT80'],
583 test_types=['test_ping_range'])
584
585
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700586# Over-the air version of ping tests
587class WifiOtaPingTest(WifiPingTest):
588 """Class to test over-the-air ping
Omar El Ayacheb226db2018-09-04 15:28:45 -0700589
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700590 This class tests WiFi ping performance in an OTA chamber. It enables
591 setting turntable orientation and other chamber parameters to study
592 performance in varying channel conditions
593 """
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700594 def __init__(self, controllers):
595 base_test.BaseTestClass.__init__(self, controllers)
Omar El Ayach02a1cce2019-09-19 17:51:39 -0700596 self.testcase_metric_logger = (
Xianyuan Jia976d4042019-09-30 17:19:47 -0700597 BlackboxMappedMetricLogger.for_test_case())
Omar El Ayach02a1cce2019-09-19 17:51:39 -0700598 self.testclass_metric_logger = (
Xianyuan Jia976d4042019-09-30 17:19:47 -0700599 BlackboxMappedMetricLogger.for_test_class())
Omar El Ayach02a1cce2019-09-19 17:51:39 -0700600 self.publish_testcase_metrics = False
Omar El Ayacheb226db2018-09-04 15:28:45 -0700601
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700602 def setup_class(self):
603 WifiPingTest.setup_class(self)
604 self.ota_chamber = ota_chamber.create(
605 self.user_params['OTAChamber'])[0]
Omar El Ayacheb226db2018-09-04 15:28:45 -0700606
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700607 def teardown_class(self):
Omar El Ayach00ff4a42020-04-06 11:43:41 -0700608 WifiPingTest.teardown_class(self)
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700609 self.process_testclass_results()
610 self.ota_chamber.reset_chamber()
Omar El Ayacheb226db2018-09-04 15:28:45 -0700611
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700612 def process_testclass_results(self):
613 """Saves all test results to enable comparison."""
614 WifiPingTest.process_testclass_results(self)
Omar El Ayacheb226db2018-09-04 15:28:45 -0700615
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700616 range_vs_angle = collections.OrderedDict()
617 for test in self.testclass_results:
618 curr_params = test['testcase_params']
619 curr_config = curr_params['channel']
620 if curr_config in range_vs_angle:
Omar El Ayach87222062020-03-25 19:34:12 -0700621 if curr_params['position'] not in range_vs_angle[curr_config][
622 'position']:
623 range_vs_angle[curr_config]['position'].append(
624 curr_params['position'])
625 range_vs_angle[curr_config]['range'].append(test['range'])
626 range_vs_angle[curr_config]['llstats_at_range'].append(
627 test['llstats_at_range'])
628 else:
629 range_vs_angle[curr_config]['range'][-1] = test['range']
630 range_vs_angle[curr_config]['llstats_at_range'][-1] = test[
631 'llstats_at_range']
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700632 else:
633 range_vs_angle[curr_config] = {
634 'position': [curr_params['position']],
Omar El Ayach00ecc862019-09-28 13:31:17 -0700635 'range': [test['range']],
636 'llstats_at_range': [test['llstats_at_range']]
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700637 }
638 chamber_mode = self.testclass_results[0]['testcase_params'][
639 'chamber_mode']
640 if chamber_mode == 'orientation':
641 x_label = 'Angle (deg)'
642 elif chamber_mode == 'stepped stirrers':
643 x_label = 'Position Index'
644 figure = wputils.BokehFigure(
645 title='Range vs. Position',
646 x_label=x_label,
Omar El Ayach954eb282019-09-30 15:33:32 -0700647 primary_y_label='Range (dB)',
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700648 )
Omar El Ayach40099d02019-09-12 15:17:33 -0700649 for channel, channel_data in range_vs_angle.items():
Omar El Ayachd80a7ca2019-10-16 16:57:05 -0700650 figure.add_line(x_data=channel_data['position'],
651 y_data=channel_data['range'],
652 hover_text=channel_data['llstats_at_range'],
653 legend='Channel {}'.format(channel))
Omar El Ayach40099d02019-09-12 15:17:33 -0700654 average_range = sum(channel_data['range']) / len(
655 channel_data['range'])
656 self.log.info('Average range for Channel {} is: {}dB'.format(
657 channel, average_range))
658 metric_name = 'ota_summary_ch{}.avg_range'.format(channel)
Omar El Ayach02a1cce2019-09-19 17:51:39 -0700659 self.testclass_metric_logger.add_metric(metric_name, average_range)
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700660 current_context = context.get_current_context().get_full_output_path()
661 plot_file_path = os.path.join(current_context, 'results.html')
662 figure.generate_figure(plot_file_path)
Omar El Ayacheb226db2018-09-04 15:28:45 -0700663
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700664 # Save results
665 results_file_path = os.path.join(current_context,
666 'testclass_summary.json')
667 with open(results_file_path, 'w') as results_file:
668 json.dump(range_vs_angle, results_file, indent=4)
Omar El Ayacheb226db2018-09-04 15:28:45 -0700669
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700670 def setup_ping_test(self, testcase_params):
671 WifiPingTest.setup_ping_test(self, testcase_params)
672 # Setup turntable
673 if testcase_params['chamber_mode'] == 'orientation':
674 self.ota_chamber.set_orientation(testcase_params['position'])
675 elif testcase_params['chamber_mode'] == 'stepped stirrers':
676 self.ota_chamber.step_stirrers(testcase_params['total_positions'])
Omar El Ayacheb226db2018-09-04 15:28:45 -0700677
Omar El Ayach10c67b72019-09-16 15:14:54 -0700678 def extract_test_id(self, testcase_params, id_fields):
679 test_id = collections.OrderedDict(
680 (param, testcase_params[param]) for param in id_fields)
681 return test_id
682
683 def get_range_start_atten(self, testcase_params):
684 """Gets the starting attenuation for this ping test.
685
686 The function gets the starting attenuation by checking whether a test
687 at the same configuration has executed. If so it sets the starting
688 point a configurable number of dBs below the reference test.
689
690 Returns:
691 start_atten: starting attenuation for current test
692 """
Omar El Ayach87222062020-03-25 19:34:12 -0700693 # If the test is being retried, start from the beginning
694 if self.retry_flag:
695 self.log.info('Retry flag set. Setting attenuation to minimum.')
696 return self.testclass_params['range_atten_start']
Omar El Ayach10c67b72019-09-16 15:14:54 -0700697 # Get the current and reference test config. The reference test is the
698 # one performed at the current MCS+1
Omar El Ayach9c56cf32019-09-19 13:07:51 -0700699 ref_test_params = self.extract_test_id(testcase_params,
700 ['channel', 'mode'])
Omar El Ayach10c67b72019-09-16 15:14:54 -0700701 # Check if reference test has been run and set attenuation accordingly
702 previous_params = [
Omar El Ayach9c56cf32019-09-19 13:07:51 -0700703 self.extract_test_id(result['testcase_params'],
704 ['channel', 'mode'])
Omar El Ayach10c67b72019-09-16 15:14:54 -0700705 for result in self.testclass_results
706 ]
707 try:
708 ref_index = previous_params[::-1].index(ref_test_params)
709 ref_index = len(previous_params) - 1 - ref_index
710 start_atten = self.testclass_results[ref_index][
711 'atten_at_range'] - (
712 self.testclass_params['adjacent_range_test_gap'])
713 except ValueError:
Omar El Ayach87222062020-03-25 19:34:12 -0700714 self.log.info(
715 'Reference test not found. Starting from {} dB'.format(
716 self.testclass_params['range_atten_start']))
Omar El Ayach10c67b72019-09-16 15:14:54 -0700717 start_atten = self.testclass_params['range_atten_start']
718 return start_atten
719
Omar El Ayach22460ae2019-09-10 13:29:48 -0700720 def generate_test_cases(self, ap_power, channels, modes, chamber_mode,
721 positions):
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700722 test_cases = []
723 allowed_configs = {
724 'VHT20': [
725 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 36, 40, 44, 48, 149, 153,
726 157, 161
727 ],
728 'VHT40': [36, 44, 149, 157],
729 'VHT80': [36, 149]
730 }
731 for channel, mode, position in itertools.product(
732 channels, modes, positions):
733 if channel not in allowed_configs[mode]:
734 continue
735 testcase_name = 'test_ping_range_ch{}_{}_pos{}'.format(
736 channel, mode, position)
737 testcase_params = collections.OrderedDict(
738 test_type='test_ping_range',
Omar El Ayach22460ae2019-09-10 13:29:48 -0700739 ap_power=ap_power,
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700740 channel=channel,
741 mode=mode,
Omar El Ayachc27b7f92019-12-04 15:46:43 -0800742 chain_mask='2x2',
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700743 chamber_mode=chamber_mode,
744 total_positions=len(positions),
745 position=position)
746 setattr(self, testcase_name,
747 partial(self._test_ping, testcase_params))
748 test_cases.append(testcase_name)
749 return test_cases
Omar El Ayacheb226db2018-09-04 15:28:45 -0700750
Omar El Ayacheb226db2018-09-04 15:28:45 -0700751
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700752class WifiOtaPing_TenDegree_Test(WifiOtaPingTest):
753 def __init__(self, controllers):
754 WifiOtaPingTest.__init__(self, controllers)
Omar El Ayachd80a7ca2019-10-16 16:57:05 -0700755 self.tests = self.generate_test_cases(ap_power='standard',
756 channels=[6, 36, 149],
757 modes=['VHT20'],
758 chamber_mode='orientation',
759 positions=list(range(0, 360,
760 10)))
Omar El Ayacheb226db2018-09-04 15:28:45 -0700761
Omar El Ayacheb226db2018-09-04 15:28:45 -0700762
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700763class WifiOtaPing_45Degree_Test(WifiOtaPingTest):
764 def __init__(self, controllers):
765 WifiOtaPingTest.__init__(self, controllers)
766 self.tests = self.generate_test_cases(
Omar El Ayach22460ae2019-09-10 13:29:48 -0700767 ap_power='standard',
768 channels=[1, 6, 11, 36, 40, 44, 48, 149, 153, 157, 161],
769 modes=['VHT20'],
770 chamber_mode='orientation',
771 positions=list(range(0, 360, 45)))
Omar El Ayacheb226db2018-09-04 15:28:45 -0700772
Omar El Ayacheb226db2018-09-04 15:28:45 -0700773
Omar El Ayachbbc6a0a2019-07-22 10:26:11 -0700774class WifiOtaPing_SteppedStirrers_Test(WifiOtaPingTest):
775 def __init__(self, controllers):
776 WifiOtaPingTest.__init__(self, controllers)
Omar El Ayachd80a7ca2019-10-16 16:57:05 -0700777 self.tests = self.generate_test_cases(ap_power='standard',
778 channels=[6, 36, 149],
779 modes=['VHT20'],
780 chamber_mode='stepped stirrers',
781 positions=list(range(100)))
Omar El Ayach22460ae2019-09-10 13:29:48 -0700782
783
784class WifiOtaPing_LowPowerAP_TenDegree_Test(WifiOtaPingTest):
785 def __init__(self, controllers):
786 WifiOtaPingTest.__init__(self, controllers)
Omar El Ayachd80a7ca2019-10-16 16:57:05 -0700787 self.tests = self.generate_test_cases(ap_power='low_power',
788 channels=[6, 36, 149],
789 modes=['VHT20'],
790 chamber_mode='orientation',
791 positions=list(range(0, 360,
792 10)))
Omar El Ayach22460ae2019-09-10 13:29:48 -0700793
794
795class WifiOtaPing_LowPowerAP_45Degree_Test(WifiOtaPingTest):
796 def __init__(self, controllers):
797 WifiOtaPingTest.__init__(self, controllers)
798 self.tests = self.generate_test_cases(
799 ap_power='low_power',
800 channels=[1, 6, 11, 36, 40, 44, 48, 149, 153, 157, 161],
801 modes=['VHT20'],
802 chamber_mode='orientation',
803 positions=list(range(0, 360, 45)))
804
805
806class WifiOtaPing_LowPowerAP_SteppedStirrers_Test(WifiOtaPingTest):
807 def __init__(self, controllers):
808 WifiOtaPingTest.__init__(self, controllers)
Omar El Ayachd80a7ca2019-10-16 16:57:05 -0700809 self.tests = self.generate_test_cases(ap_power='low_power',
810 channels=[6, 36, 149],
811 modes=['VHT20'],
812 chamber_mode='stepped stirrers',
813 positions=list(range(100)))