import os
from telemetry import test as test_module
+from telemetry.core import exceptions
from telemetry.core import util
+from telemetry.page import page
from telemetry.page import page_set
+# pylint: disable=W0401,W0614
from telemetry.page import page_test
+from telemetry.page.actions.all_page_actions import *
data_path = os.path.join(
util.GetChromiumSrcDir(), 'content', 'test', 'data', 'gpu')
# after each run, but if more tests are added which crash the GPU
# process, then it will.
super(_ContextLostValidator, self).__init__(
- 'ValidatePage', needs_browser_restart_after_each_page=True)
+ needs_browser_restart_after_each_page=True)
def CustomizeBrowserOptions(self, options):
options.AppendExtraBrowserArgs(
'--disable-domain-blocking-for-3d-apis')
+ options.AppendExtraBrowserArgs(
+ '--disable-gpu-process-crash-limit')
# Required for about:gpucrash handling from Telemetry.
options.AppendExtraBrowserArgs('--enable-gpu-benchmarking')
def ValidatePage(self, page, tab, results):
if page.kill_gpu_process:
- if not tab.browser.supports_tab_control:
- raise page_test.Failure('Browser must support tab control')
- # Crash the GPU process.
- new_tab = tab.browser.tabs.New()
- # To access these debug URLs from Telemetry, they have to be
- # written using the chrome:// scheme.
- new_tab.Navigate('chrome://gpucrash')
- # Activate the original tab and wait for completion.
- tab.Activate()
+ # Doing the GPU process kill operation cooperatively -- in the
+ # same page's context -- is much more stressful than restarting
+ # the browser every time.
+ for x in range(page.number_of_gpu_process_kills):
+ if not tab.browser.supports_tab_control:
+ raise page_test.Failure('Browser must support tab control')
+ # Reset the test's state.
+ tab.EvaluateJavaScript(
+ 'window.domAutomationController._succeeded = false');
+ tab.EvaluateJavaScript(
+ 'window.domAutomationController._finished = false');
+ # Crash the GPU process.
+ new_tab = tab.browser.tabs.New()
+ # To access these debug URLs from Telemetry, they have to be
+ # written using the chrome:// scheme.
+ # The try/except is a workaround for crbug.com/368107.
+ try:
+ new_tab.Navigate('chrome://gpucrash')
+ except (exceptions.TabCrashException, Exception):
+ print 'Tab crashed while navigating to chrome://gpucrash'
+ # Activate the original tab and wait for completion.
+ tab.Activate()
+ completed = False
+ try:
+ util.WaitFor(lambda: tab.EvaluateJavaScript(
+ 'window.domAutomationController._finished'), wait_timeout)
+ completed = True
+ except util.TimeoutException:
+ pass
+ # The try/except is a workaround for crbug.com/368107.
+ try:
+ new_tab.Close()
+ except (exceptions.TabCrashException, Exception):
+ print 'Tab crashed while closing chrome://gpucrash'
+ if not completed:
+ raise page_test.Failure(
+ 'Test didn\'t complete (no context lost event?)')
+ if not tab.EvaluateJavaScript(
+ 'window.domAutomationController._succeeded'):
+ raise page_test.Failure(
+ 'Test failed (context not restored properly?)')
+ elif page.force_garbage_collection:
+ # Try to corce GC to clean up any contexts not attached to the page.
+ # This method seem unreliable, so the page will also attempt to force
+ # GC through excessive allocations.
+ tab.CollectGarbage()
completed = False
try:
+ print "Waiting for page to finish."
util.WaitFor(lambda: tab.EvaluateJavaScript(
'window.domAutomationController._finished'), wait_timeout)
completed = True
except util.TimeoutException:
pass
- new_tab.Close()
+
if not completed:
raise page_test.Failure(
- 'Test didn\'t complete (no context lost event?)')
- if not tab.EvaluateJavaScript('window.domAutomationController._succeeded'):
- raise page_test.Failure('Test failed (context not restored properly?)')
+ 'Test didn\'t complete (no context restored event?)')
+ if not tab.EvaluateJavaScript(
+ 'window.domAutomationController._succeeded'):
+ raise page_test.Failure(
+ 'Test failed (context not restored properly?)')
+
+class WebGLContextLostFromGPUProcessExitPage(page.Page):
+ def __init__(self, page_set, base_dir):
+ super(WebGLContextLostFromGPUProcessExitPage, self).__init__(
+ url='file://webgl.html?query=kill_after_notification',
+ page_set=page_set,
+ base_dir=base_dir,
+ name='ContextLost.WebGLContextLostFromGPUProcessExit')
+ self.script_to_evaluate_on_commit = harness_script
+ self.kill_gpu_process = True
+ self.number_of_gpu_process_kills = 1
+ self.force_garbage_collection = False
+
+ def RunNavigateSteps(self, action_runner):
+ action_runner.RunAction(NavigateAction())
+ action_runner.RunAction(WaitAction(
+ {'javascript': 'window.domAutomationController._loaded'}))
+
+
+class WebGLContextLostFromLoseContextExtensionPage(page.Page):
+ def __init__(self, page_set, base_dir):
+ super(WebGLContextLostFromLoseContextExtensionPage, self).__init__(
+ url='file://webgl.html?query=WEBGL_lose_context',
+ page_set=page_set,
+ base_dir=base_dir,
+ name='ContextLost.WebGLContextLostFromLoseContextExtension')
+ self.script_to_evaluate_on_commit = harness_script
+ self.kill_gpu_process = False
+ self.force_garbage_collection = False
+
+ def RunNavigateSteps(self, action_runner):
+ action_runner.RunAction(NavigateAction())
+ action_runner.RunAction(WaitAction(
+ {'javascript': 'window.domAutomationController._finished'}))
+
+class WebGLContextLostFromQuantityPage(page.Page):
+ def __init__(self, page_set, base_dir):
+ super(WebGLContextLostFromQuantityPage, self).__init__(
+ url='file://webgl.html?query=forced_quantity_loss',
+ page_set=page_set,
+ base_dir=base_dir,
+ name='ContextLost.WebGLContextLostFromQuantity')
+ self.script_to_evaluate_on_commit = harness_script
+ self.kill_gpu_process = False
+ self.force_garbage_collection = True
+
+ def RunNavigateSteps(self, action_runner):
+ action_runner.RunAction(NavigateAction())
+ action_runner.RunAction(WaitAction(
+ {'javascript': 'window.domAutomationController._loaded'}))
class ContextLost(test_module.Test):
enabled = True
test = _ContextLostValidator
-
+ # For the record, this would have been another way to get the pages
+ # to repeat. pageset_repeat would be another option.
+ # options = {'page_repeat': 5}
def CreatePageSet(self, options):
- page_set_dict = {
- 'description': 'Test cases for real and synthetic context lost events',
- 'user_agent_type': 'desktop',
- 'serving_dirs': [''],
- 'pages': [
- {
- 'name': 'ContextLost.WebGLContextLostFromGPUProcessExit',
- 'url': 'file://webgl.html?query=kill_after_notification',
- 'script_to_evaluate_on_commit': harness_script,
- 'navigate_steps': [
- { 'action': 'navigate' },
- { 'action': 'wait',
- 'javascript': 'window.domAutomationController._loaded' }
- ],
- 'kill_gpu_process': True
- },
- {
- 'name': 'ContextLost.WebGLContextLostFromLoseContextExtension',
- 'url': 'file://webgl.html?query=WEBGL_lose_context',
- 'script_to_evaluate_on_commit': harness_script,
- 'navigate_steps': [
- { 'action': 'navigate' },
- { 'action': 'wait',
- 'javascript': 'window.domAutomationController._finished' }
- ],
- 'kill_gpu_process': False
- },
- ]
- }
- return page_set.PageSet.FromDict(page_set_dict, data_path)
+ ps = page_set.PageSet(
+ file_path=data_path,
+ description='Test cases for real and synthetic context lost events',
+ user_agent_type='desktop',
+ serving_dirs=set(['']))
+ ps.AddPage(WebGLContextLostFromGPUProcessExitPage(ps, ps.base_dir))
+ ps.AddPage(WebGLContextLostFromLoseContextExtensionPage(ps, ps.base_dir))
+ ps.AddPage(WebGLContextLostFromQuantityPage(ps, ps.base_dir))
+ return ps
+
+