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

Side by Side Diff: tools/perf/profile_creators/extensions_profile_creator.py

Issue 847583002: Fix telemetry extension profile generator for OSX. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@telemetry_profile_generation4_2
Patch Set: Created 5 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
« no previous file with comments | « no previous file | tools/perf/profile_creators/many_extensions_profile_creator.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 2014 The Chromium Authors. All rights reserved. 1 # Copyright 2014 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 json 5 import json
6 import logging 6 import logging
7 import os 7 import os
8 import platform 8 import platform
9 import shutil 9 import shutil
10 import socket 10 import socket
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
47 # Profile setup works in 2 phases: 47 # Profile setup works in 2 phases:
48 # Phase 1: When the first page is loaded: we wait for a timeout to allow 48 # Phase 1: When the first page is loaded: we wait for a timeout to allow
49 # all extensions to install and to prime safe browsing and other 49 # all extensions to install and to prime safe browsing and other
50 # caches. Extensions may open tabs as part of the install process. 50 # caches. Extensions may open tabs as part of the install process.
51 # Phase 2: When the second page loads, user_story_runner closes all tabs - 51 # Phase 2: When the second page loads, user_story_runner closes all tabs -
52 # we are left with one open tab, wait for that to finish loading. 52 # we are left with one open tab, wait for that to finish loading.
53 53
54 # Sleep for a bit to allow safe browsing and other data to load + 54 # Sleep for a bit to allow safe browsing and other data to load +
55 # extensions to install. 55 # extensions to install.
56 if not self._extensions_installed: 56 if not self._extensions_installed:
57 sleep_seconds = 5 * 60 57 sleep_seconds = 15
58 logging.info("Sleeping for %d seconds." % sleep_seconds) 58 logging.info("Sleeping for %d seconds." % sleep_seconds)
59 time.sleep(sleep_seconds) 59 time.sleep(sleep_seconds)
60 self._extensions_installed = True 60 self._extensions_installed = True
61 else: 61 else:
62 # Phase 2: Wait for tab to finish loading. 62 # Phase 2: Wait for tab to finish loading.
63 for i in xrange(len(tab.browser.tabs)): 63 for i in xrange(len(tab.browser.tabs)):
64 t = tab.browser.tabs[i] 64 t = tab.browser.tabs[i]
65 t.WaitForDocumentReadyStateToBeComplete() 65 t.WaitForDocumentReadyStateToBeComplete()
66 66
67 def DidRunTest(self, browser, results): 67 def DidRunTest(self, browser, results):
68 """Superclass override.""" 68 """Superclass override."""
69 super(_ExtensionPageTest, self).DidRunTest(browser, 69 super(_ExtensionPageTest, self).DidRunTest(browser,
70 results) 70 results)
71 # Do some basic sanity checks to make sure the profile is complete. 71 # Do some basic sanity checks to make sure the profile is complete.
72 installed_extensions = browser.extensions.keys() 72 installed_extensions = browser.extensions.keys()
73 if not len(installed_extensions) == self._expected_extension_count: 73 if not len(installed_extensions) == self._expected_extension_count:
74 # Diagnosing errors: 74 # Diagnosing errors:
75 # Too many extensions: Managed environment may be installing additional 75 # Too many extensions: Managed environment may be installing additional
76 # extensions. 76 # extensions.
77 raise Exception("Unexpected number of extensions installed in browser", 77 raise Exception("Unexpected number of extensions installed in browser",
78 installed_extensions) 78 installed_extensions)
79 79
80 80
81 def _ExternalExtensionsPath(): 81 def _ExternalExtensionsPath(profile_path):
82 """Returns the OS-dependent path at which to install the extension deployment 82 """Returns the OS-dependent path at which to install the extension deployment
83 files""" 83 files.
84
85 |profile_path| is the path of the profile that will be used to launch the
86 browser.
87 """
84 if platform.system() == 'Darwin': 88 if platform.system() == 'Darwin':
85 return os.path.join('/Library', 'Application Support', 'Google', 'Chrome', 89 return str(profile_path) + '/External Extensions'
86 'External Extensions') 90
87 elif platform.system() == 'Linux':
88 return os.path.join('/opt', 'google', 'chrome', 'extensions' )
89 else: 91 else:
90 raise NotImplementedError('Extension install on %s is not yet supported' % 92 raise NotImplementedError('Extension install on %s is not yet supported' %
91 platform.system()) 93 platform.system())
92 94
93 95
94 def _DownloadExtension(extension_id, output_dir): 96 def _DownloadExtension(extension_id, output_dir):
95 """Download an extension to disk. 97 """Download an extension to disk.
96 98
97 Args: 99 Args:
98 extension_id: the extension id. 100 extension_id: the extension id.
99 output_dir: Directory to download into. 101 output_dir: Directory to download into.
100 102
101 Returns: 103 Returns:
102 Extension file downloaded.""" 104 Extension file downloaded."""
103 extension_download_path = os.path.join(output_dir, "%s.crx" % extension_id) 105 extension_download_path = os.path.join(output_dir, "%s.crx" % extension_id)
106
107 # Ideally, the Chrome version would be dynamically extracted from the binary.
108 # Instead, we use a Chrome version whose release date is expected to be
109 # about a hundred years in the future.
110 chrome_version = '1000.0.0.0'
104 extension_url = ( 111 extension_url = (
105 "https://clients2.google.com/service/update2/crx?response=redirect" 112 "https://clients2.google.com/service/update2/crx?response=redirect"
106 "&x=id%%3D%s%%26lang%%3Den-US%%26uc" % extension_id) 113 "&prodversion=%s&x=id%%3D%s%%26lang%%3Den-US%%26uc"
114 % (chrome_version, extension_id))
107 response = urllib2.urlopen(extension_url) 115 response = urllib2.urlopen(extension_url)
108 assert(response.getcode() == 200) 116 assert(response.getcode() == 200)
109 117
110 with open(extension_download_path, "w") as f: 118 with open(extension_download_path, "w") as f:
111 f.write(response.read()) 119 f.write(response.read())
112 120
113 return extension_download_path 121 return extension_download_path
114 122
115 123
116 def _GetExtensionInfoFromCRX(crx_path): 124 def _GetExtensionInfoFromCRX(crx_path):
(...skipping 21 matching lines...) Expand all
138 146
139 class ExtensionsProfileCreator(profile_creator.ProfileCreator): 147 class ExtensionsProfileCreator(profile_creator.ProfileCreator):
140 """Abstract base class for profile creators that install extensions. 148 """Abstract base class for profile creators that install extensions.
141 149
142 Extensions are installed using the mechanism described in 150 Extensions are installed using the mechanism described in
143 https://developer.chrome.com/extensions/external_extensions.html . 151 https://developer.chrome.com/extensions/external_extensions.html .
144 152
145 Subclasses are meant to be run interactively. 153 Subclasses are meant to be run interactively.
146 """ 154 """
147 def __init__(self, extensions_to_install=None, theme_to_install=None): 155 def __init__(self, extensions_to_install=None, theme_to_install=None):
148 self._CheckTestEnvironment()
149 super(ExtensionsProfileCreator, self).__init__() 156 super(ExtensionsProfileCreator, self).__init__()
150 157
151 # List of extensions to install. 158 # List of extensions to install.
152 self._extensions_to_install = list(extensions_to_install or []) 159 self._extensions_to_install = []
153 160 if extensions_to_install:
154 # Theme to install (if any). 161 self._extensions_to_install.extend(extensions_to_install)
155 self._theme_to_install = theme_to_install 162 if theme_to_install:
163 self._extensions_to_install.append(theme_to_install)
156 164
157 # Directory to download extension files into. 165 # Directory to download extension files into.
158 self._extension_download_dir = None 166 self._extension_download_dir = None
159 167
160 # List of files to delete after run. 168 # List of files to delete after run.
161 self._files_to_cleanup = [] 169 self._files_to_cleanup = []
162 170
163 def _CheckTestEnvironment(self): 171 def Run(self, options):
164 # Running this script on a corporate network or other managed environment 172 # Installing extensions requires that the profile directory exist before
165 # could potentially alter the profile contents. 173 # the browser is launched.
166 hostname = socket.gethostname() 174 if not options.browser_options.profile_dir:
167 if hostname.endswith('corp.google.com'): 175 options.browser_options.profile_dir = tempfile.mkdtemp()
168 raise Exception("It appears you are connected to a corporate network " 176 options.browser_options.disable_default_apps = False
169 "(hostname=%s). This script needs to be run off the corp "
170 "network." % hostname)
171 177
172 prompt = ("\n!!!This script must be run on a fresh OS installation, " 178 self._PrepareExtensionInstallFiles(options.browser_options.profile_dir)
173 "disconnected from any corporate network. Are you sure you want to "
174 "continue? (y/N) ")
175 if (raw_input(prompt).lower() != 'y'):
176 sys.exit(-1)
177
178 def Run(self, options):
179 self._PrepareExtensionInstallFiles()
180 179
181 expectations = test_expectations.TestExpectations() 180 expectations = test_expectations.TestExpectations()
182 results = results_options.CreateResults( 181 results = results_options.CreateResults(
183 benchmark.BenchmarkMetadata(profile_creator.__class__.__name__), 182 benchmark.BenchmarkMetadata(profile_creator.__class__.__name__),
184 options) 183 options)
185 extension_page_test = _ExtensionPageTest() 184 extension_page_test = _ExtensionPageTest()
186 extension_page_test._expected_extension_count = len( 185 extension_page_test._expected_extension_count = len(
187 self._extensions_to_install) 186 self._extensions_to_install)
188 user_story_runner.Run(extension_page_test, extension_page_test._page_set, 187 user_story_runner.Run(extension_page_test, extension_page_test._page_set,
189 expectations, options, results) 188 expectations, options, results)
190 189
191 self._CleanupExtensionInstallFiles() 190 self._CleanupExtensionInstallFiles()
192 191
193 # Check that files on this list exist and have content. 192 # Check that files on this list exist and have content.
194 expected_files = [ 193 expected_files = [
195 os.path.join('Default', 'Network Action Predictor')] 194 os.path.join('Default', 'Network Action Predictor')]
196 for filename in expected_files: 195 for filename in expected_files:
197 filename = os.path.join(options.output_profile_path, filename) 196 filename = os.path.join(options.output_profile_path, filename)
198 if not os.path.getsize(filename) > 0: 197 if not os.path.getsize(filename) > 0:
199 raise Exception("Profile not complete: %s is zero length." % filename) 198 raise Exception("Profile not complete: %s is zero length." % filename)
200 199
201 if results.failures: 200 if results.failures:
202 logging.warning('Some pages failed.') 201 logging.warning('Some pages failed.')
203 logging.warning('Failed pages:\n%s', 202 logging.warning('Failed pages:\n%s',
204 '\n'.join(map(str, results.pages_that_failed))) 203 '\n'.join(map(str, results.pages_that_failed)))
205 raise Exception('ExtensionsProfileCreator failed.') 204 raise Exception('ExtensionsProfileCreator failed.')
206 205
207 def _PrepareExtensionInstallFiles(self): 206 def _PrepareExtensionInstallFiles(self, profile_path):
208 """Download extension archives and create extension install files.""" 207 """Download extension archives and create extension install files."""
209 extensions_to_install = self._extensions_to_install 208 extensions_to_install = self._extensions_to_install
210 if self._theme_to_install:
211 extensions_to_install.append(self._theme_to_install)
212 if not extensions_to_install: 209 if not extensions_to_install:
213 raise ValueError("No extensions or themes to install:", 210 raise ValueError("No extensions or themes to install:",
214 extensions_to_install) 211 extensions_to_install)
215 212
216 # Create external extensions path if it doesn't exist already. 213 # Create external extensions path if it doesn't exist already.
217 external_extensions_dir = _ExternalExtensionsPath() 214 external_extensions_dir = _ExternalExtensionsPath(profile_path)
218 if not os.path.isdir(external_extensions_dir): 215 if not os.path.isdir(external_extensions_dir):
219 os.makedirs(external_extensions_dir) 216 os.makedirs(external_extensions_dir)
220 217
221 self._extension_download_dir = tempfile.mkdtemp() 218 self._extension_download_dir = tempfile.mkdtemp()
222 219
223 num_extensions = len(extensions_to_install) 220 num_extensions = len(extensions_to_install)
224 for i, extension_id in extensions_to_install: 221 for i in range(num_extensions):
222 extension_id = extensions_to_install[i]
225 logging.info("Downloading %s - %d/%d" % ( 223 logging.info("Downloading %s - %d/%d" % (
226 extension_id, (i + 1), num_extensions)) 224 extension_id, (i + 1), num_extensions))
227 extension_path = _DownloadExtension(extension_id, 225 extension_path = _DownloadExtension(extension_id,
228 self._extension_download_dir) 226 self._extension_download_dir)
229 (version, name) = _GetExtensionInfoFromCRX(extension_path) 227 (version, name) = _GetExtensionInfoFromCRX(extension_path)
230 extension_info = {'external_crx' : extension_path, 228 extension_info = {'external_crx' : extension_path,
231 'external_version' : version, 229 'external_version' : version,
232 '_comment' : name} 230 '_comment' : name}
233 extension_json_path = os.path.join(external_extensions_dir, 231 extension_json_path = os.path.join(external_extensions_dir,
234 "%s.json" % extension_id) 232 "%s.json" % extension_id)
235 with open(extension_json_path, 'w') as f: 233 with open(extension_json_path, 'w') as f:
236 f.write(json.dumps(extension_info)) 234 f.write(json.dumps(extension_info))
237 self._files_to_cleanup.append(extension_json_path) 235 self._files_to_cleanup.append(extension_json_path)
238 236
239 def _CleanupExtensionInstallFiles(self): 237 def _CleanupExtensionInstallFiles(self):
240 """Cleanup stray files before exiting.""" 238 """Cleanup stray files before exiting."""
241 logging.info("Cleaning up stray files") 239 logging.info("Cleaning up stray files")
242 for filename in self._files_to_cleanup: 240 for filename in self._files_to_cleanup:
243 os.remove(filename) 241 os.remove(filename)
244 242
245 if self._extension_download_dir: 243 if self._extension_download_dir:
246 # Simple sanity check to lessen the impact of a stray rmtree(). 244 # Simple sanity check to lessen the impact of a stray rmtree().
247 if len(self._extension_download_dir.split(os.sep)) < 3: 245 if len(self._extension_download_dir.split(os.sep)) < 3:
248 raise Exception("Path too shallow: %s" % self._extension_download_dir) 246 raise Exception("Path too shallow: %s" % self._extension_download_dir)
249 shutil.rmtree(self._extension_download_dir) 247 shutil.rmtree(self._extension_download_dir)
250 self._extension_download_dir = None 248 self._extension_download_dir = None
OLDNEW
« no previous file with comments | « no previous file | tools/perf/profile_creators/many_extensions_profile_creator.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698