Create a servo based WiFi suspend resume test.
BUG=chromium:358924
TEST=Manual; ran it
Change-Id: I40b0f724fecc343ff8784994c2d87841b32c532e
Reviewed-on: https://chromium-review.googlesource.com/212956
Reviewed-by: Kris Rambish <krisr@chromium.org>
Commit-Queue: Kris Rambish <krisr@chromium.org>
Tested-by: Kris Rambish <krisr@chromium.org>
diff --git a/server/cros/network/wifi_test_context_manager.py b/server/cros/network/wifi_test_context_manager.py
index 391279f..2a17fda 100644
--- a/server/cros/network/wifi_test_context_manager.py
+++ b/server/cros/network/wifi_test_context_manager.py
@@ -16,6 +16,9 @@
from autotest_lib.server.cros.network import attenuator_controller
from autotest_lib.server.cros.network import wifi_client
+from collections import namedtuple
+
+ConnectTime = namedtuple('ConnectTime', 'state, time')
class WiFiTestContextManager(object):
"""A context manager for state used in WiFi autotests.
@@ -287,6 +290,7 @@
@param timeout_seconds int number of seconds to wait for
connection on the given frequency.
+ @returns a named tuple of (state, time)
"""
POLLING_INTERVAL_SECONDS = 1.0
start_time = time.time()
@@ -296,7 +300,7 @@
ap_num = 0
desired_subnet = self.router.get_wifi_ip_subnet(ap_num)
while duration() < timeout_seconds:
- success, state, _ = self.client.wait_for_service_states(
+ success, state, conn_time = self.client.wait_for_service_states(
ssid, self.CONNECTED_STATES, timeout_seconds - duration())
if not success:
time.sleep(POLLING_INTERVAL_SECONDS)
@@ -319,7 +323,7 @@
continue
self.assert_ping_from_dut(ap_num=ap_num)
- return
+ return ConnectTime(state, conn_time)
freq_error_str = (' on frequency %d Mhz' % freq) if freq else ''
raise error.TestFail(
diff --git a/server/site_tests/network_WiFi_SuspendStress/control.11a b/server/site_tests/network_WiFi_SuspendStress/control.11a
new file mode 100644
index 0000000..3f862e4
--- /dev/null
+++ b/server/site_tests/network_WiFi_SuspendStress/control.11a
@@ -0,0 +1,40 @@
+# Copyright 2014 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+from autotest_lib.server import utils
+
+AUTHOR = 'krisr, tienchang, bmahadev'
+NAME = 'network_WiFi_SuspendStress.11a'
+TIME = 'MEDIUM'
+TEST_TYPE = 'Server'
+DEPENDENCIES = 'servo, wificell'
+
+DOC = """
+This test uses servo to simulate lid close and open events and checks that the
+wifi adapter is brought back up and connects to a 802.11a network on channels
+48, 64.
+"""
+
+from autotest_lib.client.common_lib.cros.network import xmlrpc_datatypes
+from autotest_lib.server.cros.network import hostap_config
+
+args_dict = utils.args_to_dict(args)
+servo_args = hosts.CrosHost.get_servo_arguments(args_dict)
+
+def run(machine):
+ host = hosts.create_host(machine, servo_args=servo_args)
+ a_mode = hostap_config.HostapConfig.MODE_11A
+ configurations = [(hostap_config.HostapConfig(channel=48, mode=a_mode),
+ xmlrpc_datatypes.AssociationParameters()),
+ (hostap_config.HostapConfig(channel=64, mode=a_mode),
+ xmlrpc_datatypes.AssociationParameters())]
+
+ job.run_test('network_WiFi_SuspendStress',
+ host=host,
+ tag=NAME.split('.')[1],
+ suspends=5,
+ raw_cmdline_args=args,
+ additional_params=configurations)
+
+parallel_simple(run, machines)
diff --git a/server/site_tests/network_WiFi_SuspendStress/network_WiFi_SuspendStress.py b/server/site_tests/network_WiFi_SuspendStress/network_WiFi_SuspendStress.py
new file mode 100644
index 0000000..c2df90b
--- /dev/null
+++ b/server/site_tests/network_WiFi_SuspendStress/network_WiFi_SuspendStress.py
@@ -0,0 +1,103 @@
+# Copyright (c) 2014 The Chromium OS 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 json
+import logging
+import time
+from autotest_lib.client.common_lib.cros.network import xmlrpc_datatypes
+from autotest_lib.server import autotest
+from autotest_lib.server.cros import stress
+from autotest_lib.server.cros.network import wifi_cell_test_base
+
+_DELAY = 10
+_CLIENT_TERMINATION_FILE_PATH = '/tmp/simple_login_exit'
+
+
+class network_WiFi_SuspendStress(wifi_cell_test_base.WiFiCellTestBase):
+ """Uses servo to repeatedly close & open lid while running BrowserTests."""
+ version = 1
+
+
+ def parse_additional_arguments(self, commandline_args, additional_params):
+ """Hook into super class to take control files parameters.
+
+ @param commandline_args dict of parsed parameters from the autotest.
+ @param additional_params list of tuple(HostapConfig,
+ AssociationParameters).
+ """
+ self._configurations = additional_params
+
+
+ def logged_in(self):
+ """Checks if the host has a logged in user.
+
+ @return True if a user is logged in on the device.
+
+ """
+ try:
+ out = self._host.run('cryptohome --action=status').stdout
+ except:
+ return False
+ try:
+ status = json.loads(out.strip())
+ except ValueError:
+ logging.info('Cryptohome did not return a value.')
+ return False
+
+ success = any((mount['mounted'] for mount in status['mounts']))
+ if success:
+ # Chrome needs a few moments to get ready, otherwise an immediate
+ # suspend will power down the system.
+ time.sleep(5)
+ return success
+
+
+ def stress_wifi_suspend(self):
+ """Perform the suspend stress."""
+ self._host.servo.lid_close()
+ self._host.wait_down(timeout=_DELAY)
+ self._host.servo.lid_open()
+ self._host.wait_up(timeout=_DELAY)
+ state_info = self.context.wait_for_connection(
+ self.context.router.get_ssid())
+ self._timings.append(state_info.time)
+
+
+ def exit_client(self):
+ """End the client side test."""
+ self._host.run('touch %s' % _CLIENT_TERMINATION_FILE_PATH)
+
+
+ def run_once(self, suspends=5):
+ self._host = self.context.client.host
+ for router_conf, client_conf in self._configurations:
+ self.context.configure(router_conf)
+ assoc_params = xmlrpc_datatypes.AssociationParameters(
+ ssid=self.context.router.get_ssid())
+ self.context.assert_connect_wifi(assoc_params)
+
+ self._timings = list()
+
+ autotest_client = autotest.Autotest(self._host)
+ stressor = stress.CountedStressor(self.stress_wifi_suspend,
+ on_exit=self.exit_client)
+ stressor.start(suspends, start_condition=self.logged_in)
+ autotest_client.run_test('desktopui_SimpleLogin')
+ stressor.wait()
+
+ perf_dict = {'fastest': max(self._timings),
+ 'slowest': min(self._timings),
+ 'average': (float(sum(self._timings)) /
+ len(self._timings))}
+ for key in perf_dict:
+ self.output_perf_value(description=key,
+ value=perf_dict[key],
+ units='seconds',
+ higher_is_better=False,
+ graph=router_conf.perf_loggable_description)
+
+
+ def cleanup(self):
+ """Cold reboot the device so the WiFi card is back in a good state."""
+ self._host.servo.get_power_state_controller().reset()