Home | History | Annotate | Download | only in network_WiFi_VerifyRouter
      1 # Copyright (c) 2013 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 import site_linux_system
     11 from autotest_lib.server.cros.network import hostap_config
     12 from autotest_lib.server.cros.network import wifi_cell_test_base
     13 
     14 
     15 class network_WiFi_VerifyRouter(wifi_cell_test_base.WiFiCellTestBase):
     16     """Test that a dual radio router can use both radios."""
     17     version = 1
     18     MAX_ASSOCIATION_RETRIES = 8  # Super lucky number.  Not science.
     19 
     20 
     21     def _connect(self, wifi_params):
     22         assoc_result = xmlrpc_datatypes.deserialize(
     23                 self.context.client.shill.connect_wifi(wifi_params))
     24         logging.info('Finished connection attempt to %s with times: '
     25                      'discovery=%.2f, association=%.2f, configuration=%.2f.',
     26                      wifi_params.ssid,
     27                      assoc_result.discovery_time,
     28                      assoc_result.association_time,
     29                      assoc_result.configuration_time)
     30         return assoc_result.success
     31 
     32 
     33     def _antenna_test(self, bitmap, channel):
     34         """Test that we can connect on |channel|, with given antenna |bitmap|.
     35 
     36         Sets up two radios on |channel|, configures both radios with the
     37         given antenna |bitmap|, and then verifies that a client can connect
     38         to the AP on each radio.
     39 
     40         Why do we run the two radios concurrently, instead of iterating over
     41         them? That's simply because our lower-layer code doesn't provide an
     42         interface for specifiying which PHY to run an AP on.
     43 
     44         To work around the API limitaiton, we bring up multiple APs, and let
     45         the lower-layer code spread them across radios. For stumpy/panther,
     46         this works in an obvious way. That is, each call to this method
     47         exercises phy0 and phy1.
     48 
     49         For whirlwind, we still cover all radios, but in a less obvious way.
     50         Calls with a 2.4 GHz channel exercise phy0 and phy2, while calls
     51         with a 5 GHz channel exercise phy1 and phy2.
     52 
     53         @param bitmap: int bitmask controlling which antennas to enable.
     54         @param channel: int Wifi channel to conduct test on
     55 
     56         """
     57         # Antenna can only be configured when the wireless interface is down.
     58         self.context.router.deconfig()
     59         # Set the bitmasks to both antennas on before turning one off.
     60         self.context.router.disable_antennas_except(3)
     61         # This seems to increase the probability that our association
     62         # attempts pass.  It is the very definition of a dark incantation.
     63         time.sleep(5)
     64         if bitmap != 3:
     65             self.context.router.disable_antennas_except(bitmap)
     66         # Setup two APs on |channel|. configure() will spread these across
     67         # radios.
     68         n_mode = hostap_config.HostapConfig.MODE_11N_MIXED
     69         ap_config = hostap_config.HostapConfig(channel=channel, mode=n_mode)
     70         self.context.configure(ap_config)
     71         self.context.configure(ap_config, multi_interface=True)
     72         failures = []
     73         # Verify connectivity to both APs. As the APs are spread
     74         # across radios, this exercises multiple radios.
     75         for instance in range(2):
     76             context_message = ('bitmap=%d, ap_instance=%d, channel=%d' %
     77                                (bitmap, instance, channel))
     78             logging.info('Connecting to AP with settings %s.',
     79                          context_message)
     80             client_conf = xmlrpc_datatypes.AssociationParameters(
     81                     ssid=self.context.router.get_ssid(instance=instance))
     82             if self._connect(client_conf):
     83                 signal_level = self.context.client.wifi_signal_level
     84                 logging.info('Signal level for AP %d with bitmap %d is %d',
     85                              instance, bitmap, signal_level)
     86                 self.write_perf_keyval(
     87                         {'signal_for_ap_%d_bm_%d_ch_%d' %
     88                                  (instance, bitmap, channel):
     89                          signal_level})
     90             else:
     91                 failures.append(context_message)
     92             # Don't automatically reconnect to this AP.
     93             self.context.client.shill.disconnect(
     94                     self.context.router.get_ssid(instance=instance))
     95         return failures
     96 
     97 
     98     def cleanup(self):
     99         """Clean up after the test is completed
    100 
    101         Perform additional cleanups after the test, the important thing is
    102         to re-enable all antennas.
    103         """
    104         self.context.router.deconfig()
    105         self.context.router.enable_all_antennas()
    106         super(network_WiFi_VerifyRouter, self).cleanup()
    107 
    108 
    109     def run_once(self):
    110         """Verify that all radios on this router are functional."""
    111         self.context.router.require_capabilities(
    112                 [site_linux_system.LinuxSystem.CAPABILITY_MULTI_AP_SAME_BAND])
    113 
    114         all_failures = []
    115         # Run antenna test for 2GHz band and 5GHz band
    116         for channel in (6, 149):
    117             # First connect with both antennas enabled. Then connect with just
    118             # one antenna enabled at a time.
    119             for bitmap in (3, 1, 2):
    120                 failures = set()
    121                 for attempt in range(self.MAX_ASSOCIATION_RETRIES):
    122                     new_failures = self._antenna_test(bitmap, channel)
    123                     if not new_failures:
    124                         break
    125                     failures.update(new_failures)
    126                 else:
    127                     all_failures += failures
    128 
    129         if all_failures:
    130             failure_message = ', '.join(
    131                     ['(' + message + ')' for message in all_failures])
    132             raise error.TestFail('Failed to connect when %s.' % failure_message)
    133