tests/run-tests.py
changeset 1162 0928d50a0abe
parent 1161 ce884838a955
child 1163 d5d13134793a
equal deleted inserted replaced
1156:337e1ceae82e 1162:0928d50a0abe
    53 import tempfile
    53 import tempfile
    54 import time
    54 import time
    55 import re
    55 import re
    56 import threading
    56 import threading
    57 import killdaemons as killmod
    57 import killdaemons as killmod
       
    58 import cPickle as pickle
    58 
    59 
    59 processlock = threading.Lock()
    60 processlock = threading.Lock()
    60 
    61 
    61 closefds = os.name == 'posix'
    62 closefds = os.name == 'posix'
    62 def Popen4(cmd, wd, timeout):
    63 def Popen4(cmd, wd, timeout):
   173     parser.add_option("--shell", type="string",
   174     parser.add_option("--shell", type="string",
   174         help="shell to use (default: $%s or %s)" % defaults['shell'])
   175         help="shell to use (default: $%s or %s)" % defaults['shell'])
   175     parser.add_option("-t", "--timeout", type="int",
   176     parser.add_option("-t", "--timeout", type="int",
   176         help="kill errant tests after TIMEOUT seconds"
   177         help="kill errant tests after TIMEOUT seconds"
   177              " (default: $%s or %d)" % defaults['timeout'])
   178              " (default: $%s or %d)" % defaults['timeout'])
       
   179     parser.add_option("--time", action="store_true",
       
   180         help="time how long each test takes")
   178     parser.add_option("--tmpdir", type="string",
   181     parser.add_option("--tmpdir", type="string",
   179         help="run tests in the given temporary directory"
   182         help="run tests in the given temporary directory"
   180              " (implies --keep-tmpdir)")
   183              " (implies --keep-tmpdir)")
   181     parser.add_option("-v", "--verbose", action="store_true",
   184     parser.add_option("-v", "--verbose", action="store_true",
   182         help="output verbose messages")
   185         help="output verbose messages")
   261     if options.debug:
   264     if options.debug:
   262         if options.timeout != defaults['timeout']:
   265         if options.timeout != defaults['timeout']:
   263             sys.stderr.write(
   266             sys.stderr.write(
   264                 'warning: --timeout option ignored with --debug\n')
   267                 'warning: --timeout option ignored with --debug\n')
   265         options.timeout = 0
   268         options.timeout = 0
       
   269         if options.time:
       
   270             sys.stderr.write(
       
   271                 'warning: --time option ignored with --debug\n')
       
   272         options.time = False
   266     if options.py3k_warnings:
   273     if options.py3k_warnings:
   267         if sys.version_info[:2] < (2, 6) or sys.version_info[:2] >= (3, 0):
   274         if sys.version_info[:2] < (2, 6) or sys.version_info[:2] >= (3, 0):
   268             parser.error('--py3k-warnings can only be used on Python 2.6+')
   275             parser.error('--py3k-warnings can only be used on Python 2.6+')
   269     if options.blacklist:
   276     if options.blacklist:
   270         options.blacklist = parselistfiles(options.blacklist, 'blacklist')
   277         options.blacklist = parselistfiles(options.blacklist, 'blacklist')
   444         rc = os.path.join(TESTDIR, '.coveragerc')
   451         rc = os.path.join(TESTDIR, '.coveragerc')
   445         vlog('# Installing coverage rc to %s' % rc)
   452         vlog('# Installing coverage rc to %s' % rc)
   446         os.environ['COVERAGE_PROCESS_START'] = rc
   453         os.environ['COVERAGE_PROCESS_START'] = rc
   447         fn = os.path.join(INST, '..', '.coverage')
   454         fn = os.path.join(INST, '..', '.coverage')
   448         os.environ['COVERAGE_FILE'] = fn
   455         os.environ['COVERAGE_FILE'] = fn
       
   456 
       
   457 def outputtimes(options):
       
   458     vlog('# Producing time report')
       
   459     times.sort(key=lambda t: (t[1], t[0]), reverse=True)
       
   460     cols = '%7.3f   %s'
       
   461     print '\n%-7s   %s' % ('Time', 'Test')
       
   462     for test, timetaken in times:
       
   463         print cols % (timetaken, test)
   449 
   464 
   450 def outputcoverage(options):
   465 def outputcoverage(options):
   451 
   466 
   452     vlog('# Producing coverage report')
   467     vlog('# Producing coverage report')
   453     os.chdir(PYTHONDIR)
   468     os.chdir(PYTHONDIR)
   751     '''tristate output:
   766     '''tristate output:
   752     None -> skipped
   767     None -> skipped
   753     True -> passed
   768     True -> passed
   754     False -> failed'''
   769     False -> failed'''
   755 
   770 
   756     global results, resultslock, iolock
   771     global results, iolock
   757 
   772 
   758     testpath = os.path.join(TESTDIR, test)
   773     testpath = os.path.join(TESTDIR, test)
   759 
       
   760     def result(l, e):
       
   761         resultslock.acquire()
       
   762         results[l].append(e)
       
   763         resultslock.release()
       
   764 
   774 
   765     def skip(msg):
   775     def skip(msg):
   766         if not options.verbose:
   776         if not options.verbose:
   767             result('s', (test, msg))
   777             results['s'].append((test, msg))
   768         else:
   778         else:
   769             iolock.acquire()
   779             iolock.acquire()
   770             print "\nSkipping %s: %s" % (testpath, msg)
   780             print "\nSkipping %s: %s" % (testpath, msg)
   771             iolock.release()
   781             iolock.release()
   772         return None
   782         return None
   785             if answer.lower() in "y yes".split():
   795             if answer.lower() in "y yes".split():
   786                 if test.endswith(".t"):
   796                 if test.endswith(".t"):
   787                     rename(testpath + ".err", testpath)
   797                     rename(testpath + ".err", testpath)
   788                 else:
   798                 else:
   789                     rename(testpath + ".err", testpath + ".out")
   799                     rename(testpath + ".err", testpath + ".out")
   790                 result('p', test)
   800                 success(test)
   791                 return
   801                 return
   792         result('f', (test, msg))
   802         results['f'].append((test, msg))
   793 
   803 
   794     def success():
   804     def success():
   795         result('p', test)
   805         results['p'].append(test)
   796 
   806 
   797     def ignore(msg):
   807     def ignore(msg):
   798         result('i', (test, msg))
   808         results['i'].append((test, msg))
   799 
   809 
   800     if (os.path.basename(test).startswith("test-") and '~' not in test and
   810     if (os.path.basename(test).startswith("test-") and '~' not in test and
   801         ('.' not in test or test.endswith('.py') or
   811         ('.' not in test or test.endswith('.py') or
   802          test.endswith('.bat') or test.endswith('.t'))):
   812          test.endswith('.bat') or test.endswith('.t'))):
   803         if not os.path.exists(test):
   813         if not os.path.exists(test):
   889                      for c in testtmp), '$TESTTMP'))
   899                      for c in testtmp), '$TESTTMP'))
   890     else:
   900     else:
   891         replacements.append((re.escape(testtmp), '$TESTTMP'))
   901         replacements.append((re.escape(testtmp), '$TESTTMP'))
   892 
   902 
   893     os.mkdir(testtmp)
   903     os.mkdir(testtmp)
       
   904     if options.time:
       
   905         starttime = time.time()
   894     ret, out = runner(testpath, testtmp, options, replacements)
   906     ret, out = runner(testpath, testtmp, options, replacements)
       
   907     if options.time:
       
   908         endtime = time.time()
       
   909         times.append((test, endtime - starttime))
   895     vlog("# Ret was:", ret)
   910     vlog("# Ret was:", ret)
   896 
   911 
   897     mark = '.'
   912     mark = '.'
   898 
   913 
   899     skipped = (ret == SKIPPED_STATUS)
   914     skipped = (ret == SKIPPED_STATUS)
  1054         childopts = ['--child=%d' % wfd, '--port=%d' % (options.port + j * 3)]
  1069         childopts = ['--child=%d' % wfd, '--port=%d' % (options.port + j * 3)]
  1055         childtmp = os.path.join(HGTMP, 'child%d' % j)
  1070         childtmp = os.path.join(HGTMP, 'child%d' % j)
  1056         childopts += ['--tmpdir', childtmp]
  1071         childopts += ['--tmpdir', childtmp]
  1057         cmdline = [PYTHON, sys.argv[0]] + opts + childopts + job
  1072         cmdline = [PYTHON, sys.argv[0]] + opts + childopts + job
  1058         vlog(' '.join(cmdline))
  1073         vlog(' '.join(cmdline))
  1059         fps[os.spawnvp(os.P_NOWAIT, cmdline[0], cmdline)] = os.fdopen(rfd, 'r')
  1074         fps[os.spawnvp(os.P_NOWAIT, cmdline[0], cmdline)] = os.fdopen(rfd, 'rb')
  1060         os.close(wfd)
  1075         os.close(wfd)
  1061     signal.signal(signal.SIGINT, signal.SIG_IGN)
  1076     signal.signal(signal.SIGINT, signal.SIG_IGN)
  1062     failures = 0
  1077     failures = 0
  1063     tested, skipped, failed = 0, 0, 0
  1078     passed, skipped, failed = 0, 0, 0
  1064     skips = []
  1079     skips = []
  1065     fails = []
  1080     fails = []
  1066     while fps:
  1081     while fps:
  1067         pid, status = os.wait()
  1082         pid, status = os.wait()
  1068         fp = fps.pop(pid)
  1083         fp = fps.pop(pid)
  1069         l = fp.read().splitlines()
       
  1070         try:
  1084         try:
  1071             test, skip, fail = map(int, l[:3])
  1085             childresults = pickle.load(fp)
  1072         except ValueError:
  1086         except pickle.UnpicklingError:
  1073             test, skip, fail = 0, 0, 0
  1087             pass
  1074         split = -fail or len(l)
  1088         else:
  1075         for s in l[3:split]:
  1089             passed += len(childresults['p'])
  1076             skips.append(s.split(" ", 1))
  1090             skipped += len(childresults['s'])
  1077         for s in l[split:]:
  1091             failed += len(childresults['f'])
  1078             fails.append(s.split(" ", 1))
  1092             skips.extend(childresults['s'])
  1079         tested += test
  1093             fails.extend(childresults['f'])
  1080         skipped += skip
  1094         if options.time:
  1081         failed += fail
  1095             childtimes = pickle.load(fp)
       
  1096             times.extend(childtimes)
       
  1097 
  1082         vlog('pid %d exited, status %d' % (pid, status))
  1098         vlog('pid %d exited, status %d' % (pid, status))
  1083         failures |= status
  1099         failures |= status
  1084     print
  1100     print
  1085     skipped += len(blacklisted)
  1101     skipped += len(blacklisted)
  1086     if not options.noskips:
  1102     if not options.noskips:
  1091     for s in fails:
  1107     for s in fails:
  1092         print "Failed %s: %s" % (s[0], s[1])
  1108         print "Failed %s: %s" % (s[0], s[1])
  1093 
  1109 
  1094     _checkhglib("Tested")
  1110     _checkhglib("Tested")
  1095     print "# Ran %d tests, %d skipped, %d failed." % (
  1111     print "# Ran %d tests, %d skipped, %d failed." % (
  1096         tested, skipped, failed)
  1112         passed + failed, skipped, failed)
  1097 
  1113 
       
  1114     if options.time:
       
  1115         outputtimes(options)
  1098     if options.anycoverage:
  1116     if options.anycoverage:
  1099         outputcoverage(options)
  1117         outputcoverage(options)
  1100     sys.exit(failures != 0)
  1118     sys.exit(failures != 0)
  1101 
  1119 
  1102 results = dict(p=[], f=[], s=[], i=[])
  1120 results = dict(p=[], f=[], s=[], i=[])
  1103 resultslock = threading.Lock()
  1121 times = []
  1104 iolock = threading.Lock()
  1122 iolock = threading.Lock()
  1105 
  1123 
  1106 def runqueue(options, tests, results):
  1124 def runqueue(options, tests):
  1107     for test in tests:
  1125     for test in tests:
  1108         ret = runone(options, test)
  1126         ret = runone(options, test)
  1109         if options.first and ret is not None and not ret:
  1127         if options.first and ret is not None and not ret:
  1110             break
  1128             break
  1111 
  1129 
  1127                 tests.pop(0)
  1145                 tests.pop(0)
  1128             if not tests:
  1146             if not tests:
  1129                 print "running all tests"
  1147                 print "running all tests"
  1130                 tests = orig
  1148                 tests = orig
  1131 
  1149 
  1132         runqueue(options, tests, results)
  1150         runqueue(options, tests)
  1133 
  1151 
  1134         failed = len(results['f'])
  1152         failed = len(results['f'])
  1135         tested = len(results['p']) + failed
  1153         tested = len(results['p']) + failed
  1136         skipped = len(results['s'])
  1154         skipped = len(results['s'])
  1137         ignored = len(results['i'])
  1155         ignored = len(results['i'])
  1138 
  1156 
  1139         if options.child:
  1157         if options.child:
  1140             fp = os.fdopen(options.child, 'w')
  1158             fp = os.fdopen(options.child, 'wb')
  1141             fp.write('%d\n%d\n%d\n' % (tested, skipped, failed))
  1159             pickle.dump(results, fp, pickle.HIGHEST_PROTOCOL)
  1142             for s in results['s']:
  1160             if options.time:
  1143                 fp.write("%s %s\n" % s)
  1161                 pickle.dump(times, fp, pickle.HIGHEST_PROTOCOL)
  1144             for s in results['f']:
       
  1145                 fp.write("%s %s\n" % s)
       
  1146             fp.close()
  1162             fp.close()
  1147         else:
  1163         else:
  1148             print
  1164             print
  1149             for s in results['s']:
  1165             for s in results['s']:
  1150                 print "Skipped %s: %s" % s
  1166                 print "Skipped %s: %s" % s
  1151             for s in results['f']:
  1167             for s in results['f']:
  1152                 print "Failed %s: %s" % s
  1168                 print "Failed %s: %s" % s
  1153             _checkhglib("Tested")
  1169             _checkhglib("Tested")
  1154             print "# Ran %d tests, %d skipped, %d failed." % (
  1170             print "# Ran %d tests, %d skipped, %d failed." % (
  1155                 tested, skipped + ignored, failed)
  1171                 tested, skipped + ignored, failed)
       
  1172             if options.time:
       
  1173                 outputtimes(options)
  1156 
  1174 
  1157         if options.anycoverage:
  1175         if options.anycoverage:
  1158             outputcoverage(options)
  1176             outputcoverage(options)
  1159     except KeyboardInterrupt:
  1177     except KeyboardInterrupt:
  1160         failed = True
  1178         failed = True