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