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