def Close(self): if self._proc: def IsClosed(): if not self._proc: return True return self._proc.poll() != None # Try to politely shutdown, first. self._proc.terminate() try: util.WaitFor(IsClosed, timeout=1) self._proc = None except util.TimeoutException: pass # Kill it. if not IsClosed(): self._proc.kill() try: util.WaitFor(IsClosed, timeout=5) self._proc = None except util.TimeoutException: self._proc = None raise Exception('Could not shutdown the browser.') if self._tmpdir and os.path.exists(self._tmpdir): shutil.rmtree(self._tmpdir, ignore_errors=True) self._tmpdir = None if self._devnull: self._devnull.close() self._devnull = None
def Wait(self, timeout=1): if not self._pid: raise Exception('Closed') def IsDone(): return not self.IsAlive() util.WaitFor(IsDone, timeout) self._pid = None
def WaitForDocumentReadyStateToBeInteractiveOrBetter( self, timeout=DEFAULT_TAB_TIMEOUT): def IsReadyStateInteractiveOrBetter(): rs = self._runtime.Evaluate('document.readyState') return rs == 'complete' or rs == 'interactive' util.WaitFor(IsReadyStateInteractiveOrBetter, timeout)
def _WaitForFormToLoad(form_id, tab): def IsFormLoaded(): return tab.runtime.Evaluate('document.querySelector("#%s")!== null' % form_id) # Wait until the form is submitted and the page completes loading. util.WaitFor(lambda: IsFormLoaded(), 60) # pylint: disable=W0108
def testConsoleOutputStream(self): unittest_data_dir = os.path.join(os.path.dirname(__file__), '..', 'unittest_data') self._browser.SetHTTPServerDirectory(unittest_data_dir) stream = StringIO.StringIO() self._tab.console.MessageOutputStream = stream self._tab.page.Navigate( self._browser.http_server.UrlOf('page_that_logs_to_console.html')) self._tab.WaitForDocumentReadyStateToBeComplete() initial = self._tab.runtime.Evaluate('window.__logCount') def GotLog(): current = self._tab.runtime.Evaluate('window.__logCount') return current > initial util.WaitFor(GotLog, 5) lines = [l for l in stream.getvalue().split('\n') if len(l)] self.assertTrue(len(lines) >= 1) for l in lines: u_l = 'http://localhost:(\d+)/page_that_logs_to_console.html:9' self.assertTrue(re.match('At %s: Hello, world' % u_l, l))
def Navigate(self, url, timeout=60): """Navigates to url""" # Turn on notifications. We need them to get the Page.frameNavigated event. request = {'method': 'Page.enable'} res = self._inspector_backend.SyncRequest(request, timeout) assert len(res['result'].keys()) == 0 # Navigate the page. However, there seems to be a bug in chrome devtools # protocol where the request id for this event gets held on the browser side # pretty much indefinitely. # # So, instead of waiting for the event to actually complete, wait for the # Page.frameNavigated event. request = { 'method': 'Page.navigate', 'params': { 'url': url, } } res = self._inspector_backend.SendAndIgnoreResponse(request) self._pending_navigate_url = url def IsNavigationDone(time_left): self._inspector_backend.DispatchNotifications(time_left) return self._pending_navigate_url == None util.WaitFor(IsNavigationDone, timeout, pass_time_left_to_func=True) # Turn off notifications. request = {'method': 'Page.disable'} res = self._inspector_backend.SyncRequest(request, timeout) assert len(res['result'].keys()) == 0
def _SubmitFormAndWait(form_id, tab): js = 'document.getElementById("%s").submit();' % form_id tab.runtime.Execute(js) def IsLoginStillHappening(): return tab.runtime.Evaluate('document.querySelector("#%s")!== null' % form_id) # Wait until the form is submitted and the page completes loading. util.WaitFor(lambda: not IsLoginStillHappening(), 60)
def CloseTab(self, index, timeout=None): assert self.num_tabs > 1, 'Closing the last tab not supported.' target_tab = self._ListTabs()[index] tab_id = target_tab['webSocketDebuggerUrl'].split('/')[-1] target_num_tabs = self.num_tabs - 1 urllib2.urlopen('%s/close/%s' % (self._debugger_url, tab_id), timeout=timeout) util.WaitFor(lambda: self.num_tabs == target_num_tabs, timeout=5)
def MeasurePage(self, _, tab, results): tab.runtime.Execute('ToggleRoboHornet()') done = 'document.getElementById("results").innerHTML.indexOf("Total") != -1' def _IsDone(): return tab.runtime.Evaluate(done) util.WaitFor(_IsDone, 60) result = int(tab.runtime.Evaluate('stopTime - startTime')) results.Add('Total', 'ms', result)
def MeasurePage(self, _, tab, results): tab.runtime.Execute('UI.call({}, "perftest")') js_is_done = 'document.getElementById("perfscore0") != null' def _IsDone(): return bool(tab.runtime.Evaluate(js_is_done)) util.WaitFor(_IsDone, 600) js_get_results = 'document.getElementById("perfscore0").innerHTML' result = int(tab.runtime.Evaluate(js_get_results)) results.Add('Score', 'score (bigger is better)', result)
def MeasurePage(self, _, tab, results): if tab.browser.is_content_shell: results.Add('first_paint', 'seconds', 'unsupported') return tab.runtime.Execute(""" window.__rafFired = false; window.webkitRequestAnimationFrame(function() { window.__rafFired = true; }); """) util.WaitFor(lambda: tab.runtime.Evaluate('window.__rafFired'), 60) first_paint_secs = tab.runtime.Evaluate( 'window.chrome.loadTimes().firstPaintTime - ' + 'window.chrome.loadTimes().requestTime') results.Add('first_paint', 'seconds', round(first_paint_secs, 1))
def MeasurePage(self, _, tab, results): js_is_done = """ document.title.indexOf("Results") != -1 && document.readyState == "complete" """ def _IsDone(): return bool(tab.runtime.Evaluate(js_is_done)) util.WaitFor(_IsDone, 300) js_get_results = """ var formElement = document.getElementsByTagName("input")[0]; decodeURIComponent(formElement.value.split("?")[1]); """ result_dict = eval(tab.runtime.Evaluate(js_get_results)) total = 0 for key in result_dict: if key == 'v': continue results.Add(key, 'ms', result_dict[key], data_type='unimportant') total += _Mean(result_dict[key]) results.Add('Total', 'ms', total)
def ScrollPageFully(page, tab): scroll_js_path = os.path.join(os.path.dirname(__file__), 'scroll.js') scroll_js = open(scroll_js_path, 'r').read() # Run scroll test. tab.runtime.Execute(scroll_js) with tab.browser.platform.GetSurfaceCollector(''): start_scroll_js = """ window.__renderingStatsDeltas = null; new __ScrollTest(function(rendering_stats_deltas) { window.__renderingStatsDeltas = rendering_stats_deltas; }).start(element); """ # scrollable_element_function is a function that passes the scrollable # element on the page to a callback. For example: # function (callback) { # callback(document.getElementById('foo')); # } if hasattr(page, 'scrollable_element_function'): tab.runtime.Execute('(%s)(function(element) { %s });' % (page.scrollable_element_function, start_scroll_js)) else: tab.runtime.Execute( '(function() { var element = document.body; %s})();' % start_scroll_js) # Poll for scroll benchmark completion. util.WaitFor(lambda: tab.runtime.Evaluate( 'window.__renderingStatsDeltas'), 60) rendering_stats_deltas = tab.runtime.Evaluate( 'window.__renderingStatsDeltas') if not (rendering_stats_deltas['numFramesSentToScreen'] > 0): raise DidNotScrollException() return rendering_stats_deltas
def _WaitForBrowserToComeUp(self): def IsBrowserUp(): try: self._ListTabs() except socket.error: if not self.IsBrowserRunning(): raise browser_gone_exception.BrowserGoneException() return False except httplib.BadStatusLine: if not self.IsBrowserRunning(): raise browser_gone_exception.BrowserGoneException() return False except urllib2.URLError: if not self.IsBrowserRunning(): raise browser_gone_exception.BrowserGoneException() return False else: return True try: util.WaitFor(IsBrowserUp, timeout=30) except util.TimeoutException: raise browser_gone_exception.BrowserGoneException()
def WaitForDocumentReadyStateToBeComplete(self, timeout=DEFAULT_TAB_TIMEOUT): util.WaitFor( lambda: self._runtime.Evaluate('document.readyState') == 'complete', timeout)
def testTimeout(self): def test(): return False self.assertRaises(util.TimeoutException, lambda: util.WaitFor(test, 0.1))
def WaitForPageToLoad(expression, tab): def IsPageLoaded(): return tab.runtime.Evaluate(expression) # Wait until the form is submitted and the page completes loading. util.WaitFor(lambda: IsPageLoaded(), 60) # pylint: disable=W0108
def testNonTimeout(): def test(): return True util.WaitFor(test, 0.1)
def __init__(self, cri, device_side_args, prevent_output=True, extra_ssh_args=None, leave_ssh_alive=False, env=None, login_shell=False): # Init members first so that Close will always succeed. self._cri = cri self._proc = None self._devnull = open(os.devnull, 'w') if prevent_output: out = self._devnull else: out = sys.stderr cri.RmRF('/tmp/cros_interface_remote_device_pid') cmd_str = ' '.join(device_side_args) if env: env_str = ' '.join(['%s=%s' % (k, v) for k, v in env.items()]) cmd = env_str + ' ' + cmd_str else: cmd = cmd_str contents = """%s&\n""" % cmd contents += 'echo $! > /tmp/cros_interface_remote_device_pid\n' cri.PushContents(contents, '/tmp/cros_interface_remote_device_bootstrap.sh') cmdline = ['/bin/bash'] if login_shell: cmdline.append('-l') cmdline.append('/tmp/cros_interface_remote_device_bootstrap.sh') proc = subprocess.Popen( cri.FormSSHCommandLine(cmdline, extra_ssh_args=extra_ssh_args), stdout=out, stderr=out, stdin=self._devnull, shell=False) time.sleep(0.1) def TryGetResult(): try: self._pid = cri.GetFileContents( '/tmp/cros_interface_remote_device_pid').strip() return True except OSError: return False try: util.WaitFor(TryGetResult, 5) except util.TimeoutException: raise Exception('Something horrible has happened!') # Killing the ssh session leaves the process running. We dont # need it anymore, unless we have port-forwards. if not leave_ssh_alive: proc.kill() else: self._proc = proc self._pid = int(self._pid) if not self.IsAlive(): raise OSError('Process did not come up or did not stay alive verry long!') self._cri = cri