tests/run-tests.py
changeset 21349 2d767c7c3df0
parent 21348 b3399154505f
child 21350 dfcef61f5bd4
equal deleted inserted replaced
21348:b3399154505f 21349:2d767c7c3df0
   386 
   386 
   387 def killdaemons(pidfile):
   387 def killdaemons(pidfile):
   388     return killmod.killdaemons(pidfile, tryhard=False, remove=True,
   388     return killmod.killdaemons(pidfile, tryhard=False, remove=True,
   389                                logfn=vlog)
   389                                logfn=vlog)
   390 
   390 
   391 def cleanup(runner, options):
   391 def cleanup(runner):
   392     if not options.keep_tmpdir:
   392     if runner.options.keep_tmpdir:
   393         vlog("# Cleaning up HGTMP", runner.hgtmp)
   393         return
   394         shutil.rmtree(runner.hgtmp, True)
   394 
   395         for f in createdfiles:
   395     vlog("# Cleaning up HGTMP", runner.hgtmp)
   396             try:
   396     shutil.rmtree(runner.hgtmp, True)
   397                 os.remove(f)
   397     for f in createdfiles:
   398             except OSError:
   398         try:
   399                 pass
   399             os.remove(f)
       
   400         except OSError:
       
   401             pass
   400 
   402 
   401 def usecorrectpython(runner):
   403 def usecorrectpython(runner):
   402     # some tests run python interpreter. they must use same
   404     # some tests run python interpreter. they must use same
   403     # interpreter we use or bad things will happen.
   405     # interpreter we use or bad things will happen.
   404     pyexename = sys.platform == 'win32' and 'python.exe' or 'python'
   406     pyexename = sys.platform == 'win32' and 'python.exe' or 'python'
   430             path.remove(exedir)
   432             path.remove(exedir)
   431         os.environ['PATH'] = os.pathsep.join([exedir] + path)
   433         os.environ['PATH'] = os.pathsep.join([exedir] + path)
   432         if not findprogram(pyexename):
   434         if not findprogram(pyexename):
   433             print "WARNING: Cannot find %s in search path" % pyexename
   435             print "WARNING: Cannot find %s in search path" % pyexename
   434 
   436 
   435 def installhg(runner, options):
   437 def installhg(runner):
   436     vlog("# Performing temporary installation of HG")
   438     vlog("# Performing temporary installation of HG")
   437     installerrs = os.path.join("tests", "install.err")
   439     installerrs = os.path.join("tests", "install.err")
   438     compiler = ''
   440     compiler = ''
   439     if options.compiler:
   441     if runner.options.compiler:
   440         compiler = '--compiler ' + options.compiler
   442         compiler = '--compiler ' + runner.options.compiler
   441     pure = options.pure and "--pure" or ""
   443     pure = runner.options.pure and "--pure" or ""
   442     py3 = ''
   444     py3 = ''
   443     if sys.version_info[0] == 3:
   445     if sys.version_info[0] == 3:
   444         py3 = '--c2to3'
   446         py3 = '--c2to3'
   445 
   447 
   446     # Run installer in hg root
   448     # Run installer in hg root
   463               'prefix': runner.inst, 'libdir': runner.pythondir,
   465               'prefix': runner.inst, 'libdir': runner.pythondir,
   464               'bindir': runner.bindir,
   466               'bindir': runner.bindir,
   465               'nohome': nohome, 'logfile': installerrs})
   467               'nohome': nohome, 'logfile': installerrs})
   466     vlog("# Running", cmd)
   468     vlog("# Running", cmd)
   467     if os.system(cmd) == 0:
   469     if os.system(cmd) == 0:
   468         if not options.verbose:
   470         if not runner.options.verbose:
   469             os.remove(installerrs)
   471             os.remove(installerrs)
   470     else:
   472     else:
   471         f = open(installerrs)
   473         f = open(installerrs)
   472         for line in f:
   474         for line in f:
   473             print line,
   475             print line,
   475         sys.exit(1)
   477         sys.exit(1)
   476     os.chdir(runner.testdir)
   478     os.chdir(runner.testdir)
   477 
   479 
   478     usecorrectpython(runner)
   480     usecorrectpython(runner)
   479 
   481 
   480     if options.py3k_warnings and not options.anycoverage:
   482     if runner.options.py3k_warnings and not runner.options.anycoverage:
   481         vlog("# Updating hg command to enable Py3k Warnings switch")
   483         vlog("# Updating hg command to enable Py3k Warnings switch")
   482         f = open(os.path.join(runner.bindir, 'hg'), 'r')
   484         f = open(os.path.join(runner.bindir, 'hg'), 'r')
   483         lines = [line.rstrip() for line in f]
   485         lines = [line.rstrip() for line in f]
   484         lines[0] += ' -3'
   486         lines[0] += ' -3'
   485         f.close()
   487         f.close()
   502             f.write(data)
   504             f.write(data)
   503             f.close()
   505             f.close()
   504         else:
   506         else:
   505             print 'WARNING: cannot fix hg.bat reference to python.exe'
   507             print 'WARNING: cannot fix hg.bat reference to python.exe'
   506 
   508 
   507     if options.anycoverage:
   509     if runner.options.anycoverage:
   508         custom = os.path.join(runner.testdir, 'sitecustomize.py')
   510         custom = os.path.join(runner.testdir, 'sitecustomize.py')
   509         target = os.path.join(runner.pythondir, 'sitecustomize.py')
   511         target = os.path.join(runner.pythondir, 'sitecustomize.py')
   510         vlog('# Installing coverage trigger to %s' % target)
   512         vlog('# Installing coverage trigger to %s' % target)
   511         shutil.copyfile(custom, target)
   513         shutil.copyfile(custom, target)
   512         rc = os.path.join(runner.testdir, '.coveragerc')
   514         rc = os.path.join(runner.testdir, '.coveragerc')
   521     cols = '%7.3f   %s'
   523     cols = '%7.3f   %s'
   522     print '\n%-7s   %s' % ('Time', 'Test')
   524     print '\n%-7s   %s' % ('Time', 'Test')
   523     for test, timetaken in times:
   525     for test, timetaken in times:
   524         print cols % (timetaken, test)
   526         print cols % (timetaken, test)
   525 
   527 
   526 def outputcoverage(runner, options):
   528 def outputcoverage(runner):
   527 
   529 
   528     vlog('# Producing coverage report')
   530     vlog('# Producing coverage report')
   529     os.chdir(runner.pythondir)
   531     os.chdir(runner.pythondir)
   530 
   532 
   531     def covrun(*args):
   533     def covrun(*args):
   535 
   537 
   536     covrun('-c')
   538     covrun('-c')
   537     omit = ','.join(os.path.join(x, '*') for x in
   539     omit = ','.join(os.path.join(x, '*') for x in
   538                     [runner.bindir, runner.testdir])
   540                     [runner.bindir, runner.testdir])
   539     covrun('-i', '-r', '"--omit=%s"' % omit) # report
   541     covrun('-i', '-r', '"--omit=%s"' % omit) # report
   540     if options.htmlcov:
   542     if runner.options.htmlcov:
   541         htmldir = os.path.join(runner.testdir, 'htmlcov')
   543         htmldir = os.path.join(runner.testdir, 'htmlcov')
   542         covrun('-i', '-b', '"--directory=%s"' % htmldir, '"--omit=%s"' % omit)
   544         covrun('-i', '-b', '"--directory=%s"' % htmldir, '"--omit=%s"' % omit)
   543     if options.annotate:
   545     if runner.options.annotate:
   544         adir = os.path.join(runner.testdir, 'annotated')
   546         adir = os.path.join(runner.testdir, 'annotated')
   545         if not os.path.isdir(adir):
   547         if not os.path.isdir(adir):
   546             os.mkdir(adir)
   548             os.mkdir(adir)
   547         covrun('-i', '-a', '"--directory=%s"' % adir, '"--omit=%s"' % omit)
   549         covrun('-i', '-a', '"--directory=%s"' % adir, '"--omit=%s"' % omit)
   548 
   550 
   551 
   553 
   552     Test instances can be run multiple times via run(). However, multiple
   554     Test instances can be run multiple times via run(). However, multiple
   553     runs cannot be run concurrently.
   555     runs cannot be run concurrently.
   554     """
   556     """
   555 
   557 
   556     def __init__(self, runner, test, options, count, refpath):
   558     def __init__(self, runner, test, count, refpath):
   557         path = os.path.join(runner.testdir, test)
   559         path = os.path.join(runner.testdir, test)
   558         errpath = os.path.join(runner.testdir, '%s.err' % test)
   560         errpath = os.path.join(runner.testdir, '%s.err' % test)
   559 
   561 
   560         self._testdir = runner.testdir
   562         self._testdir = runner.testdir
   561         self._test = test
   563         self._test = test
   562         self._path = path
   564         self._path = path
   563         self._options = options
   565         self._options = runner.options
   564         self._count = count
   566         self._count = count
   565         self._daemonpids = []
   567         self._daemonpids = []
   566         self._refpath = refpath
   568         self._refpath = refpath
   567         self._errpath = errpath
   569         self._errpath = errpath
   568 
   570 
   569         # If we're not in --debug mode and reference output file exists,
   571         # If we're not in --debug mode and reference output file exists,
   570         # check test output against it.
   572         # check test output against it.
   571         if options.debug:
   573         if runner.options.debug:
   572             self._refout = None # to match "out is None"
   574             self._refout = None # to match "out is None"
   573         elif os.path.exists(refpath):
   575         elif os.path.exists(refpath):
   574             f = open(refpath, 'r')
   576             f = open(refpath, 'r')
   575             self._refout = f.read().splitlines(True)
   577             self._refout = f.read().splitlines(True)
   576             f.close()
   578             f.close()
  1085                 return TTest.globmatch(el[:-8], l)
  1087                 return TTest.globmatch(el[:-8], l)
  1086             if os.altsep and l.replace('\\', '/') == el:
  1088             if os.altsep and l.replace('\\', '/') == el:
  1087                 return '+glob'
  1089                 return '+glob'
  1088         return False
  1090         return False
  1089 
  1091 
  1090 def gettest(runner, test, options, count):
  1092 def gettest(runner, test, count):
  1091     """Obtain a Test by looking at its filename.
  1093     """Obtain a Test by looking at its filename.
  1092 
  1094 
  1093     Returns a Test instance. The Test may not be runnable if it doesn't map
  1095     Returns a Test instance. The Test may not be runnable if it doesn't map
  1094     to a known type.
  1096     to a known type.
  1095     """
  1097     """
  1103         if lctest.endswith(ext):
  1105         if lctest.endswith(ext):
  1104             testcls = cls
  1106             testcls = cls
  1105             refpath = os.path.join(runner.testdir, test + out)
  1107             refpath = os.path.join(runner.testdir, test + out)
  1106             break
  1108             break
  1107 
  1109 
  1108     return testcls(runner, test, options, count, refpath)
  1110     return testcls(runner, test, count, refpath)
  1109 
  1111 
  1110 wifexited = getattr(os, "WIFEXITED", lambda x: False)
  1112 wifexited = getattr(os, "WIFEXITED", lambda x: False)
  1111 def run(cmd, wd, options, replacements, env):
  1113 def run(cmd, wd, options, replacements, env):
  1112     """Run command in a sub-process, capturing the output (stdout and stderr).
  1114     """Run command in a sub-process, capturing the output (stdout and stderr).
  1113     Return a tuple (exitcode, output).  output is None in debug mode."""
  1115     Return a tuple (exitcode, output).  output is None in debug mode."""
  1183 results = {'.':[], '!':[], '~': [], 's':[], 'i':[]}
  1185 results = {'.':[], '!':[], '~': [], 's':[], 'i':[]}
  1184 times = []
  1186 times = []
  1185 iolock = threading.Lock()
  1187 iolock = threading.Lock()
  1186 abort = False
  1188 abort = False
  1187 
  1189 
  1188 def scheduletests(runner, options, tests):
  1190 def scheduletests(runner, tests):
  1189     jobs = options.jobs
  1191     jobs = runner.options.jobs
  1190     done = queue.Queue()
  1192     done = queue.Queue()
  1191     running = 0
  1193     running = 0
  1192     count = 0
  1194     count = 0
  1193     global abort
  1195     global abort
  1194 
  1196 
  1195     def job(test, count):
  1197     def job(test, count):
  1196         try:
  1198         try:
  1197             t = gettest(runner, test, options, count)
  1199             t = gettest(runner, test, count)
  1198             done.put(t.run())
  1200             done.put(t.run())
  1199             t.cleanup()
  1201             t.cleanup()
  1200         except KeyboardInterrupt:
  1202         except KeyboardInterrupt:
  1201             pass
  1203             pass
  1202         except: # re-raises
  1204         except: # re-raises
  1207         while tests or running:
  1209         while tests or running:
  1208             if not done.empty() or running == jobs or not tests:
  1210             if not done.empty() or running == jobs or not tests:
  1209                 try:
  1211                 try:
  1210                     code, test, msg = done.get(True, 1)
  1212                     code, test, msg = done.get(True, 1)
  1211                     results[code].append((test, msg))
  1213                     results[code].append((test, msg))
  1212                     if options.first and code not in '.si':
  1214                     if runner.options.first and code not in '.si':
  1213                         break
  1215                         break
  1214                 except queue.Empty:
  1216                 except queue.Empty:
  1215                     continue
  1217                     continue
  1216                 running -= 1
  1218                 running -= 1
  1217             if tests and not running == jobs:
  1219             if tests and not running == jobs:
  1218                 test = tests.pop(0)
  1220                 test = tests.pop(0)
  1219                 if options.loop:
  1221                 if runner.options.loop:
  1220                     tests.append(test)
  1222                     tests.append(test)
  1221                 t = threading.Thread(target=job, name=test, args=(test, count))
  1223                 t = threading.Thread(target=job, name=test, args=(test, count))
  1222                 t.start()
  1224                 t.start()
  1223                 running += 1
  1225                 running += 1
  1224                 count += 1
  1226                 count += 1
  1225     except KeyboardInterrupt:
  1227     except KeyboardInterrupt:
  1226         abort = True
  1228         abort = True
  1227 
  1229 
  1228 def runtests(runner, options, tests):
  1230 def runtests(runner, tests):
  1229     try:
  1231     try:
  1230         if runner.inst:
  1232         if runner.inst:
  1231             installhg(runner, options)
  1233             installhg(runner)
  1232             _checkhglib(runner, "Testing")
  1234             _checkhglib(runner, "Testing")
  1233         else:
  1235         else:
  1234             usecorrectpython(runner)
  1236             usecorrectpython(runner)
  1235 
  1237 
  1236         if options.restart:
  1238         if runner.options.restart:
  1237             orig = list(tests)
  1239             orig = list(tests)
  1238             while tests:
  1240             while tests:
  1239                 if os.path.exists(tests[0] + ".err"):
  1241                 if os.path.exists(tests[0] + ".err"):
  1240                     break
  1242                     break
  1241                 tests.pop(0)
  1243                 tests.pop(0)
  1242             if not tests:
  1244             if not tests:
  1243                 print "running all tests"
  1245                 print "running all tests"
  1244                 tests = orig
  1246                 tests = orig
  1245 
  1247 
  1246         scheduletests(runner, options, tests)
  1248         scheduletests(runner, tests)
  1247 
  1249 
  1248         failed = len(results['!'])
  1250         failed = len(results['!'])
  1249         warned = len(results['~'])
  1251         warned = len(results['~'])
  1250         tested = len(results['.']) + failed + warned
  1252         tested = len(results['.']) + failed + warned
  1251         skipped = len(results['s'])
  1253         skipped = len(results['s'])
  1252         ignored = len(results['i'])
  1254         ignored = len(results['i'])
  1253 
  1255 
  1254         print
  1256         print
  1255         if not options.noskips:
  1257         if not runner.options.noskips:
  1256             for s in results['s']:
  1258             for s in results['s']:
  1257                 print "Skipped %s: %s" % s
  1259                 print "Skipped %s: %s" % s
  1258         for s in results['~']:
  1260         for s in results['~']:
  1259             print "Warned %s: %s" % s
  1261             print "Warned %s: %s" % s
  1260         for s in results['!']:
  1262         for s in results['!']:
  1262         _checkhglib(runner, "Tested")
  1264         _checkhglib(runner, "Tested")
  1263         print "# Ran %d tests, %d skipped, %d warned, %d failed." % (
  1265         print "# Ran %d tests, %d skipped, %d warned, %d failed." % (
  1264             tested, skipped + ignored, warned, failed)
  1266             tested, skipped + ignored, warned, failed)
  1265         if results['!']:
  1267         if results['!']:
  1266             print 'python hash seed:', os.environ['PYTHONHASHSEED']
  1268             print 'python hash seed:', os.environ['PYTHONHASHSEED']
  1267         if options.time:
  1269         if runner.options.time:
  1268             outputtimes(options)
  1270             outputtimes(runner.options)
  1269 
  1271 
  1270         if options.anycoverage:
  1272         if runner.options.anycoverage:
  1271             outputcoverage(runner, options)
  1273             outputcoverage(runner)
  1272     except KeyboardInterrupt:
  1274     except KeyboardInterrupt:
  1273         failed = True
  1275         failed = True
  1274         print "\ninterrupted!"
  1276         print "\ninterrupted!"
  1275 
  1277 
  1276     if failed:
  1278     if failed:
  1417     vlog("# Using HGTMP", runner.hgtmp)
  1419     vlog("# Using HGTMP", runner.hgtmp)
  1418     vlog("# Using PATH", os.environ["PATH"])
  1420     vlog("# Using PATH", os.environ["PATH"])
  1419     vlog("# Using", IMPL_PATH, os.environ[IMPL_PATH])
  1421     vlog("# Using", IMPL_PATH, os.environ[IMPL_PATH])
  1420 
  1422 
  1421     try:
  1423     try:
  1422         return runtests(runner, options, tests) or 0
  1424         return runtests(runner, tests) or 0
  1423     finally:
  1425     finally:
  1424         time.sleep(.1)
  1426         time.sleep(.1)
  1425         cleanup(runner, options)
  1427         cleanup(runner)
  1426 
  1428 
  1427 if __name__ == '__main__':
  1429 if __name__ == '__main__':
  1428     sys.exit(main(sys.argv[1:]))
  1430     sys.exit(main(sys.argv[1:]))