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

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: Ready for review. 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 import logging
7 import optparse
8 import os
9 import shutil
10 import signal
11 import subprocess
12 import sys
13 import tempfile
14 import time
15 import urllib
16
17
tonyg 2012/04/13 14:32:21 A file level docstring would be helpful.
slamm_google 2012/04/13 23:43:36 Done.
18 USAGE = '%s [options] TEST_NAME' % os.path.basename(sys.argv[0])
19
20 USER_DATA_DIR = '{TEMP}/webpagereplay_utils-chrome'
21
22 class ReplayError(Exception):
23 """Catch-all exception for the module."""
24 pass
25
26 class ReplayNotFoundError(Exception):
27 pass
28
29 class ReplayNotStartedError(Exception):
30 pass
31
32
33 class ReplayLauncher(object):
34 HTTP_PORT = 8080
35 HTTPS_PORT = 8413
tonyg 2012/04/13 14:32:21 Looks like these have to match the ones hardcoded
slamm_google 2012/04/13 23:43:36 I moved these constants to the top of the file and
36 UP_URL = 'http://localhost:%s/web-page-replay-generate-200' % HTTP_PORT
37 LOG_FILE = 'log.txt'
38
39 def __init__(self, replay_dir, archive_path, log_dir, replay_options=None):
40 """Initialize ReplayLauncher.
41
42 Args:
43 replay_dir: directory that has replay.py and related modules.
44 archive_path: either a directory that contains WPR archives or,
45 a path to a specific WPR archive.
46 log_dir: where to write log.txt.
47 replay_options: a list of options strings to forward to replay.py.
48 """
49 self.replay_dir = replay_dir
50 self.archive_path = archive_path
51 self.log_dir = log_dir
52 self.replay_options = replay_options if replay_options else []
53
54 self.log_name = os.path.join(self.log_dir, self.LOG_FILE)
55 self.log_fh = None
56 self.proxy_process = None
57
58 self.wpr_py = os.path.join(self.replay_dir, 'replay.py')
59 if not os.path.exists(self.wpr_py):
60 raise ReplayNotFoundError('Path does not exist: %s' % self.wpr_py)
61 self.wpr_options = [
62 '--port', str(self.HTTP_PORT),
63 '--ssl_port', str(self.HTTPS_PORT),
64 '--use_closest_match',
65 # TODO(slamm): Add traffic shaping (requires root):
66 # '--net', 'fios',
67 ]
68 self.wpr_options.extend(self.replay_options)
69
70 def OpenLogFile_(self):
James Simonsen 2012/04/12 23:14:19 I think the _ goes on the other side in Python.
slamm_google 2012/04/13 23:43:36 Done.
71 if not os.path.exists(self.log_dir):
72 os.makedirs(self.log_dir)
73 return open(self.log_name, 'w')
74
75 def StartServer(self):
76 cmd_line = [self.wpr_py]
77 cmd_line.extend(self.wpr_options)
78 # TODO(slamm): Support choosing archive on-the-fly.
79 cmd_line.append(self.archive_path)
80 self.log_fh = self.OpenLogFile_()
81 logging.debug('Starting Web-Page-Replay: %s', cmd_line)
82 self.proxy_process = subprocess.Popen(
83 cmd_line, stdout=self.log_fh, stderr=subprocess.STDOUT)
84 if not self.IsStarted():
85 raise ReplayNotStartedError(
86 'Web Page Replay failed to start. See the log file: ' + self.log_name)
87
88 def IsStarted(self):
89 """Checks to see if the server is up and running."""
90 for _ in range(5):
91 if self.proxy_process.poll() is not None:
92 # The process has exited.
93 break
94 try:
95 if 200 == urllib.urlopen(self.UP_URL, None, {}).getcode():
96 return True
97 except IOError:
98 time.sleep(1)
99 return False
100
101 def StopServer(self):
102 if self.proxy_process:
103 logging.debug('Stopping Web-Page-Replay')
104 # Use a SIGINT here so that it can do graceful cleanup.
105 # Otherwise, we will leave subprocesses hanging.
106 self.proxy_process.send_signal(signal.SIGINT)
107 self.proxy_process.wait()
108 if self.log_fh:
109 self.log_fh.close()
110
111
112 class ChromiumPaths(object):
113 """Collect all the path handling together."""
114 PATHS = {
115 'archives': 'src/data/page_cycler/webpagereplay',
116 '.wpr': 'src/data/page_cycler/webpagereplay/{TEST_NAME}.wpr',
117 '.wpr_alt': 'src/tools/page_cycler/webpagereplay/tests/{TEST_NAME}.wpr',
118 'start.html': 'src/tools/page_cycler/webpagereplay/start.html',
119 'extension': 'src/tools/page_cycler/webpagereplay/extension',
120 'chrome': 'src/out/{TARGET}/chrome',
James Simonsen 2012/04/12 23:14:19 This is Linux only. You might want to just make it
slamm_google 2012/04/13 23:43:36 Thanks for catching that. I see that runtest.py do
121 'logs': 'src/webpagereplay_logs/{TEST_EXE_NAME}',
122 'replay': 'tools/build/third_party/webpagereplay',
123 }
124
125 def __init__(self, **replacements):
126 """Initialize ChromiumPaths.
127
128 Args:
129 replacements: a dict of format replacements for PATHS
130 (e.g. {'TARGET': 'Debug', 'TEST_NAME': '2012Q2'}).
131 """
132 module_dir = os.path.dirname(__file__)
133 self.base_dir = os.path.abspath(os.path.join(
134 module_dir, '..', '..', '..', '..'))
135 self.replacements = replacements
136
137 def __getitem__(self, key):
138 path_parts = [x.format(**self.replacements)
139 for x in self.PATHS[key].split('/')]
140 return os.path.join(self.base_dir, *path_parts)
141
142
143 def LaunchChromium(chromium_paths, test_name, is_dns_forwarded, use_auto):
144 REPLAY_HOST='127.0.0.1'
145 user_data_dir = USER_DATA_DIR.format(**{'TEMP': tempfile.gettempdir()})
146 chromium_args = [
147 chromium_paths['chrome'],
148 '--load-extension=%s' % chromium_paths['extension'],
149 '--testing-fixed-http-port=%s' % ReplayLauncher.HTTP_PORT,
150 '--testing-fixed-https-port=%s' % ReplayLauncher.HTTPS_PORT,
tonyg 2012/04/13 14:32:21 These flags all look very similar to the ones in t
slamm_google 2012/04/13 23:43:36 This is for a developer wanting to investigate one
tonyg 2012/04/16 15:34:32 A comment is better than nothing. But it still see
slamm_google 2012/04/16 23:43:07 I agree that there seems to be a fair amount of du
tonyg 2012/04/17 11:04:45 Good point. It is important to get something runni
slamm_google 2012/04/17 20:47:16 runtest.py uses this module to start and stop WPR.
151 '--disable-translate',
152 '--disable-background-networking',
153 '--enable-experimental-extension-apis',
154 '--enable-file-cookies',
155 '--enable-logging',
156 '--log-level=0',
157 '--enable-stats-table',
158 '--enable-benchmarking',
159 '--ignore-certificate-errors',
160 '--metrics-recording-only',
161 '--activate-on-launch',
162 '--no-first-run',
163 '--no-proxy-server',
164 '--user-data-dir=%s' % user_data_dir,
165 '--window-size=1280,1024',
166 ]
167 if not is_dns_forwarded:
168 chromium_args.append('--host-resolver-rules=MAP * %s' % REPLAY_HOST)
169 start_url = 'file://%s?test=%s' % (chromium_paths['start.html'], test_name)
170 if use_auto:
171 start_url += '&auto=1'
172 chromium_args.append(start_url)
173 if os.path.exists(user_data_dir):
174 shutil.rmtree(user_data_dir)
175 os.makedirs(user_data_dir)
176 try:
177 retval = subprocess.call(chromium_args)
178 finally:
179 shutil.rmtree(user_data_dir)
180
181
182 def main():
183 log_level = logging.DEBUG
184 logging.basicConfig(level=log_level,
185 format='%(asctime)s %(filename)s:%(lineno)-3d'
186 ' %(levelname)s %(message)s',
187 datefmt='%y%m%d %H:%M:%S')
188
189 option_parser = optparse.OptionParser(usage=USAGE)
190 option_parser.add_option(
191 '', '--auto', action='store_true', default=False,
192 help='Start test automatically.')
193 option_parser.add_option(
194 '', '--target', default='Release',
195 help='build target (Debug or Release)')
196 option_parser.add_option(
197 '', '--replay-dir', default=None,
198 help='Run replay from this directory instead of tools/build/third_party.')
199 replay_group = optparse.OptionGroup(option_parser,
200 'Options for replay.py', 'These options are passed through to replay.py.')
201 replay_group.add_option(
202 '', '--record', action='store_true', default=False,
203 help='Record a new WPR archive.')
204 replay_group.add_option( # use default that does not require sudo
205 '', '--dns_forwarding', default=False, action='store_true',
206 help='Forward DNS requests to the local replay server.')
207 option_parser.add_option_group(replay_group)
208 options, args = option_parser.parse_args()
209 if len(args) != 1:
210 print >>sys.stderr, '%s: Error: Need exactly one TEST_NAME.' % sys.argv[0]
211 return 1
212 test_name = args[0]
213
214 chromium_paths = ChromiumPaths(
215 TARGET=options.target,
216 TEST_NAME=test_name,
217 TEST_EXE_NAME='webpagereplay_utils')
218 if os.path.exists(chromium_paths['archives']):
219 archive_path = chromium_paths['.wpr']
220 else:
221 archive_path = chromium_paths['.wpr_alt']
222 if not os.path.exists(archive_path) and not options.record:
223 print >>sys.stderr, 'Archive does not exist:', archive_path
224 return 1
225
226 replay_options = []
227 if options.record:
228 replay_options.append('--record')
229 if not options.dns_forwarding:
230 replay_options.append('--no-dns_forwarding')
231
232 if options.replay_dir:
233 replay_dir = options.replay_dir
234 else:
235 replay_dir = chromium_paths['replay']
236 wpr = ReplayLauncher(replay_dir, archive_path,
237 chromium_paths['logs'], replay_options)
238 try:
239 wpr.StartServer()
240 LaunchChromium(chromium_paths, test_name,
241 options.dns_forwarding, options.auto)
242 finally:
243 wpr.StopServer()
244 return 0
245
246 if '__main__' == __name__:
247 sys.exit(main())
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698