diff options
author | dtu@chromium.org <dtu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-12-10 20:18:50 +0000 |
---|---|---|
committer | dtu@chromium.org <dtu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-12-10 20:18:50 +0000 |
commit | f7c5052cf76bbb5e3dd0fe512f59a3d343187614 (patch) | |
tree | 3bb2b1bbc486e88bb6000242e9f916d32b49f6ed /tools | |
parent | 616f27774090a7891b606fe5b3b1a1d8278f82f9 (diff) | |
download | chromium_src-f7c5052cf76bbb5e3dd0fe512f59a3d343187614.zip chromium_src-f7c5052cf76bbb5e3dd0fe512f59a3d343187614.tar.gz chromium_src-f7c5052cf76bbb5e3dd0fe512f59a3d343187614.tar.bz2 |
[telemetry] Use a unified Tab object for all tab controls.
The public APIs now look like this:
browser.supports_tab_control
browser.tabs is a list-like object that can be used to access the tabs.
browser.tabs.New()
browser.tabs[i].url queries the JSON API for the URL. Previously browser.GetUrlOfTab()
browser.tabs[i].Disconnect() closes the WebSocket connection. Previously tab.Close()
browser.tabs[i].Close() disconnects and closes the tab. Previously browser.CloseTab()
browser.tabs[i]._Connect() is not public and is called automatically as needed.
BUG=155077,159852,160945,160946
Review URL: https://codereview.chromium.org/11280224
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@172126 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'tools')
-rw-r--r-- | tools/perf/perf_tools/smoothness_benchmark_unittest.py | 74 | ||||
-rwxr-xr-x | tools/telemetry/examples/rendering_microbenchmark_test.py | 60 | ||||
-rwxr-xr-x | tools/telemetry/examples/telemetry_perf_test.py | 36 | ||||
-rw-r--r-- | tools/telemetry/telemetry/android_browser_finder.py | 4 | ||||
-rw-r--r-- | tools/telemetry/telemetry/browser.py | 26 | ||||
-rw-r--r-- | tools/telemetry/telemetry/browser_backend.py | 151 | ||||
-rw-r--r-- | tools/telemetry/telemetry/browser_unittest.py | 35 | ||||
-rw-r--r-- | tools/telemetry/telemetry/cros_browser_backend.py | 4 | ||||
-rw-r--r-- | tools/telemetry/telemetry/cros_browser_finder.py | 4 | ||||
-rw-r--r-- | tools/telemetry/telemetry/desktop_browser_finder.py | 4 | ||||
-rw-r--r-- | tools/telemetry/telemetry/google_credentials_backend_unittest.py | 5 | ||||
-rw-r--r-- | tools/telemetry/telemetry/inspector_backend.py | 16 | ||||
-rw-r--r-- | tools/telemetry/telemetry/page_runner.py | 19 | ||||
-rw-r--r-- | tools/telemetry/telemetry/tab.py | 62 | ||||
-rw-r--r-- | tools/telemetry/telemetry/tab_test_case.py | 4 | ||||
-rw-r--r-- | tools/telemetry/telemetry/temporary_http_server_unittest.py | 13 |
16 files changed, 295 insertions, 222 deletions
diff --git a/tools/perf/perf_tools/smoothness_benchmark_unittest.py b/tools/perf/perf_tools/smoothness_benchmark_unittest.py index d7b4880..66eb0ef 100644 --- a/tools/perf/perf_tools/smoothness_benchmark_unittest.py +++ b/tools/perf/perf_tools/smoothness_benchmark_unittest.py @@ -82,43 +82,43 @@ class SmoothnessBenchmarkUnitTest( raise Exception('No browser found, cannot continue test.') with browser_to_create.Create() as browser: - with browser.ConnectToNthTab(0) as tab: - ps = self.CreatePageSetFromFileInUnittestDataDir('blank.html') - parsed_url = urlparse.urlparse(ps.pages[0].url) - path = os.path.join(parsed_url.netloc, parsed_url.path) - dirname, filename = os.path.split(path) - dirname = os.path.join(ps.base_dir, dirname[1:]) - browser.SetHTTPServerDirectory(dirname) - target_side_url = browser.http_server.UrlOf(filename) - tab.page.Navigate(target_side_url) - - # Verify that the rect returned by getBoundingVisibleRect() in - # scroll.js is completely contained within the viewport. Scroll - # events dispatched by the benchmarks use the center of this rect - # as their location, and this location needs to be within the - # viewport bounds to correctly decide between main-thread and - # impl-thread scrolling. If the scrollable area were not clipped - # to the viewport bounds, then the instance used here (the scrollable - # area being more than twice as tall as the viewport) would - # result in a scroll location outside of the viewport bounds. - tab.runtime.Execute("""document.body.style.height = - (2 * window.innerHeight + 1) + 'px';""") - scroll_js_path = os.path.join(os.path.dirname(__file__), '..', '..', - 'telemetry', 'telemetry', 'scroll.js') - scroll_js = open(scroll_js_path, 'r').read() - tab.runtime.Evaluate(scroll_js) - - rect_bottom = int(tab.runtime.Evaluate(""" - __ScrollTest_GetBoundingVisibleRect(document.body).top + - __ScrollTest_GetBoundingVisibleRect(document.body).height""")) - rect_right = int(tab.runtime.Evaluate(""" - __ScrollTest_GetBoundingVisibleRect(document.body).left + - __ScrollTest_GetBoundingVisibleRect(document.body).width""")) - viewport_width = int(tab.runtime.Evaluate('window.innerWidth')) - viewport_height = int(tab.runtime.Evaluate('window.innerHeight')) - - self.assertTrue(rect_bottom <= viewport_height) - self.assertTrue(rect_right <= viewport_width) + tab = browser.tabs[0] + ps = self.CreatePageSetFromFileInUnittestDataDir('blank.html') + parsed_url = urlparse.urlparse(ps.pages[0].url) + path = os.path.join(parsed_url.netloc, parsed_url.path) + dirname, filename = os.path.split(path) + dirname = os.path.join(ps.base_dir, dirname[1:]) + browser.SetHTTPServerDirectory(dirname) + target_side_url = browser.http_server.UrlOf(filename) + tab.page.Navigate(target_side_url) + + # Verify that the rect returned by getBoundingVisibleRect() in + # scroll.js is completely contained within the viewport. Scroll + # events dispatched by the benchmarks use the center of this rect + # as their location, and this location needs to be within the + # viewport bounds to correctly decide between main-thread and + # impl-thread scrolling. If the scrollable area were not clipped + # to the viewport bounds, then the instance used here (the scrollable + # area being more than twice as tall as the viewport) would + # result in a scroll location outside of the viewport bounds. + tab.runtime.Execute("""document.body.style.height = + (2 * window.innerHeight + 1) + 'px';""") + scroll_js_path = os.path.join(os.path.dirname(__file__), '..', '..', + 'telemetry', 'telemetry', 'scroll.js') + scroll_js = open(scroll_js_path, 'r').read() + tab.runtime.Evaluate(scroll_js) + + rect_bottom = int(tab.runtime.Evaluate(""" + __ScrollTest_GetBoundingVisibleRect(document.body).top + + __ScrollTest_GetBoundingVisibleRect(document.body).height""")) + rect_right = int(tab.runtime.Evaluate(""" + __ScrollTest_GetBoundingVisibleRect(document.body).left + + __ScrollTest_GetBoundingVisibleRect(document.body).width""")) + viewport_width = int(tab.runtime.Evaluate('window.innerWidth')) + viewport_height = int(tab.runtime.Evaluate('window.innerHeight')) + + self.assertTrue(rect_bottom <= viewport_height) + self.assertTrue(rect_right <= viewport_width) def testDoesImplThreadScroll(self): ps = self.CreatePageSetFromFileInUnittestDataDir('scrollable_page.html') diff --git a/tools/telemetry/examples/rendering_microbenchmark_test.py b/tools/telemetry/examples/rendering_microbenchmark_test.py index 9976c74..b096cb9 100755 --- a/tools/telemetry/examples/rendering_microbenchmark_test.py +++ b/tools/telemetry/examples/rendering_microbenchmark_test.py @@ -34,41 +34,41 @@ def Main(args): telemetry.GetAllAvailableBrowserTypes(options)) return 255 with browser_to_create.Create() as b: - with b.ConnectToNthTab(0) as tab: - # Check browser for benchmark API. Can only be done on non-chrome URLs. - tab.page.Navigate('http://www.google.com') - import time - time.sleep(2) - tab.WaitForDocumentReadyStateToBeComplete() - if tab.runtime.Evaluate('window.chrome.gpuBenchmarking === undefined'): - print 'Browser does not support gpu benchmarks API.' - return 255 + tab = b.tabs[0] + # Check browser for benchmark API. Can only be done on non-chrome URLs. + tab.page.Navigate('http://www.google.com') + import time + time.sleep(2) + tab.WaitForDocumentReadyStateToBeComplete() + if tab.runtime.Evaluate('window.chrome.gpuBenchmarking === undefined'): + print 'Browser does not support gpu benchmarks API.' + return 255 - if tab.runtime.Evaluate( - 'window.chrome.gpuBenchmarking.runRenderingBenchmarks === undefined'): - print 'Browser does not support rendering benchmarks API.' - return 255 + if tab.runtime.Evaluate( + 'window.chrome.gpuBenchmarking.runRenderingBenchmarks === undefined'): + print 'Browser does not support rendering benchmarks API.' + return 255 - # Run the test. :) - first_line = [] - def DumpResults(url, results): - if len(first_line) == 0: - cols = ['url'] - for r in results: - cols.append(r['benchmark']) - print ','.join(cols) - first_line.append(0) - cols = [url] + # Run the test. :) + first_line = [] + def DumpResults(url, results): + if len(first_line) == 0: + cols = ['url'] for r in results: - cols.append(str(r['result'])) + cols.append(r['benchmark']) print ','.join(cols) + first_line.append(0) + cols = [url] + for r in results: + cols.append(str(r['result'])) + print ','.join(cols) - for u in urls: - tab.page.Navigate(u) - tab.WaitForDocumentReadyStateToBeInteractiveOrBetter() - results = tab.runtime.Evaluate( - 'window.chrome.gpuBenchmarking.runRenderingBenchmarks();') - DumpResults(url, results) + for u in urls: + tab.page.Navigate(u) + tab.WaitForDocumentReadyStateToBeInteractiveOrBetter() + results = tab.runtime.Evaluate( + 'window.chrome.gpuBenchmarking.runRenderingBenchmarks();') + DumpResults(url, results) return 0 diff --git a/tools/telemetry/examples/telemetry_perf_test.py b/tools/telemetry/examples/telemetry_perf_test.py index de9aceb..acfdc00 100755 --- a/tools/telemetry/examples/telemetry_perf_test.py +++ b/tools/telemetry/examples/telemetry_perf_test.py @@ -18,24 +18,24 @@ def Main(args): browser_to_create = telemetry.FindBrowser(options) assert browser_to_create with browser_to_create.Create() as b: - with b.ConnectToNthTab(0) as tab: - - # Measure round-trip-time for evaluate - times = [] - for i in range(1000): - start = time.time() - tab.runtime.Evaluate('%i * 2' % i) - times.append(time.time() - start) - N = float(len(times)) - avg = sum(times, 0.0) / N - squared_diffs = [(t - avg) * (t - avg) for t in times] - stdev = sum(squared_diffs, 0.0) / (N - 1) - times.sort() - percentile_75 = times[int(0.75 * N)] - - print "%s: avg=%f; stdev=%f; min=%f; 75th percentile = %f" % ( - "Round trip time (seconds)", - avg, stdev, min(times), percentile_75) + tab = b.tabs[0] + + # Measure round-trip-time for evaluate + times = [] + for i in range(1000): + start = time.time() + tab.runtime.Evaluate('%i * 2' % i) + times.append(time.time() - start) + N = float(len(times)) + avg = sum(times, 0.0) / N + squared_diffs = [(t - avg) * (t - avg) for t in times] + stdev = sum(squared_diffs, 0.0) / (N - 1) + times.sort() + percentile_75 = times[int(0.75 * N)] + + print "%s: avg=%f; stdev=%f; min=%f; 75th percentile = %f" % ( + "Round trip time (seconds)", + avg, stdev, min(times), percentile_75) return 0 diff --git a/tools/telemetry/telemetry/android_browser_finder.py b/tools/telemetry/telemetry/android_browser_finder.py index 2661435..01e28e0 100644 --- a/tools/telemetry/telemetry/android_browser_finder.py +++ b/tools/telemetry/telemetry/android_browser_finder.py @@ -56,7 +56,9 @@ class PossibleAndroidBrowser(possible_browser.PossibleBrowser): platform = android_platform.AndroidPlatform( self._args[0].Adb(), self._args[1], self._args[1] + self._args[4]) - return browser.Browser(backend, platform) + b = browser.Browser(backend, platform) + backend.SetBrowser(b) + return b def FindAllAvailableBrowsers(options, logging=real_logging): """Finds all the desktop browsers available on this machine.""" diff --git a/tools/telemetry/telemetry/browser.py b/tools/telemetry/telemetry/browser.py index d33c847..dced3c0 100644 --- a/tools/telemetry/telemetry/browser.py +++ b/tools/telemetry/telemetry/browser.py @@ -8,6 +8,7 @@ from telemetry import browser_credentials from telemetry import wpr_modes from telemetry import wpr_server + class Browser(object): """A running browser instance that can be controlled in a limited way. @@ -33,6 +34,10 @@ class Browser(object): self.Close() @property + def platform(self): + return self._platform + + @property def browser_type(self): return self._backend.browser_type @@ -42,26 +47,15 @@ class Browser(object): return self._backend.is_content_shell @property - def num_tabs(self): - return self._backend.num_tabs + def supports_tab_control(self): + return self._backend.supports_tab_control @property - def platform(self): - return self._platform - - def NewTab(self): - return self._backend.NewTab() - - def CloseTab(self, index): - self._backend.CloseTab(index) - - def GetNthTabUrl(self, index): - return self._backend.GetNthTabUrl(index) - - def ConnectToNthTab(self, index): - return self._backend.ConnectToNthTab(self, index) + def tabs(self): + return self._backend.tabs def Close(self): + """Closes this browser.""" if self._wpr_server: self._wpr_server.Close() self._wpr_server = None diff --git a/tools/telemetry/telemetry/browser_backend.py b/tools/telemetry/telemetry/browser_backend.py index 5ec3205..c7eb304 100644 --- a/tools/telemetry/telemetry/browser_backend.py +++ b/tools/telemetry/telemetry/browser_backend.py @@ -6,9 +6,9 @@ import httplib import socket import json import re +import weakref from telemetry import browser_gone_exception -from telemetry import inspector_backend from telemetry import tab from telemetry import user_agent from telemetry import util @@ -21,10 +21,97 @@ class BrowserConnectionGoneException( pass +class TabController(object): + def __init__(self, browser, browser_backend): + self._browser = browser + self._browser_backend = browser_backend + + # Stores web socket debugger URLs in iteration order. + self._tab_list = [] + # Maps debugger URLs to Tab objects. + self._tab_dict = weakref.WeakValueDictionary() + + self._UpdateTabList() + + def New(self, timeout=None): + self._browser_backend.Request('new', timeout=timeout) + return self[-1] + + def DoesDebuggerUrlExist(self, url): + self._UpdateTabList() + return url in self._tab_list + + def CloseTab(self, debugger_url, timeout=None): + # TODO(dtu): crbug.com/160946, allow closing the last tab on some platforms. + # For now, just create a new tab before closing the last tab. + if len(self) <= 1: + self.New() + + tab_id = debugger_url.split('/')[-1] + try: + response = self._browser_backend.Request('close/%s' % tab_id, + timeout=timeout) + except urllib2.HTTPError: + raise Exception('Unable to close tab, tab id not found: %s' % tab_id) + assert response == 'Target is closing' + + util.WaitFor(lambda: not self._FindTabInfo(debugger_url), timeout=5) + self._UpdateTabList() + + def GetTabUrl(self, debugger_url): + tab_info = self._FindTabInfo(debugger_url) + assert tab_info is not None + return tab_info['url'] + + def __iter__(self): + self._UpdateTabList() + return self._tab_list.__iter__() + + def __len__(self): + self._UpdateTabList() + return len(self._tab_list) + + def __getitem__(self, index): + self._UpdateTabList() + # This dereference will propagate IndexErrors. + debugger_url = self._tab_list[index] + # Lazily get/create a Tab object. + tab_object = self._tab_dict.get(debugger_url) + if not tab_object: + tab_object = tab.Tab(self._browser, self, debugger_url) + self._tab_dict[debugger_url] = tab_object + return tab_object + + def _ListTabs(self, timeout=None): + try: + data = self._browser_backend.Request('', timeout=timeout) + all_contexts = json.loads(data) + tabs = [ctx for ctx in all_contexts + if not ctx['url'].startswith('chrome-extension://')] + return tabs + except (socket.error, httplib.BadStatusLine, urllib2.URLError): + if not self.IsBrowserRunning(): + raise browser_gone_exception.BrowserGoneException() + raise BrowserConnectionGoneException() + + def _UpdateTabList(self): + new_tab_list = map(lambda tab_info: tab_info['webSocketDebuggerUrl'], + self._ListTabs()) + self._tab_list = [t for t in self._tab_list if t in new_tab_list] + self._tab_list += [t for t in new_tab_list if t not in self._tab_list] + + def _FindTabInfo(self, debugger_url): + for tab_info in self._ListTabs(): + if tab_info.get('webSocketDebuggerUrl') == debugger_url: + return tab_info + return None + + class BrowserBackend(object): """A base class for browser backends. Provides basic functionality once a remote-debugger port has been established.""" def __init__(self, is_content_shell, options): + self.tabs = None self.browser_type = options.browser_type self.is_content_shell = is_content_shell self.options = options @@ -34,6 +121,9 @@ class BrowserBackend(object): self._chrome_branch_number = 0 self._webkit_base_revision = 0 + def SetBrowser(self, browser): + self.tabs = TabController(browser, self) + def GetBrowserStartupArgs(self): args = [] args.extend(self.options.extra_browser_args) @@ -50,11 +140,11 @@ class BrowserBackend(object): def wpr_mode(self): return self.options.wpr_mode - def _WaitForBrowserToComeUp(self): + def _WaitForBrowserToComeUp(self, timeout=None): def IsBrowserUp(): try: - self._ListTabs() - except BrowserConnectionGoneException: + self.Request('', timeout=timeout) + except (socket.error, httplib.BadStatusLine, urllib2.URLError): return False else: return True @@ -65,7 +155,7 @@ class BrowserBackend(object): def _PostBrowserStartupInitialization(self): # Detect version information. - data = self._Request('version') + data = self.Request('version') resp = json.loads(data) if 'Protocol-Version' in resp: self._inspector_protocol_version = resp['Protocol-Version'] @@ -82,59 +172,14 @@ class BrowserBackend(object): self._chrome_branch_number = 1025 self._webkit_base_revision = 106313 - def _Request(self, path, timeout=None): + def Request(self, path, timeout=None): url = 'http://localhost:%i/json/%s' % (self._port, path) req = urllib2.urlopen(url, timeout=timeout) return req.read() - def _ListTabs(self, timeout=None): - try: - data = self._Request('', timeout=timeout) - all_contexts = json.loads(data) - tabs = [ctx for ctx in all_contexts - if not ctx['url'].startswith('chrome-extension://')] - # FIXME(dtu): The remote debugger protocol returns in order of most - # recently created tab first. In order to convert it to the UI tab - # order, we just reverse the list, which assumes we can't move tabs. - # We should guarantee that the remote debugger returns in UI tab order. - tabs.reverse() - return tabs - except (socket.error, httplib.BadStatusLine, urllib2.URLError): - if not self.IsBrowserRunning(): - raise browser_gone_exception.BrowserGoneException() - raise BrowserConnectionGoneException() - - def NewTab(self, timeout=None): - data = self._Request('new', timeout=timeout) - new_tab = json.loads(data) - return new_tab - - 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 - - self._Request('close/%s' % tab_id, timeout=timeout) - - util.WaitFor(lambda: self.num_tabs == target_num_tabs, timeout=5) - @property - def num_tabs(self): - return len(self._ListTabs()) - - def GetNthTabUrl(self, index): - return self._ListTabs()[index]['url'] - - def ConnectToNthTab(self, browser, index): - ib = inspector_backend.InspectorBackend(self, self._ListTabs()[index]) - return tab.Tab(browser, ib) - - def DoesDebuggerUrlExist(self, url): - matches = [t for t in self._ListTabs() - if 'webSocketDebuggerUrl' in t and\ - t['webSocketDebuggerUrl'] == url] - return len(matches) >= 1 + def supports_tab_control(self): + return self._chrome_branch_number >= 1303 def CreateForwarder(self, host_port): raise NotImplementedError() diff --git a/tools/telemetry/telemetry/browser_unittest.py b/tools/telemetry/telemetry/browser_unittest.py index edc0877..0bbed70 100644 --- a/tools/telemetry/telemetry/browser_unittest.py +++ b/tools/telemetry/telemetry/browser_unittest.py @@ -13,10 +13,10 @@ class BrowserTest(unittest.TestCase): if not browser_to_create: raise Exception('No browser found, cannot continue test.') with browser_to_create.Create() as b: - self.assertEquals(1, b.num_tabs) + self.assertEquals(1, len(b.tabs)) # Different browsers boot up to different things - assert b.GetNthTabUrl(0) + assert b.tabs[0].url def testCommandLineOverriding(self): # This test starts the browser with --enable-benchmarking, which should @@ -29,11 +29,10 @@ class BrowserTest(unittest.TestCase): browser_to_create = browser_finder.FindBrowser(options) with browser_to_create.Create() as b: - with b.ConnectToNthTab(0) as t: - t.page.Navigate('http://www.google.com/') - t.WaitForDocumentReadyStateToBeInteractiveOrBetter() - self.assertEquals(t.runtime.Evaluate('navigator.userAgent'), - 'telemetry') + t = b.tabs[0] + t.page.Navigate('http://www.google.com/') + t.WaitForDocumentReadyStateToBeInteractiveOrBetter() + self.assertEquals(t.runtime.Evaluate('navigator.userAgent'), 'telemetry') def testVersionDetection(self): options = options_for_unittests.GetCopy() @@ -48,13 +47,15 @@ class BrowserTest(unittest.TestCase): options = options_for_unittests.GetCopy() browser_to_create = browser_finder.FindBrowser(options) with browser_to_create.Create() as b: - self.assertEquals(1, b.num_tabs) - existing_tab_url = b.GetNthTabUrl(0) - b.NewTab() - self.assertEquals(2, b.num_tabs) - self.assertEquals(b.GetNthTabUrl(0), existing_tab_url) - self.assertEquals(b.GetNthTabUrl(1), 'about:blank') - b.CloseTab(1) - self.assertEquals(1, b.num_tabs) - self.assertEquals(b.GetNthTabUrl(0), existing_tab_url) - self.assertRaises(AssertionError, b.CloseTab, 0) + existing_tab = b.tabs[0] + self.assertEquals(1, len(b.tabs)) + existing_tab_url = existing_tab.url + + new_tab = b.tabs.New() + self.assertEquals(2, len(b.tabs)) + self.assertEquals(existing_tab.url, existing_tab_url) + self.assertEquals(new_tab.url, 'about:blank') + + new_tab.Close() + self.assertEquals(1, len(b.tabs)) + self.assertEquals(existing_tab.url, existing_tab_url) diff --git a/tools/telemetry/telemetry/cros_browser_backend.py b/tools/telemetry/telemetry/cros_browser_backend.py index 0e89334..3c4dd44 100644 --- a/tools/telemetry/telemetry/cros_browser_backend.py +++ b/tools/telemetry/telemetry/cros_browser_backend.py @@ -70,8 +70,8 @@ class CrOSBrowserBackend(browser_backend.BrowserBackend): raise # Make sure there's a tab open. - if self.num_tabs == 0: - self.NewTab() + if len(self.tabs) == 0: + self.tabs.New() logging.info('Browser is up!') diff --git a/tools/telemetry/telemetry/cros_browser_finder.py b/tools/telemetry/telemetry/cros_browser_finder.py index 130dac3..f9b5847 100644 --- a/tools/telemetry/telemetry/cros_browser_finder.py +++ b/tools/telemetry/telemetry/cros_browser_finder.py @@ -28,7 +28,9 @@ class PossibleCrOSBrowser(possible_browser.PossibleBrowser): def Create(self): backend = cros_browser_backend.CrOSBrowserBackend( self.browser_type, self._options, *self._args) - return browser.Browser(backend, platform.Platform()) + b = browser.Browser(backend, platform.Platform()) + backend.SetBrowser(b) + return b def FindAllAvailableBrowsers(options): """Finds all the desktop browsers available on this machine.""" diff --git a/tools/telemetry/telemetry/desktop_browser_finder.py b/tools/telemetry/telemetry/desktop_browser_finder.py index 15c630d..64cf199 100644 --- a/tools/telemetry/telemetry/desktop_browser_finder.py +++ b/tools/telemetry/telemetry/desktop_browser_finder.py @@ -36,7 +36,9 @@ class PossibleDesktopBrowser(possible_browser.PossibleBrowser): def Create(self): backend = desktop_browser_backend.DesktopBrowserBackend( self._options, self._local_executable, self._is_content_shell) - return browser.Browser(backend, platform.Platform()) + b = browser.Browser(backend, platform.Platform()) + backend.SetBrowser(b) + return b def FindAllAvailableBrowsers(options): """Finds all the desktop browsers available on this machine.""" diff --git a/tools/telemetry/telemetry/google_credentials_backend_unittest.py b/tools/telemetry/telemetry/google_credentials_backend_unittest.py index b54944d..f2b175b 100644 --- a/tools/telemetry/telemetry/google_credentials_backend_unittest.py +++ b/tools/telemetry/telemetry/google_credentials_backend_unittest.py @@ -30,9 +30,8 @@ class TestGoogleCredentialsBackend(unittest.TestCase): b.credentials.credentials_path = credentials_path if not b.credentials.CanLogin('google'): return - with b.ConnectToNthTab(0) as tab: - ret = b.credentials.LoginNeeded(tab, 'google') - self.assertTrue(ret) + ret = b.credentials.LoginNeeded(b.tabs[0], 'google') + self.assertTrue(ret) def testLoginUsingMock(self): # pylint: disable=R0201 tab = MockTab() diff --git a/tools/telemetry/telemetry/inspector_backend.py b/tools/telemetry/telemetry/inspector_backend.py index 958f24f..a0e7ed8 100644 --- a/tools/telemetry/telemetry/inspector_backend.py +++ b/tools/telemetry/telemetry/inspector_backend.py @@ -13,12 +13,10 @@ class InspectorException(Exception): pass class InspectorBackend(object): - def __init__(self, backend, descriptor): - self._backend = backend - self._descriptor = descriptor - self._socket_url = descriptor['webSocketDebuggerUrl'] - self._socket = websocket.create_connection( - descriptor['webSocketDebuggerUrl']) + def __init__(self, tab_controller, debugger_url): + self._tab_controller = tab_controller + self._socket_url = debugger_url + self._socket = websocket.create_connection(self._socket_url) self._next_request_id = 0 self._domain_handlers = {} self._cur_socket_timeout = 0 @@ -30,14 +28,14 @@ class InspectorBackend(object): self._domain_handlers = {} self._socket.close() self._socket = None - self._backend = None + self._tab_controller = None def DispatchNotifications(self, timeout=10): self._SetTimeout(timeout) try: data = self._socket.recv() except (socket.error, websocket.WebSocketException): - if self._backend.DoesDebuggerUrlExist(self._socket_url): + if self._tab_controller.DoesDebuggerUrlExist(self._socket_url): return raise tab_crash_exception.TabCrashException() @@ -81,7 +79,7 @@ class InspectorBackend(object): try: data = self._socket.recv() except (socket.error, websocket.WebSocketException): - if self._backend.DoesDebuggerUrlExist(self._socket_url): + if self._tab_controller.DoesDebuggerUrlExist(self._socket_url): raise util.TimeoutException( 'Timed out waiting for reply. This is unusual.') raise tab_crash_exception.TabCrashException() diff --git a/tools/telemetry/telemetry/page_runner.py b/tools/telemetry/telemetry/page_runner.py index b2268e2..181ac03 100644 --- a/tools/telemetry/telemetry/page_runner.py +++ b/tools/telemetry/telemetry/page_runner.py @@ -27,11 +27,11 @@ class _RunState(object): def Close(self): if self.trace_tab: - self.trace_tab.Close() + self.trace_tab.Disconnect() self.trace_tab = None if self.tab: - self.tab.Close() + self.tab.Disconnect() self.tab = None if self.browser: @@ -118,16 +118,22 @@ http://goto/read-src-internal, or create a new archive using --record. self._SetupBrowser(state, test, possible_browser, credentials_path, archive_path) if not state.tab: - state.tab = state.browser.ConnectToNthTab(0) + if len(state.browser.tabs) == 0: + state.browser.tabs.New() + state.tab = state.browser.tabs[0] if options.trace_dir: self._SetupTracingTab(state) try: self._RunPage(options, page, state.tab, test, results) except tab_crash_exception.TabCrashException: + # Close the crashed tab. We'll open another before the next run. + if state.browser.supports_tab_control: + state.tab.Close() + state.tab = None # If we don't support tab control, just restart the browser. - # TODO(dtu): Create a new tab: crbug.com/155077, crbug.com/159852 - state.Close() + else: + state.Close() if options.trace_dir and state.trace_tab: self._EndTracing(state, options, page) @@ -224,13 +230,12 @@ http://goto/read-src-internal, or create a new archive using --record. def _SetupTracingTab(self, state): if not state.trace_tab: - state.browser.NewTab() # Swap the two tabs because new tabs open to about:blank, and we # can't navigate across protocols to chrome://tracing. The initial # tab starts at chrome://newtab, so it works for that tab. # TODO(dtu): If the trace_tab crashes, we're hosed. state.trace_tab = state.tab - state.tab = state.browser.ConnectToNthTab(1) + state.tab = state.browser.tabs.New() state.trace_tab.page.Navigate('chrome://tracing') state.trace_tab.WaitForDocumentReadyStateToBeInteractiveOrBetter() diff --git a/tools/telemetry/telemetry/tab.py b/tools/telemetry/telemetry/tab.py index 9d6530f..7f3730f 100644 --- a/tools/telemetry/telemetry/tab.py +++ b/tools/telemetry/telemetry/tab.py @@ -1,6 +1,7 @@ # Copyright (c) 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +from telemetry import inspector_backend from telemetry import inspector_console from telemetry import inspector_page from telemetry import inspector_runtime @@ -20,35 +21,52 @@ class Tab(object): # Evaluates 1+1 in the tab's javascript context. tab.runtime.Evaluate('1+1') """ - def __init__(self, browser, inspector_backend): + def __init__(self, browser, tab_controller, debugger_url): self._browser = browser - self._inspector_backend = inspector_backend + self._tab_controller = tab_controller + self._debugger_url = debugger_url + + self._inspector_backend = None + self._console = None + self._page = None + self._runtime = None + self._timeline = None + + def __del__(self): + self.Disconnect() + + def _Connect(self): + if self._inspector_backend: + return + + self._inspector_backend = inspector_backend.InspectorBackend( + self._tab_controller, self._debugger_url) + self._console = inspector_console.InspectorConsole( + self._inspector_backend, self) self._page = inspector_page.InspectorPage(self._inspector_backend, self) self._runtime = inspector_runtime.InspectorRuntime( self._inspector_backend, self) - self._console = inspector_console.InspectorConsole( - self._inspector_backend, self) self._timeline = inspector_timeline.InspectorTimeline( self._inspector_backend, self) - def __del__(self): - self.Close() - - def Close(self): + def Disconnect(self): + """Closes the connection to this tab.""" self._console = None - self._runtime = None self._page = None + self._runtime = None self._timeline = None if self._inspector_backend: self._inspector_backend.Close() self._inspector_backend = None self._browser = None - def __enter__(self): - return self + def Close(self): + """Closes this tab. - def __exit__(self, *args): - self.Close() + Not all browsers or browser versions support this method. + Be sure to check browser.supports_tab_control.""" + self.Disconnect() + self._tab_controller.CloseTab(self._debugger_url) @property def browser(self): @@ -56,23 +74,31 @@ class Tab(object): return self._browser @property + def url(self): + return self._tab_controller.GetTabUrl(self._debugger_url) + + @property + def console(self): + """Methods for interacting with the page's console object.""" + self._Connect() + return self._console + + @property def page(self): """Methods for interacting with the current page.""" + self._Connect() return self._page @property def runtime(self): """Methods for interacting with the page's javascript runtime.""" + self._Connect() return self._runtime @property - def console(self): - """Methods for interacting with the page's console object.""" - return self._console - - @property def timeline(self): """Methods for interacting with the inspector timeline.""" + self._Connect() return self._timeline def WaitForDocumentReadyStateToBeComplete(self, timeout=DEFAULT_TAB_TIMEOUT): diff --git a/tools/telemetry/telemetry/tab_test_case.py b/tools/telemetry/telemetry/tab_test_case.py index 09145e7..c890ca8 100644 --- a/tools/telemetry/telemetry/tab_test_case.py +++ b/tools/telemetry/telemetry/tab_test_case.py @@ -27,14 +27,14 @@ class TabTestCase(unittest.TestCase): raise Exception('No browser found, cannot continue test.') try: self._browser = browser_to_create.Create() - self._tab = self._browser.ConnectToNthTab(0) + self._tab = self._browser.tabs[0] except: self.tearDown() raise def tearDown(self): if self._tab: - self._tab.Close() + self._tab.Disconnect() if self._browser: self._browser.Close() diff --git a/tools/telemetry/telemetry/temporary_http_server_unittest.py b/tools/telemetry/telemetry/temporary_http_server_unittest.py index 08129d8..85785c4 100644 --- a/tools/telemetry/telemetry/temporary_http_server_unittest.py +++ b/tools/telemetry/telemetry/temporary_http_server_unittest.py @@ -15,11 +15,10 @@ class TemporaryHTTPServerTest(unittest.TestCase): browser_to_create = browser_finder.FindBrowser(options) with browser_to_create.Create() as b: b.SetHTTPServerDirectory(unittest_data_dir) - with b.ConnectToNthTab(0) as t: - t.page.Navigate(b.http_server.UrlOf('/blank.html')) - t.WaitForDocumentReadyStateToBeComplete() - x = t.runtime.Evaluate('document.body.innerHTML') - x = x.strip() - - self.assertEquals(x, 'Hello world') + t = b.tabs[0] + t.page.Navigate(b.http_server.UrlOf('/blank.html')) + t.WaitForDocumentReadyStateToBeComplete() + x = t.runtime.Evaluate('document.body.innerHTML') + x = x.strip() + self.assertEquals(x, 'Hello world') |