1# Copyright 2014 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
5"""This is a display hot-plug and suspend test using the Chameleon board."""
6
7import logging
8import time
9
10from autotest_lib.client.common_lib import error
11from autotest_lib.client.cros.chameleon import chameleon_port_finder
12from autotest_lib.client.cros.chameleon import chameleon_screen_test
13from autotest_lib.server import test
14from autotest_lib.server.cros.multimedia import remote_facade_factory
15
16
17class display_HotPlugAtSuspend(test.test):
18    """Display hot-plug and suspend test.
19
20    This test talks to a Chameleon board and a DUT to set up, run, and verify
21    DUT behavior response to different configuration of hot-plug during
22    suspend/resume.
23    """
24    version = 1
25    # Duration of suspend, in second.
26    SUSPEND_DURATION = 30
27    # Allowed timeout for the transition of suspend.
28    SUSPEND_TIMEOUT = 20
29    # Allowed timeout for the transition of resume.
30    RESUME_TIMEOUT = 60
31    # Time margin to do plug/unplug before resume.
32    TIME_MARGIN_BEFORE_RESUME = 5
33
34
35    def run_once(self, host, plug_status, test_mirrored=False):
36        factory = remote_facade_factory.RemoteFacadeFactory(host)
37        display_facade = factory.create_display_facade()
38        chameleon_board = host.chameleon
39
40        chameleon_board.reset()
41        finder = chameleon_port_finder.ChameleonVideoInputFinder(
42                chameleon_board, display_facade)
43
44        errors = []
45        for chameleon_port in finder.iterate_all_ports():
46            screen_test = chameleon_screen_test.ChameleonScreenTest(
47                    chameleon_port, display_facade, self.outputdir)
48
49            logging.info('See the display on Chameleon: port %d (%s)',
50                         chameleon_port.get_connector_id(),
51                         chameleon_port.get_connector_type())
52
53            logging.info('Set mirrored: %s', test_mirrored)
54            display_facade.set_mirrored(test_mirrored)
55
56            # Keep the original connector name, for later comparison.
57            expected_connector = display_facade.get_external_connector_name()
58            resolution = display_facade.get_external_resolution()
59            logging.info('See the display on DUT: %s %r',
60                         expected_connector, resolution)
61
62            for (plugged_before_suspend, plugged_after_suspend,
63                 plugged_before_resume) in plug_status:
64                test_case = ('TEST CASE: %s > SUSPEND > %s > %s > RESUME' %
65                    ('PLUG' if plugged_before_suspend else 'UNPLUG',
66                     'PLUG' if plugged_after_suspend else 'UNPLUG',
67                     'PLUG' if plugged_before_resume else 'UNPLUG'))
68                logging.info(test_case)
69                boot_id = host.get_boot_id()
70                chameleon_port.set_plug(plugged_before_suspend)
71
72                if screen_test.check_external_display_connected(
73                        expected_connector if plugged_before_suspend else False,
74                        errors):
75                    # Skip the following test if an unexpected display detected.
76                    continue
77
78                logging.info('GOING TO SUSPEND FOR %d SECONDS...',
79                             self.SUSPEND_DURATION)
80                time_before_suspend = time.time()
81                display_facade.suspend_resume_bg(self.SUSPEND_DURATION)
82
83                # Confirm DUT suspended.
84                logging.info('WAITING FOR SUSPEND...')
85                try:
86                    host.test_wait_for_sleep(self.SUSPEND_TIMEOUT)
87                except error.TestFail, ex:
88                    errors.append("%s - %s" % (test_case, str(ex)))
89                if plugged_after_suspend is not plugged_before_suspend:
90                    chameleon_port.set_plug(plugged_after_suspend)
91
92                current_time = time.time()
93                sleep_time = (self.SUSPEND_DURATION -
94                              (current_time - time_before_suspend) -
95                              self.TIME_MARGIN_BEFORE_RESUME)
96                if sleep_time > 0:
97                    logging.info('- Sleep for %.2f seconds...', sleep_time)
98                    time.sleep(sleep_time)
99                if plugged_before_resume is not plugged_after_suspend:
100                    chameleon_port.set_plug(plugged_before_resume)
101                time.sleep(self.TIME_MARGIN_BEFORE_RESUME)
102
103                logging.info('WAITING FOR RESUME...')
104                try:
105                    host.test_wait_for_resume(boot_id, self.RESUME_TIMEOUT)
106                except error.TestFail, ex:
107                    errors.append("%s - %s" % (test_case, str(ex)))
108
109                logging.info('Resumed back')
110
111                if screen_test.check_external_display_connected(
112                        expected_connector if plugged_before_resume else False,
113                        errors):
114                    # Skip the following test if an unexpected display detected.
115                    continue
116
117                if plugged_before_resume:
118                    if test_mirrored and (
119                            not display_facade.is_mirrored_enabled()):
120                        error_message = 'Error: not resumed to mirrored mode'
121                        errors.append("%s - %s" % (test_case, error_message))
122                        logging.error(error_message)
123                        logging.info('Set mirrored: %s', True)
124                        display_facade.set_mirrored(True)
125                    else:
126                        screen_test.test_screen_with_image(
127                                resolution, test_mirrored, errors)
128
129        if errors:
130            raise error.TestFail('; '.join(set(errors)))
131