1 # Copyright (c) 2013 The Chromium 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.
6 from telemetry import test as test_module
7 from telemetry.core import exceptions
8 from telemetry.core import util
9 from telemetry.page import page
10 from telemetry.page import page_set
11 # pylint: disable=W0401,W0614
12 from telemetry.page import page_test
13 from telemetry.page.actions.all_page_actions import *
15 data_path = os.path.join(
16 util.GetChromiumSrcDir(), 'content', 'test', 'data', 'gpu')
18 wait_timeout = 20 # seconds
21 var domAutomationController = {};
23 domAutomationController._loaded = false;
24 domAutomationController._succeeded = false;
25 domAutomationController._finished = false;
27 domAutomationController.setAutomationId = function(id) {}
29 domAutomationController.send = function(msg) {
30 msg = msg.toLowerCase()
31 if (msg == "loaded") {
32 domAutomationController._loaded = true;
33 } else if (msg == "success") {
34 domAutomationController._succeeded = true;
35 domAutomationController._finished = true;
37 domAutomationController._succeeded = false;
38 domAutomationController._finished = true;
42 window.domAutomationController = domAutomationController;
43 console.log("Harness injected.");
46 class _ContextLostValidator(page_test.PageTest):
48 # Strictly speaking this test doesn't yet need a browser restart
49 # after each run, but if more tests are added which crash the GPU
50 # process, then it will.
51 super(_ContextLostValidator, self).__init__(
52 needs_browser_restart_after_each_page=True)
54 def CustomizeBrowserOptions(self, options):
55 options.AppendExtraBrowserArgs(
56 '--disable-domain-blocking-for-3d-apis')
57 options.AppendExtraBrowserArgs(
58 '--disable-gpu-process-crash-limit')
59 # Required for about:gpucrash handling from Telemetry.
60 options.AppendExtraBrowserArgs('--enable-gpu-benchmarking')
62 def ValidatePage(self, page, tab, results):
63 if page.kill_gpu_process:
64 # Doing the GPU process kill operation cooperatively -- in the
65 # same page's context -- is much more stressful than restarting
66 # the browser every time.
67 for x in range(page.number_of_gpu_process_kills):
68 if not tab.browser.supports_tab_control:
69 raise page_test.Failure('Browser must support tab control')
70 # Reset the test's state.
71 tab.EvaluateJavaScript(
72 'window.domAutomationController._succeeded = false');
73 tab.EvaluateJavaScript(
74 'window.domAutomationController._finished = false');
75 # Crash the GPU process.
76 new_tab = tab.browser.tabs.New()
77 # To access these debug URLs from Telemetry, they have to be
78 # written using the chrome:// scheme.
79 # The try/except is a workaround for crbug.com/368107.
81 new_tab.Navigate('chrome://gpucrash')
82 except (exceptions.TabCrashException, Exception):
83 print 'Tab crashed while navigating to chrome://gpucrash'
84 # Activate the original tab and wait for completion.
88 util.WaitFor(lambda: tab.EvaluateJavaScript(
89 'window.domAutomationController._finished'), wait_timeout)
91 except util.TimeoutException:
93 # The try/except is a workaround for crbug.com/368107.
96 except (exceptions.TabCrashException, Exception):
97 print 'Tab crashed while closing chrome://gpucrash'
99 raise page_test.Failure(
100 'Test didn\'t complete (no context lost event?)')
101 if not tab.EvaluateJavaScript(
102 'window.domAutomationController._succeeded'):
103 raise page_test.Failure(
104 'Test failed (context not restored properly?)')
105 elif page.force_garbage_collection:
106 # Try to corce GC to clean up any contexts not attached to the page.
107 # This method seem unreliable, so the page will also attempt to force
108 # GC through excessive allocations.
112 print "Waiting for page to finish."
113 util.WaitFor(lambda: tab.EvaluateJavaScript(
114 'window.domAutomationController._finished'), wait_timeout)
116 except util.TimeoutException:
120 raise page_test.Failure(
121 'Test didn\'t complete (no context restored event?)')
122 if not tab.EvaluateJavaScript(
123 'window.domAutomationController._succeeded'):
124 raise page_test.Failure(
125 'Test failed (context not restored properly?)')
129 print "Waiting for page to finish."
130 util.WaitFor(lambda: tab.EvaluateJavaScript(
131 'window.domAutomationController._finished'), wait_timeout)
133 except util.TimeoutException:
137 raise page_test.Failure('Test didn\'t complete')
138 if not tab.EvaluateJavaScript(
139 'window.domAutomationController._succeeded'):
140 raise page_test.Failure('Test failed')
142 class WebGLContextLostFromGPUProcessExitPage(page.Page):
143 def __init__(self, page_set, base_dir):
144 super(WebGLContextLostFromGPUProcessExitPage, self).__init__(
145 url='file://webgl.html?query=kill_after_notification',
148 name='ContextLost.WebGLContextLostFromGPUProcessExit')
149 self.script_to_evaluate_on_commit = harness_script
150 self.kill_gpu_process = True
151 self.number_of_gpu_process_kills = 1
152 self.force_garbage_collection = False
154 def RunNavigateSteps(self, action_runner):
155 action_runner.NavigateToPage(self)
156 action_runner.WaitForJavaScriptCondition(
157 'window.domAutomationController._loaded')
160 class WebGLContextLostFromLoseContextExtensionPage(page.Page):
161 def __init__(self, page_set, base_dir):
162 super(WebGLContextLostFromLoseContextExtensionPage, self).__init__(
163 url='file://webgl.html?query=WEBGL_lose_context',
166 name='ContextLost.WebGLContextLostFromLoseContextExtension')
167 self.script_to_evaluate_on_commit = harness_script
168 self.kill_gpu_process = False
169 self.force_garbage_collection = False
171 def RunNavigateSteps(self, action_runner):
172 action_runner.NavigateToPage(self)
173 action_runner.WaitForJavaScriptCondition(
174 'window.domAutomationController._finished')
176 class WebGLContextLostFromQuantityPage(page.Page):
177 def __init__(self, page_set, base_dir):
178 super(WebGLContextLostFromQuantityPage, self).__init__(
179 url='file://webgl.html?query=forced_quantity_loss',
182 name='ContextLost.WebGLContextLostFromQuantity')
183 self.script_to_evaluate_on_commit = harness_script
184 self.kill_gpu_process = False
185 self.force_garbage_collection = True
187 def RunNavigateSteps(self, action_runner):
188 action_runner.NavigateToPage(self)
189 action_runner.WaitForJavaScriptCondition(
190 'window.domAutomationController._loaded')
192 class WebGLContextLostFromSelectElementPage(page.Page):
193 def __init__(self, page_set, base_dir):
194 super(WebGLContextLostFromSelectElementPage, self).__init__(
195 url='file://webgl_with_select_element.html',
198 name='ContextLost.WebGLContextLostFromSelectElement')
199 self.script_to_evaluate_on_commit = harness_script
200 self.kill_gpu_process = False
201 self.force_garbage_collection = False
203 def RunNavigateSteps(self, action_runner):
204 action_runner.NavigateToPage(self)
205 action_runner.WaitForJavaScriptCondition(
206 'window.domAutomationController._loaded')
208 class ContextLost(test_module.Test):
210 test = _ContextLostValidator
211 # For the record, this would have been another way to get the pages
212 # to repeat. pageset_repeat would be another option.
213 # options = {'page_repeat': 5}
214 def CreatePageSet(self, options):
215 ps = page_set.PageSet(
217 user_agent_type='desktop',
218 serving_dirs=set(['']))
219 ps.AddPage(WebGLContextLostFromGPUProcessExitPage(ps, ps.base_dir))
220 ps.AddPage(WebGLContextLostFromLoseContextExtensionPage(ps, ps.base_dir))
221 ps.AddPage(WebGLContextLostFromQuantityPage(ps, ps.base_dir))
222 ps.AddPage(WebGLContextLostFromSelectElementPage(ps, ps.base_dir))