Refactored TestExpectations out of Telemetry and into content/test/gpu.
[chromium-blink-merge.git] / content / test / gpu / gpu_tests / context_lost.py
blob39ca422f2df20b3b0952c65b68df89103d463d53
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.
4 import os
5 import time
7 import context_lost_expectations
8 import gpu_test_base
10 from telemetry.core import exceptions
11 from telemetry.core import util
12 from telemetry.page import page_test
13 from telemetry.story import story_set as story_set_module
15 data_path = os.path.join(
16 util.GetChromiumSrcDir(), 'content', 'test', 'data', 'gpu')
18 wait_timeout = 60 # seconds
20 harness_script = r"""
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;
36 } else {
37 domAutomationController._succeeded = false;
38 domAutomationController._finished = true;
42 domAutomationController.reset = function() {
43 domAutomationController._succeeded = false;
44 domAutomationController._finished = false;
47 window.domAutomationController = domAutomationController;
48 console.log("Harness injected.");
49 """
51 class _ContextLostValidator(gpu_test_base.ValidatorBase):
52 def __init__(self):
53 # Strictly speaking this test doesn't yet need a browser restart
54 # after each run, but if more tests are added which crash the GPU
55 # process, then it will.
56 super(_ContextLostValidator, self).__init__(
57 needs_browser_restart_after_each_page=True)
59 def CustomizeBrowserOptions(self, options):
60 options.AppendExtraBrowserArgs(
61 '--disable-domain-blocking-for-3d-apis')
62 options.AppendExtraBrowserArgs(
63 '--disable-gpu-process-crash-limit')
64 # Required for about:gpucrash handling from Telemetry.
65 options.AppendExtraBrowserArgs('--enable-gpu-benchmarking')
67 def ValidateAndMeasurePageInner(self, page, tab, results):
68 def WaitForPageToFinish():
69 print "Waiting for page to finish."
70 try:
71 util.WaitFor(lambda: tab.EvaluateJavaScript(
72 'window.domAutomationController._finished'), wait_timeout)
73 return True
74 except exceptions.TimeoutException:
75 return False
77 if page.kill_gpu_process:
78 # Doing the GPU process kill operation cooperatively -- in the
79 # same page's context -- is much more stressful than restarting
80 # the browser every time.
81 for x in range(page.number_of_gpu_process_kills):
82 if not tab.browser.supports_tab_control:
83 raise page_test.Failure('Browser must support tab control')
85 expected_kills = x + 1
87 # Reset the test's state.
88 tab.EvaluateJavaScript(
89 'window.domAutomationController.reset()');
91 # If we're running the GPU process crash test, we need the
92 # test to have fully reset before crashing the GPU process.
93 if page.check_crash_count:
94 util.WaitFor(lambda: tab.EvaluateJavaScript(
95 'window.domAutomationController._finished'), wait_timeout)
97 # Crash the GPU process.
98 gpucrash_tab = tab.browser.tabs.New()
99 # To access these debug URLs from Telemetry, they have to be
100 # written using the chrome:// scheme.
101 # The try/except is a workaround for crbug.com/368107.
102 try:
103 gpucrash_tab.Navigate('chrome://gpucrash')
104 except Exception:
105 print 'Tab crashed while navigating to chrome://gpucrash'
106 # Activate the original tab and wait for completion.
107 tab.Activate()
108 completed = WaitForPageToFinish()
110 if page.check_crash_count:
111 if not tab.browser.supports_system_info:
112 raise page_test.Failure('Browser must support system info')
114 if not tab.EvaluateJavaScript(
115 'window.domAutomationController._succeeded'):
116 raise page_test.Failure(
117 'Test failed (didn\'t render content properly?)')
119 number_of_crashes = -1
120 # To allow time for a gpucrash to complete, wait up to 20s,
121 # polling repeatedly.
122 start_time = time.time()
123 current_time = time.time()
124 while current_time - start_time < 20:
125 system_info = tab.browser.GetSystemInfo()
126 number_of_crashes = \
127 system_info.gpu.aux_attributes[u'process_crash_count']
128 if number_of_crashes >= expected_kills:
129 break
130 time.sleep(1)
131 current_time = time.time()
133 # Wait 5 more seconds and re-read process_crash_count, in
134 # attempt to catch latent process crashes.
135 time.sleep(5)
136 system_info = tab.browser.GetSystemInfo()
137 number_of_crashes = \
138 system_info.gpu.aux_attributes[u'process_crash_count']
140 if number_of_crashes < expected_kills:
141 raise page_test.Failure(
142 'Timed out waiting for a gpu process crash')
143 elif number_of_crashes != expected_kills:
144 raise page_test.Failure(
145 'Expected %d gpu process crashes; got: %d' %
146 (expected_kills, number_of_crashes))
148 # The try/except is a workaround for crbug.com/368107.
149 try:
150 gpucrash_tab.Close()
151 except Exception:
152 print 'Tab crashed while closing chrome://gpucrash'
153 if not completed:
154 raise page_test.Failure(
155 'Test didn\'t complete (no context lost event?)')
156 if not tab.EvaluateJavaScript(
157 'window.domAutomationController._succeeded'):
158 raise page_test.Failure(
159 'Test failed (context not restored properly?)')
160 elif page.force_garbage_collection:
161 # Try to corce GC to clean up any contexts not attached to the page.
162 # This method seem unreliable, so the page will also attempt to force
163 # GC through excessive allocations.
164 tab.CollectGarbage()
165 completed = WaitForPageToFinish()
167 if not completed:
168 raise page_test.Failure(
169 'Test didn\'t complete (no context restored event?)')
170 if not tab.EvaluateJavaScript(
171 'window.domAutomationController._succeeded'):
172 raise page_test.Failure(
173 'Test failed (context not restored properly?)')
174 elif page.hide_tab_and_lose_context:
175 if not tab.browser.supports_tab_control:
176 raise page_test.Failure('Browser must support tab control')
178 # Test losing a context in a hidden tab. This test passes if the tab
179 # doesn't crash.
180 dummy_tab = tab.browser.tabs.New()
181 tab.EvaluateJavaScript('loseContextUsingExtension()')
182 tab.Activate()
184 completed = WaitForPageToFinish()
186 if not completed:
187 raise page_test.Failure('Test didn\'t complete')
188 if not tab.EvaluateJavaScript(
189 'window.domAutomationController._succeeded'):
190 raise page_test.Failure('Test failed')
191 else:
192 completed = WaitForPageToFinish()
194 if not completed:
195 raise page_test.Failure('Test didn\'t complete')
196 if not tab.EvaluateJavaScript(
197 'window.domAutomationController._succeeded'):
198 raise page_test.Failure('Test failed')
200 # Test that navigating to chrome://gpucrash causes the GPU process to crash
201 # exactly one time per navigation.
202 class GPUProcessCrashesExactlyOnce(gpu_test_base.PageBase):
203 def __init__(self, story_set, base_dir, expectations):
204 super(GPUProcessCrashesExactlyOnce, self).__init__(
205 url='file://gpu_process_crash.html',
206 page_set=story_set,
207 base_dir=base_dir,
208 name='GpuCrash.GPUProcessCrashesExactlyOnce',
209 expectations=expectations)
210 self.script_to_evaluate_on_commit = harness_script
211 self.kill_gpu_process = True
212 self.number_of_gpu_process_kills = 2
213 self.check_crash_count = True
214 self.force_garbage_collection = False
215 self.hide_tab_and_lose_context = False
217 def RunNavigateStepsInner(self, action_runner):
218 action_runner.WaitForJavaScriptCondition(
219 'window.domAutomationController._loaded')
221 class WebGLContextLostFromGPUProcessExitPage(gpu_test_base.PageBase):
222 def __init__(self, story_set, base_dir, expectations):
223 super(WebGLContextLostFromGPUProcessExitPage, self).__init__(
224 url='file://webgl.html?query=kill_after_notification',
225 page_set=story_set,
226 base_dir=base_dir,
227 name='ContextLost.WebGLContextLostFromGPUProcessExit',
228 expectations=expectations)
229 self.script_to_evaluate_on_commit = harness_script
230 self.kill_gpu_process = True
231 self.check_crash_count = False
232 self.number_of_gpu_process_kills = 1
233 self.force_garbage_collection = False
234 self.hide_tab_and_lose_context = False
236 def RunNavigateStepsInner(self, action_runner):
237 action_runner.WaitForJavaScriptCondition(
238 'window.domAutomationController._loaded')
241 class WebGLContextLostFromLoseContextExtensionPage(gpu_test_base.PageBase):
242 def __init__(self, story_set, base_dir, expectations):
243 super(WebGLContextLostFromLoseContextExtensionPage, self).__init__(
244 url='file://webgl.html?query=WEBGL_lose_context',
245 page_set=story_set,
246 base_dir=base_dir,
247 name='ContextLost.WebGLContextLostFromLoseContextExtension',
248 expectations=expectations)
249 self.script_to_evaluate_on_commit = harness_script
250 self.kill_gpu_process = False
251 self.check_crash_count = False
252 self.force_garbage_collection = False
253 self.hide_tab_and_lose_context = False
255 def RunNavigateStepsInner(self, action_runner):
256 action_runner.WaitForJavaScriptCondition(
257 'window.domAutomationController._finished')
260 class WebGLContextLostInHiddenTabPage(gpu_test_base.PageBase):
261 def __init__(self, story_set, base_dir, expectations):
262 super(WebGLContextLostInHiddenTabPage, self).__init__(
263 url='file://webgl.html?query=kill_after_notification',
264 page_set=story_set,
265 base_dir=base_dir,
266 name='ContextLost.WebGLContextLostInHiddenTab',
267 expectations=expectations)
268 self.script_to_evaluate_on_commit = harness_script
269 self.kill_gpu_process = False
270 self.check_crash_count = False
271 self.force_garbage_collection = False
272 self.hide_tab_and_lose_context = True
274 def RunNavigateStepsInner(self, action_runner):
275 action_runner.WaitForJavaScriptCondition(
276 'window.domAutomationController._loaded')
279 class WebGLContextLostFromQuantityPage(gpu_test_base.PageBase):
280 def __init__(self, story_set, base_dir, expectations):
281 super(WebGLContextLostFromQuantityPage, self).__init__(
282 url='file://webgl.html?query=forced_quantity_loss',
283 page_set=story_set,
284 base_dir=base_dir,
285 name='ContextLost.WebGLContextLostFromQuantity',
286 expectations=expectations)
287 self.script_to_evaluate_on_commit = harness_script
288 self.kill_gpu_process = False
289 self.check_crash_count = False
290 self.force_garbage_collection = True
291 self.hide_tab_and_lose_context = False
293 def RunNavigateStepsInner(self, action_runner):
294 action_runner.WaitForJavaScriptCondition(
295 'window.domAutomationController._loaded')
297 class WebGLContextLostFromSelectElementPage(gpu_test_base.PageBase):
298 def __init__(self, story_set, base_dir, expectations):
299 super(WebGLContextLostFromSelectElementPage, self).__init__(
300 url='file://webgl_with_select_element.html',
301 page_set=story_set,
302 base_dir=base_dir,
303 name='ContextLost.WebGLContextLostFromSelectElement',
304 expectations=expectations)
305 self.script_to_evaluate_on_commit = harness_script
306 self.kill_gpu_process = False
307 self.check_crash_count = False
308 self.force_garbage_collection = False
309 self.hide_tab_and_lose_context = False
311 def RunNavigateStepsInner(self, action_runner):
312 action_runner.WaitForJavaScriptCondition(
313 'window.domAutomationController._loaded')
315 class ContextLost(gpu_test_base.TestBase):
316 enabled = True
317 test = _ContextLostValidator
319 @classmethod
320 def Name(cls):
321 return 'context_lost'
323 def _CreateExpectations(self):
324 return context_lost_expectations.ContextLostExpectations()
326 # For the record, this would have been another way to get the pages
327 # to repeat. pageset_repeat would be another option.
328 # options = {'page_repeat': 5}
329 def CreateStorySet(self, options):
330 ps = story_set_module.StorySet(
331 base_dir=data_path,
332 serving_dirs=set(['']))
333 ps.AddStory(GPUProcessCrashesExactlyOnce(
334 ps, ps.base_dir, self.GetExpectations()))
335 ps.AddStory(WebGLContextLostFromGPUProcessExitPage(
336 ps, ps.base_dir, self.GetExpectations()))
337 ps.AddStory(WebGLContextLostFromLoseContextExtensionPage(
338 ps, ps.base_dir, self.GetExpectations()))
339 ps.AddStory(WebGLContextLostFromQuantityPage(
340 ps, ps.base_dir, self.GetExpectations()))
341 ps.AddStory(WebGLContextLostFromSelectElementPage(
342 ps, ps.base_dir, self.GetExpectations()))
343 ps.AddStory(WebGLContextLostInHiddenTabPage(
344 ps, ps.base_dir, self.GetExpectations()))
345 return ps