| OLD | NEW |
| (Empty) |
| 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 | |
| OLD | NEW |