Merge "Adding support for Netgear R7800 and upgrading R7500/R7800" am: de616b5250 am: 5c3db42503
am: 1a9a0cd0b8

Test: Done
Bug: 65563975

Change-Id: Ic7080652126b137477f55fae0905352481e23f30
(cherry picked from commit 83452254e324da4dea37728b01a0248a31ea7015)
diff --git a/acts/framework/acts/test_utils/wifi/wifi_retail_ap.py b/acts/framework/acts/test_utils/wifi/wifi_retail_ap.py
index 40155dc..ad17b82 100644
--- a/acts/framework/acts/test_utils/wifi/wifi_retail_ap.py
+++ b/acts/framework/acts/test_utils/wifi/wifi_retail_ap.py
@@ -33,6 +33,7 @@
     SUPPORTED_APS = {
         ("Netgear", "R7000"): "NetgearR7000AP",
         ("Netgear", "R7500"): "NetgearR7500AP",
+        ("Netgear", "R7800"): "NetgearR7800AP",
         ("Netgear", "R8000"): "NetgearR8000AP"
     }
     objs = []
@@ -51,7 +52,7 @@
 
 
 def visit_config_page(browser, url, page_load_timeout, num_tries):
-    """ Method to visit Netgear AP webpages
+    """ Method to visit Netgear AP webpages.
 
     This function visits a web page and checks the the resulting URL matches
     the intended URL, i.e. no redirects have happened
@@ -95,6 +96,23 @@
         """
         raise NotImplementedError
 
+    def validate_ap_settings(self):
+        """ Function to validate ap settings.
+
+        This function compares the actual ap settings read from the web GUI
+        with the assumed settings saved in the AP object. When called after AP
+        configuration, this method helps ensure that our configuration was
+        successful.
+
+        Raises:
+            ValueError: If read AP settings do not match stored settings.
+        """
+        assumed_ap_settings = self.ap_settings.copy()
+        actual_ap_settings = self.read_ap_settings()
+        if assumed_ap_settings != actual_ap_settings:
+            raise ValueError(
+                "Discrepancy in AP settings. Potential configuration error.")
+
     def configure_ap(self):
         """ Function that configures ap based on values of ap_settings.
 
@@ -104,7 +122,7 @@
         raise NotImplementedError
 
     def set_radio_on_off(self, network, status):
-        """ Function that turns the radio on or off
+        """ Function that turns the radio on or off.
 
         Args:
             network: string containing network identifier (2G, 5G_1, 5G_2)
@@ -114,7 +132,7 @@
         self.update_ap_settings(setting_to_update)
 
     def set_ssid(self, network, ssid):
-        """ Function that sets network SSID
+        """ Function that sets network SSID.
 
         Args:
             network: string containing network identifier (2G, 5G_1, 5G_2)
@@ -124,7 +142,7 @@
         self.update_ap_settings(setting_to_update)
 
     def set_channel(self, network, channel):
-        """ Function that sets network channel
+        """ Function that sets network channel.
 
         Args:
             network: string containing network identifier (2G, 5G_1, 5G_2)
@@ -134,7 +152,7 @@
         self.update_ap_settings(setting_to_update)
 
     def set_bandwidth(self, network, bandwidth):
-        """ Function that sets network bandwidth/mode
+        """ Function that sets network bandwidth/mode.
 
         Args:
             network: string containing network identifier (2G, 5G_1, 5G_2)
@@ -144,7 +162,7 @@
         self.update_ap_settings(setting_to_update)
 
     def set_power(self, network, power):
-        """ Function that sets network transmit power
+        """ Function that sets network transmit power.
 
         Args:
             network: string containing network identifier (2G, 5G_1, 5G_2)
@@ -154,7 +172,7 @@
         self.update_ap_settings(setting_to_update)
 
     def set_security(self, network, security_type, *password):
-        """ Function that sets network security setting and password (optional)
+        """ Function that sets network security setting and password.
 
         Args:
             network: string containing network identifier (2G, 5G_1, 5G_2)
@@ -224,8 +242,7 @@
 
 
 class NetgearR7000AP(WifiRetailAP):
-    """ Class that implements Netgear R7500 AP.
-    """
+    """ Class that implements Netgear R7500 AP."""
 
     def __init__(self, ap_settings):
         self.ap_settings = ap_settings.copy()
@@ -245,8 +262,8 @@
         self.CHROME_OPTIONS.add_argument("--allow-running-insecure-content")
         self.CHROME_OPTIONS.add_argument("--ignore-certificate-errors")
         self.CHROME_CAPABILITIES = DesiredCapabilities.CHROME.copy()
-        self.CHROME_CAPABILITIES['acceptSslCerts'] = True
-        self.CHROME_CAPABILITIES['acceptInsecureCerts'] = True
+        self.CHROME_CAPABILITIES["acceptSslCerts"] = True
+        self.CHROME_CAPABILITIES["acceptInsecureCerts"] = True
         if self.ap_settings["headless_browser"]:
             self.CHROME_OPTIONS.add_argument("--headless")
             self.CHROME_OPTIONS.add_argument("--disable-gpu")
@@ -299,6 +316,24 @@
             ("2G", "password"): "passphrase",
             ("5G_1", "password"): "passphrase_an"
         }
+        self.BW_MODE_VALUES = {
+            "g and b": "11g",
+            "145Mbps": "VHT20",
+            "300Mbps": "VHT40",
+            "HT80": "VHT80"
+        }
+        self.POWER_MODE_VALUES = {
+            "1": "100%",
+            "2": "75%",
+            "3": "50%",
+            "4": "25%"
+        }
+        self.BW_MODE_TEXT = {
+            "11g": "Up to 54 Mbps",
+            "VHT20": "Up to 289 Mbps",
+            "VHT40": "Up to 600 Mbps",
+            "VHT80": "Up to 1300 Mbps"
+        }
         self.read_ap_settings()
         if ap_settings.items() <= self.ap_settings.items():
             return
@@ -306,16 +341,7 @@
             self.update_ap_settings(ap_settings)
 
     def read_ap_settings(self):
-        """ Function to read ap settings.
-        """
-        BW_MODE_VALUES = {
-            "g and b": "11g",
-            "145Mbps": "VHT20",
-            "300Mbps": "VHT40",
-            "HT80": "VHT80"
-        }
-        POWER_MODE_VALUES = {"1": "100%", "2": "75%", "3": "50%", "4": "25%"}
-
+        """ Function to read ap settings."""
         with splinter.Browser(
                 "chrome",
                 options=self.CHROME_OPTIONS,
@@ -337,12 +363,12 @@
                 else:
                     config_item = browser.find_by_name(value)
                     if "bandwidth" in key:
-                        self.ap_settings["{}_{}".format(
-                            key[1],
-                            key[0])] = BW_MODE_VALUES[config_item.first.value]
-                    elif "power" in key:
                         self.ap_settings["{}_{}".format(key[1], key[
-                            0])] = POWER_MODE_VALUES[config_item.first.value]
+                            0])] = self.BW_MODE_VALUES[config_item.first.value]
+                    elif "power" in key:
+                        self.ap_settings["{}_{}".format(
+                            key[1], key[0])] = self.POWER_MODE_VALUES[
+                                config_item.first.value]
                     elif "region" in key:
                         self.ap_settings["region"] = self.REGION_MAP[
                             config_item.first.value]
@@ -357,29 +383,8 @@
                             key[1], key[0])] = config_item.first.value
         return self.ap_settings.copy()
 
-    def validate_ap_settings(self):
-        """ Function to validate ap settings
-
-        This function compares the actual ap settings read from the web GUI
-        with the assumed settings saved in the AP object. When called after AP
-        configuration, this method helps ensure that our configuration was
-        successful.
-        """
-        assumed_ap_settings = self.ap_settings.copy()
-        actual_ap_settings = self.read_ap_settings()
-        if assumed_ap_settings != actual_ap_settings:
-            raise ValueError(
-                "Discrepancy in AP settings. Potential configuration error.")
-
     def configure_ap(self):
-        """ Function to configure ap wireless settings
-        """
-        BW_MODE_TEXT = {
-            "11g": "Up to 54 Mbps",
-            "VHT20": "Up to 289 Mbps",
-            "VHT40": "Up to 600 Mbps",
-            "VHT80": "Up to 1300 Mbps"
-        }
+        """ Function to configure ap wireless settings."""
         # Turn radios on or off
         self.configure_radio_on_off()
         # Configure radios
@@ -404,7 +409,7 @@
                 elif "bandwidth" in key:
                     config_item = browser.find_by_name(value).first
                     config_item.select_by_text(
-                        BW_MODE_TEXT[self.ap_settings["{}_{}".format(
+                        self.BW_MODE_TEXT[self.ap_settings["{}_{}".format(
                             key[1], key[0])]])
 
             # Update security settings (passwords updated only if applicable)
@@ -455,8 +460,7 @@
             self.validate_ap_settings()
 
     def configure_radio_on_off(self):
-        """ Helper configuration function to turn radios on/off
-        """
+        """ Helper configuration function to turn radios on/off."""
         with splinter.Browser(
                 "chrome",
                 options=self.CHROME_OPTIONS,
@@ -489,29 +493,28 @@
 
 
 class NetgearR7500AP(WifiRetailAP):
-    """ Class that implements Netgear R7000 AP.
-
-    NOTE: Many of the functions here are reused in NetgearR8000AP
-    """
+    """ Class that implements Netgear R7500 AP."""
 
     def __init__(self, ap_settings):
         self.ap_settings = ap_settings.copy()
-        self.CONFIG_PAGE = "http://{}:{}@{}/index.htm".format(
-            self.ap_settings["admin_username"],
-            self.ap_settings["admin_password"], self.ap_settings["ip_address"])
-        self.CONFIG_PAGE_NOLOGIN = "http://{}/index.htm".format(
-            self.ap_settings["ip_address"])
-        self.CONFIG_PAGE_ADVANCED = "http://{}:{}@{}/adv_index.htm".format(
-            self.ap_settings["admin_username"],
-            self.ap_settings["admin_password"], self.ap_settings["ip_address"])
+        self.CONFIG_PAGE = "{}://{}:{}@{}:{}/index.htm".format(
+            self.ap_settings["protocol"], self.ap_settings["admin_username"],
+            self.ap_settings["admin_password"], self.ap_settings["ip_address"],
+            self.ap_settings["port"])
+        self.CONFIG_PAGE_NOLOGIN = "{}://{}:{}/index.htm".format(
+            self.ap_settings["protocol"], self.ap_settings["ip_address"],
+            self.ap_settings["port"])
+        self.CONFIG_PAGE_ADVANCED = "{}://{}:{}/adv_index.htm".format(
+            self.ap_settings["protocol"], self.ap_settings["ip_address"],
+            self.ap_settings["port"])
         self.CHROME_OPTIONS = splinter.driver.webdriver.chrome.Options()
         self.CHROME_OPTIONS.add_argument("--no-proxy-server")
         self.CHROME_OPTIONS.add_argument("--no-sandbox")
         self.CHROME_OPTIONS.add_argument("--allow-running-insecure-content")
         self.CHROME_OPTIONS.add_argument("--ignore-certificate-errors")
         self.CHROME_CAPABILITIES = DesiredCapabilities.CHROME.copy()
-        self.CHROME_CAPABILITIES['acceptSslCerts'] = True
-        self.CHROME_CAPABILITIES['acceptInsecureCerts'] = True
+        self.CHROME_CAPABILITIES["acceptSslCerts"] = True
+        self.CHROME_CAPABILITIES["acceptInsecureCerts"] = True
         if self.ap_settings["headless_browser"]:
             self.CHROME_OPTIONS.add_argument("--headless")
             self.CHROME_OPTIONS.add_argument("--disable-gpu")
@@ -562,16 +565,17 @@
             "20": "Singapore",
             "21": "Taiwan"
         }
-        self.read_ap_settings()
-        if ap_settings.items() <= self.ap_settings.items():
-            return
-        else:
-            self.update_ap_settings(ap_settings)
-
-    def read_ap_settings(self):
-        """ Function to read ap wireless settings
-        """
-        BW_MODE_VALUES = {
+        self.BW_MODE_TEXT_2G = {
+            "11g": "Up to 54 Mbps",
+            "VHT20": "Up to 289 Mbps",
+            "VHT40": "Up to 600 Mbps"
+        }
+        self.BW_MODE_TEXT_5G = {
+            "VHT20": "Up to 347 Mbps",
+            "VHT40": "Up to 800 Mbps",
+            "VHT80": "Up to 1733 Mbps"
+        }
+        self.BW_MODE_VALUES = {
             "1": "11g",
             "2": "VHT20",
             "3": "VHT40",
@@ -579,6 +583,14 @@
             "8": "VHT40",
             "9": "VHT80"
         }
+        self.read_ap_settings()
+        if ap_settings.items() <= self.ap_settings.items():
+            return
+        else:
+            self.update_ap_settings(ap_settings)
+
+    def read_ap_settings(self):
+        """ Function to read ap wireless settings."""
         # Get radio status (on/off)
         self.read_radio_on_off()
         # Get radio configuration. Note that if both radios are off, the below
@@ -589,9 +601,10 @@
                 desired_capabilities=self.CHROME_CAPABILITIES) as browser:
             visit_config_page(browser, self.CONFIG_PAGE, BROWSER_WAIT_MED, 10)
             visit_config_page(browser, self.CONFIG_PAGE, BROWSER_WAIT_MED, 10)
+            sleep(BROWSER_WAIT_SHORT)
             wireless_button = browser.find_by_id("wireless").first
             wireless_button.click()
-            sleep(BROWSER_WAIT_SHORT)
+            sleep(BROWSER_WAIT_MED)
 
             with browser.get_iframe("formframe") as iframe:
                 for key, value in self.CONFIG_PAGE_FIELDS.items():
@@ -599,7 +612,7 @@
                         config_item = iframe.find_by_name(value).first
                         self.ap_settings["{}_{}".format(
                             key[1],
-                            key[0])] = BW_MODE_VALUES[config_item.value]
+                            key[0])] = self.BW_MODE_VALUES[config_item.value]
                     elif "region" in key:
                         config_item = iframe.find_by_name(value).first
                         self.ap_settings["region"] = self.REGION_MAP[
@@ -625,19 +638,7 @@
         return self.ap_settings.copy()
 
     def configure_ap(self):
-        """ Function to configure ap wireless settings
-        """
-        BW_MODE_TEXT_2G = {
-            "11g": "Up to 54 Mbps",
-            "VHT20": "Up to 289 Mbps",
-            "VHT40": "Up to 600 Mbps"
-        }
-        BW_MODE_TEXT_5G = {
-            "VHT20": "Up to 347 Mbps",
-            "VHT40": "Up to 800 Mbps",
-            "VHT80": "Up to 1733 Mbps"
-        }
-
+        """ Function to configure ap wireless settings."""
         # Turn radios on or off
         self.configure_radio_on_off()
         # Configure radios
@@ -647,6 +648,7 @@
                 desired_capabilities=self.CHROME_CAPABILITIES) as browser:
             visit_config_page(browser, self.CONFIG_PAGE, BROWSER_WAIT_MED, 10)
             visit_config_page(browser, self.CONFIG_PAGE, BROWSER_WAIT_MED, 10)
+            sleep(BROWSER_WAIT_SHORT)
             wireless_button = browser.find_by_id("wireless").first
             wireless_button.click()
             sleep(BROWSER_WAIT_MED)
@@ -675,12 +677,12 @@
                     elif key == ("2G", "bandwidth"):
                         config_item = iframe.find_by_name(value).first
                         config_item.select_by_text(
-                            str(BW_MODE_TEXT_2G[self.ap_settings[
+                            str(self.BW_MODE_TEXT_2G[self.ap_settings[
                                 "{}_{}".format(key[1], key[0])]]))
                     elif key == ("5G_1", "bandwidth"):
                         config_item = iframe.find_by_name(value).first
                         config_item.select_by_text(
-                            str(BW_MODE_TEXT_5G[self.ap_settings[
+                            str(self.BW_MODE_TEXT_5G[self.ap_settings[
                                 "{}_{}".format(key[1], key[0])]]))
 
                 # Update passwords for WPA2-PSK protected networks
@@ -712,13 +714,13 @@
                 except:
                     pass
                 sleep(BROWSER_WAIT_SHORT)
+            sleep(BROWSER_WAIT_EXTRA_LONG)
             visit_config_page(browser, self.CONFIG_PAGE,
                               BROWSER_WAIT_EXTRA_LONG, 10)
-            sleep(BROWSER_WAIT_LONG)
+            self.validate_ap_settings()
 
     def configure_radio_on_off(self):
-        """ Helper configuration function to turn radios on/off
-        """
+        """ Helper configuration function to turn radios on/off."""
         with splinter.Browser(
                 "chrome",
                 options=self.CHROME_OPTIONS,
@@ -726,6 +728,7 @@
             visit_config_page(browser, self.CONFIG_PAGE, BROWSER_WAIT_MED, 10)
             visit_config_page(browser, self.CONFIG_PAGE_ADVANCED,
                               BROWSER_WAIT_MED, 10)
+            sleep(BROWSER_WAIT_SHORT)
             wireless_button = browser.find_by_id("advanced_bt").first
             wireless_button.click()
             sleep(BROWSER_WAIT_SHORT)
@@ -757,8 +760,7 @@
                                       BROWSER_WAIT_EXTRA_LONG, 10)
 
     def read_radio_on_off(self):
-        """ Helper configuration function to read radio status
-        """
+        """ Helper configuration function to read radio status."""
         with splinter.Browser(
                 "chrome",
                 options=self.CHROME_OPTIONS,
@@ -782,6 +784,104 @@
                             config_item.checked)
 
 
+class NetgearR7800AP(NetgearR7500AP):
+    """ Class that implements Netgear R7800 AP."""
+
+    def __init__(self, ap_settings):
+        self.ap_settings = ap_settings.copy()
+        self.CONFIG_PAGE = "{}://{}:{}@{}:{}/index.htm".format(
+            self.ap_settings["protocol"], self.ap_settings["admin_username"],
+            self.ap_settings["admin_password"], self.ap_settings["ip_address"],
+            self.ap_settings["port"])
+        self.CONFIG_PAGE_NOLOGIN = "{}://{}:{}/index.htm".format(
+            self.ap_settings["protocol"], self.ap_settings["ip_address"],
+            self.ap_settings["port"])
+        self.CONFIG_PAGE_ADVANCED = "{}://{}:{}/adv_index.htm".format(
+            self.ap_settings["protocol"], self.ap_settings["ip_address"],
+            self.ap_settings["port"])
+        self.CHROME_OPTIONS = splinter.driver.webdriver.chrome.Options()
+        self.CHROME_OPTIONS.add_argument("--no-proxy-server")
+        self.CHROME_OPTIONS.add_argument("--no-sandbox")
+        self.CHROME_OPTIONS.add_argument("--allow-running-insecure-content")
+        self.CHROME_OPTIONS.add_argument("--ignore-certificate-errors")
+        self.CHROME_CAPABILITIES = DesiredCapabilities.CHROME.copy()
+        self.CHROME_CAPABILITIES["acceptSslCerts"] = True
+        self.CHROME_CAPABILITIES["acceptInsecureCerts"] = True
+        if self.ap_settings["headless_browser"]:
+            self.CHROME_OPTIONS.add_argument("--headless")
+            self.CHROME_OPTIONS.add_argument("--disable-gpu")
+        self.NETWORKS = ["2G", "5G_1"]
+        self.CHANNEL_BAND_MAP = {
+            "2G": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
+            "5G_1": [
+                36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120,
+                124, 128, 132, 136, 140, 149, 153, 157, 161, 165
+            ]
+        }
+        self.CONFIG_PAGE_FIELDS = {
+            "region": "WRegion",
+            ("2G", "status"): "enable_ap",
+            ("5G_1", "status"): "enable_ap_an",
+            ("2G", "ssid"): "ssid",
+            ("5G_1", "ssid"): "ssid_an",
+            ("2G", "channel"): "w_channel",
+            ("5G_1", "channel"): "w_channel_an",
+            ("2G", "bandwidth"): "opmode",
+            ("5G_1", "bandwidth"): "opmode_an",
+            ("2G", "security_type"): "security_type",
+            ("5G_1", "security_type"): "security_type_an",
+            ("2G", "password"): "passphrase",
+            ("5G_1", "password"): "passphrase_an"
+        }
+        self.REGION_MAP = {
+            "0": "Africa",
+            "1": "Asia",
+            "2": "Australia",
+            "3": "Canada",
+            "4": "Europe",
+            "5": "Israel",
+            "6": "Japan",
+            "7": "Korea",
+            "8": "Mexico",
+            "9": "South America",
+            "10": "United States",
+            "11": "China",
+            "12": "India",
+            "13": "Malaysia",
+            "14": "Middle East(Algeria/Syria/Yemen)",
+            "15": "Middle East(Iran/Labanon/Qatar)",
+            "16": "Middle East(Turkey/Egypt/Tunisia/Kuwait)",
+            "17": "Middle East(Saudi Arabia)",
+            "18": "Middle East(United Arab Emirates)",
+            "19": "Russia",
+            "20": "Singapore",
+            "21": "Taiwan"
+        }
+        self.BW_MODE_TEXT_2G = {
+            "11g": "Up to 54 Mbps",
+            "VHT20": "Up to 347 Mbps",
+            "VHT40": "Up to 600 Mbps"
+        }
+        self.BW_MODE_TEXT_5G = {
+            "VHT20": "Up to 347 Mbps",
+            "VHT40": "Up to 800 Mbps",
+            "VHT80": "Up to 1733 Mbps"
+        }
+        self.BW_MODE_VALUES = {
+            "1": "11g",
+            "2": "VHT20",
+            "3": "VHT40",
+            "7": "VHT20",
+            "8": "VHT40",
+            "9": "VHT80"
+        }
+        self.read_ap_settings()
+        if ap_settings.items() <= self.ap_settings.items():
+            return
+        else:
+            self.update_ap_settings(ap_settings)
+
+
 class NetgearR8000AP(NetgearR7000AP):
     """ Class that implements Netgear R8000 AP.