Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 # Copyright 2016 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 | |
| 5 import os | |
| 6 import time | |
| 7 | |
| 8 from gpu_tests import gpu_integration_test | |
| 9 from gpu_tests import context_lost_expectations | |
| 10 from gpu_tests import path_util | |
| 11 | |
| 12 from telemetry.core import exceptions | |
| 13 from telemetry.core import util | |
| 14 | |
| 15 data_path = os.path.join( | |
| 16 path_util.GetChromiumSrcDir(), 'content', 'test', 'data', 'gpu') | |
| 17 | |
| 18 wait_timeout = 60 # seconds | |
| 19 | |
| 20 harness_script = r""" | |
| 21 var domAutomationController = {}; | |
| 22 | |
| 23 domAutomationController._loaded = false; | |
| 24 domAutomationController._succeeded = false; | |
| 25 domAutomationController._finished = false; | |
| 26 | |
| 27 domAutomationController.setAutomationId = function(id) {} | |
| 28 | |
| 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; | |
|
eyaich1
2016/08/24 01:28:46
Do we no longer need to care about squelching earl
Ken Russell (switch to Gerrit)
2016/08/24 01:50:25
Thanks for catching that. I'm not sure how I manag
| |
| 35 domAutomationController._finished = true; | |
| 36 } else { | |
| 37 domAutomationController._succeeded = false; | |
| 38 domAutomationController._finished = true; | |
| 39 } | |
| 40 } | |
| 41 | |
| 42 domAutomationController.reset = function() { | |
| 43 domAutomationController._succeeded = false; | |
| 44 domAutomationController._finished = false; | |
| 45 } | |
| 46 | |
| 47 window.domAutomationController = domAutomationController; | |
| 48 console.log("Harness injected."); | |
| 49 """ | |
| 50 | |
| 51 class ContextLostIntegrationTest(gpu_integration_test.GpuIntegrationTest): | |
| 52 | |
| 53 @classmethod | |
| 54 def Name(cls): | |
| 55 return 'context_lost' | |
| 56 | |
| 57 @classmethod | |
| 58 def CustomizeOptions(cls): | |
| 59 options = cls._finder_options.browser_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') | |
| 66 | |
| 67 @classmethod | |
| 68 def GenerateGpuTests(cls, options): | |
| 69 tests = (('GPUProcessCrashesExactlyOnce', 'gpu_process_crash.html'), | |
| 70 ('WebGLContextLostFromGPUProcessExit', | |
| 71 'webgl.html?query=kill_after_notification'), | |
| 72 ('WebGLContextLostFromLoseContextExtension', | |
| 73 'webgl.html?query=WEBGL_lose_context'), | |
| 74 ('WebGLContextLostFromQuantity', | |
| 75 'webgl.html?query=forced_quantity_loss'), | |
| 76 ('WebGLContextLostFromSelectElement', | |
| 77 'webgl_with_select_element.html'), | |
| 78 ('WebGLContextLostInHiddenTab', | |
| 79 'webgl.html?query=kill_after_notification')) | |
| 80 for t in tests: | |
| 81 yield (t[0], t[1], ('_' + t[0])) | |
| 82 | |
| 83 def RunActualGpuTest(self, test_path, *args): | |
| 84 test_name = args[0] | |
| 85 tab = self.tab | |
| 86 if not tab.browser.supports_tab_control: | |
| 87 self.fail('Browser must support tab control') | |
| 88 getattr(self, test_name)(test_path) | |
| 89 | |
| 90 @classmethod | |
| 91 def _CreateExpectations(cls): | |
| 92 return context_lost_expectations.ContextLostExpectations() | |
| 93 | |
| 94 @classmethod | |
| 95 def setUpClass(cls): | |
| 96 super(cls, ContextLostIntegrationTest).setUpClass() | |
| 97 cls.CustomizeOptions() | |
|
eyaich1
2016/08/24 01:28:46
Why do we start the browser in the setUpClass of t
Ken Russell (switch to Gerrit)
2016/08/24 01:50:25
The superclass doesn't know the static server dir.
| |
| 98 cls.SetBrowserOptions(cls._finder_options) | |
| 99 cls.StartBrowser() | |
| 100 cls.SetStaticServerDir(data_path) | |
| 101 | |
| 102 def _WaitForPageToFinish(self, tab): | |
| 103 try: | |
| 104 util.WaitFor(lambda: tab.EvaluateJavaScript( | |
| 105 'window.domAutomationController._finished'), wait_timeout) | |
| 106 return True | |
| 107 except exceptions.TimeoutException: | |
| 108 return False | |
| 109 | |
| 110 def _KillGPUProcess(self, tab, number_of_gpu_process_kills, | |
| 111 check_crash_count): | |
| 112 # Doing the GPU process kill operation cooperatively -- in the | |
| 113 # same page's context -- is much more stressful than restarting | |
| 114 # the browser every time. | |
| 115 for x in range(number_of_gpu_process_kills): | |
| 116 expected_kills = x + 1 | |
| 117 | |
| 118 # Reset the test's state. | |
| 119 tab.EvaluateJavaScript( | |
| 120 'window.domAutomationController.reset()') | |
| 121 | |
| 122 # If we're running the GPU process crash test, we need the test | |
| 123 # to have fully reset before crashing the GPU process. | |
| 124 if check_crash_count: | |
| 125 util.WaitFor(lambda: tab.EvaluateJavaScript( | |
| 126 'window.domAutomationController._finished'), wait_timeout) | |
| 127 | |
| 128 # Crash the GPU process. | |
| 129 gpucrash_tab = tab.browser.tabs.New() | |
| 130 # To access these debug URLs from Telemetry, they have to be | |
| 131 # written using the chrome:// scheme. | |
| 132 # The try/except is a workaround for crbug.com/368107. | |
| 133 try: | |
| 134 gpucrash_tab.Navigate('chrome://gpucrash') | |
| 135 except Exception: | |
| 136 print 'Tab crashed while navigating to chrome://gpucrash' | |
| 137 # Activate the original tab and wait for completion. | |
| 138 tab.Activate() | |
| 139 completed = self._WaitForPageToFinish(tab) | |
| 140 | |
| 141 if check_crash_count: | |
| 142 self._CheckCrashCount(tab, expected_kills) | |
| 143 | |
| 144 # The try/except is a workaround for crbug.com/368107. | |
| 145 try: | |
| 146 gpucrash_tab.Close() | |
| 147 except Exception: | |
| 148 print 'Tab crashed while closing chrome://gpucrash' | |
| 149 if not completed: | |
| 150 self.fail('Test didn\'t complete (no context lost event?)') | |
| 151 if not tab.EvaluateJavaScript( | |
| 152 'window.domAutomationController._succeeded'): | |
| 153 self.fail('Test failed (context not restored properly?)') | |
| 154 | |
| 155 def _CheckCrashCount(self, tab, expected_kills): | |
| 156 if not tab.browser.supports_system_info: | |
| 157 self.fail('Browser must support system info') | |
| 158 | |
| 159 if not tab.EvaluateJavaScript( | |
| 160 'window.domAutomationController._succeeded'): | |
| 161 self.fail('Test failed (didn\'t render content properly?)') | |
| 162 | |
| 163 number_of_crashes = -1 | |
| 164 # To allow time for a gpucrash to complete, wait up to 20s, | |
| 165 # polling repeatedly. | |
| 166 start_time = time.time() | |
| 167 current_time = time.time() | |
| 168 while current_time - start_time < 20: | |
| 169 system_info = tab.browser.GetSystemInfo() | |
| 170 number_of_crashes = \ | |
| 171 system_info.gpu.aux_attributes[u'process_crash_count'] | |
| 172 if number_of_crashes >= expected_kills: | |
| 173 break | |
| 174 time.sleep(1) | |
| 175 current_time = time.time() | |
| 176 | |
| 177 # Wait 5 more seconds and re-read process_crash_count, in | |
| 178 # attempt to catch latent process crashes. | |
| 179 time.sleep(5) | |
| 180 system_info = tab.browser.GetSystemInfo() | |
| 181 number_of_crashes = \ | |
| 182 system_info.gpu.aux_attributes[u'process_crash_count'] | |
| 183 | |
| 184 if number_of_crashes < expected_kills: | |
| 185 self.fail('Timed out waiting for a gpu process crash') | |
| 186 elif number_of_crashes != expected_kills: | |
| 187 self.fail('Expected %d gpu process crashes; got: %d' % | |
| 188 (expected_kills, number_of_crashes)) | |
| 189 | |
| 190 def _WaitForTabAndCheckCompletion(self, tab): | |
| 191 completed = self._WaitForPageToFinish(tab) | |
| 192 if not completed: | |
| 193 self.fail('Test didn\'t complete (no context restored event?)') | |
| 194 if not tab.EvaluateJavaScript('window.domAutomationController._succeeded'): | |
| 195 self.fail('Test failed (context not restored properly?)') | |
| 196 | |
| 197 # The browser test runner synthesizes methods with the exact name | |
| 198 # given in GenerateGpuTests, so in order to hand-write our tests but | |
| 199 # also go through the _RunGpuTest trampoline, the test needs to be | |
| 200 # slightly differently named. | |
| 201 def _GPUProcessCrashesExactlyOnce(self, test_path): | |
|
eyaich1
2016/08/24 01:28:46
The first five lines of each of these tests is ide
Ken Russell (switch to Gerrit)
2016/08/24 01:50:25
No good reason. Thanks. Refactored.
| |
| 202 url = self.UrlOfStaticFilePath(test_path) | |
| 203 tab = self.tab | |
| 204 tab.Navigate(url, script_to_evaluate_on_commit=harness_script) | |
| 205 tab.action_runner.WaitForJavaScriptCondition( | |
| 206 'window.domAutomationController._loaded') | |
| 207 self._KillGPUProcess(tab, 2, True) | |
|
eyaich1
2016/08/24 01:28:46
The test name indicates "exactly once" and if I am
Ken Russell (switch to Gerrit)
2016/08/24 01:50:25
You're right, it's a poorly named test. Fixed.
| |
| 208 self._RestartBrowser('must restart after tests that kill the GPU process') | |
| 209 | |
| 210 def _WebGLContextLostFromGPUProcessExit(self, test_path): | |
| 211 url = self.UrlOfStaticFilePath(test_path) | |
| 212 tab = self.tab | |
| 213 tab.Navigate(url, script_to_evaluate_on_commit=harness_script) | |
| 214 tab.action_runner.WaitForJavaScriptCondition( | |
| 215 'window.domAutomationController._loaded') | |
| 216 self._KillGPUProcess(tab, 1, False) | |
| 217 self._RestartBrowser('must restart after tests that kill the GPU process') | |
| 218 | |
| 219 def _WebGLContextLostFromLoseContextExtension(self, test_path): | |
| 220 url = self.UrlOfStaticFilePath(test_path) | |
| 221 tab = self.tab | |
| 222 tab.Navigate(url, script_to_evaluate_on_commit=harness_script) | |
| 223 tab.action_runner.WaitForJavaScriptCondition( | |
| 224 'window.domAutomationController._finished') | |
|
eyaich1
2016/08/24 01:28:46
What are you testing here?
Ken Russell (switch to Gerrit)
2016/08/24 01:50:25
See src/content/test/data/gpu/webgl.html and the c
| |
| 225 | |
| 226 def _WebGLContextLostFromQuantity(self, test_path): | |
| 227 url = self.UrlOfStaticFilePath(test_path) | |
| 228 tab = self.tab | |
| 229 tab.Navigate(url, script_to_evaluate_on_commit=harness_script) | |
| 230 tab.action_runner.WaitForJavaScriptCondition( | |
| 231 'window.domAutomationController._loaded') | |
| 232 # Try to corce GC to clean up any contexts not attached to the page. | |
| 233 # This method seems unreliable, so the page will also attempt to | |
| 234 # force GC through excessive allocations. | |
| 235 tab.CollectGarbage() | |
| 236 self._WaitForTabAndCheckCompletion(tab) | |
| 237 | |
| 238 def _WebGLContextLostFromSelectElement(self, test_path): | |
| 239 url = self.UrlOfStaticFilePath(test_path) | |
| 240 tab = self.tab | |
| 241 tab.Navigate(url, script_to_evaluate_on_commit=harness_script) | |
| 242 tab.action_runner.WaitForJavaScriptCondition( | |
| 243 'window.domAutomationController._loaded') | |
| 244 self._WaitForTabAndCheckCompletion(tab) | |
| 245 | |
| 246 def _WebGLContextLostInHiddenTab(self, test_path): | |
| 247 url = self.UrlOfStaticFilePath(test_path) | |
| 248 tab = self.tab | |
| 249 tab.Navigate(url, script_to_evaluate_on_commit=harness_script) | |
| 250 tab.action_runner.WaitForJavaScriptCondition( | |
| 251 'window.domAutomationController._loaded') | |
| 252 # Test losing a context in a hidden tab. This test passes if the tab | |
| 253 # doesn't crash. | |
| 254 dummy_tab = tab.browser.tabs.New() | |
| 255 tab.EvaluateJavaScript('loseContextUsingExtension()') | |
| 256 tab.Activate() | |
| 257 self._WaitForTabAndCheckCompletion(tab) | |
| OLD | NEW |