blob: d576894a8b2397d4275d7ae3ba17806b4b63d7c9 [file] [log] [blame]
# Copyright (c) 2012 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 json
import optparse
import os
import sys
import gpu_test_base
import path_util
import webgl_conformance_expectations
import webgl2_conformance_expectations
from telemetry.internal.browser import browser_finder
from telemetry.page import page_test
from telemetry.page import shared_page_state
from telemetry.story.story_set import StorySet
conformance_path = os.path.join(
path_util.GetChromiumSrcDir(),
'third_party', 'webgl', 'src', 'sdk', 'tests')
conformance_harness_script = r"""
var testHarness = {};
testHarness._allTestSucceeded = true;
testHarness._messages = '';
testHarness._failures = 0;
testHarness._finished = false;
testHarness._originalLog = window.console.log;
testHarness.log = function(msg) {
testHarness._messages += msg + "\n";
testHarness._originalLog.apply(window.console, [msg]);
}
testHarness.reportResults = function(url, success, msg) {
testHarness._allTestSucceeded = testHarness._allTestSucceeded && !!success;
if(!success) {
testHarness._failures++;
if(msg) {
testHarness.log(msg);
}
}
};
testHarness.notifyFinished = function(url) {
testHarness._finished = true;
};
testHarness.navigateToPage = function(src) {
var testFrame = document.getElementById("test-frame");
testFrame.src = src;
};
window.webglTestHarness = testHarness;
window.parent.webglTestHarness = testHarness;
window.console.log = testHarness.log;
window.onerror = function(message, url, line) {
testHarness.reportResults(null, false, message);
testHarness.notifyFinished(null);
};
window.quietMode = function() { return true; }
"""
def _DidWebGLTestSucceed(tab):
return tab.EvaluateJavaScript('webglTestHarness._allTestSucceeded')
def _WebGLTestMessages(tab):
return tab.EvaluateJavaScript('webglTestHarness._messages')
def _CompareVersion(version1, version2):
ver_num1 = [int(x) for x in version1.split('.')]
ver_num2 = [int(x) for x in version2.split('.')]
size = min(len(ver_num1), len(ver_num2))
return cmp(ver_num1[0:size], ver_num2[0:size])
class WebglConformanceValidator(gpu_test_base.ValidatorBase):
def __init__(self):
super(WebglConformanceValidator, self).__init__()
def ValidateAndMeasurePage(self, page, tab, results):
if not _DidWebGLTestSucceed(tab):
raise page_test.Failure(_WebGLTestMessages(tab))
def CustomizeBrowserOptions(self, options):
# --test-type=gpu is used only to suppress the "Google API Keys are missing"
# infobar, which causes flakiness in tests.
options.AppendExtraBrowserArgs([
'--disable-gesture-requirement-for-media-playback',
'--disable-domain-blocking-for-3d-apis',
'--disable-gpu-process-crash-limit',
'--test-type=gpu'
])
browser = browser_finder.FindBrowser(options.finder_options)
if (browser.target_os.startswith('android') and
browser.browser_type == 'android-webview-shell'):
# TODO(kbr): this is overly broad. We'd like to do this only on
# Nexus 9. It'll go away shortly anyway. crbug.com/499928
#
# The --ignore_egl_sync_failures is only there to work around
# some strange failure on the Nexus 9 bot, not reproducible on
# local hardware.
options.AppendExtraBrowserArgs([
'--disable-gl-extensions=GL_EXT_disjoint_timer_query',
'--ignore_egl_sync_failures'
])
class Webgl2ConformanceValidator(WebglConformanceValidator):
def __init__(self):
super(Webgl2ConformanceValidator, self).__init__()
def CustomizeBrowserOptions(self, options):
# --test-type=gpu is used only to suppress the "Google API Keys are missing"
# infobar, which causes flakiness in tests.
options.AppendExtraBrowserArgs([
'--disable-gesture-requirement-for-media-playback',
'--disable-domain-blocking-for-3d-apis',
'--disable-gpu-process-crash-limit',
'--enable-unsafe-es3-apis',
'--test-type=gpu'
])
class WebglConformancePage(gpu_test_base.PageBase):
def __init__(self, story_set, test, expectations):
super(WebglConformancePage, self).__init__(
url='file://' + test, page_set=story_set, base_dir=story_set.base_dir,
shared_page_state_class=gpu_test_base.DesktopGpuSharedPageState,
name=('WebglConformance.%s' %
test.replace('/', '_').replace('-', '_').
replace('\\', '_').rpartition('.')[0].replace('.', '_')),
expectations=expectations)
self.script_to_evaluate_on_commit = conformance_harness_script
def RunNavigateSteps(self, action_runner):
super(WebglConformancePage, self).RunNavigateSteps(action_runner)
action_runner.WaitForJavaScriptCondition(
'webglTestHarness._finished', timeout_in_seconds=180)
class WebglConformance(gpu_test_base.TestBase):
"""Conformance with Khronos WebGL Conformance Tests"""
def __init__(self):
super(WebglConformance, self).__init__(max_failures=10)
self._cached_expectations = None
self._webgl_version = 0
@classmethod
def Name(cls):
return 'webgl_conformance'
@classmethod
def AddBenchmarkCommandLineArgs(cls, group):
group.add_option('--webgl-conformance-version',
help='Version of the WebGL conformance tests to run.',
default='1.0.4')
group.add_option('--webgl2-only',
help='Whether we include webgl 1 tests if version is 2.0.0 or above.',
default='false')
def CreatePageTest(self, options):
if _CompareVersion(options.webgl_conformance_version, '2.0.0') >= 0:
return Webgl2ConformanceValidator()
return WebglConformanceValidator()
def CreateStorySet(self, options):
tests = self._ParseTests('00_test_list.txt',
options.webgl_conformance_version,
(options.webgl2_only == 'true'),
None)
self._webgl_version = [
int(x) for x in options.webgl_conformance_version.split('.')][0]
ps = StorySet(serving_dirs=[''], base_dir=conformance_path)
expectations = self.GetExpectations()
for test in tests:
ps.AddStory(WebglConformancePage(ps, test, expectations))
return ps
def _CreateExpectations(self):
assert (self._webgl_version == 1 or self._webgl_version == 2)
if self._webgl_version == 1:
return webgl_conformance_expectations.WebGLConformanceExpectations(
conformance_path)
else:
return webgl2_conformance_expectations.WebGL2ConformanceExpectations(
conformance_path)
@staticmethod
def _ParseTests(path, version, webgl2_only, folder_min_version):
test_paths = []
current_dir = os.path.dirname(path)
full_path = os.path.normpath(os.path.join(conformance_path, path))
webgl_version = int(version.split('.')[0])
if not os.path.exists(full_path):
raise Exception('The WebGL conformance test path specified ' +
'does not exist: ' + full_path)
with open(full_path, 'r') as f:
for line in f:
line = line.strip()
if not line:
continue
if line.startswith('//') or line.startswith('#'):
continue
line_tokens = line.split(' ')
test_name = line_tokens[-1]
i = 0
min_version = None
while i < len(line_tokens):
token = line_tokens[i]
if token == '--min-version':
i += 1
min_version = line_tokens[i]
i += 1
min_version_to_compare = min_version or folder_min_version
if (min_version_to_compare and
_CompareVersion(version, min_version_to_compare) < 0):
continue
if (webgl2_only and (not ('.txt' in test_name)) and
((not min_version_to_compare) or
(not min_version_to_compare.startswith('2')))):
continue
if '.txt' in test_name:
include_path = os.path.join(current_dir, test_name)
# We only check min-version >= 2.0.0 for the top level list.
test_paths += WebglConformance._ParseTests(
include_path, version, webgl2_only, min_version_to_compare)
else:
test = os.path.join(current_dir, test_name)
if webgl_version > 1:
test += '?webglVersion=' + str(webgl_version)
test_paths.append(test)
return test_paths