summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordtu@chromium.org <dtu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-04-06 22:07:15 +0000
committerdtu@chromium.org <dtu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-04-06 22:07:15 +0000
commit2831638398f9ab2b991009c1e380395758c98e60 (patch)
tree327d974ef60426b8182c52e3d434b5e34b89bf4a
parent9cb31511cb8ba57c36157c5a509ffd3fe4568437 (diff)
downloadchromium_src-2831638398f9ab2b991009c1e380395758c98e60.zip
chromium_src-2831638398f9ab2b991009c1e380395758c98e60.tar.gz
chromium_src-2831638398f9ab2b991009c1e380395758c98e60.tar.bz2
Initial inclusion of power_strip code.
Including WifiRouterStrip code that is used for power_strips that exclusively have Wifi routers attached to them. Added first connect test case using the power strip. BUG= TEST=run chromeos_wifi.py Review URL: http://codereview.chromium.org/6764022 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@80704 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/test/functional/chromeos_wifi.py10
-rw-r--r--chrome/test/functional/chromeos_wifi_compliance.py53
-rw-r--r--chrome/test/pyautolib/chromeos/__init__.py0
-rw-r--r--chrome/test/pyautolib/chromeos/power_strip.py78
-rw-r--r--chrome/test/pyautolib/chromeos_network.py196
-rw-r--r--chrome/test/pyautolib/pyauto.py22
6 files changed, 342 insertions, 17 deletions
diff --git a/chrome/test/functional/chromeos_wifi.py b/chrome/test/functional/chromeos_wifi.py
index 0019003..131f4a6 100644
--- a/chrome/test/functional/chromeos_wifi.py
+++ b/chrome/test/functional/chromeos_wifi.py
@@ -12,22 +12,18 @@ import chromeos_network # pyauto_functional must come before chromeos_network
class ChromeosWifi(chromeos_network.PyNetworkUITest):
"""Tests for ChromeOS wifi."""
- def testNetworkInfo(self):
+ def testNetworkInfoAndScan(self):
"""Get basic info on networks."""
- result = self.GetNetworkInfo()
+ # NetworkScan will also call GetNetworkInfo and return the results.
+ result = self.NetworkScan()
self.assertTrue(result)
logging.debug(result)
- def testNetworkScan(self):
- """Basic check to ensure that a network scan doesn't throw errors."""
- self.NetworkScan()
-
def testGetProxySettings(self):
"""Print some information about proxy settings."""
result = self.GetProxySettingsOnChromeOS()
self.assertTrue(result)
logging.debug(result)
-
if __name__ == '__main__':
pyauto_functional.Main()
diff --git a/chrome/test/functional/chromeos_wifi_compliance.py b/chrome/test/functional/chromeos_wifi_compliance.py
new file mode 100644
index 0000000..b66be87
--- /dev/null
+++ b/chrome/test/functional/chromeos_wifi_compliance.py
@@ -0,0 +1,53 @@
+#!/usr/bin/python
+# Copyright (c) 2011 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 pyauto_functional
+import chromeos_network # pyauto_functional must come before chromeos_network
+
+
+class ChromeosWifiCompliance(chromeos_network.PyNetworkUITest):
+ """Tests for ChromeOS wifi complaince.
+
+ These tests should be run within vacinity of the power strip where the wifi
+ routers are attached.
+ """
+
+ def _BasicConnectRouterCompliance(self, router_name):
+ """Generic basic test routine for connecting to a router.
+
+ Args:
+ router_name: The name of the router.
+ """
+ self.InitWifiPowerStrip()
+ router = self.GetRouterConfig(router_name)
+ self.RouterPower(router_name, True)
+
+ self.assertTrue(self.WaitUntilWifiNetworkAvailable(router['ssid']),
+ 'Wifi network %s never showed up.' % router['ssid'])
+
+ # Verify connect did not have any errors.
+ error = self.ConnectToWifiRouter(router_name)
+ self.assertFalse(error, 'Failed to connect to wifi network %s. '
+ 'Reason: %s.' % (router['ssid'], error))
+
+ # Verify the network we connected to.
+ ssid = self.GetConnectedWifi()
+ self.assertEqual(ssid, router['ssid'],
+ 'Did not successfully connect to wifi network %s.' % ssid)
+
+ self.DisconnectFromWifiNetwork()
+ self.RouterPower(router_name, False)
+
+ def testConnectBelkinG(self):
+ """Test connecting to the Belkin G router."""
+ self._BasicConnectRouterCompliance('Belkin_G')
+
+ def testConnectLinksysWRT54G2(self):
+ """Test connecting to the Linksys WRT54G2 router."""
+ self._BasicConnectRouterCompliance('Linksys_WRT54G2')
+
+
+if __name__ == '__main__':
+ pyauto_functional.Main()
diff --git a/chrome/test/pyautolib/chromeos/__init__.py b/chrome/test/pyautolib/chromeos/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/chrome/test/pyautolib/chromeos/__init__.py
diff --git a/chrome/test/pyautolib/chromeos/power_strip.py b/chrome/test/pyautolib/chromeos/power_strip.py
new file mode 100644
index 0000000..50d7b19
--- /dev/null
+++ b/chrome/test/pyautolib/chromeos/power_strip.py
@@ -0,0 +1,78 @@
+# Copyright (c) 2011 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 telnetlib
+
+
+class PowerStrip(object):
+ """Controls Server Technology CW-16V1-C20M switched CDUs.
+ (Cabinet Power Distribution Unit)
+
+ This class is used to control the CW-16V1-C20M unit which
+ is a 16 port remote power strip. The strip supports AC devices
+ using 100-120V 50/60Hz input voltages. The commands in this
+ class are supported by switches that use Sentry Switched CDU Version 6.0g.
+
+ Opens a new connection for every command.
+ """
+
+ def __init__(self, host, user='admn', password='admn'):
+ self._host = host
+ self._user = user
+ self._password = password
+
+ def PowerOff(self, outlet):
+ """Powers off the device that is plugged into the specified outlet.
+
+ Args:
+ outlet: The outlet ID defined on the switch (eg. .a14).
+ """
+ self._DoCommand('off', outlet)
+
+ def PowerOn(self, outlet):
+ """Powers on the device that is plugged into the specified outlet.
+
+ Args:
+ outlet: The outlet ID defined on the switch (eg. .a14).
+ """
+ self._DoCommand('on', outlet)
+
+ def _DoCommand(self, command, outlet):
+ """Performs power strip commands on the specified outlet.
+
+ Sample telnet interaction:
+ Escape character is '^]'.
+
+ Sentry Switched CDU Version 6.0g
+
+ Username: admn
+ Password: < password hidden from view >
+
+ Location:
+
+ Switched CDU: on .a1
+
+ Outlet Outlet Outlet Control
+ ID Name Status State
+
+ .A1 TowerA_Outlet1 On On
+
+ Command successful
+
+ Switched CDU: < cdu cmd >
+
+ Args:
+ command: A valid CW-16V1-C20M command that follows the format
+ <command> <outlet>.
+ outlet: The outlet ID defined on the switch (eg. .a14).
+ """
+ tn = telnetlib.Telnet(self._host)
+ tn.read_until('Username: ')
+ tn.write(self._user + '\n')
+ tn.read_until('Password: ')
+ tn.write(self._password + '\n')
+ tn.read_until('Switched CDU: ')
+ tn.write('%s %s\n' % (command, outlet))
+ tn.read_some()
+ tn.close()
diff --git a/chrome/test/pyautolib/chromeos_network.py b/chrome/test/pyautolib/chromeos_network.py
index aaeed55..9146be0 100644
--- a/chrome/test/pyautolib/chromeos_network.py
+++ b/chrome/test/pyautolib/chromeos_network.py
@@ -4,10 +4,104 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import copy
import dbus
+import logging
+import os
+import time
+
+from chromeos.power_strip import PowerStrip
import pyauto
+class WifiPowerStrip(PowerStrip):
+ """Manages the power state of wifi routers connected to a power strip.
+
+ This class provides additional functionality over PowerStrip by providing
+ a timeout feature for wifi routers connected to the strip. This is to prevent
+ repeated on/off calls to the same router which may put the router in an
+ undesired state.
+ """
+
+ def __init__ (self, host, routers):
+ """Initializes a WifiPowerStrip object.
+
+ Args:
+ host: IP of the switch that the routers are attached to.
+ routers: Dictionary of wifi routers in the following format:
+ {
+ '< router name >': {
+ 'strip_id' : '.aX' # where X is the port number
+ < additional fields may be added here for each router >
+ }
+ }
+ """
+ self._router_dict = routers
+
+ # Each router will have a timestamp associated to it regarding whether
+ # or not an action can be performed on it yet. This is to prevent
+ # the spamming of power on/off calls on a particular router.
+ # The WifiPowerStrip_UsableTime field specifies the earliest time
+ # after which the router may be used. We will initialize it to now
+ # since they should all be usable at init.
+ for router_info in self._router_dict.values():
+ router_info['WifiPowerStrip_UsableTime'] = time.time()
+
+ PowerStrip.__init__(self, host)
+
+ def GetRouterConfig(self, router_name):
+ """Returns the configuration for the specified router.
+
+ Args:
+ router_name: A string specifying the router.
+
+ Returns:
+ The config dictionary for the given router if the router is defined.
+ None otherwise.
+ """
+ return copy.deepcopy(self._router_dict.get(router_name))
+
+ def RouterPower(self, router_name, power_state, pause_after=5):
+ """Executes PowerStrip commands.
+
+ Args:
+ router_name: The name of the router to perform the action on.
+ power_state: A boolean value where True represents turning the router on
+ and False represents turning the router off.
+ pause_after: Specified in seconds, and specifies the time to sleep
+ after a command is run. This is to prevent spamming of
+ power on/off of the same router which has put the router
+ in an undesirable state.
+
+ Raises:
+ Exception if router_name is not a valid router.
+ """
+ router = self.GetRouterConfig(router_name)
+ if not router: raise Exception('Invalid router name \'%s\'.' % router_name)
+
+ sleep_time = router['WifiPowerStrip_UsableTime'] - time.time()
+ if sleep_time > 0:
+ sleep(sleep_time)
+
+ if power_state:
+ logging.debug('Turning on router %s:%s.' %
+ (router['strip_id'], router_name))
+ self.PowerOn(router['strip_id'])
+ else:
+ logging.debug('Turning off router %s:%s.' %
+ (router['strip_id'], router_name))
+ self.PowerOff(router['strip_id'])
+
+ # Set the Usable time of the particular router to pause_after
+ # seconds after the current time.
+ router['WifiPowerStrip_UsableTime'] = time.time() + pause_after
+
+ def TurnOffAllRouters(self):
+ """Turns off all the routers."""
+ for router in self._router_dict:
+ self.RouterPower(router, False, pause_after=0)
+
+
class PyNetworkUITest(pyauto.PyUITest):
"""A subclass of PyUITest for Chrome OS network tests.
@@ -15,6 +109,9 @@ class PyNetworkUITest(pyauto.PyUITest):
priorities to put wifi connections first before starting tests.
This is for convenience when writing wifi tests.
"""
+ _ROUTER_CONFIG_FILE = os.path.join(pyauto.PyUITest.DataDir(),
+ 'pyauto_private', 'chromeos', 'network',
+ 'wifi_testbed_config')
_FLIMFLAM_PATH = 'org.chromium.flimflam'
_proxy = dbus.SystemBus().get_object(_FLIMFLAM_PATH, '/')
@@ -26,11 +123,17 @@ class PyNetworkUITest(pyauto.PyUITest):
# test harness might be using and putting wifi ahead.
self._PushServiceOrder('vpn,bluetooth,wifi,wimax,cellular,ethernet')
pyauto.PyUITest.setUp(self)
+ self._wifi_power_strip = None
def tearDown(self):
pyauto.PyUITest.tearDown(self)
self._PopServiceOrder()
+ # If the test case used the WifiPowerStrip, make sure
+ # everything is clean by turning all the routers off.
+ if self._wifi_power_strip:
+ self._wifi_power_strip.TurnOffAllRouters()
+
def _SetServiceOrder(self, service_order):
self._manager.SetServiceOrder(service_order)
self._manager.DisableTechnology('wifi')
@@ -40,9 +143,98 @@ class PyNetworkUITest(pyauto.PyUITest):
self._old_service_order = self._manager.GetServiceOrder()
self._SetServiceOrder(service_order)
assert service_order == self._manager.GetServiceOrder(), \
- 'Flimflam service order not set properly.'
+ 'Flimflam service order not set properly. %s != %s' % \
+ (self._old_service_order, self._manager.GetServiceOrder())
def _PopServiceOrder(self):
self._SetServiceOrder(self._old_service_order)
assert self._old_service_order == self._manager.GetServiceOrder(), \
- 'Flimflam service order not reset properly.'
+ 'Flimflam service order not reset properly. %s != %s' % \
+ (self._old_service_order, self._manager.GetServiceOrder())
+
+ def InitWifiPowerStrip(self):
+ """Initializes the router controller using the specified config file."""
+
+ assert os.path.exists(PyNetworkUITest._ROUTER_CONFIG_FILE), \
+ 'Router configuration file does not exist.'
+
+ config = pyauto.PyUITest.EvalDataFrom(self._ROUTER_CONFIG_FILE)
+ strip_ip, routers = config['strip_ip'], config['routers']
+
+ self._wifi_power_strip = WifiPowerStrip(strip_ip, routers)
+
+ self.RouterPower = self._wifi_power_strip.RouterPower
+ self.TurnOffAllRouters = self._wifi_power_strip.TurnOffAllRouters
+ self.GetRouterConfig = self._wifi_power_strip.GetRouterConfig
+
+ def WaitUntilWifiNetworkAvailable(self, ssid, timeout=60):
+ """Waits until the given network is available.
+
+ Routers that are just turned on may take up to 1 minute upon turning them
+ on to broadcast their SSID.
+
+ Args:
+ ssid: SSID of the service we want to connect to.
+ timeout: timeout (in seconds)
+
+ Raises:
+ Exception if timeout duration has been hit before wifi router is seen.
+
+ Returns:
+ True, when the wifi network is seen within the timout period.
+ False, otherwise.
+ """
+ def _GotWifiNetwork():
+ # Returns non-empty array if desired SSID is available.
+ return [wifi for wifi in
+ self.NetworkScan().get('wifi_networks', {}).values()
+ if wifi.get('name') == ssid]
+
+ return self.WaitUntil(_GotWifiNetwork, timeout=timeout, retry_sleep=1)
+
+ def GetConnectedWifi(self):
+ """Returns the SSID of the currently connected wifi network.
+
+ Returns:
+ The SSID of the connected network or None if we're not connected.
+ """
+ service_list = self.GetNetworkInfo()
+ connected_service_path = service_list.get('connected_wifi')
+ if 'wifi_networks' in service_list and \
+ connected_service_path in service_list['wifi_networks']:
+ return service_list['wifi_networks'][connected_service_path]['name']
+
+ def GetServicePath(self, ssid):
+ """Returns the service path associated with an SSID.
+
+ Args:
+ ssid: String defining the SSID we are searching for.
+
+ Returns:
+ The service path or None if SSID does not exist.
+ """
+ service_list = self.GetNetworkInfo()
+ service_list = service_list.get('wifi_networks', [])
+ for service_path, service_obj in service_list.iteritems():
+ if service_obj['name'] == ssid:
+ return service_path
+ return None
+
+ def ConnectToWifiRouter(self, router_name):
+ """Connects to a router by name.
+
+ Args:
+ router_name: The name of the router that is specified in the
+ configuration file.
+ """
+ router = self._wifi_power_strip.GetRouterConfig(router_name)
+ assert router, 'Router with name %s is not defined ' \
+ 'in the router configuration.' % router_name
+
+ service_path = self.GetServicePath(router['ssid'])
+ assert service_path, 'Service with SSID %s is not present.' % router['ssid']
+
+ passphrase = router.get('passphrase', '')
+
+ logging.debug('Connecting to router %s.' % router_name)
+ return self.ConnectToWifiNetwork(service_path, passphrase)
diff --git a/chrome/test/pyautolib/pyauto.py b/chrome/test/pyautolib/pyauto.py
index 46ff17c..c091c59 100644
--- a/chrome/test/pyautolib/pyauto.py
+++ b/chrome/test/pyautolib/pyauto.py
@@ -2504,11 +2504,15 @@ class PyUITest(pyautolib.PyUITestBase, unittest.TestCase):
Blocks until scanning is complete.
+ Returns:
+ The new list of networks obtained from GetNetworkInfo().
+
Raises:
pyauto_errors.JSONInterfaceError if the automation call returns an error.
"""
cmd_dict = { 'command': 'NetworkScan' }
self._GetResultFromJSONRequest(cmd_dict, windex=-1)
+ return self.GetNetworkInfo()
PROXY_TYPE_DIRECT = 1
PROXY_TYPE_MANUAL = 2
@@ -2609,10 +2613,15 @@ class PyUITest(pyautolib.PyUITestBase, unittest.TestCase):
Blocks until connection succeeds or fails.
+ Args:
+ service_path: Flimflam path that defines the wifi network.
+ password: Passphrase for connecting to the wifi network.
+ identity: Identity for 802.11x networks.
+ certpath: Certificate path for 802.11x networks.
+
Returns:
- A tuple.
- The first element is True on success and False on failure.
- The second element is None on success or an error string on failure.
+ An error string if an error occured.
+ None otherwise.
Raises:
pyauto_errors.JSONInterfaceError if the automation call returns an error.
@@ -2625,13 +2634,10 @@ class PyUITest(pyautolib.PyUITestBase, unittest.TestCase):
'certpath': certpath,
}
result = self._GetResultFromJSONRequest(cmd_dict, windex=-1)
- if result.has_key('error_code'):
- return (False, result['error_code'])
- else:
- return (True, None)
+ return result.get('error_code')
def DisconnectFromWifiNetwork(self):
- """Disconnect from a wifi network by its service path.
+ """Disconnect from the connected wifi network.
Blocks until disconnect is complete.