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

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

Issue 825703003: Change profile_creator to not subclass page_test (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@telemetry_profile_generation
Patch Set: Created 5 years, 12 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
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
11 import sys 11 import sys
12 import tempfile 12 import tempfile
13 import time 13 import time
14 import urllib2 14 import urllib2
15 import zipfile 15 import zipfile
16 16
17 from telemetry.page import profile_creator 17 from telemetry.page import profile_creator
18 18
19 import page_sets 19 import page_sets
20 20
21 from telemetry import benchmark
22 from telemetry.page import page_test
23 from telemetry.page import test_expectations
24 from telemetry.results import results_options
25 from telemetry.user_story import user_story_runner
21 26
22 def _ExternalExtensionsPath(): 27 def _ExternalExtensionsPath():
23 """Returns the OS-dependent path at which to install the extension deployment 28 """Returns the OS-dependent path at which to install the extension deployment
24 files""" 29 files"""
25 if platform.system() == 'Darwin': 30 if platform.system() == 'Darwin':
26 return os.path.join('/Library', 'Application Support', 'Google', 'Chrome', 31 return os.path.join('/Library', 'Application Support', 'Google', 'Chrome',
27 'External Extensions') 32 'External Extensions')
28 elif platform.system() == 'Linux': 33 elif platform.system() == 'Linux':
29 return os.path.join('/opt', 'google', 'chrome', 'extensions' ) 34 return os.path.join('/opt', 'google', 'chrome', 'extensions' )
30 else: 35 else:
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
68 (crx_version, extension_name)""" 73 (crx_version, extension_name)"""
69 crx_zip = zipfile.ZipFile(crx_path) 74 crx_zip = zipfile.ZipFile(crx_path)
70 manifest_contents = crx_zip.read('manifest.json') 75 manifest_contents = crx_zip.read('manifest.json')
71 decoded_manifest = json.loads(manifest_contents) 76 decoded_manifest = json.loads(manifest_contents)
72 crx_version = decoded_manifest['version'] 77 crx_version = decoded_manifest['version']
73 extension_name = decoded_manifest['name'] 78 extension_name = decoded_manifest['name']
74 79
75 return (crx_version, extension_name) 80 return (crx_version, extension_name)
76 81
77 class ExtensionsProfileCreator(profile_creator.ProfileCreator): 82 class ExtensionsProfileCreator(profile_creator.ProfileCreator):
78 """Virtual base class for profile creators that install extensions. 83 """Abstract base class for profile creators that install extensions.
79 84
80 Extensions are installed using the mechanism described in 85 Extensions are installed using the mechanism described in
81 https://developer.chrome.com/extensions/external_extensions.html . 86 https://developer.chrome.com/extensions/external_extensions.html .
82 87
83 Subclasses are meant to be run interactively. 88 Subclasses are meant to be run interactively.
84 """ 89 """
90 class PageTest(page_test.PageTest):
dtu 2015/01/09 01:23:58 I'm finding the nested classes hard to read. Can y
erikchen 2015/01/09 03:12:42 Done. I renamed it to _ExtensionPageTest just to m
91 def __init__(self):
92 super(ExtensionsProfileCreator.PageTest, self).__init__()
93 self._page_set = page_sets.Typical25PageSet()
94
95 # Have the extensions been installed yet?
96 self._extensions_installed = False
97
98 # Expected
99 self._expected_extension_count = 0
100
101 def CanRunForPage(self, page):
102 # Superclass override.
103 # No matter how many pages in the pageset, just perform two test
104 # iterations.
105 return page.page_set.pages.index(page) < 2
106
107 def ValidateAndMeasurePage(self, _, tab, results):
108 # Superclass override.
109 # Profile setup works in 2 phases:
110 # Phase 1: When the first page is loaded: we wait for a timeout to allow
111 # all extensions to install and to prime safe browsing and other
112 # caches. Extensions may open tabs as part of the install process.
113 # Phase 2: When the second page loads, user_story_runner closes all tabs -
114 # we are left with one open tab, wait for that to finish loading.
115
116 # Sleep for a bit to allow safe browsing and other data to load +
117 # extensions to install.
118 if not self._extensions_installed:
119 sleep_seconds = 5 * 60
120 logging.info("Sleeping for %d seconds." % sleep_seconds)
121 time.sleep(sleep_seconds)
122 self._extensions_installed = True
123 else:
124 # Phase 2: Wait for tab to finish loading.
125 for i in xrange(len(tab.browser.tabs)):
126 t = tab.browser.tabs[i]
127 t.WaitForDocumentReadyStateToBeComplete()
128
129 def DidRunTest(self, browser, results):
130 """Superclass override."""
131 super(ExtensionsProfileCreator.PageTest, self).DidRunTest(browser,
132 results)
133 # Do some basic sanity checks to make sure the profile is complete.
134 installed_extensions = browser.extensions.keys()
135 if not len(installed_extensions) == self._expected_extension_count:
136 # Diagnosing errors:
137 # Too many extensions: Managed environment may be installing additional
138 # extensions.
139 raise Exception("Unexpected number of extensions installed in browser",
140 installed_extensions)
141
85 142
86 def __init__(self): 143 def __init__(self):
87 super(ExtensionsProfileCreator, self).__init__() 144 super(ExtensionsProfileCreator, self).__init__()
88 self._page_set = page_sets.Typical25() 145 self._page_test = ExtensionsProfileCreator.PageTest()
dtu 2015/01/09 01:23:58 Why create a side-effect on the class if you're us
erikchen 2015/01/09 03:12:42 I removed the member, and made it a local variable
89
90 # Directory into which the output profile is written.
91 self._output_profile_path = None
92 146
93 # List of extensions to install. 147 # List of extensions to install.
94 self._extensions_to_install = [] 148 self._extensions_to_install = []
95 149
96 # Theme to install (if any). 150 # Theme to install (if any).
97 self._theme_to_install = None 151 self._theme_to_install = None
98 152
99 # Directory to download extension files into. 153 # Directory to download extension files into.
100 self._extension_download_dir = None 154 self._extension_download_dir = None
101 155
102 # Have the extensions been installed yet?
103 self._extensions_installed = False
104
105 # List of files to delete after run. 156 # List of files to delete after run.
106 self._files_to_cleanup = [] 157 self._files_to_cleanup = []
107 158
159 def Run(self, options):
160 self._PrepareExtensionInstallFiles()
161
162 expectations = test_expectations.TestExpectations()
163 results = results_options.CreateResults(
164 benchmark.BenchmarkMetadata(profile_creator.__class__.__name__),
165 options)
166 self._page_test._expected_extension_count = len(self._extensions_to_install)
167 user_story_runner.Run(self._page_test, self._page_test._page_set,
168 expectations, options, results)
169
170 self._CleanupExtensionInstallFiles()
171
172 # Check that files on this list exist and have content.
173 expected_files = [
174 os.path.join('Default', 'Network Action Predictor')]
175 for filename in expected_files:
176 filename = os.path.join(options.output_profile_path, filename)
177 if not os.path.getsize(filename) > 0:
178 raise Exception("Profile not complete: %s is zero length." % filename)
179
180 if results.failures:
181 logging.warning('Some pages failed.')
182 logging.warning('Failed pages:\n%s',
183 '\n'.join(map(str, results.pages_that_failed)))
184 raise Exception('ExtensionsProfileCreator failed.')
185
108 def _PrepareExtensionInstallFiles(self): 186 def _PrepareExtensionInstallFiles(self):
109 """Download extension archives and create extension install files.""" 187 """Download extension archives and create extension install files."""
110 extensions_to_install = self._extensions_to_install 188 extensions_to_install = self._extensions_to_install
111 if self._theme_to_install: 189 if self._theme_to_install:
112 extensions_to_install = extensions_to_install + [self._theme_to_install] 190 extensions_to_install = extensions_to_install + [self._theme_to_install]
113 num_extensions = len(extensions_to_install) 191 num_extensions = len(extensions_to_install)
114 if not num_extensions: 192 if not num_extensions:
115 raise ValueError("No extensions or themes to install:", 193 raise ValueError("No extensions or themes to install:",
116 extensions_to_install) 194 extensions_to_install)
117 195
(...skipping 26 matching lines...) Expand all
144 for filename in self._files_to_cleanup: 222 for filename in self._files_to_cleanup:
145 os.remove(filename) 223 os.remove(filename)
146 224
147 if self._extension_download_dir: 225 if self._extension_download_dir:
148 # Simple sanity check to lessen the impact of a stray rmtree(). 226 # Simple sanity check to lessen the impact of a stray rmtree().
149 if len(self._extension_download_dir.split(os.sep)) < 3: 227 if len(self._extension_download_dir.split(os.sep)) < 3:
150 raise Exception("Path too shallow: %s" % self._extension_download_dir) 228 raise Exception("Path too shallow: %s" % self._extension_download_dir)
151 shutil.rmtree(self._extension_download_dir) 229 shutil.rmtree(self._extension_download_dir)
152 self._extension_download_dir = None 230 self._extension_download_dir = None
153 231
154 def CustomizeBrowserOptions(self, options):
155 self._output_profile_path = options.output_profile_path
156
157 def WillRunTest(self, options):
158 """Run before browser starts.
159
160 Download extensions and write installation files."""
161 super(ExtensionsProfileCreator, self).WillRunTest(options)
162
163 # Running this script on a corporate network or other managed environment
164 # could potentially alter the profile contents.
165 hostname = socket.gethostname()
166 if hostname.endswith('corp.google.com'):
167 raise Exception("It appears you are connected to a corporate network "
168 "(hostname=%s). This script needs to be run off the corp "
169 "network." % hostname)
170
171 prompt = ("\n!!!This script must be run on a fresh OS installation, "
172 "disconnected from any corporate network. Are you sure you want to "
173 "continue? (y/N) ")
174 if (raw_input(prompt).lower() != 'y'):
175 sys.exit(-1)
176 self._PrepareExtensionInstallFiles()
177
178 def DidRunTest(self, browser, results):
179 """Run before exit."""
180 super(ExtensionsProfileCreator, self).DidRunTest()
181 # Do some basic sanity checks to make sure the profile is complete.
182 installed_extensions = browser.extensions.keys()
183 if not len(installed_extensions) == len(self._extensions_to_install):
184 # Diagnosing errors:
185 # Too many extensions: Managed environment may be installing additional
186 # extensions.
187 raise Exception("Unexpected number of extensions installed in browser",
188 installed_extensions)
189
190 # Check that files on this list exist and have content.
191 expected_files = [
192 os.path.join('Default', 'Network Action Predictor')]
193 for filename in expected_files:
194 filename = os.path.join(self._output_profile_path, filename)
195 if not os.path.getsize(filename) > 0:
196 raise Exception("Profile not complete: %s is zero length." % filename)
197
198 self._CleanupExtensionInstallFiles()
199
200 def CanRunForPage(self, page):
201 # No matter how many pages in the pageset, just perform two test iterations.
202 return page.page_set.pages.index(page) < 2
203
204 def ValidateAndMeasurePage(self, _, tab, results):
205 # Profile setup works in 2 phases:
206 # Phase 1: When the first page is loaded: we wait for a timeout to allow
207 # all extensions to install and to prime safe browsing and other
208 # caches. Extensions may open tabs as part of the install process.
209 # Phase 2: When the second page loads, user_story_runner closes all tabs -
210 # we are left with one open tab, wait for that to finish loading.
211
212 # Sleep for a bit to allow safe browsing and other data to load +
213 # extensions to install.
214 if not self._extensions_installed:
215 sleep_seconds = 5 * 60
216 logging.info("Sleeping for %d seconds." % sleep_seconds)
217 time.sleep(sleep_seconds)
218 self._extensions_installed = True
219 else:
220 # Phase 2: Wait for tab to finish loading.
221 for i in xrange(len(tab.browser.tabs)):
222 t = tab.browser.tabs[i]
223 t.WaitForDocumentReadyStateToBeComplete()
OLDNEW
« no previous file with comments | « no previous file | tools/perf/profile_creators/small_profile_creator.py » ('j') | tools/telemetry/telemetry/page/profile_creator.py » ('J')

Powered by Google App Engine
This is Rietveld 408576698