1 # Copyright 2018 The Chromium OS Authors. All rights reserved. 2 # Use of this source code is governed by a BSD-style license that can be 3 # found in the LICENSE file. 4 5 import logging 6 import time 7 8 from autotest_lib.client.common_lib import error 9 from autotest_lib.client.common_lib.cros.network import xmlrpc_datatypes 10 from autotest_lib.server.cros.network import wifi_cell_test_base 11 12 13 class network_WiFi_AssocConfigPerformance(wifi_cell_test_base.WiFiCellTestBase): 14 """Test for performance of discovery, association, and configuration, and 15 that WiFi comes back up properly on every attempt. 16 Measure and report the performance of the suspend/resume cycle. 17 """ 18 version = 1 19 20 21 def parse_additional_arguments(self, commandline_args, additional_params): 22 """Hook into super class to take control files parameters. 23 24 @param commandline_args dict of parsed parameters from the autotest. 25 @param additional_params list of HostapConfig objects. 26 """ 27 self._ap_configs = additional_params 28 29 30 def _report_perf(self, descript, perf_times, graph_description): 31 """Output a summary of performance to logs and to perf value json 32 33 @param descript: string description of the performance numbers, 34 labelling which operation they describe 35 @param perf_times: list of float values representing how long the 36 specified operation took, for each iteration 37 """ 38 perf_dict = {descript + '_fastest': min(perf_times), 39 descript + '_slowest': max(perf_times), 40 descript + '_average': sum(perf_times) / len(perf_times)} 41 42 logging.info('Operation: %s', descript) 43 44 for key in perf_dict: 45 self.output_perf_value( 46 description=key, 47 value=perf_dict[key], 48 units='seconds', 49 higher_is_better=False, 50 graph=graph_description) 51 logging.info('%s: %s', key, perf_dict[key]) 52 53 54 def _connect_disconnect_performance(self, ap_config): 55 """Connect to the router, and disconnect, fully removing entries 56 for for the router's ssid. 57 58 @param ap_config: the AP configuration that is being used. 59 60 @returns: serialized AssociationResult from xmlrpc_datatypes 61 """ 62 # connect to router 63 self.context.configure(ap_config) 64 client_conf = xmlrpc_datatypes.AssociationParameters() 65 client_conf.ssid = self.context.router.get_ssid() 66 assoc_result = self.context.client.shill.connect_wifi(client_conf) 67 # ensure successful connection 68 if assoc_result['success']: 69 logging.info('WiFi connected') 70 else: 71 raise error.TestFail(assoc_result['failure_reason']) 72 # Clean up router and client state for the next run. 73 self.context.client.shill.disconnect(client_conf.ssid) 74 self.context.router.deconfig() 75 return assoc_result 76 77 78 def _suspend_resume_performance(self, ap_config, suspend_duration): 79 """Test that the DUT can be placed in suspend and then resume that 80 WiFi connection, and report the performance of that resume. 81 82 @param ap_config: the AP configuration that is being used. 83 @param suspend_duration: integer value for how long to suspend. 84 85 @returns dictionary with two keys: 86 connect_time: resume time reported, how long it took for the 87 service state to reach connected again 88 total_time: total time reported, how long to connect on resume 89 as well as perform other checks on the 90 frequency and subnet, and ping the router 91 """ 92 self.context.configure(ap_config) 93 client_conf = xmlrpc_datatypes.AssociationParameters() 94 client_conf.ssid = self.context.router.get_ssid() 95 # need to connect before suspending 96 assoc_result = self.context.client.shill.connect_wifi(client_conf) 97 if assoc_result['success']: 98 logging.info('Wifi connected') 99 else: 100 raise error.TestFail(assoc_result['failure_reason']) 101 102 # this suspend is blocking 103 self.context.client.do_suspend(suspend_duration) 104 start_time = time.time() 105 # now wait for the connection to resume after the suspend 106 assoc_result = self.context.wait_for_connection(client_conf.ssid) 107 # check for success of the connection 108 if assoc_result.state not in self.context.client.CONNECTED_STATES: 109 raise error.TestFail('WiFi failed to resume connection') 110 111 total_time = time.time() - start_time 112 timings = {'connect_time': assoc_result.time, 'total_time': total_time} 113 114 # Clean up router and client state for the next run. 115 self.context.client.shill.disconnect(client_conf.ssid) 116 self.context.router.deconfig() 117 return timings 118 119 120 def run_once(self, num_iterations=1, suspend_duration=10): 121 """Body of the test.""" 122 123 # Measure performance for each HostapConfig 124 for ap_config in self._ap_configs: 125 # need to track the performance numbers for each operation 126 connect_disconnect = [] 127 suspend_resume = [] 128 for _ in range(0, num_iterations): 129 connect_disconnect.append( 130 self._connect_disconnect_performance(ap_config)) 131 for _ in range(0, num_iterations): 132 suspend_resume.append(self._suspend_resume_performance( 133 ap_config, suspend_duration)) 134 135 graph_descript = ap_config.perf_loggable_description 136 logging.info('Configuration: %s', graph_descript) 137 138 # process reported performance to group the numbers by step 139 discovery = [perf['discovery_time'] for perf in connect_disconnect] 140 assoc = [perf['association_time'] for perf in connect_disconnect] 141 config = [perf['configuration_time'] for perf in connect_disconnect] 142 143 # report the performance from the connect_disconnect 144 prefix = 'connect_disconnect' 145 self._report_perf( 146 descript=prefix + '_discovery', 147 perf_times=discovery, 148 graph_description=graph_descript) 149 self._report_perf( 150 descript=prefix + '_association', 151 perf_times=assoc, 152 graph_description=graph_descript) 153 self._report_perf( 154 descript=prefix + '_configuration', 155 perf_times=config, 156 graph_description=graph_descript) 157 158 # process reported performance to group the numbers by step 159 # suspend_resume has different keys than connect_disconnect 160 connect_times = [perf['connect_time'] for perf in suspend_resume] 161 total_times = [perf['total_time'] for perf in suspend_resume] 162 163 # report the performance from suspend_resume 164 prefix = 'suspend_resume' 165 self._report_perf( 166 descript=prefix + '_connection', 167 perf_times=connect_times, 168 graph_description=graph_descript) 169 self._report_perf( 170 descript=prefix + '_total', 171 perf_times=total_times, 172 graph_description=graph_descript) 173 174 175