• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright (c) 2012 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 logging, threading, time
6
7from autotest_lib.server import autotest, test
8from autotest_lib.client.common_lib import error
9
10_WAIT_DELAY = 10
11_LONG_TIMEOUT = 60
12_WAKE_PRESS_IN_SEC=0.2
13
14class platform_ExternalUSBStress(test.test):
15    """Uses servo to repeatedly connect/remove USB devices."""
16    version = 1
17
18    def run_once(self, host, client_autotest, repeat, network_debug):
19        self.has_lid = True
20
21        # Check if DUT has lid.
22        if host.servo.get('lid_open') == 'not_applicable':
23            self.has_lid = False
24        else:
25            # Check if
26            host.servo.lid_open()
27            if host.servo.get('lid_open') != 'yes':
28                raise error.TestError('SERVO has a bad lid_open control')
29
30        autotest_client = autotest.Autotest(host)
31        diff_list = []
32        off_list = []
33        # The servo hubs come up as diffs in connected components. These
34        # should be ignored for this test.
35        servo_hardware_prefix = 'Standard Microsystems Corp.'
36        self.is_suspended = False
37
38        def strip_lsusb_output(lsusb_output):
39            """Finds the external USB devices plugged
40
41            @param lsusb_output: lsusb command output to parse
42
43            @returns plugged_list: List of plugged usb devices names
44
45            """
46            items = lsusb_output.split('\n')
47            named_list = []
48            unnamed_device_count = 0
49            for item in items:
50                columns = item.split(' ')
51                if len(columns) == 6 or len(' '.join(columns[6:]).strip()) == 0:
52                    logging.debug('Unnamed device located, adding generic name.')
53                    name = 'Unnamed device %d' % unnamed_device_count
54                    unnamed_device_count += 1
55                else:
56                    name = ' '.join(columns[6:]).strip()
57                if not name.startswith(servo_hardware_prefix):
58                    named_list.append(name)
59            return named_list
60
61
62        def set_hub_power(on=True):
63            """Turns on or off the USB hub (dut_hub1_rst1).
64
65            @param on: To power on the servo-usb hub or not
66
67            @returns usb devices list if not suspended, None if suspended
68            """
69            reset = 'off'
70            if not on:
71                reset = 'on'
72            host.servo.set('dut_hub1_rst1', reset)
73            time.sleep(_WAIT_DELAY)
74
75
76        def wait_to_detect(timeout=_LONG_TIMEOUT):
77            """Waits till timeout for set of peripherals in lsusb output.
78
79            @param timeout: timeout in seconds
80
81            @raise error.TestFail: if timeout is reached
82
83            """
84            start_time = int(time.time())
85            while True:
86                connected = strip_lsusb_output(host.run('lsusb').stdout.strip())
87                if diff_list.issubset(connected):
88                    break
89                elif int(time.time()) - start_time > timeout:
90                    raise error.TestFail('USB peripherals not detected: %s' %
91                                          str(diff_list.difference(connected)))
92                time.sleep(1)
93
94
95        def test_suspend(plugged_before_suspended=False,
96                         plugged_before_resume=False):
97            """Close and open lid while different USB plug status.
98
99            @param plugged_before_suspended: USB plugged before suspended
100            @param plugged_before_resume: USB plugged after suspended
101
102
103            @raise error.TestFail: if USB peripherals do not match expectations.
104
105            """
106            set_hub_power(plugged_before_suspended)
107
108            # Suspend
109            boot_id = host.get_boot_id()
110            if self.has_lid:
111                host.servo.lid_close()
112            else:
113                thread = threading.Thread(target = host.suspend)
114                thread.start()
115            host.test_wait_for_sleep(_LONG_TIMEOUT)
116            logging.debug(' --DUT suspended')
117            self.is_suspended = True
118
119            if plugged_before_resume is not plugged_before_suspended:
120                set_hub_power(plugged_before_resume)
121
122            # Resume
123            if self.has_lid:
124                host.servo.lid_open()
125            else:
126                host.servo.power_key(_WAKE_PRESS_IN_SEC)
127            host.test_wait_for_resume(boot_id, _LONG_TIMEOUT)
128            logging.debug(' --DUT resumed')
129            self.is_suspended = False
130
131            if not plugged_before_resume:
132                time.sleep(_WAIT_DELAY)
133                connected = strip_lsusb_output(host.run('lsusb').stdout.strip())
134                if connected != off_list:
135                    raise error.TestFail('Devices were not removed on wake.')
136            else:
137                wait_to_detect(_LONG_TIMEOUT)
138
139
140        def test_hotplug():
141            """Testing unplug-plug and check for expected peripherals.
142
143             @raise error.TestFail: if USB peripherals do not match expectations.
144
145            """
146            set_hub_power(False)
147            set_hub_power(True)
148            wait_to_detect(_LONG_TIMEOUT)
149
150
151        def stress_external_usb():
152            """Test procedures in one iteration."""
153
154            # Unplug/plug
155            test_hotplug()
156
157            # Suspend/resume as unplugged
158            test_suspend()
159
160            # Plug/close_lid/unplug/open_lid
161            test_suspend(plugged_before_suspended=True)
162
163            #Unplug/close_lid/plug/open_lid
164            test_suspend(plugged_before_resume=True)
165
166            # Suspend/resume as plugged
167            test_suspend(plugged_before_suspended=True,
168                         plugged_before_resume=True)
169
170
171        host.servo.switch_usbkey('dut')
172
173        # There are some mice that need the data and power connection to both
174        # be removed, otherwise they won't come back up.  This means that the
175        # external devices should only use the usb connections labeled:
176        # USB_KEY and DUT_HUB1_USB.
177        set_hub_power(False)
178        time.sleep(_WAIT_DELAY)
179        off_list = strip_lsusb_output(host.run('lsusb').stdout.strip())
180        set_hub_power(True)
181        time.sleep(_WAIT_DELAY * 2)
182        connected = strip_lsusb_output(host.run('lsusb').stdout.strip())
183        diff_list = set(connected).difference(set(off_list))
184        if len(diff_list) == 0:
185            raise error.TestError('No connected devices were detected.  Make '
186                                  'sure the devices are connected to USB_KEY '
187                                  'and DUT_HUB1_USB on the servo board.')
188        logging.debug('Connected devices list: %s', diff_list)
189
190        autotest_client.run_test(client_autotest,
191                                 exit_without_logout=True)
192        for iteration in xrange(1, repeat + 1):
193            logging.debug('---Iteration %d/%d' % (iteration, repeat))
194            stress_external_usb()
195