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

Side by Side Diff: tools/python/google/webpagereplay_utils.py

Issue 9956045: Add Web Page Replay test to page cycler. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Implement review suggestions. Created 8 years, 8 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
OLDNEW
(Empty)
1 #!/usr/bin/env python
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
5
6 """A class to help start/stop a Web Page Replay Server.
7
8 The page cycler tests use this module to run Web Page Replay
9 (see tools/build/scripts/slave/runtest.py).
10
11 If run from the command-line, the module will launch Web Page Replay
12 and the specified test:
13
14 ./webpagereplay_utils.py --help # list options
15 ./webpagereplay_utils.py 2012Q2 # run a WPR-enabled test
16 """
17
18 import logging
19 import optparse
20 import os
21 import shutil
22 import signal
23 import subprocess
24 import sys
25 import tempfile
26 import time
27 import urllib
28
29
30 USAGE = '%s [options] TEST_NAME' % os.path.basename(sys.argv[0])
31 USER_DATA_DIR = '{TEMP}/webpagereplay_utils-chrome'
32
33 # The port numbers must match those in chrome/test/perf/page_cycler_test.cc.
34 HTTP_PORT = 8080
35 HTTPS_PORT = 8413
36
37
38 class ReplayError(Exception):
39 """Catch-all exception for the module."""
40 pass
41
42 class ReplayNotFoundError(Exception):
43 pass
44
45 class ReplayNotStartedError(Exception):
46 pass
47
48
49 class ReplayLauncher(object):
50 LOG_FILE = 'log.txt'
51
52 def __init__(self, replay_dir, archive_path, log_dir, replay_options=None):
53 """Initialize ReplayLauncher.
54
55 Args:
56 replay_dir: directory that has replay.py and related modules.
57 archive_path: either a directory that contains WPR archives or,
58 a path to a specific WPR archive.
59 log_dir: where to write log.txt.
60 replay_options: a list of options strings to forward to replay.py.
61 """
62 self.replay_dir = replay_dir
63 self.archive_path = archive_path
64 self.log_dir = log_dir
65 self.replay_options = replay_options if replay_options else []
66
67 self.log_name = os.path.join(self.log_dir, self.LOG_FILE)
68 self.log_fh = None
69 self.proxy_process = None
70
71 self.wpr_py = os.path.join(self.replay_dir, 'replay.py')
72 if not os.path.exists(self.wpr_py):
73 raise ReplayNotFoundError('Path does not exist: %s' % self.wpr_py)
74 self.wpr_options = [
75 '--port', str(HTTP_PORT),
76 '--ssl_port', str(HTTPS_PORT),
77 '--use_closest_match',
78 # TODO(slamm): Add traffic shaping (requires root):
79 # '--net', 'fios',
80 ]
81 self.wpr_options.extend(self.replay_options)
82
83 def _OpenLogFile(self):
84 if not os.path.exists(self.log_dir):
85 os.makedirs(self.log_dir)
86 return open(self.log_name, 'w')
87
88 def StartServer(self):
89 cmd_line = [self.wpr_py]
90 cmd_line.extend(self.wpr_options)
91 # TODO(slamm): Support choosing archive on-the-fly.
92 cmd_line.append(self.archive_path)
93 self.log_fh = self._OpenLogFile()
94 logging.debug('Starting Web-Page-Replay: %s', cmd_line)
95 self.proxy_process = subprocess.Popen(
96 cmd_line, stdout=self.log_fh, stderr=subprocess.STDOUT)
97 if not self.IsStarted():
98 raise ReplayNotStartedError(
99 'Web Page Replay failed to start. See the log file: ' + self.log_name)
100
101 def IsStarted(self):
102 """Checks to see if the server is up and running."""
103 for _ in range(5):
104 if self.proxy_process.poll() is not None:
105 # The process has exited.
106 break
107 try:
108 up_url = '%s://localhost:%s/web-page-replay-generate-200'
109 http_up_url = up_url % ('http', HTTP_PORT)
110 https_up_url = up_url % ('https', HTTPS_PORT)
111 if (200 == urllib.urlopen(http_up_url, None, {}).getcode() and
112 200 == urllib.urlopen(https_up_url, None, {}).getcode()):
113 return True
114 except IOError:
115 time.sleep(1)
116 return False
117
118 def StopServer(self):
119 if self.proxy_process:
120 logging.debug('Stopping Web-Page-Replay')
121 # Use a SIGINT here so that it can do graceful cleanup.
122 # Otherwise, we will leave subprocesses hanging.
123 self.proxy_process.send_signal(signal.SIGINT)
124 self.proxy_process.wait()
125 if self.log_fh:
126 self.log_fh.close()
127
128
129 class ChromiumPaths(object):
130 """Collect all the path handling together."""
131 PATHS = {
132 'archives': 'src/data/page_cycler/webpagereplay',
133 '.wpr': 'src/data/page_cycler/webpagereplay/{TEST_NAME}.wpr',
134 '.wpr_alt': 'src/tools/page_cycler/webpagereplay/tests/{TEST_NAME}.wpr',
135 'start.html': 'src/tools/page_cycler/webpagereplay/start.html',
136 'extension': 'src/tools/page_cycler/webpagereplay/extension',
137 'logs': 'src/webpagereplay_logs/{TEST_EXE_NAME}',
138 'replay': 'tools/build/third_party/webpagereplay',
139 }
140
141 def __init__(self, **replacements):
142 """Initialize ChromiumPaths.
143
144 Args:
145 replacements: a dict of format replacements for PATHS such as
146 {'TEST_NAME': '2012Q2', 'TEST_EXE_NAME': 'performance_ui_tests'}.
147 """
148 module_dir = os.path.dirname(__file__)
149 self.base_dir = os.path.abspath(os.path.join(
150 module_dir, '..', '..', '..', '..'))
151 self.replacements = replacements
152
153 def __getitem__(self, key):
154 path_parts = [x.format(**self.replacements)
155 for x in self.PATHS[key].split('/')]
156 return os.path.join(self.base_dir, *path_parts)
157
158
159 def LaunchChromium(chrome_exe, chromium_paths, test_name,
160 is_dns_forwarded, use_auto):
161 """Launch chromium to run WPR-backed page cycler tests.
162
163 These options need to be kept in sync with
164 src/chrome/test/perf/page_cycler_test.cc.
165 """
166 REPLAY_HOST='127.0.0.1'
167 user_data_dir = USER_DATA_DIR.format(**{'TEMP': tempfile.gettempdir()})
168 chromium_args = [
169 chrome_exe,
170 '--load-extension=%s' % chromium_paths['extension'],
171 '--testing-fixed-http-port=%s' % HTTP_PORT,
172 '--testing-fixed-https-port=%s' % HTTPS_PORT,
173 '--disable-background-networking',
174 '--enable-experimental-extension-apis',
175 '--enable-file-cookies',
176 '--enable-logging',
177 '--log-level=0',
178 '--enable-stats-table',
179 '--enable-benchmarking',
180 '--ignore-certificate-errors',
181 '--metrics-recording-only',
182 '--activate-on-launch',
183 '--no-first-run',
184 '--no-proxy-server',
185 '--user-data-dir=%s' % user_data_dir,
186 '--window-size=1280,1024',
187 ]
188 if not is_dns_forwarded:
189 chromium_args.append('--host-resolver-rules=MAP * %s' % REPLAY_HOST)
190 start_url = 'file://%s?test=%s' % (chromium_paths['start.html'], test_name)
191 if use_auto:
192 start_url += '&auto=1'
193 chromium_args.append(start_url)
194 if os.path.exists(user_data_dir):
195 shutil.rmtree(user_data_dir)
196 os.makedirs(user_data_dir)
197 try:
198 logging.debug('Starting Chrome: %s', chromium_args)
199 retval = subprocess.call(chromium_args)
200 finally:
201 shutil.rmtree(user_data_dir)
202
203
204 def main():
205 log_level = logging.DEBUG
206 logging.basicConfig(level=log_level,
207 format='%(asctime)s %(filename)s:%(lineno)-3d'
208 ' %(levelname)s %(message)s',
209 datefmt='%y%m%d %H:%M:%S')
210
211 option_parser = optparse.OptionParser(usage=USAGE)
212 option_parser.add_option(
213 '', '--auto', action='store_true', default=False,
214 help='Start test automatically.')
215 option_parser.add_option(
216 '', '--chrome-exe', default=None,
James Simonsen 2012/04/17 03:30:19 It seems this is required, but I don't see exactly
slamm_google 2012/04/17 20:47:16 Thanks for catching that. I made it an argument in
217 help='Path for the Chrome binary.')
218 option_parser.add_option(
219 '', '--replay-dir', default=None,
220 help='Run replay from this directory instead of tools/build/third_party.')
221 replay_group = optparse.OptionGroup(option_parser,
222 'Options for replay.py', 'These options are passed through to replay.py.')
223 replay_group.add_option(
224 '', '--record', action='store_true', default=False,
225 help='Record a new WPR archive.')
226 replay_group.add_option( # use default that does not require sudo
227 '', '--dns_forwarding', default=False, action='store_true',
228 help='Forward DNS requests to the local replay server.')
229 option_parser.add_option_group(replay_group)
230 options, args = option_parser.parse_args()
231 if len(args) != 1:
232 print >>sys.stderr, '%s: Error: Need exactly one TEST_NAME.' % sys.argv[0]
233 return 1
234 test_name = args[0]
235
236 chromium_paths = ChromiumPaths(
237 TEST_NAME=test_name,
238 TEST_EXE_NAME='webpagereplay_utils')
239 if os.path.exists(chromium_paths['archives']):
240 archive_path = chromium_paths['.wpr']
241 else:
242 archive_path = chromium_paths['.wpr_alt']
243 if not os.path.exists(archive_path) and not options.record:
244 print >>sys.stderr, 'Archive does not exist:', archive_path
245 return 1
246
247 replay_options = []
248 if options.record:
249 replay_options.append('--record')
250 if not options.dns_forwarding:
251 replay_options.append('--no-dns_forwarding')
252
253 if options.replay_dir:
254 replay_dir = options.replay_dir
255 else:
256 replay_dir = chromium_paths['replay']
257 wpr = ReplayLauncher(replay_dir, archive_path,
258 chromium_paths['logs'], replay_options)
259 try:
260 wpr.StartServer()
261 LaunchChromium(options.chrome_exe, chromium_paths, test_name,
262 options.dns_forwarding, options.auto)
263 finally:
264 wpr.StopServer()
265 return 0
266
267 if '__main__' == __name__:
268 sys.exit(main())
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698