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 out of range or the 129 DUT cannot manually connect to the network. 130 131 """ 132 if not self.is_network_in_range(ssid): 133 raise error.TestFail( 134 "The SSID: %r is not in WiFi range of the DUT" % 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( 168 "The SSID: %r is not in WiFi range of the DUT" % 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, wait_time=0): 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 @param wait_time: Seconds to wait for SSID to appear. 204 205 @returns: True if the network/ssid is within WiFi range of the DUT, 206 else returns False 207 208 """ 209 try: 210 return utils.poll_for_condition( 211 lambda: self._get_network_info(ssid) is not None, 212 timeout=wait_time) 213 except utils.TimeoutError: 214 return False 215 216 217 def is_network_connected(self, ssid): 218 """ 219 Return True if the DUT is connected to the Network. 220 221 Returns True if the DUT is connected to the network. Waits for a 222 a short time if the DUT is in a connecting state. 223 224 @param ssid: The SSID of the network. 225 226 @returns: True if the DUT is connected to the network/ssid, 227 else returns False 228 229 @raises error.TestFail: If the DUT is stuck in the connecting state. 230 231 """ 232 utils.poll_for_condition( 233 lambda: (self._get_network_connection_state(ssid) 234 != 'Connecting'), 235 exception=error.TestFail('Device stuck in connecting state'), 236 timeout=self.SHORT_TIMEOUT) 237 try: 238 utils.poll_for_condition( 239 lambda: (self._get_network_connection_state(ssid) 240 == 'Connected'), 241 timeout=self.SHORT_TIMEOUT) 242 return True 243 except utils.TimeoutError: 244 logging.debug("Connection state for SSID-%r is: %r", 245 ssid, self._get_network_connection_state(ssid)) 246 return False 247