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