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

Side by Side Diff: tools/test.py

Issue 11000052: tools/test.py: Add support for JUnit compatible XML output (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 8 years, 2 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 | tools/test-wrapper-gypbuild.py » ('j') | tools/unittest_output.py » ('J')
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 # 2 #
3 # Copyright 2012 the V8 project authors. All rights reserved. 3 # Copyright 2012 the V8 project authors. All rights reserved.
4 # Redistribution and use in source and binary forms, with or without 4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions are 5 # modification, are permitted provided that the following conditions are
6 # met: 6 # met:
7 # 7 #
8 # * Redistributions of source code must retain the above copyright 8 # * Redistributions of source code must retain the above copyright
9 # notice, this list of conditions and the following disclaimer. 9 # notice, this list of conditions and the following disclaimer.
10 # * Redistributions in binary form must reproduce the above 10 # * Redistributions in binary form must reproduce the above
(...skipping 25 matching lines...) Expand all
36 import re 36 import re
37 import signal 37 import signal
38 import subprocess 38 import subprocess
39 import sys 39 import sys
40 import tempfile 40 import tempfile
41 import time 41 import time
42 import threading 42 import threading
43 import utils 43 import utils
44 from Queue import Queue, Empty 44 from Queue import Queue, Empty
45 45
46 from unittest_output import UnitTestOutput
46 47
47 VERBOSE = False 48 VERBOSE = False
49 XMLOUT = None
Jakob Kummerow 2012/09/28 17:38:52 No global variables. Please.
50 XMLTESTSUITE = None
48 51
49 52
50 # --------------------------------------------- 53 # ---------------------------------------------
51 # --- P r o g r e s s I n d i c a t o r s --- 54 # --- P r o g r e s s I n d i c a t o r s ---
52 # --------------------------------------------- 55 # ---------------------------------------------
53 56
54 57
55 class ProgressIndicator(object): 58 class ProgressIndicator(object):
56 59
57 def __init__(self, cases): 60 def __init__(self, cases):
58 self.cases = cases 61 self.cases = cases
59 self.queue = Queue(len(cases)) 62 self.queue = Queue(len(cases))
60 for case in cases: 63 for case in cases:
61 self.queue.put_nowait(case) 64 self.queue.put_nowait(case)
62 self.succeeded = 0 65 self.succeeded = 0
63 self.remaining = len(cases) 66 self.remaining = len(cases)
64 self.total = len(cases) 67 self.total = len(cases)
65 self.failed = [ ] 68 self.failed = [ ]
66 self.crashed = 0 69 self.crashed = 0
67 self.terminate = False 70 self.terminate = False
68 self.lock = threading.Lock() 71 self.lock = threading.Lock()
72 if XMLOUT:
Jakob Kummerow 2012/09/28 17:38:52 This looks weird. The UnitTestProgressIndicator is
73 self.xmlOutputter = UnitTestProgressIndicator()
69 74
70 def PrintFailureHeader(self, test): 75 def PrintFailureHeader(self, test):
71 if test.IsNegative(): 76 if test.IsNegative():
72 negative_marker = '[negative] ' 77 negative_marker = '[negative] '
73 else: 78 else:
74 negative_marker = '' 79 negative_marker = ''
75 print "=== %(label)s %(negative)s===" % { 80 print "=== %(label)s %(negative)s===" % {
76 'label': test.GetLabel(), 81 'label': test.GetLabel(),
77 'negative': negative_marker 82 'negative': negative_marker
78 } 83 }
79 print "Path: %s" % "/".join(test.path) 84 print "Path: %s" % "/".join(test.path)
80 85
81 def Run(self, tasks): 86 def Run(self, tasks):
82 self.Starting() 87 self.Starting()
88 if XMLOUT:
89 self.xmlOutputter.Starting()
83 threads = [] 90 threads = []
84 # Spawn N-1 threads and then use this thread as the last one. 91 # Spawn N-1 threads and then use this thread as the last one.
85 # That way -j1 avoids threading altogether which is a nice fallback 92 # That way -j1 avoids threading altogether which is a nice fallback
86 # in case of threading problems. 93 # in case of threading problems.
87 for i in xrange(tasks - 1): 94 for i in xrange(tasks - 1):
88 thread = threading.Thread(target=self.RunSingle, args=[]) 95 thread = threading.Thread(target=self.RunSingle, args=[])
89 threads.append(thread) 96 threads.append(thread)
90 thread.start() 97 thread.start()
91 try: 98 try:
92 self.RunSingle() 99 self.RunSingle()
93 # Wait for the remaining threads 100 # Wait for the remaining threads
94 for thread in threads: 101 for thread in threads:
95 # Use a timeout so that signals (ctrl-c) will be processed. 102 # Use a timeout so that signals (ctrl-c) will be processed.
96 thread.join(timeout=10000000) 103 thread.join(timeout=10000000)
97 except Exception, e: 104 except Exception, e:
98 # If there's an exception we schedule an interruption for any 105 # If there's an exception we schedule an interruption for any
99 # remaining threads. 106 # remaining threads.
100 self.terminate = True 107 self.terminate = True
101 # ...and then reraise the exception to bail out 108 # ...and then reraise the exception to bail out
102 raise 109 raise
103 self.Done() 110 self.Done()
111 if XMLOUT:
112 self.xmlOutputter.Done()
104 return not self.failed 113 return not self.failed
105 114
106 def RunSingle(self): 115 def RunSingle(self):
107 while not self.terminate: 116 while not self.terminate:
108 try: 117 try:
109 test = self.queue.get_nowait() 118 test = self.queue.get_nowait()
110 except Empty: 119 except Empty:
111 return 120 return
112 case = test.case 121 case = test.case
113 self.lock.acquire() 122 self.lock.acquire()
114 self.AboutToRun(case) 123 self.AboutToRun(case)
124 if XMLOUT:
125 self.xmlOutputter.AboutToRun(case)
115 self.lock.release() 126 self.lock.release()
116 try: 127 try:
117 start = time.time() 128 start = time.time()
118 output = case.Run() 129 output = case.Run()
119 case.duration = (time.time() - start) 130 case.duration = (time.time() - start)
120 except BreakNowException: 131 except BreakNowException:
121 self.terminate = True 132 self.terminate = True
122 except IOError, e: 133 except IOError, e:
123 assert self.terminate 134 assert self.terminate
124 return 135 return
125 if self.terminate: 136 if self.terminate:
126 return 137 return
127 self.lock.acquire() 138 self.lock.acquire()
128 if output.UnexpectedOutput(): 139 if output.UnexpectedOutput():
129 self.failed.append(output) 140 self.failed.append(output)
130 if output.HasCrashed(): 141 if output.HasCrashed():
131 self.crashed += 1 142 self.crashed += 1
132 else: 143 else:
133 self.succeeded += 1 144 self.succeeded += 1
134 self.remaining -= 1 145 self.remaining -= 1
135 self.HasRun(output) 146 self.HasRun(output)
147 if XMLOUT:
148 self.xmlOutputter.HasRun(output)
136 self.lock.release() 149 self.lock.release()
137 150
138 151
139 def EscapeCommand(command): 152 def EscapeCommand(command):
140 parts = [] 153 parts = []
141 for part in command: 154 for part in command:
142 if ' ' in part: 155 if ' ' in part:
143 # Escape spaces and double quotes. We may need to escape more characters 156 # Escape spaces and double quotes. We may need to escape more characters
144 # for this to work properly. 157 # for this to work properly.
145 parts.append('"%s"' % part.replace('"', '\\"')) 158 parts.append('"%s"' % part.replace('"', '\\"'))
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after
297 def __init__(self, cases): 310 def __init__(self, cases):
298 templates = { 311 templates = {
299 'status_line': "[%(mins)02i:%(secs)02i|%%%(remaining) 4d|+%(passed) 4d|-%( failed) 4d]: %(test)s", 312 'status_line': "[%(mins)02i:%(secs)02i|%%%(remaining) 4d|+%(passed) 4d|-%( failed) 4d]: %(test)s",
300 'stdout': '%s', 313 'stdout': '%s',
301 'stderr': '%s', 314 'stderr': '%s',
302 } 315 }
303 super(MonochromeProgressIndicator, self).__init__(cases, templates) 316 super(MonochromeProgressIndicator, self).__init__(cases, templates)
304 317
305 def ClearLine(self, last_line_length): 318 def ClearLine(self, last_line_length):
306 print ("\r" + (" " * last_line_length) + "\r"), 319 print ("\r" + (" " * last_line_length) + "\r"),
307 320
Jakob Kummerow 2012/09/28 17:38:52 nit: two newlines between top-level definitions
321 class UnitTestProgressIndicator(ProgressIndicator):
322
323 def __init__(self):
324 self.outputter = UnitTestOutput(XMLTESTSUITE)
325 if XMLOUT:
326 self.outfile = open(XMLOUT, "w")
327 else:
328 self.outfile = sys.stdout
329
330 def Starting(self):
331 pass
332
333 def AboutToRun(self, case):
334 self.outputter.startNewTest(case.GetName())
335
336 def Done(self):
337 self.outputter.finishAndWrite(self.outfile)
338 if self.outfile != sys.stdout:
339 self.outfile.close()
340
341 def HasRun(self, output):
342 if output.UnexpectedOutput():
343 failtext = ""
344 stdout = output.output.stdout.strip()
345 if len(stdout):
346 failtext += "stdout:\n"
347 failtext += stdout
348 failtext += "\n"
349 stderr = output.output.stderr.strip()
350 if len(stderr):
351 failtext += "stderr:\n"
352 failtext += stderr
353 failtext += "\n"
354 if output.HasCrashed():
355 failtext += "--- CRASHED ---"
356 if output.HasTimedOut():
357 failtext += "--- TIMEOUT ---"
358 self.outputter.finishCurrentTest(output.command, True, failtext)
359 else:
360 self.outputter.finishCurrentTest(output.command, False)
361
308 362
309 PROGRESS_INDICATORS = { 363 PROGRESS_INDICATORS = {
310 'verbose': VerboseProgressIndicator, 364 'verbose': VerboseProgressIndicator,
311 'dots': DotsProgressIndicator, 365 'dots': DotsProgressIndicator,
312 'color': ColorProgressIndicator, 366 'color': ColorProgressIndicator,
313 'mono': MonochromeProgressIndicator 367 'mono': MonochromeProgressIndicator
314 } 368 }
315 369
316 370
317 # ------------------------- 371 # -------------------------
(...skipping 913 matching lines...) Expand 10 before | Expand all | Expand 10 after
1231 dest="suppress_dialogs", action="store_false") 1285 dest="suppress_dialogs", action="store_false")
1232 result.add_option("--mips-arch-variant", help="mips architecture variant: mips 32r1/mips32r2", default="mips32r2"); 1286 result.add_option("--mips-arch-variant", help="mips architecture variant: mips 32r1/mips32r2", default="mips32r2");
1233 result.add_option("--shell", help="Path to V8 shell", default="d8") 1287 result.add_option("--shell", help="Path to V8 shell", default="d8")
1234 result.add_option("--isolates", help="Whether to test isolates", default=False , action="store_true") 1288 result.add_option("--isolates", help="Whether to test isolates", default=False , action="store_true")
1235 result.add_option("--store-unexpected-output", 1289 result.add_option("--store-unexpected-output",
1236 help="Store the temporary JS files from tests that fails", 1290 help="Store the temporary JS files from tests that fails",
1237 dest="store_unexpected_output", default=True, action="store_true") 1291 dest="store_unexpected_output", default=True, action="store_true")
1238 result.add_option("--no-store-unexpected-output", 1292 result.add_option("--no-store-unexpected-output",
1239 help="Deletes the temporary JS files from tests that fails", 1293 help="Deletes the temporary JS files from tests that fails",
1240 dest="store_unexpected_output", action="store_false") 1294 dest="store_unexpected_output", action="store_false")
1295 result.add_option("--xmlout", help="File name of the UnitTest output")
1296 result.add_option("--xmltestsuite", help="Name of the testsuite in the UnitTes t XML output", default="v8tests")
1241 result.add_option("--stress-only", 1297 result.add_option("--stress-only",
1242 help="Only run tests with --always-opt --stress-opt", 1298 help="Only run tests with --always-opt --stress-opt",
1243 default=False, action="store_true") 1299 default=False, action="store_true")
1244 result.add_option("--nostress", 1300 result.add_option("--nostress",
1245 help="Don't run crankshaft --always-opt --stress-op test", 1301 help="Don't run crankshaft --always-opt --stress-op test",
1246 default=False, action="store_true") 1302 default=False, action="store_true")
1247 result.add_option("--shard-count", 1303 result.add_option("--shard-count",
1248 help="Split testsuites into this number of shards", 1304 help="Split testsuites into this number of shards",
1249 default=1, type="int") 1305 default=1, type="int")
1250 result.add_option("--shard-run", 1306 result.add_option("--shard-run",
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
1284 if options.arch in ['android', 'arm', 'mipsel']: 1340 if options.arch in ['android', 'arm', 'mipsel']:
1285 options.timeout = 2 * TIMEOUT_DEFAULT; 1341 options.timeout = 2 * TIMEOUT_DEFAULT;
1286 else: 1342 else:
1287 options.timeout = TIMEOUT_DEFAULT; 1343 options.timeout = TIMEOUT_DEFAULT;
1288 if options.snapshot: 1344 if options.snapshot:
1289 options.scons_flags.append("snapshot=on") 1345 options.scons_flags.append("snapshot=on")
1290 global VARIANT_FLAGS 1346 global VARIANT_FLAGS
1291 if options.mips_arch_variant: 1347 if options.mips_arch_variant:
1292 options.scons_flags.append("mips_arch_variant=" + options.mips_arch_variant) 1348 options.scons_flags.append("mips_arch_variant=" + options.mips_arch_variant)
1293 1349
1350 global XMLOUT
1351 XMLOUT = options.xmlout
1352 global XMLTESTSUITE
1353 XMLTESTSUITE = options.xmltestsuite
1354
1294 if options.stress_only: 1355 if options.stress_only:
1295 VARIANT_FLAGS = [['--stress-opt', '--always-opt']] 1356 VARIANT_FLAGS = [['--stress-opt', '--always-opt']]
1296 if options.nostress: 1357 if options.nostress:
1297 VARIANT_FLAGS = [[],['--nocrankshaft']] 1358 VARIANT_FLAGS = [[],['--nocrankshaft']]
1298 if options.shell.endswith("d8"): 1359 if options.shell.endswith("d8"):
1299 if options.special_command: 1360 if options.special_command:
1300 options.special_command += " --test" 1361 options.special_command += " --test"
1301 else: 1362 else:
1302 options.special_command = "@ --test" 1363 options.special_command = "@ --test"
1303 if options.noprof: 1364 if options.noprof:
(...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after
1545 index = 1 1606 index = 1
1546 for entry in timed_tests[:20]: 1607 for entry in timed_tests[:20]:
1547 t = FormatTime(entry.duration) 1608 t = FormatTime(entry.duration)
1548 sys.stderr.write("%4i (%s) %s\n" % (index, t, entry.GetLabel())) 1609 sys.stderr.write("%4i (%s) %s\n" % (index, t, entry.GetLabel()))
1549 index += 1 1610 index += 1
1550 1611
1551 return result 1612 return result
1552 1613
1553 1614
1554 if __name__ == '__main__': 1615 if __name__ == '__main__':
1555 sys.exit(Main()) 1616 if XMLOUT:
1617 Main()
1618 sys.exit(0)
1619 else:
1620 sys.exit(Main())
OLDNEW
« no previous file with comments | « no previous file | tools/test-wrapper-gypbuild.py » ('j') | tools/unittest_output.py » ('J')

Powered by Google App Engine
This is Rietveld 408576698