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

Side by Side Diff: chrome/test/functional/perf/endure_setup.py

Issue 10837114: Automate Chrome Endure setup process. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: get rid of revision number option 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 | « no previous file | 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
(Empty)
1 """Automate the setup process of Chrome Endure environment.
Nirnimesh 2012/08/09 17:28:05 license header?
fdeng1 2012/08/14 19:11:40 Done.
2
3 Usage:
4 python endure_setup.py [fetch|server] [option]
5
6 We use <ENDURE_DIR> to refer to the root directory in which Chrome Endure
7 is set up. By default, <ENDURE_DIR> is the current working directory.
8
9 First, run "python endure_setup.py fetch". This command will automatically setup
10 Chrome Endure in <ENDURE_DIR>.
11
12 Next, try to run your first endure test by:
13 TEST_LENGTH=60 LOCAL_GRAPH='<ENDURE_DIR>/chrome_graph' \\
14 python <ENDURE_DIR>/src/chrome/test/functional/perf_endure_setup.py \\
15 perf_endure.ChromeEndureGmailTest.testGmailComposeDiscard \\
16 The above commands runs a Chrome Endure test for 60 seconds and saves
17 the results to <ENDURE_DIR>/chrome_graph.
18
19 Last, run "python endure_setup.py server". This command will start a local
20 HTTP server to serve <ENDURE_DIR>/chrome_graph. A port will be automatically
21 picked. You can now view the result graphs via http://localhost:<GIVEN_PORT>.
22
23 Use python endure_setup.py [fetch|server] --help for more options.
24 """
dennis_jeffrey 2012/08/08 23:41:07 in this docstring, also list the dependencies that
fdeng1 2012/08/14 19:11:40 Add some text about dependencies on depot_tools an
25
26 import BaseHTTPServer
27 import optparse
28 import os
29 import shutil
30 import SimpleHTTPServer
31 import subprocess
32 import sys
33 import urllib
34 import zipfile
35
36
37 class SetupError(Exception):
38 """Catch errors in setting up Chrome Endure."""
39 pass
40
41
42 class PlainHelpFormatter(optparse.IndentedHelpFormatter):
43 """Format the help message of this script."""
44
45 def format_description(self, description):
46 if description:
47 return description + '\n'
48 else:
49 return ''
50
51
52 class CmdFetch(object):
53 """Fetch Chrome Endure.
54
55 Usage:
56 python endure_setup.py fetch [options]
Nirnimesh 2012/08/09 17:28:05 leave a blank line
fdeng1 2012/08/14 19:11:40 Done.
57 Examples:
58 python endure_setup.py fetch
59 Fetch the latest version of Chrome Endure to the current
60 working directory.
61
62 python endure_setup.py fetch --endure-dir=/home/user/endure_dir
63 Fetch the latest version of Chrome Endure to /home/user/endure_dir.
64 """
65 _URLS = {'depot_tools': ('http://src.chromium.org'
66 '/chrome/trunk/tools/depot_tools'),
67 'pyauto': ('https://src.chromium.org/'
68 'chrome/trunk/src/chrome/test/functional.DEPS'),
69 # TODO(fdeng): change to an external address after graph code
70 # is checked in
71 'graph': ('http://www.corp.google.com/'
72 '~dennisjeffrey/chrome_perf/local_graphs.zip'),
73 }
74 NAME = 'fetch'
75 DESCRIPTION = 'Fetch Chrome Endure.'
76
77 def _ParseArgs(self, argv):
78 parser = optparse.OptionParser(
79 usage='%%prog %s [options]' % self.NAME,
80 formatter=PlainHelpFormatter(),
81 description=self.__doc__)
82 parser.add_option(
83 '-d', '--endure-dir', type='string', default=os.getcwd(),
84 help='Directory in which to setup or update. ' \
85 'Default value is the current working directory')
86 return parser.parse_args(argv)
87
88 def Run(self, argv):
89 """Run this command."""
90 options, _ = self._ParseArgs(argv)
91 self._endure_dir = os.path.abspath(options.endure_dir)
92 self._depot_dir = os.path.join(self._endure_dir, 'depot_tools')
93 self._gclient = os.path.join(self._depot_dir, 'gclient')
94 self._fetch_py = os.path.join(self._endure_dir, 'src', 'chrome',
95 'test', 'pyautolib',
96 'fetch_prebuilt_pyauto.py')
97 self._binary_dir = os.path.join(self._endure_dir, 'src', 'out', 'Release')
98 self._graph_dir = os.path.join(self._endure_dir, 'chrome_graph')
99
100 if not os.path.isdir(self._endure_dir):
101 os.makedirs(self._endure_dir)
102
103 print 'Checking depot tools...'
dennis_jeffrey 2012/08/08 23:41:07 i recommend using the "logging" module instead of
fdeng1 2012/08/14 19:11:40 Switch from "print" to "logging". On 2012/08/08 23
104 self._FetchDepot()
105 print 'Fetching PyAuto (python code)...'
106 self._FetchPyAuto()
107 print 'Fetching binaries(chrome, pyautolib, chrome driver)...'
108 self._FetchBinaries()
109 # TODO(fdeng): remove this after it is check into the chrome tree.
110 print 'Fetching chrome graphing files...'
111 self._FetchGraph()
112 return 0
113
114 def _FetchDepot(self):
115 """Fetch depot_tool if not installed in the system."""
116 try:
117 subprocess.call(['gclient', '--version'])
118 self._gclient = 'gclient'
119 except OSError:
120 # TODO(fdeng): how can I know gclient is not installed
121 # without checking OSError, a better way?
dennis_jeffrey 2012/08/08 23:41:07 it's possible depot_tools may already be installed
fdeng1 2012/08/14 19:11:40 Done.
122 url = self._URLS['depot_tools']
123 print 'Fetching depot tools: %s' % url
124 subprocess.call(['svn', 'co', self._URLS['depot_tools'],
125 self._depot_dir])
126 subprocess.call([self._gclient, '--version'])
dennis_jeffrey 2012/08/08 23:41:07 is there any way to verify that we were successful
fdeng1 2012/08/14 19:11:40 Added code to check that gclient/gclient.bat(win)
127
128 def _FetchPyAuto(self):
129 """Use gclient to fetch python code."""
130 cur_dir = os.getcwd()
131 os.chdir(self._endure_dir)
132 # gclient config
133 config_cmd = [self._gclient, 'config', self._URLS['pyauto']]
dennis_jeffrey 2012/08/08 23:41:07 Did Nirnimesh say it's not sufficient to use pyaut
fdeng1 2012/08/14 19:11:40 I think we were talking about webpagereplay was no
dennis_jeffrey 2012/08/15 17:53:08 Ok. I thought there was some problem where the fu
134 code = subprocess.call(config_cmd)
135 if code != 0:
136 raise SetupError('Running "%s" failed.' % ' '.join(config_cmd))
137 # gclient sync
138 sync_cmd = [self._gclient, 'sync']
139 code = subprocess.call(sync_cmd)
140 if code != 0:
141 raise SetupError('Running "%s" failed.' % ' '.join(sync_cmd))
142 os.chdir(cur_dir)
dennis_jeffrey 2012/08/08 23:41:07 should we also check to see whether an expected di
fdeng1 2012/08/14 19:11:40 Add _CheckPyAuto() Check src/chrome/test/pyatuolib
dennis_jeffrey 2012/08/15 17:53:08 I think this is good. I just thought a simple san
143
144 def _FetchBinaries(self):
145 """Get the prebuilt binaries from continuous build archive."""
146 if not os.path.exists(self._fetch_py):
147 raise SetupError(
148 'Unable to find %s, did fetching python code succeed?'
149 % self._fetch_py)
150 print 'Cleaning %s' % self._binary_dir
151 if os.path.exists(self._binary_dir):
152 shutil.rmtree(self._binary_dir)
153 print 'Downloading...'
154 cmd = [self._fetch_py, '-d', self._binary_dir, '--latest']
155 code = subprocess.call(cmd)
dennis_jeffrey 2012/08/08 23:41:07 if this is successful, maybe we could log a messag
fdeng1 2012/08/14 19:11:40 Done.
156 if code != 0:
157 raise SetupError('Running "%s" failed.' % ' '.join(cmd))
158
159 def _FetchGraph(self):
160 """Fetch graph code."""
161 graph_zip = urllib.urlretrieve(self._URLS['graph'])[0]
162 if graph_zip == None or not os.path.exists(graph_zip):
163 raise SetupError('Unable to retrieve %s' % self._URLS['graph'])
164 if os.path.exists(self._graph_dir):
165 print 'Cleaning %s, ' % self._graph_dir,
dennis_jeffrey 2012/08/08 23:41:07 Do we need to do all this work to clean the old di
fdeng1 2012/08/14 19:11:40 Done.
166 print 'data files(.dat) will be preserved.'
167 files = os.listdir(self._graph_dir)
168 for f in files:
169 path = os.path.join(self._graph_dir, f)
170 if os.path.isdir(path):
171 shutil.rmtree(path)
172 elif os.path.splitext(f) != 'dat':
173 os.remove(path)
174 else:
175 os.mkdir(self._graph_dir)
176 self._UnzipFilenameToDir(graph_zip, self._graph_dir)
177
178 @classmethod
179 def _UnzipFilenameToDir(cls, filename, directory):
180 """Unzip |filename| to directory |directory|.
181
182 This works with as low as python2.4 (used on win).
183 """
184 zf = zipfile.ZipFile(filename)
185 pushd = os.getcwd()
186 if not os.path.isdir(directory):
187 os.mkdir(directory)
188 os.chdir(directory)
189 # Extract files.
190 for info in zf.infolist():
191 name = info.filename
192 print name
193 if name.endswith('/'): # dir
194 if not os.path.isdir(name):
195 os.makedirs(name)
196 else: # file
197 directory = os.path.dirname(name)
198 if directory and not os.path.isdir(directory):
199 os.makedirs(directory)
200 out = open(name, 'wb')
201 out.write(zf.read(name))
202 out.close()
203 # Set permissions. Permission info in external_attr is shifted 16 bits.
204 os.chmod(name, info.external_attr >> 16L)
dennis_jeffrey 2012/08/08 23:41:07 did you get this code from somewhere? should we c
fdeng1 2012/08/14 19:11:40 Mentioned it in docstring that it is adapted from
205 os.chdir(pushd)
206
207
208 class CmdServer(object):
209 """Start an http server which serves the Chrome Endure test results.
dennis_jeffrey 2012/08/08 23:41:07 'test results' --> 'graphs'.
fdeng1 2012/08/14 19:11:40 Done.
210
211 Usage:
212 python endure_setup.py server [options]
213 Examples:
214 python endure_setup.py server
215 Start a server which serves the default location
216 <CURRENT_WORKING_DIR>/chrome_graph.
217
218 python endure_setup.py server --graph-dir=/home/user/Document/graph_dir
219 Start a server which serves /home/user/Document/graph_dir which
220 is where your graph code and test results are.
221 """
222 NAME = 'server'
223 DESCRIPTION = 'Start an http server for viewing the' \
224 'tests results from a browser.'
225
226 def _ParseArgs(self, argv):
227 parser = optparse.OptionParser(
228 usage='%%prog %s [options]' % self.NAME,
229 formatter=PlainHelpFormatter(),
230 description=self.__doc__)
231 parser.add_option(
232 '-g', '--graph-dir', type='string',
233 default=os.path.join(os.getcwd(), 'chrome_graph'),
234 help='The directory that contains graph code ' \
235 'and data files of test results. Default value is ' \
236 '<CURRENT_WORKING_DIR>/chrome_graph')
237 return parser.parse_args(argv)
238
239 def Run(self, argv):
240 """Run this command."""
241 options, _ = self._ParseArgs(argv)
242 self._graph_dir = os.path.abspath(options.graph_dir)
243 cur_dir = os.getcwd()
244 os.chdir(self._graph_dir)
245 httpd = BaseHTTPServer.HTTPServer(('', 0),
246 EndureHTTPRequestHandler)
247 try:
248 print 'Serving %s at port %d' % (self._graph_dir, httpd.server_port)
249 print 'View test results at http://localhost:%d' % httpd.server_port
250 print 'Press Ctrl-C to stop the server.'
251 httpd.serve_forever()
252 except KeyboardInterrupt:
253 print 'Shutting down ...'
254 httpd.shutdown()
255 finally:
256 os.chdir(cur_dir)
257 return 0
258
259
260 class EndureHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
261 """A simple HTTP request handler for showing Chrome Endure test results."""
262
263 def send_head(self):
264 """Override send_head so it won't redirect if path is not ended with "/".
265
266 Common code for GET and HEAD commands. This sends the response
267 code and MIME headers.
268
269 Returns:
270 either a file object (which has to be copied
271 to the output file by the caller unless the command was HEAD,
272 and must be closed by the caller under all circumstances), or
273 None, in which case the caller has nothing further to do.
274 """
275 path = self.translate_path(self.path)
276 f = None
277 if os.path.isdir(path):
278 for index in 'index.html', 'index.htm':
279 index = os.path.join(path, index)
280 if os.path.exists(index):
281 path = index
282 break
283 else:
284 return self.list_directory(path)
285 ctype = self.guess_type(path)
286 try:
287 # Always read in binary mode. Opening files in text mode may cause
288 # newline translations, making the actual size of the content
289 # transmitted *less* than the content-length!
290 f = open(path, 'rb')
291 except IOError:
292 self.send_error(404, 'File not found')
293 return None
294 self.send_response(200)
295 self.send_header('Content-type', ctype)
296 fs = os.fstat(f.fileno())
297 self.send_header('Content-Length', str(fs[6]))
298 self.send_header('Last-Modified', self.date_time_string(fs.st_mtime))
299 self.end_headers()
300 return f
301
302
303 class CmdHelp(object):
304 """Print a list of commands or help for a specific command."""
305 NAME = 'help'
306 DESCRIPTION = __doc__
307
308 def __init__(self, cmds):
309 """Initialize help command.
310
311 Args:
312 cmds: Commands for which help information will be printed.
313 """
314 self.cmds = cmds
315
316 def Run(self, args):
317 """Run this command."""
318 if len(args) == 1:
319 return Main(args + ['--help'])
320 #print 'Usage:\n ./endure_setup.py [options] command'
321 print __doc__
322 print 'Commands are:'
323 for cmd in self.cmds:
324 print '\t%s\t\t%s' % (cmd.NAME, cmd.DESCRIPTION)
325
326 return 0
327
328
329 def Main(argv):
dennis_jeffrey 2012/08/08 23:41:07 maybe we should split up this script into 2 separa
fdeng1 2012/08/09 03:26:16 Since we are able to solve the problem brought by
dennis_jeffrey 2012/08/09 17:16:27 I like the feature of having a free port automatic
fdeng1 2012/08/14 19:11:40 That sounds reasonable. I've moved it to a separat
330 if argv and argv[0] == CmdFetch.NAME:
331 command = CmdFetch()
332 elif argv and argv[0] == CmdServer.NAME:
333 command = CmdServer()
334 else:
335 cmds = [CmdFetch, CmdServer, CmdHelp]
dennis_jeffrey 2012/08/08 23:41:07 I think it's easier to use optparse for parsing ar
fdeng1 2012/08/14 19:11:40 Done.
336 command = CmdHelp(cmds)
337 return command.Run(argv[1:])
338
339
340 if '__main__' == __name__:
341 sys.exit(Main(sys.argv[1:]))
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698