tests/run-tests.py
changeset 781 c7a471b49819
parent 777 cd294ce45931
child 793 9cc90e2c826f
equal deleted inserted replaced
773:9f939fae8ff3 781:c7a471b49819
    50 import subprocess
    50 import subprocess
    51 import signal
    51 import signal
    52 import sys
    52 import sys
    53 import tempfile
    53 import tempfile
    54 import time
    54 import time
       
    55 import re
    55 
    56 
    56 closefds = os.name == 'posix'
    57 closefds = os.name == 'posix'
    57 def Popen4(cmd, bufsize=-1):
    58 def Popen4(cmd, bufsize=-1):
    58     p = subprocess.Popen(cmd, shell=True, bufsize=bufsize,
    59     p = subprocess.Popen(cmd, shell=True, bufsize=bufsize,
    59                          close_fds=closefds,
    60                          close_fds=closefds,
   439     pass
   440     pass
   440 
   441 
   441 def alarmed(signum, frame):
   442 def alarmed(signum, frame):
   442     raise Timeout
   443     raise Timeout
   443 
   444 
       
   445 def pytest(test, options):
       
   446     py3kswitch = options.py3k_warnings and ' -3' or ''
       
   447     cmd = '%s%s "%s"' % (PYTHON, py3kswitch, test)
       
   448     vlog("# Running", cmd)
       
   449     return run(cmd, options)
       
   450 
       
   451 def shtest(test, options):
       
   452     cmd = '"%s"' % test
       
   453     vlog("# Running", cmd)
       
   454     return run(cmd, options)
       
   455 
       
   456 def battest(test, options):
       
   457     # To reliably get the error code from batch files on WinXP,
       
   458     # the "cmd /c call" prefix is needed. Grrr
       
   459     cmd = 'cmd /c call "%s"' % testpath
       
   460     vlog("# Running", cmd)
       
   461     return run(cmd, options)
       
   462 
       
   463 def tsttest(test, options):
       
   464     t = open(test)
       
   465     out = []
       
   466     script = []
       
   467     salt = "SALT" + str(time.time())
       
   468 
       
   469     pos = prepos = -1
       
   470     after = {}
       
   471     expected = {}
       
   472     for n, l in enumerate(t):
       
   473         if l.startswith('  $ '): # commands
       
   474             after.setdefault(pos, []).append(l)
       
   475             prepos = pos
       
   476             pos = n
       
   477             script.append('echo %s %s\n' % (salt, n))
       
   478             script.append(l[4:])
       
   479         elif l.startswith('  > '): # continuations
       
   480             after.setdefault(prepos, []).append(l)
       
   481             script.append(l[4:])
       
   482         elif l.startswith('  '): # results
       
   483             # queue up a list of expected results
       
   484             expected.setdefault(pos, []).append(l[2:])
       
   485         else:
       
   486             # non-command/result - queue up for merged output
       
   487             after.setdefault(pos, []).append(l)
       
   488 
       
   489     fd, name = tempfile.mkstemp(suffix='hg-tst')
       
   490 
       
   491     try:
       
   492         for l in script:
       
   493             os.write(fd, l)
       
   494         os.close(fd)
       
   495 
       
   496         cmd = '/bin/sh "%s"' % name
       
   497         vlog("# Running", cmd)
       
   498         exitcode, output = run(cmd, options)
       
   499     finally:
       
   500         os.remove(name)
       
   501 
       
   502     def rematch(el, l):
       
   503         try:
       
   504             return re.match(el, l)
       
   505         except re.error:
       
   506             # el is an invalid regex
       
   507             return False
       
   508 
       
   509     pos = -1
       
   510     postout = []
       
   511     for n, l in enumerate(output):
       
   512         if l.startswith(salt):
       
   513             if pos in after:
       
   514                 postout += after.pop(pos)
       
   515             pos = int(l.split()[1])
       
   516         else:
       
   517             el = None
       
   518             if pos in expected and expected[pos]:
       
   519                 el = expected[pos].pop(0)
       
   520 
       
   521             if el == l: # perfect match (fast)
       
   522                 postout.append("  " + l)
       
   523             elif el and rematch(el, l): # fallback regex match
       
   524                 postout.append("  " + el)
       
   525             else: # mismatch - let diff deal with it
       
   526                 postout.append("  " + l)
       
   527 
       
   528     if pos in after:
       
   529         postout += after.pop(pos)
       
   530 
       
   531     return exitcode, postout
       
   532 
   444 def run(cmd, options):
   533 def run(cmd, options):
   445     """Run command in a sub-process, capturing the output (stdout and stderr).
   534     """Run command in a sub-process, capturing the output (stdout and stderr).
   446     Return a tuple (exitcode, output).  output is None in debug mode."""
   535     Return a tuple (exitcode, output).  output is None in debug mode."""
   447     # TODO: Use subprocess.Popen if we're running on Python 2.4
   536     # TODO: Use subprocess.Popen if we're running on Python 2.4
   448     if options.debug:
   537     if options.debug:
   535     except:
   624     except:
   536         firstline = ''
   625         firstline = ''
   537     lctest = test.lower()
   626     lctest = test.lower()
   538 
   627 
   539     if lctest.endswith('.py') or firstline == '#!/usr/bin/env python':
   628     if lctest.endswith('.py') or firstline == '#!/usr/bin/env python':
   540         py3kswitch = options.py3k_warnings and ' -3' or ''
   629         runner = pytest
   541         cmd = '%s%s "%s"' % (PYTHON, py3kswitch, testpath)
       
   542     elif lctest.endswith('.bat'):
   630     elif lctest.endswith('.bat'):
   543         # do not run batch scripts on non-windows
   631         # do not run batch scripts on non-windows
   544         if os.name != 'nt':
   632         if os.name != 'nt':
   545             return skip("batch script")
   633             return skip("batch script")
   546         # To reliably get the error code from batch files on WinXP,
   634         runner = battest
   547         # the "cmd /c call" prefix is needed. Grrr
   635     elif lctest.endswith('.t'):
   548         cmd = 'cmd /c call "%s"' % testpath
   636         runner = tsttest
       
   637         ref = testpath
   549     else:
   638     else:
   550         # do not run shell scripts on windows
   639         # do not run shell scripts on windows
   551         if os.name == 'nt':
   640         if os.name == 'nt':
   552             return skip("shell script")
   641             return skip("shell script")
   553         # do not try to run non-executable programs
   642         # do not try to run non-executable programs
   554         if not os.path.exists(testpath):
   643         if not os.path.exists(testpath):
   555             return fail("does not exist")
   644             return fail("does not exist")
   556         elif not os.access(testpath, os.X_OK):
   645         elif not os.access(testpath, os.X_OK):
   557             return skip("not executable")
   646             return skip("not executable")
   558         cmd = '"%s"' % testpath
   647         runner = shtest
   559 
   648 
   560     # Make a tmp subdirectory to work in
   649     # Make a tmp subdirectory to work in
   561     tmpd = os.path.join(HGTMP, test)
   650     tmpd = os.path.join(HGTMP, test)
   562     os.mkdir(tmpd)
   651     os.mkdir(tmpd)
   563     os.chdir(tmpd)
   652     os.chdir(tmpd)
   564 
   653 
   565     if options.timeout > 0:
   654     if options.timeout > 0:
   566         signal.alarm(options.timeout)
   655         signal.alarm(options.timeout)
   567 
   656 
   568     vlog("# Running", cmd)
   657     ret, out = runner(testpath, options)
   569     ret, out = run(cmd, options)
       
   570     vlog("# Ret was:", ret)
   658     vlog("# Ret was:", ret)
   571 
   659 
   572     if options.timeout > 0:
   660     if options.timeout > 0:
   573         signal.alarm(0)
   661         signal.alarm(0)
   574 
   662 
   805             elif not ret:
   893             elif not ret:
   806                 if options.interactive:
   894                 if options.interactive:
   807                     print "Accept this change? [n] ",
   895                     print "Accept this change? [n] ",
   808                     answer = sys.stdin.readline().strip()
   896                     answer = sys.stdin.readline().strip()
   809                     if answer.lower() in "y yes".split():
   897                     if answer.lower() in "y yes".split():
   810                         rename(test + ".err", test + ".out")
   898                         if test.endswith(".t"):
       
   899                             rename(test + ".err", test)
       
   900                         else:
       
   901                             rename(test + ".err", test + ".out")
   811                         tested += 1
   902                         tested += 1
   812                         fails.pop()
   903                         fails.pop()
   813                         continue
   904                         continue
   814                 failed += 1
   905                 failed += 1
   815                 if options.first:
   906                 if options.first:
   942 
  1033 
   943     tests = []
  1034     tests = []
   944     for test in args:
  1035     for test in args:
   945         if (test.startswith("test-") and '~' not in test and
  1036         if (test.startswith("test-") and '~' not in test and
   946             ('.' not in test or test.endswith('.py') or
  1037             ('.' not in test or test.endswith('.py') or
   947              test.endswith('.bat'))):
  1038              test.endswith('.bat') or test.endswith('.t'))):
   948             tests.append(test)
  1039             tests.append(test)
   949     if not tests:
  1040     if not tests:
   950         print "# Ran 0 tests, 0 skipped, 0 failed."
  1041         print "# Ran 0 tests, 0 skipped, 0 failed."
   951         return
  1042         return
   952 
  1043