diff options
author | krisr@chromium.org <krisr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-04-09 22:37:55 +0000 |
---|---|---|
committer | krisr@chromium.org <krisr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-04-09 22:37:55 +0000 |
commit | 7be4a96af7eecf23ec5d8655fc8bb4c1558897e2 (patch) | |
tree | cfcea28e9a05ba227f54a2a9598a35ba85899727 | |
parent | 92ff0a7db633bde3ae4971cceac127b55041dca6 (diff) | |
download | chromium_src-7be4a96af7eecf23ec5d8655fc8bb4c1558897e2.zip chromium_src-7be4a96af7eecf23ec5d8655fc8bb4c1558897e2.tar.gz chromium_src-7be4a96af7eecf23ec5d8655fc8bb4c1558897e2.tar.bz2 |
Initial check-in of a python interface to control third party access points via their web interface using webdriver.
Review URL: https://chromiumcodereview.appspot.com/10025010
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@131463 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/test/functional/ap_lab/ap_configurator.py | 348 | ||||
-rw-r--r-- | chrome/test/functional/ap_lab/ap_configurator_test.py | 142 | ||||
-rw-r--r-- | chrome/test/functional/ap_lab/dlink_ap_configurator.py | 289 | ||||
-rw-r--r-- | chrome/test/functional/ap_lab/linksys_ap_configurator.py | 192 | ||||
-rw-r--r-- | chrome/test/functional/ap_lab/pyauto_ap_configurator.py | 25 |
5 files changed, 996 insertions, 0 deletions
diff --git a/chrome/test/functional/ap_lab/ap_configurator.py b/chrome/test/functional/ap_lab/ap_configurator.py new file mode 100644 index 0000000..ee4bd64 --- /dev/null +++ b/chrome/test/functional/ap_lab/ap_configurator.py @@ -0,0 +1,348 @@ +# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import copy +import logging +import os + +import pyauto_ap_configurator +import pyauto + +import selenium.common.exceptions +from selenium.webdriver.support.ui import WebDriverWait + + +class APConfigurator(object): + """Base class for objects to configure access points using webdriver.""" + + def __init__(self, pyauto_instance): + self.pyauto_instance = pyauto_instance + self._driver = pyauto_instance.NewWebDriver() + # Any call to wait.until() will raise an exception if the timeout is hit. + self._wait = WebDriverWait(self._driver, timeout=5) + + # Possible bands + self.band_2ghz = '2.4GHz' + self.band_5ghz = '5GHz' + + # Possible modes + self.mode_a = 0x0001 + self.mode_b = 0x0010 + self.mode_g = 0x0100 + self.mode_n = 0x1000 + + # Possible security settings + self.security_disabled = 'Disabled' + self.security_wep = 'WEP' + self.security_wpawpsk = 'WPA-Personal' + self.security_wpa2wpsk = 'WPA2-Personal' + self.security_wpa8021x = 'WPA-Enterprise' + self.security_wpa28021x = 'WPA2-Enterprise' + + self.wep_authentication_open = 'Open' + self.wep_authentication_shared = 'Shared Key' + + self._command_list = [] + + def _WaitForObjectByXPath(self, xpath): + """Waits for an object to appear.""" + try: + self._wait.until(lambda _: self._driver.find_element_by_xpath(xpath)) + except selenium.common.exceptions.TimeoutException, e: + logging.exception('Unable to find the wait for object by xpath: %s\n' + 'WebDriver exception: %s', xpath, str(e)) + + def SelectItemFromPopupByID(self, item, element_id, wait_for_xpath=None): + """Selects an item from a popup, by passing the element ID. + + Args: + item: the item to select from the popup + element_id: the html ID of the item + wait_for_xpath: an item to wait for before returning + """ + xpath = 'id("%s")' % element_id + self.SelectItemFromPopupByXPath(item, xpath, wait_for_xpath) + + def SelectItemFromPopupByXPath(self, item, xpath, wait_for_xpath=None): + """Selects an item from a popup, by passing the xpath of the popup. + + Args: + item: the item to select from the popup + xpath: the xpath of the popup + wait_for_xpath: an item to wait for before returning + """ + popup = self._driver.find_element_by_xpath(xpath) + for option in popup.find_elements_by_tag_name('option'): + if option.text == item: + option.click() + break + if wait_for_xpath: self._WaitForObjectByXPath(wait_for_xpath) + + def SetContentOfTextFieldByID(self, content, text_field_id, + wait_for_xpath=None): + """Sets the content of a textfield, by passing the element ID. + + Args: + content: the content to apply to the textfield + text_field_id: the html ID of the textfield + wait_for_xpath: an item to wait for before returning + """ + xpath = 'id("%s")' % text_field_id + self.SetConentsOfTextFieldByXPath(content, xpath, wait_for_xpath) + + def SetConentsOfTextFieldByXPath(self, content, xpath, wait_for_xpath=None): + """Sets the content of a textfield, by passing the xpath. + + Args: + content: the content to apply to the textfield + xpath: the xpath of the textfield + wait_for_xpath: an item to wait for before returning + """ + # When we can get the value we know the text field is ready. + text_field = self._driver.find_element_by_xpath(xpath) + try: + self._wait.until(lambda _: text_field.get_attribute('value')) + except selenium.common.exceptions.TimeoutException, e: + logging.exception('Unable to obtain the value of the text field %s.\n' + 'WebDriver exception: %s', wait_for_xpath, str(e)) + text_field = self._driver.find_element_by_xpath(xpath) + text_field.clear() + text_field.send_keys(content) + if wait_for_xpath: self._WaitForObjectByXPath(wait_for_xpath) + + def SetCheckBoxSelectedByID(self, check_box_id, selected=True, + wait_for_xpath=None): + """Sets the state of a checkbox, by passing the ID. + + Args: + check_box_id: the html id of the checkbox + selected: True to enable the checkbox; False otherwise + wait_for_xpath: an item to wait for before returning + """ + xpath = 'id("%s")' % check_box_id + self.SetCheckBoxSelectedByXPath(xpath, selected, wait_for_xpath) + + def SetCheckBoxSelectedByXPath(self, xpath, selected=True, + wait_for_xpath=None): + """Sets the state of a checkbox, by passing the xpath. + + Args: + xpath: the xpath of the checkbox + selected: True to enable the checkbox; False otherwise + wait_for_xpath: an item to wait for before returning + """ + check_box = self._driver.find_element_by_xpath(xpath) + value = check_box.get_attribute('value') + if (value == '1' and not selected) or (value == '0' and selected): + check_box.click() + if wait_for_xpath: self._WaitForObjectByXPath(wait_for_xpath) + + def AddItemToCommandList(self, method, args, page, priority): + """Adds commands to be executed against the AP web UI. + + Args: + method: the method to run + args: the arguments for the method you want executed + page: the page on the web ui where the method should be run against + priority: the priority of the method + """ + self._command_list.append({'method': method, + 'args': copy.copy(args), + 'page': page, + 'priority': priority}) + + def GetRouterName(self): + """Returns a string to describe the router. + + Note: The derrived class must implement this method. + """ + raise NotImplementedError + + def GetNumberOfPages(self): + """Returns the number of web pages used to configure the router. + + Note: This is used internally by applySettings, and this method must be + implemented by the derrived class. + """ + raise NotImplementedError + + def GetSupportedBands(self): + """Returns a list of dictionaries describing the supported bands. + + Example: returned is a dictionary of band and a list of channels. The band + object returned must be one of those defined in the __init___ of + this class. + + supported_bands = [{'band' : self.band_2GHz, + 'channels' : [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]}, + {'band' : self.band_5ghz, + 'channels' : [26, 40, 44, 48, 149, 153, 157, 161, 165]}] + + Returns: + A list of dictionaries as described above + + Note: The derrived class must implement this method. + """ + raise NotImplementedError + + def GetSupportedModes(self): + """Returns a list of dictionaries describing the supported modes. + + Example: returned is a dictionary of band and a list of modess. The band + and modes objects returned must be one of those defined in the + __init___ of this class. + + supported_modes = [{'band' : self.band_2GHz, + 'modes' : [mode_b, mode_b | mode_g]}, + {'band' : self.band_5ghz, + 'modes' : [mode_a, mode_n, mode_a | mode_n]}] + + Returns: + A list of dictionaries as described above + + Note: The derrived class must implement this method. + """ + raise NotImplementedError + + def NavigateToPage(self, page_number): + """Navigates to the page corresponding to the given page number. + + This method performs the translation between a page number and a url to + load. This is used internally by applySettings. + + Args: + page_number: Page number of the page to load + + Returns: + True if navigation is successful; False otherwise. + + Note: The derrived class must implement this method. + """ + raise NotImplementedError + + def SavePage(self, page_number): + """Saves the given page. + + Args: + page_number: Page number of the page to save. + + Returns: + True if navigation is successful; False otherwise. + + Note: The derrived class must implement this method. + """ + raise NotImplementedError + + def SetMode(self, mode, band=None): + """Sets the mode. + + Args: + mode: must be one of the modes listed in __init__() + band: the band to select + + Note: The derrived class must implement this method + """ + raise NotImplementedError + + def SetRadio(self, enabled=True): + """Turns the radio on and off. + + Args: + enabled: True to turn on the radio; False otherwise + + Note: The derrived class must implement this method. + """ + raise NotImplementedError + + def SetSSID(self, ssid): + """Sets the SSID of the wireless network. + + Args: + ssid: Name of the wireless network + + Note: The derrived class must implement this method. + """ + raise NotImplementedError + + def SetChannel(self, channel): + """Sets the channel of the wireless network. + + Args: + channel: Integer value of the channel + + Note: The derrived class must implement this method. + """ + raise NotImplementedError + + def SetBand(self, band): + """Sets the band of the wireless network. + + Currently there are only two possible values for band 2kGHz and 5kGHz. + + Args: + band: Constant describing the band type + + Note: The derrived class must implement this method. + """ + raise NotImplementedError + + def SetSecurityDisabled(self): + """Disables the security of the wireless network. + + Note: The derrived class must implement this method. + """ + raise NotImplementedError + + def SetSecurityWEP(self, key_value, authentication): + """Enabled WEP security for the wireless network. + + Args: + key_value: encryption key to use + authentication: one of two supported authentication types: + wep_authentication_open or wep_authentication_shared + + Note: The derrived class must implement this method. + """ + raise NotImplementedError + + def SetSecurityWPAPSK(self, shared_key, update_interval=1800): + """Enabled WPA using a private security key for the wireless network. + + Args: + shared_key: shared encryption key to use + update_interval: number of seconds to wait before updating + + Note: The derrived class must implement this method. + """ + raise NotImplementedError + + def SetVisibility(self, visible=True): + """Set the visibility of the wireless network. + + Args: + visible: True for visible; False otherwise + + Note: The derrived class must implement this method. + """ + raise NotImplementedError + + def ApplySettings(self): + """Apply all settings to the access point.""" + # Pull items by page and then sort + if self.GetNumberOfPages() == -1: + self.fail(msg='Number of pages is not set.') + page_range = range(1, self.GetNumberOfPages() + 1) + for i in page_range: + page_commands = [] + for command in self._command_list: + if command['page'] == i: + page_commands.append(command) + # Sort the commands in this page by priority + sorted_page_commands = sorted(page_commands, key=lambda k: k['priority']) + if sorted_page_commands and self.NavigateToPage(i): + for command in sorted_page_commands: + command['method'](*command['args']) + self.SavePage(i) + self._command_list = [] + diff --git a/chrome/test/functional/ap_lab/ap_configurator_test.py b/chrome/test/functional/ap_lab/ap_configurator_test.py new file mode 100644 index 0000000..f6588af --- /dev/null +++ b/chrome/test/functional/ap_lab/ap_configurator_test.py @@ -0,0 +1,142 @@ +# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import unittest + +import dlink_ap_configurator +import linksys_ap_configurator + +import pyauto_ap_configurator # must preceed pyauto +import pyauto + + +class ConfiguratorTest(pyauto.PyUITest): + """This test needs to be run against the UI interface. + + The purpose of this test is to act as a basic acceptance test when developing + a new AP configurator class. Use this to make sure all core functionality is + implemented. + + This test does not verify that everything works. + + """ + + def setUp(self): + pyauto.PyUITest.setUp(self) + # Build your new class object and add it to the list + # TODO (krisr): Create a factory object that creates the ap configurators. + linksys = linksys_ap_configurator.LinksysAPConfigurator(self, + '172.22.12.107') + dlink = dlink_ap_configurator.DLinkAPConfigurator(self, '172.22.12.124') + # Set self.ap to the one you want to test against. + self.ap = dlink + + def testMakeNoChanges(self): + """Test saving with no changes doesn't throw an error.""" + # Set to a known state. + self.ap.SetRadio(True) + self.ap.ApplySettings() + # Set the same setting again. + self.ap.SetRadio(True) + self.ap.ApplySettings() + + def testRadio(self): + """Test we can adjust the radio setting.""" + self.ap.SetRadio(True) + self.ap.ApplySettings() + self.ap.SetRadio(False) + self.ap.ApplySettings() + + def testChannel(self): + """Test adjusting the channel.""" + self.ap.SetRadio(4) + self.ap.ApplySettings() + + def testVisibility(self): + """Test adjusting the visibility.""" + self.ap.SetVisibility(False) + self.ap.ApplySettings() + self.ap.SetVisibility(True) + self.ap.ApplySettings() + + def testSSID(self): + """Test setting the SSID.""" + self.ap.SetSSID('AP-automated-ssid') + self.ap.ApplySettings() + + def testSecurityWEP(self): + """Test configuring WEP security.""" + self.ap.SetSecurityWEP('45678', self.ap.wep_authentication_open) + self.ap.ApplySettings() + self.ap.SetSecurityWEP('90123', self.ap.wep_authentication_shared) + self.ap.ApplySettings() + + def testPrioritySets(self): + """Test that commands are run in the right priority.""" + self.ap.SetRadio(False) + self.ap.SetVisibility(True) + self.ap.SetSSID('priority_test') + self.ap.ApplySettings() + + def testSecurityAndGeneralSettings(self): + """Test updating settings that are general and security related.""" + self.ap.SetRadio(False) + self.ap.SetVisibility(True) + self.ap.SetSecurityWEP('88888', self.ap.wep_authentication_open) + self.ap.SetSSID('sec&gen_test') + self.ap.ApplySettings() + + def testModes(self): + """Tests switching modes.""" + modes_info = self.ap.GetSupportedModes() + self.assertFalse(not modes_info, + msg='Returned an invalid mode list. Is this method' + ' implemented?') + for band_modes in modes_info: + for mode in band_modes['modes']: + self.ap.SetMode(mode) + self.ap.ApplySettings() + + def testModesWithBand(self): + """Tests switching modes that support adjusting the band.""" + # Check if we support self.kModeN across multiple bands + modes_info = self.ap.GetSupportedModes() + n_bands = [] + for band_modes in modes_info: + if self.ap.mode_n in band_modes['modes']: + n_bands.append(band_modes['band']) + if len(n_bands) > 1: + for n_band in n_bands: + self.ap.SetMode(self.ap.mode_n, band=n_band) + self.ap.ApplySettings() + + def testFastCycleSecurity(self): + """Mini stress for changing security settings rapidly.""" + self.ap.SetRadio(True) + self.ap.SetSecurityWEP('77777', self.ap.wep_authentication_open) + self.ap.SetSecurityDisabled() + self.ap.SetSecurityWPAPSK('qwertyuiolkjhgfsdfg') + self.ap.ApplySettings() + + def testCycleSecurity(self): + """Test switching between different security settings.""" + self.ap.SetRadio(True) + self.ap.SetSecurityWEP('77777', self.ap.wep_authentication_open) + self.ap.ApplySettings() + self.ap.SetSecurityDisabled() + self.ap.ApplySettings() + self.ap.SetSecurityWPAPSK('qwertyuiolkjhgfsdfg') + self.ap.ApplySettings() + + def testActionsWhenRadioDisabled(self): + """Test making changes when the radio is diabled.""" + self.ap.SetRadio(False) + self.ap.ApplySettings() + self.ap.SetSecurityWEP('77777', self.ap.wep_authentication_open) + self.ap.SetRadio(False) + self.ap.ApplySettings() + + +if __name__ == '__main__': + pyauto_ap_configurator.Main() diff --git a/chrome/test/functional/ap_lab/dlink_ap_configurator.py b/chrome/test/functional/ap_lab/dlink_ap_configurator.py new file mode 100644 index 0000000..30be355 --- /dev/null +++ b/chrome/test/functional/ap_lab/dlink_ap_configurator.py @@ -0,0 +1,289 @@ +# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import logging +import os + +import ap_configurator +import selenium.common.exceptions + + +class DLinkAPConfigurator(ap_configurator.APConfigurator): + """Derived class to control the DLink DAP-1522.""" + + def __init__(self, pyauto_instance, admin_interface_url): + super(DLinkAPConfigurator, self).__init__(pyauto_instance) + # Override constants + self.security_disabled = 'Disable Wireless Security (not recommended)' + self.security_wep = 'WEP' + self.security_wpapsk = 'WPA-Personal' + self.security_wpa2psk = 'WPA-Personal' + self.security_wpa8021x = 'WPA-Enterprise' + self.security_wpa28021x = 'WPA2-Enterprise' + + self.admin_interface_url = admin_interface_url + + def _OpenLandingPage(self): + self.pyauto_instance.NavigateToURL('http://%s/index.php' % + self.admin_interface_url) + page_name = os.path.basename(self.pyauto_instance.GetActiveTabURL().spec()) + if page_name == 'login.php' or page_name == 'index.php': + try: + self._wait.until(lambda _: self._driver.find_element_by_xpath( + '//*[@name="login"]')) + except selenium.common.exceptions.TimeoutException, e: + # Maybe we were re-routes to the configuration page + if (os.path.basename(self.pyauto_instance.GetActiveTabURL().spec()) == + 'bsc_wizard.php'): + return + logging.exception('WebDriver exception: %s', str(e)) + login_button = self._driver.find_element_by_xpath('//*[@name="login"]') + login_button.click() + + def _OpenConfigurationPage(self): + self._OpenLandingPage() + if (os.path.basename(self.pyauto_instance.GetActiveTabURL().spec()) != + 'bsc_wizard.php'): + self.fail(msg='Taken to an unknown page %s' % + self.pyauto_instance.GetActiveTabURL().spec()) + + # Else we are being logged in automatically to the landing page + wlan = '//*[@name="wlan_wireless"]' + try: + self._wait.until(lambda _: self._driver.find_element_by_xpath(wlan)) + except selenium.common.exceptions.TimeoutException, e: + logging.exception('WebDriver exception: %s', str(e)) + + wlan_button = self._driver.find_element_by_xpath(wlan) + wlan_button.click() + # Wait for the main configuration page, look for the radio button + try: + self._wait.until(lambda _: self._driver.find_element_by_xpath( + 'id("enable")')) + except selenium.common.exceptions.TimeoutException, e: + logging.exception('Unable to find the radio button on the main landing ' + 'page.\nWebDriver exception: %s', str(e)) + + def GetRouterName(self): + return 'Router Name: DAP-1522; Class: DLinkAPConfigurator' + + def GetNumberOfPages(self): + return 1 + + def GetSupportedBands(self): + return [{'band': self.band_2ghz, + 'channels': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]}, + {'band': self.band_5ghz, + 'channels': [26, 40, 44, 48, 149, 153, 157, 161, 165]}] + + def GetSupportedModes(self): + return [{'band': self.band_2ghz, + 'modes': [self.mode_b, self.mode_g, self.mode_n, + self.mode_b | self.mode_g, self.mode_g | self.mode_n]}, + {'band': self.band_5ghz, + 'modes': [self.mode_a, self.mode_n, self.mode_a | self.mode_n]}] + + def NavigateToPage(self, page_number): + # All settings are on the same page, so we always open the config page + self._OpenConfigurationPage() + return True + + def SavePage(self, page_number): + # All settings are on the same page, we can ignore page_number + button = self._driver.find_element_by_xpath('//input[@name="apply"]') + button.click() + # If we did not make changes so we are sent to the continue screen. + continue_screen = True + button_xpath = '//input[@name="bt"]' + try: + self._wait.until(lambda _: + self._driver.find_element_by_xpath(button_xpath)) + except selenium.common.exceptions.TimeoutException, e: + continue_screen = False + if continue_screen: + button = self._driver.find_element_by_xpath(button_xpath) + button.click() + # We will be returned to the landing page when complete + try: + self._wait.until(lambda _: + self._driver.find_element_by_xpath('id("enable")')) + except selenium.common.exceptions.TimeoutException, e: + logging.exception('Unable to find the radio button on the main landing ' + 'page.\nWebDriver exception: %s', str(e)) + return False + return True + + def SetMode(self, mode, band=None): + # Mode overrides the band. So if a band change is made after a mode change + # it may make an incompatible pairing. + self.AddItemToCommandList(self._SetMode, (mode, band), 1, 800) + + def _SetMode(self, mode, band=None): + # Create the mode to popup item mapping + mode_mapping = {self.mode_b: '802.11b Only', self.mode_g: '802.11g Only', + self.mode_n: '802.11n Only', + self.mode_b | self.mode_g: 'Mixed 802.11g and 802.11b', + self.mode_n | self.mode_g: 'Mixed 802.11n and 802.11g', + self.mode_n | self.mode_g | self.mode_b: + 'Mixed 802.11n, 802.11g, and 802.11b', + self.mode_n | self.mode_g | self.mode_b: + 'Mixed 802.11n, 802.11g, and 802.11b', + self.mode_a: '802.11a Only', + self.mode_n | self.mode_a: 'Mixed 802.11n and 802.11a'} + band_value = self.band_2ghz + if mode in mode_mapping.keys(): + popup_value = mode_mapping[mode] + # If the mode contains 802.11a we use 5Ghz + if mode & self.mode_a == self.mode_a: + band_value = self.band_5ghz + # If the mode is 802.11n mixed with 802.11a it must be 5Ghz + elif mode & (self.mode_n | self.mode_a) == (self.mode_n | self.mode_a): + band_value = self.band_5ghz + # If the mode is 802.11n mixed with something other than 802.11a its 2Ghz + elif mode & self.mode_n == self.mode_n and mode ^ self.mode_n > 0: + band_value = self.band_2ghz + # If the mode is 802.11n then we default to 5Ghz unless there is a band + elif mode == self.mode_n: + band_value = self.band_5ghz + if band: + band_value = band + else: + logging.exception('The mode selected %d is not supported by router %s.', + hex(mode), self.getRouterName()) + # Set the band first + self._SetBand(band_value) + popup_id = 'mode_80211_11g' + if band_value == self.band_5ghz: + popup_id = 'mode_80211_11a' + self.SelectItemFromPopupByID(popup_value, popup_id) + + def SetRadio(self, enabled=True): + # If we are enabling we are activating all other UI components, do it first. + # Otherwise we are turning everything off so do it last. + if enabled: + weight = 1 + else: + weight = 1000 + # This disables all UI so it should be the last item to be changed + self.AddItemToCommandList(self._SetRadio, (enabled,), 1, weight) + + def _SetRadio(self, enabled=True): + # The radio checkbox for this router always has a value of 1. So we need to + # use other methods to determine if the radio is on or not. Check if the + # ssid textfield is disabled. + ssid = self._driver.find_element_by_xpath('//input[@name="ssid"]') + if ssid.get_attribute('disabled') == 'true': + radio_enabled = False + else: + radio_enabled = True + print 'radio_enabled = %d; enabld = %d' % (radio_enabled, enabled) + if radio_enabled == enabled: + # Nothing to do + return + self.SetCheckBoxSelectedByID('enable', selected=False, + wait_for_xpath='id("security_type_ap")') + + def SetSSID(self, ssid): + # Can be done as long as it is enabled + self.AddItemToCommandList(self._SetSSID, (ssid,), 1, 900) + + def _SetSSID(self, ssid): + self._SetRadio(enabled=True) + self.SetContentOfTextFieldByID(ssid, 'ssid') + + def SetChannel(self, channel): + self.AddItemToCommandList(self._SetChannel, (channel,), 1, 900) + + def _SetChannel(self, channel): + self._SetRadio(enabled=True) + self.SetCheckBoxSelectedByID('autochann', selected=False) + self.SelectItemFromPopupByID(str(channel), 'channel_g') + + # Experimental + def GetBand(self): + # The radio buttons do more than run a script that adjusts the possible + # channels. We will just check the channel to popup. + self.setRadioSetting(enabled=True) + xpath = ('id("channel_g")') + self._OpenConfigurationPage() + try: + self._wait.until(lambda _: self._driver.find_element_by_xpath(xpath)) + except selenium.common.exceptions.TimeoutException, e: + logging.exception('WebDriver exception: %s', str(e)) + element = self._driver.find_element_by_xpath(xpath) + if element.find_elements_by_tag_name('option')[0].text == '1': + return self.band_2ghz + return self.band_5ghz + + def SetBand(self, band): + if band != self.band_2GHz or band != self.band_5ghz: + self.fail(msg='Invalid band sent %s' % band) + self.AddItemToCommandList(self._SetBand, (band,), 1, 900) + + def _SetBand(self, band): + self._SetRadio(enabled=True) + if band == self.band_2ghz: + int_value = 0 + wait_for_xpath = 'id("mode_80211_11g")' + elif band == self.band_5ghz: + int_value = 1 + wait_for_xpath = 'id("mode_80211_11a")' + xpath = ('//*[contains(@class, "l_tb")]/input[@value="%d" and @name="band"]' + % int_value) + element = self._driver.find_element_by_xpath(xpath) + element.click() + try: + self._wait.until(lambda _: + self._driver.find_element_by_xpath(wait_for_xpath)) + except selenium.common.exceptions.TimeoutException, e: + logging.exception('The appropriate mode popup could not be found after ' + 'adjusting the band. WebDriver exception: %s', str(e)) + + def SetSecurityDisabled(self): + self.AddItemToCommandList(self._SetSecurityDisabled, (), 1, 900) + + def _SetSecurityDisabled(self): + self._SetRadio(enabled=True) + self.SelectItemFromPopupByID(self.security_disabled, 'security_type_ap') + + def SetSecurityWEP(self, key_value, authentication): + self.AddItemToCommandList(self._SetSecurityWEP, (key_value, authentication), + 1, 900) + + def _SetSecurityWEP(self, key_value, authentication): + self._SetRadio(enabled=True) + self.SelectItemFromPopupByID(self.security_wep, 'security_type_ap', + wait_for_xpath='id("auth_type")') + self.SelectItemFromPopupByID(authentication, 'auth_type', + wait_for_xpath='id("wep_key_value")') + self.SetContentOfTextFieldByID(key_value, 'wep_key_value') + self.SetContentOfTextFieldByID(key_value, 'verify_wep_key_value') + + def SetSecurityWPAPSK(self, shared_key, update_interval=1800): + self.AddItemToCommandList(self._SetSecurityWPAPSK, + (shared_key, update_interval), 1, 900) + + def _SetSecurityWPAPSK(self, shared_key, update_interval=1800): + self._SetRadio(enabled=True) + self.SelectItemFromPopupByID(self.security_wpapsk, 'security_type_ap', + wait_for_xpath='id("wpa_mode")') + self.SelectItemFromPopupByID('WPA Only', 'wpa_mode', + wait_for_xpath='id("grp_key_interval")') + self.SetContentOfTextFieldByID(str(update_interval), 'grp_key_interval') + self.SetContentOfTextFieldByID(shared_key, 'wpapsk1') + + def SetVisibility(self, visible=True): + self.AddItemToCommandList(self._SetVisibility, (visible,), 1, 900) + + def _SetVisibility(self, visible=True): + self._SetRadio(enabled=True) + # value=0 is visible; value=1 is invisible + int_value = 0 + if not visible: + int_value = 1 + xpath = ('//*[contains(@class, "l_tb")]/input[@value="%d" ' + 'and @name="visibility_status"]' % int_value) + element = self._driver.find_element_by_xpath(xpath) + element.click() + diff --git a/chrome/test/functional/ap_lab/linksys_ap_configurator.py b/chrome/test/functional/ap_lab/linksys_ap_configurator.py new file mode 100644 index 0000000..4e65e71 --- /dev/null +++ b/chrome/test/functional/ap_lab/linksys_ap_configurator.py @@ -0,0 +1,192 @@ +# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import logging +import os + +import ap_configurator +import selenium.common.exceptions + + +class LinksysAPConfigurator(ap_configurator.APConfigurator): + + def __init__(self, pyauto_instance, admin_interface_url): + super(LinksysAPConfigurator, self).__init__(pyauto_instance) + # Override constants + self.security_disabled = 'Disabled' + self.security_wep = 'WEP' + self.security_wpapsk = 'WPA Personal' + self.security_wpa2psk = 'WPA2 Personal' + self.security_wpa8021x = 'WPA Enterprise' + self.security_wpa28021x = 'WPA2 Enterprise' + + self.admin_interface_url = admin_interface_url + + def GetRouterName(self): + return 'Router Name: WRT54G2; Class: LinksysAPConfigurator' + + def GetNumberOfPages(self): + return 2 + + def GetSupportedBands(self): + return [{'band': self.k2GHz, + 'channels': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]}] + + def GetSupportedModes(self): + return [{'band': self.band_2ghz, + 'modes': [self.mode_b, self.mode_g, self.mode_b | self.mode_g]}] + + def NavigateToPage(self, page_number): + if page_number == 1: + self.pyauto_instance.NavigateToURL('http://%s/wireless.htm' + % self.admin_interface_url) + elif page_number == 2: + self.pyauto_instance.NavigateToURL('http://%s/WSecurity.htm' + % self.admin_interface_url) + else: + logging.exception('Invalid page number passed. Number of pages %d, ' + 'page value sent was %d', self.GetNumberOfPages(), + page_number) + return False + return True + + def SavePage(self, page_number): + try: + self._wait.until(lambda _: + self._driver.find_element_by_xpath('id("divBT1")')) + except selenium.common.exceptions.TimeoutException, e: + logging.exception('Unable to locate the save button.\nWebDriver' + ' exception: %s', str(e)) + return False + button = self._driver.find_element_by_xpath('id("divBT1")') + button.click() + # Wait for the continue button + continue_xpath = '//input[@value="Continue" and @type="button"]' + try: + self._wait.until(lambda _: + self._driver.find_element_by_xpath(continue_xpath)) + except selenium.common.exceptions.TimeoutException, e: + logging.exception('Unable to location the continue button, save probably' + ' failed.\nWebDriver exception: %s', str(e)) + return False + button = self._driver.find_element_by_xpath(continue_xpath) + button.click() + return True + + def SetMode(self, mode, band=None): + self.AddItemToCommandList(self._SetMode, (mode,), 1, 900) + + def _SetMode(self, mode): + # Different bands are not supported so we ignore. + # Create the mode to popup item mapping + mode_mapping = {self.mode_b: 'B-Only', self.mode_g: 'G-Only', + self.mode_b | self.mode_g: 'Mixed'} + mode_name = '' + if mode in mode_mapping.keys(): + mode_name = mode_mapping[mode] + else: + logging.exception('The mode selected %d is not supported by router %s.', + hex(mode), self.getRouterName()) + xpath = ('//select[@onchange="SelWL()" and @name="Mode"]') + self.SelectItemFromPopupByXPath(mode_name, xpath) + + def SetRadio(self, enabled=True): + # If we are enabling we are activating all other UI components, do it + # first. Otherwise we are turning everything off so do it last. + if enabled: + weight = 1 + else: + weight = 1000 + self.AddItemToCommandList(self._SetRadio, (enabled,), 1, weight) + + def _SetRadio(self, enabled=True): + xpath = ('//select[@onchange="SelWL()" and @name="Mode"]') + # To turn off we pick disabled, to turn on we set to G + if not enabled: + setting = 'Disabled' + else: + setting = 'G-Only' + self.SelectItemFromPopupByXPath(setting, xpath) + + def SetSSID(self, ssid): + self.AddItemToCommandList(self._SetSSID, (ssid,), 1, 900) + + def _SetSSID(self, ssid): + self._SetRadio(enabled=True) + xpath = ('//input[@maxlength="32" and @name="SSID"]') + self.SetConentsOfTextFieldByXPath(ssid, xpath) + + def SetChannel(self, channel): + self.AddItemToCommandList(self._SetChannel, (channel,), 1, 900) + + def _SetChannel(self, channel): + self._SetRadio(enabled=True) + channel_choices = ['1 - 2.412GHz', '2 - 2.417GHz', '3 - 2.422GHz', + '4 - 2.427GHz', '5 - 2.432GHz', '6 - 2.437GHz', + '7 - 2.442GHz', '8 - 2.447GHz', '9 - 2.452GHz', + '10 - 2.457GHz', '11 - 2.462GHz'] + xpath = ('//select[@onfocus="check_action(this,0)" and @name="Freq"]') + self.SelectItemFromPopupByXPath(channel_choices[channel - 1], xpath) + + def SetBand(self, band): + return None + + def SetSecurityDisabled(self): + self.AddItemToCommandList(self._SetSecurityDisabled, (), 2, 1000) + + def _SetSecurityDisabled(self): + xpath = ('//select[@name="SecurityMode"]') + self.SelectItemFromPopupByXPath(self.security_disabled, xpath) + + def SetSecurityWEP(self, key_value, authentication): + self.AddItemToCommandList(self._SetSecurityWEP, (key_value, authentication), + 2, 1000) + + def _SetSecurityWEP(self, key_value, authentication): + logging.info('This router %s does not support WEP authentication type: %s', + self.GetRouterName(), authentication) + popup = '//select[@name="SecurityMode"]' + try: + self._wait.until(lambda _: self._driver.find_element_by_xpath(popup)) + except selenium.common.exceptions.TimeoutException, e: + logging.exception('Unable to find the security mode pop up.\nWebDriver ' + ' exception: %s', str(e)) + text_field = ('//input[@name="wl_passphrase"]') + self.SelectItemFromPopupByXPath(self.security_wep, popup, + wait_for_xpath=text_field) + self.SetConentsOfTextFieldByXPath(key_value, text_field) + button = self._driver.find_element_by_xpath('//input[@value="Generate"]') + button.click() + + def SetSecurityWPAPSK(self, shared_key, update_interval=1800): + self.AddItemToCommandList(self._SetSecurityWPAPSK, + (shared_key, update_interval), 1, 900) + + def _SetSecurityWPAPSK(self, shared_key, update_interval=1800): + popup = '//select[@name="SecurityMode"]' + try: + self._wait.until(lambda _: self._driver.find_element_by_xpath(popup)) + except selenium.common.exceptions.TimeoutException, e: + logging.exception('Unable to find the security mode pop up. WebDriver ' + ' exception: %s', str(e)) + key_field = '//input[@name="PassPhrase"]' + self.SelectItemFromPopupByXPath(self.security_wpapsk, popup, + wait_for_xpath=key_field) + self.SetConentsOfTextFieldByXPath(shared_key, key_field) + interval_field = ('//input[@name="GkuInterval"]') + self.SetConentsOfTextFieldByXPath(str(update_interval), interval_field) + + def SetVisibility(self, visible=True): + self.AddItemToCommandList(self._SetVisibility, (visible,), 1, 900) + + def _SetVisibility(self, visible=True): + self._SetRadio(enabled=True) + # value=1 is visible; value=0 is invisible + int_value = 1 + if not visible: + int_value = 0 + xpath = ('//input[@value="%d" and @name="wl_closed"]' % int_value) + element = self._driver.find_element_by_xpath(xpath) + element.click() + diff --git a/chrome/test/functional/ap_lab/pyauto_ap_configurator.py b/chrome/test/functional/ap_lab/pyauto_ap_configurator.py new file mode 100644 index 0000000..3e99a5517 --- /dev/null +++ b/chrome/test/functional/ap_lab/pyauto_ap_configurator.py @@ -0,0 +1,25 @@ +# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Setup for AP Configurator Pyauto tests.""" + +import os +import sys + + +def _SetupPaths(): + """Setting path to find pyauto_functional.py.""" + ap_configurator_dir = os.path.abspath(os.path.dirname(__file__)) + sys.path.append(ap_configurator_dir) + sys.path.append(os.path.normpath(os.path.join(ap_configurator_dir, + os.pardir))) + +_SetupPaths() + + +from pyauto_functional import Main + + +if __name__ == '__main__': + Main() |