blob: d7ec579bedcea8cb5f776d951d0d70108402948a [file] [log] [blame]
# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
from autotest_lib.client.common_lib import error
from autotest_lib.client.common_lib.cros.network import xmlrpc_datatypes
from autotest_lib.client.common_lib.cros.network import xmlrpc_security_types
from autotest_lib.server.cros.network import hostap_config
from autotest_lib.server.cros.network import wifi_cell_test_base
class ProfileRemovingContext(object):
"""Creates and pushes a profile that is guaranteed to be removed."""
@property
def profile_name(self):
"""@return string: name of profile created and pushed."""
return self._profile_name
def __init__(self, wifi_client, profile_name='always_removed'):
self._wifi_client = wifi_client
self._profile_name = profile_name
def __enter__(self):
if not all([self._wifi_client.shill.create_profile(self.profile_name),
self._wifi_client.shill.push_profile(self.profile_name)]):
raise error.TestFail('Failed to create/push profile %s' %
self.profile_name)
return self
def __exit__(self, exc_type, exc_value, traceback):
# Ignore pop errors in case the test popped it on its own
self._wifi_client.shill.pop_profile(self.profile_name)
if not self._wifi_client.shill.remove_profile(self.profile_name):
raise error.TestFail('Failed to remove profile %s.' %
self.profile_name)
class network_WiFi_ProfileBasic(wifi_cell_test_base.WiFiCellTestBase):
"""Tests that credentials are stored in profiles."""
version = 1
CHANNEL_NUMBER = 1
STATE_TRANSITION_TIMEOUT_SECONDS = 20
def _assert_state_transition(self, ssid, states):
"""Raise an error if a WiFi service doesn't transition to |states|.
@param ssid: string ssid of service.
@param states: list of string states to wait for.
"""
result = self.context.client.wait_for_service_states(
ssid, states,
timeout_seconds=self.STATE_TRANSITION_TIMEOUT_SECONDS)
success, state, duration_seconds = result
if not success:
raise error.TestFail('Timed out waiting for states: %r in %f '
'seconds. Ended in %s' %
(states, duration_seconds, state))
def run_once(self):
"""Body of the test."""
self.context.client.shill.clean_profiles()
wep_config = xmlrpc_security_types.WEPConfig(
wep_keys=['abcde', 'fghij', 'klmno', 'pqrst'])
ap_config0 = hostap_config.HostapConfig(
channel=self.CHANNEL_NUMBER, security_config=wep_config)
ap_config1 = hostap_config.HostapConfig(
channel=self.CHANNEL_NUMBER, security_config=wep_config)
with ProfileRemovingContext(self.context.client,
profile_name='bottom') as bottom:
self.context.configure(ap_config0)
client_config0 = xmlrpc_datatypes.AssociationParameters(
security_config=ap_config0.security_config,
ssid=self.context.router.get_ssid())
self.context.assert_connect_wifi(client_config0)
self.context.assert_ping_from_dut(ap_num=0)
# Check that popping a profile causes a loss of credentials and a
# disconnect.
if not self.context.client.shill.pop_profile(bottom.profile_name):
raise error.TestFail('Failed to pop profile %s.' %
bottom.profile_name)
self._assert_state_transition(client_config0.ssid, ['idle'])
# Check that pushing a profile causes credentials to reappear.
if not self.context.client.shill.push_profile(bottom.profile_name):
raise error.TestFail('Failed to push profile %s.' %
bottom.profile_name)
self._assert_state_transition(client_config0.ssid,
self.context.client.CONNECTED_STATES)
# Explicitly disconnect from the AP.
self.context.client.shill.disconnect(client_config0.ssid)
self._assert_state_transition(client_config0.ssid, ['idle'])
with ProfileRemovingContext(self.context.client,
profile_name='top') as top:
# Changes to the profile stack should clear the "explicitly
# disconnected" flag on all services. This should cause shill
# to re-connect to the AP.
self._assert_state_transition(client_config0.ssid,
self.context.client.CONNECTED_STATES)
self.context.configure(ap_config1, multi_interface=True)
client_config1 = xmlrpc_datatypes.AssociationParameters(
security_config=ap_config1.security_config,
ssid=self.context.router.get_ssid(instance=1))
self.context.assert_connect_wifi(client_config1)
self.context.assert_ping_from_dut(ap_num=1)
# Check that deleting an entry also causes a disconnect and
# autoconect to a previously remembered service.
if not self.context.client.shill.delete_entries_for_ssid(
client_config1.ssid):
raise error.TestFail('Failed to delete profile entry for '
'%s' % client_config1.ssid)
self._assert_state_transition(client_config1.ssid, ['idle'])
self._assert_state_transition(client_config0.ssid,
self.context.client.CONNECTED_STATES)
# Verify that the same sort of thing happens when we pop
# a profile on top of another one.
self.context.assert_connect_wifi(client_config1)
self.context.assert_ping_from_dut(ap_num=1)
if not self.context.client.shill.pop_profile(top.profile_name):
raise error.TestFail('Failed to pop profile %s.' %
top.profile_name)
self._assert_state_transition(client_config1.ssid, ['idle'])
self._assert_state_transition(client_config0.ssid,
self.context.client.CONNECTED_STATES)
# Re-push the top profile.
if not self.context.client.shill.push_profile(top.profile_name):
raise error.TestFail('Failed to push profile %s.' %
top.profile_name)
# Explicitly disconnect from the AP.
self.context.client.shill.disconnect(client_config0.ssid)
self._assert_state_transition(client_config0.ssid, ['idle'])
# Verify that popping a profile -- even one which does not
# affect the service profile -- returns explicitly disconnected
# services back into the pool of connectable services.
if not self.context.client.shill.pop_profile(top.profile_name):
raise error.TestFail('Failed to pop profile %s.' %
top.profile_name)
# A change to the profile stack should have caused us to
# reconnect to the service, since the "explicitly disconnected"
# flag will be removed.
self._assert_state_transition(client_config0.ssid,
self.context.client.CONNECTED_STATES)