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:])) |