1 # Copyright (c) 2012 The Chromium 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 import copy 6 import logging 7 import os 8 9 import pyauto_ap_configurator 10 import pyauto 11 12 import selenium.common.exceptions 13 from selenium.webdriver.support.ui import WebDriverWait 14 15 16 class APConfigurator(object): 17 """Base class for objects to configure access points using webdriver.""" 18 19 def __init__(self, pyauto_instance): 20 self.pyauto_instance = pyauto_instance 21 self._driver = pyauto_instance.NewWebDriver() 22 # Any call to wait.until() will raise an exception if the timeout is hit. 23 self._wait = WebDriverWait(self._driver, timeout=5) 24 25 # Possible bands 26 self.band_2ghz = '2.4GHz' 27 self.band_5ghz = '5GHz' 28 29 # Possible modes 30 self.mode_a = 0x0001 31 self.mode_b = 0x0010 32 self.mode_g = 0x0100 33 self.mode_n = 0x1000 34 35 # Possible security settings 36 self.security_disabled = 'Disabled' 37 self.security_wep = 'WEP' 38 self.security_wpawpsk = 'WPA-Personal' 39 self.security_wpa2wpsk = 'WPA2-Personal' 40 self.security_wpa8021x = 'WPA-Enterprise' 41 self.security_wpa28021x = 'WPA2-Enterprise' 42 43 self.wep_authentication_open = 'Open' 44 self.wep_authentication_shared = 'Shared Key' 45 46 self._command_list = [] 47 48 def _WaitForObjectByXPath(self, xpath): 49 """Waits for an object to appear.""" 50 try: 51 self._wait.until(lambda _: self._driver.find_element_by_xpath(xpath)) 52 except selenium.common.exceptions.TimeoutException, e: 53 logging.exception('Unable to find the wait for object by xpath: %s\n' 54 'WebDriver exception: %s', xpath, str(e)) 55 56 def SelectItemFromPopupByID(self, item, element_id, wait_for_xpath=None): 57 """Selects an item from a popup, by passing the element ID. 58 59 Args: 60 item: the item to select from the popup 61 element_id: the html ID of the item 62 wait_for_xpath: an item to wait for before returning 63 """ 64 xpath = 'id("%s")' % element_id 65 self.SelectItemFromPopupByXPath(item, xpath, wait_for_xpath) 66 67 def SelectItemFromPopupByXPath(self, item, xpath, wait_for_xpath=None): 68 """Selects an item from a popup, by passing the xpath of the popup. 69 70 Args: 71 item: the item to select from the popup 72 xpath: the xpath of the popup 73 wait_for_xpath: an item to wait for before returning 74 """ 75 popup = self._driver.find_element_by_xpath(xpath) 76 for option in popup.find_elements_by_tag_name('option'): 77 if option.text == item: 78 option.click() 79 break 80 if wait_for_xpath: self._WaitForObjectByXPath(wait_for_xpath) 81 82 def SetContentOfTextFieldByID(self, content, text_field_id, 83 wait_for_xpath=None): 84 """Sets the content of a textfield, by passing the element ID. 85 86 Args: 87 content: the content to apply to the textfield 88 text_field_id: the html ID of the textfield 89 wait_for_xpath: an item to wait for before returning 90 """ 91 xpath = 'id("%s")' % text_field_id 92 self.SetConentsOfTextFieldByXPath(content, xpath, wait_for_xpath) 93 94 def SetConentsOfTextFieldByXPath(self, content, xpath, wait_for_xpath=None): 95 """Sets the content of a textfield, by passing the xpath. 96 97 Args: 98 content: the content to apply to the textfield 99 xpath: the xpath of the textfield 100 wait_for_xpath: an item to wait for before returning 101 """ 102 # When we can get the value we know the text field is ready. 103 text_field = self._driver.find_element_by_xpath(xpath) 104 try: 105 self._wait.until(lambda _: text_field.get_attribute('value')) 106 except selenium.common.exceptions.TimeoutException, e: 107 logging.exception('Unable to obtain the value of the text field %s.\n' 108 'WebDriver exception: %s', wait_for_xpath, str(e)) 109 text_field = self._driver.find_element_by_xpath(xpath) 110 text_field.clear() 111 text_field.send_keys(content) 112 if wait_for_xpath: self._WaitForObjectByXPath(wait_for_xpath) 113 114 def SetCheckBoxSelectedByID(self, check_box_id, selected=True, 115 wait_for_xpath=None): 116 """Sets the state of a checkbox, by passing the ID. 117 118 Args: 119 check_box_id: the html id of the checkbox 120 selected: True to enable the checkbox; False otherwise 121 wait_for_xpath: an item to wait for before returning 122 """ 123 xpath = 'id("%s")' % check_box_id 124 self.SetCheckBoxSelectedByXPath(xpath, selected, wait_for_xpath) 125 126 def SetCheckBoxSelectedByXPath(self, xpath, selected=True, 127 wait_for_xpath=None): 128 """Sets the state of a checkbox, by passing the xpath. 129 130 Args: 131 xpath: the xpath of the checkbox 132 selected: True to enable the checkbox; False otherwise 133 wait_for_xpath: an item to wait for before returning 134 """ 135 check_box = self._driver.find_element_by_xpath(xpath) 136 value = check_box.get_attribute('value') 137 if (value == '1' and not selected) or (value == '0' and selected): 138 check_box.click() 139 if wait_for_xpath: self._WaitForObjectByXPath(wait_for_xpath) 140 141 def AddItemToCommandList(self, method, args, page, priority): 142 """Adds commands to be executed against the AP web UI. 143 144 Args: 145 method: the method to run 146 args: the arguments for the method you want executed 147 page: the page on the web ui where the method should be run against 148 priority: the priority of the method 149 """ 150 self._command_list.append({'method': method, 151 'args': copy.copy(args), 152 'page': page, 153 'priority': priority}) 154 155 def GetRouterName(self): 156 """Returns a string to describe the router. 157 158 Note: The derived class must implement this method. 159 """ 160 raise NotImplementedError 161 162 def GetRouterShortName(self): 163 """Returns a short string to describe the router. 164 165 Note: The derived class must implement this method. 166 """ 167 raise NotImplementedError 168 169 def GetNumberOfPages(self): 170 """Returns the number of web pages used to configure the router. 171 172 Note: This is used internally by applySettings, and this method must be 173 implemented by the derived class. 174 """ 175 raise NotImplementedError 176 177 def GetSupportedBands(self): 178 """Returns a list of dictionaries describing the supported bands. 179 180 Example: returned is a dictionary of band and a list of channels. The band 181 object returned must be one of those defined in the __init___ of 182 this class. 183 184 supported_bands = [{'band' : self.band_2GHz, 185 'channels' : [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]}, 186 {'band' : self.band_5ghz, 187 'channels' : [26, 40, 44, 48, 149, 153, 157, 161, 165]}] 188 189 Returns: 190 A list of dictionaries as described above 191 192 Note: The derived class must implement this method. 193 """ 194 raise NotImplementedError 195 196 def GetSupportedModes(self): 197 """Returns a list of dictionaries describing the supported modes. 198 199 Example: returned is a dictionary of band and a list of modess. The band 200 and modes objects returned must be one of those defined in the 201 __init___ of this class. 202 203 supported_modes = [{'band' : self.band_2GHz, 204 'modes' : [mode_b, mode_b | mode_g]}, 205 {'band' : self.band_5ghz, 206 'modes' : [mode_a, mode_n, mode_a | mode_n]}] 207 208 Returns: 209 A list of dictionaries as described above 210 211 Note: The derived class must implement this method. 212 """ 213 raise NotImplementedError 214 215 def NavigateToPage(self, page_number): 216 """Navigates to the page corresponding to the given page number. 217 218 This method performs the translation between a page number and a url to 219 load. This is used internally by applySettings. 220 221 Args: 222 page_number: Page number of the page to load 223 224 Returns: 225 True if navigation is successful; False otherwise. 226 227 Note: The derived class must implement this method. 228 """ 229 raise NotImplementedError 230 231 def SavePage(self, page_number): 232 """Saves the given page. 233 234 Args: 235 page_number: Page number of the page to save. 236 237 Returns: 238 True if navigation is successful; False otherwise. 239 240 Note: The derived class must implement this method. 241 """ 242 raise NotImplementedError 243 244 def SetMode(self, mode, band=None): 245 """Sets the mode. 246 247 Args: 248 mode: must be one of the modes listed in __init__() 249 band: the band to select 250 251 Note: The derived class must implement this method 252 """ 253 raise NotImplementedError 254 255 def SetRadio(self, enabled=True): 256 """Turns the radio on and off. 257 258 Args: 259 enabled: True to turn on the radio; False otherwise 260 261 Note: The derived class must implement this method. 262 """ 263 raise NotImplementedError 264 265 def SetSSID(self, ssid): 266 """Sets the SSID of the wireless network. 267 268 Args: 269 ssid: Name of the wireless network 270 271 Note: The derived class must implement this method. 272 """ 273 raise NotImplementedError 274 275 def SetChannel(self, channel): 276 """Sets the channel of the wireless network. 277 278 Args: 279 channel: Integer value of the channel 280 281 Note: The derived class must implement this method. 282 """ 283 raise NotImplementedError 284 285 def SetBand(self, band): 286 """Sets the band of the wireless network. 287 288 Currently there are only two possible values for band 2kGHz and 5kGHz. 289 290 Args: 291 band: Constant describing the band type 292 293 Note: The derived class must implement this method. 294 """ 295 raise NotImplementedError 296 297 def SetSecurityDisabled(self): 298 """Disables the security of the wireless network. 299 300 Note: The derived class must implement this method. 301 """ 302 raise NotImplementedError 303 304 def SetSecurityWEP(self, key_value, authentication): 305 """Enabled WEP security for the wireless network. 306 307 Args: 308 key_value: encryption key to use 309 authentication: one of two supported authentication types: 310 wep_authentication_open or wep_authentication_shared 311 312 Note: The derived class must implement this method. 313 """ 314 raise NotImplementedError 315 316 def SetSecurityWPAPSK(self, shared_key, update_interval=1800): 317 """Enabled WPA using a private security key for the wireless network. 318 319 Args: 320 shared_key: shared encryption key to use 321 update_interval: number of seconds to wait before updating 322 323 Note: The derived class must implement this method. 324 """ 325 raise NotImplementedError 326 327 def SetVisibility(self, visible=True): 328 """Set the visibility of the wireless network. 329 330 Args: 331 visible: True for visible; False otherwise 332 333 Note: The derived class must implement this method. 334 """ 335 raise NotImplementedError 336 337 def ApplySettings(self): 338 """Apply all settings to the access point.""" 339 # Pull items by page and then sort 340 if self.GetNumberOfPages() == -1: 341 self.fail(msg='Number of pages is not set.') 342 page_range = range(1, self.GetNumberOfPages() + 1) 343 for i in page_range: 344 page_commands = [] 345 for command in self._command_list: 346 if command['page'] == i: 347 page_commands.append(command) 348 # Sort the commands in this page by priority 349 sorted_page_commands = sorted(page_commands, key=lambda k: k['priority']) 350 if sorted_page_commands and self.NavigateToPage(i): 351 for command in sorted_page_commands: 352 command['method'](*command['args']) 353 self.SavePage(i) 354 self._command_list = [] 355 356