200 lines
9.0 KiB
Python
200 lines
9.0 KiB
Python
# Copyright 2014 The Chromium OS Authors. All rights reserved.
|
|
# Use of this source code is governed by a BSD-style license that can be
|
|
# found in the LICENSE file.
|
|
|
|
import logging
|
|
import time
|
|
|
|
from autotest_lib.client.bin import utils
|
|
from autotest_lib.client.common_lib import error as error_lib
|
|
from autotest_lib.client.cros.chameleon import screen_utility_factory
|
|
|
|
|
|
class ChameleonScreenTest(object):
|
|
"""Utility to test the screen between Chameleon and CrOS.
|
|
|
|
This class contains the screen-related testing operations.
|
|
|
|
"""
|
|
# Time in seconds to wait for notation bubbles, including bubbles for
|
|
# external detection, mirror mode and fullscreen, to disappear.
|
|
_TEST_IMAGE_STABILIZE_TIME = 10
|
|
|
|
def __init__(self, host, chameleon_port, display_facade, output_dir):
|
|
"""Initializes the ScreenUtilityFactory objects."""
|
|
self._host = host
|
|
self._display_facade = display_facade
|
|
factory = screen_utility_factory.ScreenUtilityFactory(
|
|
chameleon_port, display_facade)
|
|
self._resolution_comparer = factory.create_resolution_comparer()
|
|
self._screen_comparer = factory.create_screen_comparer(output_dir)
|
|
self._mirror_comparer = factory.create_mirror_comparer(output_dir)
|
|
self._calib_comparer = factory.create_calibration_comparer(output_dir)
|
|
self._calibration_image_tab_descriptor = None
|
|
|
|
|
|
def test_resolution(self, expected_resolution):
|
|
"""Tests if the resolution of Chameleon matches with the one of CrOS.
|
|
|
|
@param expected_resolution: A tuple (width, height) for the expected
|
|
resolution.
|
|
@return: None if the check passes; otherwise, a string of error message.
|
|
"""
|
|
return self._resolution_comparer.compare(expected_resolution)
|
|
|
|
|
|
def test_screen(self, expected_resolution, test_mirrored=None,
|
|
error_list=None):
|
|
"""Tests if the screen of Chameleon matches with the one of CrOS.
|
|
|
|
@param expected_resolution: A tuple (width, height) for the expected
|
|
resolution.
|
|
@param test_mirrored: True to test mirrored mode. False not to. None
|
|
to test mirrored mode iff the current mode is
|
|
mirrored.
|
|
@param error_list: A list to append the error message to or None.
|
|
@return: None if the check passes; otherwise, a string of error message.
|
|
"""
|
|
if test_mirrored is None:
|
|
test_mirrored = self._display_facade.is_mirrored_enabled()
|
|
|
|
error = self._resolution_comparer.compare(expected_resolution)
|
|
if not error:
|
|
# Do two screen comparisons with and without hiding cursor, to
|
|
# work-around some devices still showing cursor on CrOS FB.
|
|
# TODO: Remove this work-around once crosbug/p/34524 got fixed.
|
|
error = self._screen_comparer.compare()
|
|
if error:
|
|
logging.info('Hide cursor and do screen comparison again...')
|
|
self._display_facade.hide_cursor()
|
|
error = self._screen_comparer.compare()
|
|
|
|
if error:
|
|
# On some ARM device, the internal FB has some issue and it
|
|
# won't get fixed in the near future. As this issue don't
|
|
# affect users, just the tests. So compare it with the
|
|
# calibration image directly as an workaround.
|
|
board = self._host.get_board().replace('board:', '')
|
|
if board in ['kevin']:
|
|
# TODO(waihong): In mirrored mode, using calibration image
|
|
# to compare is not feasible due to the size difference.
|
|
# Skip the error first and think a better way to compare.
|
|
if test_mirrored:
|
|
raise error_lib.TestNAError('Test this item manually! '
|
|
'Missing CrOS feature, not able to automate.')
|
|
logging.info('Compare the calibration image directly...')
|
|
error = self._calib_comparer.compare()
|
|
|
|
if not error and test_mirrored:
|
|
error = self._mirror_comparer.compare()
|
|
if error and error_list is not None:
|
|
error_list.append(error)
|
|
return error
|
|
|
|
|
|
def load_test_image(self, image_size, test_mirrored=None):
|
|
"""Loads calibration image on the CrOS with logging
|
|
|
|
@param image_size: A tuple (width, height) conforms the resolution.
|
|
@param test_mirrored: True to test mirrored mode. False not to. None
|
|
to test mirrored mode iff the current mode is
|
|
mirrored.
|
|
"""
|
|
if test_mirrored is None:
|
|
test_mirrored = self._display_facade.is_mirrored_enabled()
|
|
self._calibration_image_tab_descriptor = \
|
|
self._display_facade.load_calibration_image(image_size)
|
|
if not test_mirrored:
|
|
self._display_facade.move_to_display(
|
|
self._display_facade.get_first_external_display_id())
|
|
self._display_facade.set_fullscreen(True)
|
|
logging.info('Waiting for calibration image to stabilize...')
|
|
time.sleep(self._TEST_IMAGE_STABILIZE_TIME)
|
|
|
|
|
|
def unload_test_image(self):
|
|
"""Closes the tab in browser to unload the fullscreen test image."""
|
|
self._display_facade.close_tab(self._calibration_image_tab_descriptor)
|
|
|
|
|
|
def test_screen_with_image(self, expected_resolution, test_mirrored=None,
|
|
error_list=None, chameleon_supported=True,
|
|
retry_count=2):
|
|
"""Tests the screen with image loaded.
|
|
|
|
@param expected_resolution: A tuple (width, height) for the expected
|
|
resolution.
|
|
@param test_mirrored: True to test mirrored mode. False not to. None
|
|
to test mirrored mode iff the current mode is
|
|
mirrored.
|
|
@param error_list: A list to append the error message to or None.
|
|
@param retry_count: A count to retry the screen test.
|
|
@param chameleon_supported: Whether resolution is supported by
|
|
chameleon. The DP RX doesn't support
|
|
4K resolution. The max supported resolution
|
|
is 2560x1600. See crbug/585900.
|
|
@return: None if the check passes; otherwise, a string of error message.
|
|
"""
|
|
if test_mirrored is None:
|
|
test_mirrored = self._display_facade.is_mirrored_enabled()
|
|
|
|
if test_mirrored:
|
|
test_image_size = self._display_facade.get_internal_resolution()
|
|
else:
|
|
# DUT needs time to respond to the plug event
|
|
test_image_size = utils.wait_for_value_changed(
|
|
self._display_facade.get_external_resolution,
|
|
old_value=None)
|
|
error = None
|
|
if test_image_size != expected_resolution:
|
|
error = ('Screen size %s is not as expected %s!'
|
|
% (str(test_image_size), str(expected_resolution)))
|
|
if test_mirrored:
|
|
# For the case of mirroring, depending on hardware vs
|
|
# software mirroring, screen size can be different.
|
|
logging.info('Warning: %s', error)
|
|
error = None
|
|
else:
|
|
error_list.append(error)
|
|
|
|
# Avoid browser tab focus issue. See crbug/1035014.
|
|
self._display_facade.set_fullscreen(True)
|
|
if chameleon_supported:
|
|
error = self._resolution_comparer.compare(expected_resolution)
|
|
if not error:
|
|
while retry_count:
|
|
retry_count = retry_count - 1
|
|
try:
|
|
self.load_test_image(test_image_size)
|
|
error = self.test_screen(expected_resolution, test_mirrored)
|
|
if error is None:
|
|
return error
|
|
elif retry_count > 0:
|
|
logging.info('Retry screen comparison again...')
|
|
finally:
|
|
self.unload_test_image()
|
|
|
|
if error and error_list is not None:
|
|
error_list.append(error)
|
|
return error
|
|
|
|
|
|
def check_external_display_connected(self, expected_display,
|
|
error_list=None):
|
|
"""Checks the given external display connected.
|
|
|
|
@param expected_display: Name of the expected display or False
|
|
if no external display is expected.
|
|
@param error_list: A list to append the error message to or None.
|
|
@return: None if the check passes; otherwise, a string of error message.
|
|
"""
|
|
error = None
|
|
if not self._display_facade.wait_external_display_connected(
|
|
expected_display):
|
|
error = 'Waited for display %s but timed out' % expected_display
|
|
|
|
if error and error_list is not None:
|
|
logging.error(error)
|
|
error_list.append(error)
|
|
return error
|