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

Side by Side Diff: ppapi/native_client/tools/browser_tester/browser_tester.py

Issue 10914053: Relocating files in the nacl repo that belong in chrome. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: merge Created 8 years, 3 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/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 glob
7 import optparse
8 import os.path
9 import socket
10 import sys
11 import thread
12 import time
13 import urllib
14
15 # Allow the import of third party modules
16 script_dir = os.path.dirname(os.path.abspath(__file__))
17 sys.path.append(os.path.join(script_dir, '../../../../third_party/'))
18 sys.path.append(os.path.join(script_dir, '../../../../tools/valgrind/'))
19
20 import browsertester.browserlauncher
21 import browsertester.rpclistener
22 import browsertester.server
23
24 import memcheck_analyze
25 import tsan_analyze
26
27 def BuildArgParser():
28 usage = 'usage: %prog [options]'
29 parser = optparse.OptionParser(usage)
30
31 parser.add_option('-p', '--port', dest='port', action='store', type='int',
32 default='0', help='The TCP port the server will bind to. '
33 'The default is to pick an unused port number.')
34 parser.add_option('--browser_path', dest='browser_path', action='store',
35 type='string', default=None,
36 help='Use the browser located here.')
37 parser.add_option('--map_file', dest='map_files', action='append',
38 type='string', nargs=2, default=[],
39 metavar='DEST SRC',
40 help='Add file SRC to be served from the HTTP server, '
41 'to be made visible under the path DEST.')
42 parser.add_option('--serving_dir', dest='serving_dirs', action='append',
43 type='string', default=[],
44 metavar='DIRNAME',
45 help='Add directory DIRNAME to be served from the HTTP '
46 'server to be made visible under the root.')
47 parser.add_option('--test_arg', dest='test_args', action='append',
48 type='string', nargs=2, default=[],
49 metavar='KEY VALUE',
50 help='Parameterize the test with a key/value pair.')
51 parser.add_option('--redirect_url', dest='map_redirects', action='append',
52 type='string', nargs=2, default=[],
53 metavar='DEST SRC',
54 help='Add a redirect to the HTTP server, '
55 'requests for SRC will result in a redirect (302) to DEST.')
56 parser.add_option('--prefer_portable_in_manifest',
57 dest='prefer_portable_in_manifest',
58 action='store_true', default=False,
59 help='Use portable programs in manifest if available.')
60 parser.add_option('-f', '--file', dest='files', action='append',
61 type='string', default=[],
62 metavar='FILENAME',
63 help='Add a file to serve from the HTTP server, to be '
64 'made visible in the root directory. '
65 '"--file path/to/foo.html" is equivalent to '
66 '"--map_file foo.html path/to/foo.html"')
67 parser.add_option('--mime_type', dest='mime_types', action='append',
68 type='string', nargs=2, default=[], metavar='DEST SRC',
69 help='Map file extension SRC to MIME type DEST when '
70 'serving it from the HTTP server.')
71 parser.add_option('-u', '--url', dest='url', action='store',
72 type='string', default=None,
73 help='The webpage to load.')
74 parser.add_option('--ppapi_plugin', dest='ppapi_plugin', action='store',
75 type='string', default=None,
76 help='Use the browser plugin located here.')
77 parser.add_option('--sel_ldr', dest='sel_ldr', action='store',
78 type='string', default=None,
79 help='Use the sel_ldr located here.')
80 parser.add_option('--sel_ldr_bootstrap', dest='sel_ldr_bootstrap',
81 action='store', type='string', default=None,
82 help='Use the bootstrap loader located here.')
83 parser.add_option('--irt_library', dest='irt_library', action='store',
84 type='string', default=None,
85 help='Use the integrated runtime (IRT) library '
86 'located here.')
87 parser.add_option('--interactive', dest='interactive', action='store_true',
88 default=False, help='Do not quit after testing is done. '
89 'Handy for iterative development. Disables timeout.')
90 parser.add_option('--debug', dest='debug', action='store_true', default=False,
91 help='Request debugging output from browser.')
92 parser.add_option('--timeout', dest='timeout', action='store', type='float',
93 default=5.0,
94 help='The maximum amount of time to wait, in seconds, for '
95 'the browser to make a request. The timer resets with each '
96 'request.')
97 parser.add_option('--hard_timeout', dest='hard_timeout', action='store',
98 type='float', default=None,
99 help='The maximum amount of time to wait, in seconds, for '
100 'the entire test. This will kill runaway tests. ')
101 parser.add_option('--allow_404', dest='allow_404', action='store_true',
102 default=False,
103 help='Allow 404s to occur without failing the test.')
104 parser.add_option('-b', '--bandwidth', dest='bandwidth', action='store',
105 type='float', default='0.0',
106 help='The amount of bandwidth (megabits / second) to '
107 'simulate between the client and the server. This used for '
108 'replies with file payloads. All other responses are '
109 'assumed to be short. Bandwidth values <= 0.0 are assumed '
110 'to mean infinite bandwidth.')
111 parser.add_option('--extension', dest='browser_extensions', action='append',
112 type='string', default=[],
113 help='Load the browser extensions located at the list of '
114 'paths. Note: this currently only works with the Chrome '
115 'browser.')
116 parser.add_option('--tool', dest='tool', action='store',
117 type='string', default=None,
118 help='Run tests under a tool.')
119 parser.add_option('--browser_flag', dest='browser_flags', action='append',
120 type='string', default=[],
121 help='Additional flags for the chrome command.')
122 parser.add_option('--enable_ppapi_dev', dest='enable_ppapi_dev',
123 action='store', type='int', default=1,
124 help='Enable/disable PPAPI Dev interfaces while testing.')
125 parser.add_option('--nacl_exe_stdin', dest='nacl_exe_stdin',
126 type='string', default=None,
127 help='Redirect standard input of NaCl executable.')
128 parser.add_option('--nacl_exe_stdout', dest='nacl_exe_stdout',
129 type='string', default=None,
130 help='Redirect standard output of NaCl executable.')
131 parser.add_option('--nacl_exe_stderr', dest='nacl_exe_stderr',
132 type='string', default=None,
133 help='Redirect standard error of NaCl executable.')
134
135 return parser
136
137
138 def ProcessToolLogs(options, logs_dir):
139 if options.tool == 'memcheck':
140 analyzer = memcheck_analyze.MemcheckAnalyzer('', use_gdb=True)
141 logs_wildcard = 'xml.*'
142 elif options.tool == 'tsan':
143 analyzer = tsan_analyze.TsanAnalyzer('', use_gdb=True)
144 logs_wildcard = 'log.*'
145 files = glob.glob(os.path.join(logs_dir, logs_wildcard))
146 retcode = analyzer.Report(files, options.url)
147 return retcode
148
149
150 # An exception that indicates possible flake.
151 class RetryTest(Exception):
152 pass
153
154
155 def DumpNetLog(netlog):
156 sys.stdout.write('\n')
157 if not os.path.isfile(netlog):
158 sys.stdout.write('Cannot find netlog, did Chrome actually launch?\n')
159 else:
160 sys.stdout.write('Netlog exists (%d bytes).\n' % os.path.getsize(netlog))
161 sys.stdout.write('Dumping it to stdout.\n\n\n')
162 sys.stdout.write(open(netlog).read())
163 sys.stdout.write('\n\n\n')
164
165
166 # Try to discover the real IP address of this machine. If we can't figure it
167 # out, fall back to localhost.
168 # A windows bug makes using the loopback interface flaky in rare cases.
169 # http://code.google.com/p/chromium/issues/detail?id=114369
170 def GetHostName():
171 host = 'localhost'
172 try:
173 host = socket.gethostbyname(socket.gethostname())
174 except Exception:
175 pass
176 if host == '0.0.0.0':
177 host = 'localhost'
178 return host
179
180
181 def RunTestsOnce(url, options):
182 # Set the default here so we're assured hard_timeout will be defined.
183 # Tests, such as run_inbrowser_trusted_crash_in_startup_test, may not use the
184 # RunFromCommand line entry point - and otherwise get stuck in an infinite
185 # loop when something goes wrong and the hard timeout is not set.
186 # http://code.google.com/p/chromium/issues/detail?id=105406
187 if options.hard_timeout is None:
188 options.hard_timeout = options.timeout * 4
189
190 options.files.append(os.path.join(script_dir, 'browserdata', 'nacltest.js'))
191
192 # Create server
193 host = GetHostName()
194 try:
195 server = browsertester.server.Create(host, options.port)
196 except Exception:
197 sys.stdout.write('Could not bind %r, falling back to localhost.\n' % host)
198 server = browsertester.server.Create('localhost', options.port)
199
200 # If port 0 has been requested, an arbitrary port will be bound so we need to
201 # query it. Older version of Python do not set server_address correctly when
202 # The requested port is 0 so we need to break encapsulation and query the
203 # socket directly.
204 host, port = server.socket.getsockname()
205
206 file_mapping = dict(options.map_files)
207 for filename in options.files:
208 file_mapping[os.path.basename(filename)] = filename
209 for server_path, real_path in file_mapping.iteritems():
210 if not os.path.exists(real_path):
211 raise AssertionError('\'%s\' does not exist.' % real_path)
212 mime_types = {}
213 for ext, mime_type in options.mime_types:
214 mime_types['.' + ext] = mime_type
215
216 def ShutdownCallback():
217 server.TestingEnded()
218 close_browser = options.tool is not None and not options.interactive
219 return close_browser
220
221 listener = browsertester.rpclistener.RPCListener(ShutdownCallback)
222 server.Configure(file_mapping,
223 dict(options.map_redirects),
224 mime_types,
225 options.allow_404,
226 options.bandwidth,
227 listener,
228 options.serving_dirs)
229
230 browser = browsertester.browserlauncher.ChromeLauncher(options)
231
232 full_url = 'http://%s:%d/%s' % (host, port, url)
233 if len(options.test_args) > 0:
234 full_url += '?' + urllib.urlencode(options.test_args)
235 browser.Run(full_url, port)
236 server.TestingBegun(0.125)
237
238 # In Python 2.5, server.handle_request may block indefinitely. Serving pages
239 # is done in its own thread so the main thread can time out as needed.
240 def Serve():
241 while server.test_in_progress or options.interactive:
242 server.handle_request()
243 thread.start_new_thread(Serve, ())
244
245 tool_failed = False
246 time_started = time.time()
247
248 def HardTimeout(total_time):
249 return total_time >= 0.0 and time.time() - time_started >= total_time
250
251 try:
252 while server.test_in_progress or options.interactive:
253 if not browser.IsRunning():
254 listener.ServerError('Browser process ended during test '
255 '(return code %r)' % browser.GetReturnCode())
256 # If Chrome exits prematurely without making a single request to the
257 # web server, this is probally a Chrome crash-on-launch bug not related
258 # to the test at hand. Retry, unless we're in interactive mode. In
259 # interactive mode the user may manually close the browser, so don't
260 # retry (it would just be annoying.)
261 if not server.received_request and not options.interactive:
262 raise RetryTest('Chrome failed to launch.')
263 else:
264 break
265 elif not options.interactive and server.TimedOut(options.timeout):
266 js_time = server.TimeSinceJSHeartbeat()
267 err = 'Did not hear from the test for %.1f seconds.' % options.timeout
268 err += '\nHeard from Javascript %.1f seconds ago.' % js_time
269 if js_time > 2.0:
270 err += '\nThe renderer probably hung or crashed.'
271 else:
272 err += '\nThe test probably did not get a callback that it expected.'
273 listener.ServerError(err)
274 break
275 elif not options.interactive and HardTimeout(options.hard_timeout):
276 listener.ServerError('The test took over %.1f seconds. This is '
277 'probably a runaway test.' % options.hard_timeout)
278 break
279 else:
280 # If Python 2.5 support is dropped, stick server.handle_request() here.
281 time.sleep(0.125)
282
283 if options.tool:
284 sys.stdout.write('##################### Waiting for the tool to exit\n')
285 browser.WaitForProcessDeath()
286 sys.stdout.write('##################### Processing tool logs\n')
287 tool_failed = ProcessToolLogs(options, browser.tool_log_dir)
288
289 finally:
290 try:
291 if listener.ever_failed and not options.interactive:
292 if not server.received_request:
293 sys.stdout.write('\nNo URLs were served by the test runner. It is '
294 'unlikely this test failure has anything to do with '
295 'this particular test.\n')
296 DumpNetLog(browser.NetLogName())
297 except Exception:
298 listener.ever_failed = 1
299 browser.Cleanup()
300 server.server_close()
301
302 if tool_failed:
303 return 2
304 elif listener.ever_failed:
305 return 1
306 else:
307 return 0
308
309
310 # This is an entrypoint for tests that treat the browser tester as a Python
311 # library rather than an opaque script.
312 # (e.g. run_inbrowser_trusted_crash_in_startup_test)
313 def Run(url, options):
314 result = 1
315 attempt = 1
316 while True:
317 try:
318 result = RunTestsOnce(url, options)
319 break
320 except RetryTest:
321 # Only retry once.
322 if attempt < 2:
323 sys.stdout.write('\n@@@STEP_WARNINGS@@@\n')
324 sys.stdout.write('WARNING: suspected flake, retrying test!\n\n')
325 attempt += 1
326 continue
327 else:
328 sys.stdout.write('\nWARNING: failed too many times, not retrying.\n\n')
329 result = 1
330 break
331 return result
332
333
334 def RunFromCommandLine():
335 parser = BuildArgParser()
336 options, args = parser.parse_args()
337
338 if len(args) != 0:
339 print args
340 parser.error('Invalid arguments')
341
342 # Validate the URL
343 url = options.url
344 if url is None:
345 parser.error('Must specify a URL')
346
347 return Run(url, options)
348
349
350 if __name__ == '__main__':
351 sys.exit(RunFromCommandLine())
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698