Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / content / test / gpu / gpu_tests / context_lost.py
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
6
7 import context_lost_expectations
8
9 from telemetry import benchmark as benchmark_module
10 from telemetry.core import exceptions
11 from telemetry.core import util
12 from telemetry.page import page
13 from telemetry.page import page_set
14 from telemetry.page import page_test
15
16 data_path = os.path.join(
17     util.GetChromiumSrcDir(), 'content', 'test', 'data', 'gpu')
18
19 wait_timeout = 20  # seconds
20
21 harness_script = r"""
22   var domAutomationController = {};
23
24   domAutomationController._loaded = false;
25   domAutomationController._succeeded = false;
26   domAutomationController._finished = false;
27
28   domAutomationController.setAutomationId = function(id) {}
29
30   domAutomationController.send = function(msg) {
31     msg = msg.toLowerCase()
32     if (msg == "loaded") {
33       domAutomationController._loaded = true;
34     } else if (msg == "success") {
35       domAutomationController._succeeded = true;
36       domAutomationController._finished = true;
37     } else {
38       domAutomationController._succeeded = false;
39       domAutomationController._finished = true;
40     }
41   }
42
43   domAutomationController.reset = function() {
44     domAutomationController._succeeded = false;
45     domAutomationController._finished = false;
46   }
47
48   window.domAutomationController = domAutomationController;
49   console.log("Harness injected.");
50 """
51
52 class _ContextLostValidator(page_test.PageTest):
53   def __init__(self):
54     # Strictly speaking this test doesn't yet need a browser restart
55     # after each run, but if more tests are added which crash the GPU
56     # process, then it will.
57     super(_ContextLostValidator, self).__init__(
58       needs_browser_restart_after_each_page=True)
59
60   def CustomizeBrowserOptions(self, options):
61     options.AppendExtraBrowserArgs(
62         '--disable-domain-blocking-for-3d-apis')
63     options.AppendExtraBrowserArgs(
64         '--disable-gpu-process-crash-limit')
65     # Required for about:gpucrash handling from Telemetry.
66     options.AppendExtraBrowserArgs('--enable-gpu-benchmarking')
67
68   def ValidateAndMeasurePage(self, page, tab, results):
69     def WaitForPageToFinish():
70       print "Waiting for page to finish."
71       try:
72         util.WaitFor(lambda: tab.EvaluateJavaScript(
73             'window.domAutomationController._finished'), wait_timeout)
74         return True
75       except util.TimeoutException:
76         return False
77
78     if page.kill_gpu_process:
79       # Doing the GPU process kill operation cooperatively -- in the
80       # same page's context -- is much more stressful than restarting
81       # the browser every time.
82       for x in range(page.number_of_gpu_process_kills):
83         if not tab.browser.supports_tab_control:
84           raise page_test.Failure('Browser must support tab control')
85
86         expected_kills = x + 1
87
88         # Reset the test's state.
89         tab.EvaluateJavaScript(
90           'window.domAutomationController.reset()');
91
92         # If we're running the GPU process crash test, we need the
93         # test to have fully reset before crashing the GPU process.
94         if page.check_crash_count:
95           util.WaitFor(lambda: tab.EvaluateJavaScript(
96               'window.domAutomationController._finished'), wait_timeout)
97
98         # Crash the GPU process.
99         gpucrash_tab = tab.browser.tabs.New()
100         # To access these debug URLs from Telemetry, they have to be
101         # written using the chrome:// scheme.
102         # The try/except is a workaround for crbug.com/368107.
103         try:
104           gpucrash_tab.Navigate('chrome://gpucrash')
105         except (exceptions.TabCrashException, Exception):
106           print 'Tab crashed while navigating to chrome://gpucrash'
107         # Activate the original tab and wait for completion.
108         tab.Activate()
109         completed = WaitForPageToFinish()
110
111         if page.check_crash_count:
112           if not tab.browser.supports_system_info:
113             raise page_test.Failure('Browser must support system info')
114
115           if not tab.EvaluateJavaScript(
116             'window.domAutomationController._succeeded'):
117             raise page_test.Failure(
118               'Test failed (didn\'t render content properly?)')
119
120           number_of_crashes = -1
121           # To allow time for a gpucrash to complete, wait up to 20s,
122           # polling repeatedly.
123           start_time = time.time()
124           current_time = time.time()
125           while current_time - start_time < 20:
126             system_info = tab.browser.GetSystemInfo()
127             number_of_crashes = \
128                 system_info.gpu.aux_attributes[u'process_crash_count']
129             if number_of_crashes >= expected_kills:
130               break
131             time.sleep(1)
132             current_time = time.time()
133
134           # Wait 5 more seconds and re-read process_crash_count, in
135           # attempt to catch latent process crashes.
136           time.sleep(5)
137           system_info = tab.browser.GetSystemInfo()
138           number_of_crashes = \
139               system_info.gpu.aux_attributes[u'process_crash_count']
140
141           if number_of_crashes < expected_kills:
142             raise page_test.Failure(
143                 'Timed out waiting for a gpu process crash')
144           elif number_of_crashes != expected_kills:
145             raise page_test.Failure(
146                 'Expected %d gpu process crashes; got: %d' %
147                 (expected_kills, number_of_crashes))
148
149         # The try/except is a workaround for crbug.com/368107.
150         try:
151           gpucrash_tab.Close()
152         except (exceptions.TabCrashException, Exception):
153           print 'Tab crashed while closing chrome://gpucrash'
154         if not completed:
155           raise page_test.Failure(
156               'Test didn\'t complete (no context lost event?)')
157         if not tab.EvaluateJavaScript(
158           'window.domAutomationController._succeeded'):
159           raise page_test.Failure(
160             'Test failed (context not restored properly?)')
161     elif page.force_garbage_collection:
162       # Try to corce GC to clean up any contexts not attached to the page.
163       # This method seem unreliable, so the page will also attempt to force
164       # GC through excessive allocations.
165       tab.CollectGarbage()
166       completed = WaitForPageToFinish()
167
168       if not completed:
169         raise page_test.Failure(
170             'Test didn\'t complete (no context restored event?)')
171       if not tab.EvaluateJavaScript(
172         'window.domAutomationController._succeeded'):
173         raise page_test.Failure(
174           'Test failed (context not restored properly?)')
175     elif page.hide_tab_and_lose_context:
176       if not tab.browser.supports_tab_control:
177         raise page_test.Failure('Browser must support tab control')
178
179       # Test losing a context in a hidden tab. This test passes if the tab
180       # doesn't crash.
181       dummy_tab = tab.browser.tabs.New()
182       tab.EvaluateJavaScript('loseContextUsingExtension()')
183       tab.Activate()
184
185       completed = WaitForPageToFinish()
186
187       if not completed:
188         raise page_test.Failure('Test didn\'t complete')
189       if not tab.EvaluateJavaScript(
190         'window.domAutomationController._succeeded'):
191         raise page_test.Failure('Test failed')
192     else:
193       completed = WaitForPageToFinish()
194
195       if not completed:
196         raise page_test.Failure('Test didn\'t complete')
197       if not tab.EvaluateJavaScript(
198         'window.domAutomationController._succeeded'):
199         raise page_test.Failure('Test failed')
200
201 # Test that navigating to chrome://gpucrash causes the GPU process to crash
202 # exactly one time per navigation.
203 class GPUProcessCrashesExactlyOnce(page.Page):
204   def __init__(self, page_set, base_dir):
205     super(GPUProcessCrashesExactlyOnce, self).__init__(
206       url='file://gpu_process_crash.html',
207       page_set=page_set,
208       base_dir=base_dir,
209       name='GpuCrash.GPUProcessCrashesExactlyOnce')
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
216
217   def RunNavigateSteps(self, action_runner):
218     action_runner.NavigateToPage(self)
219     action_runner.WaitForJavaScriptCondition(
220         'window.domAutomationController._loaded')
221
222 class WebGLContextLostFromGPUProcessExitPage(page.Page):
223   def __init__(self, page_set, base_dir):
224     super(WebGLContextLostFromGPUProcessExitPage, self).__init__(
225       url='file://webgl.html?query=kill_after_notification',
226       page_set=page_set,
227       base_dir=base_dir,
228       name='ContextLost.WebGLContextLostFromGPUProcessExit')
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
235
236   def RunNavigateSteps(self, action_runner):
237     action_runner.NavigateToPage(self)
238     action_runner.WaitForJavaScriptCondition(
239         'window.domAutomationController._loaded')
240
241
242 class WebGLContextLostFromLoseContextExtensionPage(page.Page):
243   def __init__(self, page_set, base_dir):
244     super(WebGLContextLostFromLoseContextExtensionPage, self).__init__(
245       url='file://webgl.html?query=WEBGL_lose_context',
246       page_set=page_set,
247       base_dir=base_dir,
248       name='ContextLost.WebGLContextLostFromLoseContextExtension')
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
254
255   def RunNavigateSteps(self, action_runner):
256     action_runner.NavigateToPage(self)
257     action_runner.WaitForJavaScriptCondition(
258         'window.domAutomationController._finished')
259
260
261 class WebGLContextLostInHiddenTabPage(page.Page):
262   def __init__(self, page_set, base_dir):
263     super(WebGLContextLostInHiddenTabPage, self).__init__(
264       url='file://webgl.html?query=kill_after_notification',
265       page_set=page_set,
266       base_dir=base_dir,
267       name='ContextLost.WebGLContextLostInHiddenTab')
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
273
274   def RunNavigateSteps(self, action_runner):
275     action_runner.NavigateToPage(self)
276     action_runner.WaitForJavaScriptCondition(
277         'window.domAutomationController._loaded')
278
279
280 class WebGLContextLostFromQuantityPage(page.Page):
281   def __init__(self, page_set, base_dir):
282     super(WebGLContextLostFromQuantityPage, self).__init__(
283       url='file://webgl.html?query=forced_quantity_loss',
284       page_set=page_set,
285       base_dir=base_dir,
286       name='ContextLost.WebGLContextLostFromQuantity')
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
292
293   def RunNavigateSteps(self, action_runner):
294     action_runner.NavigateToPage(self)
295     action_runner.WaitForJavaScriptCondition(
296         'window.domAutomationController._loaded')
297
298 class WebGLContextLostFromSelectElementPage(page.Page):
299   def __init__(self, page_set, base_dir):
300     super(WebGLContextLostFromSelectElementPage, self).__init__(
301       url='file://webgl_with_select_element.html',
302       page_set=page_set,
303       base_dir=base_dir,
304       name='ContextLost.WebGLContextLostFromSelectElement')
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
310
311   def RunNavigateSteps(self, action_runner):
312     action_runner.NavigateToPage(self)
313     action_runner.WaitForJavaScriptCondition(
314         'window.domAutomationController._loaded')
315
316 class ContextLost(benchmark_module.Benchmark):
317   enabled = True
318   test = _ContextLostValidator
319
320   def CreateExpectations(self):
321     return context_lost_expectations.ContextLostExpectations()
322
323   # For the record, this would have been another way to get the pages
324   # to repeat. pageset_repeat would be another option.
325   # options = {'page_repeat': 5}
326   def CreatePageSet(self, options):
327     ps = page_set.PageSet(
328       file_path=data_path,
329       user_agent_type='desktop',
330       serving_dirs=set(['']))
331     ps.AddPage(GPUProcessCrashesExactlyOnce(ps, ps.base_dir))
332     ps.AddPage(WebGLContextLostFromGPUProcessExitPage(ps, ps.base_dir))
333     ps.AddPage(WebGLContextLostFromLoseContextExtensionPage(ps, ps.base_dir))
334     ps.AddPage(WebGLContextLostFromQuantityPage(ps, ps.base_dir))
335     ps.AddPage(WebGLContextLostFromSelectElementPage(ps, ps.base_dir))
336     ps.AddPage(WebGLContextLostInHiddenTabPage(ps, ps.base_dir))
337     return ps