--- a/tests/run-tests.py Thu Nov 08 18:35:43 2012 +0000
+++ b/tests/run-tests.py Wed Nov 14 13:25:00 2012 +0000
@@ -55,6 +55,7 @@
import re
import threading
import killdaemons as killmod
+import cPickle as pickle
processlock = threading.Lock()
@@ -175,6 +176,8 @@
parser.add_option("-t", "--timeout", type="int",
help="kill errant tests after TIMEOUT seconds"
" (default: $%s or %d)" % defaults['timeout'])
+ parser.add_option("--time", action="store_true",
+ help="time how long each test takes")
parser.add_option("--tmpdir", type="string",
help="run tests in the given temporary directory"
" (implies --keep-tmpdir)")
@@ -263,6 +266,10 @@
sys.stderr.write(
'warning: --timeout option ignored with --debug\n')
options.timeout = 0
+ if options.time:
+ sys.stderr.write(
+ 'warning: --time option ignored with --debug\n')
+ options.time = False
if options.py3k_warnings:
if sys.version_info[:2] < (2, 6) or sys.version_info[:2] >= (3, 0):
parser.error('--py3k-warnings can only be used on Python 2.6+')
@@ -447,6 +454,14 @@
fn = os.path.join(INST, '..', '.coverage')
os.environ['COVERAGE_FILE'] = fn
+def outputtimes(options):
+ vlog('# Producing time report')
+ times.sort(key=lambda t: (t[1], t[0]), reverse=True)
+ cols = '%7.3f %s'
+ print '\n%-7s %s' % ('Time', 'Test')
+ for test, timetaken in times:
+ print cols % (timetaken, test)
+
def outputcoverage(options):
vlog('# Producing coverage report')
@@ -753,18 +768,13 @@
True -> passed
False -> failed'''
- global results, resultslock, iolock
+ global results, iolock
testpath = os.path.join(TESTDIR, test)
- def result(l, e):
- resultslock.acquire()
- results[l].append(e)
- resultslock.release()
-
def skip(msg):
if not options.verbose:
- result('s', (test, msg))
+ results['s'].append((test, msg))
else:
iolock.acquire()
print "\nSkipping %s: %s" % (testpath, msg)
@@ -787,15 +797,15 @@
rename(testpath + ".err", testpath)
else:
rename(testpath + ".err", testpath + ".out")
- result('p', test)
+ success(test)
return
- result('f', (test, msg))
+ results['f'].append((test, msg))
def success():
- result('p', test)
+ results['p'].append(test)
def ignore(msg):
- result('i', (test, msg))
+ results['i'].append((test, msg))
if (os.path.basename(test).startswith("test-") and '~' not in test and
('.' not in test or test.endswith('.py') or
@@ -891,7 +901,12 @@
replacements.append((re.escape(testtmp), '$TESTTMP'))
os.mkdir(testtmp)
+ if options.time:
+ starttime = time.time()
ret, out = runner(testpath, testtmp, options, replacements)
+ if options.time:
+ endtime = time.time()
+ times.append((test, endtime - starttime))
vlog("# Ret was:", ret)
mark = '.'
@@ -1056,29 +1071,30 @@
childopts += ['--tmpdir', childtmp]
cmdline = [PYTHON, sys.argv[0]] + opts + childopts + job
vlog(' '.join(cmdline))
- fps[os.spawnvp(os.P_NOWAIT, cmdline[0], cmdline)] = os.fdopen(rfd, 'r')
+ fps[os.spawnvp(os.P_NOWAIT, cmdline[0], cmdline)] = os.fdopen(rfd, 'rb')
os.close(wfd)
signal.signal(signal.SIGINT, signal.SIG_IGN)
failures = 0
- tested, skipped, failed = 0, 0, 0
+ passed, skipped, failed = 0, 0, 0
skips = []
fails = []
while fps:
pid, status = os.wait()
fp = fps.pop(pid)
- l = fp.read().splitlines()
try:
- test, skip, fail = map(int, l[:3])
- except ValueError:
- test, skip, fail = 0, 0, 0
- split = -fail or len(l)
- for s in l[3:split]:
- skips.append(s.split(" ", 1))
- for s in l[split:]:
- fails.append(s.split(" ", 1))
- tested += test
- skipped += skip
- failed += fail
+ childresults = pickle.load(fp)
+ except pickle.UnpicklingError:
+ pass
+ else:
+ passed += len(childresults['p'])
+ skipped += len(childresults['s'])
+ failed += len(childresults['f'])
+ skips.extend(childresults['s'])
+ fails.extend(childresults['f'])
+ if options.time:
+ childtimes = pickle.load(fp)
+ times.extend(childtimes)
+
vlog('pid %d exited, status %d' % (pid, status))
failures |= status
print
@@ -1093,17 +1109,19 @@
_checkhglib("Tested")
print "# Ran %d tests, %d skipped, %d failed." % (
- tested, skipped, failed)
+ passed + failed, skipped, failed)
+ if options.time:
+ outputtimes(options)
if options.anycoverage:
outputcoverage(options)
sys.exit(failures != 0)
results = dict(p=[], f=[], s=[], i=[])
-resultslock = threading.Lock()
+times = []
iolock = threading.Lock()
-def runqueue(options, tests, results):
+def runqueue(options, tests):
for test in tests:
ret = runone(options, test)
if options.first and ret is not None and not ret:
@@ -1129,7 +1147,7 @@
print "running all tests"
tests = orig
- runqueue(options, tests, results)
+ runqueue(options, tests)
failed = len(results['f'])
tested = len(results['p']) + failed
@@ -1137,12 +1155,10 @@
ignored = len(results['i'])
if options.child:
- fp = os.fdopen(options.child, 'w')
- fp.write('%d\n%d\n%d\n' % (tested, skipped, failed))
- for s in results['s']:
- fp.write("%s %s\n" % s)
- for s in results['f']:
- fp.write("%s %s\n" % s)
+ fp = os.fdopen(options.child, 'wb')
+ pickle.dump(results, fp, pickle.HIGHEST_PROTOCOL)
+ if options.time:
+ pickle.dump(times, fp, pickle.HIGHEST_PROTOCOL)
fp.close()
else:
print
@@ -1153,6 +1169,8 @@
_checkhglib("Tested")
print "# Ran %d tests, %d skipped, %d failed." % (
tested, skipped + ignored, failed)
+ if options.time:
+ outputtimes(options)
if options.anycoverage:
outputcoverage(options)