Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 1 | #!/usr/bin/env python3.4 |
| 2 | # |
| 3 | # Copyright 2017 - The Android Open Source Project |
| 4 | # |
| 5 | # Licensed under the Apache License, Version 2.0 (the "License"); |
| 6 | # you may not use this file except in compliance with the License. |
| 7 | # You may obtain a copy of the License at |
| 8 | # |
| 9 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 10 | # |
| 11 | # Unless required by applicable law or agreed to in writing, software |
| 12 | # distributed under the License is distributed on an "AS IS" BASIS, |
| 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 14 | # See the License for the specific language governing permissions and |
| 15 | # limitations under the License. |
| 16 | import splinter |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 17 | import time |
| 18 | from acts.libs.proc import job |
android-build-prod (mdb) | dd7347e | 2018-05-03 23:13:56 -0700 | [diff] [blame] | 19 | from selenium.webdriver.common.desired_capabilities import DesiredCapabilities |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 20 | |
| 21 | BROWSER_WAIT_SHORT = 1 |
| 22 | BROWSER_WAIT_MED = 3 |
Omar El Ayach | d0c4b94 | 2018-01-30 06:02:14 +0000 | [diff] [blame] | 23 | BROWSER_WAIT_LONG = 30 |
| 24 | BROWSER_WAIT_EXTRA_LONG = 60 |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 25 | |
| 26 | |
| 27 | def create(configs): |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 28 | """Factory method for retail AP class. |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 29 | |
| 30 | Args: |
| 31 | configs: list of dicts containing ap settings. ap settings must contain |
| 32 | the following: brand, model, ip_address, username and password |
| 33 | """ |
| 34 | SUPPORTED_APS = { |
| 35 | ("Netgear", "R7000"): "NetgearR7000AP", |
| 36 | ("Netgear", "R7500"): "NetgearR7500AP", |
Omar El Ayach | d4bc7ac | 2018-05-09 19:47:26 -0700 | [diff] [blame] | 37 | ("Netgear", "R7800"): "NetgearR7800AP", |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 38 | ("Netgear", "R8000"): "NetgearR8000AP" |
| 39 | } |
| 40 | objs = [] |
| 41 | for config in configs: |
| 42 | try: |
| 43 | ap_class_name = SUPPORTED_APS[(config["brand"], config["model"])] |
| 44 | ap_class = globals()[ap_class_name] |
| 45 | except KeyError: |
| 46 | raise KeyError("Invalid retail AP brand and model combination.") |
| 47 | objs.append(ap_class(config)) |
| 48 | return objs |
| 49 | |
| 50 | |
| 51 | def detroy(objs): |
| 52 | return |
| 53 | |
| 54 | |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 55 | def start_chrome_browser(headless, max_allowed_sessions, timeout): |
| 56 | """Method to start chrome browser for retail AP configuration |
| 57 | |
| 58 | This function starts a chrome browser session to interface with the APs |
| 59 | web interface. The function attempts to maintain only one chromedriver |
| 60 | session by waiting until no chromedriver sessions are running on a machine. |
| 61 | |
| 62 | Args: |
| 63 | headless: boolean controlling headless operation |
| 64 | max_allowed_sessions: maximum number of concurrent chrome sessions |
| 65 | timeout: maximum waiting time to launch chrome session |
| 66 | Returns: |
| 67 | browser: chrome browser session |
| 68 | Raises: |
| 69 | TimeoutError: raised when a browser session could not be started |
| 70 | withing the specified timeout |
| 71 | """ |
| 72 | chrome_options = splinter.driver.webdriver.chrome.Options() |
| 73 | chrome_options.add_argument("--no-proxy-server") |
| 74 | chrome_options.add_argument("--no-sandbox") |
| 75 | chrome_options.add_argument("--allow-running-insecure-content") |
| 76 | chrome_options.add_argument("--ignore-certificate-errors") |
| 77 | chrome_capabilities = DesiredCapabilities.CHROME.copy() |
| 78 | chrome_capabilities["acceptSslCerts"] = True |
| 79 | chrome_capabilities["acceptInsecureCerts"] = True |
| 80 | if headless: |
| 81 | chrome_options.add_argument("--headless") |
| 82 | chrome_options.add_argument("--disable-gpu") |
| 83 | |
| 84 | start_time = time.time() |
| 85 | end_time = start_time + timeout |
| 86 | while time.time() < end_time: |
| 87 | browsers_running = int(job.run('pgrep chromedriver | wc -l').stdout) |
| 88 | if browsers_running >= max_allowed_sessions: |
| 89 | time.sleep(BROWSER_WAIT_SHORT) |
| 90 | else: |
| 91 | try: |
| 92 | browser = splinter.Browser( |
| 93 | "chrome", |
| 94 | options=chrome_options, |
| 95 | desired_capabilities=chrome_capabilities) |
| 96 | return browser |
| 97 | except: |
| 98 | time.sleep(BROWSER_WAIT_SHORT) |
| 99 | raise TimeoutError("Could not start chrome browser in time.") |
| 100 | |
| 101 | |
android-build-prod (mdb) | 70753e8 | 2018-05-02 17:54:37 -0700 | [diff] [blame] | 102 | def visit_config_page(browser, url, page_load_timeout, num_tries): |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 103 | """Method to visit Netgear AP webpages. |
android-build-prod (mdb) | 70753e8 | 2018-05-02 17:54:37 -0700 | [diff] [blame] | 104 | |
| 105 | This function visits a web page and checks the the resulting URL matches |
| 106 | the intended URL, i.e. no redirects have happened |
| 107 | |
| 108 | Args: |
| 109 | browser: the splinter browser object that will visit the URL |
| 110 | url: the intended url |
| 111 | num_tries: number of tries before url is declared unreachable |
| 112 | """ |
| 113 | browser.driver.set_page_load_timeout(page_load_timeout) |
| 114 | for idx in range(num_tries): |
| 115 | try: |
| 116 | browser.visit(url) |
| 117 | except: |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 118 | browser.visit("about:blank") |
android-build-prod (mdb) | 70753e8 | 2018-05-02 17:54:37 -0700 | [diff] [blame] | 119 | if browser.url.split("/")[-1] == url.split("/")[-1]: |
| 120 | break |
| 121 | if idx == num_tries - 1: |
android-build-prod (mdb) | 70753e8 | 2018-05-02 17:54:37 -0700 | [diff] [blame] | 122 | raise RuntimeError("URL was unreachable.") |
| 123 | |
| 124 | |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 125 | class WifiRetailAP(object): |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 126 | """Base class implementation for retail ap. |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 127 | |
| 128 | Base class provides functions whose implementation is shared by all aps. |
| 129 | If some functions such as set_power not supported by ap, checks will raise |
| 130 | exceptions. |
| 131 | """ |
| 132 | |
| 133 | def __init__(self, ap_settings): |
| 134 | raise NotImplementedError |
| 135 | |
| 136 | def read_ap_settings(self): |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 137 | """Function that reads current ap settings. |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 138 | |
| 139 | Function implementation is AP dependent and thus base class raises exception |
| 140 | if function not implemented in child class. |
| 141 | """ |
| 142 | raise NotImplementedError |
| 143 | |
Omar El Ayach | d4bc7ac | 2018-05-09 19:47:26 -0700 | [diff] [blame] | 144 | def validate_ap_settings(self): |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 145 | """Function to validate ap settings. |
Omar El Ayach | d4bc7ac | 2018-05-09 19:47:26 -0700 | [diff] [blame] | 146 | |
| 147 | This function compares the actual ap settings read from the web GUI |
| 148 | with the assumed settings saved in the AP object. When called after AP |
| 149 | configuration, this method helps ensure that our configuration was |
| 150 | successful. |
| 151 | |
| 152 | Raises: |
| 153 | ValueError: If read AP settings do not match stored settings. |
| 154 | """ |
| 155 | assumed_ap_settings = self.ap_settings.copy() |
| 156 | actual_ap_settings = self.read_ap_settings() |
| 157 | if assumed_ap_settings != actual_ap_settings: |
| 158 | raise ValueError( |
| 159 | "Discrepancy in AP settings. Potential configuration error.") |
| 160 | |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 161 | def configure_ap(self): |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 162 | """Function that configures ap based on values of ap_settings. |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 163 | |
| 164 | Function implementation is AP dependent and thus base class raises exception |
| 165 | if function not implemented in child class. |
| 166 | """ |
| 167 | raise NotImplementedError |
| 168 | |
Omar El Ayach | d0c4b94 | 2018-01-30 06:02:14 +0000 | [diff] [blame] | 169 | def set_radio_on_off(self, network, status): |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 170 | """Function that turns the radio on or off. |
Omar El Ayach | d0c4b94 | 2018-01-30 06:02:14 +0000 | [diff] [blame] | 171 | |
| 172 | Args: |
| 173 | network: string containing network identifier (2G, 5G_1, 5G_2) |
| 174 | status: boolean indicating on or off (0: off, 1: on) |
| 175 | """ |
| 176 | setting_to_update = {"status_{}".format(network): int(status)} |
| 177 | self.update_ap_settings(setting_to_update) |
| 178 | |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 179 | def set_ssid(self, network, ssid): |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 180 | """Function that sets network SSID. |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 181 | |
| 182 | Args: |
| 183 | network: string containing network identifier (2G, 5G_1, 5G_2) |
| 184 | ssid: string containing ssid |
| 185 | """ |
| 186 | setting_to_update = {"ssid_{}".format(network): str(ssid)} |
| 187 | self.update_ap_settings(setting_to_update) |
| 188 | |
| 189 | def set_channel(self, network, channel): |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 190 | """Function that sets network channel. |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 191 | |
| 192 | Args: |
| 193 | network: string containing network identifier (2G, 5G_1, 5G_2) |
| 194 | channel: string or int containing channel |
| 195 | """ |
| 196 | setting_to_update = {"channel_{}".format(network): str(channel)} |
| 197 | self.update_ap_settings(setting_to_update) |
| 198 | |
| 199 | def set_bandwidth(self, network, bandwidth): |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 200 | """Function that sets network bandwidth/mode. |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 201 | |
| 202 | Args: |
| 203 | network: string containing network identifier (2G, 5G_1, 5G_2) |
| 204 | bandwidth: string containing mode, e.g. 11g, VHT20, VHT40, VHT80. |
| 205 | """ |
| 206 | setting_to_update = {"bandwidth_{}".format(network): str(bandwidth)} |
| 207 | self.update_ap_settings(setting_to_update) |
| 208 | |
| 209 | def set_power(self, network, power): |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 210 | """Function that sets network transmit power. |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 211 | |
| 212 | Args: |
| 213 | network: string containing network identifier (2G, 5G_1, 5G_2) |
| 214 | power: string containing power level, e.g., 25%, 100% |
| 215 | """ |
| 216 | setting_to_update = {"power_{}".format(network): str(power)} |
| 217 | self.update_ap_settings(setting_to_update) |
| 218 | |
| 219 | def set_security(self, network, security_type, *password): |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 220 | """Function that sets network security setting and password. |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 221 | |
| 222 | Args: |
| 223 | network: string containing network identifier (2G, 5G_1, 5G_2) |
| 224 | security: string containing security setting, e.g., WPA2-PSK |
| 225 | password: optional argument containing password |
| 226 | """ |
| 227 | if (len(password) == 1) and (type(password[0]) == str): |
| 228 | setting_to_update = { |
| 229 | "security_type_{}".format(network): str(security_type), |
| 230 | "password_{}".format(network): str(password[0]) |
| 231 | } |
| 232 | else: |
| 233 | setting_to_update = { |
| 234 | "security_type_{}".format(network): str(security_type) |
| 235 | } |
| 236 | self.update_ap_settings(setting_to_update) |
| 237 | |
| 238 | def update_ap_settings(self, *dict_settings, **named_settings): |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 239 | """Function to update settings of existing AP. |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 240 | |
| 241 | Function copies arguments into ap_settings and calls configure_retail_ap |
| 242 | to apply them. |
| 243 | |
| 244 | Args: |
| 245 | *dict_settings accepts single dictionary of settings to update |
| 246 | **named_settings accepts named settings to update |
| 247 | Note: dict and named_settings cannot contain the same settings. |
| 248 | """ |
| 249 | settings_to_update = {} |
| 250 | if (len(dict_settings) == 1) and (type(dict_settings[0]) == dict): |
| 251 | for key, value in dict_settings[0].items(): |
| 252 | if key in named_settings: |
| 253 | raise KeyError("{} was passed twice.".format(key)) |
| 254 | else: |
| 255 | settings_to_update[key] = value |
| 256 | elif len(dict_settings) > 1: |
| 257 | raise TypeError("Wrong number of positional arguments given") |
| 258 | return |
| 259 | |
| 260 | for key, value in named_settings.items(): |
| 261 | settings_to_update[key] = value |
| 262 | |
Omar El Ayach | 7331ba8 | 2018-01-03 22:52:34 +0000 | [diff] [blame] | 263 | updates_requested = False |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 264 | for key, value in settings_to_update.items(): |
| 265 | if (key in self.ap_settings): |
Omar El Ayach | 7331ba8 | 2018-01-03 22:52:34 +0000 | [diff] [blame] | 266 | if self.ap_settings[key] != value: |
| 267 | self.ap_settings[key] = value |
| 268 | updates_requested = True |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 269 | else: |
| 270 | raise KeyError("Invalid setting passed to AP configuration.") |
| 271 | |
Omar El Ayach | 7331ba8 | 2018-01-03 22:52:34 +0000 | [diff] [blame] | 272 | if updates_requested: |
| 273 | self.configure_ap() |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 274 | |
Omar El Ayach | 9be1c3c | 2017-12-27 19:20:56 +0000 | [diff] [blame] | 275 | def band_lookup_by_channel(self, channel): |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 276 | """Function that gives band name by channel number. |
Omar El Ayach | 9be1c3c | 2017-12-27 19:20:56 +0000 | [diff] [blame] | 277 | |
| 278 | Args: |
| 279 | channel: channel number to lookup |
| 280 | Returns: |
| 281 | band: name of band which this channel belongs to on this ap |
| 282 | """ |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 283 | for key, value in self.channel_band_map.items(): |
Omar El Ayach | 9be1c3c | 2017-12-27 19:20:56 +0000 | [diff] [blame] | 284 | if channel in value: |
| 285 | return key |
| 286 | raise ValueError("Invalid channel passed in argument.") |
| 287 | |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 288 | |
| 289 | class NetgearR7000AP(WifiRetailAP): |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 290 | """Class that implements Netgear R7500 AP.""" |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 291 | |
| 292 | def __init__(self, ap_settings): |
| 293 | self.ap_settings = ap_settings.copy() |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 294 | self.init_gui_data() |
| 295 | # Read and update AP settings |
| 296 | self.read_ap_settings() |
| 297 | if ap_settings.items() <= self.ap_settings.items(): |
| 298 | return |
| 299 | else: |
| 300 | self.update_ap_settings(ap_settings) |
| 301 | |
| 302 | def init_gui_data(self): |
| 303 | """Function to initialize data used while interacting with web GUI""" |
| 304 | self.config_page = "{}://{}:{}@{}:{}/WLG_wireless_dual_band_r10.htm".format( |
android-build-prod (mdb) | 70753e8 | 2018-05-02 17:54:37 -0700 | [diff] [blame] | 305 | self.ap_settings["protocol"], self.ap_settings["admin_username"], |
| 306 | self.ap_settings["admin_password"], self.ap_settings["ip_address"], |
| 307 | self.ap_settings["port"]) |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 308 | self.config_page_nologin = "{}://{}:{}/WLG_wireless_dual_band_r10.htm".format( |
android-build-prod (mdb) | 70753e8 | 2018-05-02 17:54:37 -0700 | [diff] [blame] | 309 | self.ap_settings["protocol"], self.ap_settings["ip_address"], |
| 310 | self.ap_settings["port"]) |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 311 | self.config_page_advanced = "{}://{}:{}/WLG_adv_dual_band2.htm".format( |
android-build-prod (mdb) | 70753e8 | 2018-05-02 17:54:37 -0700 | [diff] [blame] | 312 | self.ap_settings["protocol"], self.ap_settings["ip_address"], |
| 313 | self.ap_settings["port"]) |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 314 | self.networks = ["2G", "5G_1"] |
| 315 | self.channel_band_map = { |
Omar El Ayach | 9be1c3c | 2017-12-27 19:20:56 +0000 | [diff] [blame] | 316 | "2G": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], |
Omar El Ayach | d0c4b94 | 2018-01-30 06:02:14 +0000 | [diff] [blame] | 317 | "5G_1": [ |
| 318 | 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, |
| 319 | 124, 128, 132, 136, 140, 149, 153, 157, 161, 165 |
| 320 | ] |
| 321 | } |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 322 | self.region_map = { |
Omar El Ayach | d0c4b94 | 2018-01-30 06:02:14 +0000 | [diff] [blame] | 323 | "1": "Africa", |
| 324 | "2": "Asia", |
| 325 | "3": "Australia", |
| 326 | "4": "Canada", |
| 327 | "5": "Europe", |
| 328 | "6": "Israel", |
| 329 | "7": "Japan", |
| 330 | "8": "Korea", |
| 331 | "9": "Mexico", |
| 332 | "10": "South America", |
| 333 | "11": "United States", |
| 334 | "12": "Middle East(Algeria/Syria/Yemen)", |
| 335 | "14": "Russia", |
| 336 | "16": "China", |
| 337 | "17": "India", |
| 338 | "18": "Malaysia", |
| 339 | "19": "Middle East(Iran/Labanon/Qatar)", |
| 340 | "20": "Middle East(Turkey/Egypt/Tunisia/Kuwait)", |
| 341 | "21": "Middle East(Saudi Arabia)", |
| 342 | "22": "Middle East(United Arab Emirates)", |
| 343 | "23": "Singapore", |
| 344 | "24": "Taiwan" |
Omar El Ayach | 9be1c3c | 2017-12-27 19:20:56 +0000 | [diff] [blame] | 345 | } |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 346 | self.config_page_fields = { |
Omar El Ayach | d0c4b94 | 2018-01-30 06:02:14 +0000 | [diff] [blame] | 347 | "region": "WRegion", |
| 348 | ("2G", "status"): "enable_ap", |
| 349 | ("5G_1", "status"): "enable_ap_an", |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 350 | ("2G", "ssid"): "ssid", |
| 351 | ("5G_1", "ssid"): "ssid_an", |
| 352 | ("2G", "channel"): "w_channel", |
| 353 | ("5G_1", "channel"): "w_channel_an", |
| 354 | ("2G", "bandwidth"): "opmode", |
| 355 | ("5G_1", "bandwidth"): "opmode_an", |
| 356 | ("2G", "power"): "enable_tpc", |
| 357 | ("5G_1", "power"): "enable_tpc_an", |
| 358 | ("2G", "security_type"): "security_type", |
| 359 | ("5G_1", "security_type"): "security_type_an", |
| 360 | ("2G", "password"): "passphrase", |
| 361 | ("5G_1", "password"): "passphrase_an" |
| 362 | } |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 363 | self.bw_mode_values = { |
Omar El Ayach | d4bc7ac | 2018-05-09 19:47:26 -0700 | [diff] [blame] | 364 | "g and b": "11g", |
| 365 | "145Mbps": "VHT20", |
| 366 | "300Mbps": "VHT40", |
| 367 | "HT80": "VHT80" |
| 368 | } |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 369 | self.power_mode_values = { |
Omar El Ayach | d4bc7ac | 2018-05-09 19:47:26 -0700 | [diff] [blame] | 370 | "1": "100%", |
| 371 | "2": "75%", |
| 372 | "3": "50%", |
| 373 | "4": "25%" |
| 374 | } |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 375 | self.bw_mode_text = { |
Omar El Ayach | d4bc7ac | 2018-05-09 19:47:26 -0700 | [diff] [blame] | 376 | "11g": "Up to 54 Mbps", |
| 377 | "VHT20": "Up to 289 Mbps", |
| 378 | "VHT40": "Up to 600 Mbps", |
| 379 | "VHT80": "Up to 1300 Mbps" |
| 380 | } |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 381 | |
| 382 | def read_ap_settings(self): |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 383 | """Function to read ap settings.""" |
| 384 | with start_chrome_browser(self.ap_settings["headless_browser"], 1, |
| 385 | 600) as browser: |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 386 | # Visit URL |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 387 | visit_config_page(browser, self.config_page, BROWSER_WAIT_MED, 10) |
| 388 | visit_config_page(browser, self.config_page_nologin, |
android-build-prod (mdb) | 70753e8 | 2018-05-02 17:54:37 -0700 | [diff] [blame] | 389 | BROWSER_WAIT_MED, 10) |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 390 | |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 391 | for key, value in self.config_page_fields.items(): |
Omar El Ayach | d0c4b94 | 2018-01-30 06:02:14 +0000 | [diff] [blame] | 392 | if "status" in key: |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 393 | visit_config_page(browser, self.config_page_advanced, |
android-build-prod (mdb) | 70753e8 | 2018-05-02 17:54:37 -0700 | [diff] [blame] | 394 | BROWSER_WAIT_MED, 10) |
Omar El Ayach | d0c4b94 | 2018-01-30 06:02:14 +0000 | [diff] [blame] | 395 | config_item = browser.find_by_name(value) |
| 396 | self.ap_settings["{}_{}".format(key[1], key[0])] = int( |
| 397 | config_item.first.checked) |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 398 | visit_config_page(browser, self.config_page_nologin, |
android-build-prod (mdb) | 70753e8 | 2018-05-02 17:54:37 -0700 | [diff] [blame] | 399 | BROWSER_WAIT_MED, 10) |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 400 | else: |
Omar El Ayach | d0c4b94 | 2018-01-30 06:02:14 +0000 | [diff] [blame] | 401 | config_item = browser.find_by_name(value) |
| 402 | if "bandwidth" in key: |
Omar El Ayach | d0c4b94 | 2018-01-30 06:02:14 +0000 | [diff] [blame] | 403 | self.ap_settings["{}_{}".format(key[1], key[ |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 404 | 0])] = self.bw_mode_values[config_item.first.value] |
Omar El Ayach | d4bc7ac | 2018-05-09 19:47:26 -0700 | [diff] [blame] | 405 | elif "power" in key: |
| 406 | self.ap_settings["{}_{}".format( |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 407 | key[1], key[0])] = self.power_mode_values[ |
Omar El Ayach | d4bc7ac | 2018-05-09 19:47:26 -0700 | [diff] [blame] | 408 | config_item.first.value] |
Omar El Ayach | d0c4b94 | 2018-01-30 06:02:14 +0000 | [diff] [blame] | 409 | elif "region" in key: |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 410 | self.ap_settings["region"] = self.region_map[ |
Omar El Ayach | d0c4b94 | 2018-01-30 06:02:14 +0000 | [diff] [blame] | 411 | config_item.first.value] |
| 412 | elif "security_type" in key: |
| 413 | for item in config_item: |
| 414 | if item.checked: |
| 415 | self.ap_settings["{}_{}".format( |
| 416 | key[1], key[0])] = item.value |
| 417 | else: |
| 418 | config_item = browser.find_by_name(value) |
android-build-prod (mdb) | 70753e8 | 2018-05-02 17:54:37 -0700 | [diff] [blame] | 419 | self.ap_settings["{}_{}".format( |
| 420 | key[1], key[0])] = config_item.first.value |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 421 | return self.ap_settings.copy() |
| 422 | |
| 423 | def configure_ap(self): |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 424 | """Function to configure ap wireless settings.""" |
Omar El Ayach | d0c4b94 | 2018-01-30 06:02:14 +0000 | [diff] [blame] | 425 | # Turn radios on or off |
| 426 | self.configure_radio_on_off() |
| 427 | # Configure radios |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 428 | with start_chrome_browser(self.ap_settings["headless_browser"], 1, |
| 429 | 600) as browser: |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 430 | # Visit URL |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 431 | visit_config_page(browser, self.config_page, BROWSER_WAIT_MED, 10) |
| 432 | visit_config_page(browser, self.config_page_nologin, |
android-build-prod (mdb) | 70753e8 | 2018-05-02 17:54:37 -0700 | [diff] [blame] | 433 | BROWSER_WAIT_MED, 10) |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 434 | |
Omar El Ayach | d0c4b94 | 2018-01-30 06:02:14 +0000 | [diff] [blame] | 435 | # Update region, and power/bandwidth for each network |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 436 | for key, value in self.config_page_fields.items(): |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 437 | if "power" in key: |
Omar El Ayach | d0c4b94 | 2018-01-30 06:02:14 +0000 | [diff] [blame] | 438 | config_item = browser.find_by_name(value).first |
android-build-prod (mdb) | 70753e8 | 2018-05-02 17:54:37 -0700 | [diff] [blame] | 439 | config_item.select_by_text(self.ap_settings["{}_{}".format( |
| 440 | key[1], key[0])]) |
Omar El Ayach | d0c4b94 | 2018-01-30 06:02:14 +0000 | [diff] [blame] | 441 | elif "region" in key: |
| 442 | config_item = browser.find_by_name(value).first |
| 443 | config_item.select_by_text(self.ap_settings["region"]) |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 444 | elif "bandwidth" in key: |
Omar El Ayach | d0c4b94 | 2018-01-30 06:02:14 +0000 | [diff] [blame] | 445 | config_item = browser.find_by_name(value).first |
android-build-prod (mdb) | 70753e8 | 2018-05-02 17:54:37 -0700 | [diff] [blame] | 446 | config_item.select_by_text( |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 447 | self.bw_mode_text[self.ap_settings["{}_{}".format( |
android-build-prod (mdb) | 70753e8 | 2018-05-02 17:54:37 -0700 | [diff] [blame] | 448 | key[1], key[0])]]) |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 449 | |
| 450 | # Update security settings (passwords updated only if applicable) |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 451 | for key, value in self.config_page_fields.items(): |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 452 | if "security_type" in key: |
android-build-prod (mdb) | 70753e8 | 2018-05-02 17:54:37 -0700 | [diff] [blame] | 453 | browser.choose(value, self.ap_settings["{}_{}".format( |
| 454 | key[1], key[0])]) |
| 455 | if self.ap_settings["{}_{}".format(key[1], |
| 456 | key[0])] == "WPA2-PSK": |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 457 | config_item = browser.find_by_name( |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 458 | self.config_page_fields[(key[0], |
android-build-prod (mdb) | 70753e8 | 2018-05-02 17:54:37 -0700 | [diff] [blame] | 459 | "password")]).first |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 460 | config_item.fill(self.ap_settings["{}_{}".format( |
| 461 | "password", key[0])]) |
| 462 | |
| 463 | # Update SSID and channel for each network |
| 464 | # NOTE: Update ordering done as such as workaround for R8000 |
| 465 | # wherein channel and SSID get overwritten when some other |
Omar El Ayach | d0c4b94 | 2018-01-30 06:02:14 +0000 | [diff] [blame] | 466 | # variables are changed. However, region does have to be set before |
| 467 | # channel in all cases. |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 468 | for key, value in self.config_page_fields.items(): |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 469 | if "ssid" in key: |
Omar El Ayach | d0c4b94 | 2018-01-30 06:02:14 +0000 | [diff] [blame] | 470 | config_item = browser.find_by_name(value).first |
android-build-prod (mdb) | 70753e8 | 2018-05-02 17:54:37 -0700 | [diff] [blame] | 471 | config_item.fill(self.ap_settings["{}_{}".format( |
| 472 | key[1], key[0])]) |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 473 | elif "channel" in key: |
Omar El Ayach | d0c4b94 | 2018-01-30 06:02:14 +0000 | [diff] [blame] | 474 | config_item = browser.find_by_name(value).first |
android-build-prod (mdb) | 70753e8 | 2018-05-02 17:54:37 -0700 | [diff] [blame] | 475 | config_item.select(self.ap_settings["{}_{}".format( |
| 476 | key[1], key[0])]) |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 477 | time.sleep(BROWSER_WAIT_SHORT) |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 478 | try: |
| 479 | alert = browser.get_alert() |
| 480 | alert.accept() |
| 481 | except: |
| 482 | pass |
| 483 | |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 484 | time.sleep(BROWSER_WAIT_SHORT) |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 485 | browser.find_by_name("Apply").first.click() |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 486 | time.sleep(BROWSER_WAIT_SHORT) |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 487 | try: |
| 488 | alert = browser.get_alert() |
| 489 | alert.accept() |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 490 | time.sleep(BROWSER_WAIT_SHORT) |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 491 | except: |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 492 | time.sleep(BROWSER_WAIT_SHORT) |
| 493 | visit_config_page(browser, self.config_page, |
android-build-prod (mdb) | 70753e8 | 2018-05-02 17:54:37 -0700 | [diff] [blame] | 494 | BROWSER_WAIT_EXTRA_LONG, 10) |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 495 | self.validate_ap_settings() |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 496 | |
Omar El Ayach | d0c4b94 | 2018-01-30 06:02:14 +0000 | [diff] [blame] | 497 | def configure_radio_on_off(self): |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 498 | """Helper configuration function to turn radios on/off.""" |
| 499 | with start_chrome_browser(self.ap_settings["headless_browser"], 1, |
| 500 | 600) as browser: |
Omar El Ayach | d0c4b94 | 2018-01-30 06:02:14 +0000 | [diff] [blame] | 501 | # Visit URL |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 502 | visit_config_page(browser, self.config_page, BROWSER_WAIT_MED, 10) |
| 503 | visit_config_page(browser, self.config_page_advanced, |
android-build-prod (mdb) | 70753e8 | 2018-05-02 17:54:37 -0700 | [diff] [blame] | 504 | BROWSER_WAIT_MED, 10) |
Omar El Ayach | d0c4b94 | 2018-01-30 06:02:14 +0000 | [diff] [blame] | 505 | |
| 506 | # Turn radios on or off |
| 507 | status_toggled = False |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 508 | for key, value in self.config_page_fields.items(): |
Omar El Ayach | d0c4b94 | 2018-01-30 06:02:14 +0000 | [diff] [blame] | 509 | if "status" in key: |
| 510 | config_item = browser.find_by_name(value).first |
| 511 | current_status = int(config_item.checked) |
| 512 | if current_status != self.ap_settings["{}_{}".format( |
| 513 | key[1], key[0])]: |
| 514 | status_toggled = True |
| 515 | if self.ap_settings["{}_{}".format(key[1], key[0])]: |
| 516 | config_item.check() |
| 517 | else: |
| 518 | config_item.uncheck() |
| 519 | |
| 520 | if status_toggled: |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 521 | time.sleep(BROWSER_WAIT_SHORT) |
Omar El Ayach | d0c4b94 | 2018-01-30 06:02:14 +0000 | [diff] [blame] | 522 | browser.find_by_name("Apply").first.click() |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 523 | time.sleep(BROWSER_WAIT_EXTRA_LONG) |
| 524 | visit_config_page(browser, self.config_page, |
android-build-prod (mdb) | 70753e8 | 2018-05-02 17:54:37 -0700 | [diff] [blame] | 525 | BROWSER_WAIT_EXTRA_LONG, 10) |
Omar El Ayach | d0c4b94 | 2018-01-30 06:02:14 +0000 | [diff] [blame] | 526 | |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 527 | |
| 528 | class NetgearR7500AP(WifiRetailAP): |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 529 | """Class that implements Netgear R7500 AP.""" |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 530 | |
| 531 | def __init__(self, ap_settings): |
| 532 | self.ap_settings = ap_settings.copy() |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 533 | self.init_gui_data() |
| 534 | # Read and update AP settings |
| 535 | self.read_ap_settings() |
| 536 | if ap_settings.items() <= self.ap_settings.items(): |
| 537 | return |
| 538 | else: |
| 539 | self.update_ap_settings(ap_settings) |
| 540 | |
| 541 | def init_gui_data(self): |
| 542 | """Function to initialize data used while interacting with web GUI""" |
| 543 | self.config_page = "{}://{}:{}@{}:{}/index.htm".format( |
Omar El Ayach | d4bc7ac | 2018-05-09 19:47:26 -0700 | [diff] [blame] | 544 | self.ap_settings["protocol"], self.ap_settings["admin_username"], |
| 545 | self.ap_settings["admin_password"], self.ap_settings["ip_address"], |
| 546 | self.ap_settings["port"]) |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 547 | self.config_page_nologin = "{}://{}:{}/index.htm".format( |
Omar El Ayach | d4bc7ac | 2018-05-09 19:47:26 -0700 | [diff] [blame] | 548 | self.ap_settings["protocol"], self.ap_settings["ip_address"], |
| 549 | self.ap_settings["port"]) |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 550 | self.config_page_advanced = "{}://{}:{}/adv_index.htm".format( |
Omar El Ayach | d4bc7ac | 2018-05-09 19:47:26 -0700 | [diff] [blame] | 551 | self.ap_settings["protocol"], self.ap_settings["ip_address"], |
| 552 | self.ap_settings["port"]) |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 553 | self.networks = ["2G", "5G_1"] |
| 554 | self.channel_band_map = { |
Omar El Ayach | 9be1c3c | 2017-12-27 19:20:56 +0000 | [diff] [blame] | 555 | "2G": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], |
Omar El Ayach | d0c4b94 | 2018-01-30 06:02:14 +0000 | [diff] [blame] | 556 | "5G_1": [ |
| 557 | 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, |
| 558 | 124, 128, 132, 136, 140, 149, 153, 157, 161, 165 |
| 559 | ] |
Omar El Ayach | 9be1c3c | 2017-12-27 19:20:56 +0000 | [diff] [blame] | 560 | } |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 561 | self.config_page_fields = { |
Omar El Ayach | d0c4b94 | 2018-01-30 06:02:14 +0000 | [diff] [blame] | 562 | "region": "WRegion", |
| 563 | ("2G", "status"): "enable_ap", |
| 564 | ("5G_1", "status"): "enable_ap_an", |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 565 | ("2G", "ssid"): "ssid", |
| 566 | ("5G_1", "ssid"): "ssid_an", |
| 567 | ("2G", "channel"): "w_channel", |
| 568 | ("5G_1", "channel"): "w_channel_an", |
| 569 | ("2G", "bandwidth"): "opmode", |
| 570 | ("5G_1", "bandwidth"): "opmode_an", |
| 571 | ("2G", "security_type"): "security_type", |
| 572 | ("5G_1", "security_type"): "security_type_an", |
| 573 | ("2G", "password"): "passphrase", |
| 574 | ("5G_1", "password"): "passphrase_an" |
| 575 | } |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 576 | self.region_map = { |
Omar El Ayach | d0c4b94 | 2018-01-30 06:02:14 +0000 | [diff] [blame] | 577 | "0": "Africa", |
| 578 | "1": "Asia", |
| 579 | "2": "Australia", |
| 580 | "3": "Canada", |
| 581 | "4": "Europe", |
| 582 | "5": "Israel", |
| 583 | "6": "Japan", |
| 584 | "7": "Korea", |
| 585 | "8": "Mexico", |
| 586 | "9": "South America", |
| 587 | "10": "United States", |
| 588 | "11": "China", |
| 589 | "12": "India", |
| 590 | "13": "Malaysia", |
| 591 | "14": "Middle East(Algeria/Syria/Yemen)", |
| 592 | "15": "Middle East(Iran/Labanon/Qatar)", |
| 593 | "16": "Middle East(Turkey/Egypt/Tunisia/Kuwait)", |
| 594 | "17": "Middle East(Saudi Arabia)", |
| 595 | "18": "Middle East(United Arab Emirates)", |
| 596 | "19": "Russia", |
| 597 | "20": "Singapore", |
| 598 | "21": "Taiwan" |
| 599 | } |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 600 | self.bw_mode_text_2g = { |
Omar El Ayach | d4bc7ac | 2018-05-09 19:47:26 -0700 | [diff] [blame] | 601 | "11g": "Up to 54 Mbps", |
| 602 | "VHT20": "Up to 289 Mbps", |
| 603 | "VHT40": "Up to 600 Mbps" |
| 604 | } |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 605 | self.bw_mode_text_5g = { |
Omar El Ayach | d4bc7ac | 2018-05-09 19:47:26 -0700 | [diff] [blame] | 606 | "VHT20": "Up to 347 Mbps", |
| 607 | "VHT40": "Up to 800 Mbps", |
| 608 | "VHT80": "Up to 1733 Mbps" |
| 609 | } |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 610 | self.bw_mode_values = { |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 611 | "1": "11g", |
| 612 | "2": "VHT20", |
| 613 | "3": "VHT40", |
| 614 | "7": "VHT20", |
| 615 | "8": "VHT40", |
| 616 | "9": "VHT80" |
| 617 | } |
Omar El Ayach | d4bc7ac | 2018-05-09 19:47:26 -0700 | [diff] [blame] | 618 | |
| 619 | def read_ap_settings(self): |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 620 | """Function to read ap wireless settings.""" |
Omar El Ayach | d0c4b94 | 2018-01-30 06:02:14 +0000 | [diff] [blame] | 621 | # Get radio status (on/off) |
| 622 | self.read_radio_on_off() |
| 623 | # Get radio configuration. Note that if both radios are off, the below |
| 624 | # code will result in an error |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 625 | with start_chrome_browser(self.ap_settings["headless_browser"], 1, |
| 626 | 600) as browser: |
| 627 | visit_config_page(browser, self.config_page, BROWSER_WAIT_MED, 10) |
| 628 | visit_config_page(browser, self.config_page, BROWSER_WAIT_MED, 10) |
| 629 | time.sleep(BROWSER_WAIT_SHORT) |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 630 | wireless_button = browser.find_by_id("wireless").first |
| 631 | wireless_button.click() |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 632 | time.sleep(BROWSER_WAIT_MED) |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 633 | |
| 634 | with browser.get_iframe("formframe") as iframe: |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 635 | for key, value in self.config_page_fields.items(): |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 636 | if "bandwidth" in key: |
| 637 | config_item = iframe.find_by_name(value).first |
android-build-prod (mdb) | 70753e8 | 2018-05-02 17:54:37 -0700 | [diff] [blame] | 638 | self.ap_settings["{}_{}".format( |
| 639 | key[1], |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 640 | key[0])] = self.bw_mode_values[config_item.value] |
Omar El Ayach | d0c4b94 | 2018-01-30 06:02:14 +0000 | [diff] [blame] | 641 | elif "region" in key: |
| 642 | config_item = iframe.find_by_name(value).first |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 643 | self.ap_settings["region"] = self.region_map[ |
Omar El Ayach | d0c4b94 | 2018-01-30 06:02:14 +0000 | [diff] [blame] | 644 | config_item.value] |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 645 | elif "password" in key: |
| 646 | try: |
| 647 | config_item = iframe.find_by_name(value).first |
android-build-prod (mdb) | 70753e8 | 2018-05-02 17:54:37 -0700 | [diff] [blame] | 648 | self.ap_settings["{}_{}".format( |
| 649 | key[1], key[0])] = config_item.value |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 650 | self.ap_settings["{}_{}".format( |
| 651 | "security_type", key[0])] = "WPA2-PSK" |
| 652 | except: |
android-build-prod (mdb) | 70753e8 | 2018-05-02 17:54:37 -0700 | [diff] [blame] | 653 | self.ap_settings["{}_{}".format( |
| 654 | key[1], key[0])] = "defaultpassword" |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 655 | self.ap_settings["{}_{}".format( |
| 656 | "security_type", key[0])] = "Disable" |
Omar El Ayach | d0c4b94 | 2018-01-30 06:02:14 +0000 | [diff] [blame] | 657 | elif ("channel" in key) or ("ssid" in key): |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 658 | config_item = iframe.find_by_name(value).first |
android-build-prod (mdb) | 70753e8 | 2018-05-02 17:54:37 -0700 | [diff] [blame] | 659 | self.ap_settings["{}_{}".format( |
| 660 | key[1], key[0])] = config_item.value |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 661 | else: |
| 662 | pass |
Omar El Ayach | d0c4b94 | 2018-01-30 06:02:14 +0000 | [diff] [blame] | 663 | return self.ap_settings.copy() |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 664 | |
| 665 | def configure_ap(self): |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 666 | """Function to configure ap wireless settings.""" |
Omar El Ayach | d0c4b94 | 2018-01-30 06:02:14 +0000 | [diff] [blame] | 667 | # Turn radios on or off |
| 668 | self.configure_radio_on_off() |
| 669 | # Configure radios |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 670 | with start_chrome_browser(self.ap_settings["headless_browser"], 1, |
| 671 | 600) as browser: |
| 672 | visit_config_page(browser, self.config_page, BROWSER_WAIT_MED, 10) |
| 673 | visit_config_page(browser, self.config_page, BROWSER_WAIT_MED, 10) |
| 674 | time.sleep(BROWSER_WAIT_SHORT) |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 675 | wireless_button = browser.find_by_id("wireless").first |
| 676 | wireless_button.click() |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 677 | time.sleep(BROWSER_WAIT_MED) |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 678 | |
| 679 | with browser.get_iframe("formframe") as iframe: |
Omar El Ayach | d0c4b94 | 2018-01-30 06:02:14 +0000 | [diff] [blame] | 680 | # Update AP region. Must be done before channel setting |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 681 | for key, value in self.config_page_fields.items(): |
Omar El Ayach | d0c4b94 | 2018-01-30 06:02:14 +0000 | [diff] [blame] | 682 | if "region" in key: |
| 683 | config_item = iframe.find_by_name(value).first |
| 684 | config_item.select_by_text(self.ap_settings["region"]) |
| 685 | # Update wireless settings for each network |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 686 | for key, value in self.config_page_fields.items(): |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 687 | if "ssid" in key: |
| 688 | config_item = iframe.find_by_name(value).first |
android-build-prod (mdb) | 70753e8 | 2018-05-02 17:54:37 -0700 | [diff] [blame] | 689 | config_item.fill(self.ap_settings["{}_{}".format( |
| 690 | key[1], key[0])]) |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 691 | elif "channel" in key: |
| 692 | channel_string = "0" * (int( |
| 693 | self.ap_settings["{}_{}".format(key[1], key[0])] |
Omar El Ayach | d0c4b94 | 2018-01-30 06:02:14 +0000 | [diff] [blame] | 694 | ) < 10) + str(self.ap_settings["{}_{}".format( |
| 695 | key[1], key[0])]) + "(DFS)" * ( |
| 696 | 48 < int(self.ap_settings["{}_{}".format( |
| 697 | key[1], key[0])]) < 149) |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 698 | config_item = iframe.find_by_name(value).first |
| 699 | config_item.select_by_text(channel_string) |
| 700 | elif key == ("2G", "bandwidth"): |
| 701 | config_item = iframe.find_by_name(value).first |
| 702 | config_item.select_by_text( |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 703 | str(self.bw_mode_text_2g[self.ap_settings[ |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 704 | "{}_{}".format(key[1], key[0])]])) |
| 705 | elif key == ("5G_1", "bandwidth"): |
| 706 | config_item = iframe.find_by_name(value).first |
| 707 | config_item.select_by_text( |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 708 | str(self.bw_mode_text_5g[self.ap_settings[ |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 709 | "{}_{}".format(key[1], key[0])]])) |
| 710 | |
| 711 | # Update passwords for WPA2-PSK protected networks |
| 712 | # (Must be done after security type is selected) |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 713 | for key, value in self.config_page_fields.items(): |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 714 | if "security_type" in key: |
android-build-prod (mdb) | 70753e8 | 2018-05-02 17:54:37 -0700 | [diff] [blame] | 715 | iframe.choose(value, self.ap_settings["{}_{}".format( |
| 716 | key[1], key[0])]) |
| 717 | if self.ap_settings["{}_{}".format( |
| 718 | key[1], key[0])] == "WPA2-PSK": |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 719 | config_item = iframe.find_by_name( |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 720 | self.config_page_fields[(key[0], |
android-build-prod (mdb) | 70753e8 | 2018-05-02 17:54:37 -0700 | [diff] [blame] | 721 | "password")]).first |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 722 | config_item.fill(self.ap_settings["{}_{}".format( |
| 723 | "password", key[0])]) |
| 724 | |
| 725 | apply_button = iframe.find_by_name("Apply") |
| 726 | apply_button[0].click() |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 727 | time.sleep(BROWSER_WAIT_SHORT) |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 728 | try: |
| 729 | alert = browser.get_alert() |
| 730 | alert.accept() |
| 731 | except: |
| 732 | pass |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 733 | time.sleep(BROWSER_WAIT_SHORT) |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 734 | try: |
| 735 | alert = browser.get_alert() |
| 736 | alert.accept() |
| 737 | except: |
| 738 | pass |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 739 | time.sleep(BROWSER_WAIT_SHORT) |
| 740 | time.sleep(BROWSER_WAIT_EXTRA_LONG) |
| 741 | visit_config_page(browser, self.config_page, |
android-build-prod (mdb) | 70753e8 | 2018-05-02 17:54:37 -0700 | [diff] [blame] | 742 | BROWSER_WAIT_EXTRA_LONG, 10) |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 743 | self.validate_ap_settings() |
Omar El Ayach | d0c4b94 | 2018-01-30 06:02:14 +0000 | [diff] [blame] | 744 | |
| 745 | def configure_radio_on_off(self): |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 746 | """Helper configuration function to turn radios on/off.""" |
| 747 | with start_chrome_browser(self.ap_settings["headless_browser"], 1, |
| 748 | 600) as browser: |
| 749 | visit_config_page(browser, self.config_page, BROWSER_WAIT_MED, 10) |
| 750 | visit_config_page(browser, self.config_page_advanced, |
android-build-prod (mdb) | 70753e8 | 2018-05-02 17:54:37 -0700 | [diff] [blame] | 751 | BROWSER_WAIT_MED, 10) |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 752 | time.sleep(BROWSER_WAIT_SHORT) |
Omar El Ayach | d0c4b94 | 2018-01-30 06:02:14 +0000 | [diff] [blame] | 753 | wireless_button = browser.find_by_id("advanced_bt").first |
| 754 | wireless_button.click() |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 755 | time.sleep(BROWSER_WAIT_SHORT) |
Omar El Ayach | d0c4b94 | 2018-01-30 06:02:14 +0000 | [diff] [blame] | 756 | wireless_button = browser.find_by_id("wladv").first |
| 757 | wireless_button.click() |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 758 | time.sleep(BROWSER_WAIT_MED) |
Omar El Ayach | d0c4b94 | 2018-01-30 06:02:14 +0000 | [diff] [blame] | 759 | |
| 760 | with browser.get_iframe("formframe") as iframe: |
| 761 | # Turn radios on or off |
| 762 | status_toggled = False |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 763 | for key, value in self.config_page_fields.items(): |
Omar El Ayach | d0c4b94 | 2018-01-30 06:02:14 +0000 | [diff] [blame] | 764 | if "status" in key: |
| 765 | config_item = iframe.find_by_name(value).first |
| 766 | current_status = int(config_item.checked) |
| 767 | if current_status != self.ap_settings["{}_{}".format( |
| 768 | key[1], key[0])]: |
| 769 | status_toggled = True |
android-build-prod (mdb) | 70753e8 | 2018-05-02 17:54:37 -0700 | [diff] [blame] | 770 | if self.ap_settings["{}_{}".format(key[1], |
| 771 | key[0])]: |
Omar El Ayach | d0c4b94 | 2018-01-30 06:02:14 +0000 | [diff] [blame] | 772 | config_item.check() |
| 773 | else: |
| 774 | config_item.uncheck() |
| 775 | |
| 776 | if status_toggled: |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 777 | time.sleep(BROWSER_WAIT_SHORT) |
Omar El Ayach | d0c4b94 | 2018-01-30 06:02:14 +0000 | [diff] [blame] | 778 | browser.find_by_name("Apply").first.click() |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 779 | time.sleep(BROWSER_WAIT_EXTRA_LONG) |
| 780 | visit_config_page(browser, self.config_page, |
android-build-prod (mdb) | 70753e8 | 2018-05-02 17:54:37 -0700 | [diff] [blame] | 781 | BROWSER_WAIT_EXTRA_LONG, 10) |
Omar El Ayach | d0c4b94 | 2018-01-30 06:02:14 +0000 | [diff] [blame] | 782 | |
| 783 | def read_radio_on_off(self): |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 784 | """Helper configuration function to read radio status.""" |
| 785 | with start_chrome_browser(self.ap_settings["headless_browser"], 1, |
| 786 | 600) as browser: |
| 787 | visit_config_page(browser, self.config_page, BROWSER_WAIT_MED, 10) |
| 788 | visit_config_page(browser, self.config_page_advanced, |
android-build-prod (mdb) | 70753e8 | 2018-05-02 17:54:37 -0700 | [diff] [blame] | 789 | BROWSER_WAIT_MED, 10) |
Omar El Ayach | d0c4b94 | 2018-01-30 06:02:14 +0000 | [diff] [blame] | 790 | wireless_button = browser.find_by_id("advanced_bt").first |
| 791 | wireless_button.click() |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 792 | time.sleep(BROWSER_WAIT_SHORT) |
Omar El Ayach | d0c4b94 | 2018-01-30 06:02:14 +0000 | [diff] [blame] | 793 | wireless_button = browser.find_by_id("wladv").first |
| 794 | wireless_button.click() |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 795 | time.sleep(BROWSER_WAIT_MED) |
Omar El Ayach | d0c4b94 | 2018-01-30 06:02:14 +0000 | [diff] [blame] | 796 | |
| 797 | with browser.get_iframe("formframe") as iframe: |
| 798 | # Turn radios on or off |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 799 | for key, value in self.config_page_fields.items(): |
Omar El Ayach | d0c4b94 | 2018-01-30 06:02:14 +0000 | [diff] [blame] | 800 | if "status" in key: |
| 801 | config_item = iframe.find_by_name(value).first |
| 802 | self.ap_settings["{}_{}".format(key[1], key[0])] = int( |
| 803 | config_item.checked) |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 804 | |
| 805 | |
Omar El Ayach | d4bc7ac | 2018-05-09 19:47:26 -0700 | [diff] [blame] | 806 | class NetgearR7800AP(NetgearR7500AP): |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 807 | """Class that implements Netgear R7800 AP. |
| 808 | |
| 809 | Since most of the class' implementation is shared with the R7500, this |
| 810 | class inherits from NetgearR7500AP and simply redifines config parameters |
| 811 | """ |
Omar El Ayach | d4bc7ac | 2018-05-09 19:47:26 -0700 | [diff] [blame] | 812 | |
| 813 | def __init__(self, ap_settings): |
| 814 | self.ap_settings = ap_settings.copy() |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 815 | self.init_gui_data() |
| 816 | # Overwrite minor differences from R7500 AP |
| 817 | self.bw_mode_text_2g["VHT20"] = "Up to 347 Mbps" |
| 818 | # Read and update AP settings |
Omar El Ayach | d4bc7ac | 2018-05-09 19:47:26 -0700 | [diff] [blame] | 819 | self.read_ap_settings() |
| 820 | if ap_settings.items() <= self.ap_settings.items(): |
| 821 | return |
| 822 | else: |
| 823 | self.update_ap_settings(ap_settings) |
| 824 | |
| 825 | |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 826 | class NetgearR8000AP(NetgearR7000AP): |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 827 | """Class that implements Netgear R8000 AP. |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 828 | |
| 829 | Since most of the class' implementation is shared with the R7000, this |
| 830 | class inherits from NetgearR7000AP and simply redifines config parameters |
| 831 | """ |
| 832 | |
| 833 | def __init__(self, ap_settings): |
| 834 | self.ap_settings = ap_settings.copy() |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 835 | self.init_gui_data() |
| 836 | # Overwrite minor differences from R7000 AP |
| 837 | self.config_page = "{}://{}:{}@{}:{}/WLG_wireless_dual_band_r8000.htm".format( |
| 838 | self.ap_settings["protocol"], self.ap_settings["admin_username"], |
| 839 | self.ap_settings["admin_password"], self.ap_settings["ip_address"], |
| 840 | self.ap_settings["port"]) |
| 841 | self.config_page_nologin = "{}://{}:{}/WLG_wireless_dual_band_r8000.htm".format( |
| 842 | self.ap_settings["protocol"], self.ap_settings["ip_address"], |
| 843 | self.ap_settings["port"]) |
| 844 | self.config_page_advanced = "{}://{}:{}/WLG_adv_dual_band2_r8000.htm".format( |
| 845 | self.ap_settings["protocol"], self.ap_settings["ip_address"], |
| 846 | self.ap_settings["port"]) |
| 847 | self.networks = ["2G", "5G_1", "5G_2"] |
| 848 | self.channel_band_map = { |
Omar El Ayach | 9be1c3c | 2017-12-27 19:20:56 +0000 | [diff] [blame] | 849 | "2G": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], |
| 850 | "5G_1": [36, 40, 44, 48], |
Omar El Ayach | d0c4b94 | 2018-01-30 06:02:14 +0000 | [diff] [blame] | 851 | "5G_2": [149, 153, 157, 161, 165] |
| 852 | } |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 853 | self.config_page_fields = { |
Omar El Ayach | d0c4b94 | 2018-01-30 06:02:14 +0000 | [diff] [blame] | 854 | "region": "WRegion", |
| 855 | ("2G", "status"): "enable_ap", |
| 856 | ("5G_1", "status"): "enable_ap_an", |
| 857 | ("5G_2", "status"): "enable_ap_an_2", |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 858 | ("2G", "ssid"): "ssid", |
| 859 | ("5G_1", "ssid"): "ssid_an", |
| 860 | ("5G_2", "ssid"): "ssid_an_2", |
| 861 | ("2G", "channel"): "w_channel", |
| 862 | ("5G_1", "channel"): "w_channel_an", |
| 863 | ("5G_2", "channel"): "w_channel_an_2", |
| 864 | ("2G", "bandwidth"): "opmode", |
| 865 | ("5G_1", "bandwidth"): "opmode_an", |
| 866 | ("5G_2", "bandwidth"): "opmode_an_2", |
| 867 | ("2G", "security_type"): "security_type", |
| 868 | ("5G_1", "security_type"): "security_type_an", |
| 869 | ("5G_2", "security_type"): "security_type_an_2", |
| 870 | ("2G", "password"): "passphrase", |
| 871 | ("5G_1", "password"): "passphrase_an", |
| 872 | ("5G_2", "password"): "passphrase_an_2" |
| 873 | } |
Omar El Ayach | 7a6e241 | 2018-05-17 20:00:54 -0700 | [diff] [blame^] | 874 | # Read and update AP settings |
Omar El Ayach | 32b3afa | 2017-10-02 15:23:53 -0700 | [diff] [blame] | 875 | self.read_ap_settings() |
| 876 | if ap_settings.items() <= self.ap_settings.items(): |
| 877 | return |
| 878 | else: |
| 879 | self.update_ap_settings(ap_settings) |