Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 1 | #!/usr/bin/env python3.4 |
| 2 | # |
| 3 | # Copyright 2019 - The Android Open Source Project |
| 4 | # |
| 5 | # Licensed under the Apache License, Version 2.0 (the "License"); |
| 6 | # you may not use this file except in compliance with the License. |
| 7 | # You may obtain a copy of the License at |
| 8 | # |
| 9 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 10 | # |
| 11 | # Unless required by applicable law or agreed to in writing, software |
| 12 | # distributed under the License is distributed on an "AS IS" BASIS, |
| 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 14 | # See the License for the specific language governing permissions and |
| 15 | # limitations under the License. |
| 16 | |
| 17 | import collections |
Omar El Ayach | 45ea322 | 2020-12-21 22:00:49 -0800 | [diff] [blame^] | 18 | import copy |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 19 | import json |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 20 | import math |
| 21 | import os |
| 22 | import time |
| 23 | from acts import asserts |
| 24 | from acts import base_test |
| 25 | from acts import context |
Omar El Ayach | d710909 | 2019-09-29 18:31:33 -0700 | [diff] [blame] | 26 | from acts import utils |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 27 | from acts.controllers import iperf_server as ipf |
| 28 | from acts.controllers.utils_lib import ssh |
Omar El Ayach | d30d398 | 2020-04-06 14:07:01 -0700 | [diff] [blame] | 29 | from acts.metrics.loggers.blackbox import BlackboxMappedMetricLogger |
Xianyuan Jia | 63751fb | 2020-11-17 00:07:40 +0000 | [diff] [blame] | 30 | from acts_contrib.test_utils.wifi import wifi_performance_test_utils as wputils |
| 31 | from acts_contrib.test_utils.wifi import wifi_retail_ap as retail_ap |
| 32 | from acts_contrib.test_utils.wifi import wifi_test_utils as wutils |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 33 | |
| 34 | SHORT_SLEEP = 1 |
| 35 | MED_SLEEP = 5 |
| 36 | TRAFFIC_GAP_THRESH = 0.5 |
| 37 | IPERF_INTERVAL = 0.25 |
| 38 | |
| 39 | |
| 40 | class WifiRoamingPerformanceTest(base_test.BaseTestClass): |
| 41 | """Class for ping-based Wifi performance tests. |
| 42 | |
| 43 | This class implements WiFi ping performance tests such as range and RTT. |
| 44 | The class setups up the AP in the desired configurations, configures |
| 45 | and connects the phone to the AP, and runs For an example config file to |
| 46 | run this test class see example_connectivity_performance_ap_sta.json. |
| 47 | """ |
Omar El Ayach | d30d398 | 2020-04-06 14:07:01 -0700 | [diff] [blame] | 48 | def __init__(self, controllers): |
| 49 | base_test.BaseTestClass.__init__(self, controllers) |
| 50 | self.testcase_metric_logger = ( |
| 51 | BlackboxMappedMetricLogger.for_test_case()) |
| 52 | self.testclass_metric_logger = ( |
| 53 | BlackboxMappedMetricLogger.for_test_class()) |
| 54 | self.publish_testcase_metrics = True |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 55 | |
| 56 | def setup_class(self): |
| 57 | """Initializes common test hardware and parameters. |
| 58 | |
| 59 | This function initializes hardwares and compiles parameters that are |
| 60 | common to all tests in this class. |
| 61 | """ |
Omar El Ayach | 74f78dc | 2019-07-30 15:15:34 -0700 | [diff] [blame] | 62 | self.dut = self.android_devices[-1] |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 63 | req_params = [ |
| 64 | 'RetailAccessPoints', 'roaming_test_params', 'testbed_params' |
| 65 | ] |
| 66 | opt_params = ['main_network', 'RemoteServer'] |
| 67 | self.unpack_userparams(req_params, opt_params) |
| 68 | self.testclass_params = self.roaming_test_params |
| 69 | self.num_atten = self.attenuators[0].instrument.num_atten |
| 70 | self.remote_server = ssh.connection.SshConnection( |
| 71 | ssh.settings.from_config(self.RemoteServer[0]['ssh_config'])) |
| 72 | self.remote_server.setup_master_ssh() |
| 73 | self.iperf_server = self.iperf_servers[0] |
| 74 | self.iperf_client = self.iperf_clients[0] |
Omar El Ayach | 45ea322 | 2020-12-21 22:00:49 -0800 | [diff] [blame^] | 75 | self.access_points = retail_ap.create(self.RetailAccessPoints) |
Omar El Ayach | 7347770 | 2019-08-07 10:12:33 -0700 | [diff] [blame] | 76 | |
| 77 | # Get RF connection map |
| 78 | self.log.info("Getting RF connection map.") |
Omar El Ayach | 98be238 | 2019-09-04 15:11:50 -0700 | [diff] [blame] | 79 | wutils.wifi_toggle_state(self.dut, True) |
Omar El Ayach | 7347770 | 2019-08-07 10:12:33 -0700 | [diff] [blame] | 80 | self.rf_map_by_network, self.rf_map_by_atten = ( |
| 81 | wputils.get_full_rf_connection_map(self.attenuators, self.dut, |
| 82 | self.remote_server, |
Omar El Ayach | 45ea322 | 2020-12-21 22:00:49 -0800 | [diff] [blame^] | 83 | self.main_network, True)) |
Omar El Ayach | ab047c0 | 2019-09-03 11:38:30 -0700 | [diff] [blame] | 84 | self.log.info("RF Map (by Network): {}".format(self.rf_map_by_network)) |
| 85 | self.log.info("RF Map (by Atten): {}".format(self.rf_map_by_atten)) |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 86 | |
| 87 | #Turn WiFi ON |
Omar El Ayach | d710909 | 2019-09-29 18:31:33 -0700 | [diff] [blame] | 88 | if self.testclass_params.get('airplane_mode', 1): |
| 89 | self.log.info('Turning on airplane mode.') |
Omar El Ayach | d30d398 | 2020-04-06 14:07:01 -0700 | [diff] [blame] | 90 | asserts.assert_true(utils.force_airplane_mode(self.dut, True), |
| 91 | "Can not turn on airplane mode.") |
Omar El Ayach | 9c56cf3 | 2019-09-19 13:07:51 -0700 | [diff] [blame] | 92 | wutils.wifi_toggle_state(self.dut, True) |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 93 | |
| 94 | def pass_fail_traffic_continuity(self, result): |
| 95 | """Pass fail check for traffic continuity |
| 96 | |
| 97 | Currently, the function only reports test results and implicitly passes |
| 98 | the test. A pass fail criterion is current being researched. |
| 99 | |
| 100 | Args: |
| 101 | result: dict containing test results |
| 102 | """ |
| 103 | self.log.info('Detected {} roam transitions:'.format( |
| 104 | len(result['roam_transitions']))) |
| 105 | for event in result['roam_transitions']: |
Omar El Ayach | 45ea322 | 2020-12-21 22:00:49 -0800 | [diff] [blame^] | 106 | self.log.info('Roam @ {0:.2f}s: {1} -> {2})'.format( |
| 107 | event[0], event[1], event[2])) |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 108 | self.log.info('Roam transition statistics: {}'.format( |
| 109 | result['roam_counts'])) |
| 110 | |
| 111 | formatted_traffic_gaps = [ |
| 112 | round(gap, 2) for gap in result['traffic_disruption'] |
| 113 | ] |
| 114 | self.log.info('Detected {} traffic gaps of duration: {}'.format( |
| 115 | len(result['traffic_disruption']), formatted_traffic_gaps)) |
| 116 | |
Omar El Ayach | d30d398 | 2020-04-06 14:07:01 -0700 | [diff] [blame] | 117 | if result['total_roams'] > 0: |
| 118 | disruption_percentage = (len(result['traffic_disruption']) / |
| 119 | result['total_roams']) * 100 |
| 120 | max_disruption = max(result['traffic_disruption']) |
Omar El Ayach | 7347770 | 2019-08-07 10:12:33 -0700 | [diff] [blame] | 121 | else: |
Omar El Ayach | d30d398 | 2020-04-06 14:07:01 -0700 | [diff] [blame] | 122 | disruption_percentage = 0 |
| 123 | max_disruption = 0 |
| 124 | self.testcase_metric_logger.add_metric('disruption_percentage', |
| 125 | disruption_percentage) |
| 126 | self.testcase_metric_logger.add_metric('max_disruption', |
| 127 | max_disruption) |
| 128 | |
| 129 | if disruption_percentage == 0: |
| 130 | asserts.explicit_pass('Test passed. No traffic disruptions found.') |
| 131 | elif max_disruption > self.testclass_params[ |
| 132 | 'traffic_disruption_threshold']: |
| 133 | asserts.fail('Test failed. Disruption Percentage = {}%. ' |
| 134 | 'Max traffic disruption: {}s.'.format( |
| 135 | disruption_percentage, max_disruption)) |
| 136 | else: |
| 137 | asserts.explicit_pass('Test failed. Disruption Percentage = {}%. ' |
| 138 | 'Max traffic disruption: {}s.'.format( |
| 139 | disruption_percentage, max_disruption)) |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 140 | |
| 141 | def pass_fail_roaming_consistency(self, results_dict): |
| 142 | """Function to evaluate roaming consistency results. |
| 143 | |
| 144 | The function looks for the roams recorded in multiple runs of the same |
| 145 | attenuation waveform and checks that the DUT reliably roams to the |
| 146 | same network |
| 147 | |
| 148 | Args: |
| 149 | results_dict: dict containing consistency test results |
| 150 | """ |
| 151 | test_fail = False |
| 152 | for secondary_atten, roam_stats in results_dict['roam_stats'].items(): |
| 153 | total_roams = sum(list(roam_stats.values())) |
| 154 | common_roam = max(roam_stats.keys(), key=(lambda k: roam_stats[k])) |
| 155 | common_roam_frequency = roam_stats[common_roam] / total_roams |
| 156 | self.log.info( |
| 157 | '{}dB secondary atten. Most common roam: {}. Frequency: {}'. |
| 158 | format(secondary_atten, common_roam, common_roam_frequency)) |
| 159 | if common_roam_frequency < self.testclass_params[ |
| 160 | 'consistency_threshold']: |
| 161 | test_fail = True |
| 162 | self.log.info('Unstable Roams at {}dB secondary att'.format( |
| 163 | secondary_atten)) |
Omar El Ayach | d30d398 | 2020-04-06 14:07:01 -0700 | [diff] [blame] | 164 | self.testcase_metric_logger.add_metric('common_roam_frequency', |
| 165 | common_roam_frequency) |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 166 | if test_fail: |
| 167 | asserts.fail('Incosistent roaming detected.') |
| 168 | else: |
| 169 | asserts.explicit_pass('Consistent roaming at all levels.') |
| 170 | |
| 171 | def process_traffic_continuity_results(self, testcase_params, result): |
| 172 | """Function to process traffic results. |
| 173 | |
| 174 | The function looks for traffic gaps during a roaming test |
| 175 | |
| 176 | Args: |
| 177 | testcase_params: dict containing all test results and meta data |
| 178 | results_dict: dict containing consistency test results |
| 179 | """ |
| 180 | self.detect_roam_events(result) |
Omar El Ayach | 68395c4 | 2019-03-01 11:25:47 -0800 | [diff] [blame] | 181 | current_context = context.get_current_context().get_full_output_path() |
| 182 | plot_file_path = os.path.join(current_context, |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 183 | self.current_test_name + '.html') |
| 184 | |
| 185 | if 'ping' in self.current_test_name: |
| 186 | self.detect_ping_gaps(result) |
Omar El Ayach | d30d398 | 2020-04-06 14:07:01 -0700 | [diff] [blame] | 187 | self.plot_ping_result(testcase_params, |
| 188 | result, |
| 189 | output_file_path=plot_file_path) |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 190 | elif 'iperf' in self.current_test_name: |
| 191 | self.detect_iperf_gaps(result) |
Omar El Ayach | d30d398 | 2020-04-06 14:07:01 -0700 | [diff] [blame] | 192 | self.plot_iperf_result(testcase_params, |
| 193 | result, |
| 194 | output_file_path=plot_file_path) |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 195 | |
Omar El Ayach | 68395c4 | 2019-03-01 11:25:47 -0800 | [diff] [blame] | 196 | results_file_path = os.path.join(current_context, |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 197 | self.current_test_name + '.json') |
| 198 | with open(results_file_path, 'w') as results_file: |
Omar El Ayach | 7347770 | 2019-08-07 10:12:33 -0700 | [diff] [blame] | 199 | json.dump(wputils.serialize_dict(result), results_file, indent=4) |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 200 | |
| 201 | def process_consistency_results(self, testcase_params, results_dict): |
| 202 | """Function to process roaming consistency results. |
| 203 | |
| 204 | The function looks compiles the test of roams recorded in consistency |
| 205 | tests and plots results for easy visualization. |
| 206 | |
| 207 | Args: |
| 208 | testcase_params: dict containing all test results and meta data |
| 209 | results_dict: dict containing consistency test results |
| 210 | """ |
| 211 | # make figure placeholder and get relevant functions |
| 212 | if 'ping' in self.current_test_name: |
| 213 | detect_gaps = self.detect_ping_gaps |
| 214 | plot_result = self.plot_ping_result |
| 215 | primary_y_axis = 'RTT (ms)' |
| 216 | elif 'iperf' in self.current_test_name: |
| 217 | detect_gaps = self.detect_iperf_gaps |
| 218 | plot_result = self.plot_iperf_result |
| 219 | primary_y_axis = 'Throughput (Mbps)' |
| 220 | # loop over results |
| 221 | roam_stats = collections.OrderedDict() |
Omar El Ayach | 68395c4 | 2019-03-01 11:25:47 -0800 | [diff] [blame] | 222 | current_context = context.get_current_context().get_full_output_path() |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 223 | for secondary_atten, results_list in results_dict.items(): |
Omar El Ayach | d30d398 | 2020-04-06 14:07:01 -0700 | [diff] [blame] | 224 | figure = wputils.BokehFigure(title=self.current_test_name, |
| 225 | x_label='Time (ms)', |
| 226 | primary_y_label=primary_y_axis, |
| 227 | secondary_y_label='RSSI (dBm)') |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 228 | roam_stats[secondary_atten] = collections.OrderedDict() |
| 229 | for result in results_list: |
| 230 | self.detect_roam_events(result) |
| 231 | for roam_transition, count in result['roam_counts'].items(): |
| 232 | roam_stats[secondary_atten][ |
| 233 | roam_transition] = roam_stats[secondary_atten].get( |
| 234 | roam_transition, 0) + count |
| 235 | detect_gaps(result) |
| 236 | plot_result(testcase_params, result, figure=figure) |
| 237 | # save plot |
Omar El Ayach | d30d398 | 2020-04-06 14:07:01 -0700 | [diff] [blame] | 238 | plot_file_name = (self.current_test_name + '_' + |
| 239 | str(secondary_atten) + '.html') |
Omar El Ayach | 68395c4 | 2019-03-01 11:25:47 -0800 | [diff] [blame] | 240 | |
| 241 | plot_file_path = os.path.join(current_context, plot_file_name) |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 242 | figure.save_figure(plot_file_path) |
| 243 | results_dict['roam_stats'] = roam_stats |
| 244 | |
Omar El Ayach | 68395c4 | 2019-03-01 11:25:47 -0800 | [diff] [blame] | 245 | results_file_path = os.path.join(current_context, |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 246 | self.current_test_name + '.json') |
| 247 | with open(results_file_path, 'w') as results_file: |
Omar El Ayach | 7347770 | 2019-08-07 10:12:33 -0700 | [diff] [blame] | 248 | json.dump(wputils.serialize_dict(result), results_file, indent=4) |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 249 | |
| 250 | def detect_roam_events(self, result): |
| 251 | """Function to process roaming results. |
| 252 | |
| 253 | The function detects roams by looking at changes in BSSID and compiles |
| 254 | meta data about each roam, e.g., RSSI before and after a roam. The |
| 255 | function then calls the relevant method to process traffic results and |
| 256 | report traffic disruptions. |
| 257 | |
| 258 | Args: |
| 259 | testcase_params: dict containing AP and other test params |
| 260 | result: dict containing test results |
| 261 | """ |
| 262 | roam_events = [ |
| 263 | (idx, idx + 1) |
| 264 | for idx in range(len(result['rssi_result']['bssid']) - 1) |
| 265 | if result['rssi_result']['bssid'][idx] != result['rssi_result'] |
| 266 | ['bssid'][idx + 1] |
| 267 | ] |
| 268 | |
| 269 | def ignore_entry(vals): |
| 270 | for val in vals: |
| 271 | if val in {0} or math.isnan(val): |
| 272 | return True |
| 273 | return False |
| 274 | |
| 275 | for roam_idx, roam_event in enumerate(roam_events): |
| 276 | # Find true roam start by scanning earlier samples for valid data |
| 277 | while ignore_entry([ |
| 278 | result['rssi_result']['frequency'][roam_event[0]], |
| 279 | result['rssi_result']['signal_poll_rssi']['data'][ |
| 280 | roam_event[0]] |
| 281 | ]): |
| 282 | roam_event = (roam_event[0] - 1, roam_event[1]) |
| 283 | roam_events[roam_idx] = roam_event |
| 284 | # Find true roam end by scanning later samples for valid data |
| 285 | while ignore_entry([ |
| 286 | result['rssi_result']['frequency'][roam_event[1]], |
| 287 | result['rssi_result']['signal_poll_rssi']['data'][ |
| 288 | roam_event[1]] |
| 289 | ]): |
| 290 | roam_event = (roam_event[0], roam_event[1] + 1) |
| 291 | roam_events[roam_idx] = roam_event |
| 292 | |
| 293 | roam_events = list(set(roam_events)) |
| 294 | roam_events.sort(key=lambda event_tuple: event_tuple[1]) |
| 295 | roam_transitions = [] |
| 296 | roam_counts = {} |
Omar El Ayach | d30d398 | 2020-04-06 14:07:01 -0700 | [diff] [blame] | 297 | total_roams = 0 |
Omar El Ayach | 45ea322 | 2020-12-21 22:00:49 -0800 | [diff] [blame^] | 298 | roam_candidates = copy.deepcopy(self.main_network) |
| 299 | roam_candidates['disconnected'] = {'BSSID': 'disconnected'} |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 300 | for event in roam_events: |
| 301 | from_bssid = next( |
Omar El Ayach | 45ea322 | 2020-12-21 22:00:49 -0800 | [diff] [blame^] | 302 | key for key, value in roam_candidates.items() |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 303 | if value['BSSID'] == result['rssi_result']['bssid'][event[0]]) |
| 304 | to_bssid = next( |
Omar El Ayach | 45ea322 | 2020-12-21 22:00:49 -0800 | [diff] [blame^] | 305 | key for key, value in roam_candidates.items() |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 306 | if value['BSSID'] == result['rssi_result']['bssid'][event[1]]) |
Omar El Ayach | 45ea322 | 2020-12-21 22:00:49 -0800 | [diff] [blame^] | 307 | if from_bssid == to_bssid: |
| 308 | continue |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 309 | curr_bssid_transition = (from_bssid, to_bssid) |
| 310 | curr_roam_transition = ( |
Omar El Ayach | 45ea322 | 2020-12-21 22:00:49 -0800 | [diff] [blame^] | 311 | result['rssi_result']['time_stamp'][event[0]], |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 312 | (from_bssid, |
| 313 | result['rssi_result']['signal_poll_rssi']['data'][event[0]]), |
| 314 | (to_bssid, |
| 315 | result['rssi_result']['signal_poll_rssi']['data'][event[1]])) |
| 316 | roam_transitions.append(curr_roam_transition) |
| 317 | roam_counts[curr_bssid_transition] = roam_counts.get( |
| 318 | curr_bssid_transition, 0) + 1 |
Omar El Ayach | d30d398 | 2020-04-06 14:07:01 -0700 | [diff] [blame] | 319 | total_roams = total_roams + 1 |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 320 | result['roam_events'] = roam_events |
| 321 | result['roam_transitions'] = roam_transitions |
| 322 | result['roam_counts'] = roam_counts |
Omar El Ayach | d30d398 | 2020-04-06 14:07:01 -0700 | [diff] [blame] | 323 | result['total_roams'] = total_roams |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 324 | |
| 325 | def detect_ping_gaps(self, result): |
| 326 | """Function to process ping results. |
| 327 | |
| 328 | The function looks for gaps in iperf traffic and reports them as |
| 329 | disruptions due to roams. |
| 330 | |
| 331 | Args: |
| 332 | result: dict containing test results |
| 333 | """ |
| 334 | traffic_disruption = [ |
| 335 | x for x in result['ping_result']['ping_interarrivals'] |
| 336 | if x > TRAFFIC_GAP_THRESH |
| 337 | ] |
| 338 | result['traffic_disruption'] = traffic_disruption |
| 339 | |
| 340 | def detect_iperf_gaps(self, result): |
| 341 | """Function to process iperf results. |
| 342 | |
| 343 | The function looks for gaps in iperf traffic and reports them as |
| 344 | disruptions due to roams. |
| 345 | |
| 346 | Args: |
| 347 | result: dict containing test results |
| 348 | """ |
| 349 | tput_thresholding = [tput < 1 for tput in result['throughput']] |
| 350 | window_size = int(TRAFFIC_GAP_THRESH / IPERF_INTERVAL) |
| 351 | tput_thresholding = [ |
| 352 | any(tput_thresholding[max(0, idx - window_size):idx]) |
| 353 | for idx in range(1, |
| 354 | len(tput_thresholding) + 1) |
| 355 | ] |
| 356 | |
| 357 | traffic_disruption = [] |
| 358 | current_disruption = 1 - window_size |
| 359 | for tput_low in tput_thresholding: |
| 360 | if tput_low: |
| 361 | current_disruption += 1 |
| 362 | elif current_disruption > window_size: |
| 363 | traffic_disruption.append(current_disruption * IPERF_INTERVAL) |
| 364 | current_disruption = 1 - window_size |
| 365 | else: |
| 366 | current_disruption = 1 - window_size |
| 367 | result['traffic_disruption'] = traffic_disruption |
| 368 | |
| 369 | def plot_ping_result(self, |
| 370 | testcase_params, |
| 371 | result, |
| 372 | figure=None, |
| 373 | output_file_path=None): |
| 374 | """Function to plot ping results. |
| 375 | |
| 376 | The function plots ping RTTs along with RSSI over time during a roaming |
| 377 | test. |
| 378 | |
| 379 | Args: |
| 380 | testcase_params: dict containing all test params |
| 381 | result: dict containing test results |
| 382 | figure: optional bokeh figure object to add current plot to |
| 383 | output_file_path: optional path to output file |
| 384 | """ |
| 385 | if not figure: |
Omar El Ayach | d30d398 | 2020-04-06 14:07:01 -0700 | [diff] [blame] | 386 | figure = wputils.BokehFigure(title=self.current_test_name, |
| 387 | x_label='Time (ms)', |
| 388 | primary_y_label='RTT (ms)', |
| 389 | secondary_y_label='RSSI (dBm)') |
| 390 | figure.add_line(x_data=result['ping_result']['time_stamp'], |
| 391 | y_data=result['ping_result']['rtt'], |
| 392 | legend='Ping RTT', |
| 393 | width=1) |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 394 | figure.add_line( |
Omar El Ayach | 7347770 | 2019-08-07 10:12:33 -0700 | [diff] [blame] | 395 | x_data=result['rssi_result']['time_stamp'], |
| 396 | y_data=result['rssi_result']['signal_poll_rssi']['data'], |
| 397 | legend='RSSI', |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 398 | y_axis='secondary') |
Omar El Ayach | 45ea322 | 2020-12-21 22:00:49 -0800 | [diff] [blame^] | 399 | try: |
| 400 | figure.generate_figure(output_file_path) |
| 401 | except: |
| 402 | pass |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 403 | |
| 404 | def plot_iperf_result(self, |
| 405 | testcase_params, |
| 406 | result, |
| 407 | figure=None, |
| 408 | output_file_path=None): |
| 409 | """Function to plot iperf results. |
| 410 | |
| 411 | The function plots iperf throughput and RSSI over time during a roaming |
| 412 | test. |
| 413 | |
| 414 | Args: |
| 415 | testcase_params: dict containing all test params |
| 416 | result: dict containing test results |
| 417 | figure: optional bokeh figure object to add current plot to |
| 418 | output_file_path: optional path to output file |
| 419 | """ |
| 420 | if not figure: |
Omar El Ayach | d30d398 | 2020-04-06 14:07:01 -0700 | [diff] [blame] | 421 | figure = wputils.BokehFigure(title=self.current_test_name, |
| 422 | x_label='Time (s)', |
| 423 | primary_y_label='Throughput (Mbps)', |
| 424 | secondary_y_label='RSSI (dBm)') |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 425 | iperf_time_stamps = [ |
| 426 | idx * IPERF_INTERVAL for idx in range(len(result['throughput'])) |
| 427 | ] |
Omar El Ayach | d30d398 | 2020-04-06 14:07:01 -0700 | [diff] [blame] | 428 | figure.add_line(iperf_time_stamps, |
| 429 | result['throughput'], |
| 430 | 'Throughput', |
| 431 | width=1) |
| 432 | figure.add_line(result['rssi_result']['time_stamp'], |
| 433 | result['rssi_result']['signal_poll_rssi']['data'], |
| 434 | 'RSSI', |
| 435 | y_axis='secondary') |
Omar El Ayach | 45ea322 | 2020-12-21 22:00:49 -0800 | [diff] [blame^] | 436 | try: |
| 437 | figure.generate_figure(output_file_path) |
| 438 | except: |
| 439 | pass |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 440 | |
| 441 | def setup_ap(self, testcase_params): |
| 442 | """Sets up the AP and attenuator to the test configuration. |
| 443 | |
| 444 | Args: |
| 445 | testcase_params: dict containing AP and other test params |
| 446 | """ |
| 447 | (primary_net_id, |
| 448 | primary_net_config) = next(net for net in self.main_network.items() |
| 449 | if net[1]['roaming_label'] == 'primary') |
Omar El Ayach | 98be238 | 2019-09-04 15:11:50 -0700 | [diff] [blame] | 450 | for idx, atten in enumerate(self.attenuators): |
| 451 | nets_on_port = [ |
| 452 | item["network"] for item in self.rf_map_by_atten[idx] |
| 453 | ] |
| 454 | if primary_net_id in nets_on_port: |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 455 | atten.set_atten(0) |
| 456 | else: |
| 457 | atten.set_atten(atten.instrument.max_atten) |
| 458 | |
| 459 | def setup_dut(self, testcase_params): |
| 460 | """Sets up the DUT in the configuration required by the test. |
| 461 | |
| 462 | Args: |
| 463 | testcase_params: dict containing AP and other test params |
| 464 | """ |
Omar El Ayach | 656bf3d | 2019-07-31 15:04:53 -0700 | [diff] [blame] | 465 | # Check battery level before test |
| 466 | if not wputils.health_check(self.dut, 10): |
| 467 | asserts.skip('Battery level too low. Skipping test.') |
Omar El Ayach | 74f78dc | 2019-07-30 15:15:34 -0700 | [diff] [blame] | 468 | wutils.reset_wifi(self.dut) |
Roshan Pius | 5b19a12 | 2019-09-13 08:07:30 -0700 | [diff] [blame] | 469 | wutils.set_wifi_country_code(self.dut, |
Omar El Ayach | d30d398 | 2020-04-06 14:07:01 -0700 | [diff] [blame] | 470 | self.testclass_params['country_code']) |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 471 | (primary_net_id, |
| 472 | primary_net_config) = next(net for net in self.main_network.items() |
| 473 | if net[1]['roaming_label'] == 'primary') |
| 474 | network = primary_net_config.copy() |
| 475 | network.pop('BSSID', None) |
Omar El Ayach | 74f78dc | 2019-07-30 15:15:34 -0700 | [diff] [blame] | 476 | self.dut.droid.wifiSetEnableAutoJoinWhenAssociated(1) |
Omar El Ayach | d30d398 | 2020-04-06 14:07:01 -0700 | [diff] [blame] | 477 | wutils.wifi_connect(self.dut, |
| 478 | network, |
| 479 | num_of_tries=5, |
Omar El Ayach | 45ea322 | 2020-12-21 22:00:49 -0800 | [diff] [blame^] | 480 | check_connectivity=True) |
Omar El Ayach | 74f78dc | 2019-07-30 15:15:34 -0700 | [diff] [blame] | 481 | self.dut.droid.wifiSetEnableAutoJoinWhenAssociated(1) |
| 482 | self.dut_ip = self.dut.droid.connectivityGetIPv4Addresses('wlan0')[0] |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 483 | if testcase_params['screen_on']: |
Omar El Ayach | 74f78dc | 2019-07-30 15:15:34 -0700 | [diff] [blame] | 484 | self.dut.wakeup_screen() |
| 485 | self.dut.droid.wakeLockAcquireBright() |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 486 | time.sleep(MED_SLEEP) |
| 487 | |
| 488 | def setup_roaming_test(self, testcase_params): |
| 489 | """Function to set up roaming test.""" |
| 490 | self.setup_ap(testcase_params) |
| 491 | self.setup_dut(testcase_params) |
| 492 | |
| 493 | def run_ping_test(self, testcase_params): |
| 494 | """Main function for ping roaming tests. |
| 495 | |
| 496 | Args: |
| 497 | testcase_params: dict including all test params encoded in test |
| 498 | name |
| 499 | Returns: |
| 500 | dict containing all test results and meta data |
| 501 | """ |
| 502 | self.log.info('Starting ping test.') |
Omar El Ayach | 45ea322 | 2020-12-21 22:00:49 -0800 | [diff] [blame^] | 503 | if testcase_params.get('ping_to_dut', False): |
| 504 | ping_future = wputils.get_ping_stats_nb( |
| 505 | self.remote_server, self.dut_ip, |
| 506 | testcase_params['atten_waveforms']['length'], |
| 507 | testcase_params['ping_interval'], 64) |
| 508 | else: |
| 509 | if testcase_params.get('lan_traffic_only', False): |
| 510 | ping_address = wputils.get_server_address( |
| 511 | self.remote_server, self.dut_ip, '255.255.255.0') |
| 512 | else: |
| 513 | ping_address = wputils.get_server_address( |
| 514 | self.remote_server, self.dut_ip, 'public') |
| 515 | ping_future = wputils.get_ping_stats_nb( |
| 516 | self.dut, ping_address, |
| 517 | testcase_params['atten_waveforms']['length'], |
| 518 | testcase_params['ping_interval'], 64) |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 519 | rssi_future = wputils.get_connected_rssi_nb( |
Omar El Ayach | 74f78dc | 2019-07-30 15:15:34 -0700 | [diff] [blame] | 520 | self.dut, |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 521 | int(testcase_params['atten_waveforms']['length'] / |
| 522 | testcase_params['rssi_polling_frequency']), |
| 523 | testcase_params['rssi_polling_frequency']) |
| 524 | self.run_attenuation_waveform(testcase_params) |
| 525 | return { |
Omar El Ayach | 7347770 | 2019-08-07 10:12:33 -0700 | [diff] [blame] | 526 | 'ping_result': ping_future.result().as_dict(), |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 527 | 'rssi_result': rssi_future.result(), |
Omar El Ayach | 45ea322 | 2020-12-21 22:00:49 -0800 | [diff] [blame^] | 528 | 'ap_settings': [ap.ap_settings for ap in self.access_points], |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 529 | } |
| 530 | |
| 531 | def run_iperf_test(self, testcase_params): |
| 532 | """Main function for iperf roaming tests. |
| 533 | |
| 534 | Args: |
| 535 | testcase_params: dict including all test params encoded in test |
| 536 | name |
| 537 | Returns: |
| 538 | result: dict containing all test results and meta data |
| 539 | """ |
| 540 | self.log.info('Starting iperf test.') |
| 541 | self.iperf_server.start(extra_args='-i {}'.format(IPERF_INTERVAL)) |
Omar El Ayach | 7347770 | 2019-08-07 10:12:33 -0700 | [diff] [blame] | 542 | self.dut_ip = self.dut.droid.connectivityGetIPv4Addresses('wlan0')[0] |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 543 | if isinstance(self.iperf_server, ipf.IPerfServerOverAdb): |
Omar El Ayach | 7347770 | 2019-08-07 10:12:33 -0700 | [diff] [blame] | 544 | iperf_server_address = self.dut_ip |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 545 | else: |
Omar El Ayach | 45ea322 | 2020-12-21 22:00:49 -0800 | [diff] [blame^] | 546 | if testcase_params.get('lan_traffic_only', False): |
| 547 | iperf_server_address = wputils.get_server_address( |
| 548 | self.remote_server, self.dut_ip, '255.255.255.0') |
| 549 | else: |
| 550 | iperf_server_address = wputils.get_server_address( |
| 551 | self.remote_server, self.dut_ip, 'public') |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 552 | iperf_args = '-i {} -t {} -J'.format( |
| 553 | IPERF_INTERVAL, testcase_params['atten_waveforms']['length']) |
| 554 | if not isinstance(self.iperf_server, ipf.IPerfServerOverAdb): |
| 555 | iperf_args = iperf_args + ' -R' |
| 556 | iperf_future = wputils.start_iperf_client_nb( |
| 557 | self.iperf_client, iperf_server_address, iperf_args, 0, |
| 558 | testcase_params['atten_waveforms']['length'] + MED_SLEEP) |
| 559 | rssi_future = wputils.get_connected_rssi_nb( |
Omar El Ayach | 74f78dc | 2019-07-30 15:15:34 -0700 | [diff] [blame] | 560 | self.dut, |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 561 | int(testcase_params['atten_waveforms']['length'] / |
| 562 | testcase_params['rssi_polling_frequency']), |
| 563 | testcase_params['rssi_polling_frequency']) |
| 564 | self.run_attenuation_waveform(testcase_params) |
| 565 | client_output_path = iperf_future.result() |
| 566 | server_output_path = self.iperf_server.stop() |
| 567 | if isinstance(self.iperf_server, ipf.IPerfServerOverAdb): |
| 568 | iperf_file = server_output_path |
| 569 | else: |
| 570 | iperf_file = client_output_path |
| 571 | iperf_result = ipf.IPerfResult(iperf_file) |
Omar El Ayach | 98be238 | 2019-09-04 15:11:50 -0700 | [diff] [blame] | 572 | instantaneous_rates = [ |
| 573 | rate * 8 * (1.024**2) for rate in iperf_result.instantaneous_rates |
| 574 | ] |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 575 | return { |
Omar El Ayach | 98be238 | 2019-09-04 15:11:50 -0700 | [diff] [blame] | 576 | 'throughput': instantaneous_rates, |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 577 | 'rssi_result': rssi_future.result(), |
Omar El Ayach | 45ea322 | 2020-12-21 22:00:49 -0800 | [diff] [blame^] | 578 | 'ap_settings': [ap.ap_settings for ap in self.access_points], |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 579 | } |
| 580 | |
| 581 | def run_attenuation_waveform(self, testcase_params, step_duration=1): |
| 582 | """Function that generates test params based on the test name. |
| 583 | |
| 584 | Args: |
| 585 | testcase_params: dict including all test params encoded in test |
| 586 | name |
| 587 | step_duration: int representing number of seconds to dwell on each |
| 588 | atten level |
| 589 | """ |
| 590 | atten_waveforms = testcase_params['atten_waveforms'] |
| 591 | for atten_idx in range(atten_waveforms['length']): |
| 592 | start_time = time.time() |
| 593 | for network, atten_waveform in atten_waveforms.items(): |
Omar El Ayach | 7347770 | 2019-08-07 10:12:33 -0700 | [diff] [blame] | 594 | for idx, atten in enumerate(self.attenuators): |
| 595 | nets_on_port = [ |
| 596 | item["network"] for item in self.rf_map_by_atten[idx] |
| 597 | ] |
| 598 | if network in nets_on_port: |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 599 | atten.set_atten(atten_waveform[atten_idx]) |
| 600 | measure_time = time.time() - start_time |
| 601 | time.sleep(step_duration - measure_time) |
| 602 | |
| 603 | def compile_atten_waveforms(self, waveform_params): |
| 604 | """Function to compile all attenuation waveforms for roaming test. |
| 605 | |
| 606 | Args: |
| 607 | waveform_params: list of dicts representing waveforms to generate |
| 608 | """ |
| 609 | atten_waveforms = {} |
Omar El Ayach | 45ea322 | 2020-12-21 22:00:49 -0800 | [diff] [blame^] | 610 | for network in self.main_network: |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 611 | atten_waveforms[network] = [] |
| 612 | |
| 613 | for waveform in waveform_params: |
Omar El Ayach | 45ea322 | 2020-12-21 22:00:49 -0800 | [diff] [blame^] | 614 | for network_name, network in self.main_network.items(): |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 615 | waveform_vector = self.gen_single_atten_waveform( |
Omar El Ayach | 45ea322 | 2020-12-21 22:00:49 -0800 | [diff] [blame^] | 616 | waveform[network['roaming_label']]) |
| 617 | atten_waveforms[network_name] += waveform_vector |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 618 | |
| 619 | waveform_lengths = { |
| 620 | len(atten_waveforms[network]) |
| 621 | for network in atten_waveforms.keys() |
| 622 | } |
| 623 | if len(waveform_lengths) != 1: |
| 624 | raise ValueError( |
| 625 | 'Attenuation waveform length should be equal for all networks.' |
| 626 | ) |
| 627 | else: |
| 628 | atten_waveforms['length'] = waveform_lengths.pop() |
| 629 | return atten_waveforms |
| 630 | |
| 631 | def gen_single_atten_waveform(self, waveform_params): |
| 632 | """Function to generate a single attenuation waveform for roaming test. |
| 633 | |
| 634 | Args: |
| 635 | waveform_params: dict representing waveform to generate |
| 636 | """ |
| 637 | waveform_vector = [] |
| 638 | for section in range(len(waveform_params['atten_levels']) - 1): |
| 639 | section_limits = waveform_params['atten_levels'][section:section + |
| 640 | 2] |
| 641 | up_down = (1 - 2 * (section_limits[1] < section_limits[0])) |
| 642 | temp_section = list( |
| 643 | range(section_limits[0], section_limits[1] + up_down, |
| 644 | up_down * waveform_params['step_size'])) |
| 645 | temp_section = [ |
| 646 | val for val in temp_section |
| 647 | for _ in range(waveform_params['step_duration']) |
| 648 | ] |
| 649 | waveform_vector += temp_section |
| 650 | waveform_vector *= waveform_params['repetitions'] |
| 651 | return waveform_vector |
| 652 | |
Omar El Ayach | 7347770 | 2019-08-07 10:12:33 -0700 | [diff] [blame] | 653 | def parse_test_params(self, testcase_params): |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 654 | """Function that generates test params based on the test name. |
| 655 | |
| 656 | Args: |
| 657 | test_name: current test name |
| 658 | Returns: |
| 659 | testcase_params: dict including all test params encoded in test |
| 660 | name |
| 661 | """ |
Omar El Ayach | 7347770 | 2019-08-07 10:12:33 -0700 | [diff] [blame] | 662 | if testcase_params["waveform_type"] == 'smooth': |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 663 | testcase_params[ |
| 664 | 'roaming_waveforms_params'] = self.testclass_params[ |
| 665 | 'smooth_roaming_waveforms'] |
Omar El Ayach | 7347770 | 2019-08-07 10:12:33 -0700 | [diff] [blame] | 666 | elif testcase_params["waveform_type"] == 'failover': |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 667 | testcase_params[ |
| 668 | 'roaming_waveforms_params'] = self.testclass_params[ |
| 669 | 'failover_roaming_waveforms'] |
Omar El Ayach | 7347770 | 2019-08-07 10:12:33 -0700 | [diff] [blame] | 670 | elif testcase_params["waveform_type"] == 'consistency': |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 671 | testcase_params[ |
| 672 | 'roaming_waveforms_params'] = self.testclass_params[ |
| 673 | 'consistency_waveforms'] |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 674 | return testcase_params |
| 675 | |
Omar El Ayach | 7347770 | 2019-08-07 10:12:33 -0700 | [diff] [blame] | 676 | def _test_traffic_continuity(self, testcase_params): |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 677 | """Test function for traffic continuity""" |
| 678 | # Compile test parameters from config and test name |
Omar El Ayach | 7347770 | 2019-08-07 10:12:33 -0700 | [diff] [blame] | 679 | testcase_params = self.parse_test_params(testcase_params) |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 680 | testcase_params.update(self.testclass_params) |
| 681 | testcase_params['atten_waveforms'] = self.compile_atten_waveforms( |
| 682 | testcase_params['roaming_waveforms_params']) |
| 683 | # Run traffic test |
| 684 | self.setup_roaming_test(testcase_params) |
| 685 | if testcase_params['traffic_type'] == 'iperf': |
| 686 | result = self.run_iperf_test(testcase_params) |
| 687 | elif testcase_params['traffic_type'] == 'ping': |
| 688 | result = self.run_ping_test(testcase_params) |
| 689 | # Postprocess results |
| 690 | self.process_traffic_continuity_results(testcase_params, result) |
| 691 | self.pass_fail_traffic_continuity(result) |
| 692 | |
Omar El Ayach | 7347770 | 2019-08-07 10:12:33 -0700 | [diff] [blame] | 693 | def _test_roam_consistency(self, testcase_params): |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 694 | """Test function for roaming consistency""" |
Omar El Ayach | 7347770 | 2019-08-07 10:12:33 -0700 | [diff] [blame] | 695 | testcase_params = self.parse_test_params(testcase_params) |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 696 | testcase_params.update(self.testclass_params) |
| 697 | # Run traffic test |
| 698 | secondary_attens = range( |
| 699 | self.testclass_params['consistency_waveforms']['secondary_loop'] |
| 700 | ['atten_levels'][0], self.testclass_params['consistency_waveforms'] |
| 701 | ['secondary_loop']['atten_levels'][1], |
| 702 | self.testclass_params['consistency_waveforms']['secondary_loop'] |
| 703 | ['step_size']) |
| 704 | results = collections.OrderedDict() |
| 705 | for secondary_atten in secondary_attens: |
| 706 | primary_waveform = self.gen_single_atten_waveform( |
| 707 | testcase_params['roaming_waveforms_params']['primary_sweep']) |
| 708 | secondary_waveform_params = { |
| 709 | 'atten_levels': [secondary_atten, secondary_atten], |
| 710 | 'step_size': 1, |
| 711 | 'step_duration': len(primary_waveform), |
| 712 | 'repetitions': 1 |
| 713 | } |
| 714 | secondary_waveform = self.gen_single_atten_waveform( |
| 715 | secondary_waveform_params) |
| 716 | testcase_params['atten_waveforms'] = { |
| 717 | 'length': len(primary_waveform) |
| 718 | } |
| 719 | for network_key, network_info in self.main_network.items(): |
| 720 | if 'primary' in network_info['roaming_label']: |
| 721 | testcase_params['atten_waveforms'][ |
| 722 | network_key] = primary_waveform |
| 723 | else: |
| 724 | testcase_params['atten_waveforms'][ |
| 725 | network_key] = secondary_waveform |
| 726 | results[secondary_atten] = [] |
| 727 | for run in range(self.testclass_params['consistency_num_runs']): |
| 728 | self.setup_roaming_test(testcase_params) |
| 729 | results[secondary_atten].append( |
| 730 | self.run_ping_test(testcase_params)) |
| 731 | # Postprocess results |
| 732 | self.process_consistency_results(testcase_params, results) |
| 733 | self.pass_fail_roaming_consistency(results) |
| 734 | |
| 735 | def test_consistency_roaming_screen_on_ping(self): |
Omar El Ayach | 7347770 | 2019-08-07 10:12:33 -0700 | [diff] [blame] | 736 | testcase_params = { |
| 737 | "waveform_type": "consistency", |
| 738 | "screen_on": 1, |
| 739 | "traffic_type": "ping" |
| 740 | } |
| 741 | self._test_roam_consistency(testcase_params) |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 742 | |
| 743 | def test_smooth_roaming_screen_on_ping_continuity(self): |
Omar El Ayach | 7347770 | 2019-08-07 10:12:33 -0700 | [diff] [blame] | 744 | testcase_params = { |
| 745 | "waveform_type": "smooth", |
| 746 | "screen_on": 1, |
| 747 | "traffic_type": "ping" |
| 748 | } |
| 749 | self._test_traffic_continuity(testcase_params) |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 750 | |
| 751 | def test_smooth_roaming_screen_on_iperf_continuity(self): |
Omar El Ayach | 7347770 | 2019-08-07 10:12:33 -0700 | [diff] [blame] | 752 | testcase_params = { |
| 753 | "waveform_type": "smooth", |
| 754 | "screen_on": 1, |
| 755 | "traffic_type": "iperf" |
| 756 | } |
| 757 | self._test_traffic_continuity(testcase_params) |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 758 | |
| 759 | def test_failover_roaming_screen_on_ping_continuity(self): |
Omar El Ayach | 7347770 | 2019-08-07 10:12:33 -0700 | [diff] [blame] | 760 | testcase_params = { |
| 761 | "waveform_type": "failover", |
| 762 | "screen_on": 1, |
| 763 | "traffic_type": "ping" |
| 764 | } |
| 765 | self._test_traffic_continuity(testcase_params) |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 766 | |
| 767 | def test_failover_roaming_screen_on_iperf_continuity(self): |
Omar El Ayach | 7347770 | 2019-08-07 10:12:33 -0700 | [diff] [blame] | 768 | testcase_params = { |
| 769 | "waveform_type": "failover", |
| 770 | "screen_on": 1, |
| 771 | "traffic_type": "iperf" |
| 772 | } |
| 773 | self._test_traffic_continuity(testcase_params) |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 774 | |
| 775 | def test_smooth_roaming_screen_off_ping_continuity(self): |
Omar El Ayach | 7347770 | 2019-08-07 10:12:33 -0700 | [diff] [blame] | 776 | testcase_params = { |
| 777 | "waveform_type": "smooth", |
| 778 | "screen_on": 0, |
| 779 | "traffic_type": "ping" |
| 780 | } |
| 781 | self._test_traffic_continuity(testcase_params) |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 782 | |
| 783 | def test_smooth_roaming_screen_off_iperf_continuity(self): |
Omar El Ayach | 7347770 | 2019-08-07 10:12:33 -0700 | [diff] [blame] | 784 | testcase_params = { |
| 785 | "waveform_type": "smooth", |
| 786 | "screen_on": 0, |
| 787 | "traffic_type": "iperf" |
| 788 | } |
| 789 | self._test_traffic_continuity(testcase_params) |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 790 | |
| 791 | def test_failover_roaming_screen_off_ping_continuity(self): |
Omar El Ayach | 7347770 | 2019-08-07 10:12:33 -0700 | [diff] [blame] | 792 | testcase_params = { |
| 793 | "waveform_type": "failover", |
| 794 | "screen_on": 0, |
| 795 | "traffic_type": "ping" |
| 796 | } |
| 797 | self._test_traffic_continuity(testcase_params) |
Omar El Ayach | b503ae8 | 2019-02-13 09:36:36 -0800 | [diff] [blame] | 798 | |
| 799 | def test_failover_roaming_screen_off_iperf_continuity(self): |
Omar El Ayach | 7347770 | 2019-08-07 10:12:33 -0700 | [diff] [blame] | 800 | testcase_params = { |
| 801 | "waveform_type": "failover", |
| 802 | "screen_on": 0, |
| 803 | "traffic_type": "iperf" |
| 804 | } |
| 805 | self._test_traffic_continuity(testcase_params) |