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 5import logging 6import urlparse 7import time 8 9import dynamic_ap_configurator 10import ap_spec 11 12from selenium.common.exceptions import TimeoutException 13from selenium.common.exceptions import WebDriverException 14from selenium.webdriver.support import expected_conditions as ec 15from selenium.webdriver.common.by import By 16 17class WesternDigitalN600APConfigurator( 18 dynamic_ap_configurator.DynamicAPConfigurator): 19 """Base class for objects to configure Western Digital N600 access point 20 using webdriver.""" 21 22 23 def _sec_alert(self, alert): 24 text = alert.text 25 if 'Your wireless security mode is not compatible with' in text: 26 alert.accept() 27 elif 'WARNING: Your Wireless-N devices will only operate' in text: 28 alert.accept() 29 elif 'Your new setting will disable Wi-Fi Protected Setup.' in text: 30 alert.accept() 31 elif 'To use WEP security, WPS must be disabled. Proceed ?' in text: 32 alert.accept() 33 elif 'Warning ! Selecting None in Security Mode will make' in text: 34 alert.accept() 35 else: 36 raise RuntimeError('Invalid handler') 37 38 39 def get_number_of_pages(self): 40 return 1 41 42 43 def is_update_interval_supported(self): 44 """ 45 Returns True if setting the PSK refresh interval is supported. 46 47 @return True is supported; False otherwise 48 """ 49 return False 50 51 52 def is_visibility_supported(self): 53 """ 54 Returns if AP supports setting the visibility (SSID broadcast). 55 56 @return True if supported; False otherwise. 57 58 """ 59 return False 60 61 62 def get_supported_modes(self): 63 return [{'band': ap_spec.BAND_2GHZ, 64 'modes': [ap_spec.MODE_B, ap_spec.MODE_G, ap_spec.MODE_N, 65 ap_spec.MODE_B | ap_spec.MODE_G, 66 ap_spec.MODE_G | ap_spec.MODE_N, 67 ap_spec.MODE_B | ap_spec.MODE_G | ap_spec.MODE_N]}, 68 {'band': ap_spec.BAND_5GHZ, 69 'modes': [ap_spec.MODE_A, ap_spec.MODE_N, 70 ap_spec.MODE_A | ap_spec.MODE_N]}] 71 72 73 def get_supported_bands(self): 74 return [{'band': ap_spec.BAND_2GHZ, 75 'channels': ['Auto', 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]}, 76 {'band': ap_spec.BAND_5GHZ, 77 'channels': ['Auto', 36, 40, 44, 48, 149, 153, 157, 161, 165]}] 78 79 80 def is_security_mode_supported(self, security_mode): 81 """Check if the AP supports this mode of security. 82 83 @param security_mode: Type of security. 84 85 """ 86 return security_mode in (ap_spec.SECURITY_TYPE_DISABLED, 87 ap_spec.SECURITY_TYPE_WPAPSK, 88 ap_spec.SECURITY_TYPE_WPA2PSK, 89 ap_spec.SECURITY_TYPE_WEP) 90 91 92 def navigate_to_page(self, page_number): 93 """Navigate to the required page. 94 95 @param page_number: The page number to navigate to. 96 97 """ 98 page_url = urlparse.urljoin(self.admin_interface_url, 'wlan.php') 99 self.get_url(page_url, page_title='WESTERN DIGITAL') 100 xpath_found = self.wait_for_objects_by_id(['loginusr', 'ssid']) 101 if 'loginusr' in xpath_found: 102 self._login_to_router() 103 elif 'ssid' not in xpath_found: 104 raise RuntimeError('The page %s did not load or Radio is switched' 105 'off' % page_url) 106 self.set_radio(enabled=True) 107 108 109 def _login_to_router(self): 110 self.wait_for_object_by_id('loginusr') 111 self.set_content_of_text_field_by_id('admin', 'loginusr', 112 abort_check=True) 113 self.wait_for_object_by_id('loginpwd') 114 self.set_content_of_text_field_by_id('password', 'loginpwd', 115 abort_check=True) 116 self.click_button_by_xpath('//input[@value="Submit"]') 117 self.wait_for_object_by_id('ssid') 118 119 120 def save_page(self, page_number): 121 """ Save page after applying settings. 122 123 @param page_number: The page number to be saved. 124 125 """ 126 self.wait_for_object_by_id('onsumit') 127 self.click_button_by_id('onsumit', alert_handler=self._sec_alert) 128 warning = '//h1[text()="Warning"]' 129 settings_changed = True 130 try: 131 self.wait_for_object_by_xpath(warning) 132 xpath = '//input[@id="onsumit"]' 133 button = self.driver.find_elements_by_xpath(xpath)[1] 134 button.click() 135 self._handle_alert(xpath, self._sec_alert) 136 self.wait_for_object_by_xpath('//input[@value="Ok"]', wait_time=5) 137 except WebDriverException, e: 138 logging.debug('There is a webdriver exception: "%s".', str(e)) 139 settings_changed = False 140 if not settings_changed: 141 try: 142 # if settings are not changed, hit 'continue' button. 143 self.driver.find_element_by_id('nochg') 144 self.click_button_by_id('nochg') 145 except WebDriverException, e: 146 logging.debug('There is a webdriver exception: "%s".', str(e)) 147 148 149 def set_mode(self, mode, band=None): 150 self.add_item_to_command_list(self._set_mode, (mode,), 1, 900) 151 152 153 def _set_mode(self, mode, band=None): 154 # This is a dummy wait to give enough time for the popup to 155 # load all options. 156 self._wait_for_page_reload() 157 mode_mapping = {ap_spec.MODE_B | ap_spec.MODE_G:'Mixed 802.11 b+g', 158 ap_spec.MODE_G:'802.11g only', 159 ap_spec.MODE_B:'802.11b only', 160 ap_spec.MODE_N:'802.11n only', 161 ap_spec.MODE_A:'802.11a only', 162 ap_spec.MODE_G | ap_spec.MODE_N:'Mixed 802.11 g+n', 163 ap_spec.MODE_B | ap_spec.MODE_G | ap_spec.MODE_N: 164 'Mixed 802.11 b+g+n', 165 ap_spec.MODE_A | ap_spec.MODE_N: 'Mixed 802.11 a+n'} 166 mode_id = 'wlan_mode' 167 if self.current_band == ap_spec.BAND_5GHZ: 168 mode_id = 'wlan_mode_Aband' 169 mode_name = '' 170 if mode in mode_mapping.keys(): 171 mode_name = mode_mapping[mode] 172 else: 173 raise RuntimeError('The mode selected \'%d\' is not supported by ' 174 ' \'%s\'.', hex(mode), self.name) 175 popup = self.wait_for_object_by_id(mode_id) 176 while popup and not(self.object_by_id_exist(mode_id)): 177 logging.debug('The object %s does not exist', mode_id) 178 # Click is needed so that we can focus and don't get an empty popup. 179 self.driver.find_element_by_id(mode_id).click() 180 self.select_item_from_popup_by_id(mode_name, mode_id, 181 alert_handler=self._sec_alert) 182 183 184 def set_ssid(self, ssid): 185 self.add_item_to_command_list(self._set_ssid, (ssid,), 1, 900) 186 187 188 def _set_ssid(self, ssid): 189 self._set_radio(True) 190 ssid_id = 'ssid' 191 if self.current_band == ap_spec.BAND_5GHZ: 192 ssid_id = 'ssid_Aband' 193 self.wait_for_object_by_id(ssid_id) 194 self.set_content_of_text_field_by_id(ssid, ssid_id, abort_check=True) 195 self._ssid = ssid 196 197 198 def _wait_for_page_reload(self): 199 """ 200 This router has a tendency to reload the webpage right after we load 201 it. To avoid any exceptions because of this we wait for the page to 202 reload by default. 203 """ 204 elements = self.driver.find_elements_by_css_selector('span.checkbox') 205 checkbox = elements[0] 206 ssid_id = 'ssid' 207 if self.current_band == ap_spec.BAND_5GHZ: 208 checkbox = elements[3] 209 ssid_id = 'ssid_Aband' 210 for timer in range(5): # Waiting for the page to reload 211 try: 212 if ('checkbox.png' in 213 checkbox.value_of_css_property('background-image')): 214 break 215 except: 216 pass 217 time.sleep(1) 218 try: 219 if(self.wait_for_object_by_id(ssid_id).is_enabled()): 220 logging.info('The page reload succeeded.') 221 except: 222 raise RuntimeError('The page reload after login failed.') 223 224 225 def set_radio(self, enabled=True): 226 self.add_item_to_command_list(self._set_radio, (enabled, ), 1, 1000) 227 228 229 def _set_radio(self, enabled=True): 230 self._wait_for_page_reload() 231 elements = self.driver.find_elements_by_css_selector('span.checkbox') 232 checkbox = elements[0] 233 ssid = 'ssid' 234 if self.current_band == ap_spec.BAND_5GHZ: 235 checkbox = elements[3] 236 ssid = 'ssid_Aband' 237 image = 'checkbox_off.png' 238 if enabled: 239 image = 'checkbox.png' 240 try: 241 self.wait.until(ec.element_to_be_clickable((By.ID, ssid))) 242 except TimeoutException, e: 243 if not (image in 244 checkbox.value_of_css_property('background-image')): 245 checkbox.click() 246 else: 247 message = 'Radio is not enabled. ' + str(e) 248 raise TimeoutException(message) 249 elif not (image in checkbox.value_of_css_property('background-image')): 250 checkbox.click() 251 252 253 def set_channel(self, channel): 254 self.add_item_to_command_list(self._set_channel, (channel,), 1, 900) 255 256 257 def _set_channel(self, channel): 258 self._wait_for_page_reload() 259 position = self._get_channel_popup_position(channel) 260 channel_id = 'channel' 261 channel_choices = ['Auto', '2.412 GHz - CH 1', '2.417 GHz - CH 2', 262 '2.422 GHz - CH 3', '2.427 GHz - CH 4', 263 '2.432 GHz - CH 5', '2.437 GHz - CH 6', 264 '2.442 GHz - CH 7', '2.447 GHz - CH 8', 265 '2.452 GHz - CH 9', '2.457 GHz - CH 10', 266 '2.462 GHz - CH 11'] 267 if self.current_band == ap_spec.BAND_5GHZ: 268 channel_id = 'channel_Aband' 269 channel_choices = ['Auto', '5.180 GHz - CH 36', '5.200 GHz - CH 40', 270 '5.220 GHz - CH 44', '5.240 GHz - CH 48', 271 '5.745 GHz - CH 149', '5.765 GHz - CH 153', 272 '5.785 GHz - CH 157', '5.805 GHz - CH 161', 273 '5.825 GHz - CH 165'] 274 self.wait_for_object_by_id(channel_id) 275 self.select_item_from_popup_by_id(channel_choices[position], channel_id) 276 277 278 def set_channel_width(self, channel_wid): 279 self.add_item_to_command_list(self._set_channel_width, (channel_wid,), 280 1, 900) 281 282 283 def _set_channel_width(self, channel_wid): 284 channel_width_choice = ['20 MHz', '20/40 MHz(Auto)'] 285 width_id = 'bw' 286 if self.current_band == ap_spec.BAND_5GHZ: 287 width_id = 'bw_Aband' 288 self.select_item_from_popup_by_id(channel_width_choice[channel_wid], 289 width_id) 290 291 292 def set_band(self, band): 293 if band == ap_spec.BAND_5GHZ: 294 self.current_band = ap_spec.BAND_5GHZ 295 elif band == ap_spec.BAND_2GHZ: 296 self.current_band = ap_spec.BAND_2GHZ 297 else: 298 raise RuntimeError('Invalid band sent %s' % band) 299 self.set_radio(True) 300 301 302 def _set_security(self, security_type, wait_path=None): 303 self._wait_for_page_reload() 304 sec_id = 'security_type' 305 if self.current_band == ap_spec.BAND_5GHZ: 306 sec_id = 'security_type_Aband' 307 text = '//input[@name="wpapsk_Aband" and @type="text"]' 308 self.wait_for_object_by_id(sec_id, wait_time=5) 309 if self.item_in_popup_by_id_exist(security_type, sec_id): 310 self.select_item_from_popup_by_id(security_type, sec_id, 311 wait_for_xpath=wait_path, 312 alert_handler=self._sec_alert) 313 elif security_type == 'WEP': 314 raise RuntimeError('Could not find WEP security_type in dropdown. ' 315 'Please check the network mode. ' 316 'Some of the modes do not support WEP.') 317 else: 318 raise RuntimeError('The dropdown %s does not have item %s' % 319 (sec_id, security_type)) 320 321 322 def set_security_disabled(self): 323 self.add_item_to_command_list(self._set_security_disabled, (), 1, 1000) 324 325 326 def _set_security_disabled(self): 327 self._set_security('None') 328 329 330 def set_security_wep(self, key_value, authentication): 331 self.add_item_to_command_list(self._set_security_wep, 332 (key_value, authentication), 1, 1000) 333 334 335 def _set_security_wep(self, key_value, authentication): 336 # WEP is not supported for Wireless-N only and Mixed (g+n, b+g+n) mode. 337 # WEP does not show up in the list, no alert is thrown. 338 text = '//input[@name="wepkey_64"]' 339 if self.current_band == ap_spec.BAND_5GHZ: 340 text = '//input[@name="wepkey_64_Aband"]' 341 self._set_security('WEP', text) 342 self.set_content_of_text_field_by_xpath(key_value, text, 343 abort_check=True) 344 345 346 def set_security_wpapsk(self, security, shared_key, update_interval=None): 347 # WEP and WPA-Personal are not supported for Wireless-N only mode, 348 self.add_item_to_command_list(self._set_security_wpapsk, 349 (security, shared_key,), 1, 1000) 350 351 352 def _set_security_wpapsk(self, security, shared_key): 353 text = 'wpapsk' 354 if self.current_band == ap_spec.BAND_5GHZ: 355 text = 'wpapsk_Aband' 356 if security == ap_spec.SECURITY_TYPE_WPAPSK: 357 self._set_security('WPA - Personal', '//input[@id="%s"]' % text) 358 else: 359 self._set_security('WPA2 - Personal', '//input[@id="%s"]' % text) 360 self.set_content_of_text_field_by_id(shared_key, text, 361 abort_check=False) 362 363 364 def set_visibility(self, visible=True): 365 # The SSID Broadcast can't be reliable set on this AP beacuse the CSS 366 # property for backgroung-image always returns OFF. 367 return None 368