4 lit - LLVM Integrated Tester.
6 See lit.pod for more information.
9 import math
, os
, platform
, random
, re
, sys
, time
, threading
, traceback
15 from TestingConfig
import TestingConfig
19 # FIXME: Rename to 'config.lit', 'site.lit', and 'local.lit' ?
20 kConfigName
= 'lit.cfg'
21 kSiteConfigName
= 'lit.site.cfg'
22 kLocalConfigName
= 'lit.local.cfg'
24 class TestingProgressDisplay
:
25 def __init__(self
, opts
, numTests
, progressBar
=None):
27 self
.numTests
= numTests
29 self
.lock
= threading
.Lock()
30 self
.progressBar
= progressBar
33 def update(self
, test
):
34 # Avoid locking overhead in quiet mode
35 if self
.opts
.quiet
and not test
.result
.isFailure
:
42 self
.handleUpdate(test
)
48 self
.progressBar
.clear()
51 elif self
.opts
.succinct
:
52 sys
.stdout
.write('\n')
54 def handleUpdate(self
, test
):
57 self
.progressBar
.update(float(self
.completed
)/self
.numTests
,
60 if self
.opts
.succinct
and not test
.result
.isFailure
:
64 self
.progressBar
.clear()
66 print '%s: %s (%d of %d)' % (test
.result
.name
, test
.getFullName(),
67 self
.completed
, self
.numTests
)
69 if test
.result
.isFailure
and self
.opts
.showOutput
:
70 print "%s TEST '%s' FAILED %s" % ('*'*20, test
.getFullName(),
78 def __init__(self
, tests
, maxTime
):
79 self
.maxTime
= maxTime
80 self
.iter = iter(tests
)
81 self
.lock
= threading
.Lock()
82 self
.startTime
= time
.time()
85 # Check if we have run out of time.
86 if self
.maxTime
is not None:
87 if time
.time() - self
.startTime
> self
.maxTime
:
90 # Otherwise take the next test.
93 item
= self
.iter.next()
99 class Tester(threading
.Thread
):
100 def __init__(self
, litConfig
, provider
, display
):
101 threading
.Thread
.__init
__(self
)
102 self
.litConfig
= litConfig
103 self
.provider
= provider
104 self
.display
= display
108 item
= self
.provider
.get()
113 def runTest(self
, test
):
115 startTime
= time
.time()
117 result
, output
= test
.config
.test_format
.execute(test
,
119 except KeyboardInterrupt:
120 # This is a sad hack. Unfortunately subprocess goes
121 # bonkers with ctrl-c and we start forking merrily.
122 print '\nCtrl-C detected, goodbye.'
125 if self
.litConfig
.debug
:
127 result
= Test
.UNRESOLVED
128 output
= 'Exception during script execution:\n'
129 output
+= traceback
.format_exc()
131 elapsed
= time
.time() - startTime
133 test
.setResult(result
, output
, elapsed
)
134 self
.display
.update(test
)
136 def dirContainsTestSuite(path
):
137 cfgpath
= os
.path
.join(path
, kSiteConfigName
)
138 if os
.path
.exists(cfgpath
):
140 cfgpath
= os
.path
.join(path
, kConfigName
)
141 if os
.path
.exists(cfgpath
):
144 def getTestSuite(item
, litConfig
, cache
):
145 """getTestSuite(item, litConfig, cache) -> (suite, relative_path)
147 Find the test suite containing @arg item.
149 @retval (None, ...) - Indicates no test suite contains @arg item.
150 @retval (suite, relative_path) - The suite that @arg item is in, and its
151 relative path inside that suite.
154 # Check for a site config or a lit config.
155 cfgpath
= dirContainsTestSuite(path
)
157 # If we didn't find a config file, keep looking.
159 parent
,base
= os
.path
.split(path
)
163 ts
, relative
= search(parent
)
164 return (ts
, relative
+ (base
,))
166 # We found a config file, load it.
168 litConfig
.note('loading suite config %r' % cfgpath
)
170 cfg
= TestingConfig
.frompath(cfgpath
, None, litConfig
, mustExist
= True)
171 source_root
= os
.path
.realpath(cfg
.test_source_root
or path
)
172 exec_root
= os
.path
.realpath(cfg
.test_exec_root
or path
)
173 return Test
.TestSuite(cfg
.name
, source_root
, exec_root
, cfg
), ()
176 # Check for an already instantiated test suite.
177 res
= cache
.get(path
)
179 cache
[path
] = res
= search1(path
)
182 # Canonicalize the path.
183 item
= os
.path
.realpath(item
)
185 # Skip files and virtual components.
187 while not os
.path
.isdir(item
):
188 parent
,base
= os
.path
.split(item
)
191 components
.append(base
)
195 ts
, relative
= search(item
)
196 return ts
, tuple(relative
+ tuple(components
))
198 def getLocalConfig(ts
, path_in_suite
, litConfig
, cache
):
199 def search1(path_in_suite
):
200 # Get the parent config.
201 if not path_in_suite
:
204 parent
= search(path_in_suite
[:-1])
206 # Load the local configuration.
207 source_path
= ts
.getSourcePath(path_in_suite
)
208 cfgpath
= os
.path
.join(source_path
, kLocalConfigName
)
210 litConfig
.note('loading local config %r' % cfgpath
)
211 return TestingConfig
.frompath(cfgpath
, parent
, litConfig
,
213 config
= parent
.clone(cfgpath
))
215 def search(path_in_suite
):
216 key
= (ts
, path_in_suite
)
219 cache
[key
] = res
= search1(path_in_suite
)
222 return search(path_in_suite
)
224 def getTests(path
, litConfig
, testSuiteCache
, localConfigCache
):
225 # Find the test suite for this input and its relative path.
226 ts
,path_in_suite
= getTestSuite(path
, litConfig
, testSuiteCache
)
228 litConfig
.warning('unable to find test suite for %r' % path
)
232 litConfig
.note('resolved input %r to %r::%r' % (path
, ts
.name
,
235 return getTestsInSuite(ts
, path_in_suite
, litConfig
,
236 testSuiteCache
, localConfigCache
)
238 def getTestsInSuite(ts
, path_in_suite
, litConfig
,
239 testSuiteCache
, localConfigCache
):
240 # Check that the source path exists (errors here are reported by the
242 source_path
= ts
.getSourcePath(path_in_suite
)
243 if not os
.path
.exists(source_path
):
246 # Check if the user named a test directly.
247 if not os
.path
.isdir(source_path
):
248 lc
= getLocalConfig(ts
, path_in_suite
[:-1], litConfig
, localConfigCache
)
249 yield Test
.Test(ts
, path_in_suite
, lc
)
252 # Otherwise we have a directory to search for tests, start by getting the
253 # local configuration.
254 lc
= getLocalConfig(ts
, path_in_suite
, litConfig
, localConfigCache
)
257 for res
in lc
.test_format
.getTestsInDirectory(ts
, path_in_suite
,
261 # Search subdirectories.
262 for filename
in os
.listdir(source_path
):
263 # FIXME: This doesn't belong here?
264 if filename
== 'Output' or filename
in lc
.excludes
:
267 # Ignore non-directories.
268 file_sourcepath
= os
.path
.join(source_path
, filename
)
269 if not os
.path
.isdir(file_sourcepath
):
272 # Check for nested test suites, first in the execpath in case there is a
273 # site configuration and then in the source path.
274 file_execpath
= ts
.getExecPath(path_in_suite
+ (filename
,))
275 if dirContainsTestSuite(file_execpath
):
276 subiter
= getTests(file_execpath
, litConfig
,
277 testSuiteCache
, localConfigCache
)
278 elif dirContainsTestSuite(file_sourcepath
):
279 subiter
= getTests(file_sourcepath
, litConfig
,
280 testSuiteCache
, localConfigCache
)
282 # Otherwise, continue loading from inside this test suite.
283 subiter
= getTestsInSuite(ts
, path_in_suite
+ (filename
,),
284 litConfig
, testSuiteCache
,
290 def runTests(numThreads
, litConfig
, provider
, display
):
291 # If only using one testing thread, don't use threads at all; this lets us
292 # profile, among other things.
294 t
= Tester(litConfig
, provider
, display
)
298 # Otherwise spin up the testing threads and wait for them to finish.
299 testers
= [Tester(litConfig
, provider
, display
)
300 for i
in range(numThreads
)]
306 except KeyboardInterrupt:
311 from optparse
import OptionParser
, OptionGroup
312 parser
= OptionParser("usage: %prog [options] {file-or-path}")
314 parser
.add_option("-j", "--threads", dest
="numThreads", metavar
="N",
315 help="Number of testing threads",
316 type=int, action
="store", default
=None)
318 group
= OptionGroup(parser
, "Output Format")
319 # FIXME: I find these names very confusing, although I like the
321 group
.add_option("-q", "--quiet", dest
="quiet",
322 help="Suppress no error output",
323 action
="store_true", default
=False)
324 group
.add_option("-s", "--succinct", dest
="succinct",
325 help="Reduce amount of output",
326 action
="store_true", default
=False)
327 group
.add_option("-v", "--verbose", dest
="showOutput",
328 help="Show all test output",
329 action
="store_true", default
=False)
330 group
.add_option("", "--no-progress-bar", dest
="useProgressBar",
331 help="Do not use curses based progress bar",
332 action
="store_false", default
=True)
333 parser
.add_option_group(group
)
335 group
= OptionGroup(parser
, "Test Execution")
336 group
.add_option("", "--path", dest
="path",
337 help="Additional paths to add to testing environment",
338 action
="append", type=str, default
=[])
339 group
.add_option("", "--vg", dest
="useValgrind",
340 help="Run tests under valgrind",
341 action
="store_true", default
=False)
342 group
.add_option("", "--vg-arg", dest
="valgrindArgs", metavar
="ARG",
343 help="Specify an extra argument for valgrind",
344 type=str, action
="append", default
=[])
345 group
.add_option("", "--time-tests", dest
="timeTests",
346 help="Track elapsed wall time for each test",
347 action
="store_true", default
=False)
348 group
.add_option("", "--no-execute", dest
="noExecute",
349 help="Don't execute any tests (assume PASS)",
350 action
="store_true", default
=False)
351 parser
.add_option_group(group
)
353 group
= OptionGroup(parser
, "Test Selection")
354 group
.add_option("", "--max-tests", dest
="maxTests", metavar
="N",
355 help="Maximum number of tests to run",
356 action
="store", type=int, default
=None)
357 group
.add_option("", "--max-time", dest
="maxTime", metavar
="N",
358 help="Maximum time to spend testing (in seconds)",
359 action
="store", type=float, default
=None)
360 group
.add_option("", "--shuffle", dest
="shuffle",
361 help="Run tests in random order",
362 action
="store_true", default
=False)
363 parser
.add_option_group(group
)
365 group
= OptionGroup(parser
, "Debug and Experimental Options")
366 group
.add_option("", "--debug", dest
="debug",
367 help="Enable debugging (for 'lit' development)",
368 action
="store_true", default
=False)
369 group
.add_option("", "--show-suites", dest
="showSuites",
370 help="Show discovered test suites",
371 action
="store_true", default
=False)
372 group
.add_option("", "--no-tcl-as-sh", dest
="useTclAsSh",
373 help="Don't run Tcl scripts using 'sh'",
374 action
="store_false", default
=True)
375 parser
.add_option_group(group
)
377 (opts
, args
) = parser
.parse_args()
380 parser
.error('No inputs specified')
382 if opts
.numThreads
is None:
383 opts
.numThreads
= Util
.detectCPUs()
387 # Create the global config object.
388 litConfig
= LitConfig
.LitConfig(progname
= os
.path
.basename(sys
.argv
[0]),
391 useValgrind
= opts
.useValgrind
,
392 valgrindArgs
= opts
.valgrindArgs
,
393 useTclAsSh
= opts
.useTclAsSh
,
394 noExecute
= opts
.noExecute
,
396 isWindows
= (platform
.system()=='Windows'))
398 # Load the tests from the inputs.
401 localConfigCache
= {}
404 tests
.extend(getTests(input, litConfig
,
405 testSuiteCache
, localConfigCache
))
406 if prev
== len(tests
):
407 litConfig
.warning('input %r contained no tests' % input)
409 # If there were any errors during test discovery, exit now.
410 if litConfig
.numErrors
:
411 print >>sys
.stderr
, '%d errors, exiting.' % litConfig
.numErrors
415 suitesAndTests
= dict([(ts
,[])
416 for ts
,_
in testSuiteCache
.values()])
418 suitesAndTests
[t
.suite
].append(t
)
420 print '-- Test Suites --'
421 suitesAndTests
= suitesAndTests
.items()
422 suitesAndTests
.sort(key
= lambda (ts
,_
): ts
.name
)
423 for ts
,tests
in suitesAndTests
:
424 print ' %s - %d tests' %(ts
.name
, len(tests
))
425 print ' Source Root: %s' % ts
.source_root
426 print ' Exec Root : %s' % ts
.exec_root
428 # Select and order the tests.
429 numTotalTests
= len(tests
)
431 random
.shuffle(tests
)
433 tests
.sort(key
= lambda t
: t
.getFullName())
434 if opts
.maxTests
is not None:
435 tests
= tests
[:opts
.maxTests
]
438 if len(tests
) != numTotalTests
:
439 extra
= ' of %d' % numTotalTests
440 header
= '-- Testing: %d%s tests, %d threads --'%(len(tests
),extra
,
445 if opts
.succinct
and opts
.useProgressBar
:
447 tc
= ProgressBar
.TerminalController()
448 progressBar
= ProgressBar
.ProgressBar(tc
, header
)
451 progressBar
= ProgressBar
.SimpleProgressBar('Testing: ')
455 # Don't create more threads than tests.
456 opts
.numThreads
= min(len(tests
), opts
.numThreads
)
458 startTime
= time
.time()
459 display
= TestingProgressDisplay(opts
, len(tests
), progressBar
)
460 provider
= TestProvider(tests
, opts
.maxTime
)
461 runTests(opts
.numThreads
, litConfig
, provider
, display
)
465 print 'Testing Time: %.2fs'%(time
.time() - startTime
)
467 # Update results for any tests which weren't run.
470 t
.setResult(Test
.UNRESOLVED
, '', 0.0)
472 # List test results organized by kind.
476 if t
.result
not in byCode
:
477 byCode
[t
.result
] = []
478 byCode
[t
.result
].append(t
)
479 if t
.result
.isFailure
:
482 # FIXME: Show unresolved and (optionally) unsupported tests.
483 for title
,code
in (('Unexpected Passing Tests', Test
.XPASS
),
484 ('Failing Tests', Test
.FAIL
)):
485 elts
= byCode
.get(code
)
489 print '%s (%d):' % (title
, len(elts
))
491 print ' %s' % t
.getFullName()
496 byTime
.sort(key
= lambda t
: t
.elapsed
)
498 Util
.printHistogram([(t
.getFullName(), t
.elapsed
) for t
in byTime
],
501 for name
,code
in (('Expected Passes ', Test
.PASS
),
502 ('Expected Failures ', Test
.XFAIL
),
503 ('Unsupported Tests ', Test
.UNSUPPORTED
),
504 ('Unresolved Tests ', Test
.UNRESOLVED
),
505 ('Unexpected Passes ', Test
.XPASS
),
506 ('Unexpected Failures', Test
.FAIL
),):
507 if opts
.quiet
and not code
.isFailure
:
509 N
= len(byCode
.get(code
,[]))
511 print ' %s: %d' % (name
,N
)
513 # If we encountered any additional errors, exit abnormally.
514 if litConfig
.numErrors
:
515 print >>sys
.stderr
, '\n%d error(s), exiting.' % litConfig
.numErrors
518 # Warn about warnings.
519 if litConfig
.numWarnings
:
520 print >>sys
.stderr
, '\n%d warning(s) in tests.' % litConfig
.numWarnings
526 if __name__
=='__main__':
527 # Bump the GIL check interval, its more important to get any one thread to a
528 # blocking operation (hopefully exec) than to try and unblock other threads.
530 sys
.setcheckinterval(1000)