1# Copyright 2015 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5import json
6import logging
7import time
8from autotest_lib.client.common_lib import error
9from autotest_lib.client.common_lib.cros.network import xmlrpc_datatypes
10from autotest_lib.server import autotest
11from autotest_lib.server.cros import stress
12from autotest_lib.server.cros.network import wifi_cell_test_base
13
14_DELAY = 10
15_CLIENT_TERMINATION_FILE_PATH = '/tmp/simple_login_exit'
16_START_TIMEOUT_SECONDS = 20
17
18
19class network_WiFi_SuspendStress(wifi_cell_test_base.WiFiCellTestBase):
20    """Uses servo to repeatedly close & open lid while running BrowserTests."""
21    version = 1
22
23
24    def parse_additional_arguments(self, commandline_args, additional_params):
25        """Hook into super class to take control files parameters.
26
27        @param commandline_args dict of parsed parameters from the autotest.
28        @param additional_params list of tuple(HostapConfig,
29                                               AssociationParameters).
30        """
31        self._configurations = additional_params
32
33
34    def logged_in(self):
35        """Checks if the host has a logged in user.
36
37        @return True if a user is logged in on the device.
38
39        """
40        try:
41            out = self._host.run('cryptohome --action=status').stdout
42        except:
43            return False
44        try:
45            status = json.loads(out.strip())
46        except ValueError:
47            logging.info('Cryptohome did not return a value.')
48            return False
49
50        success = any((mount['mounted'] for mount in status['mounts']))
51        if success:
52            # Chrome needs a few moments to get ready, otherwise an immediate
53            # suspend will power down the system.
54            time.sleep(5)
55        return success
56
57
58    def stress_wifi_suspend(self):
59        """Perform the suspend stress."""
60
61        # servo might be taking time to come up; wait a bit
62        if not self._host.servo:
63           time.sleep(10)
64
65        if self._host.servo.get('lid_open') == 'not_applicable':
66            self.context.client.do_suspend(10)
67        else:
68            self._host.servo.lid_close()
69            self._host.wait_down(timeout=_DELAY)
70            self._host.servo.lid_open()
71            self._host.wait_up(timeout=_DELAY)
72
73        state_info = self.context.wait_for_connection(
74            self.context.router.get_ssid())
75        self._timings.append(state_info.time)
76
77
78    def exit_client(self):
79        """End the client side test."""
80        self._host.run('touch %s' % _CLIENT_TERMINATION_FILE_PATH)
81
82
83    def run_once(self, suspends=5):
84        self._host = self.context.client.host
85
86        if not self._host.servo:
87            raise error.TestNAError(
88                'Servo object returned None. Check if servo is missing or bad')
89
90        # If the DUT is up and cold_reset is set to on, that means the DUT does
91        # not support cold_reset.  We can't run the test, because it may get
92        # in a bad state and we won't be able to recover.
93        if self._host.servo.get('cold_reset') == 'on':
94            raise error.TestNAError('This DUT does not support cold reset, '
95                                    'exiting')
96        for router_conf, client_conf in self._configurations:
97            self.context.configure(configuration_parameters=router_conf)
98            assoc_params = xmlrpc_datatypes.AssociationParameters(
99                is_hidden=client_conf.is_hidden,
100                security_config=client_conf.security_config,
101                ssid=self.context.router.get_ssid())
102            self.context.assert_connect_wifi(assoc_params)
103
104            self._timings = list()
105
106            autotest_client = autotest.Autotest(self._host)
107            stressor = stress.CountedStressor(self.stress_wifi_suspend,
108                                              on_exit=self.exit_client)
109            stressor.start(suspends,
110                           start_condition=self.logged_in,
111                           start_timeout_secs=_START_TIMEOUT_SECONDS)
112            autotest_client.run_test('desktopui_SimpleLogin')
113            stressor.wait()
114
115            perf_dict = {'fastest': max(self._timings),
116                         'slowest': min(self._timings),
117                         'average': (float(sum(self._timings)) /
118                                     len(self._timings))}
119            for key in perf_dict:
120                self.output_perf_value(description=key,
121                    value=perf_dict[key],
122                    units='seconds',
123                    higher_is_better=False,
124                    graph=router_conf.perf_loggable_description)
125
126
127    def cleanup(self):
128        """Cold reboot the device so the WiFi card is back in a good state."""
129        if self._host.servo and self._host.servo.get('cold_reset') == 'off':
130            self._host.servo.get_power_state_controller().reset()
131