Home | History | Annotate | Download | only in network_WiFi_AssocConfigPerformance
      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