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"""Class to control the Belkin F9K router.""" 6 7import logging 8import urlparse 9import time 10import dynamic_ap_configurator 11import ap_spec 12from selenium.webdriver.common.keys import Keys 13from selenium.common.exceptions import WebDriverException 14from selenium.common.exceptions import TimeoutException as \ 15 SeleniumTimeoutException 16 17 18class BelkinF9KAPConfigurator( 19 dynamic_ap_configurator.DynamicAPConfigurator): 20 """Class to configure Blekin f9k1002v4 router.""" 21 22 23 def __init__(self, ap_config): 24 super(BelkinF9KAPConfigurator, self).__init__(ap_config) 25 self._dhcp_delay = 30 26 27 28 security_popup = '//select[@name="security_type"]' 29 30 def _security_alert(self, alert): 31 text = alert.text 32 if 'Invalid character' in text: 33 alert.accept() 34 elif 'It is recommended to use WPA/WPA2 when WPS is enabled' in text: 35 alert.accept() 36 elif 'After changing to 11g mode' in text: 37 alert.accept() 38 elif 'After changing to 11b&g&n or 11n mode' in text: 39 alert.accept() 40 else: 41 alert.accept() 42 raise RuntimeError('Unhandeled modal dialog. %s' % text) 43 44 45 def open_new_tab(self): 46 """Re-Opens tab on the browser""" 47 body = self.driver.find_element_by_tag_name("body") 48 body.send_keys(Keys.CONTROL + 't') 49 50 51 def _login(self): 52 """Opens the login page and logs in using the password. 53 We need to login before doing any other change to make sure that 54 we have access to the router.""" 55 page_url = urlparse.urljoin(self.admin_interface_url,'login.stm') 56 xpath = '//input[@name="pws"]' 57 try: 58 self.open_new_tab() 59 self.get_url(page_url, page_title='login.stm') 60 self.wait_for_object_by_xpath(xpath, wait_time=10) 61 except WebDriverException as e: 62 logging.info("Page did not load or %s", str(e)) 63 self.driver.refresh() 64 self.wait_for_object_by_xpath(xpath, wait_time=10) 65 self.set_content_of_text_field_by_xpath('password', xpath, 66 abort_check=True) 67 self.click_button_by_xpath('//input[@value="Submit"]', 68 alert_handler=self._security_alert) 69 70 71 def get_supported_bands(self): 72 return [{'band': ap_spec.BAND_2GHZ, 73 'channels': ['Auto', 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]}] 74 75 76 def get_supported_modes(self): 77 return [{'band': ap_spec.BAND_2GHZ, 78 'modes': [ap_spec.MODE_G, ap_spec.MODE_N, 79 ap_spec.MODE_B | ap_spec.MODE_G | ap_spec.MODE_N]}] 80 81 82 def get_number_of_pages(self): 83 return 2 84 85 86 def is_security_mode_supported(self, security_mode): 87 """ 88 Returns if a given security_type is supported. 89 90 @param security_mode: one security modes defined in the APSpec 91 92 @return True if the security mode is supported; False otherwise. 93 94 """ 95 return security_mode in (ap_spec.SECURITY_TYPE_DISABLED, 96 ap_spec.SECURITY_TYPE_WPAPSK, 97 ap_spec.SECURITY_TYPE_WPA2PSK, 98 ap_spec.SECURITY_TYPE_WEP) 99 100 101 def navigate_to_page(self, page_number): 102 """ 103 Navigates to the page corresponding to the given page number. 104 105 This method performs the translation between a page number and a url to 106 load. This is used internally by apply_settings. 107 108 @param page_number: page number of the page to load 109 110 """ 111 self._login() 112 if page_number == 1: 113 page_url = urlparse.urljoin(self.admin_interface_url, 114 'wireless_id.stm') 115 self.get_url(page_url, page_title='wireless_id') 116 self.wait_for_object_by_xpath('//input[@name="ssid"]') 117 elif page_number == 2: 118 page_url = urlparse.urljoin(self.admin_interface_url, 119 'wireless_e.stm') 120 try: 121 self.get_url(page_url, page_title='wireless') 122 self.wait_for_object_by_xpath(self.security_popup) 123 except (WebDriverException, SeleniumTimeoutException), e: 124 message = str(e) 125 if 'Timed out receiving message from renderer' in message: 126 self.driver.refresh() 127 self.wait_for_object_by_xpath(self.security_popup) 128 elif (any(alert in message for alert in 129 ['unexpected alert open', 'An open modal dialog blocked'])): 130 self._security_alert(self.driver.switch_to_alert()) 131 else: 132 raise RuntimeError(message) 133 else: 134 raise RuntimeError('Invalid page number passed. Number of pages ' 135 '%d, page value sent was %d' % 136 (self.get_number_of_pages(), page_number)) 137 138 139 def save_page(self, page_number): 140 """Save changes and logout from the router. 141 142 @param page_number: the page number to save as an integer. 143 144 """ 145 self.click_button_by_xpath('//input[@type="submit" and ' 146 '@value="Apply Changes"]', 147 alert_handler=self._security_alert) 148 try: 149 self.wait_for_object_by_xpath_to_vanish('//input[@name= \ 150 "timeRemain]"',wait_time=30) 151 self.wait.until(lambda _:'setup.htm' in self.driver.title) 152 except WebDriverException, e: 153 logging.info("Driver title page did not load or %s", str(e)) 154 self.open_new_tab() 155 finally: 156 self.restore_default_wait_time() 157 158 159 def set_ssid(self, ssid): 160 self.add_item_to_command_list(self._set_ssid, (ssid,), 1, 900) 161 162 163 def _set_ssid(self, ssid): 164 xpath = '//input[@name="ssid"]' 165 self.set_content_of_text_field_by_xpath(ssid, xpath, abort_check=True) 166 self._ssid = ssid 167 168 169 def set_channel(self, channel): 170 self.add_item_to_command_list(self._set_channel, (channel,), 1, 900) 171 172 173 def _set_channel(self, channel): 174 position = self._get_channel_popup_position(channel) 175 channel_choices = ['Auto', '1', '2', '3', '4', '5', '6', '7', '8', 176 '9', '10', '11'] 177 xpath = '//select[@name="wchan"]' 178 self.select_item_from_popup_by_xpath(channel_choices[position], xpath) 179 180 181 def set_mode(self, mode): 182 self.add_item_to_command_list(self._set_mode, (mode,), 1, 900) 183 184 185 def _set_mode(self, mode): 186 mode_mapping = {ap_spec.MODE_G: '802.11g', 187 ap_spec.MODE_N: '802.11n', 188 ap_spec.MODE_B | ap_spec.MODE_G | ap_spec.MODE_N: 189 '802.11b&802.11g&802.11n'} 190 mode_name = mode_mapping.get(mode) 191 if not mode_name: 192 raise RuntimeError('The mode %d not supported by router %s. ', 193 hex(mode), self.name) 194 xpath = '//select[@name="wbr"]' 195 self.wait_for_object_by_xpath(xpath) 196 while self.number_of_items_in_popup_by_xpath(xpath) < 3: 197 time.sleep(0.25) 198 self.select_item_from_popup_by_xpath(mode_name, xpath, 199 wait_for_xpath=None, 200 alert_handler=self._security_alert) 201 202 203 def set_ch_width(self, channel_width): 204 """ 205 Adjusts the channel width. 206 207 @param channel_width: the channel width 208 """ 209 self.add_item_to_command_list(self._set_ch_width,(channel_width,), 210 1, 900) 211 212 213 def _set_ch_width(self, channel_width): 214 channel_choice = ['20MHz', '20/40MHz'] 215 xpath = '//select[@name="bandwidth"]' 216 self.select_item_from_popup_by_xpath(channel_choice[channel_width], 217 xpath) 218 219 220 def set_radio(self, enabled=True): 221 logging.debug('This router (%s) does not support radio', self.name) 222 return None 223 224 225 def set_band(self, band): 226 logging.debug('This router %s does not support multiple bands.', 227 self.name) 228 return None 229 230 231 def set_security_disabled(self): 232 self.add_item_to_command_list(self._set_security_disabled, (), 2, 1000) 233 234 235 def _set_security_disabled(self): 236 self.select_item_from_popup_by_xpath('Disabled', 237 self.security_popup, 238 alert_handler=self._security_alert) 239 240 241 def set_security_wep(self, key_value, authentication): 242 self.add_item_to_command_list(self._set_security_wep, 243 (key_value, authentication), 2, 1000) 244 245 246 def _set_security_wep(self, key_value, authentication): 247 text_field = '//input[@name="passphrase"]' 248 try: 249 self.select_item_from_popup_by_xpath('64bit WEP', 250 self.security_popup, wait_for_xpath=text_field, 251 alert_handler=self._security_alert) 252 except WebDriverException, e: 253 message = str(e) 254 if message.find('An open modal dialog blocked') == -1: 255 raise RuntimeError(message) 256 return 257 self._security_alert(self.driver.switch_to_alert()) 258 self.set_content_of_text_field_by_xpath(key_value, text_field, 259 abort_check=True) 260 self.click_button_by_xpath('//input[@class="submitBtn" and ' 261 '@value="Generate"]', 262 alert_handler=self._security_alert) 263 264 265 def set_security_wpapsk(self, security, shared_key, update_interval=None): 266 self.add_item_to_command_list(self._set_security_wpapsk, 267 (security, shared_key, update_interval), 268 2, 900) 269 270 271 def _set_security_wpapsk(self, security, shared_key, update_interval=None): 272 key_field = '//input[@name="wpa_key_pass"]' 273 psk = '//select[@name="authentication"]' 274 self.select_item_from_popup_by_xpath('WPA/WPA2-Personal (PSK)', 275 self.security_popup, 276 wait_for_xpath=key_field, 277 alert_handler=self._security_alert) 278 auth_type = 'WPA-PSK' 279 if security == ap_spec.SECURITY_TYPE_WPA2PSK: 280 auth_type = 'WPA2-PSK' 281 self.select_item_from_popup_by_xpath(auth_type, psk, 282 wait_for_xpath=key_field, 283 alert_handler=self._security_alert) 284 self.set_content_of_text_field_by_xpath(shared_key, key_field, 285 abort_check=True) 286 287 288 def is_visibility_supported(self): 289 """ 290 Returns if AP supports setting the visibility (SSID broadcast). 291 292 @return True if supported; False otherwise. 293 """ 294 return False 295 296 297 def is_update_interval_supported(self): 298 """ 299 Returns True if setting the PSK refresh interval is supported. 300 301 @return True is supported; False otherwise 302 """ 303 return False 304