comparison tests/run-tests.py @ 10648:58128004cca1 stable

tests: use external coverage, mandate newer version This removes the option for including the stdlib in coverage reports.
author Dirkjan Ochtman <djc.ochtman@kentyde.com>
date Thu, 11 Mar 2010 15:32:24 +0100
parents e433002acb05
children 92ff2d0b751a 4eb6311d217a
comparison
equal deleted inserted replaced
10646:86dc21148bdb 10648:58128004cca1
39 # (You could use any subset of the tests: test-s* happens to match 39 # (You could use any subset of the tests: test-s* happens to match
40 # enough that it's worth doing parallel runs, few enough that it 40 # enough that it's worth doing parallel runs, few enough that it
41 # completes fairly quickly, includes both shell and Python scripts, and 41 # completes fairly quickly, includes both shell and Python scripts, and
42 # includes some scripts that run daemon processes.) 42 # includes some scripts that run daemon processes.)
43 43
44 from distutils import version
44 import difflib 45 import difflib
45 import errno 46 import errno
46 import optparse 47 import optparse
47 import os 48 import os
48 import signal 49 import signal
108 parser.add_option("-p", "--port", type="int", 109 parser.add_option("-p", "--port", type="int",
109 help="port on which servers should listen" 110 help="port on which servers should listen"
110 " (default: $%s or %d)" % defaults['port']) 111 " (default: $%s or %d)" % defaults['port'])
111 parser.add_option("-r", "--retest", action="store_true", 112 parser.add_option("-r", "--retest", action="store_true",
112 help="retest failed tests") 113 help="retest failed tests")
113 parser.add_option("-s", "--cover_stdlib", action="store_true",
114 help="print a test coverage report inc. standard libraries")
115 parser.add_option("-S", "--noskips", action="store_true", 114 parser.add_option("-S", "--noskips", action="store_true",
116 help="don't report skip tests verbosely") 115 help="don't report skip tests verbosely")
117 parser.add_option("-t", "--timeout", type="int", 116 parser.add_option("-t", "--timeout", type="int",
118 help="kill errant tests after TIMEOUT seconds" 117 help="kill errant tests after TIMEOUT seconds"
119 " (default: $%s or %d)" % defaults['timeout']) 118 " (default: $%s or %d)" % defaults['timeout'])
153 if not os.access(hgbin, os.X_OK): 152 if not os.access(hgbin, os.X_OK):
154 parser.error('--local specified, but %r not found or not executable' 153 parser.error('--local specified, but %r not found or not executable'
155 % hgbin) 154 % hgbin)
156 options.with_hg = hgbin 155 options.with_hg = hgbin
157 156
158 options.anycoverage = (options.cover or 157 options.anycoverage = options.cover or options.annotate
159 options.cover_stdlib or 158 if options.anycoverage:
160 options.annotate) 159 try:
161 160 import coverage
162 if options.anycoverage and options.with_hg: 161 covver = version.StrictVersion(coverage.__version__).version
163 # I'm not sure if this is a fundamental limitation or just a 162 if covver < (3, 3):
164 # bug. But I don't want to waste people's time and energy doing 163 parser.error('coverage options require coverage 3.3 or later')
165 # test runs that don't give the results they want. 164 except ImportError:
166 parser.error("sorry, coverage options do not work when --with-hg " 165 parser.error('coverage options now require the coverage package')
167 "or --local specified") 166
167 if options.anycoverage and options.local:
168 # this needs some path mangling somewhere, I guess
169 parser.error("sorry, coverage options do not work when --local "
170 "is specified")
168 171
169 global vlog 172 global vlog
170 if options.verbose: 173 if options.verbose:
171 if options.jobs > 1 or options.child is not None: 174 if options.jobs > 1 or options.child is not None:
172 pid = "[%d]" % os.getpid() 175 pid = "[%d]" % os.getpid()
388 for line in lines: 391 for line in lines:
389 f.write(line + '\n') 392 f.write(line + '\n')
390 f.close() 393 f.close()
391 394
392 if options.anycoverage: 395 if options.anycoverage:
393 vlog("# Installing coverage wrapper") 396 custom = os.path.join(TESTDIR, 'sitecustomize.py')
394 os.environ['COVERAGE_FILE'] = COVERAGE_FILE 397 target = os.path.join(PYTHONDIR, 'sitecustomize.py')
395 if os.path.exists(COVERAGE_FILE): 398 vlog('# Installing coverage trigger to %s' % target)
396 os.unlink(COVERAGE_FILE) 399 shutil.copyfile(custom, target)
397 # Create a wrapper script to invoke hg via coverage.py 400 rc = os.path.join(TESTDIR, '.coveragerc')
398 os.rename(os.path.join(BINDIR, "hg"), os.path.join(BINDIR, "_hg.py")) 401 vlog('# Installing coverage rc to %s' % rc)
399 f = open(os.path.join(BINDIR, 'hg'), 'w') 402 os.environ['COVERAGE_PROCESS_START'] = rc
400 f.write('#!' + sys.executable + '\n') 403 fn = os.path.join(INST, '..', '.coverage')
401 f.write('import sys, os; os.execv(sys.executable, [sys.executable, ' 404 os.environ['COVERAGE_FILE'] = fn
402 '"%s", "-x", "-p", "%s"] + sys.argv[1:])\n' %
403 (os.path.join(TESTDIR, 'coverage.py'),
404 os.path.join(BINDIR, '_hg.py')))
405 f.close()
406 os.chmod(os.path.join(BINDIR, 'hg'), 0700)
407 405
408 def outputcoverage(options): 406 def outputcoverage(options):
409 407
410 vlog('# Producing coverage report') 408 vlog('# Producing coverage report')
411 os.chdir(PYTHONDIR) 409 os.chdir(PYTHONDIR)
412 410
413 def covrun(*args): 411 def covrun(*args):
414 start = sys.executable, os.path.join(TESTDIR, 'coverage.py') 412 cmd = 'coverage %s' % ' '.join(args)
415 cmd = '"%s" "%s" %s' % (start[0], start[1], ' '.join(args))
416 vlog('# Running: %s' % cmd) 413 vlog('# Running: %s' % cmd)
417 os.system(cmd) 414 os.system(cmd)
418 415
419 omit = [BINDIR, TESTDIR, PYTHONDIR] 416 if options.child:
420 if not options.cover_stdlib: 417 return
421 # Exclude as system paths (ignoring empty strings seen on win) 418
422 omit += [x for x in sys.path if x != ''] 419 covrun('-c')
423 omit = ','.join(omit) 420 omit = ','.join([BINDIR, TESTDIR])
424
425 covrun('-c') # combine from parallel processes
426 for fn in os.listdir(TESTDIR):
427 if fn.startswith('.coverage.'):
428 os.unlink(os.path.join(TESTDIR, fn))
429
430 covrun('-i', '-r', '"--omit=%s"' % omit) # report 421 covrun('-i', '-r', '"--omit=%s"' % omit) # report
431 if options.annotate: 422 if options.annotate:
432 adir = os.path.join(TESTDIR, 'annotated') 423 adir = os.path.join(TESTDIR, 'annotated')
433 if not os.path.isdir(adir): 424 if not os.path.isdir(adir):
434 os.mkdir(adir) 425 os.mkdir(adir)
666 657
667 optcopy = dict(options.__dict__) 658 optcopy = dict(options.__dict__)
668 optcopy['jobs'] = 1 659 optcopy['jobs'] = 1
669 if optcopy['with_hg'] is None: 660 if optcopy['with_hg'] is None:
670 optcopy['with_hg'] = os.path.join(BINDIR, "hg") 661 optcopy['with_hg'] = os.path.join(BINDIR, "hg")
662 optcopy.pop('anycoverage', None)
663
671 opts = [] 664 opts = []
672 for opt, value in optcopy.iteritems(): 665 for opt, value in optcopy.iteritems():
673 name = '--' + opt.replace('_', '-') 666 name = '--' + opt.replace('_', '-')
674 if value is True: 667 if value is True:
675 opts.append(name) 668 opts.append(name)
727 print "Failed %s: %s" % (s[0], s[1]) 720 print "Failed %s: %s" % (s[0], s[1])
728 721
729 _checkhglib("Tested") 722 _checkhglib("Tested")
730 print "# Ran %d tests, %d skipped, %d failed." % ( 723 print "# Ran %d tests, %d skipped, %d failed." % (
731 tested, skipped, failed) 724 tested, skipped, failed)
725
726 if options.anycoverage:
727 outputcoverage(options)
732 sys.exit(failures != 0) 728 sys.exit(failures != 0)
733 729
734 def runtests(options, tests): 730 def runtests(options, tests):
735 global DAEMON_PIDS, HGRCPATH 731 global DAEMON_PIDS, HGRCPATH
736 DAEMON_PIDS = os.environ["DAEMON_PIDS"] = os.path.join(HGTMP, 'daemon.pids') 732 DAEMON_PIDS = os.environ["DAEMON_PIDS"] = os.path.join(HGTMP, 'daemon.pids')