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 5import logging 6from collections import namedtuple 7 8from autotest_lib.client.bin import utils 9from autotest_lib.client.common_lib import error 10from autotest_lib.client.cros.networking.chrome_testing \ 11 import chrome_networking_test_context as cntc 12from autotest_lib.client.cros.networking.chrome_testing \ 13 import chrome_networking_test_api as cnta 14 15 16NETWORK_TEST_EXTENSION_PATH = cntc.NETWORK_TEST_EXTENSION_PATH 17 18 19class ChromeEnterpriseNetworkContext(object): 20 """ 21 This class contains all the Network API methods required for 22 Enterprise Network WiFi tests. 23 24 """ 25 SHORT_TIMEOUT = 20 26 LONG_TIMEOUT = 120 27 28 29 def __init__(self, browser=None): 30 testing_context = cntc.ChromeNetworkingTestContext() 31 testing_context.setup(browser) 32 self.chrome_net_context = cnta.ChromeNetworkProvider(testing_context) 33 self.enable_wifi_on_dut() 34 35 36 def _extract_wifi_network_info(self, networks_found_list): 37 """ 38 Extract the required Network params from list of Networks found. 39 40 Filter out the required network parameters such Network Name/SSID, 41 GUID, connection state and security type of each of the networks in 42 WiFi range of the DUT. 43 44 @param networks_found_list: Network information returned as a result 45 of the getVisibleNetworks api. 46 47 @returns: Formatted list of namedtuples containing the 48 required network parameters. 49 50 """ 51 network_info_list = [] 52 network_info = namedtuple( 53 'NetworkInfo', 'name guid connectionState security') 54 55 for network in networks_found_list: 56 network_data = network_info( 57 name=network['Name'], 58 guid=network['GUID'], 59 connectionState=network['ConnectionState'], 60 security=network['WiFi']['Security']) 61 network_info_list.append(network_data) 62 return network_info_list 63 64 65 def list_networks(self): 66 """@returns: List of available WiFi networks.""" 67 return self._extract_wifi_network_info( 68 self.chrome_net_context.get_wifi_networks()) 69 70 71 def disable_network_device(self, network): 72 """ 73 Disable given network device. 74 75 This will fail if called multiple times in a test. Use the version in 76 'chrome_networking_test_api' if this is the case. 77 78 @param network: string name of the network device to be disabled. 79 Options include 'WiFi', 'Cellular', and 'Ethernet'. 80 81 """ 82 logging.info('Disabling: %s', network) 83 disable_network_result = self.chrome_net_context.\ 84 _chrome_testing.call_test_function_async( 85 'disableNetworkDevice', 86 '"' + network + '"') 87 88 89 def _get_network_info(self, ssid): 90 """ 91 Returns the Network parameters for a specific network. 92 93 @param ssid: SSID of the network. 94 95 @returns: The NetworkInfo tuple containing the network parameters. 96 Returns None if network info for the SSID was not found. 97 98 """ 99 networks_in_range = self._extract_wifi_network_info( 100 self.chrome_net_context.get_wifi_networks()) 101 logging.debug('Network info of all the networks in WiFi' 102 'range of DUT:%r', networks_in_range) 103 for network_info in networks_in_range: 104 if network_info.name == ssid: 105 return network_info 106 return None 107 108 109 def _get_network_connection_state(self, ssid): 110 """ 111 Returns the connection State of the network. 112 113 @returns: Connection State for the SSID. 114 115 """ 116 network_info = self._get_network_info(ssid) 117 if network_info is None: 118 return None 119 return network_info.connectionState 120 121 122 def connect_to_network(self, ssid): 123 """ 124 Triggers a manual connect to the network using networkingPrivate API. 125 126 @param ssid: The ssid that the connection request is initiated for. 127 128 @raises error.TestFail: If the WiFi network is not in WiFi range of the 129 DUT or if the DUT cannot manually connect to the SSID. 130 131 """ 132 if not self.is_network_in_range(ssid): 133 raise error.TestFail("The SSID: %r is not in WiFi range of the DUT"% 134 ssid) 135 136 network_to_connect = self._get_network_info(ssid) 137 logging.info("Triggering a manual connect to network SSID: %r, GUID %r", 138 network_to_connect.name, network_to_connect.guid) 139 140 # TODO(krishnargv): Replace below code with the 141 # self.chrome_net_context.connect_to_network(network_to_connect) method. 142 new_network_connect = self.chrome_net_context._chrome_testing.\ 143 call_test_function( 144 self.LONG_TIMEOUT, 145 'connectToNetwork', 146 '"%s"'% network_to_connect.guid) 147 logging.debug("Manual network connection status: %r", 148 new_network_connect['status']) 149 if new_network_connect['status'] == 'chrome-test-call-status-failure': 150 raise error.TestFail( 151 'Could not connect to %s network. Error returned by ' 152 'chrome.networkingPrivate.startConnect API: %s' % 153 (network_to_connect.name, new_network_connect['error'])) 154 155 156 def disconnect_from_network(self, ssid): 157 """ 158 Triggers a disconnect from the network using networkingPrivate API. 159 160 @param ssid: The ssid that the disconnection request is initiated for. 161 162 @raises error.TestFail: If the WiFi network is not in WiFi range of the 163 DUT or if the DUT cannot manually disconnect from the SSID. 164 165 """ 166 if not self.is_network_in_range(ssid): 167 raise error.TestFail("The SSID: %r is not in WiFi range of the DUT"% 168 ssid) 169 170 network_to_disconnect = self._get_network_info(ssid) 171 logging.info("Triggering a disconnect from network SSID: %r, GUID %r", 172 network_to_disconnect.name, network_to_disconnect.guid) 173 174 new_network_disconnect = self.chrome_net_context._chrome_testing.\ 175 call_test_function( 176 self.LONG_TIMEOUT, 177 'disconnectFromNetwork', 178 '"%s"'% network_to_disconnect.guid) 179 logging.debug("Manual network disconnection status: %r", 180 new_network_disconnect['status']) 181 if (new_network_disconnect['status'] == 182 'chrome-test-call-status-failure'): 183 raise error.TestFail( 184 'Could not disconnect from %s network. Error returned by ' 185 'chrome.networkingPrivate.startDisconnect API: %s' % 186 (network_to_disconnect.name, 187 new_network_disconnect['error'])) 188 189 190 def enable_wifi_on_dut(self): 191 """Enable the WiFi interface on the DUT if it is disabled.""" 192 enabled_devices = self.chrome_net_context.get_enabled_devices() 193 if self.chrome_net_context.WIFI_DEVICE not in enabled_devices: 194 self.chrome_net_context.enable_network_device( 195 self.chrome_net_context.WIFI_DEVICE) 196 197 198 def is_network_in_range(self, ssid): 199 """ 200 Returns True if the WiFi network is within WiFi range of the DUT. 201 202 @param ssid: The SSID of the network. 203 204 @returns: True if the network/ssid is within WiFi range of the DUT, 205 else returns False 206 207 """ 208 return self._get_network_info(ssid) is not None 209 210 211 def is_network_connected(self, ssid): 212 """ 213 Return True if the DUT is connected to the Network. 214 215 Returns True if the DUT is connected to the network. Waits for a 216 a short time if the DUT is in a connecting state. 217 218 @param ssid: The SSID of the network. 219 220 @returns: True if the DUT is connected to the network/ssid, 221 else returns False 222 223 @raises error.TestFail: If the DUT is stuck in the connecting state. 224 225 """ 226 utils.poll_for_condition( 227 lambda: (self._get_network_connection_state(ssid) 228 != 'Connecting'), 229 exception=error.TestFail('Device stuck in connecting state'), 230 timeout=self.SHORT_TIMEOUT) 231 try: 232 utils.poll_for_condition( 233 lambda: (self._get_network_connection_state(ssid) 234 == 'Connected'), 235 timeout=self.SHORT_TIMEOUT) 236 except utils.TimeoutError: 237 pass 238 network_connection_state = self._get_network_connection_state(ssid) 239 logging.debug("Connection state for SSID-%r is: %r", 240 ssid, network_connection_state) 241 return network_connection_state == 'Connected' 242