1# Lint as: python2, python3 2# Copyright 2014 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"""This is a display lid close and open test using the Chameleon board.""" 7 8import logging, 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 16class display_LidCloseOpen(test.test): 17 """External Display Lid Close/Open test. """ 18 version = 1 19 20 # Time to check if device is suspended 21 TIMEOUT_SUSPEND_CHECK = 5 22 # Allowed timeout for the transition of suspend. 23 TIMEOUT_SUSPEND_TRANSITION = 30 24 # Allowed timeout for the transition of resume. 25 TIMEOUT_RESUME_TRANSITION = 60 26 # Time to allow for table video input 27 WAIT_TIME_STABLE_VIDEO_INPUT = 10 28 # Time to allow lid transition to take effect 29 WAIT_TIME_LID_TRANSITION = 5 30 # Time to allow display port plug transition to take effect 31 WAIT_TIME_PLUG_TRANSITION = 5 32 # Some boards do not play well with servo - crosbug.com/p/27591 33 INCOMPATIBLE_SERVO_BOARDS = ['daisy', 'falco', 'auron_paine'] 34 35 36 def close_lid(self): 37 """Close lid through servo""" 38 logging.info('CLOSING LID...') 39 self.host.servo.lid_close() 40 time.sleep(self.WAIT_TIME_LID_TRANSITION) 41 42 43 def open_lid(self): 44 """Open lid through servo""" 45 logging.info('OPENING LID...') 46 self.host.servo.lid_open() 47 time.sleep(self.WAIT_TIME_LID_TRANSITION) 48 49 50 def check_primary_display_on_internal_screen(self): 51 """Checks primary display is on onboard/internal screen""" 52 if not self.display_facade.is_display_primary(internal=True): 53 raise error.TestFail('Primary display is not on internal screen') 54 55 56 def check_primary_display_on_external_screen(self): 57 """Checks primary display is on external screen""" 58 if not self.display_facade.is_display_primary(internal=False): 59 raise error.TestFail('Primary display is not on external screen') 60 61 62 def check_mode(self): 63 """Checks the display mode is as expected""" 64 if self.display_facade.is_mirrored_enabled() is not self.test_mirrored: 65 raise error.TestFail('Display mode %s is not preserved!' % 66 ('mirrored' if self.test_mirrored 67 else 'extended')) 68 69 70 def check_docked(self): 71 """Checks DUT is docked""" 72 # Device does not suspend 73 if self.host.ping_wait_down(timeout=self.TIMEOUT_SUSPEND_TRANSITION): 74 raise error.TestFail('Device suspends when docked!') 75 # Verify Chameleon displays main screen 76 self.check_primary_display_on_external_screen() 77 logging.info('DUT IS DOCKED!') 78 return self.chameleon_port.wait_video_input_stable( 79 timeout=self.WAIT_TIME_STABLE_VIDEO_INPUT) 80 81 82 def check_still_suspended(self): 83 """Checks DUT is (still) suspended""" 84 if not self.host.ping_wait_down(timeout=self.TIMEOUT_SUSPEND_CHECK): 85 raise error.TestFail('Device does not stay suspended!') 86 logging.info('DUT STILL SUSPENDED') 87 88 89 def check_external_display(self): 90 """Display status check""" 91 # Check connector 92 if self.screen_test.check_external_display_connected( 93 self.connector_used, self.errors) is None: 94 # Check mode is same as beginning of the test 95 self.check_mode() 96 # Check test image 97 resolution = self.chameleon_port.get_resolution() 98 self.screen_test.test_screen_with_image( 99 resolution, self.test_mirrored, self.errors) 100 101 102 def run_once(self, host, plug_status, test_mirrored=False): 103 104 # Check for chromebook type devices 105 if not host.get_board_type() == 'CHROMEBOOK': 106 raise error.TestNAError('DUT is not Chromebook. Test Skipped') 107 108 # Check for incompatible with servo chromebooks 109 board_name = host.get_board().split(':')[1] 110 if board_name in self.INCOMPATIBLE_SERVO_BOARDS: 111 raise error.TestNAError( 112 'DUT is incompatible with servo. Skipping test.') 113 114 self.host = host 115 self.test_mirrored = test_mirrored 116 self.errors = list() 117 118 # Check the servo object 119 if self.host.servo is None: 120 raise error.TestError('Invalid servo object found on the host.') 121 122 factory = remote_facade_factory.RemoteFacadeFactory(host) 123 display_facade = factory.create_display_facade() 124 chameleon_board = host.chameleon 125 126 chameleon_board.setup_and_reset(self.outputdir) 127 finder = chameleon_port_finder.ChameleonVideoInputFinder( 128 chameleon_board, display_facade) 129 for chameleon_port in finder.iterate_all_ports(): 130 self.run_test_on_port(chameleon_port, display_facade, plug_status) 131 132 133 def run_test_on_port(self, chameleon_port, display_facade, plug_status): 134 """Run the test on the given Chameleon port. 135 136 @param chameleon_port: a ChameleonPorts object. 137 @param display_facade: a display facade object. 138 @param plug_status: the plugged status before_close, after_close, 139 and before_open 140 """ 141 self.chameleon_port = chameleon_port 142 self.display_facade = display_facade 143 self.screen_test = chameleon_screen_test.ChameleonScreenTest( 144 self.host, chameleon_port, display_facade, self.outputdir) 145 146 # Get connector type used (HDMI,DP,...) 147 self.connector_used = self.display_facade.get_external_connector_name() 148 # Set main display mode for the test 149 self.display_facade.set_mirrored(self.test_mirrored) 150 151 for (plugged_before_close, 152 plugged_after_close, 153 plugged_before_open) in plug_status: 154 logging.info('TEST CASE: %s > CLOSE_LID > %s > %s > OPEN_LID', 155 'PLUG' if plugged_before_close else 'UNPLUG', 156 'PLUG' if plugged_after_close else 'UNPLUG', 157 'PLUG' if plugged_before_open else 'UNPLUG') 158 159 is_suspended = False 160 boot_id = self.host.get_boot_id() 161 162 # Plug before close 163 self.chameleon_port.set_plug(plugged_before_close) 164 self.chameleon_port.wait_video_input_stable( 165 timeout=self.WAIT_TIME_STABLE_VIDEO_INPUT) 166 167 # Close lid and check 168 self.close_lid() 169 if plugged_before_close: 170 self.check_docked() 171 else: 172 self.host.test_wait_for_sleep(self.TIMEOUT_SUSPEND_TRANSITION) 173 is_suspended = True 174 175 # Plug after close and check 176 if plugged_after_close is not plugged_before_close: 177 self.chameleon_port.set_plug(plugged_after_close) 178 self.chameleon_port.wait_video_input_stable( 179 timeout=self.WAIT_TIME_STABLE_VIDEO_INPUT) 180 if not plugged_before_close: 181 self.check_still_suspended() 182 else: 183 self.host.test_wait_for_sleep( 184 self.TIMEOUT_SUSPEND_TRANSITION) 185 is_suspended = True 186 187 # Plug before open and check 188 if plugged_before_open is not plugged_after_close: 189 self.chameleon_port.set_plug(plugged_before_open) 190 self.chameleon_port.wait_video_input_stable( 191 timeout=self.WAIT_TIME_STABLE_VIDEO_INPUT) 192 if not plugged_before_close or not plugged_after_close: 193 self.check_still_suspended() 194 else: 195 self.host.test_wait_for_sleep( 196 self.TIMEOUT_SUSPEND_TRANSITION) 197 is_suspended = True 198 199 # Open lid and check 200 self.open_lid() 201 if is_suspended: 202 self.host.test_wait_for_resume(boot_id, 203 self.TIMEOUT_RESUME_TRANSITION) 204 is_suspended = False 205 206 # Check internal screen switch to primary display 207 self.check_primary_display_on_internal_screen() 208 209 # Plug monitor if not plugged, such that we can test the screen. 210 if not plugged_before_open: 211 self.chameleon_port.set_plug(True) 212 self.chameleon_port.wait_video_input_stable( 213 timeout=self.WAIT_TIME_STABLE_VIDEO_INPUT) 214 215 # Check status 216 self.check_external_display() 217 218 if self.errors: 219 raise error.TestFail('; '.join(set(self.errors))) 220 221 def cleanup(self): 222 """Test cleanup""" 223 # Keep device in lid open sate. 224 self.open_lid() 225