summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkrisr@chromium.org <krisr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-04-09 22:37:55 +0000
committerkrisr@chromium.org <krisr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-04-09 22:37:55 +0000
commit7be4a96af7eecf23ec5d8655fc8bb4c1558897e2 (patch)
treecfcea28e9a05ba227f54a2a9598a35ba85899727
parent92ff0a7db633bde3ae4971cceac127b55041dca6 (diff)
downloadchromium_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.py348
-rw-r--r--chrome/test/functional/ap_lab/ap_configurator_test.py142
-rw-r--r--chrome/test/functional/ap_lab/dlink_ap_configurator.py289
-rw-r--r--chrome/test/functional/ap_lab/linksys_ap_configurator.py192
-rw-r--r--chrome/test/functional/ap_lab/pyauto_ap_configurator.py25
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()