blob: e5e90e06b5632e73172808d1d04c8309a8a54d1c [file] [log] [blame]
# Copyright 2018 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.
import logging
from collections import namedtuple
from autotest_lib.client.bin import utils
from autotest_lib.client.common_lib import error
from autotest_lib.client.cros.networking.chrome_testing \
import chrome_networking_test_context as cntc
from autotest_lib.client.cros.networking.chrome_testing \
import chrome_networking_test_api as cnta
NETWORK_TEST_EXTENSION_PATH = cntc.NETWORK_TEST_EXTENSION_PATH
def create_network_policy(ssid, security=None, eap=None, password=None,
identity=None, autoconnect=None, ca_cert=None):
"""
Generate a network configuration policy dictionary for WiFi networks.
@param ssid: Service set identifier for wireless local area network.
@param security: Security of network. Options are:
'None', 'WEP-PSK', 'WEP-8021X', 'WPA-PSK', and 'WPA-EAP'.
@param eap: EAP type, required if security is 'WEP-8021X' or 'WPA-EAP'.
@param identity: Username, if the network type requires it.
@param password: Password, if the network type requires it.
@param ca_cert: CA certificate in PEM format. Required
for EAP networks.
@param autoconnect: True iff network policy should autoconnect.
@returns conf: A dictionary in the format suitable to setting as a network
policy.
"""
if security is None:
security = 'None'
conf = {
'NetworkConfigurations': [
{'GUID': 'policy_WiFi* Test',
'Name': ssid,
'Type': 'WiFi',
'WiFi': {
'SSID': ssid,
'Security': security}
}
],
}
if ca_cert is not None:
conf['Certificates'] = [
{'GUID': 'CA_CERT',
'Type': 'Authority',
'X509': ca_cert}
]
wifi_conf = conf['NetworkConfigurations'][0]['WiFi']
if autoconnect is not None:
wifi_conf['AutoConnect'] = autoconnect
if security == 'WPA-PSK':
if password is None:
raise error.TestError('Password is required for WPA-PSK networks.')
wifi_conf['Passphrase'] = password
if eap is not None:
eap_conf = {
'Outer': eap,
'Identity': identity,
'ServerCARefs': ['CA_CERT']
}
if password is not None:
eap_conf['Password'] = password
if eap == 'EAP-TLS':
eap_conf['ClientCertType'] = 'Pattern'
eap_conf['ClientCertPattern'] = {
'IssuerCARef': ['CA_CERT']
}
wifi_conf['EAP'] = eap_conf
return conf
class ChromeEnterpriseNetworkContext(object):
"""
This class contains all the Network API methods required for
Enterprise Network WiFi tests.
"""
SHORT_TIMEOUT = 20
LONG_TIMEOUT = 120
def __init__(self, browser=None):
testing_context = cntc.ChromeNetworkingTestContext()
testing_context.setup(browser)
self.chrome_net_context = cnta.ChromeNetworkProvider(testing_context)
self.enable_wifi_on_dut()
def _extract_wifi_network_info(self, networks_found_list):
"""
Extract the required Network params from list of Networks found.
Filter out the required network parameters such Network Name/SSID,
GUID, connection state and security type of each of the networks in
WiFi range of the DUT.
@param networks_found_list: Network information returned as a result
of the getVisibleNetworks api.
@returns: Formatted list of namedtuples containing the
required network parameters.
"""
network_info_list = []
network_info = namedtuple(
'NetworkInfo', 'name guid connectionState security')
for network in networks_found_list:
network_data = network_info(
name=network['Name'],
guid=network['GUID'],
connectionState=network['ConnectionState'],
security=network['WiFi']['Security'])
network_info_list.append(network_data)
return network_info_list
def list_networks(self):
"""@returns: List of available WiFi networks."""
return self._extract_wifi_network_info(
self.chrome_net_context.get_wifi_networks())
def disable_network_device(self, network):
"""
Disable given network device.
This will fail if called multiple times in a test. Use the version in
'chrome_networking_test_api' if this is the case.
@param network: string name of the network device to be disabled.
Options include 'WiFi', 'Cellular', and 'Ethernet'.
"""
logging.info('Disabling: %s', network)
disable_network_result = self.chrome_net_context.\
_chrome_testing.call_test_function_async(
'disableNetworkDevice',
'"' + network + '"')
def _get_network_info(self, ssid):
"""
Returns the Network parameters for a specific network.
@param ssid: SSID of the network.
@returns: The NetworkInfo tuple containing the network parameters.
Returns None if network info for the SSID was not found.
"""
networks_in_range = self._extract_wifi_network_info(
self.chrome_net_context.get_wifi_networks())
logging.debug('Network info of all the networks in WiFi'
'range of DUT:%r', networks_in_range)
for network_info in networks_in_range:
if network_info.name == ssid:
return network_info
return None
def _get_network_connection_state(self, ssid):
"""
Returns the connection State of the network.
@returns: Connection State for the SSID.
"""
network_info = self._get_network_info(ssid)
return network_info.connectionState
def connect_to_network(self, ssid):
"""
Triggers a manual connect to the network using networkingPrivate API.
@param ssid: The ssid that the connection request is initiated for.
@raises error.TestFail: If the WiFi network is not in WiFi range of the
DUT or if the DUT cannot manually connect to the SSID.
"""
if not self.is_network_in_range(ssid):
raise error.TestFail("The SSID: %r is not in WiFi range of the DUT"%
ssid)
network_to_connect = self._get_network_info(ssid)
logging.info("Triggering a manual connect to network SSID: %r, GUID %r",
network_to_connect.name, network_to_connect.guid)
# TODO(krishnargv): Replace below code with the
# self.chrome_net_context.connect_to_network(network_to_connect) method.
new_network_connect = self.chrome_net_context._chrome_testing.\
call_test_function(
self.LONG_TIMEOUT,
'connectToNetwork',
'"%s"'% network_to_connect.guid)
logging.debug("Manual network connection status: %r",
new_network_connect['status'])
if (new_network_connect['status'] ==
'chrome-test-call-status-failure'):
raise error.TestFail(
'Could not connect to %s network. Error returned by '
'chrome.networkingPrivate.startConnect API: %s' %
(network_to_connect.name, new_network_connect['error']))
def disconnect_from_network(self, ssid):
"""
Triggers a disconnect from the network using networkingPrivate API.
@param ssid: The ssid that the disconnection request is initiated for.
@raises error.TestFail: If the WiFi network is not in WiFi range of the
DUT or if the DUT cannot manually disconnect from the SSID.
"""
if not self.is_network_in_range(ssid):
raise error.TestFail("The SSID: %r is not in WiFi range of the DUT"%
ssid)
network_to_disconnect = self._get_network_info(ssid)
logging.info("Triggering a disconnect from network SSID: %r, GUID %r",
network_to_disconnect.name, network_to_disconnect.guid)
new_network_disconnect = self.chrome_net_context._chrome_testing.\
call_test_function(
self.LONG_TIMEOUT,
'disconnectFromNetwork',
'"%s"'% network_to_disconnect.guid)
logging.debug("Manual network disconnection status: %r",
new_network_disconnect['status'])
if (new_network_disconnect['status'] ==
'chrome-test-call-status-failure'):
raise error.TestFail(
'Could not disconnect from %s network. Error returned by '
'chrome.networkingPrivate.startDisconnect API: %s' %
(network_to_disconnect.name,
new_network_disconnect['error']))
def enable_wifi_on_dut(self):
"""Enable the WiFi interface on the DUT if it is disabled."""
enabled_devices = self.chrome_net_context.get_enabled_devices()
if self.chrome_net_context.WIFI_DEVICE not in enabled_devices:
self.chrome_net_context.enable_network_device(
self.chrome_net_context.WIFI_DEVICE)
def is_network_in_range(self, ssid):
"""
Returns True if the WiFi network is within WiFi range of the DUT.
@param ssid: The SSID of the network.
@returns: True if the network/ssid is within WiFi range of the DUT,
else returns False
"""
return self._get_network_info(ssid) is not None
def is_network_connected(self, ssid):
"""
Return True if the DUT is connected to the Network.
Returns True if the DUT is connected to the network. Waits for a
a short time if the DUT is in a connecting state.
@param ssid: The SSID of the network.
@returns: True if the DUT is connected to the network/ssid,
else returns False
@raises error.TestFail: If the DUT is stuck in the connecting state.
"""
utils.poll_for_condition(
lambda:self._get_network_connection_state(ssid) != 'Connecting',
exception=error.TestFail('Device stuck in connecting state'),
timeout=self.SHORT_TIMEOUT)
network_connection_state = self._get_network_connection_state(ssid)
if network_connection_state is None:
return False
logging.debug("Connection state for SSID-%r is: %r",
ssid, network_connection_state)
return network_connection_state == 'Connected'