blob: d088ee6ddcec5ada7a888a6275562fb43543f071 [file] [log] [blame]
# Copyright 2017 The Chromium 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 math
import os
import random
import sys
from gpu_tests import color_profile_manager
from gpu_tests import gpu_integration_test
from gpu_tests import path_util
from gpu_tests import screenshot_sync_expectations
from telemetry.util import image_util
from telemetry.util import rgba_color
data_path = os.path.join(
path_util.GetChromiumSrcDir(), 'content', 'test', 'data', 'gpu')
class ScreenshotSyncIntegrationTest(gpu_integration_test.GpuIntegrationTest):
"""Tests that screenshots are properly synchronized with the frame on
which they were requested.
"""
@classmethod
def Name(cls):
"""The name by which this test is invoked on the command line."""
return 'screenshot_sync'
# The command line options (which are passed to subclasses'
# GenerateGpuTests) *must* be configured here, via a call to
# SetParsedCommandLineOptions. If they are not, an error will be
# raised when running the tests.
_parsed_command_line_options = None
@classmethod
def SetParsedCommandLineOptions(cls, options):
cls._parsed_command_line_options = options
@classmethod
def GetParsedCommandLineOptions(cls):
return cls._parsed_command_line_options
@classmethod
def AddCommandlineArgs(cls, parser):
super(ScreenshotSyncIntegrationTest, cls).AddCommandlineArgs(parser)
parser.add_option(
'--dont-restore-color-profile-after-test',
dest='dont_restore_color_profile_after_test',
action='store_true', default=False,
help='(Mainly on Mac) don\'t restore the system\'s original color '
'profile after the test completes; leave the system using the sRGB color '
'profile. See http://crbug.com/784456.')
@classmethod
def SetUpProcess(cls):
options = cls.GetParsedCommandLineOptions()
color_profile_manager.ForceUntilExitSRGB(
options.dont_restore_color_profile_after_test)
super(cls, ScreenshotSyncIntegrationTest).SetUpProcess()
cls.CustomizeBrowserArgs(cls._AddDefaultArgs([]))
cls.StartBrowser()
cls.SetStaticServerDirs([data_path])
@staticmethod
def _AddDefaultArgs(browser_args):
# --test-type=gpu is used to suppress the "Google API Keys are
# missing" infobar, which causes flakiness in tests.
return [
'--force-color-profile=srgb',
'--ensure-forced-color-profile',
'--test-type=gpu'] + browser_args
@classmethod
def _CreateExpectations(cls):
return screenshot_sync_expectations.ScreenshotSyncExpectations()
@classmethod
def GenerateGpuTests(cls, options):
cls.SetParsedCommandLineOptions(options)
yield('ScreenshotSync_SWRasterWithCanvas',
'screenshot_sync_canvas.html',
('--disable-gpu-rasterization'))
yield('ScreenshotSync_SWRasterWithDivs',
'screenshot_sync_divs.html',
('--disable-gpu-rasterization'))
yield('ScreenshotSync_GPURasterWithCanvas',
'screenshot_sync_canvas.html',
('--force-gpu-rasterization'))
yield('ScreenshotSync_GPURasterWithDivs',
'screenshot_sync_divs.html',
('--force-gpu-rasterization'))
def _Navigate(self, test_path):
url = self.UrlOfStaticFilePath(test_path)
# It's crucial to use the action_runner, rather than the tab's
# Navigate method directly. It waits for the document ready state
# to become interactive or better, avoiding critical race
# conditions.
self.tab.action_runner.Navigate(url)
def _CheckColorMatchAtLocation(self, expectedRGB, screenshot, x, y):
pixel_value = image_util.GetPixelColor(screenshot, x, y)
# Allow for off-by-one errors due to color conversion.
tolerance = 1
if not expectedRGB.IsEqual(pixel_value, tolerance):
error_message = ('Color mismatch at (%d, %d): expected (%d, %d, %d), ' +
'got (%d, %d, %d)') % (
x, y, expectedRGB.r, expectedRGB.g, expectedRGB.b,
pixel_value.r, pixel_value.g, pixel_value.b)
self.fail(error_message)
def _CheckScreenshot(self):
canvasRGB = rgba_color.RgbaColor(random.randint(0, 255),
random.randint(0, 255),
random.randint(0, 255),
255)
tab = self.tab
tab.EvaluateJavaScript(
"window.draw({{ red }}, {{ green }}, {{ blue }});",
red=canvasRGB.r, green=canvasRGB.g, blue=canvasRGB.b)
screenshot = tab.Screenshot(10)
# Avoid checking along antialiased boundary due to limited Adreno 3xx
# interpolation precision (crbug.com/847984). We inset by one CSS pixel
# adjusted by the device pixel ratio.
inset = int(math.ceil(tab.EvaluateJavaScript('window.devicePixelRatio')))
# It seems that we should be able to set start_x to 2 * inset (one to
# account for the inner div having left=1 and one to avoid sampling the
# aa edge). For reasons not fully understood this is insufficent on
# several bots (N9, 6P, mac_chromium_rel_ng).
start_x = 10
start_y = inset
outer_size = 256 - inset
skip = 10
for y in range(start_y, outer_size, skip):
for x in range(start_x, outer_size, skip):
self._CheckColorMatchAtLocation(canvasRGB, screenshot, x, y)
def RunActualGpuTest(self, test_path, *args):
browser_arg = args[0]
self.RestartBrowserIfNecessaryWithArgs(self._AddDefaultArgs([browser_arg]))
self._Navigate(test_path)
repetitions = 20
for _ in range(0, repetitions):
self._CheckScreenshot()
def load_tests(loader, tests, pattern):
del loader, tests, pattern # Unused.
return gpu_integration_test.LoadAllTestsInModule(sys.modules[__name__])