Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(372)

Side by Side Diff: tools/telemetry/telemetry/browser_backend.py

Issue 11412238: Proof of concept for running extension API stack through dev tools. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase Created 7 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « tools/telemetry/telemetry/browser.py ('k') | tools/telemetry/telemetry/browser_finder.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 import urllib2 5 import urllib2
6 import httplib 6 import httplib
7 import socket 7 import socket
8 import json 8 import json
9 import re 9 import re
10 import sys 10 import sys
11 import weakref 11 import weakref
12 12
13 from telemetry import browser_gone_exception 13 from telemetry import browser_gone_exception
14 from telemetry import extension_page
14 from telemetry import tab 15 from telemetry import tab
15 from telemetry import tracing_backend 16 from telemetry import tracing_backend
16 from telemetry import user_agent 17 from telemetry import user_agent
17 from telemetry import util 18 from telemetry import util
18 from telemetry import wpr_modes 19 from telemetry import wpr_modes
19 from telemetry import wpr_server 20 from telemetry import wpr_server
20 21
21 22
22 class BrowserConnectionGoneException( 23 class BrowserConnectionGoneException(
23 browser_gone_exception.BrowserGoneException): 24 browser_gone_exception.BrowserGoneException):
24 pass 25 pass
25 26
26 27 class ContextControler(object):
27 class TabController(object):
28 def __init__(self, browser, browser_backend): 28 def __init__(self, browser, browser_backend):
29 self._browser = browser 29 self._browser = browser
30 self._browser_backend = browser_backend 30 self._browser_backend = browser_backend
31
32 # Stores web socket debugger URLs in iteration order. 31 # Stores web socket debugger URLs in iteration order.
33 self._tab_list = [] 32 self._context_list = []
34 # Maps debugger URLs to Tab objects. 33 # Maps debugger URLs to Tab objects.
35 self._tab_dict = weakref.WeakValueDictionary() 34 self._context_dict = weakref.WeakValueDictionary()
36 35 self._UpdateContextList()
37 self._UpdateTabList()
38
39 def New(self, timeout=None):
40 self._browser_backend.Request('new', timeout=timeout)
41 return self[-1]
42 36
43 def DoesDebuggerUrlExist(self, url): 37 def DoesDebuggerUrlExist(self, url):
44 self._UpdateTabList() 38 self._UpdateContextList()
45 return url in self._tab_list 39 return url in self._context_list
46 40
47 def CloseTab(self, debugger_url, timeout=None): 41 def CloseTab(self, debugger_url, timeout=None):
48 # TODO(dtu): crbug.com/160946, allow closing the last tab on some platforms. 42 # TODO(dtu): crbug.com/160946, allow closing the last tab on some platforms.
49 # For now, just create a new tab before closing the last tab. 43 # For now, just create a new tab before closing the last tab.
50 if len(self) <= 1: 44 if len(self) <= 1:
51 self.New() 45 self.New()
52 46
53 tab_id = debugger_url.split('/')[-1] 47 tab_id = debugger_url.split('/')[-1]
54 try: 48 try:
55 response = self._browser_backend.Request('close/%s' % tab_id, 49 response = self._browser_backend.Request('close/%s' % tab_id,
(...skipping 18 matching lines...) Expand all
74 def GetTabUrl(self, debugger_url): 68 def GetTabUrl(self, debugger_url):
75 tab_info = self._FindTabInfo(debugger_url) 69 tab_info = self._FindTabInfo(debugger_url)
76 # TODO(hartmanng): crbug.com/166886 (uncomment the following assert and 70 # TODO(hartmanng): crbug.com/166886 (uncomment the following assert and
77 # remove the extra None check when _ListTabs is fixed): 71 # remove the extra None check when _ListTabs is fixed):
78 # assert tab_info is not None 72 # assert tab_info is not None
79 if tab_info is None: 73 if tab_info is None:
80 return None 74 return None
81 return tab_info['url'] 75 return tab_info['url']
82 76
83 def __iter__(self): 77 def __iter__(self):
84 self._UpdateTabList() 78 self._UpdateContextList()
85 return self._tab_list.__iter__() 79 return self._context_list.__iter__()
86 80
87 def __len__(self): 81 def __len__(self):
88 self._UpdateTabList() 82 self._UpdateContextList()
89 return len(self._tab_list) 83 return len(self._context_list)
90 84
91 def __getitem__(self, index): 85 def __getitem__(self, index):
92 self._UpdateTabList() 86 self._UpdateContextList()
93 # This dereference will propagate IndexErrors. 87 # This dereference will propagate IndexErrors.
94 debugger_url = self._tab_list[index] 88 debugger_url = self._context_list[index]
89 return self._GetContextObjectForDebugger(debugger_url)
90
91 def FindByUrl(self, url):
92 for tab_info in self._ListContexts():
93 if tab_info['url'] == url:
94 return self._GetContextObjectForDebugger(
95 tab_info.get('webSocketDebuggerUrl'))
96 return None
97
98 def GetAllForUrl(self, url):
99 return [self._GetContextObjectForDebugger(
100 tab_info.get('webSocketDebuggerUrl'))
101 for tab_info in self._ListContexts()
102 if tab_info['url'] == url]
103
104 def _GetContextObjectForDebugger(self, debugger_url):
95 # Lazily get/create a Tab object. 105 # Lazily get/create a Tab object.
96 tab_object = self._tab_dict.get(debugger_url) 106 tab_object = self._context_dict.get(debugger_url)
97 if not tab_object: 107 if not tab_object:
98 tab_object = tab.Tab(self._browser, self, debugger_url) 108 tab_object = self._CreateContextObject(debugger_url)
99 self._tab_dict[debugger_url] = tab_object 109 self._context_dict[debugger_url] = tab_object
100 return tab_object 110 return tab_object
101 111
102 def _ListTabs(self, timeout=None): 112 def _ListContexts(self, timeout=None):
103 try: 113 try:
104 data = self._browser_backend.Request('', timeout=timeout) 114 data = self._browser_backend.Request('', timeout=timeout)
105 all_contexts = json.loads(data) 115 all_contexts = json.loads(data)
106 tabs = [ctx for ctx in all_contexts 116 contexts = self._FilterContexts(all_contexts)
107 if not ctx['url'].startswith('chrome-extension://')] 117 return contexts
108 return tabs
109 except (socket.error, httplib.BadStatusLine, urllib2.URLError): 118 except (socket.error, httplib.BadStatusLine, urllib2.URLError):
110 if not self._browser_backend.IsBrowserRunning(): 119 if not self._browser_backend.IsBrowserRunning():
111 raise browser_gone_exception.BrowserGoneException() 120 raise browser_gone_exception.BrowserGoneException()
112 raise BrowserConnectionGoneException() 121 raise BrowserConnectionGoneException()
113 122
114 def _UpdateTabList(self): 123 def _UpdateContextList(self):
115 def GetDebuggerUrl(tab_info): 124 def GetDebuggerUrl(tab_info):
116 if 'webSocketDebuggerUrl' not in tab_info: 125 if 'webSocketDebuggerUrl' not in tab_info:
117 return None 126 return None
118 return tab_info['webSocketDebuggerUrl'] 127 return tab_info['webSocketDebuggerUrl']
119 new_tab_list = map(GetDebuggerUrl, self._ListTabs()) 128 new_context_list = map(GetDebuggerUrl, self._ListContexts())
120 self._tab_list = [t for t in self._tab_list if t in new_tab_list] 129 self._context_list = [t for t in self._context_list
121 self._tab_list += [t for t in new_tab_list if t not in self._tab_list] 130 if t in new_context_list]
131 self._context_list += [t for t in new_context_list
132 if t not in self._context_list]
122 133
123 def _FindTabInfo(self, debugger_url): 134 def _FindContextInfo(self, debugger_url):
124 for tab_info in self._ListTabs(): 135 for tab_info in self._ListContexts():
125 if tab_info.get('webSocketDebuggerUrl') == debugger_url: 136 if tab_info.get('webSocketDebuggerUrl') == debugger_url:
126 return tab_info 137 return tab_info
127 return None 138 return None
128 139
129 140
141 class TabController(ContextControler):
142 def __init__(self, browser, browser_backend):
143 super(TabController, self).__init__(browser, browser_backend)
144
145 def _CreateContextObject(self, debugger_url):
146 return tab.Tab(self._browser, self, debugger_url)
147
148 def _FilterContexts(self, all_contexts):
149 return [ctx for ctx in all_contexts
150 if not ctx['url'].startswith('chrome-extension://')]
151
152 def New(self, timeout=None):
153 self._browser_backend.Request('new', timeout=timeout)
154 return self[-1]
155
156 def CloseTab(self, debugger_url, timeout=None):
157 # TODO(dtu): crbug.com/160946, allow closing the last tab on some platforms.
158 # For now, just create a new tab before closing the last tab.
159 if len(self) <= 1:
160 self.New()
161
162 tab_id = debugger_url.split('/')[-1]
163 try:
164 response = self._browser_backend.Request('close/%s' % tab_id,
165 timeout=timeout)
166 except urllib2.HTTPError:
167 raise Exception('Unable to close tab, tab id not found: %s' % tab_id)
168 assert response == 'Target is closing'
169
170 util.WaitFor(lambda: not self._FindContextInfo(debugger_url), timeout=5)
171 self._UpdateContextList()
172
173 def GetTabUrl(self, debugger_url):
174 tab_info = self._FindContextInfo(debugger_url)
175 assert tab_info is not None
176 return tab_info['url']
177
178 class ExtensionController(ContextControler):
179 def __init__(self, browser, browser_backend):
180 super(ExtensionController, self).__init__(browser, browser_backend)
181
182 def _CreateContextObject(self, debugger_url):
183 return extension_page.ExtensionPage(
184 tab.Tab(self._browser, self, debugger_url))
185
186 def _FilterContexts(self, all_contexts):
187 return [ctx for ctx in all_contexts
188 if ctx['url'].startswith('chrome-extension://')]
189
130 class BrowserBackend(object): 190 class BrowserBackend(object):
131 """A base class for browser backends. Provides basic functionality 191 """A base class for browser backends. Provides basic functionality
132 once a remote-debugger port has been established.""" 192 once a remote-debugger port has been established."""
133 193
134 WEBPAGEREPLAY_HOST = '127.0.0.1' 194 WEBPAGEREPLAY_HOST = '127.0.0.1'
135 WEBPAGEREPLAY_HTTP_PORT = 8080 195 WEBPAGEREPLAY_HTTP_PORT = 8080
136 WEBPAGEREPLAY_HTTPS_PORT = 8413 196 WEBPAGEREPLAY_HTTPS_PORT = 8413
137 197
138 def __init__(self, is_content_shell, options): 198 def __init__(self, is_content_shell, options):
139 self.tabs = None 199 self.tabs = None
200 self.extensions = None
140 self.browser_type = options.browser_type 201 self.browser_type = options.browser_type
141 self.is_content_shell = is_content_shell 202 self.is_content_shell = is_content_shell
142 self.options = options 203 self.options = options
143 self._port = None 204 self._port = None
144 205
145 self._inspector_protocol_version = 0 206 self._inspector_protocol_version = 0
146 self._chrome_branch_number = 0 207 self._chrome_branch_number = 0
147 self._webkit_base_revision = 0 208 self._webkit_base_revision = 0
148 self._tracing_backend = None 209 self._tracing_backend = None
149 210
150 if options.dont_override_profile: 211 if options.dont_override_profile:
151 sys.stderr.write('Warning: Not overriding profile. This can cause ' 212 sys.stderr.write('Warning: Not overriding profile. This can cause '
152 'unexpected effects due to profile-specific settings, ' 213 'unexpected effects due to profile-specific settings, '
153 'such as about:flags settings, cookies, and ' 214 'such as about:flags settings, cookies, and '
154 'extensions.\n') 215 'extensions.\n')
155 216
156 def SetBrowser(self, browser): 217 def SetBrowser(self, browser):
157 self.tabs = TabController(browser, self) 218 self.tabs = TabController(browser, self)
219 if not self.is_content_shell:
220 self.extensions = ExtensionController(browser, self)
158 221
159 def GetBrowserStartupArgs(self): 222 def GetBrowserStartupArgs(self):
160 args = [] 223 args = []
161 args.extend(self.options.extra_browser_args) 224 args.extend(self.options.extra_browser_args)
162 args.append('--disable-background-networking') 225 args.append('--disable-background-networking')
163 args.append('--metrics-recording-only') 226 args.append('--metrics-recording-only')
164 args.append('--no-first-run') 227 args.append('--no-first-run')
165 if self.options.wpr_mode != wpr_modes.WPR_OFF: 228 if self.options.wpr_mode != wpr_modes.WPR_OFF:
166 args.extend(wpr_server.GetChromeFlags(self.WEBPAGEREPLAY_HOST, 229 args.extend(wpr_server.GetChromeFlags(self.WEBPAGEREPLAY_HOST,
167 self.WEBPAGEREPLAY_HTTP_PORT, 230 self.WEBPAGEREPLAY_HTTP_PORT,
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
241 self._tracing_backend = None 304 self._tracing_backend = None
242 305
243 def CreateForwarder(self, *port_pairs): 306 def CreateForwarder(self, *port_pairs):
244 raise NotImplementedError() 307 raise NotImplementedError()
245 308
246 def IsBrowserRunning(self): 309 def IsBrowserRunning(self):
247 raise NotImplementedError() 310 raise NotImplementedError()
248 311
249 def GetStandardOutput(self): 312 def GetStandardOutput(self):
250 raise NotImplementedError() 313 raise NotImplementedError()
OLDNEW
« no previous file with comments | « tools/telemetry/telemetry/browser.py ('k') | tools/telemetry/telemetry/browser_finder.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698