1# Lint as: python2, python3
2# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6# WARNING(crbug.com/743265): This test is currently broken because the ability
7# to run client tests in the background from a server-side test has been
8# deleted.
9
10import logging, time
11
12from autotest_lib.server import autotest, test
13from autotest_lib.client.common_lib import error
14
15_SUSPEND_TIME = 60
16_SUSPEND_TIMEOUT = 30
17
18class power_USBHotplugInSuspend(test.test):
19
20    version = 1
21
22    # Constant to wait in seconds after turning on or off the usb port power.
23    USB_POWEROFF_DELAY_S = 2
24
25
26    def _switch_usbkey_power(self, on):
27        """
28        Turn on/off the power to the USB key.
29
30        @param on True to turn on, false otherwise.
31        """
32        if on:
33            self._host.servo.set('image_usbkey_pwr', 'on')
34        else:
35            self._host.servo.set('image_usbkey_pwr', 'off')
36        time.sleep(self.USB_POWEROFF_DELAY_S)
37
38    def _get_usb_devices(self):
39        """
40        Get the USB devices attached to the client.
41
42        Parses output from lsusb and returns the set of device IDs.
43        """
44        try:
45            lines = self._host.run('lsusb').stdout.strip().split('\n')
46        except:
47            raise error.TestError('Failed to get list of USB devices.')
48        devices = set(line.split()[5] for line in lines)
49        logging.info('USB Devices: %s' % (",".join(devices)))
50        return devices
51
52    def _suspend_client(self):
53        """
54        Start the client test power_KernelSuspend to suspend the client and
55        do not wait for it to finish.
56        """
57        self._host.suspend_bg(suspend_time=_SUSPEND_TIME)
58
59    def _suspend_and_hotplug(self, insert):
60        """
61        Suspend the client and add/remove the USB key.  This assumes that a
62        USB key is plugged into the servo and is facing the DUT.
63
64        @param insert True to test insertion during suspend, False to test
65                      removal.
66        """
67        # Initialize the USB key and get the set of USB devices before
68        # suspending.
69        self._switch_usbkey_power(not insert)
70        before_suspend = self._get_usb_devices()
71
72        # Suspend the client and wait for it to go down before powering on/off
73        # the usb key.
74        self._suspend_client()
75        if not self._host.ping_wait_down(_SUSPEND_TIMEOUT):
76            raise error.TestError('Client failed to suspend.')
77        self._switch_usbkey_power(insert)
78
79        # Wait for the client to come back up (suspend time + some slack time).
80        # TODO(beeps): Combine the two timeouts in wait_up after
81        # crbug.com/221785 is resolved.
82        time.sleep(_SUSPEND_TIME)
83        if not self._host.wait_up(self._host.RESUME_TIMEOUT):
84            raise error.TestError('Client failed to resume.')
85
86        # Get the set of devices plugged in and make sure the change was
87        # detected.
88        after_suspend = self._get_usb_devices()
89        diff = after_suspend ^ before_suspend
90        if not diff:
91            raise error.TestFail('No USB changes detected after resuming.')
92
93        # Finally, make sure hotplug still works after resuming by switching
94        # the USB key's power once more.
95        self._switch_usbkey_power(not insert)
96        after_hotplug = self._get_usb_devices()
97        diff = after_hotplug ^ after_suspend
98        if not diff:
99            raise error.TestFail('No USB changes detected after hotplugging.')
100
101    def cleanup(self):
102        """
103        Reset the USB key to its initial state.
104        """
105        self._host.servo.switch_usbkey(self._init_usbkey_direction)
106        self._switch_usbkey_power(self._init_usbkey_power == 'on')
107        super(power_USBHotplugInSuspend, self).cleanup()
108
109    def run_once(self, host):
110        """
111        Tests adding and removing a USB device while the client is suspended.
112        """
113        self._host = host
114        self._init_usbkey_power = self._host.servo.get('image_usbkey_pwr')
115        self._init_usbkey_direction = self._host.servo.get_usbkey_state()
116
117        # Make sure the USB key is facing the DUT and is actually present.
118        self._host.servo.switch_usbkey('dut')
119        self._switch_usbkey_power(False)
120        before_insert = self._get_usb_devices()
121        self._switch_usbkey_power(True)
122        after_insert = self._get_usb_devices()
123        diff = after_insert - before_insert
124        logging.info('Inserted USB device(s): %s' % (",".join(diff)))
125        if not diff:
126            raise error.TestError('No new USB devices detected. Is a USB key '
127                                  'plugged into the servo?')
128
129        logging.info('Testing insertion during suspend.')
130        self._suspend_and_hotplug(True)
131        logging.info('Testing removal during suspend.')
132        self._suspend_and_hotplug(False)
133