tests/run-tests.py
branchstable
changeset 671 629956d13cbc
parent 670 80d0ed025a02
child 674 0efa9d6ac11f
equal deleted inserted replaced
665:06ccaeb6cfc1 671:629956d13cbc
    14 #   - tests are a mix of shell scripts and Python scripts
    14 #   - tests are a mix of shell scripts and Python scripts
    15 #
    15 #
    16 # If you change this script, it is recommended that you ensure you
    16 # If you change this script, it is recommended that you ensure you
    17 # haven't broken it by running it in various modes with a representative
    17 # haven't broken it by running it in various modes with a representative
    18 # sample of test scripts.  For example:
    18 # sample of test scripts.  For example:
    19 # 
    19 #
    20 #  1) serial, no coverage, temp install:
    20 #  1) serial, no coverage, temp install:
    21 #      ./run-tests.py test-s*
    21 #      ./run-tests.py test-s*
    22 #  2) serial, no coverage, local hg:
    22 #  2) serial, no coverage, local hg:
    23 #      ./run-tests.py --local test-s*
    23 #      ./run-tests.py --local test-s*
    24 #  3) serial, coverage, temp install:
    24 #  3) serial, coverage, temp install:
    29 #      ./run-tests.py -j2 test-s*
    29 #      ./run-tests.py -j2 test-s*
    30 #  6) parallel, no coverage, local hg:
    30 #  6) parallel, no coverage, local hg:
    31 #      ./run-tests.py -j2 --local test-s*
    31 #      ./run-tests.py -j2 --local test-s*
    32 #  7) parallel, coverage, temp install:
    32 #  7) parallel, coverage, temp install:
    33 #      ./run-tests.py -j2 -c test-s*          # currently broken
    33 #      ./run-tests.py -j2 -c test-s*          # currently broken
    34 #  8) parallel, coverage, local install
    34 #  8) parallel, coverage, local install:
    35 #      ./run-tests.py -j2 -c --local test-s*  # unsupported (and broken)
    35 #      ./run-tests.py -j2 -c --local test-s*  # unsupported (and broken)
       
    36 #  9) parallel, custom tmp dir:
       
    37 #      ./run-tests.py -j2 --tmpdir /tmp/myhgtests
    36 #
    38 #
    37 # (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
    38 # 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
    39 # completes fairly quickly, includes both shell and Python scripts, and
    41 # completes fairly quickly, includes both shell and Python scripts, and
    40 # includes some scripts that run daemon processes.)
    42 # includes some scripts that run daemon processes.)
    41 
    43 
       
    44 from ConfigParser import ConfigParser
    42 import difflib
    45 import difflib
    43 import errno
    46 import errno
    44 import optparse
    47 import optparse
    45 import os
    48 import os
    46 import subprocess
    49 import subprocess
    88     parser.add_option("-i", "--interactive", action="store_true",
    91     parser.add_option("-i", "--interactive", action="store_true",
    89         help="prompt to accept changed output")
    92         help="prompt to accept changed output")
    90     parser.add_option("-j", "--jobs", type="int",
    93     parser.add_option("-j", "--jobs", type="int",
    91         help="number of jobs to run in parallel"
    94         help="number of jobs to run in parallel"
    92              " (default: $%s or %d)" % defaults['jobs'])
    95              " (default: $%s or %d)" % defaults['jobs'])
       
    96     parser.add_option("-k", "--keywords",
       
    97         help="run tests matching keywords")
    93     parser.add_option("--keep-tmpdir", action="store_true",
    98     parser.add_option("--keep-tmpdir", action="store_true",
    94         help="keep temporary directory after running tests"
    99         help="keep temporary directory after running tests")
    95              " (best used with --tmpdir)")
   100     parser.add_option("--tmpdir", type="string",
       
   101         help="run tests in the given temporary directory"
       
   102              " (implies --keep-tmpdir)")
       
   103     parser.add_option("-d", "--debug", action="store_true",
       
   104         help="debug mode: write output of test scripts to console"
       
   105              " rather than capturing and diff'ing it (disables timeout)")
    96     parser.add_option("-R", "--restart", action="store_true",
   106     parser.add_option("-R", "--restart", action="store_true",
    97         help="restart at last error")
   107         help="restart at last error")
    98     parser.add_option("-p", "--port", type="int",
   108     parser.add_option("-p", "--port", type="int",
    99         help="port on which servers should listen"
   109         help="port on which servers should listen"
   100              " (default: $%s or %d)" % defaults['port'])
   110              " (default: $%s or %d)" % defaults['port'])
   101     parser.add_option("-r", "--retest", action="store_true",
   111     parser.add_option("-r", "--retest", action="store_true",
   102         help="retest failed tests")
   112         help="retest failed tests")
   103     parser.add_option("-s", "--cover_stdlib", action="store_true",
   113     parser.add_option("-s", "--cover_stdlib", action="store_true",
   104         help="print a test coverage report inc. standard libraries")
   114         help="print a test coverage report inc. standard libraries")
       
   115     parser.add_option("-S", "--noskips", action="store_true",
       
   116         help="don't report skip tests verbosely")
   105     parser.add_option("-t", "--timeout", type="int",
   117     parser.add_option("-t", "--timeout", type="int",
   106         help="kill errant tests after TIMEOUT seconds"
   118         help="kill errant tests after TIMEOUT seconds"
   107              " (default: $%s or %d)" % defaults['timeout'])
   119              " (default: $%s or %d)" % defaults['timeout'])
   108     parser.add_option("--tmpdir", type="string",
       
   109         help="run tests in the given temporary directory")
       
   110     parser.add_option("-v", "--verbose", action="store_true",
   120     parser.add_option("-v", "--verbose", action="store_true",
   111         help="output verbose messages")
   121         help="output verbose messages")
   112     parser.add_option("-n", "--nodiff", action="store_true",
   122     parser.add_option("-n", "--nodiff", action="store_true",
   113         help="skip showing test changes")
   123         help="skip showing test changes")
   114     parser.add_option("--with-hg", type="string",
   124     parser.add_option("--with-hg", type="string",
   117              "temporary installation")
   127              "temporary installation")
   118     parser.add_option("--local", action="store_true",
   128     parser.add_option("--local", action="store_true",
   119         help="shortcut for --with-hg=<testdir>/../hg")
   129         help="shortcut for --with-hg=<testdir>/../hg")
   120     parser.add_option("--pure", action="store_true",
   130     parser.add_option("--pure", action="store_true",
   121         help="use pure Python code instead of C extensions")
   131         help="use pure Python code instead of C extensions")
       
   132     parser.add_option("-3", "--py3k-warnings", action="store_true",
       
   133         help="enable Py3k warnings on Python 2.6+")
       
   134     parser.add_option("--inotify", action="store_true",
       
   135         help="enable inotify extension when running tests")
       
   136     parser.add_option("--blacklist", action="append",
       
   137         help="skip tests listed in the specified section of "
       
   138              "the blacklist file")
   122 
   139 
   123     for option, default in defaults.items():
   140     for option, default in defaults.items():
   124         defaults[option] = int(os.environ.get(*default))
   141         defaults[option] = int(os.environ.get(*default))
   125     parser.set_defaults(**defaults)
   142     parser.set_defaults(**defaults)
   126     (options, args) = parser.parse_args()
   143     (options, args) = parser.parse_args()
   160             if pid:
   177             if pid:
   161                 print pid,
   178                 print pid,
   162             for m in msg:
   179             for m in msg:
   163                 print m,
   180                 print m,
   164             print
   181             print
       
   182             sys.stdout.flush()
   165     else:
   183     else:
   166         vlog = lambda *msg: None
   184         vlog = lambda *msg: None
   167 
   185 
       
   186     if options.tmpdir:
       
   187         options.tmpdir = os.path.expanduser(options.tmpdir)
       
   188 
   168     if options.jobs < 1:
   189     if options.jobs < 1:
   169         print >> sys.stderr, 'ERROR: -j/--jobs must be positive'
   190         parser.error('--jobs must be positive')
   170         sys.exit(1)
       
   171     if options.interactive and options.jobs > 1:
   191     if options.interactive and options.jobs > 1:
   172         print '(--interactive overrides --jobs)'
   192         print '(--interactive overrides --jobs)'
   173         options.jobs = 1
   193         options.jobs = 1
       
   194     if options.interactive and options.debug:
       
   195         parser.error("-i/--interactive and -d/--debug are incompatible")
       
   196     if options.debug:
       
   197         if options.timeout != defaults['timeout']:
       
   198             sys.stderr.write(
       
   199                 'warning: --timeout option ignored with --debug\n')
       
   200         options.timeout = 0
       
   201     if options.py3k_warnings:
       
   202         if sys.version_info[:2] < (2, 6) or sys.version_info[:2] >= (3, 0):
       
   203             parser.error('--py3k-warnings can only be used on Python 2.6+')
       
   204     if options.blacklist:
       
   205         configparser = ConfigParser()
       
   206         configparser.read("blacklist")
       
   207         blacklist = dict()
       
   208         for section in options.blacklist:
       
   209             for (item, value) in configparser.items(section):
       
   210                 blacklist["test-" + item] = section
       
   211         options.blacklist = blacklist
   174 
   212 
   175     return (options, args)
   213     return (options, args)
   176 
   214 
   177 def rename(src, dst):
   215 def rename(src, dst):
   178     """Like os.rename(), trade atomicity and opened files friendliness
   216     """Like os.rename(), trade atomicity and opened files friendliness
   211             line = line.splitlines()[0]
   249             line = line.splitlines()[0]
   212             failed.append(line[len(FAILED_PREFIX):])
   250             failed.append(line[len(FAILED_PREFIX):])
   213 
   251 
   214     return missing, failed
   252     return missing, failed
   215 
   253 
   216 def showdiff(expected, output):
   254 def showdiff(expected, output, ref, err):
   217     for line in difflib.unified_diff(expected, output,
   255     for line in difflib.unified_diff(expected, output, ref, err):
   218             "Expected output", "Test output"):
       
   219         sys.stdout.write(line)
   256         sys.stdout.write(line)
   220 
   257 
   221 def findprogram(program):
   258 def findprogram(program):
   222     """Search PATH for a executable program"""
   259     """Search PATH for a executable program"""
   223     for p in os.environ.get('PATH', os.defpath).split(os.pathsep):
   260     for p in os.environ.get('PATH', os.defpath).split(os.pathsep):
   264     vlog("# Performing temporary installation of HG")
   301     vlog("# Performing temporary installation of HG")
   265     installerrs = os.path.join("tests", "install.err")
   302     installerrs = os.path.join("tests", "install.err")
   266     pure = options.pure and "--pure" or ""
   303     pure = options.pure and "--pure" or ""
   267 
   304 
   268     # Run installer in hg root
   305     # Run installer in hg root
   269     os.chdir(os.path.join(os.path.dirname(sys.argv[0]), '..'))
   306     script = os.path.realpath(sys.argv[0])
       
   307     hgroot = os.path.dirname(os.path.dirname(script))
       
   308     os.chdir(hgroot)
       
   309     nohome = '--home=""'
       
   310     if os.name == 'nt':
       
   311         # The --home="" trick works only on OS where os.sep == '/'
       
   312         # because of a distutils convert_path() fast-path. Avoid it at
       
   313         # least on Windows for now, deal with .pydistutils.cfg bugs
       
   314         # when they happen.
       
   315         nohome = ''
   270     cmd = ('%s setup.py %s clean --all'
   316     cmd = ('%s setup.py %s clean --all'
   271            ' install --force --prefix="%s" --install-lib="%s"'
   317            ' install --force --prefix="%s" --install-lib="%s"'
   272            ' --install-scripts="%s" >%s 2>&1'
   318            ' --install-scripts="%s" %s >%s 2>&1'
   273            % (sys.executable, pure, INST, PYTHONDIR, BINDIR, installerrs))
   319            % (sys.executable, pure, INST, PYTHONDIR, BINDIR, nohome,
       
   320               installerrs))
   274     vlog("# Running", cmd)
   321     vlog("# Running", cmd)
   275     if os.system(cmd) == 0:
   322     if os.system(cmd) == 0:
   276         if not options.verbose:
   323         if not options.verbose:
   277             os.remove(installerrs)
   324             os.remove(installerrs)
   278     else:
   325     else:
   294             '    if line.startswith("diff "):\n'
   341             '    if line.startswith("diff "):\n'
   295             '        files += 1\n'
   342             '        files += 1\n'
   296             'sys.stdout.write("files patched: %d\\n" % files)\n')
   343             'sys.stdout.write("files patched: %d\\n" % files)\n')
   297     f.close()
   344     f.close()
   298     os.chmod(os.path.join(BINDIR, 'diffstat'), 0700)
   345     os.chmod(os.path.join(BINDIR, 'diffstat'), 0700)
       
   346 
       
   347     if options.py3k_warnings and not options.anycoverage:
       
   348         vlog("# Updating hg command to enable Py3k Warnings switch")
       
   349         f = open(os.path.join(BINDIR, 'hg'), 'r')
       
   350         lines = [line.rstrip() for line in f]
       
   351         lines[0] += ' -3'
       
   352         f.close()
       
   353         f = open(os.path.join(BINDIR, 'hg'), 'w')
       
   354         for line in lines:
       
   355             f.write(line + '\n')
       
   356         f.close()
   299 
   357 
   300     if options.anycoverage:
   358     if options.anycoverage:
   301         vlog("# Installing coverage wrapper")
   359         vlog("# Installing coverage wrapper")
   302         os.environ['COVERAGE_FILE'] = COVERAGE_FILE
   360         os.environ['COVERAGE_FILE'] = COVERAGE_FILE
   303         if os.path.exists(COVERAGE_FILE):
   361         if os.path.exists(COVERAGE_FILE):
   348 def alarmed(signum, frame):
   406 def alarmed(signum, frame):
   349     raise Timeout
   407     raise Timeout
   350 
   408 
   351 def run(cmd, options):
   409 def run(cmd, options):
   352     """Run command in a sub-process, capturing the output (stdout and stderr).
   410     """Run command in a sub-process, capturing the output (stdout and stderr).
   353     Return the exist code, and output."""
   411     Return a tuple (exitcode, output).  output is None in debug mode."""
   354     # TODO: Use subprocess.Popen if we're running on Python 2.4
   412     # TODO: Use subprocess.Popen if we're running on Python 2.4
       
   413     if options.debug:
       
   414         proc = subprocess.Popen(cmd, shell=True)
       
   415         ret = proc.wait()
       
   416         return (ret, None)
       
   417 
   355     if os.name == 'nt' or sys.platform.startswith('java'):
   418     if os.name == 'nt' or sys.platform.startswith('java'):
   356         tochild, fromchild = os.popen4(cmd)
   419         tochild, fromchild = os.popen4(cmd)
   357         tochild.close()
   420         tochild.close()
   358         output = fromchild.read()
   421         output = fromchild.read()
   359         ret = fromchild.close()
   422         ret = fromchild.close()
   386 
   449 
   387     def skip(msg):
   450     def skip(msg):
   388         if not options.verbose:
   451         if not options.verbose:
   389             skips.append((test, msg))
   452             skips.append((test, msg))
   390         else:
   453         else:
   391             print "\nSkipping %s: %s" % (test, msg)
   454             print "\nSkipping %s: %s" % (testpath, msg)
   392         return None
   455         return None
   393 
   456 
   394     def fail(msg):
   457     def fail(msg):
   395         fails.append((test, msg))
   458         fails.append((test, msg))
   396         if not options.nodiff:
   459         if not options.nodiff:
   397             print "\nERROR: %s %s" % (test, msg)
   460             print "\nERROR: %s %s" % (testpath, msg)
   398         return None
   461         return None
   399 
   462 
   400     vlog("# Test", test)
   463     vlog("# Test", test)
   401 
   464 
   402     # create a fresh hgrc
   465     # create a fresh hgrc
   403     hgrc = file(HGRCPATH, 'w+')
   466     hgrc = open(HGRCPATH, 'w+')
   404     hgrc.write('[ui]\n')
   467     hgrc.write('[ui]\n')
   405     hgrc.write('slash = True\n')
   468     hgrc.write('slash = True\n')
   406     hgrc.write('[defaults]\n')
   469     hgrc.write('[defaults]\n')
   407     hgrc.write('backout = -d "0 0"\n')
   470     hgrc.write('backout = -d "0 0"\n')
   408     hgrc.write('commit = -d "0 0"\n')
   471     hgrc.write('commit = -d "0 0"\n')
   409     hgrc.write('tag = -d "0 0"\n')
   472     hgrc.write('tag = -d "0 0"\n')
       
   473     if options.inotify:
       
   474         hgrc.write('[extensions]\n')
       
   475         hgrc.write('inotify=\n')
       
   476         hgrc.write('[inotify]\n')
       
   477         hgrc.write('pidfile=%s\n' % DAEMON_PIDS)
       
   478         hgrc.write('appendpid=True\n')
   410     hgrc.close()
   479     hgrc.close()
   411 
   480 
   412     err = os.path.join(TESTDIR, test+".err")
   481     err = os.path.join(TESTDIR, test+".err")
   413     ref = os.path.join(TESTDIR, test+".out")
   482     ref = os.path.join(TESTDIR, test+".out")
   414     testpath = os.path.join(TESTDIR, test)
   483     testpath = os.path.join(TESTDIR, test)
   428     except:
   497     except:
   429         firstline = ''
   498         firstline = ''
   430     lctest = test.lower()
   499     lctest = test.lower()
   431 
   500 
   432     if lctest.endswith('.py') or firstline == '#!/usr/bin/env python':
   501     if lctest.endswith('.py') or firstline == '#!/usr/bin/env python':
   433         cmd = '%s "%s"' % (PYTHON, testpath)
   502         py3kswitch = options.py3k_warnings and ' -3' or ''
       
   503         cmd = '%s%s "%s"' % (PYTHON, py3kswitch, testpath)
   434     elif lctest.endswith('.bat'):
   504     elif lctest.endswith('.bat'):
   435         # do not run batch scripts on non-windows
   505         # do not run batch scripts on non-windows
   436         if os.name != 'nt':
   506         if os.name != 'nt':
   437             return skip("batch script")
   507             return skip("batch script")
   438         # To reliably get the error code from batch files on WinXP,
   508         # To reliably get the error code from batch files on WinXP,
   460         signal.alarm(0)
   530         signal.alarm(0)
   461 
   531 
   462     mark = '.'
   532     mark = '.'
   463 
   533 
   464     skipped = (ret == SKIPPED_STATUS)
   534     skipped = (ret == SKIPPED_STATUS)
   465     # If reference output file exists, check test output against it
   535     # If we're not in --debug mode and reference output file exists,
   466     if os.path.exists(ref):
   536     # check test output against it.
       
   537     if options.debug:
       
   538         refout = None                   # to match out == None
       
   539     elif os.path.exists(ref):
   467         f = open(ref, "r")
   540         f = open(ref, "r")
   468         refout = splitnewlines(f.read())
   541         refout = splitnewlines(f.read())
   469         f.close()
   542         f.close()
   470     else:
   543     else:
   471         refout = []
   544         refout = []
       
   545 
   472     if skipped:
   546     if skipped:
   473         mark = 's'
   547         mark = 's'
   474         missing, failed = parsehghaveoutput(out)
   548         if out is None:                 # debug mode: nothing to parse
       
   549             missing = ['unknown']
       
   550             failed = None
       
   551         else:
       
   552             missing, failed = parsehghaveoutput(out)
   475         if not missing:
   553         if not missing:
   476             missing = ['irrelevant']
   554             missing = ['irrelevant']
   477         if failed:
   555         if failed:
   478             fail("hghave failed checking for %s" % failed[-1])
   556             fail("hghave failed checking for %s" % failed[-1])
   479             skipped = False
   557             skipped = False
   484         if ret:
   562         if ret:
   485             fail("output changed and returned error code %d" % ret)
   563             fail("output changed and returned error code %d" % ret)
   486         else:
   564         else:
   487             fail("output changed")
   565             fail("output changed")
   488         if not options.nodiff:
   566         if not options.nodiff:
   489             showdiff(refout, out)
   567             showdiff(refout, out, ref, err)
   490         ret = 1
   568         ret = 1
   491     elif ret:
   569     elif ret:
   492         mark = '!'
   570         mark = '!'
   493         fail("returned error code %d" % ret)
   571         fail("returned error code %d" % ret)
   494 
   572 
   495     if not options.verbose:
   573     if not options.verbose:
   496         sys.stdout.write(mark)
   574         sys.stdout.write(mark)
   497         sys.stdout.flush()
   575         sys.stdout.flush()
   498 
   576 
   499     if ret != 0 and not skipped:
   577     if ret != 0 and not skipped and not options.debug:
   500         # Save errors to a file for diagnosis
   578         # Save errors to a file for diagnosis
   501         f = open(err, "wb")
   579         f = open(err, "wb")
   502         for line in out:
   580         for line in out:
   503             f.write(line)
   581             f.write(line)
   504         f.close()
   582         f.close()
   505 
   583 
   506     # Kill off any leftover daemon processes
   584     # Kill off any leftover daemon processes
   507     try:
   585     try:
   508         fp = file(DAEMON_PIDS)
   586         fp = open(DAEMON_PIDS)
   509         for line in fp:
   587         for line in fp:
   510             try:
   588             try:
   511                 pid = int(line)
   589                 pid = int(line)
   512             except ValueError:
   590             except ValueError:
   513                 continue
   591                 continue
   588     for j, job in enumerate(jobs):
   666     for j, job in enumerate(jobs):
   589         if not job:
   667         if not job:
   590             continue
   668             continue
   591         rfd, wfd = os.pipe()
   669         rfd, wfd = os.pipe()
   592         childopts = ['--child=%d' % wfd, '--port=%d' % (options.port + j * 3)]
   670         childopts = ['--child=%d' % wfd, '--port=%d' % (options.port + j * 3)]
       
   671         childtmp = os.path.join(HGTMP, 'child%d' % j)
       
   672         childopts += ['--tmpdir', childtmp]
   593         cmdline = [PYTHON, sys.argv[0]] + opts + childopts + job
   673         cmdline = [PYTHON, sys.argv[0]] + opts + childopts + job
   594         vlog(' '.join(cmdline))
   674         vlog(' '.join(cmdline))
   595         fps[os.spawnvp(os.P_NOWAIT, cmdline[0], cmdline)] = os.fdopen(rfd, 'r')
   675         fps[os.spawnvp(os.P_NOWAIT, cmdline[0], cmdline)] = os.fdopen(rfd, 'r')
   596         os.close(wfd)
   676         os.close(wfd)
   597     failures = 0
   677     failures = 0
   612         skipped += skip
   692         skipped += skip
   613         failed += fail
   693         failed += fail
   614         vlog('pid %d exited, status %d' % (pid, status))
   694         vlog('pid %d exited, status %d' % (pid, status))
   615         failures |= status
   695         failures |= status
   616     print
   696     print
   617     for s in skips:
   697     if not options.noskips:
   618         print "Skipped %s: %s" % (s[0], s[1])
   698         for s in skips:
       
   699             print "Skipped %s: %s" % (s[0], s[1])
   619     for s in fails:
   700     for s in fails:
   620         print "Failed %s: %s" % (s[0], s[1])
   701         print "Failed %s: %s" % (s[0], s[1])
   621 
   702 
   622     _checkhglib("Tested")
   703     _checkhglib("Tested")
   623     print "# Ran %d tests, %d skipped, %d failed." % (
   704     print "# Ran %d tests, %d skipped, %d failed." % (
   657                 print "running all tests"
   738                 print "running all tests"
   658                 tests = orig
   739                 tests = orig
   659 
   740 
   660         skips = []
   741         skips = []
   661         fails = []
   742         fails = []
       
   743 
   662         for test in tests:
   744         for test in tests:
       
   745             if options.blacklist:
       
   746                 section = options.blacklist.get(test)
       
   747                 if section is not None:
       
   748                     skips.append((test, "blacklisted (%s section)" % section))
       
   749                     skipped += 1
       
   750                     continue
       
   751 
   663             if options.retest and not os.path.exists(test + ".err"):
   752             if options.retest and not os.path.exists(test + ".err"):
   664                 skipped += 1
   753                 skipped += 1
   665                 continue
   754                 continue
       
   755 
       
   756             if options.keywords:
       
   757                 t = open(test).read().lower() + test.lower()
       
   758                 for k in options.keywords.lower().split():
       
   759                     if k in t:
       
   760                         break
       
   761                 else:
       
   762                     skipped +=1
       
   763                     continue
       
   764 
   666             ret = runone(options, test, skips, fails)
   765             ret = runone(options, test, skips, fails)
   667             if ret is None:
   766             if ret is None:
   668                 skipped += 1
   767                 skipped += 1
   669             elif not ret:
   768             elif not ret:
   670                 if options.interactive:
   769                 if options.interactive:
   714 
   813 
   715         checktools()
   814         checktools()
   716 
   815 
   717     # Reset some environment variables to well-known values so that
   816     # Reset some environment variables to well-known values so that
   718     # the tests produce repeatable output.
   817     # the tests produce repeatable output.
   719     os.environ['LANG'] = os.environ['LC_ALL'] = 'C'
   818     os.environ['LANG'] = os.environ['LC_ALL'] = os.environ['LANGUAGE'] = 'C'
   720     os.environ['TZ'] = 'GMT'
   819     os.environ['TZ'] = 'GMT'
   721     os.environ["EMAIL"] = "Foo Bar <foo.bar@example.com>"
   820     os.environ["EMAIL"] = "Foo Bar <foo.bar@example.com>"
   722     os.environ['CDPATH'] = ''
   821     os.environ['CDPATH'] = ''
       
   822     os.environ['COLUMNS'] = '80'
   723 
   823 
   724     global TESTDIR, HGTMP, INST, BINDIR, PYTHONDIR, COVERAGE_FILE
   824     global TESTDIR, HGTMP, INST, BINDIR, PYTHONDIR, COVERAGE_FILE
   725     TESTDIR = os.environ["TESTDIR"] = os.getcwd()
   825     TESTDIR = os.environ["TESTDIR"] = os.getcwd()
   726     HGTMP = os.environ['HGTMP'] = os.path.realpath(tempfile.mkdtemp('', 'hgtests.',
   826     if options.tmpdir:
   727                                                    options.tmpdir))
   827         options.keep_tmpdir = True
       
   828         tmpdir = options.tmpdir
       
   829         if os.path.exists(tmpdir):
       
   830             # Meaning of tmpdir has changed since 1.3: we used to create
       
   831             # HGTMP inside tmpdir; now HGTMP is tmpdir.  So fail if
       
   832             # tmpdir already exists.
       
   833             sys.exit("error: temp dir %r already exists" % tmpdir)
       
   834 
       
   835             # Automatically removing tmpdir sounds convenient, but could
       
   836             # really annoy anyone in the habit of using "--tmpdir=/tmp"
       
   837             # or "--tmpdir=$HOME".
       
   838             #vlog("# Removing temp dir", tmpdir)
       
   839             #shutil.rmtree(tmpdir)
       
   840         os.makedirs(tmpdir)
       
   841     else:
       
   842         tmpdir = tempfile.mkdtemp('', 'hgtests.')
       
   843     HGTMP = os.environ['HGTMP'] = os.path.realpath(tmpdir)
   728     DAEMON_PIDS = None
   844     DAEMON_PIDS = None
   729     HGRCPATH = None
   845     HGRCPATH = None
   730 
   846 
   731     os.environ["HGEDITOR"] = sys.executable + ' -c "import sys; sys.exit(0)"'
   847     os.environ["HGEDITOR"] = sys.executable + ' -c "import sys; sys.exit(0)"'
   732     os.environ["HGMERGE"] = "internal:merge"
   848     os.environ["HGMERGE"] = "internal:merge"