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

Side by Side Diff: chrome/test/functional/webpagereplay.py

Issue 10825025: Make it easy to use Web Page Replay with non-page_cycler tests. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fixes for review comments. Created 8 years, 4 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 | « chrome/test/functional/perf.py ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 """Start and stop Web Page Replay.""" 6 """Start and stop Web Page Replay.
7
8 Of the public module names, the following ones are key:
9 CHROME_FLAGS: Chrome options to make it work with Web Page Replay.
10 FormatChromiumPath: a convenience function to create OS-specific paths.
11 ReplayServer: a class to start/stop Web Page Replay.
12 """
7 13
8 import logging 14 import logging
9 import optparse
10 import os 15 import os
11 import shutil
12 import signal 16 import signal
13 import subprocess 17 import subprocess
14 import sys
15 import tempfile
16 import time 18 import time
17 import urllib 19 import urllib
18 20
19 21
20 USAGE = '%s [options] CHROME_EXE TEST_NAME' % os.path.basename(sys.argv[0])
21 USER_DATA_DIR = '{TEMP}/webpagereplay_utils-chrome'
22
23 # The port numbers must match those in chrome/test/perf/page_cycler_test.cc.
24 HTTP_PORT = 8080 22 HTTP_PORT = 8080
25 HTTPS_PORT = 8413 23 HTTPS_PORT = 8413
26 REPLAY_HOST='127.0.0.1' 24 REPLAY_HOST='127.0.0.1'
25 CHROME_FLAGS = [
26 '--host-resolver-rules=MAP * %s,EXCLUDE localhost' % REPLAY_HOST,
27 '--testing-fixed-http-port=%s' % HTTP_PORT,
28 '--testing-fixed-https-port=%s' % HTTPS_PORT,
29 '--ignore-certificate-errors',
30 ]
31
32 _BASE_DIR = os.path.abspath(os.path.join(
33 os.path.dirname(__file__), os.pardir, os.pardir, os.pardir, os.pardir))
34 REPLAY_DIR = os.path.join(_BASE_DIR, 'src', 'third_party', 'webpagereplay')
35 LOG_PATH = os.path.join(_BASE_DIR, 'src', 'webpagereplay_logs', 'logs.txt')
27 36
28 37
29 class ReplayError(Exception): 38 class ReplayError(Exception):
30 """Catch-all exception for the module.""" 39 """Catch-all exception for the module."""
31 pass 40 pass
32 41
33 class ReplayNotFoundError(ReplayError): 42 class ReplayNotFoundError(ReplayError):
34 pass 43 def __init__(self, label, path):
44 self.args = (label, path)
45
46 def __str__(self):
47 label, path = self.args
48 return 'Path does not exist for %s: %s' % (label, path)
35 49
36 class ReplayNotStartedError(ReplayError): 50 class ReplayNotStartedError(ReplayError):
37 pass 51 pass
38 52
39 53
54 def FormatChromiumPath(posix_path, **kwargs):
55 """Convert a path relative to the Chromium root into an OS-specific path.
56
57 Args:
58 posix_path: a path string that may be a format().
59 Example: 'src/third_party/{module_name}/__init__.py'
60 kwargs: args for the format replacement.
61 Example: {'module_name': 'pylib'}
62 Returns:
63 an absolute path in the current Chromium tree with formatting applied.
64 """
65 formated_path = posix_path.format(**kwargs)
66 path_parts = formated_path.split('/')
67 return os.path.join(_BASE_DIR, *path_parts)
68
69
40 class ReplayServer(object): 70 class ReplayServer(object):
41 """Start and Stop Web Page Replay. 71 """Start and Stop Web Page Replay.
42 72
73 Web Page Replay is a proxy that can record and "replay" web pages with
74 simulated network characteristics -- without having to edit the pages
75 by hand. With WPR, tests can use "real" web content, and catch
76 performance issues that may result from introducing network delays and
77 bandwidth throttling.
78
43 Example: 79 Example:
44 with ReplayServer(replay_dir, archive_path, log_dir, replay_options): 80 with ReplayServer(archive_path):
45 self.NavigateToURL(start_url) 81 self.NavigateToURL(start_url)
46 self.WaitUntil(...) 82 self.WaitUntil(...)
83
84 Environment Variables (for development):
85 WPR_ARCHIVE_PATH: path to alternate archive file (e.g. '/tmp/foo.wpr').
86 WPR_RECORD: if set, puts Web Page Replay in record mode instead of replay.
87 WPR_REPLAY_DIR: path to alternate Web Page Replay source.
47 """ 88 """
48 LOG_FILE = 'log.txt' 89 def __init__(self, archive_path, replay_options=None, replay_dir=None,
49 90 log_path=None):
50 def __init__(self, replay_dir, archive_path, log_dir, replay_options=None):
51 """Initialize ReplayServer. 91 """Initialize ReplayServer.
52 92
53 Args: 93 Args:
94 archive_path: a path to a specific WPR archive (required).
95 replay_options: a list of options strings to forward to replay.py.
54 replay_dir: directory that has replay.py and related modules. 96 replay_dir: directory that has replay.py and related modules.
55 archive_path: either a directory that contains WPR archives or, 97 log_path: a path to a log file.
56 a path to a specific WPR archive. 98 """
57 log_dir: where to write log.txt. 99 self.archive_path = os.environ.get('WPR_ARCHIVE_PATH', archive_path)
58 replay_options: a list of options strings to forward to replay.py. 100 self.replay_options = replay_options or []
59 """ 101 self.replay_dir = os.environ.get('WPR_REPLAY_DIR', replay_dir or REPLAY_DIR)
60 self.replay_dir = replay_dir 102 self.log_path = log_path or LOG_PATH
61 self.archive_path = archive_path
62 self.log_dir = log_dir
63 self.replay_options = replay_options if replay_options else []
64 103
65 self.log_name = os.path.join(self.log_dir, self.LOG_FILE) 104 if 'WPR_RECORD' in os.environ and '--record' not in self.replay_options:
105 self.replay_options.append('--record')
106 self.is_record_mode = '--record' in self.replay_options
107 self._AddDefaultReplayOptions()
108
109 self.replay_py = os.path.join(self.replay_dir, 'replay.py')
110
111 if self.is_record_mode:
112 self._CheckPath('archive directory', os.path.dirname(self.archive_path))
113 elif not os.path.exists(self.archive_path):
114 self._CheckPath('archive file', self.archive_path)
115 self._CheckPath('replay script', self.replay_py)
116
66 self.log_fh = None 117 self.log_fh = None
67 self.replay_process = None 118 self.replay_process = None
68 119
69 self.wpr_py = os.path.join(self.replay_dir, 'replay.py') 120 def _AddDefaultReplayOptions(self):
70 if not os.path.exists(self.wpr_py): 121 """Set WPR command-line options. Can be overridden if needed."""
71 raise ReplayNotFoundError('Path does not exist: %s' % self.wpr_py) 122 self.replay_options += [
72 self.wpr_options = [
73 '--port', str(HTTP_PORT), 123 '--port', str(HTTP_PORT),
74 '--ssl_port', str(HTTPS_PORT), 124 '--ssl_port', str(HTTPS_PORT),
75 '--use_closest_match', 125 '--use_closest_match',
76 # TODO(slamm): Add traffic shaping (requires root): 126 '--no-dns_forwarding',
77 # '--net', 'fios', 127 # '--net', 'fios', # TODO(slamm): Add traffic shaping (requires root).
78 ] 128 ]
79 self.wpr_options.extend(self.replay_options) 129
130 def _CheckPath(self, label, path):
131 if not os.path.exists(path):
132 raise ReplayNotFoundError(label, path)
80 133
81 def _OpenLogFile(self): 134 def _OpenLogFile(self):
82 if not os.path.exists(self.log_dir): 135 log_dir = os.path.dirname(self.log_path)
83 os.makedirs(self.log_dir) 136 if not os.path.exists(log_dir):
84 return open(self.log_name, 'w') 137 os.makedirs(log_dir)
138 return open(self.log_path, 'w')
85 139
86 def IsStarted(self): 140 def IsStarted(self):
87 """Checks to see if the server is up and running.""" 141 """Checks to see if the server is up and running."""
88 for _ in range(5): 142 for _ in range(5):
89 if self.replay_process.poll() is not None: 143 if self.replay_process.poll() is not None:
90 # The process has exited. 144 # The process has exited.
91 break 145 break
92 try: 146 try:
93 up_url = '%s://localhost:%s/web-page-replay-generate-200' 147 up_url = '%s://localhost:%s/web-page-replay-generate-200'
94 http_up_url = up_url % ('http', HTTP_PORT) 148 http_up_url = up_url % ('http', HTTP_PORT)
95 https_up_url = up_url % ('https', HTTPS_PORT) 149 https_up_url = up_url % ('https', HTTPS_PORT)
96 if (200 == urllib.urlopen(http_up_url, None, {}).getcode() and 150 if (200 == urllib.urlopen(http_up_url, None, {}).getcode() and
97 200 == urllib.urlopen(https_up_url, None, {}).getcode()): 151 200 == urllib.urlopen(https_up_url, None, {}).getcode()):
98 return True 152 return True
99 except IOError: 153 except IOError:
100 time.sleep(1) 154 time.sleep(1)
101 return False 155 return False
102 156
103 def StartServer(self): 157 def StartServer(self):
104 """Start Web Page Replay and verify that it started. 158 """Start Web Page Replay and verify that it started.
105 159
106 Raises: 160 Raises:
107 ReplayNotStartedError if Replay start-up fails. 161 ReplayNotStartedError if Replay start-up fails.
108 """ 162 """
109 cmd_line = [self.wpr_py] 163 cmd_line = [self.replay_py]
110 cmd_line.extend(self.wpr_options) 164 cmd_line.extend(self.replay_options)
111 cmd_line.append(self.archive_path) 165 cmd_line.append(self.archive_path)
112 self.log_fh = self._OpenLogFile() 166 self.log_fh = self._OpenLogFile()
113 logging.debug('Starting Web-Page-Replay: %s', cmd_line) 167 logging.debug('Starting Web-Page-Replay: %s', cmd_line)
114 self.replay_process = subprocess.Popen( 168 self.replay_process = subprocess.Popen(
115 cmd_line, stdout=self.log_fh, stderr=subprocess.STDOUT) 169 cmd_line, stdout=self.log_fh, stderr=subprocess.STDOUT)
116 if not self.IsStarted(): 170 if not self.IsStarted():
117 raise ReplayNotStartedError( 171 raise ReplayNotStartedError(
118 'Web Page Replay failed to start. See the log file: ' + self.log_name) 172 'Web Page Replay failed to start. See the log file: ' + self.log_name)
119 173
120 def StopServer(self): 174 def StopServer(self):
121 """Stop Web Page Replay.""" 175 """Stop Web Page Replay."""
122 if self.replay_process: 176 if self.replay_process:
123 logging.debug('Stopping Web-Page-Replay') 177 logging.debug('Stopping Web-Page-Replay')
124 # Use a SIGINT here so that it can do graceful cleanup. 178 # Use a SIGINT here so that it can do graceful cleanup.
125 # Otherwise, we will leave subprocesses hanging. 179 # Otherwise, we will leave subprocesses hanging.
126 self.replay_process.send_signal(signal.SIGINT) 180 self.replay_process.send_signal(signal.SIGINT)
127 self.replay_process.wait() 181 self.replay_process.wait()
128 if self.log_fh: 182 if self.log_fh:
129 self.log_fh.close() 183 self.log_fh.close()
130 184
131 def __enter__(self): 185 def __enter__(self):
132 """Add support for with-statement.""" 186 """Add support for with-statement."""
133 self.StartServer() 187 self.StartServer()
fdeng1 2012/07/27 01:41:56 I figure it out. need to add "return self" here so
134 188
135 def __exit__(self, unused_exc_type, unused_exc_val, unused_exc_tb): 189 def __exit__(self, unused_exc_type, unused_exc_val, unused_exc_tb):
136 """Add support for with-statement.""" 190 """Add support for with-statement."""
137 self.StopServer() 191 self.StopServer()
OLDNEW
« no previous file with comments | « chrome/test/functional/perf.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698