Home | History | Annotate | Download | only in network_WiFi_ProfileBasic
      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 from autotest_lib.client.common_lib import error
      6 from autotest_lib.client.common_lib.cros.network import xmlrpc_datatypes
      7 from autotest_lib.client.common_lib.cros.network import xmlrpc_security_types
      8 from autotest_lib.server.cros.network import hostap_config
      9 from autotest_lib.server.cros.network import wifi_cell_test_base
     10 
     11 
     12 class ProfileRemovingContext(object):
     13     """Creates and pushes a profile that is guaranteed to be removed."""
     14 
     15     @property
     16     def profile_name(self):
     17         """@return string: name of profile created and pushed."""
     18         return self._profile_name
     19 
     20 
     21     def __init__(self, wifi_client, profile_name='always_removed'):
     22         self._wifi_client = wifi_client
     23         self._profile_name = profile_name
     24 
     25 
     26     def __enter__(self):
     27         if not all([self._wifi_client.shill.create_profile(self.profile_name),
     28                     self._wifi_client.shill.push_profile(self.profile_name)]):
     29             raise error.TestFail('Failed to create/push profile %s' %
     30                                  self.profile_name)
     31         return self
     32 
     33 
     34     def __exit__(self, exc_type, exc_value, traceback):
     35         # Ignore pop errors in case the test popped it on its own
     36         self._wifi_client.shill.pop_profile(self.profile_name)
     37         if not self._wifi_client.shill.remove_profile(self.profile_name):
     38             raise error.TestFail('Failed to remove profile %s.' %
     39                                  self.profile_name)
     40 
     41 
     42 class network_WiFi_ProfileBasic(wifi_cell_test_base.WiFiCellTestBase):
     43     """Tests that credentials are stored in profiles."""
     44 
     45     version = 1
     46 
     47     CHANNEL_NUMBER = 1
     48     STATE_TRANSITION_TIMEOUT_SECONDS = 20
     49 
     50 
     51     def _assert_state_transition(self, ssid, states):
     52         """Raise an error if a WiFi service doesn't transition to |states|.
     53 
     54         @param ssid: string ssid of service.
     55         @param states: list of string states to wait for.
     56 
     57         """
     58         result = self.context.client.wait_for_service_states(
     59                 ssid, states,
     60                 timeout_seconds=self.STATE_TRANSITION_TIMEOUT_SECONDS)
     61 
     62         success, state, duration_seconds = result
     63         if not success:
     64             raise error.TestFail('Timed out waiting for states: %r in %f '
     65                                  'seconds.  Ended in %s' %
     66                                  (states, duration_seconds, state))
     67 
     68 
     69     def run_once(self):
     70         """Body of the test."""
     71         self.context.client.shill.clean_profiles()
     72         wep_config = xmlrpc_security_types.WEPConfig(
     73                 wep_keys=['abcde', 'fghij', 'klmno', 'pqrst'])
     74         ap_config0 = hostap_config.HostapConfig(
     75                 channel=self.CHANNEL_NUMBER, security_config=wep_config)
     76         ap_config1 = hostap_config.HostapConfig(
     77                 channel=self.CHANNEL_NUMBER, security_config=wep_config)
     78         with ProfileRemovingContext(self.context.client,
     79                                     profile_name='bottom') as bottom:
     80             self.context.configure(ap_config0)
     81             client_config0 = xmlrpc_datatypes.AssociationParameters(
     82                     security_config=ap_config0.security_config,
     83                     ssid=self.context.router.get_ssid())
     84             self.context.assert_connect_wifi(client_config0)
     85             self.context.assert_ping_from_dut(ap_num=0)
     86             # Check that popping a profile causes a loss of credentials and a
     87             # disconnect.
     88             if not self.context.client.shill.pop_profile(bottom.profile_name):
     89                 raise error.TestFail('Failed to pop profile %s.' %
     90                                       bottom.profile_name)
     91 
     92             self._assert_state_transition(client_config0.ssid, ['idle'])
     93             # Check that pushing a profile causes credentials to reappear.
     94             if not self.context.client.shill.push_profile(bottom.profile_name):
     95                 raise error.TestFail('Failed to push profile %s.' %
     96                                       bottom.profile_name)
     97 
     98             self._assert_state_transition(client_config0.ssid,
     99                                           ['ready', 'portal', 'online'])
    100 
    101             # Explicitly disconnect from the AP.
    102             self.context.client.shill.disconnect(client_config0.ssid)
    103             self._assert_state_transition(client_config0.ssid, ['idle'])
    104 
    105             with ProfileRemovingContext(self.context.client,
    106                                         profile_name='top') as top:
    107                 # Changes to the profile stack should clear the "explicitly
    108                 # disconnected" flag on all services.  This should cause shill
    109                 # to re-connect to the AP.
    110                 self._assert_state_transition(client_config0.ssid,
    111                                               ['ready', 'portal', 'online'])
    112 
    113                 self.context.configure(ap_config1, multi_interface=True)
    114                 client_config1 = xmlrpc_datatypes.AssociationParameters(
    115                         security_config=ap_config1.security_config,
    116                         ssid=self.context.router.get_ssid(instance=1))
    117                 self.context.assert_connect_wifi(client_config1)
    118                 self.context.assert_ping_from_dut(ap_num=1)
    119                 # Check that deleting an entry also causes a disconnect and
    120                 # autoconect to a previously remembered service.
    121                 if not self.context.client.shill.delete_entries_for_ssid(
    122                         client_config1.ssid):
    123                     raise error.TestFail('Failed to delete profile entry for '
    124                                          '%s' % client_config1.ssid)
    125 
    126                 self._assert_state_transition(client_config1.ssid, ['idle'])
    127                 self._assert_state_transition(client_config0.ssid,
    128                                               ['ready', 'portal', 'online'])
    129                 # Verify that the same sort of thing happens when we pop
    130                 # a profile on top of another one.
    131                 self.context.assert_connect_wifi(client_config1)
    132                 self.context.assert_ping_from_dut(ap_num=1)
    133                 if not self.context.client.shill.pop_profile(top.profile_name):
    134                     raise error.TestFail('Failed to pop profile %s.' %
    135                                           top.profile_name)
    136                 self._assert_state_transition(client_config1.ssid, ['idle'])
    137                 self._assert_state_transition(client_config0.ssid,
    138                                               ['ready', 'portal', 'online'])
    139 
    140                 # Re-push the top profile.
    141                 if not self.context.client.shill.push_profile(top.profile_name):
    142                     raise error.TestFail('Failed to push profile %s.' %
    143                                           top.profile_name)
    144 
    145                 # Explicitly disconnect from the AP.
    146                 self.context.client.shill.disconnect(client_config0.ssid)
    147                 self._assert_state_transition(client_config0.ssid, ['idle'])
    148 
    149                 # Verify that popping a profile -- even one which does not
    150                 # affect the service profile -- returns explicitly disconnected
    151                 # services back into the pool of connectable services.
    152                 if not self.context.client.shill.pop_profile(top.profile_name):
    153                     raise error.TestFail('Failed to pop profile %s.' %
    154                                           top.profile_name)
    155 
    156                 # A change to the profile stack should have caused us to
    157                 # reconnect to the service, since the "explicitly disconnected"
    158                 # flag will be removed.
    159                 self._assert_state_transition(client_config0.ssid,
    160                                               ['ready', 'portal', 'online'])
    161