summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authordtu@chromium.org <dtu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-12-10 20:18:50 +0000
committerdtu@chromium.org <dtu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-12-10 20:18:50 +0000
commitf7c5052cf76bbb5e3dd0fe512f59a3d343187614 (patch)
tree3bb2b1bbc486e88bb6000242e9f916d32b49f6ed /tools
parent616f27774090a7891b606fe5b3b1a1d8278f82f9 (diff)
downloadchromium_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.py74
-rwxr-xr-xtools/telemetry/examples/rendering_microbenchmark_test.py60
-rwxr-xr-xtools/telemetry/examples/telemetry_perf_test.py36
-rw-r--r--tools/telemetry/telemetry/android_browser_finder.py4
-rw-r--r--tools/telemetry/telemetry/browser.py26
-rw-r--r--tools/telemetry/telemetry/browser_backend.py151
-rw-r--r--tools/telemetry/telemetry/browser_unittest.py35
-rw-r--r--tools/telemetry/telemetry/cros_browser_backend.py4
-rw-r--r--tools/telemetry/telemetry/cros_browser_finder.py4
-rw-r--r--tools/telemetry/telemetry/desktop_browser_finder.py4
-rw-r--r--tools/telemetry/telemetry/google_credentials_backend_unittest.py5
-rw-r--r--tools/telemetry/telemetry/inspector_backend.py16
-rw-r--r--tools/telemetry/telemetry/page_runner.py19
-rw-r--r--tools/telemetry/telemetry/tab.py62
-rw-r--r--tools/telemetry/telemetry/tab_test_case.py4
-rw-r--r--tools/telemetry/telemetry/temporary_http_server_unittest.py13
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')