##// END OF EJS Templates
tests: extract test-template-keywords.t from test-command-template.t
tests: extract test-template-keywords.t from test-command-template.t

File last commit:

r38309:b5651ae5 @38 default
r38455:da4508cd default
Show More
run-tests.py
3138 lines | 115.3 KiB | text/x-python | PythonLexer
Stephen Darnell
Add a pure python version of run-tests....
r2110 #!/usr/bin/env python
#
# run-tests.py - Run a set of tests on Mercurial
#
# Copyright 2006 Matt Mackall <mpm@selenic.com>
#
Martin Geisler
updated license to be explicit about GPL version 2
r8225 # This software may be used and distributed according to the terms of the
Matt Mackall
Update license to GPLv2+
r10263 # GNU General Public License version 2 or any later version.
Stephen Darnell
Add a pure python version of run-tests....
r2110
Greg Ward
run-tests: redefine --with-hg so it takes the 'hg' script to run....
r8674 # Modifying this script is tricky because it has many modes:
# - serial (default) vs parallel (-jN, N > 1)
# - no coverage (default) vs coverage (-c, -C, -s)
# - temp install (default) vs specific hg script (--with-hg, --local)
# - tests are a mix of shell scripts and Python scripts
#
# If you change this script, it is recommended that you ensure you
# haven't broken it by running it in various modes with a representative
# sample of test scripts. For example:
Dirkjan Ochtman
kill trailing whitespace
r8843 #
Greg Ward
run-tests: redefine --with-hg so it takes the 'hg' script to run....
r8674 # 1) serial, no coverage, temp install:
# ./run-tests.py test-s*
# 2) serial, no coverage, local hg:
# ./run-tests.py --local test-s*
# 3) serial, coverage, temp install:
# ./run-tests.py -c test-s*
# 4) serial, coverage, local hg:
# ./run-tests.py -c --local test-s* # unsupported
# 5) parallel, no coverage, temp install:
# ./run-tests.py -j2 test-s*
# 6) parallel, no coverage, local hg:
# ./run-tests.py -j2 --local test-s*
# 7) parallel, coverage, temp install:
# ./run-tests.py -j2 -c test-s* # currently broken
Greg Ward
run-tests: give each child its own tmp dir (issue1911)...
r9899 # 8) parallel, coverage, local install:
Greg Ward
run-tests: redefine --with-hg so it takes the 'hg' script to run....
r8674 # ./run-tests.py -j2 -c --local test-s* # unsupported (and broken)
Greg Ward
run-tests: give each child its own tmp dir (issue1911)...
r9899 # 9) parallel, custom tmp dir:
# ./run-tests.py -j2 --tmpdir /tmp/myhgtests
timeless@mozdev.org
run-tests: use $HGTEST_RUN_TESTS_PURE...
r26158 # 10) parallel, pure, tests that call run-tests:
# ./run-tests.py --pure `grep -l run-tests.py *.t`
Greg Ward
run-tests: redefine --with-hg so it takes the 'hg' script to run....
r8674 #
# (You could use any subset of the tests: test-s* happens to match
# enough that it's worth doing parallel runs, few enough that it
# completes fairly quickly, includes both shell and Python scripts, and
# includes some scripts that run daemon processes.)
Pulkit Goyal
py3: make files use absolute_import and print_function...
r29485 from __future__ import absolute_import, print_function
Augie Fackler
python3: update killdaemons and run-tests print and exception syntax...
r25031
Gregory Szorc
run-tests: convert to argparse...
r35188 import argparse
Gregory Szorc
run-tests: mechanism to report exceptions during test execution...
r35191 import collections
Vadim Gelfer
tests: add timeouts, make run-tests.py clean up dead daemon processes...
r2571 import difflib
Pulkit Goyal
py3: make files use absolute_import and print_function...
r29485 import distutils.version as version
Vadim Gelfer
tests: add timeouts, make run-tests.py clean up dead daemon processes...
r2571 import errno
Yuya Nishihara
tests: load json with no fallback...
r28126 import json
Vadim Gelfer
tests: add timeouts, make run-tests.py clean up dead daemon processes...
r2571 import os
Pulkit Goyal
py3: make files use absolute_import and print_function...
r29485 import random
import re
Nicolas Dumazet
pylint, pyflakes: remove unused or duplicate imports
r10905 import shutil
Vadim Gelfer
tests: add timeouts, make run-tests.py clean up dead daemon processes...
r2571 import signal
Pierre-Yves David
run-test: ensure the test ports are available before launching test...
r24967 import socket
Pulkit Goyal
py3: make files use absolute_import and print_function...
r29485 import subprocess
Vadim Gelfer
tests: add timeouts, make run-tests.py clean up dead daemon processes...
r2571 import sys
Martin von Zweigbergk
run-tests: drop fallback for sysconfig for pre-py2.7
r32302 import sysconfig
Stephen Darnell
Add a pure python version of run-tests....
r2110 import tempfile
Pulkit Goyal
py3: make files use absolute_import and print_function...
r29485 import threading
Vadim Gelfer
tests: add timeouts, make run-tests.py clean up dead daemon processes...
r2571 import time
Pulkit Goyal
py3: make files use absolute_import and print_function...
r29485 import unittest
import xml.dom.minidom as minidom
Augie Fackler
python3: update killdaemons and run-tests print and exception syntax...
r25031 try:
import Queue as queue
except ImportError:
import queue
Stephen Darnell
Add a pure python version of run-tests....
r2110
Adam Simpkins
tests: more completely restore the environment in syshgenv...
r33121 try:
import shlex
shellquote = shlex.quote
except (ImportError, AttributeError):
import pipes
shellquote = pipes.quote
timeless
run-tests: add support for RTUNICODEPEDANTRY environment variable...
r29282 if os.environ.get('RTUNICODEPEDANTRY', False):
try:
reload(sys)
sys.setdefaultencoding("undefined")
except NameError:
pass
Yuya Nishihara
tests: actually restore the original environment before running syshg...
r33198 origenviron = os.environ.copy()
Augie Fackler
run-tests: introduce a name for os.environb...
r25037 osenvironb = getattr(os, 'environb', os.environ)
Matt Mackall
run-tests: do chdir for tests under a lock for thread safety
r14019 processlock = threading.Lock()
Brendan Cully
run-tests: lock popen wait/poll...
r19413
Pulkit Goyal
run-tests: make sure to check if pygments is installed before using it...
r33552 pygmentspresent = False
Matt Harbison
run-tests: disable color on Windows...
r33500 # ANSI color is unsupported prior to Windows 10
if os.name != 'nt':
try: # is pygments installed
import pygments
import pygments.lexers as lexers
Matthieu Laneuville
run-tests: also color the summary messages (skipped, failed...)
r33813 import pygments.lexer as lexer
Matt Harbison
run-tests: disable color on Windows...
r33500 import pygments.formatters as formatters
Matthieu Laneuville
run-tests: also color the summary messages (skipped, failed...)
r33813 import pygments.token as token
import pygments.style as style
Pulkit Goyal
run-tests: make sure to check if pygments is installed before using it...
r33552 pygmentspresent = True
Jun Wu
run-tests: pre instantiate pygments objects...
r33581 difflexer = lexers.DiffLexer()
terminal256formatter = formatters.Terminal256Formatter()
Matt Harbison
run-tests: disable color on Windows...
r33500 except ImportError:
pass
Matthieu Laneuville
run-tests: add color to output if pygments is available...
r33420
Matthieu Laneuville
run-tests: also color the summary messages (skipped, failed...)
r33813 if pygmentspresent:
class TestRunnerStyle(style.Style):
default_style = ""
skipped = token.string_to_tokentype("Token.Generic.Skipped")
failed = token.string_to_tokentype("Token.Generic.Failed")
skippedname = token.string_to_tokentype("Token.Generic.SName")
failedname = token.string_to_tokentype("Token.Generic.FName")
styles = {
skipped: '#e5e5e5',
skippedname: '#00ffff',
failed: '#7f0000',
failedname: '#ff0000',
}
class TestRunnerLexer(lexer.RegexLexer):
Boris Feld
run-tests: restrict the test cases allowed characters...
r38309 testpattern = r'[\w-]+\.(t|py)(#[a-zA-Z0-9_\-\.]+)?'
Matthieu Laneuville
run-tests: also color the summary messages (skipped, failed...)
r33813 tokens = {
'root': [
(r'^Skipped', token.Generic.Skipped, 'skipped'),
(r'^Failed ', token.Generic.Failed, 'failed'),
(r'^ERROR: ', token.Generic.Failed, 'failed'),
],
'skipped': [
Martin von Zweigbergk
testrunner: on error, color the "(case xxx)" part the same as filename...
r35866 (testpattern, token.Generic.SName),
Matthieu Laneuville
run-tests: also color the summary messages (skipped, failed...)
r33813 (r':.*', token.Generic.Skipped),
],
'failed': [
Martin von Zweigbergk
testrunner: on error, color the "(case xxx)" part the same as filename...
r35866 (testpattern, token.Generic.FName),
Matthieu Laneuville
run-tests: also color the summary messages (skipped, failed...)
r33813 (r'(:| ).*', token.Generic.Failed),
]
}
Matthieu Laneuville
run-tests: pre instantiate pygments objects...
r33868 runnerformatter = formatters.Terminal256Formatter(style=TestRunnerStyle)
runnerlexer = TestRunnerLexer()
Augie Fackler
run-tests: insist that if people use Python 3, they use 3.5.x...
r25160 if sys.version_info > (3, 5, 0):
Augie Fackler
run-tests: introduce PYTHON3 boolean constant (issue4668)...
r25157 PYTHON3 = True
Augie Fackler
run-tests: work around the rename of xrange to range
r25033 xrange = range # we use xrange in one place, and we'd rather not use range
Augie Fackler
run-tests: move unicode-to-bytes operations on paths to a helper (issue4667)...
r25161 def _bytespath(p):
Augie Fackler
tests: fix up test-run-tests failures on Python 3.6...
r33676 if p is None:
return p
Augie Fackler
run-tests: move unicode-to-bytes operations on paths to a helper (issue4667)...
r25161 return p.encode('utf-8')
Augie Fackler
run-tests: replace open-coded .decode()s on paths with a helper (issue4667)...
r25162
def _strpath(p):
Augie Fackler
tests: fix up test-run-tests failures on Python 3.6...
r33676 if p is None:
return p
Augie Fackler
run-tests: replace open-coded .decode()s on paths with a helper (issue4667)...
r25162 return p.decode('utf-8')
Augie Fackler
run-tests: insist that if people use Python 3, they use 3.5.x...
r25160 elif sys.version_info >= (3, 0, 0):
Gregory Szorc
run-tests: remove references to Python 2.6...
r32353 print('%s is only supported on Python 3.5+ and 2.7, not %s' %
Augie Fackler
run-tests: insist that if people use Python 3, they use 3.5.x...
r25160 (sys.argv[0], '.'.join(str(v) for v in sys.version_info[:3])))
sys.exit(70) # EX_SOFTWARE from `man 3 sysexit`
Augie Fackler
run-tests: introduce PYTHON3 boolean constant (issue4668)...
r25157 else:
PYTHON3 = False
Augie Fackler
run-tests: replace open-coded .decode()s on paths with a helper (issue4667)...
r25162
# In python 2.x, path operations are generally done using
# bytestrings by default, so we don't have to do any extra
# fiddling there. We define the wrapper functions anyway just to
# help keep code consistent between platforms.
Augie Fackler
run-tests: move unicode-to-bytes operations on paths to a helper (issue4667)...
r25161 def _bytespath(p):
return p
Augie Fackler
run-tests: work around the rename of xrange to range
r25033
Augie Fackler
run-tests: replace open-coded .decode()s on paths with a helper (issue4667)...
r25162 _strpath = _bytespath
Matt Harbison
run-tests: resurrect the wifexited polyfill (backout 6ab5a1c9ea3c)...
r25177 # For Windows support
wifexited = getattr(os, "WIFEXITED", lambda x: False)
Jun Wu
runtests: add a function to test if IPv6 is available...
r30984 # Whether to use IPv6
Jun Wu
runtests: prefer IPv4 to IPv6...
r31002 def checksocketfamily(name, port=20058):
"""return true if we can listen on localhost using family=name
name should be either 'AF_INET', or 'AF_INET6'.
port being used is okay - EADDRINUSE is considered as successful.
"""
family = getattr(socket, name, None)
Jun Wu
runtests: add a function to test if IPv6 is available...
r30984 if family is None:
return False
try:
s = socket.socket(family, socket.SOCK_STREAM)
s.bind(('localhost', port))
s.close()
return True
except socket.error as exc:
if exc.errno == errno.EADDRINUSE:
return True
elif exc.errno in (errno.EADDRNOTAVAIL, errno.EPROTONOSUPPORT):
return False
else:
raise
else:
return False
Jun Wu
runtests: add an IPv6 command line flag...
r31011 # useipv6 will be set by parseargs
useipv6 = None
Jun Wu
runtests: add a function to test if IPv6 is available...
r30984
Pierre-Yves David
run-test: ensure the test ports are available before launching test...
r24967 def checkportisavailable(port):
"""return true if a port seems free to bind on localhost"""
Jun Wu
runtests: checkportisavailable should only check one family...
r30985 if useipv6:
family = socket.AF_INET6
else:
family = socket.AF_INET
Jun Wu
runtests: unindent an "if True" block...
r30987 try:
s = socket.socket(family, socket.SOCK_STREAM)
s.bind(('localhost', port))
s.close()
return True
except socket.error as exc:
if exc.errno not in (errno.EADDRINUSE, errno.EADDRNOTAVAIL,
errno.EPROTONOSUPPORT):
raise
Jun Wu
runtests: check ports on IPv6 address...
r30886 return False
Pierre-Yves David
run-test: ensure the test ports are available before launching test...
r24967
Martin Geisler
util: always use subprocess
r8280 closefds = os.name == 'posix'
Matt Mackall
run-tests: add env dict to isolate test environment
r19262 def Popen4(cmd, wd, timeout, env=None):
Matt Mackall
run-tests: do chdir for tests under a lock for thread safety
r14019 processlock.acquire()
Matt Mackall
run-tests: add env dict to isolate test environment
r19262 p = subprocess.Popen(cmd, shell=True, bufsize=-1, cwd=wd, env=env,
Martin Geisler
util: always use subprocess
r8280 close_fds=closefds,
stdin=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
Matt Mackall
run-tests: do chdir for tests under a lock for thread safety
r14019 processlock.release()
Martin Geisler
util: always use subprocess
r8280 p.fromchild = p.stdout
p.tochild = p.stdin
p.childerr = p.stderr
Matt Mackall
run-tests: switch timeout handling from alarm to helper thread...
r14001
Patrick Mezard
run-tests: ignore timeout when Popen.terminate is unavailable...
r14337 p.timeout = False
Matt Mackall
run-tests: switch timeout handling from alarm to helper thread...
r14001 if timeout:
def t():
start = time.time()
while time.time() - start < timeout and p.returncode is None:
Matt Mackall
tests: shorten post-test sleeps...
r16346 time.sleep(.1)
Matt Mackall
run-tests: switch timeout handling from alarm to helper thread...
r14001 p.timeout = True
if p.returncode is None:
Thomas Arendsen Hein
run-tests: fallback to SIGTERM if subprocess.Popen does not have terminate()
r14821 terminate(p)
Matt Mackall
run-tests: switch timeout handling from alarm to helper thread...
r14001 threading.Thread(target=t).start()
Martin Geisler
util: always use subprocess
r8280 return p
Augie Fackler
run-tests: move unicode-to-bytes operations on paths to a helper (issue4667)...
r25161 PYTHON = _bytespath(sys.executable.replace('\\', '/'))
Augie Fackler
run-tests: even more bytestring annotations for Python 3
r25041 IMPL_PATH = b'PYTHONPATH'
Ronny Pfannschmidt
tests: adapt the test runner to work with jython
r10758 if 'java' in sys.platform:
Augie Fackler
run-tests: even more bytestring annotations for Python 3
r25041 IMPL_PATH = b'JYTHONPATH'
Patrick Mezard
Add hghave utility and run-tests.py support....
r4881
Thomas Arendsen Hein
run-tests.py: Allow environment variables to set jobs/timeout/port.
r6366 defaults = {
'jobs': ('HGTEST_JOBS', 1),
'timeout': ('HGTEST_TIMEOUT', 180),
timeless
run-tests: add --slowtimeout and use it for slow tests
r27141 'slowtimeout': ('HGTEST_SLOWTIMEOUT', 500),
Thomas Arendsen Hein
run-tests.py: Allow environment variables to set jobs/timeout/port.
r6366 'port': ('HGTEST_PORT', 20059),
Mads Kiilerich
tests: let run-tests.py default to use 'sh' in $PATH instead of '/bin/sh'...
r15941 'shell': ('HGTEST_SHELL', 'sh'),
Thomas Arendsen Hein
run-tests.py: Allow environment variables to set jobs/timeout/port.
r6366 }
timeless
run-tests: add canonpath function...
r28644 def canonpath(path):
return os.path.realpath(os.path.expanduser(path))
Augie Fackler
run-tests: allow whitelisting tests that should always run...
r14493 def parselistfiles(files, listtype, warn=True):
entries = dict()
for filename in files:
try:
path = os.path.expanduser(os.path.expandvars(filename))
Augie Fackler
run-tests: write out scripts in binary mode...
r21916 f = open(path, "rb")
Augie Fackler
python3: update killdaemons and run-tests print and exception syntax...
r25031 except IOError as err:
Augie Fackler
run-tests: allow whitelisting tests that should always run...
r14493 if err.errno != errno.ENOENT:
raise
if warn:
Augie Fackler
python3: update killdaemons and run-tests print and exception syntax...
r25031 print("warning: no such %s file: %s" % (listtype, filename))
Augie Fackler
run-tests: allow whitelisting tests that should always run...
r14493 continue
for line in f.readlines():
Augie Fackler
run-tests: even more bytestring annotations for Python 3
r25041 line = line.split(b'#', 1)[0].strip()
Augie Fackler
run-tests: allow whitelisting tests that should always run...
r14493 if line:
entries[line] = filename
f.close()
return entries
Jun Wu
run-tests: support multiple cases in .t test...
r32317 def parsettestcases(path):
"""read a .t test file, return a set of test case names
If path does not exist, return an empty set.
"""
cases = set()
try:
with open(path, 'rb') as f:
for l in f:
if l.startswith(b'#testcases '):
cases.update(l[11:].split())
except IOError as ex:
if ex.errno != errno.ENOENT:
raise
return cases
Gregory Szorc
run-tests: allow option parser to be extended...
r21008 def getparser():
Gregory Szorc
run-tests: add some docstrings
r21383 """Obtain the OptionParser used by the CLI."""
Gregory Szorc
run-tests: convert to argparse...
r35188 parser = argparse.ArgumentParser(usage='%(prog)s [options] [tests]')
Matt Mackall
run-tests: sort options
r11039
Gregory Szorc
run-tests: organize options into argument groups...
r35189 selection = parser.add_argument_group('Test Selection')
selection.add_argument('--allow-slow-tests', action='store_true',
help='allow extremely slow tests')
selection.add_argument("--blacklist", action="append",
Matt Mackall
run-tests: sort options
r11039 help="skip tests listed in the specified blacklist file")
Gregory Szorc
run-tests: organize options into argument groups...
r35189 selection.add_argument("--changed",
Mads Kiilerich
tests: add run-tests --changed option for running tests changed in revisions...
r20821 help="run tests that are changed in parent rev or working directory")
Gregory Szorc
run-tests: organize options into argument groups...
r35189 selection.add_argument("-k", "--keywords",
help="run tests matching keywords")
selection.add_argument("-r", "--retest", action="store_true",
help = "retest failed tests")
selection.add_argument("--test-list", action="append",
help="read tests to run from the specified file")
selection.add_argument("--whitelist", action="append",
Augie Fackler
run-tests: allow whitelisting tests that should always run...
r14493 help="always run tests listed in the specified whitelist file")
Gregory Szorc
run-tests: organize options into argument groups...
r35189 selection.add_argument('tests', metavar='TESTS', nargs='*',
help='Tests to run')
harness = parser.add_argument_group('Test Harness Behavior')
harness.add_argument('--bisect-repo',
metavar='bisect_repo',
help=("Path of a repo to bisect. Use together with "
"--known-good-rev"))
harness.add_argument("-d", "--debug", action="store_true",
Matt Mackall
run-tests: sort options
r11039 help="debug mode: write output of test scripts to console"
Mads Kiilerich
spelling: fixes from spell checker
r21024 " rather than capturing and diffing it (disables timeout)")
Gregory Szorc
run-tests: organize options into argument groups...
r35189 harness.add_argument("-f", "--first", action="store_true",
Greg Ward
run-tests: factor out parse_args(). Clarify use of globals a bit.
r8091 help="exit on the first test failure")
Gregory Szorc
run-tests: organize options into argument groups...
r35189 harness.add_argument("-i", "--interactive", action="store_true",
Greg Ward
run-tests: factor out parse_args(). Clarify use of globals a bit.
r8091 help="prompt to accept changed output")
Gregory Szorc
run-tests: organize options into argument groups...
r35189 harness.add_argument("-j", "--jobs", type=int,
Greg Ward
run-tests: factor out parse_args(). Clarify use of globals a bit.
r8091 help="number of jobs to run in parallel"
" (default: $%s or %d)" % defaults['jobs'])
Gregory Szorc
run-tests: organize options into argument groups...
r35189 harness.add_argument("--keep-tmpdir", action="store_true",
Greg Ward
run-tests: make --tmpdir option more useful....
r9706 help="keep temporary directory after running tests")
Gregory Szorc
run-tests: organize options into argument groups...
r35189 harness.add_argument('--known-good-rev',
metavar="known_good_rev",
help=("Automatically bisect any failures using this "
"revision as a known-good revision."))
harness.add_argument("--list-tests", action="store_true",
Siddharth Agarwal
run-tests: add a way to list tests, with JSON and XUnit support...
r32704 help="list tests instead of running them")
Gregory Szorc
run-tests: organize options into argument groups...
r35189 harness.add_argument("--loop", action="store_true",
help="loop tests repeatedly")
harness.add_argument('--random', action="store_true",
help='run tests in random order')
Martin von Zweigbergk
testrunner: add option to sort tests by previous run time...
r36683 harness.add_argument('--order-by-runtime', action="store_true",
help='run slowest tests first, according to .testtimes')
Gregory Szorc
run-tests: organize options into argument groups...
r35189 harness.add_argument("-p", "--port", type=int,
help="port on which servers should listen"
" (default: $%s or %d)" % defaults['port'])
harness.add_argument('--profile-runner', action='store_true',
help='run statprof on run-tests')
harness.add_argument("-R", "--restart", action="store_true",
help="restart at last error")
harness.add_argument("--runs-per-test", type=int, dest="runs_per_test",
help="run each test N times (default=1)", default=1)
harness.add_argument("--shell",
help="shell to use (default: $%s or %s)" % defaults['shell'])
harness.add_argument('--showchannels', action='store_true',
help='show scheduling channels')
harness.add_argument("--slowtimeout", type=int,
help="kill errant slow tests after SLOWTIMEOUT seconds"
" (default: $%s or %d)" % defaults['slowtimeout'])
harness.add_argument("-t", "--timeout", type=int,
help="kill errant tests after TIMEOUT seconds"
" (default: $%s or %d)" % defaults['timeout'])
harness.add_argument("--tmpdir",
help="run tests in the given temporary directory"
" (implies --keep-tmpdir)")
harness.add_argument("-v", "--verbose", action="store_true",
help="output verbose messages")
hgconf = parser.add_argument_group('Mercurial Configuration')
hgconf.add_argument("--chg", action="store_true",
help="install and use chg wrapper in place of hg")
hgconf.add_argument("--compiler",
help="compiler to build with")
Gregory Szorc
run-tests: mechanism to report exceptions during test execution...
r35191 hgconf.add_argument('--extra-config-opt', action="append", default=[],
Gregory Szorc
run-tests: organize options into argument groups...
r35189 help='set the given config opt in the test hgrc')
hgconf.add_argument("-l", "--local", action="store_true",
Jun Wu
run-tests: make --local set --with-chg if --chg is used...
r29583 help="shortcut for --with-hg=<testdir>/../hg, "
"and --with-chg=<testdir>/../contrib/chg/chg if --chg is set")
Gregory Szorc
run-tests: organize options into argument groups...
r35189 hgconf.add_argument("--ipv6", action="store_true",
help="prefer IPv6 to IPv4 for network related tests")
hgconf.add_argument("--pure", action="store_true",
Matt Mackall
run-tests: sort options
r11039 help="use pure Python code instead of C extensions")
Gregory Szorc
run-tests: organize options into argument groups...
r35189 hgconf.add_argument("-3", "--py3k-warnings", action="store_true",
help="enable Py3k warnings on Python 2.7+")
hgconf.add_argument("--with-chg", metavar="CHG",
help="use specified chg wrapper in place of hg")
hgconf.add_argument("--with-hg",
Greg Ward
run-tests: redefine --with-hg so it takes the 'hg' script to run....
r8674 metavar="HG",
help="test using specified hg script rather than a "
"temporary installation")
Gregory Szorc
run-tests: add --with-python3 to define a Python 3 interpreter...
r28582 # This option should be deleted once test-check-py3-compat.t and other
# Python 3 tests run with Python 3.
Gregory Szorc
run-tests: organize options into argument groups...
r35189 hgconf.add_argument("--with-python3", metavar="PYTHON3",
help="Python 3 interpreter (if running under Python 2)"
" (TEMPORARY)")
reporting = parser.add_argument_group('Results Reporting')
reporting.add_argument("-C", "--annotate", action="store_true",
help="output files annotated with coverage")
reporting.add_argument("--color", choices=["always", "auto", "never"],
default=os.environ.get('HGRUNTESTSCOLOR', 'auto'),
help="colorisation: always|auto|never (default: auto)")
reporting.add_argument("-c", "--cover", action="store_true",
help="print a test coverage report")
Gregory Szorc
run-tests: mechanism to report exceptions during test execution...
r35191 reporting.add_argument('--exceptions', action='store_true',
help='log all exceptions and generate an exception report')
Gregory Szorc
run-tests: organize options into argument groups...
r35189 reporting.add_argument("-H", "--htmlcov", action="store_true",
help="create an HTML report of the coverage of the files")
reporting.add_argument("--json", action="store_true",
help="store test result data in 'report.json' file")
reporting.add_argument("--outputdir",
help="directory to write error logs to (default=test directory)")
reporting.add_argument("-n", "--nodiff", action="store_true",
help="skip showing test changes")
reporting.add_argument("-S", "--noskips", action="store_true",
help="don't report skip tests verbosely")
reporting.add_argument("--time", action="store_true",
help="time how long each test takes")
reporting.add_argument("--view",
help="external diff viewer")
reporting.add_argument("--xunit",
help="record xunit results at specified path")
Stephen Darnell
Add a pure python version of run-tests....
r2110
Martin Geisler
run-tests: use type of default to convert environment variable...
r14201 for option, (envvar, default) in defaults.items():
defaults[option] = type(default)(os.environ.get(envvar, default))
Greg Ward
run-tests: factor out parse_args(). Clarify use of globals a bit.
r8091 parser.set_defaults(**defaults)
Gregory Szorc
run-tests: allow option parser to be extended...
r21008
return parser
def parseargs(args, parser):
Gregory Szorc
run-tests: add some docstrings
r21383 """Parse arguments with our OptionParser and validate results."""
Gregory Szorc
run-tests: convert to argparse...
r35188 options = parser.parse_args(args)
Greg Ward
run-tests: factor out parse_args(). Clarify use of globals a bit.
r8091
Ronny Pfannschmidt
tests: adapt the test runner to work with jython
r10758 # jython is always pure
Ronny Pfannschmidt
run-tests: force to test pure on pypy as well
r10766 if 'java' in sys.platform or '__pypy__' in sys.modules:
Ronny Pfannschmidt
Fix run-tests.py -jX after 2ed667a9dfcb
r10765 options.pure = True
Ronny Pfannschmidt
tests: adapt the test runner to work with jython
r10758
Greg Ward
run-tests: redefine --with-hg so it takes the 'hg' script to run....
r8674 if options.with_hg:
timeless
run-tests: add canonpath function...
r28644 options.with_hg = canonpath(_bytespath(options.with_hg))
Greg Ward
run-tests: redefine --with-hg so it takes the 'hg' script to run....
r8674 if not (os.path.isfile(options.with_hg) and
os.access(options.with_hg, os.X_OK)):
parser.error('--with-hg must specify an executable hg script')
Kostia Balytskyi
run-tests: allow hg executable to be hg.exe...
r32328 if os.path.basename(options.with_hg) not in [b'hg', b'hg.exe']:
Thomas Arendsen Hein
run-tests: print a newline after all warnings
r14359 sys.stderr.write('warning: --with-hg should specify an hg script\n')
Greg Ward
run-tests: redefine --with-hg so it takes the 'hg' script to run....
r8674 if options.local:
timeless
run-tests: add canonpath function...
r28644 testdir = os.path.dirname(_bytespath(canonpath(sys.argv[0])))
Jun Wu
run-tests: allow --local to set multiple attributes...
r29582 reporootdir = os.path.dirname(testdir)
pathandattrs = [(b'hg', 'with_hg')]
Jun Wu
run-tests: make --local set --with-chg if --chg is used...
r29583 if options.chg:
pathandattrs.append((b'contrib/chg/chg', 'with_chg'))
Jun Wu
run-tests: allow --local to set multiple attributes...
r29582 for relpath, attr in pathandattrs:
binpath = os.path.join(reporootdir, relpath)
if os.name != 'nt' and not os.access(binpath, os.X_OK):
parser.error('--local specified, but %r not found or '
'not executable' % binpath)
setattr(options, attr, binpath)
Greg Ward
run-tests: redefine --with-hg so it takes the 'hg' script to run....
r8674
Yuya Nishihara
run-tests: add --chg option to install and run tests using chg...
r28143 if (options.chg or options.with_chg) and os.name == 'nt':
parser.error('chg does not work on %s' % os.name)
Yuya Nishihara
run-tests: add --with-chg option to run tests using chg...
r28142 if options.with_chg:
Yuya Nishihara
run-tests: add --chg option to install and run tests using chg...
r28143 options.chg = False # no installation to temporary location
timeless
run-tests: add canonpath function...
r28644 options.with_chg = canonpath(_bytespath(options.with_chg))
Yuya Nishihara
run-tests: add --with-chg option to run tests using chg...
r28142 if not (os.path.isfile(options.with_chg) and
os.access(options.with_chg, os.X_OK)):
parser.error('--with-chg must specify a chg executable')
Yuya Nishihara
run-tests: add --chg option to install and run tests using chg...
r28143 if options.chg and options.with_hg:
# chg shares installation location with hg
parser.error('--chg does not work when --with-hg is specified '
'(use --with-chg instead)')
Yuya Nishihara
run-tests: add --with-chg option to run tests using chg...
r28142
Martin von Zweigbergk
run-tests: warn if --color=always and no pygments installed...
r33567 if options.color == 'always' and not pygmentspresent:
sys.stderr.write('warning: --color=always ignored because '
'pygments is not installed\n')
Jun Wu
run-tests: allow bisecting a different repo...
r34043 if options.bisect_repo and not options.known_good_rev:
parser.error("--bisect-repo cannot be used without --known-good-rev")
Jun Wu
runtests: add an IPv6 command line flag...
r31011 global useipv6
if options.ipv6:
useipv6 = checksocketfamily('AF_INET6')
else:
# only use IPv6 if IPv4 is unavailable and IPv6 is available
useipv6 = ((not checksocketfamily('AF_INET'))
and checksocketfamily('AF_INET6'))
Markus Zapke-Gründemann
tests: add htmlcov option
r15859 options.anycoverage = options.cover or options.annotate or options.htmlcov
Dirkjan Ochtman
tests: use external coverage, mandate newer version...
r10648 if options.anycoverage:
try:
import coverage
covver = version.StrictVersion(coverage.__version__).version
if covver < (3, 3):
parser.error('coverage options require coverage 3.3 or later')
except ImportError:
parser.error('coverage options now require the coverage package')
Greg Ward
run-tests: reduce global variables set by parse_args().
r8095
Dirkjan Ochtman
tests: use external coverage, mandate newer version...
r10648 if options.anycoverage and options.local:
# this needs some path mangling somewhere, I guess
parser.error("sorry, coverage options do not work when --local "
"is specified")
Greg Ward
run-tests: redefine --with-hg so it takes the 'hg' script to run....
r8674
Gregory Szorc
run-tests: report code coverage from source directory...
r24506 if options.anycoverage and options.with_hg:
parser.error("sorry, coverage options do not work when --with-hg "
"is specified")
Matt Mackall
run-tests: make vlog a proper function
r19250 global verbose
Greg Ward
run-tests: reduce global variables set by parse_args().
r8095 if options.verbose:
Matt Mackall
run-tests: drop options.child and users
r19279 verbose = ''
Greg Ward
run-tests: factor out parse_args(). Clarify use of globals a bit.
r8091
Nicolas Dumazet
run-tests: expand --tmpdir and create it if needed
r9394 if options.tmpdir:
timeless
run-tests: add canonpath function...
r28644 options.tmpdir = canonpath(options.tmpdir)
Nicolas Dumazet
run-tests: expand --tmpdir and create it if needed
r9394
Greg Ward
run-tests: factor out parse_args(). Clarify use of globals a bit.
r8091 if options.jobs < 1:
Martin Geisler
run-tests: standardize on --foo instead of -f/--foo...
r9408 parser.error('--jobs must be positive')
Greg Ward
run-tests: add "debug" mode: don't capture child output, just show it....
r9707 if options.interactive and options.debug:
parser.error("-i/--interactive and -d/--debug are incompatible")
if options.debug:
if options.timeout != defaults['timeout']:
sys.stderr.write(
'warning: --timeout option ignored with --debug\n')
timeless
run-tests: add --slowtimeout and use it for slow tests
r27141 if options.slowtimeout != defaults['slowtimeout']:
sys.stderr.write(
'warning: --slowtimeout option ignored with --debug\n')
Greg Ward
run-tests: add "debug" mode: don't capture child output, just show it....
r9707 options.timeout = 0
timeless
run-tests: add --slowtimeout and use it for slow tests
r27141 options.slowtimeout = 0
Alejandro Santos
tests: add -3 switch to run-tests.py
r9028 if options.py3k_warnings:
Augie Fackler
run-tests: prefer PYTHON3 constant to many version_info checks (issue4668)...
r25158 if PYTHON3:
parser.error(
Gregory Szorc
run-tests: remove references to Python 2.6...
r32353 '--py3k-warnings can only be used on Python 2.7')
Gregory Szorc
run-tests: add --with-python3 to define a Python 3 interpreter...
r28582 if options.with_python3:
if PYTHON3:
parser.error('--with-python3 cannot be used when executing with '
'Python 3')
timeless
run-tests: use canonpath for with-python3
r28645 options.with_python3 = canonpath(options.with_python3)
Gregory Szorc
run-tests: add --with-python3 to define a Python 3 interpreter...
r28582 # Verify Python3 executable is acceptable.
proc = subprocess.Popen([options.with_python3, b'--version'],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
out, _err = proc.communicate()
ret = proc.wait()
if ret != 0:
parser.error('could not determine version of python 3')
if not out.startswith('Python '):
parser.error('unexpected output from python3 --version: %s' %
out)
vers = version.LooseVersion(out[len('Python '):])
if vers < version.LooseVersion('3.5.0'):
parser.error('--with-python3 version must be 3.5.0 or greater; '
'got %s' % out)
Nicolas Dumazet
run-tests: add a "--blacklist target" option to skip predefined test lists...
r9959 if options.blacklist:
Augie Fackler
run-tests: allow whitelisting tests that should always run...
r14493 options.blacklist = parselistfiles(options.blacklist, 'blacklist')
if options.whitelist:
Matt Mackall
run-tests: drop options.child and users
r19279 options.whitelisted = parselistfiles(options.whitelist, 'whitelist')
Augie Fackler
run-tests: allow whitelisting tests that should always run...
r14493 else:
options.whitelisted = {}
Greg Ward
run-tests: factor out parse_args(). Clarify use of globals a bit.
r8091
Matt Mackall
run-tests: show scheduling with --showchannels...
r27396 if options.showchannels:
options.nodiff = True
Gregory Szorc
run-tests: convert to argparse...
r35188 return options
Bryan O'Sullivan
Allow tests to run in parallel.
r5384
Patrick Mezard
Make run-tests.py --interactive work on Windows
r5800 def rename(src, dst):
"""Like os.rename(), trade atomicity and opened files friendliness
for existing destination support.
"""
shutil.copy(src, dst)
os.remove(src)
Augie Fackler
run-tests: use difflib.diff_bytes on Python 3...
r25045 _unified_diff = difflib.unified_diff
Augie Fackler
run-tests: move all open-coded sys.version_info checks to PYTHON3 (issue4668)...
r25159 if PYTHON3:
Augie Fackler
run-tests: use difflib.diff_bytes on Python 3...
r25045 import functools
_unified_diff = functools.partial(difflib.diff_bytes, difflib.unified_diff)
Gregory Szorc
run-tests: move diff generation into TestResult...
r21521 def getdiff(expected, output, ref, err):
Simon Heimberg
run-tests: test result shows when a failed test could not start a server...
r21022 servefail = False
Gregory Szorc
run-tests: move diff generation into TestResult...
r21521 lines = []
Augie Fackler
run-tests: use difflib.diff_bytes on Python 3...
r25045 for line in _unified_diff(expected, output, ref, err):
if line.startswith(b'+++') or line.startswith(b'---'):
line = line.replace(b'\\', b'/')
if line.endswith(b' \n'):
line = line[:-2] + b'\n'
Gregory Szorc
run-tests: move diff generation into TestResult...
r21521 lines.append(line)
Simon Heimberg
run-tests: test result shows when a failed test could not start a server...
r21022 if not servefail and line.startswith(
Augie Fackler
run-tests: use difflib.diff_bytes on Python 3...
r25045 b'+ abort: child process failed to start'):
Simon Heimberg
run-tests: test result shows when a failed test could not start a server...
r21022 servefail = True
Gregory Szorc
run-tests: move diff generation into TestResult...
r21521 return servefail, lines
Stephen Darnell
Add a pure python version of run-tests....
r2110
Matt Mackall
run-tests: make vlog a proper function
r19250 verbose = False
def vlog(*msg):
Gregory Szorc
run-tests: avoid duplicate code in vlog()
r21535 """Log only when in verbose mode."""
if verbose is False:
return
return log(*msg)
Matt Mackall
run-tests: make vlog a proper function
r19250
Augie Fackler
run-tests: add support for xunit test reports...
r22044 # Bytes that break XML even in a CDATA block: control characters 0-31
# sans \t, \n and \r
Augie Fackler
run-tests: do cdata escaping using bytes instead of str
r25051 CDATA_EVIL = re.compile(br"[\000-\010\013\014\016-\037]")
Augie Fackler
run-tests: add support for xunit test reports...
r22044
Matt Harbison
run-tests: support per-line conditional output in tests...
r31829 # Match feature conditionalized output lines in the form, capturing the feature
# list in group 2, and the preceeding line output in group 1:
#
# output..output (feature !)\n
Jun Wu
test-logtoprocess: make it compatible with chg...
r34445 optline = re.compile(b'(.*) \((.+?) !\)\n$')
Matt Harbison
run-tests: support per-line conditional output in tests...
r31829
Augie Fackler
run-tests: add support for xunit test reports...
r22044 def cdatasafe(data):
"""Make a string safe to include in a CDATA block.
Certain control characters are illegal in a CDATA block, and
there's no way to include a ]]> in a CDATA either. This function
replaces illegal bytes with ? and adds a space between the ]] so
that it won't break the CDATA block.
"""
Augie Fackler
run-tests: do cdata escaping using bytes instead of str
r25051 return CDATA_EVIL.sub(b'?', data).replace(b']]>', b'] ]>')
Augie Fackler
run-tests: add support for xunit test reports...
r22044
Matt Mackall
run-tests: add a log function
r19251 def log(*msg):
Gregory Szorc
run-tests: avoid duplicate code in vlog()
r21535 """Log something to stdout.
Arguments are strings to print.
"""
Augie Fackler
run-tests: switch all uses of iolock.acquire() to a context manager
r25046 with iolock:
if verbose:
print(verbose, end=' ')
for m in msg:
print(m, end=' ')
print()
sys.stdout.flush()
Matt Mackall
run-tests: add a log function
r19251
Yuya Nishihara
run-tests: factor out highlight functions
r33931 def highlightdiff(line, color):
if not color:
return line
assert pygmentspresent
Yuya Nishihara
run-tests: pass unicode to Pygments...
r33932 return pygments.highlight(line.decode('latin1'), difflexer,
terminal256formatter).encode('latin1')
Yuya Nishihara
run-tests: factor out highlight functions
r33931
def highlightmsg(msg, color):
if not color:
return msg
assert pygmentspresent
return pygments.highlight(msg, runnerlexer, runnerformatter)
Thomas Arendsen Hein
run-tests: fallback to SIGTERM if subprocess.Popen does not have terminate()
r14821 def terminate(proc):
Martin von Zweigbergk
run-tests: drop fallback for proc.terminate() for pre-py2.6
r32303 """Terminate subprocess"""
Thomas Arendsen Hein
run-tests: fallback to SIGTERM if subprocess.Popen does not have terminate()
r14821 vlog('# Terminating process %d' % proc.pid)
try:
Martin von Zweigbergk
run-tests: drop fallback for proc.terminate() for pre-py2.6
r32303 proc.terminate()
Thomas Arendsen Hein
run-tests: fallback to SIGTERM if subprocess.Popen does not have terminate()
r14821 except OSError:
pass
Matt Mackall
run-tests: use env dict to kill daemons
r19263 def killdaemons(pidfile):
Pulkit Goyal
py3: make files use absolute_import and print_function...
r29485 import killdaemons as killmod
Matt Mackall
run-tests: use env dict to kill daemons
r19263 return killmod.killdaemons(pidfile, tryhard=False, remove=True,
Patrick Mezard
run-tests: do not duplicate killdaemons() code
r17464 logfn=vlog)
Brendan Cully
run-tests: kill daemons on ^C with -j....
r10336
Gregory Szorc
run-tests: merge MercurialTest into Test...
r21488 class Test(unittest.TestCase):
Gregory Szorc
run-tests: allow Test.run() to run multiple times...
r21309 """Encapsulates a single, runnable test.
Gregory Szorc
run-tests: refactor temporary directories in Test...
r21497 While this class conforms to the unittest.TestCase API, it differs in that
instances need to be instantiated manually. (Typically, unittest.TestCase
classes are instantiated automatically by scanning modules.)
Gregory Szorc
run-tests: allow Test.run() to run multiple times...
r21309 """
Gregory Szorc
run-tests: create classes for representing tests...
r21296
Gregory Szorc
run-tests: move SKIPPED_STATUS into Test class
r21380 # Status code reserved for skipped tests (used by hghave).
SKIPPED_STATUS = 80
Siddharth Agarwal
run-tests: allow specifying an output dir to write .errs to...
r32716 def __init__(self, path, outputdir, tmpdir, keeptmpdir=False,
Gregory Szorc
run-tests: move diff generation into TestResult...
r21521 debug=False,
Jun Wu
test-run-tests: stabilize the test (issue5735)...
r35586 first=False,
Augie Fackler
tests: fix run-tests default values in Test constructor...
r34265 timeout=None,
startport=None, extraconfigopts=None,
Yuya Nishihara
run-tests: allow to specify executable of any name by --with-hg...
r28099 py3kwarnings=False, shell=None, hgcommand=None,
Augie Fackler
tests: fix run-tests default values in Test constructor...
r34265 slowtimeout=None, usechg=False,
Jun Wu
runtests: set web.ipv6 if we use IPv6...
r30986 useipv6=False):
Gregory Szorc
run-tests: pass a full test path into Test.__init__...
r21502 """Create a test from parameters.
path is the full path to the file defining the test.
Gregory Szorc
run-tests: move computation of test paths into Test.__init__
r21338
Gregory Szorc
run-tests: pass temp dir into Test.__init__...
r21504 tmpdir is the main temporary directory to use for this test.
Gregory Szorc
run-tests: pass abort into Test.__init__
r21505
Gregory Szorc
run-tests: factor options.keep_tmpdir into an argument to Test.__init__
r21509 keeptmpdir determines whether to keep the test's temporary directory
after execution. It defaults to removal (False).
Gregory Szorc
run-tests: move debug into an argument to Test.__init__
r21510
debug mode will make the test execute verbosely, with unfiltered
output.
Gregory Szorc
run-tests: move diff options into arguments of Test.__init__
r21511
Gregory Szorc
run-tests: move timeout into Test.__init__
r21513 timeout controls the maximum run time of the test. It is ignored when
timeless
run-tests: add --slowtimeout and use it for slow tests
r27141 debug is True. See slowtimeout for tests with #require slow.
slowtimeout overrides timeout if the test has #require slow.
Gregory Szorc
run-tests: refactor port number declaration...
r21514
startport controls the starting port number to use for this test. Each
test will reserve 3 port numbers for execution. It is the caller's
responsibility to allocate a non-overlapping port range to Test
instances.
Gregory Szorc
run-tests: move extra config options to Test.__init__
r21515
extraconfigopts is an iterable of extra hgrc config options. Values
must have the form "key=value" (something understood by hgrc). Values
of the form "foo.key=value" will result in "[foo] key=value".
Gregory Szorc
run-tests: move py3kwarnings to Test.__init__
r21516
py3kwarnings enables Py3k warnings.
Gregory Szorc
run-tests: move shell to Test.__init__
r21517
shell is the shell to execute tests in.
Gregory Szorc
run-tests: pass a full test path into Test.__init__...
r21502 """
Augie Fackler
tests: fix run-tests default values in Test constructor...
r34265 if timeout is None:
timeout = defaults['timeout']
if startport is None:
startport = defaults['port']
if slowtimeout is None:
slowtimeout = defaults['slowtimeout']
Augie Fackler
run-tests: be more judicious about bytes vs string on test attrs...
r25039 self.path = path
self.bname = os.path.basename(path)
Augie Fackler
run-tests: replace open-coded .decode()s on paths with a helper (issue4667)...
r25162 self.name = _strpath(self.bname)
Gregory Szorc
run-tests: pass a full test path into Test.__init__...
r21502 self._testdir = os.path.dirname(path)
Siddharth Agarwal
run-tests: allow specifying an output dir to write .errs to...
r32716 self._outputdir = outputdir
Jun Wu
run-tests: support multiple cases in .t test...
r32317 self._tmpname = os.path.basename(path)
Siddharth Agarwal
run-tests: allow specifying an output dir to write .errs to...
r32716 self.errpath = os.path.join(self._outputdir, b'%s.err' % self.bname)
Gregory Szorc
run-tests: rename Test._test to Test.name...
r21435
Augie Fackler
run-tests: be more judicious about bytes vs string on test attrs...
r25039 self._threadtmp = tmpdir
Gregory Szorc
run-tests: factor options.keep_tmpdir into an argument to Test.__init__
r21509 self._keeptmpdir = keeptmpdir
Gregory Szorc
run-tests: move debug into an argument to Test.__init__
r21510 self._debug = debug
Jun Wu
test-run-tests: stabilize the test (issue5735)...
r35586 self._first = first
Gregory Szorc
run-tests: move timeout into Test.__init__
r21513 self._timeout = timeout
timeless
run-tests: add --slowtimeout and use it for slow tests
r27141 self._slowtimeout = slowtimeout
Gregory Szorc
run-tests: refactor port number declaration...
r21514 self._startport = startport
Gregory Szorc
run-tests: move extra config options to Test.__init__
r21515 self._extraconfigopts = extraconfigopts or []
Gregory Szorc
run-tests: move py3kwarnings to Test.__init__
r21516 self._py3kwarnings = py3kwarnings
Augie Fackler
run-tests: move unicode-to-bytes operations on paths to a helper (issue4667)...
r25161 self._shell = _bytespath(shell)
Yuya Nishihara
run-tests: allow to specify executable of any name by --with-hg...
r28099 self._hgcommand = hgcommand or b'hg'
Jun Wu
run-tests: use different chg socket directories for different tests...
r28620 self._usechg = usechg
Jun Wu
runtests: export HGIPV6 to hint test scripts whether to use IPv6...
r31003 self._useipv6 = useipv6
Gregory Szorc
run-tests: remove global abort flag...
r21520
self._aborted = False
Gregory Szorc
run-tests: kill daemons during Test.cleanup()...
r21319 self._daemonpids = []
Gregory Szorc
run-tests: keep track of test execution state in Test...
r21447 self._finished = None
Gregory Szorc
run-tests: store test return code and output in Test instance...
r21449 self._ret = None
self._out = None
Gregory Szorc
run-tests: store skipped state on Test...
r21453 self._skipped = None
Gregory Szorc
run-tests: refactor testtmp...
r21454 self._testtmp = None
Jun Wu
run-tests: use different chg socket directories for different tests...
r28620 self._chgsockdir = None
Gregory Szorc
run-tests: keep track of test execution state in Test...
r21447
Jun Wu
run-tests: do not prompt changes (-i) if a race condition is detected...
r32980 self._refout = self.readrefout()
def readrefout(self):
"""read reference output"""
Gregory Szorc
run-tests: capture reference output in Test.__init__...
r21318 # If we're not in --debug mode and reference output file exists,
# check test output against it.
Jun Wu
run-tests: do not prompt changes (-i) if a race condition is detected...
r32980 if self._debug:
return None # to match "out is None"
Gregory Szorc
run-tests: move diff generation into TestResult...
r21521 elif os.path.exists(self.refpath):
Jun Wu
run-tests: do not prompt changes (-i) if a race condition is detected...
r32980 with open(self.refpath, 'rb') as f:
return f.read().splitlines(True)
Gregory Szorc
run-tests: capture reference output in Test.__init__...
r21318 else:
Jun Wu
run-tests: do not prompt changes (-i) if a race condition is detected...
r32980 return []
Gregory Szorc
run-tests: capture reference output in Test.__init__...
r21318
Pierre-Yves David
run-tests: implement Test._testMethodName...
r24965 # needed to get base class __repr__ running
@property
def _testMethodName(self):
return self.name
Gregory Szorc
run-tests: implement Test.__str__...
r21463 def __str__(self):
return self.name
Gregory Szorc
run-tests: merge MercurialTest into Test...
r21488 def shortDescription(self):
return self.name
Gregory Szorc
run-tests: support setUp() and tearDown() in TestCase wrapper...
r21446 def setUp(self):
"""Tasks to perform before run()."""
Gregory Szorc
run-tests: keep track of test execution state in Test...
r21447 self._finished = False
Gregory Szorc
run-tests: store test return code and output in Test instance...
r21449 self._ret = None
self._out = None
Gregory Szorc
run-tests: store skipped state on Test...
r21453 self._skipped = None
Gregory Szorc
run-tests: support setUp() and tearDown() in TestCase wrapper...
r21446
Gregory Szorc
run-tests: refactor temporary directories in Test...
r21497 try:
os.mkdir(self._threadtmp)
Augie Fackler
python3: update killdaemons and run-tests print and exception syntax...
r25031 except OSError as e:
Gregory Szorc
run-tests: refactor temporary directories in Test...
r21497 if e.errno != errno.EEXIST:
raise
Jun Wu
run-tests: support multiple cases in .t test...
r32317 name = self._tmpname
Jun Wu
run-tests: use different chg socket directories for different tests...
r28620 self._testtmp = os.path.join(self._threadtmp, name)
Gregory Szorc
run-tests: refactor testtmp...
r21454 os.mkdir(self._testtmp)
Gregory Szorc
run-tests: move errpath deletion to setUp()
r21457 # Remove any previous output files.
Gregory Szorc
run-tests: move test filtering into TestSuite.run()...
r21507 if os.path.exists(self.errpath):
Augie Fackler
run-tests: ignore ENOENT failures when removing old .err results...
r24332 try:
os.remove(self.errpath)
Augie Fackler
python3: update killdaemons and run-tests print and exception syntax...
r25031 except OSError as e:
Augie Fackler
run-tests: ignore ENOENT failures when removing old .err results...
r24332 # We might have raced another test to clean up a .err
# file, so ignore ENOENT when removing a previous .err
# file.
if e.errno != errno.ENOENT:
raise
Gregory Szorc
run-tests: move errpath deletion to setUp()
r21457
Jun Wu
run-tests: use different chg socket directories for different tests...
r28620 if self._usechg:
self._chgsockdir = os.path.join(self._threadtmp,
b'%s.chgsock' % name)
os.mkdir(self._chgsockdir)
Gregory Szorc
run-tests: merge MercurialTest into Test...
r21488 def run(self, result):
Gregory Szorc
run-tests: add docstrings
r21536 """Run this test and report results against a TestResult instance."""
# This function is extremely similar to unittest.TestCase.run(). Once
# we require Python 2.7 (or at least its version of unittest), this
# function can largely go away.
Gregory Szorc
run-tests: move diff generation into TestResult...
r21521 self._result = result
Gregory Szorc
run-tests: merge MercurialTest into Test...
r21488 result.startTest(self)
try:
try:
self.setUp()
except (KeyboardInterrupt, SystemExit):
Gregory Szorc
run-tests: remove global abort flag...
r21520 self._aborted = True
Gregory Szorc
run-tests: merge MercurialTest into Test...
r21488 raise
except Exception:
result.addError(self, sys.exc_info())
return
success = False
try:
self.runTest()
except KeyboardInterrupt:
Gregory Szorc
run-tests: remove global abort flag...
r21520 self._aborted = True
Gregory Szorc
run-tests: merge MercurialTest into Test...
r21488 raise
Gregory Szorc
tests: use unittest.SkipTest...
r32932 except unittest.SkipTest as e:
Gregory Szorc
run-tests: merge MercurialTest into Test...
r21488 result.addSkip(self, str(e))
Augie Fackler
run-tests: fix test result counts with --keyword specified or skips occurring...
r21997 # The base class will have already counted this as a
# test we "ran", but we want to exclude skipped tests
# from those we count towards those run.
result.testsRun -= 1
Augie Fackler
python3: update killdaemons and run-tests print and exception syntax...
r25031 except self.failureException as e:
Gregory Szorc
run-tests: merge MercurialTest into Test...
r21488 # This differs from unittest in that we don't capture
# the stack trace. This is for historical reasons and
Mads Kiilerich
spelling: fixes from proofreading of spell checker issues
r23139 # this decision could be revisited in the future,
Gregory Szorc
run-tests: merge MercurialTest into Test...
r21488 # especially for PythonTest instances.
anuraggoel
run-tests: checks behaviour of test on failure while testing...
r21753 if result.addFailure(self, str(e)):
success = True
Gregory Szorc
run-tests: merge MercurialTest into Test...
r21488 except Exception:
result.addError(self, sys.exc_info())
else:
success = True
try:
self.tearDown()
except (KeyboardInterrupt, SystemExit):
Gregory Szorc
run-tests: remove global abort flag...
r21520 self._aborted = True
Gregory Szorc
run-tests: merge MercurialTest into Test...
r21488 raise
except Exception:
result.addError(self, sys.exc_info())
success = False
if success:
result.addSuccess(self)
finally:
Gregory Szorc
run-tests: remove global abort flag...
r21520 result.stopTest(self, interrupted=self._aborted)
Gregory Szorc
run-tests: merge MercurialTest into Test...
r21488
def runTest(self):
Gregory Szorc
run-tests: add some docstrings
r21383 """Run this test instance.
This will return a tuple describing the result of the test.
"""
Gregory Szorc
run-tests: refactor port number declaration...
r21514 env = self._getenv()
Adam Simpkins
tests: more completely restore the environment in syshgenv...
r33121 self._genrestoreenv(env)
Gregory Szorc
run-tests: kill daemons during Test.cleanup()...
r21319 self._daemonpids.append(env['DAEMON_PIDS'])
Gregory Szorc
run-tests: move createhgrc into Test
r21382 self._createhgrc(env['HGRCPATH'])
Gregory Szorc
run-tests: move createhgrc() call into Test.run()...
r21300
Gregory Szorc
run-tests: rename Test._test to Test.name...
r21435 vlog('# Test', self.name)
Gregory Szorc
run-tests: move logging of test start into Test.run()
r21337
Gregory Szorc
run-tests: obtain replacements inside Test._runcommand...
r24516 ret, out = self._run(env)
Gregory Szorc
run-tests: don't trap exceptions in Test.runTest()...
r21500 self._finished = True
self._ret = ret
self._out = out
Gregory Szorc
run-tests: capture execution results in a TestResult class...
r21305
Gregory Szorc
run-tests: move output difference processing to Test.run()
r21326 def describe(ret):
if ret < 0:
return 'killed by signal: %d' % -ret
return 'returned error code %d' % ret
Gregory Szorc
run-tests: store skipped state on Test...
r21453 self._skipped = False
Gregory Szorc
run-tests: remove remaining uses of TestResult
r21336
Gregory Szorc
run-tests: move SKIPPED_STATUS into Test class
r21380 if ret == self.SKIPPED_STATUS:
Gregory Szorc
run-tests: add skip processing to Test
r21324 if out is None: # Debug mode, nothing to parse.
missing = ['unknown']
failed = None
else:
Gregory Szorc
run-tests: move parsehghaveoutput() into TTest...
r21379 missing, failed = TTest.parsehghaveoutput(out)
Gregory Szorc
run-tests: add skip processing to Test
r21324
if not missing:
Mads Kiilerich
run-tests: report skipped tests as "skipped" - they might still be "relevant"
r22292 missing = ['skipped']
Gregory Szorc
run-tests: add skip processing to Test
r21324
if failed:
Gregory Szorc
run-tests: move interactive test acceptance into TestResult...
r21523 self.fail('hg have failed checking for %s' % failed[-1])
Gregory Szorc
run-tests: add skip processing to Test
r21324 else:
Gregory Szorc
run-tests: store skipped state on Test...
r21453 self._skipped = True
Gregory Szorc
tests: use unittest.SkipTest...
r32932 raise unittest.SkipTest(missing[-1])
Gregory Szorc
run-tests: generate timeout result in Test.run()
r21325 elif ret == 'timeout':
Gregory Szorc
run-tests: move interactive test acceptance into TestResult...
r21523 self.fail('timed out')
Gregory Szorc
run-tests: raise WarnTest outside of Test.fail()
r21522 elif ret is False:
Gregory Szorc
tests: remove WarnTest...
r32934 self.fail('no result code from test')
Gregory Szorc
run-tests: move output difference processing to Test.run()
r21326 elif out != self._refout:
Gregory Szorc
run-tests: write .err files earlier...
r21614 # Diff generation may rely on written .err file.
if (ret != 0 or out != self._refout) and not self._skipped \
and not self._debug:
Matt Harbison
run-tests: use context managers for file descriptors...
r35466 with open(self.errpath, 'wb') as f:
for line in out:
f.write(line)
Gregory Szorc
run-tests: write .err files earlier...
r21614
Gregory Szorc
run-tests: move diff generation into TestResult...
r21521 # The result object handles diff calculation for us.
Jun Wu
test-run-tests: stabilize the test (issue5735)...
r35586 with firstlock:
if self._result.addOutputMismatch(self, ret, out, self._refout):
# change was accepted, skip failing
return
if self._first:
global firsterror
firsterror = True
Gregory Szorc
run-tests: move diff generation into TestResult...
r21521
Gregory Szorc
run-tests: move output difference processing to Test.run()
r21326 if ret:
Gregory Szorc
run-tests: move diff generation into TestResult...
r21521 msg = 'output changed and ' + describe(ret)
Gregory Szorc
run-tests: move output difference processing to Test.run()
r21326 else:
Gregory Szorc
run-tests: move diff generation into TestResult...
r21521 msg = 'output changed'
Gregory Szorc
run-tests: move output difference processing to Test.run()
r21326
Gregory Szorc
run-tests: move interactive test acceptance into TestResult...
r21523 self.fail(msg)
Gregory Szorc
run-tests: move remaining result processing to Test.run()
r21327 elif ret:
Gregory Szorc
run-tests: move interactive test acceptance into TestResult...
r21523 self.fail(describe(ret))
Gregory Szorc
run-tests: add skip processing to Test
r21324
Gregory Szorc
run-tests: support setUp() and tearDown() in TestCase wrapper...
r21446 def tearDown(self):
"""Tasks to perform after run()."""
Gregory Szorc
run-tests: kill daemons during tearDown()
r21456 for entry in self._daemonpids:
killdaemons(entry)
self._daemonpids = []
timeless@mozdev.org
run-tests: report paths saved by --keep-tmpdir
r26422 if self._keeptmpdir:
log('\nKeeping testtmp dir: %s\nKeeping threadtmp dir: %s' %
Gregory Szorc
run-tests: fix Python 3 incompatibilities...
r28284 (self._testtmp.decode('utf-8'),
self._threadtmp.decode('utf-8')))
timeless@mozdev.org
run-tests: report paths saved by --keep-tmpdir
r26422 else:
Gregory Szorc
run-tests: ignore failures from rmtree...
r21461 shutil.rmtree(self._testtmp, True)
Gregory Szorc
run-tests: refactor temporary directories in Test...
r21497 shutil.rmtree(self._threadtmp, True)
Gregory Szorc
run-tests: refactor testtmp...
r21454
Jun Wu
run-tests: use different chg socket directories for different tests...
r28620 if self._usechg:
# chgservers will stop automatically after they find the socket
# files are deleted
shutil.rmtree(self._chgsockdir, True)
Gregory Szorc
run-tests: move err file writing to tearDown()
r21455 if (self._ret != 0 or self._out != self._refout) and not self._skipped \
Gregory Szorc
run-tests: move debug into an argument to Test.__init__
r21510 and not self._debug and self._out:
Matt Harbison
run-tests: use context managers for file descriptors...
r35466 with open(self.errpath, 'wb') as f:
for line in self._out:
f.write(line)
Gregory Szorc
run-tests: move err file writing to tearDown()
r21455
Pierre-Yves David
run-test: include test name in the return vlog...
r24926 vlog("# Ret was:", self._ret, '(%s)' % self.name)
Gregory Szorc
run-tests: move some functionality to Test.tearDown()
r21452
Gregory Szorc
run-tests: obtain replacements inside Test._runcommand...
r24516 def _run(self, env):
Gregory Szorc
run-tests: refactor runone() into gettest() and scheduletests()...
r21339 # This should be implemented in child classes to run tests.
Gregory Szorc
tests: use unittest.SkipTest...
r32932 raise unittest.SkipTest('unknown test type')
Gregory Szorc
run-tests: create classes for representing tests...
r21296
Gregory Szorc
run-tests: remove global abort flag...
r21520 def abort(self):
"""Terminate execution of this test."""
self._aborted = True
timeless
run-tests: refactor port allocation into functions...
r28169 def _portmap(self, i):
Gregory Szorc
run-tests: fix Python 3 incompatibilities...
r28284 offset = b'' if i == 0 else b'%d' % i
timeless
run-tests: refactor port allocation into functions...
r28169 return (br':%d\b' % (self._startport + i), b':$HGPORT%s' % offset)
Gregory Szorc
run-tests: refactor testtmp...
r21454 def _getreplacements(self):
Gregory Szorc
run-tests: add docstrings
r21536 """Obtain a mapping of text replacements to apply to test output.
Test output needs to be normalized so it can be compared to expected
output. This function defines how some of that normalization will
occur.
"""
Gregory Szorc
run-tests: move replacements generation into Test...
r21298 r = [
timeless
run-tests: refactor port allocation into functions...
r28169 # This list should be parallel to defineport in _getenv
self._portmap(0),
self._portmap(1),
self._portmap(2),
Jun Wu
tests: use LOCALIP...
r31008 (br'([^0-9])%s' % re.escape(self._localip()), br'\1$LOCALIP'),
Pierre-Yves David
run-tests: auto-replace 'TXNID' output...
r31741 (br'\bHG_TXNID=TXN:[a-f0-9]{40}\b', br'HG_TXNID=TXN:$ID$'),
Gregory Szorc
run-tests: move replacements generation into Test...
r21298 ]
timeless
run-tests: factor out _escapepath
r28055 r.append((self._escapepath(self._testtmp), b'$TESTTMP'))
Gregory Szorc
run-tests: move replacements generation into Test...
r21298
Martin von Zweigbergk
run-tests: avoid calculating _testdir again...
r35195 replacementfile = os.path.join(self._testdir, b'common-pattern.py')
Boris Feld
run-tests: allow to register any arbitrary pattern for replacement...
r35068
if os.path.exists(replacementfile):
data = {}
Boris Feld
run-test: drop 'execfile' usage for 'common-pattern.py' file...
r35091 with open(replacementfile, mode='rb') as source:
# the intermediate 'compile' step help with debugging
code = compile(source.read(), replacementfile, 'exec')
exec(code, data)
Boris Feld
tests: raise a better error when patterns are wrongly formatted...
r36009 for value in data.get('substitutions', ()):
if len(value) != 2:
msg = 'malformatted substitution in %s: %r'
msg %= (replacementfile, value)
raise ValueError(msg)
r.append(value)
timeless
run-tests: factor out _escapepath
r28055 return r
def _escapepath(self, p):
Gregory Szorc
run-tests: move replacements generation into Test...
r21298 if os.name == 'nt':
timeless
run-tests: factor out _escapepath
r28055 return (
Augie Fackler
run-tests: even more bytestring annotations for Python 3
r25041 (b''.join(c.isalpha() and b'[%s%s]' % (c.lower(), c.upper()) or
c in b'/\\' and br'[/\\]' or c.isdigit() and c or b'\\' + c
timeless
run-tests: factor out _escapepath
r28055 for c in p))
)
Gregory Szorc
run-tests: move replacements generation into Test...
r21298 else:
timeless
run-tests: factor out _escapepath
r28055 return re.escape(p)
Gregory Szorc
run-tests: move replacements generation into Test...
r21298
Jun Wu
runtests: export LOCALIP...
r31006 def _localip(self):
if self._useipv6:
return b'::1'
else:
return b'127.0.0.1'
Adam Simpkins
tests: more completely restore the environment in syshgenv...
r33121 def _genrestoreenv(self, testenv):
"""Generate a script that can be used by tests to restore the original
environment."""
# Put the restoreenv script inside self._threadtmp
scriptpath = os.path.join(self._threadtmp, b'restoreenv.sh')
testenv['HGTEST_RESTOREENV'] = scriptpath
# Only restore environment variable names that the shell allows
# us to export.
Adam Simpkins
tests: fix variable name regular expression in _genrestoreenv()...
r33141 name_regex = re.compile('^[a-zA-Z][a-zA-Z0-9_]*$')
Adam Simpkins
tests: more completely restore the environment in syshgenv...
r33121
Yuya Nishihara
tests: actually restore the original environment before running syshg...
r33198 # Do not restore these variables; otherwise tests would fail.
reqnames = {'PYTHON', 'TESTDIR', 'TESTTMP'}
Adam Simpkins
tests: more completely restore the environment in syshgenv...
r33121 with open(scriptpath, 'w') as envf:
Yuya Nishihara
tests: actually restore the original environment before running syshg...
r33198 for name, value in origenviron.items():
Adam Simpkins
tests: more completely restore the environment in syshgenv...
r33121 if not name_regex.match(name):
# Skip environment variables with unusual names not
# allowed by most shells.
continue
Yuya Nishihara
tests: actually restore the original environment before running syshg...
r33198 if name in reqnames:
continue
Adam Simpkins
tests: more completely restore the environment in syshgenv...
r33121 envf.write('%s=%s\n' % (name, shellquote(value)))
for name in testenv:
Yuya Nishihara
tests: actually restore the original environment before running syshg...
r33198 if name in origenviron or name in reqnames:
Adam Simpkins
tests: more completely restore the environment in syshgenv...
r33121 continue
envf.write('unset %s\n' % (name,))
Gregory Szorc
run-tests: refactor port number declaration...
r21514 def _getenv(self):
Gregory Szorc
run-tests: add docstrings
r21536 """Obtain environment variables to use during test execution."""
timeless
run-tests: refactor port allocation into functions...
r28169 def defineport(i):
offset = '' if i == 0 else '%s' % i
env["HGPORT%s" % offset] = '%s' % (self._startport + i)
Gregory Szorc
run-tests: move createenv() into Test...
r21299 env = os.environ.copy()
Mihai Popescu
run-tests: avoid set PYTHONUSERBASE environment variable to None...
r35585 env['PYTHONUSERBASE'] = sysconfig.get_config_var('userbase') or ''
Pierre-Yves David
util: add a way to issue deprecation warning without a UI object...
r31950 env['HGEMITWARNINGS'] = '1'
Gregory Szorc
run-tests: refactor testtmp...
r21454 env['TESTTMP'] = self._testtmp
Gregory Szorc
run-tests: report tests that exception occurred in...
r36054 env['TESTNAME'] = self.name
Gregory Szorc
run-tests: refactor testtmp...
r21454 env['HOME'] = self._testtmp
timeless
run-tests: refactor port allocation into functions...
r28169 # This number should match portneeded in _getport
timeless
run-tests: stop allocating HGPORT3+HGPORT4...
r28170 for port in xrange(3):
timeless
run-tests: refactor port allocation into functions...
r28169 # This list should be parallel to _portmap in _getreplacements
defineport(port)
Augie Fackler
run-tests: use bytes explicitly for tmpdir and hgrc construction...
r25034 env["HGRCPATH"] = os.path.join(self._threadtmp, b'.hgrc')
env["DAEMON_PIDS"] = os.path.join(self._threadtmp, b'daemon.pids')
Matt Harbison
run-tests: include quotes in the HGEDITOR value when storing sys.executable...
r23347 env["HGEDITOR"] = ('"' + sys.executable + '"'
+ ' -c "import sys; sys.exit(0)"')
Gregory Szorc
run-tests: move createenv() into Test...
r21299 env["HGMERGE"] = "internal:merge"
env["HGUSER"] = "test"
env["HGENCODING"] = "ascii"
env["HGENCODINGMODE"] = "strict"
Jun Wu
runtests: export HGIPV6 to hint test scripts whether to use IPv6...
r31003 env['HGIPV6'] = str(int(self._useipv6))
Gregory Szorc
run-tests: move createenv() into Test...
r21299
Gregory Szorc
tests: conditionalize tests based on presence of custom extensions...
r37360 extraextensions = []
for opt in self._extraconfigopts:
section, key = opt.encode('utf-8').split(b'.', 1)
if section != 'extensions':
continue
name = key.split(b'=', 1)[0]
extraextensions.append(name)
if extraextensions:
env['HGTESTEXTRAEXTENSIONS'] = b' '.join(extraextensions)
Jun Wu
runtests: export LOCALIP...
r31006 # LOCALIP could be ::1 or 127.0.0.1. Useful for tests that require raw
# IP addresses.
env['LOCALIP'] = self._localip()
Gregory Szorc
run-tests: move createenv() into Test...
r21299 # Reset some environment variables to well-known values so that
# the tests produce repeatable output.
env['LANG'] = env['LC_ALL'] = env['LANGUAGE'] = 'C'
env['TZ'] = 'GMT'
env["EMAIL"] = "Foo Bar <foo.bar@example.com>"
env['COLUMNS'] = '80'
env['TERM'] = 'xterm'
for k in ('HG HGPROF CDPATH GREP_OPTIONS http_proxy no_proxy ' +
Jun Wu
runtests: unset editor and pager related environment variables...
r31635 'HGPLAIN HGPLAINEXCEPT EDITOR VISUAL PAGER ' +
Jun Wu
run-tests: unset CHGDEBUG...
r30716 'NO_PROXY CHGDEBUG').split():
Gregory Szorc
run-tests: move createenv() into Test...
r21299 if k in env:
del env[k]
# unset env related to hooks
Augie Fackler
tests: fix run-tests environment cleanup on Python 3...
r36539 for k in list(env):
Gregory Szorc
run-tests: move createenv() into Test...
r21299 if k.startswith('HG_'):
del env[k]
Jun Wu
run-tests: use different chg socket directories for different tests...
r28620 if self._usechg:
env['CHGSOCKNAME'] = os.path.join(self._chgsockdir, b'server')
Gregory Szorc
run-tests: move createenv() into Test...
r21299 return env
Gregory Szorc
run-tests: move createhgrc into Test
r21382 def _createhgrc(self, path):
Gregory Szorc
run-tests: add docstrings
r21536 """Create an hgrc file for this test."""
Matt Harbison
run-tests: use context managers for file descriptors...
r35466 with open(path, 'wb') as hgrc:
hgrc.write(b'[ui]\n')
hgrc.write(b'slash = True\n')
hgrc.write(b'interactive = False\n')
hgrc.write(b'mergemarkers = detailed\n')
hgrc.write(b'promptecho = True\n')
hgrc.write(b'[defaults]\n')
hgrc.write(b'[devel]\n')
hgrc.write(b'all-warnings = true\n')
hgrc.write(b'default-date = 0 0\n')
hgrc.write(b'[largefiles]\n')
hgrc.write(b'usercache = %s\n' %
(os.path.join(self._testtmp, b'.cache/largefiles')))
hgrc.write(b'[lfs]\n')
hgrc.write(b'usercache = %s\n' %
(os.path.join(self._testtmp, b'.cache/lfs')))
hgrc.write(b'[web]\n')
hgrc.write(b'address = localhost\n')
hgrc.write(b'ipv6 = %s\n' % str(self._useipv6).encode('ascii'))
Gregory Szorc
hgweb: allow defining Server response header for HTTP server...
r37027 hgrc.write(b'server-header = testing stub value\n')
Matt Harbison
run-tests: use context managers for file descriptors...
r35466
for opt in self._extraconfigopts:
section, key = opt.encode('utf-8').split(b'.', 1)
assert b'=' in key, ('extra config opt %s must '
'have an = for assignment' % opt)
hgrc.write(b'[%s]\n%s\n' % (section, key))
Gregory Szorc
run-tests: move createhgrc into Test
r21382
Gregory Szorc
run-tests: move interactive test acceptance into TestResult...
r21523 def fail(self, msg):
Gregory Szorc
run-tests: raise WarnTest outside of Test.fail()
r21522 # unittest differentiates between errored and failed.
# Failed is denoted by AssertionError (by default at least).
raise AssertionError(msg)
Gregory Szorc
run-tests: move fail() into Test...
r21323
Gregory Szorc
run-tests: obtain replacements inside Test._runcommand...
r24516 def _runcommand(self, cmd, env, normalizenewlines=False):
Gregory Szorc
run-tests: move run into Test class...
r24508 """Run command in a sub-process, capturing the output (stdout and
stderr).
Return a tuple (exitcode, output). output is None in debug mode.
"""
Gregory Szorc
run-tests: remove arguments from Test._runcommand...
r24509 if self._debug:
proc = subprocess.Popen(cmd, shell=True, cwd=self._testtmp,
env=env)
Gregory Szorc
run-tests: move run into Test class...
r24508 ret = proc.wait()
return (ret, None)
Gregory Szorc
run-tests: remove arguments from Test._runcommand...
r24509 proc = Popen4(cmd, self._testtmp, self._timeout, env)
Gregory Szorc
run-tests: move run into Test class...
r24508 def cleanup():
terminate(proc)
ret = proc.wait()
if ret == 0:
ret = signal.SIGTERM << 8
killdaemons(env['DAEMON_PIDS'])
return ret
output = ''
proc.tochild.close()
try:
output = proc.fromchild.read()
except KeyboardInterrupt:
vlog('# Handling keyboard interrupt')
cleanup()
raise
ret = proc.wait()
Matt Harbison
run-tests: resurrect the wifexited polyfill (backout 6ab5a1c9ea3c)...
r25177 if wifexited(ret):
Gregory Szorc
run-tests: move run into Test class...
r24508 ret = os.WEXITSTATUS(ret)
if proc.timeout:
ret = 'timeout'
if ret:
killdaemons(env['DAEMON_PIDS'])
Gregory Szorc
run-tests: obtain replacements inside Test._runcommand...
r24516 for s, r in self._getreplacements():
Gregory Szorc
run-tests: move run into Test class...
r24508 output = re.sub(s, r, output)
Gregory Szorc
run-tests: separate newline normalization from replacements...
r24510
if normalizenewlines:
output = output.replace('\r\n', '\n')
Gregory Szorc
run-tests: move run into Test class...
r24508 return ret, output.splitlines(True)
Gregory Szorc
run-tests: create classes for representing tests...
r21296 class PythonTest(Test):
"""A Python-based test."""
Gregory Szorc
run-tests: factor refpath into Test classes...
r21501
@property
Gregory Szorc
run-tests: move diff generation into TestResult...
r21521 def refpath(self):
Augie Fackler
run-tests: unblock running python tests in python 3...
r25058 return os.path.join(self._testdir, b'%s.out' % self.bname)
Gregory Szorc
run-tests: factor refpath into Test classes...
r21501
Gregory Szorc
run-tests: obtain replacements inside Test._runcommand...
r24516 def _run(self, env):
Augie Fackler
run-tests: unblock running python tests in python 3...
r25058 py3kswitch = self._py3kwarnings and b' -3' or b''
cmd = b'%s%s "%s"' % (PYTHON, py3kswitch, self.path)
Gregory Szorc
run-tests: roll pytest() into PythonTest._run()...
r21311 vlog("# Running", cmd)
Gregory Szorc
run-tests: separate newline normalization from replacements...
r24510 normalizenewlines = os.name == 'nt'
Gregory Szorc
run-tests: obtain replacements inside Test._runcommand...
r24516 result = self._runcommand(cmd, env,
Gregory Szorc
run-tests: separate newline normalization from replacements...
r24510 normalizenewlines=normalizenewlines)
Gregory Szorc
run-tests: remove global abort flag...
r21520 if self._aborted:
raise KeyboardInterrupt()
return result
Gregory Szorc
run-tests: roll pytest() into PythonTest._run()...
r21311
Augie Fackler
run-tests: add support for using 127.0.0.1 as a glob...
r29518 # Some glob patterns apply only in some circumstances, so the script
# might want to remove (glob) annotations that otherwise should be
# retained.
Matt Harbison
run-tests: don't warn on unnecessary globs mandated by check-code.py...
r23352 checkcodeglobpats = [
Augie Fackler
run-tests: add support for using 127.0.0.1 as a glob...
r29518 # On Windows it looks like \ doesn't require a (glob), but we know
# better.
Augie Fackler
run-tests: fix checking a line to see if it needs globbing
r25059 re.compile(br'^pushing to \$TESTTMP/.*[^)]$'),
re.compile(br'^moving \S+/.*[^)]$'),
Augie Fackler
run-tests: add support for using 127.0.0.1 as a glob...
r29518 re.compile(br'^pulling from \$TESTTMP/.*[^)]$'),
# Not all platforms have 127.0.0.1 as loopback (though most do),
# so we always glob that too.
Jun Wu
runtests: change local IP glob pattern from "127.0.0.1" to "$LOCALIP"...
r31673 re.compile(br'.*\$LOCALIP.*$'),
Matt Harbison
run-tests: don't warn on unnecessary globs mandated by check-code.py...
r23352 ]
Augie Fackler
run-tests: work around chr() producing unicode in Python 3
r25036 bchr = chr
Augie Fackler
run-tests: move all open-coded sys.version_info checks to PYTHON3 (issue4668)...
r25159 if PYTHON3:
Augie Fackler
run-tests: work around chr() producing unicode in Python 3
r25036 bchr = lambda x: bytes([x])
Gregory Szorc
run-tests: create classes for representing tests...
r21296 class TTest(Test):
"""A "t test" is a test backed by a .t file."""
Gregory Szorc
run-tests: fix Python 3 incompatibilities...
r28284 SKIPPED_PREFIX = b'skipped: '
FAILED_PREFIX = b'hghave check failed: '
Augie Fackler
run-tests: even more bytestring annotations for Python 3
r25041 NEEDESCAPE = re.compile(br'[\x00-\x08\x0b-\x1f\x7f-\xff]').search
Gregory Szorc
run-tests: move string escaping to TTest...
r21384
Augie Fackler
run-tests: even more bytestring annotations for Python 3
r25041 ESCAPESUB = re.compile(br'[\x00-\x08\x0b-\x1f\\\x7f-\xff]').sub
ESCAPEMAP = dict((bchr(i), br'\x%02x' % i) for i in range(256))
ESCAPEMAP.update({b'\\': b'\\\\', b'\r': br'\r'})
Gregory Szorc
run-tests: move SKIPPED_PREFIX and FAILED_PREFIX into TTest
r21381
Jun Wu
run-tests: support multiple cases in .t test...
r32317 def __init__(self, path, *args, **kwds):
# accept an extra "case" parameter
Martin von Zweigbergk
run-tests: simplify by using dict.pop() with default...
r35194 case = kwds.pop('case', None)
Jun Wu
run-tests: support multiple cases in .t test...
r32317 self._case = case
self._allcases = parsettestcases(path)
super(TTest, self).__init__(path, *args, **kwds)
if case:
Boris Feld
run-tests: update the test case name format...
r38225 self.name = '%s#%s' % (self.name, _strpath(case))
Jun Wu
run-tests: support multiple cases in .t test...
r32317 self.errpath = b'%s.%s.err' % (self.errpath[:-4], case)
self._tmpname += b'-%s' % case
Matt Harbison
run-tests: cache hghave results...
r36480 self._have = {}
Jun Wu
run-tests: support multiple cases in .t test...
r32317
Gregory Szorc
run-tests: factor refpath into Test classes...
r21501 @property
Gregory Szorc
run-tests: move diff generation into TestResult...
r21521 def refpath(self):
Augie Fackler
run-tests: even more bytestring annotations for Python 3
r25041 return os.path.join(self._testdir, self.bname)
Gregory Szorc
run-tests: factor refpath into Test classes...
r21501
Gregory Szorc
run-tests: obtain replacements inside Test._runcommand...
r24516 def _run(self, env):
Matt Harbison
run-tests: use context managers for file descriptors...
r35466 with open(self.path, 'rb') as f:
lines = f.readlines()
Gregory Szorc
run-tests: move t test execution from tsttest() to TTest.run()...
r21313
Jun Wu
run-tests: update .t reference output after reading the test...
r32981 # .t file is both reference output and the test input, keep reference
# output updated with the the test input. This avoids some race
# conditions where the reference output does not match the actual test.
if self._refout is not None:
self._refout = lines
Gregory Szorc
run-tests: refactor testtmp...
r21454 salt, script, after, expected = self._parsetest(lines)
Gregory Szorc
run-tests: move t test execution from tsttest() to TTest.run()...
r21313
# Write out the generated script.
Augie Fackler
run-tests: even more bytestring annotations for Python 3
r25041 fname = b'%s.sh' % self._testtmp
Matt Harbison
run-tests: use context managers for file descriptors...
r35466 with open(fname, 'wb') as f:
for l in script:
f.write(l)
Gregory Szorc
run-tests: move t test execution from tsttest() to TTest.run()...
r21313
Augie Fackler
run-tests: even more bytestring annotations for Python 3
r25041 cmd = b'%s "%s"' % (self._shell, fname)
Gregory Szorc
run-tests: move t test execution from tsttest() to TTest.run()...
r21313 vlog("# Running", cmd)
Gregory Szorc
run-tests: obtain replacements inside Test._runcommand...
r24516 exitcode, output = self._runcommand(cmd, env)
Gregory Szorc
run-tests: remove global abort flag...
r21520
if self._aborted:
raise KeyboardInterrupt()
Gregory Szorc
run-tests: move t test execution from tsttest() to TTest.run()...
r21313 # Do not merge output if skipped. Return hghave message instead.
# Similarly, with --debug, output is None.
Gregory Szorc
run-tests: move SKIPPED_STATUS into Test class
r21380 if exitcode == self.SKIPPED_STATUS or output is None:
Gregory Szorc
run-tests: move t test execution from tsttest() to TTest.run()...
r21313 return exitcode, output
Gregory Szorc
run-tests: finish moving tsttest() into TTest
r21314 return self._processoutput(exitcode, output, salt, after, expected)
Gregory Szorc
run-tests: create classes for representing tests...
r21296
Gregory Szorc
run-tests: refactor testtmp...
r21454 def _hghave(self, reqs):
Matt Harbison
run-tests: cache hghave results...
r36480 allreqs = b' '.join(reqs)
if allreqs in self._have:
return self._have.get(allreqs)
Gregory Szorc
run-tests: move t test parsing into its own function...
r21312 # TODO do something smarter when all other uses of hghave are gone.
FUJIWARA Katsunori
run-tests.py: execute hghave by the path relative to run-tests.py...
r25728 runtestdir = os.path.abspath(os.path.dirname(_bytespath(__file__)))
tdir = runtestdir.replace(b'\\', b'/')
Augie Fackler
run-tests: even more bytestring annotations for Python 3
r25041 proc = Popen4(b'%s -c "%s/hghave %s"' %
Matt Harbison
run-tests: cache hghave results...
r36480 (self._shell, tdir, allreqs),
FUJIWARA Katsunori
run-tests.py: execute hghave with same env vars as ones for actual tests...
r23933 self._testtmp, 0, self._getenv())
Gregory Szorc
run-tests: move t test parsing into its own function...
r21312 stdout, stderr = proc.communicate()
ret = proc.wait()
Matt Harbison
run-tests: resurrect the wifexited polyfill (backout 6ab5a1c9ea3c)...
r25177 if wifexited(ret):
Gregory Szorc
run-tests: move t test parsing into its own function...
r21312 ret = os.WEXITSTATUS(ret)
if ret == 2:
timeless
py3: convert hghave output to text...
r28699 print(stdout.decode('utf-8'))
Gregory Szorc
run-tests: move t test parsing into its own function...
r21312 sys.exit(1)
timeless
run-tests: add --slowtimeout and use it for slow tests
r27141 if ret != 0:
Matt Harbison
run-tests: cache hghave results...
r36480 self._have[allreqs] = (False, stdout)
timeless
run-tests: report missing feature for skipped tests
r27564 return False, stdout
timeless
run-tests: add --slowtimeout and use it for slow tests
r27141
Augie Fackler
tests: fix run-tests "slow test" check...
r34266 if b'slow' in reqs:
timeless
run-tests: add --slowtimeout and use it for slow tests
r27141 self._timeout = self._slowtimeout
Matt Harbison
run-tests: cache hghave results...
r36480
self._have[allreqs] = (True, None)
timeless
run-tests: report missing feature for skipped tests
r27564 return True, None
Gregory Szorc
run-tests: move t test parsing into its own function...
r21312
Jun Wu
run-tests: support multiple cases in .t test...
r32317 def _iftest(self, args):
# implements "#if"
reqs = []
for arg in args:
if arg.startswith(b'no-') and arg[3:] in self._allcases:
if arg[3:] == self._case:
return False
elif arg in self._allcases:
if arg != self._case:
return False
else:
reqs.append(arg)
return self._hghave(reqs)[0]
Gregory Szorc
run-tests: refactor testtmp...
r21454 def _parsetest(self, lines):
Gregory Szorc
run-tests: move t test parsing into its own function...
r21312 # We generate a shell script which outputs unique markers to line
# up script results with our source. These markers include input
# line number and the last return code.
Augie Fackler
run-tests: even more bytestring annotations for Python 3
r25041 salt = b"SALT%d" % time.time()
Gregory Szorc
run-tests: move t test parsing into its own function...
r21312 def addsalt(line, inpython):
if inpython:
Augie Fackler
run-tests: even more bytestring annotations for Python 3
r25041 script.append(b'%s %d 0\n' % (salt, line))
Gregory Szorc
run-tests: move t test parsing into its own function...
r21312 else:
Augie Fackler
run-tests: even more bytestring annotations for Python 3
r25041 script.append(b'echo %s %d $?\n' % (salt, line))
Gregory Szorc
run-tests: move t test parsing into its own function...
r21312
script = []
# After we run the shell script, we re-unify the script output
# with non-active parts of the source, with synchronization by our
# SALT line number markers. The after table contains the non-active
# components, ordered by line number.
after = {}
# Expected shell script output.
expected = {}
pos = prepos = -1
# True or False when in a true or false conditional section
skipping = None
# We keep track of whether or not we're in a Python block so we
# can generate the surrounding doctest magic.
inpython = False
Gregory Szorc
run-tests: move debug into an argument to Test.__init__
r21510 if self._debug:
Augie Fackler
run-tests: make sure all script lines are bytes
r25060 script.append(b'set -x\n')
Yuya Nishihara
run-tests: allow to specify executable of any name by --with-hg...
r28099 if self._hgcommand != b'hg':
script.append(b'alias hg="%s"\n' % self._hgcommand)
Gregory Szorc
run-tests: move t test parsing into its own function...
r21312 if os.getenv('MSYSTEM'):
Augie Fackler
run-tests: make sure all script lines are bytes
r25060 script.append(b'alias pwd="pwd -W"\n')
Martin von Zweigbergk
tests: make #testcase available as env var in test...
r35554 if self._case:
Augie Fackler
tests: get run-tests to reliably hand shellquote a string and not a bytes...
r35841 if isinstance(self._case, str):
quoted = shellquote(self._case)
else:
quoted = shellquote(self._case.decode('utf8')).encode('utf8')
script.append(b'TESTCASE=%s\n' % quoted)
Martin von Zweigbergk
tests: make #testcase available as env var in test...
r35554 script.append(b'export TESTCASE\n')
Gregory Szorc
run-tests: move t test parsing into its own function...
r21312
timeless
run-tests: handle empty tests
r28812 n = 0
Gregory Szorc
run-tests: move t test parsing into its own function...
r21312 for n, l in enumerate(lines):
Augie Fackler
run-tests: use bytes when constructing shell script
r25035 if not l.endswith(b'\n'):
l += b'\n'
if l.startswith(b'#require'):
Matt Mackall
run-tests: add #require to abort full test...
r22045 lsplit = l.split()
Augie Fackler
run-tests: use bytes when constructing shell script
r25035 if len(lsplit) < 2 or lsplit[0] != b'#require':
Matt Mackall
run-tests: add #require to abort full test...
r22045 after.setdefault(pos, []).append(' !!! invalid #require\n')
Jun Wu
run-tests: allow #require inside #if...
r36695 if not skipping:
haveresult, message = self._hghave(lsplit[1:])
if not haveresult:
script = [b'echo "%s"\nexit 80\n' % message]
break
Matt Mackall
run-tests: add #require to abort full test...
r22045 after.setdefault(pos, []).append(l)
Augie Fackler
run-tests: use bytes when constructing shell script
r25035 elif l.startswith(b'#if'):
Gregory Szorc
run-tests: move t test parsing into its own function...
r21312 lsplit = l.split()
Augie Fackler
run-tests: use bytes when constructing shell script
r25035 if len(lsplit) < 2 or lsplit[0] != b'#if':
Gregory Szorc
run-tests: move t test parsing into its own function...
r21312 after.setdefault(pos, []).append(' !!! invalid #if\n')
if skipping is not None:
after.setdefault(pos, []).append(' !!! nested #if\n')
Jun Wu
run-tests: support multiple cases in .t test...
r32317 skipping = not self._iftest(lsplit[1:])
Gregory Szorc
run-tests: move t test parsing into its own function...
r21312 after.setdefault(pos, []).append(l)
Augie Fackler
run-tests: use bytes when constructing shell script
r25035 elif l.startswith(b'#else'):
Gregory Szorc
run-tests: move t test parsing into its own function...
r21312 if skipping is None:
after.setdefault(pos, []).append(' !!! missing #if\n')
skipping = not skipping
after.setdefault(pos, []).append(l)
Augie Fackler
run-tests: use bytes when constructing shell script
r25035 elif l.startswith(b'#endif'):
Gregory Szorc
run-tests: move t test parsing into its own function...
r21312 if skipping is None:
after.setdefault(pos, []).append(' !!! missing #if\n')
skipping = None
after.setdefault(pos, []).append(l)
elif skipping:
after.setdefault(pos, []).append(l)
Augie Fackler
run-tests: use bytes when constructing shell script
r25035 elif l.startswith(b' >>> '): # python inlines
Gregory Szorc
run-tests: move t test parsing into its own function...
r21312 after.setdefault(pos, []).append(l)
prepos = pos
pos = n
if not inpython:
# We've just entered a Python block. Add the header.
inpython = True
addsalt(prepos, False) # Make sure we report the exit code.
Augie Fackler
run-tests: unblock running python tests in python 3...
r25058 script.append(b'%s -m heredoctest <<EOF\n' % PYTHON)
Gregory Szorc
run-tests: move t test parsing into its own function...
r21312 addsalt(n, True)
script.append(l[2:])
Augie Fackler
run-tests: use bytes when constructing shell script
r25035 elif l.startswith(b' ... '): # python inlines
Gregory Szorc
run-tests: move t test parsing into its own function...
r21312 after.setdefault(prepos, []).append(l)
script.append(l[2:])
Augie Fackler
run-tests: use bytes when constructing shell script
r25035 elif l.startswith(b' $ '): # commands
Gregory Szorc
run-tests: move t test parsing into its own function...
r21312 if inpython:
Augie Fackler
run-tests: make sure all script lines are bytes
r25060 script.append(b'EOF\n')
Gregory Szorc
run-tests: move t test parsing into its own function...
r21312 inpython = False
after.setdefault(pos, []).append(l)
prepos = pos
pos = n
addsalt(n, False)
cmd = l[4:].split()
Augie Fackler
run-tests: make sure all script lines are bytes
r25060 if len(cmd) == 2 and cmd[0] == b'cd':
l = b' $ cd %s || exit 1\n' % cmd[1]
Gregory Szorc
run-tests: move t test parsing into its own function...
r21312 script.append(l[4:])
Augie Fackler
run-tests: use bytes when constructing shell script
r25035 elif l.startswith(b' > '): # continuations
Gregory Szorc
run-tests: move t test parsing into its own function...
r21312 after.setdefault(prepos, []).append(l)
script.append(l[4:])
Augie Fackler
run-tests: use bytes when constructing shell script
r25035 elif l.startswith(b' '): # results
Gregory Szorc
run-tests: move t test parsing into its own function...
r21312 # Queue up a list of expected results.
expected.setdefault(pos, []).append(l[2:])
else:
if inpython:
Augie Fackler
run-tests: make sure all script lines are bytes
r25060 script.append(b'EOF\n')
Gregory Szorc
run-tests: move t test parsing into its own function...
r21312 inpython = False
# Non-command/result. Queue up for merged output.
after.setdefault(pos, []).append(l)
if inpython:
Augie Fackler
run-tests: make sure all script lines are bytes
r25060 script.append(b'EOF\n')
Gregory Szorc
run-tests: move t test parsing into its own function...
r21312 if skipping is not None:
after.setdefault(pos, []).append(' !!! missing #endif\n')
addsalt(n + 1, False)
return salt, script, after, expected
Gregory Szorc
run-tests: finish moving tsttest() into TTest
r21314 def _processoutput(self, exitcode, output, salt, after, expected):
# Merge the script output back into a unified test.
warnonly = 1 # 1: not yet; 2: yes; 3: for sure not
if exitcode != 0:
warnonly = 3
pos = -1
postout = []
for l in output:
lout, lcmd = l, None
if salt in l:
lout, lcmd = l.split(salt, 1)
Matt Mackall
tests: add (?) flag for optional lines...
r25388 while lout:
Augie Fackler
run-tests: even more bytestring annotations for Python 3
r25041 if not lout.endswith(b'\n'):
lout += b' (no-eol)\n'
Gregory Szorc
run-tests: finish moving tsttest() into TTest
r21314
# Find the expected output at the current position.
timeless
run-tests: teach _processoutput to handle multiple lines of churn...
r28569 els = [None]
Gregory Szorc
run-tests: finish moving tsttest() into TTest
r21314 if expected.get(pos, None):
timeless
run-tests: teach _processoutput to handle multiple lines of churn...
r28569 els = expected[pos]
i = 0
timeless
run-tests: make _processoutput picky about optional globs...
r28701 optional = []
timeless
run-tests: teach _processoutput to handle multiple lines of churn...
r28569 while i < len(els):
el = els[i]
Matt Harbison
run-tests: drop required (feature !) style lines when the output is missing...
r33658 r = self.linematch(el, lout)
timeless
run-tests: indent _processoutput to aid readability for next patch...
r28568 if isinstance(r, str):
Matt Harbison
run-tests: accept '\' vs '/' path differences without '(glob)'...
r35383 if r == '-glob':
timeless
run-tests: indent _processoutput to aid readability for next patch...
r28568 lout = ''.join(el.rsplit(' (glob)', 1))
r = '' # Warn only this line.
elif r == "retry":
postout.append(b' ' + el)
timeless
run-tests: teach _processoutput to handle multiple lines of churn...
r28569 els.pop(i)
break
timeless
run-tests: indent _processoutput to aid readability for next patch...
r28568 else:
log('\ninfo, unknown linematch result: %r\n' % r)
r = False
timeless
run-tests: teach _processoutput to handle multiple lines of churn...
r28569 if r:
els.pop(i)
break
Matt Harbison
run-tests: support per-line conditional output in tests...
r31829 if el:
if el.endswith(b" (?)\n"):
optional.append(i)
else:
m = optline.match(el)
if m:
Augie Fackler
tests: fix up test-run-tests failures on Python 3.6...
r33676 conditions = [
c for c in m.group(2).split(b' ')]
Matt Harbison
run-tests: support per-line conditional output in tests...
r31829
Jun Wu
run-tests: make per-line condition support testcase names...
r33935 if not self._iftest(conditions):
Matt Harbison
run-tests: support per-line conditional output in tests...
r31829 optional.append(i)
timeless
run-tests: teach _processoutput to handle multiple lines of churn...
r28569 i += 1
Gregory Szorc
run-tests: finish moving tsttest() into TTest
r21314 if r:
timeless
run-tests: teach _processoutput to handle multiple lines of churn...
r28569 if r == "retry":
continue
timeless
run-tests: make _processoutput picky about optional globs...
r28701 # clean up any optional leftovers
for i in optional:
postout.append(b' ' + els[i])
for i in reversed(optional):
del els[i]
Augie Fackler
run-tests: even more bytestring annotations for Python 3
r25041 postout.append(b' ' + el)
Gregory Szorc
run-tests: finish moving tsttest() into TTest
r21314 else:
Gregory Szorc
run-tests: move string escaping to TTest...
r21384 if self.NEEDESCAPE(lout):
Augie Fackler
run-tests: even more bytestring annotations for Python 3
r25041 lout = TTest._stringescape(b'%s (esc)\n' %
lout.rstrip(b'\n'))
postout.append(b' ' + lout) # Let diff deal with it.
Gregory Szorc
run-tests: finish moving tsttest() into TTest
r21314 if r != '': # If line failed.
warnonly = 3 # for sure not
elif warnonly == 1: # Is "not yet" and line is warn only.
warnonly = 2 # Yes do warn.
Matt Mackall
tests: add (?) flag for optional lines...
r25388 break
Matt Harbison
run-tests: defer leftover (?) cleanup until after all output is exhausted...
r28317 else:
# clean up any optional leftovers
while expected.get(pos, None):
el = expected[pos].pop(0)
Matt Harbison
run-tests: support per-line conditional output in tests...
r31829 if el:
Matt Harbison
run-tests: drop required (feature !) style lines when the output is missing...
r33658 if not el.endswith(b" (?)\n"):
m = optline.match(el)
if m:
Alex Gaynor
tests: fixed a bytes/unicode confusion in the test runner...
r33873 conditions = [c for c in m.group(2).split(b' ')]
Matt Harbison
run-tests: drop required (feature !) style lines when the output is missing...
r33658
Jun Wu
run-tests: make per-line condition support testcase names...
r33935 if self._iftest(conditions):
Matt Harbison
run-tests: drop required (feature !) style lines when the output is missing...
r33658 # Don't append as optional line
continue
else:
Matt Harbison
run-tests: don't drop optional lines after a missing unconditional line...
r33659 continue
Matt Harbison
run-tests: defer leftover (?) cleanup until after all output is exhausted...
r28317 postout.append(b' ' + el)
Gregory Szorc
run-tests: finish moving tsttest() into TTest
r21314
if lcmd:
# Add on last return code.
ret = int(lcmd.split()[1])
if ret != 0:
Augie Fackler
run-tests: even more bytestring annotations for Python 3
r25041 postout.append(b' [%d]\n' % ret)
Gregory Szorc
run-tests: finish moving tsttest() into TTest
r21314 if pos in after:
# Merge in non-active test bits.
postout += after.pop(pos)
pos = int(lcmd.split()[0])
if pos in after:
postout += after.pop(pos)
if warnonly == 2:
exitcode = False # Set exitcode to warned.
return exitcode, postout
Gregory Szorc
run-tests: move t test parsing into its own function...
r21312
Gregory Szorc
run-tests: make linematch a static method of TTest...
r21315 @staticmethod
Gregory Szorc
run-tests: make rematch a static method of TTest
r21316 def rematch(el, l):
try:
Martin von Zweigbergk
run-tests: make "| foo (re)" not match everything...
r35156 el = b'(?:' + el + b')'
Gregory Szorc
run-tests: make rematch a static method of TTest
r21316 # use \Z to ensure that the regex matches to the end of the string
if os.name == 'nt':
Augie Fackler
run-tests: even more bytestring annotations for Python 3
r25041 return re.match(el + br'\r?\n\Z', l)
return re.match(el + br'\n\Z', l)
Gregory Szorc
run-tests: make rematch a static method of TTest
r21316 except re.error:
# el is an invalid regex
return False
@staticmethod
Gregory Szorc
run-tests: make globmatch a static method of TTest
r21317 def globmatch(el, l):
# The only supported special characters are * and ? plus / which also
# matches \ on windows. Escaping of these characters is supported.
Augie Fackler
run-tests: even more bytestring annotations for Python 3
r25041 if el + b'\n' == l:
Gregory Szorc
run-tests: make globmatch a static method of TTest
r21317 if os.altsep:
# matching on "/" is not needed for this line
Matt Harbison
run-tests: don't warn on unnecessary globs mandated by check-code.py...
r23352 for pat in checkcodeglobpats:
if pat.match(el):
return True
Augie Fackler
run-tests: even more bytestring annotations for Python 3
r25041 return b'-glob'
Gregory Szorc
run-tests: make globmatch a static method of TTest
r21317 return True
Jun Wu
runtests: change local IP glob pattern from "127.0.0.1" to "$LOCALIP"...
r31673 el = el.replace(b'$LOCALIP', b'*')
Gregory Szorc
run-tests: make globmatch a static method of TTest
r21317 i, n = 0, len(el)
Augie Fackler
run-tests: even more bytestring annotations for Python 3
r25041 res = b''
Gregory Szorc
run-tests: make globmatch a static method of TTest
r21317 while i < n:
Augie Fackler
run-tests: even more bytestring annotations for Python 3
r25041 c = el[i:i + 1]
Gregory Szorc
run-tests: make globmatch a static method of TTest
r21317 i += 1
Augie Fackler
run-tests: even more bytestring annotations for Python 3
r25041 if c == b'\\' and i < n and el[i:i + 1] in b'*?\\/':
Gregory Szorc
run-tests: make globmatch a static method of TTest
r21317 res += el[i - 1:i + 1]
i += 1
Augie Fackler
run-tests: even more bytestring annotations for Python 3
r25041 elif c == b'*':
res += b'.*'
elif c == b'?':
res += b'.'
elif c == b'/' and os.altsep:
res += b'[/\\\\]'
Gregory Szorc
run-tests: make globmatch a static method of TTest
r21317 else:
res += re.escape(c)
return TTest.rematch(res, l)
Matt Harbison
run-tests: drop required (feature !) style lines when the output is missing...
r33658 def linematch(self, el, l):
Matt Mackall
tests: add (?) flag for optional lines...
r25388 retry = False
Gregory Szorc
run-tests: make linematch a static method of TTest...
r21315 if el == l: # perfect match (fast)
return True
if el:
Augie Fackler
run-tests: add b-prefix on two strings to fix python3 support
r26612 if el.endswith(b" (?)\n"):
Matt Mackall
tests: add (?) flag for optional lines...
r25388 retry = "retry"
Gregory Szorc
run-tests: fix Python 3 incompatibilities...
r28284 el = el[:-5] + b"\n"
Matt Harbison
run-tests: support per-line conditional output in tests...
r31829 else:
m = optline.match(el)
if m:
Augie Fackler
tests: fix up test-run-tests failures on Python 3.6...
r33676 conditions = [c for c in m.group(2).split(b' ')]
Matt Harbison
run-tests: drop required (feature !) style lines when the output is missing...
r33658
Matt Harbison
run-tests: support per-line conditional output in tests...
r31829 el = m.group(1) + b"\n"
Jun Wu
run-tests: make per-line condition support testcase names...
r33935 if not self._iftest(conditions):
Matt Harbison
run-tests: drop required (feature !) style lines when the output is missing...
r33658 retry = "retry" # Not required by listed features
Matt Harbison
run-tests: support per-line conditional output in tests...
r31829
Augie Fackler
run-tests: even more bytestring annotations for Python 3
r25041 if el.endswith(b" (esc)\n"):
Augie Fackler
run-tests: move all open-coded sys.version_info checks to PYTHON3 (issue4668)...
r25159 if PYTHON3:
Augie Fackler
run-tests: string-escape no longer exists in python 3, use unicode_escape
r25047 el = el[:-7].decode('unicode_escape') + '\n'
el = el.encode('utf-8')
else:
el = el[:-7].decode('string-escape') + '\n'
Augie Fackler
run-tests: even more bytestring annotations for Python 3
r25041 if el == l or os.name == 'nt' and el[:-1] + b'\r\n' == l:
Gregory Szorc
run-tests: make linematch a static method of TTest...
r21315 return True
Augie Fackler
run-tests: even more bytestring annotations for Python 3
r25041 if el.endswith(b" (re)\n"):
Matt Mackall
tests: add (?) flag for optional lines...
r25388 return TTest.rematch(el[:-6], l) or retry
Augie Fackler
run-tests: even more bytestring annotations for Python 3
r25041 if el.endswith(b" (glob)\n"):
Mads Kiilerich
run-tests: automatically add (glob) to "saved backup bundle to" lines...
r23728 # ignore '(glob)' added to l by 'replacements'
Augie Fackler
run-tests: even more bytestring annotations for Python 3
r25041 if l.endswith(b" (glob)\n"):
l = l[:-8] + b"\n"
Matt Harbison
run-tests: prevent a (glob) declaration from reordering (?) lines...
r31827 return TTest.globmatch(el[:-8], l) or retry
Matt Harbison
run-tests: suggest a (glob) for os.path.sep mismatches with '\r\n' EOL too...
r35382 if os.altsep:
_l = l.replace(b'\\', b'/')
if el == _l or os.name == 'nt' and el[:-1] + b'\r\n' == _l:
Matt Harbison
run-tests: accept '\' vs '/' path differences without '(glob)'...
r35383 return True
Matt Mackall
tests: add (?) flag for optional lines...
r25388 return retry
Gregory Szorc
run-tests: make linematch a static method of TTest...
r21315
Gregory Szorc
run-tests: move parsehghaveoutput() into TTest...
r21379 @staticmethod
def parsehghaveoutput(lines):
'''Parse hghave log lines.
Return tuple of lists (missing, failed):
* the missing/unknown features
* the features for which existence check failed'''
missing = []
failed = []
for line in lines:
Gregory Szorc
run-tests: move SKIPPED_PREFIX and FAILED_PREFIX into TTest
r21381 if line.startswith(TTest.SKIPPED_PREFIX):
Gregory Szorc
run-tests: move parsehghaveoutput() into TTest...
r21379 line = line.splitlines()[0]
Gregory Szorc
run-tests: fix Python 3 incompatibilities...
r28284 missing.append(line[len(TTest.SKIPPED_PREFIX):].decode('utf-8'))
Gregory Szorc
run-tests: move SKIPPED_PREFIX and FAILED_PREFIX into TTest
r21381 elif line.startswith(TTest.FAILED_PREFIX):
Gregory Szorc
run-tests: move parsehghaveoutput() into TTest...
r21379 line = line.splitlines()[0]
Gregory Szorc
run-tests: fix Python 3 incompatibilities...
r28284 failed.append(line[len(TTest.FAILED_PREFIX):].decode('utf-8'))
Gregory Szorc
run-tests: move parsehghaveoutput() into TTest...
r21379
return missing, failed
Gregory Szorc
run-tests: move string escaping to TTest...
r21384 @staticmethod
def _escapef(m):
return TTest.ESCAPEMAP[m.group(0)]
@staticmethod
def _stringescape(s):
return TTest.ESCAPESUB(TTest._escapef, s)
Matt Mackall
run-tests: attempt to fix iolock handling...
r22104 iolock = threading.RLock()
Jun Wu
test-run-tests: stabilize the test (issue5735)...
r35586 firstlock = threading.RLock()
firsterror = False
Matt Mackall
run-tests: add locking on results struct
r14000
Gregory Szorc
run-tests: define custom result and runner classes for unittest...
r21429 class TestResult(unittest._TextTestResult):
"""Holds results when executing via unittest."""
# Don't worry too much about accessing the non-public _TextTestResult.
# It is relatively common in Python testing tools.
Gregory Szorc
run-tests: abort tests after first failure in unittest mode...
r21460 def __init__(self, options, *args, **kwargs):
Gregory Szorc
run-tests: define custom result and runner classes for unittest...
r21429 super(TestResult, self).__init__(*args, **kwargs)
Gregory Szorc
run-tests: abort tests after first failure in unittest mode...
r21460 self._options = options
Gregory Szorc
run-tests: teach unittest about skipped tests
r21430 # unittest.TestResult didn't have skipped until 2.7. We need to
# polyfill it.
self.skipped = []
Gregory Szorc
run-tests: teach unittest about ignored tests
r21431 # We have a custom "ignored" result that isn't present in any Python
# unittest implementation. It is very similar to skipped. It may make
# sense to map it into skip some day.
self.ignored = []
Gregory Szorc
run-tests: capture execution times in TestResult...
r21495 self.times = []
timeless
cleanup: remove superfluous space after space after equals (python)
r27637 self._firststarttime = None
Augie Fackler
run-tests: add support for xunit test reports...
r22044 # Data stored for the benefit of generating xunit reports.
self.successes = []
self.faildata = {}
Gregory Szorc
run-tests: capture execution times in TestResult...
r21495
Martin von Zweigbergk
run-tests: pass color option via test case object , not global var...
r33565 if options.color == 'auto':
Martin von Zweigbergk
run-tests: remove unnecessary 'with_color' variable...
r33568 self.color = pygmentspresent and self.stream.isatty()
Martin von Zweigbergk
run-tests: pass color option via test case object , not global var...
r33565 elif options.color == 'never':
self.color = False
else: # 'always', for testing purposes
self.color = pygmentspresent
Matthieu Laneuville
run-tests: check if stream is a tty before using color...
r33561
Gregory Szorc
run-tests: make failure reporting in unittest mode equivalent to default...
r21462 def addFailure(self, test, reason):
self.failures.append((test, reason))
Gregory Szorc
run-tests: abort tests after first failure in unittest mode...
r21460
if self._options.first:
self.stop()
anuraggoel
run-tests: produce error on running a failing test...
r21735 else:
Augie Fackler
run-tests: switch all uses of iolock.acquire() to a context manager
r25046 with iolock:
Matt Mackall
run-tests: report timeouts in a less alarming fashion...
r27393 if reason == "timed out":
self.stream.write('t')
else:
if not self._options.nodiff:
Martin von Zweigbergk
run-tests: move newline out of colorized message...
r34843 self.stream.write('\n')
# Exclude the '\n' from highlighting to lex correctly
formatted = 'ERROR: %s output changed\n' % test
Yuya Nishihara
run-tests: factor out highlight functions
r33931 self.stream.write(highlightmsg(formatted, self.color))
Matt Mackall
run-tests: report timeouts in a less alarming fashion...
r27393 self.stream.write('!')
anuraggoel
run-tests: fixes the '--interactive' option error...
r21754
Augie Fackler
run-tests: switch all uses of iolock.acquire() to a context manager
r25046 self.stream.flush()
Gregory Szorc
run-tests: abort tests after first failure in unittest mode...
r21460
Augie Fackler
run-tests: add support for xunit test reports...
r22044 def addSuccess(self, test):
Augie Fackler
run-tests: switch all uses of iolock.acquire() to a context manager
r25046 with iolock:
super(TestResult, self).addSuccess(test)
Augie Fackler
run-tests: add support for xunit test reports...
r22044 self.successes.append(test)
Gregory Szorc
run-tests: abort tests after first failure in unittest mode...
r21460
Augie Fackler
run-tests: add support for xunit test reports...
r22044 def addError(self, test, err):
super(TestResult, self).addError(test, err)
Gregory Szorc
run-tests: abort tests after first failure in unittest mode...
r21460 if self._options.first:
self.stop()
Gregory Szorc
run-tests: teach unittest about skipped tests
r21430 # Polyfill.
def addSkip(self, test, reason):
self.skipped.append((test, reason))
Augie Fackler
run-tests: switch all uses of iolock.acquire() to a context manager
r25046 with iolock:
if self.showAll:
self.stream.writeln('skipped %s' % reason)
else:
self.stream.write('s')
self.stream.flush()
Gregory Szorc
run-tests: teach unittest about skipped tests
r21430
Gregory Szorc
run-tests: teach unittest about ignored tests
r21431 def addIgnore(self, test, reason):
self.ignored.append((test, reason))
Augie Fackler
run-tests: switch all uses of iolock.acquire() to a context manager
r25046 with iolock:
if self.showAll:
self.stream.writeln('ignored %s' % reason)
Augie Fackler
run-tests: fix test result counts with --keyword specified or skips occurring...
r21997 else:
Augie Fackler
run-tests: switch all uses of iolock.acquire() to a context manager
r25046 if reason not in ('not retesting', "doesn't match keyword"):
self.stream.write('i')
else:
self.testsRun += 1
self.stream.flush()
Gregory Szorc
run-tests: teach unittest about ignored tests
r21431
Gregory Szorc
run-tests: move interactive test acceptance into TestResult...
r21523 def addOutputMismatch(self, test, ret, got, expected):
Gregory Szorc
run-tests: move diff generation into TestResult...
r21521 """Record a mismatch in test output for a particular test."""
Jun Wu
test-run-tests: stabilize the test (issue5735)...
r35586 if self.shouldStop or firsterror:
Augie Fackler
run-tests: handle --jobs and --first gracefully...
r22838 # don't print, some other test case already failed and
# printed, we're just stale and probably failed due to our
# temp dir getting cleaned up.
return
Gregory Szorc
run-tests: move diff generation into TestResult...
r21521
Matt Mackall
run-tests: hold iolock across diff/prompt when interactive...
r21763 accepted = False
Augie Fackler
run-tests: add support for xunit test reports...
r22044 lines = []
Matt Mackall
run-tests: hold iolock across diff/prompt when interactive...
r21763
Augie Fackler
run-tests: switch all uses of iolock.acquire() to a context manager
r25046 with iolock:
if self._options.nodiff:
pass
elif self._options.view:
Augie Fackler
run-tests: be more paranoid about os.system using bytes
r25056 v = self._options.view
Augie Fackler
run-tests: move all open-coded sys.version_info checks to PYTHON3 (issue4668)...
r25159 if PYTHON3:
Augie Fackler
run-tests: move unicode-to-bytes operations on paths to a helper (issue4667)...
r25161 v = _bytespath(v)
Augie Fackler
run-tests: be more paranoid about os.system using bytes
r25056 os.system(b"%s %s %s" %
(v, test.refpath, test.errpath))
Gregory Szorc
run-tests: move diff generation into TestResult...
r21521 else:
Augie Fackler
run-tests: switch all uses of iolock.acquire() to a context manager
r25046 servefail, lines = getdiff(expected, got,
test.refpath, test.errpath)
Matt Harbison
run-tests: don't mask errors when a server fails to start...
r36456 self.stream.write('\n')
for line in lines:
line = highlightdiff(line, self.color)
if PYTHON3:
self.stream.flush()
self.stream.buffer.write(line)
self.stream.buffer.flush()
else:
self.stream.write(line)
self.stream.flush()
Gregory Szorc
run-tests: move diff generation into TestResult...
r21521
Matt Harbison
run-tests: resume raising an exception when a server fails to start...
r36479 if servefail:
raise test.failureException(
'server failed to start (HGPORT=%s)' % test._startport)
Augie Fackler
run-tests: switch all uses of iolock.acquire() to a context manager
r25046 # handle interactive prompt without releasing iolock
if self._options.interactive:
Jun Wu
run-tests: do not prompt changes (-i) if a race condition is detected...
r32980 if test.readrefout() != expected:
self.stream.write(
'Reference output has changed (run again to prompt '
'changes)')
else:
self.stream.write('Accept this change? [n] ')
answer = sys.stdin.readline().strip()
if answer.lower() in ('y', 'yes'):
Jun Wu
run-tests: fix -i when "#testcases" is used in .t test...
r32982 if test.path.endswith(b'.t'):
Jun Wu
run-tests: do not prompt changes (-i) if a race condition is detected...
r32980 rename(test.errpath, test.path)
else:
rename(test.errpath, '%s.out' % test.path)
accepted = True
Yuya Nishihara
run-tests: remove useless "failed" flag from addOutputMismatch()...
r28127 if not accepted:
Augie Fackler
run-tests: record faildata using bytes instead of str...
r25052 self.faildata[test.name] = b''.join(lines)
Matt Mackall
run-tests: hold iolock across diff/prompt when interactive...
r21763
return accepted
Gregory Szorc
run-tests: move interactive test acceptance into TestResult...
r21523
Gregory Szorc
run-tests: capture execution times in TestResult...
r21495 def startTest(self, test):
super(TestResult, self).startTest(test)
anuraggoel
run-tests: '--time' option provide more details to Linux users...
r21977 # os.times module computes the user time and system time spent by
# child's processes along with real elapsed time taken by a process.
# This module has one limitation. It can only work for Linux user
# and not for Windows.
Augie Fackler
run-tests: stop storing start/stop times in a dict by test name...
r24331 test.started = os.times()
Pierre-Yves David
run-tests: track start and end time of tests...
r25097 if self._firststarttime is None: # thread racy but irrelevant
self._firststarttime = test.started[4]
Gregory Szorc
run-tests: capture execution times in TestResult...
r21495
def stopTest(self, test, interrupted=False):
super(TestResult, self).stopTest(test)
Augie Fackler
run-tests: stop storing start/stop times in a dict by test name...
r24331 test.stopped = os.times()
anuraggoel
run-tests: '--time' option provide more details to Linux users...
r21977
Augie Fackler
run-tests: stop storing start/stop times in a dict by test name...
r24331 starttime = test.started
endtime = test.stopped
Pierre-Yves David
run-tests: track start and end time of tests...
r25097 origin = self._firststarttime
Pierre-Yves David
run-tests: spread and document the content of time tuple...
r24984 self.times.append((test.name,
endtime[2] - starttime[2], # user space CPU time
endtime[3] - starttime[3], # sys space CPU time
endtime[4] - starttime[4], # real time
Pierre-Yves David
run-tests: track start and end time of tests...
r25097 starttime[4] - origin, # start date in run context
endtime[4] - origin, # end date in run context
Pierre-Yves David
run-tests: spread and document the content of time tuple...
r24984 ))
anuraggoel
run-tests: '--time' option provide more details to Linux users...
r21977
Gregory Szorc
run-tests: capture execution times in TestResult...
r21495 if interrupted:
Augie Fackler
run-tests: switch all uses of iolock.acquire() to a context manager
r25046 with iolock:
self.stream.writeln('INTERRUPTED: %s (after %d seconds)' % (
test.name, self.times[-1][3]))
Gregory Szorc
run-tests: capture execution times in TestResult...
r21495
Gregory Szorc
run-tests: define a custom TestSuite that uses _executetests()...
r21439 class TestSuite(unittest.TestSuite):
Mads Kiilerich
spelling: fixes from proofreading of spell checker issues
r23139 """Custom unittest TestSuite that knows how to execute Mercurial tests."""
Gregory Szorc
run-tests: pass jobs into TestSuite constructor...
r21528
Gregory Szorc
run-tests: make testdir an argument of TestSuite.__init__...
r21533 def __init__(self, testdir, jobs=1, whitelist=None, blacklist=None,
Augie Fackler
run-tests: add --runs-per-test flag...
r24329 retest=False, keywords=None, loop=False, runs_per_test=1,
Matt Mackall
run-tests: show scheduling with --showchannels...
r27396 loadtest=None, showchannels=False,
Gregory Szorc
run-tests: move whitelist and blacklist to named arguments of TestSuite
r21529 *args, **kwargs):
Gregory Szorc
run-tests: pass jobs into TestSuite constructor...
r21528 """Create a new instance that can run tests with a configuration.
Gregory Szorc
run-tests: define a custom TestSuite that uses _executetests()...
r21439
Gregory Szorc
run-tests: make testdir an argument of TestSuite.__init__...
r21533 testdir specifies the directory where tests are executed from. This
is typically the ``tests`` directory from Mercurial's source
repository.
Gregory Szorc
run-tests: pass jobs into TestSuite constructor...
r21528 jobs specifies the number of jobs to run concurrently. Each test
executes on its own thread. Tests actually spawn new processes, so
state mutation should not be an issue.
Gregory Szorc
run-tests: move whitelist and blacklist to named arguments of TestSuite
r21529
timeless
run-tests: skip threading for a single test (issue5040)...
r27880 If there is only one job, it will use the main thread.
Gregory Szorc
run-tests: move whitelist and blacklist to named arguments of TestSuite
r21529 whitelist and blacklist denote tests that have been whitelisted and
blacklisted, respectively. These arguments don't belong in TestSuite.
Instead, whitelist and blacklist should be handled by the thing that
populates the TestSuite with tests. They are present to preserve
backwards compatible behavior which reports skipped tests as part
of the results.
Gregory Szorc
run-tests: make retest a named argument of TestSuite.__init__
r21530
retest denotes whether to retest failed tests. This arguably belongs
outside of TestSuite.
Gregory Szorc
run-tests: make keywords a named argument to TestSuite.__init__...
r21531
keywords denotes key words that will be used to filter which tests
to execute. This arguably belongs outside of TestSuite.
Gregory Szorc
run-tests: move loop to a named argument of TestSuite.__init__
r21532
loop denotes whether to loop over tests forever.
Gregory Szorc
run-tests: pass jobs into TestSuite constructor...
r21528 """
Gregory Szorc
run-tests: define a custom TestSuite that uses _executetests()...
r21439 super(TestSuite, self).__init__(*args, **kwargs)
Gregory Szorc
run-tests: pass jobs into TestSuite constructor...
r21528 self._jobs = jobs
Gregory Szorc
run-tests: move whitelist and blacklist to named arguments of TestSuite
r21529 self._whitelist = whitelist
self._blacklist = blacklist
Gregory Szorc
run-tests: make retest a named argument of TestSuite.__init__
r21530 self._retest = retest
Gregory Szorc
run-tests: make keywords a named argument to TestSuite.__init__...
r21531 self._keywords = keywords
Gregory Szorc
run-tests: move loop to a named argument of TestSuite.__init__
r21532 self._loop = loop
Augie Fackler
run-tests: add --runs-per-test flag...
r24329 self._runs_per_test = runs_per_test
Augie Fackler
run-tests: avoid running the same test instance concurrently...
r24330 self._loadtest = loadtest
Matt Mackall
run-tests: show scheduling with --showchannels...
r27396 self._showchannels = showchannels
Gregory Szorc
run-tests: define a custom TestSuite that uses _executetests()...
r21439
def run(self, result):
Gregory Szorc
run-tests: move test filtering into TestSuite.run()...
r21507 # We have a number of filters that need to be applied. We do this
# here instead of inside Test because it makes the running logic for
# Test simpler.
tests = []
Augie Fackler
run-tests: avoid running the same test instance concurrently...
r24330 num_tests = [0]
Gregory Szorc
run-tests: move test filtering into TestSuite.run()...
r21507 for test in self._tests:
Augie Fackler
run-tests: avoid running the same test instance concurrently...
r24330 def get():
num_tests[0] += 1
if getattr(test, 'should_reload', False):
Jun Wu
run-tests: change test identity from a path to a dict...
r32310 return self._loadtest(test, num_tests[0])
Augie Fackler
run-tests: avoid running the same test instance concurrently...
r24330 return test
Gregory Szorc
run-tests: move test filtering into TestSuite.run()...
r21507 if not os.path.exists(test.path):
result.addSkip(test, "Doesn't exist")
continue
Augie Fackler
tests: fix test-is-whitelisted check in run-tests...
r34267 if not (self._whitelist and test.bname in self._whitelist):
Augie Fackler
run-tests: blacklist entries are bytes, use bname to check blacklisting
r25055 if self._blacklist and test.bname in self._blacklist:
Gregory Szorc
run-tests: move test filtering into TestSuite.run()...
r21507 result.addSkip(test, 'blacklisted')
continue
Gregory Szorc
run-tests: make retest a named argument of TestSuite.__init__
r21530 if self._retest and not os.path.exists(test.errpath):
Gregory Szorc
run-tests: move test filtering into TestSuite.run()...
r21507 result.addIgnore(test, 'not retesting')
continue
Gregory Szorc
run-tests: make keywords a named argument to TestSuite.__init__...
r21531 if self._keywords:
Matt Harbison
run-tests: use context managers for file descriptors...
r35466 with open(test.path, 'rb') as f:
t = f.read().lower() + test.bname.lower()
Gregory Szorc
run-tests: move test filtering into TestSuite.run()...
r21507 ignored = False
Gregory Szorc
run-tests: make keywords a named argument to TestSuite.__init__...
r21531 for k in self._keywords.lower().split():
Gregory Szorc
run-tests: move test filtering into TestSuite.run()...
r21507 if k not in t:
result.addIgnore(test, "doesn't match keyword")
ignored = True
break
if ignored:
continue
Augie Fackler
run-tests: add --runs-per-test flag...
r24329 for _ in xrange(self._runs_per_test):
Augie Fackler
run-tests: avoid running the same test instance concurrently...
r24330 tests.append(get())
Gregory Szorc
run-tests: move _executetests into TestSuite
r21496
Gregory Szorc
run-tests: remove global abort flag...
r21520 runtests = list(tests)
Gregory Szorc
run-tests: move _executetests into TestSuite
r21496 done = queue.Queue()
running = 0
Matt Mackall
run-tests: show scheduling with --showchannels...
r27396 channels = [""] * self._jobs
Gregory Szorc
run-tests: move _executetests into TestSuite
r21496 def job(test, result):
Matt Mackall
run-tests: show scheduling with --showchannels...
r27396 for n, v in enumerate(channels):
if not v:
channel = n
break
Augie Fackler
tests: make run-tests fail early if no channel is found...
r32621 else:
raise ValueError('Could not find output channel')
Matt Mackall
run-tests: show scheduling with --showchannels...
r27396 channels[channel] = "=" + test.name[5:].split(".")[0]
Gregory Szorc
run-tests: move _executetests into TestSuite
r21496 try:
test(result)
done.put(None)
except KeyboardInterrupt:
Bryan O'Sullivan
run-tests: "fix" race condition in race condition fix...
r27933 pass
Gregory Szorc
run-tests: move _executetests into TestSuite
r21496 except: # re-raises
done.put(('!', test, 'run-test raised an error, see traceback'))
raise
Augie Fackler
tests: fix run-tests when there's a bad #if in a test...
r32622 finally:
try:
channels[channel] = ''
except IndexError:
pass
Matt Mackall
run-tests: show scheduling with --showchannels...
r27396
def stat():
count = 0
while channels:
d = '\n%03s ' % count
for n, v in enumerate(channels):
if v:
d += v[0]
channels[n] = v[1:] or '.'
else:
d += ' '
d += ' '
with iolock:
sys.stdout.write(d + ' ')
sys.stdout.flush()
for x in xrange(10):
if channels:
time.sleep(.1)
count += 1
Gregory Szorc
run-tests: move _executetests into TestSuite
r21496
Gregory Szorc
run-tests: wait for test threads after first error...
r24507 stoppedearly = False
Matt Mackall
run-tests: show scheduling with --showchannels...
r27396 if self._showchannels:
statthread = threading.Thread(target=stat, name="stat")
statthread.start()
Gregory Szorc
run-tests: move _executetests into TestSuite
r21496 try:
timeless
run-tests: skip threading for a single test (issue5040)...
r27880 while tests or running:
if not done.empty() or running == self._jobs or not tests:
try:
done.get(True, 1)
running -= 1
if result and result.shouldStop:
stoppedearly = True
break
except queue.Empty:
continue
if tests and not running == self._jobs:
test = tests.pop(0)
if self._loop:
if getattr(test, 'should_reload', False):
num_tests[0] += 1
tests.append(
Jun Wu
run-tests: change test identity from a path to a dict...
r32310 self._loadtest(test, num_tests[0]))
timeless
run-tests: skip threading for a single test (issue5040)...
r27880 else:
tests.append(test)
if self._jobs == 1:
job(test, result)
else:
timeless
run-tests: skip threading for a single test...
r27689 t = threading.Thread(target=job, name=test.name,
args=(test, result))
t.start()
timeless
run-tests: skip threading for a single test (issue5040)...
r27880 running += 1
Gregory Szorc
run-tests: wait for test threads after first error...
r24507
timeless
run-tests: skip threading for a single test (issue5040)...
r27880 # If we stop early we still need to wait on started tests to
# finish. Otherwise, there is a race between the test completing
# and the test's cleanup code running. This could result in the
# test reporting incorrect.
if stoppedearly:
while running:
try:
done.get(True, 1)
running -= 1
except queue.Empty:
continue
Gregory Szorc
run-tests: move _executetests into TestSuite
r21496 except KeyboardInterrupt:
Gregory Szorc
run-tests: remove global abort flag...
r21520 for test in runtests:
test.abort()
Gregory Szorc
run-tests: define a custom TestSuite that uses _executetests()...
r21439
Matt Mackall
run-tests: show scheduling with --showchannels...
r27396 channels = []
Gregory Szorc
run-tests: define a custom TestSuite that uses _executetests()...
r21439 return result
Bryan O'Sullivan
tests: write recent run times to a file named tests/.testtimes...
r27634 # Save the most recent 5 wall-clock runtimes of each test to a
# human-readable text file named .testtimes. Tests are sorted
# alphabetically, while times for each test are listed from oldest to
# newest.
Siddharth Agarwal
run-tests: write test times to output dir
r32717 def loadtimes(outputdir):
Bryan O'Sullivan
tests: write recent run times to a file named tests/.testtimes...
r27634 times = []
try:
Martin von Zweigbergk
testrunner: fix updating of .testtimes file...
r35873 with open(os.path.join(outputdir, b'.testtimes')) as fp:
Bryan O'Sullivan
tests: write recent run times to a file named tests/.testtimes...
r27634 for line in fp:
Martin von Zweigbergk
testrunner: make reading of test times work with #testcases...
r35872 m = re.match('(.*?) ([0-9. ]+)', line)
times.append((m.group(1),
[float(t) for t in m.group(2).split()]))
Bryan O'Sullivan
tests: write recent run times to a file named tests/.testtimes...
r27634 except IOError as err:
if err.errno != errno.ENOENT:
raise
return times
Siddharth Agarwal
run-tests: write test times to output dir
r32717 def savetimes(outputdir, result):
saved = dict(loadtimes(outputdir))
Bryan O'Sullivan
tests: write recent run times to a file named tests/.testtimes...
r27634 maxruns = 5
skipped = set([str(t[0]) for t in result.skipped])
for tdata in result.times:
test, real = tdata[0], tdata[3]
if test not in skipped:
ts = saved.setdefault(test, [])
ts.append(real)
ts[:] = ts[-maxruns:]
Gregory Szorc
run-tests: fix Python 3 incompatibilities...
r28284 fd, tmpname = tempfile.mkstemp(prefix=b'.testtimes',
Siddharth Agarwal
run-tests: write test times to output dir
r32717 dir=outputdir, text=True)
Bryan O'Sullivan
tests: write recent run times to a file named tests/.testtimes...
r27634 with os.fdopen(fd, 'w') as fp:
Gregory Szorc
run-tests: fix Python 3 incompatibilities...
r28284 for name, ts in sorted(saved.items()):
Bryan O'Sullivan
tests: write recent run times to a file named tests/.testtimes...
r27634 fp.write('%s %s\n' % (name, ' '.join(['%.3f' % (t,) for t in ts])))
Siddharth Agarwal
run-tests: write test times to output dir
r32717 timepath = os.path.join(outputdir, b'.testtimes')
Bryan O'Sullivan
tests: write recent run times to a file named tests/.testtimes...
r27634 try:
os.unlink(timepath)
except OSError:
pass
try:
os.rename(tmpname, timepath)
except OSError:
pass
Gregory Szorc
run-tests: define custom result and runner classes for unittest...
r21429 class TextTestRunner(unittest.TextTestRunner):
"""Custom unittest test runner that uses appropriate settings."""
Gregory Szorc
run-tests: print compatible output from TextTestRunner...
r21459 def __init__(self, runner, *args, **kwargs):
super(TextTestRunner, self).__init__(*args, **kwargs)
self._runner = runner
Siddharth Agarwal
run-tests: add a way to list tests, with JSON and XUnit support...
r32704 def listtests(self, test):
result = TestResult(self._runner.options, self.stream,
self.descriptions, 0)
test = sorted(test, key=lambda t: t.name)
for t in test:
print(t.name)
result.addSuccess(t)
if self._runner.options.xunit:
with open(self._runner.options.xunit, "wb") as xuf:
self._writexunit(result, xuf)
if self._runner.options.json:
Siddharth Agarwal
run-tests: write JSON reports to output dir
r32718 jsonpath = os.path.join(self._runner._outputdir, b'report.json')
Siddharth Agarwal
run-tests: add a way to list tests, with JSON and XUnit support...
r32704 with open(jsonpath, 'w') as fp:
self._writejson(result, fp)
return result
Gregory Szorc
run-tests: print compatible output from TextTestRunner...
r21459 def run(self, test):
Gregory Szorc
run-tests: abort tests after first failure in unittest mode...
r21460 result = TestResult(self._runner.options, self.stream,
self.descriptions, self.verbosity)
Gregory Szorc
run-tests: print compatible output from TextTestRunner...
r21459
test(result)
failed = len(result.failures)
skipped = len(result.skipped)
ignored = len(result.ignored)
Augie Fackler
run-tests: switch all uses of iolock.acquire() to a context manager
r25046 with iolock:
self.stream.writeln('')
Gregory Szorc
run-tests: print compatible output from TextTestRunner...
r21459
Augie Fackler
run-tests: switch all uses of iolock.acquire() to a context manager
r25046 if not self._runner.options.noskips:
for test, msg in result.skipped:
Yuya Nishihara
run-tests: include "\n" in formatted message instead of calling writeln()...
r33930 formatted = 'Skipped %s: %s\n' % (test.name, msg)
Yuya Nishihara
run-tests: factor out highlight functions
r33931 self.stream.write(highlightmsg(formatted, result.color))
Augie Fackler
run-tests: switch all uses of iolock.acquire() to a context manager
r25046 for test, msg in result.failures:
Yuya Nishihara
run-tests: include "\n" in formatted message instead of calling writeln()...
r33930 formatted = 'Failed %s: %s\n' % (test.name, msg)
Yuya Nishihara
run-tests: factor out highlight functions
r33931 self.stream.write(highlightmsg(formatted, result.color))
Augie Fackler
run-tests: switch all uses of iolock.acquire() to a context manager
r25046 for test, msg in result.errors:
self.stream.writeln('Errored %s: %s' % (test.name, msg))
Gregory Szorc
run-tests: print compatible output from TextTestRunner...
r21459
Augie Fackler
run-tests: switch all uses of iolock.acquire() to a context manager
r25046 if self._runner.options.xunit:
Siddharth Agarwal
run-tests: factor out xunit write code into another method...
r32700 with open(self._runner.options.xunit, "wb") as xuf:
self._writexunit(result, xuf)
Augie Fackler
run-tests: add support for xunit test reports...
r22044
Augie Fackler
run-tests: switch all uses of iolock.acquire() to a context manager
r25046 if self._runner.options.json:
Siddharth Agarwal
run-tests: write JSON reports to output dir
r32718 jsonpath = os.path.join(self._runner._outputdir, b'report.json')
Bryan O'Sullivan
run-tests: use a context manager for file I/O
r27773 with open(jsonpath, 'w') as fp:
Siddharth Agarwal
run-tests: factor out json write code into another method...
r32701 self._writejson(result, fp)
anuraggoel
run-tests: added '--json' functionality to store test result in json file...
r22391
Augie Fackler
run-tests: switch all uses of iolock.acquire() to a context manager
r25046 self._runner._checkhglib('Tested')
Gregory Szorc
run-tests: print compatible output from TextTestRunner...
r21459
Siddharth Agarwal
run-tests: write test times to output dir
r32717 savetimes(self._runner._outputdir, result)
Augie Fackler
run-tests: add support for automatically bisecting test failures
r28596
if failed and self._runner.options.known_good_rev:
Jun Wu
run-tests: move bisect logic to a separate method...
r34803 self._bisecttests(t for t, m in result.failures)
Augie Fackler
run-tests: switch all uses of iolock.acquire() to a context manager
r25046 self.stream.writeln(
Gregory Szorc
tests: remove support for warned tests...
r32942 '# Ran %d tests, %d skipped, %d failed.'
% (result.testsRun, skipped + ignored, failed))
Augie Fackler
run-tests: switch all uses of iolock.acquire() to a context manager
r25046 if failed:
self.stream.writeln('python hash seed: %s' %
os.environ['PYTHONHASHSEED'])
if self._runner.options.time:
self.printtimes(result.times)
Gregory Szorc
run-tests: mechanism to report exceptions during test execution...
r35191
if self._runner.options.exceptions:
exceptions = aggregateexceptions(
os.path.join(self._runner._outputdir, b'exceptions'))
self.stream.writeln('Exceptions Report:')
self.stream.writeln('%d total from %d frames' %
Gregory Szorc
run-tests: report tests that exception occurred in...
r36054 (exceptions['total'],
len(exceptions['exceptioncounts'])))
combined = exceptions['combined']
for key in sorted(combined, key=combined.get, reverse=True):
frame, line, exc = key
totalcount, testcount, leastcount, leasttest = combined[key]
self.stream.writeln('%d (%d tests)\t%s: %s (%s - %d total)'
% (totalcount,
testcount,
frame, exc,
leasttest, leastcount))
Gregory Szorc
run-tests: mechanism to report exceptions during test execution...
r35191
Matt Harbison
run-tests: explicitly flush test runner output for Windows stability...
r32907 self.stream.flush()
Matt Mackall
run-tests: attempt to fix iolock handling...
r22104
Gregory Szorc
run-tests: exit with non-0 exit code when tests fail or warn...
r21613 return result
Jun Wu
run-tests: move bisect logic to a separate method...
r34803 def _bisecttests(self, tests):
bisectcmd = ['hg', 'bisect']
bisectrepo = self._runner.options.bisect_repo
if bisectrepo:
bisectcmd.extend(['-R', os.path.abspath(bisectrepo)])
Jun Wu
run-tests: extract Popen logic to a single method...
r34804 def pread(args):
Jun Wu
run-tests: set HGPLAIN=1 when bisecting...
r34805 env = os.environ.copy()
env['HGPLAIN'] = '1'
Jun Wu
run-tests: move bisect logic to a separate method...
r34803 p = subprocess.Popen(args, stderr=subprocess.STDOUT,
Jun Wu
run-tests: set HGPLAIN=1 when bisecting...
r34805 stdout=subprocess.PIPE, env=env)
Jun Wu
run-tests: extract Popen logic to a single method...
r34804 data = p.stdout.read()
Jun Wu
run-tests: move bisect logic to a separate method...
r34803 p.wait()
Jun Wu
run-tests: extract Popen logic to a single method...
r34804 return data
Jun Wu
run-tests: move bisect logic to a separate method...
r34803 for test in tests:
Jun Wu
run-tests: extract Popen logic to a single method...
r34804 pread(bisectcmd + ['--reset']),
pread(bisectcmd + ['--bad', '.'])
pread(bisectcmd + ['--good', self._runner.options.known_good_rev])
Jun Wu
run-tests: move bisect logic to a separate method...
r34803 # TODO: we probably need to forward more options
# that alter hg's behavior inside the tests.
opts = ''
withhg = self._runner.options.with_hg
if withhg:
opts += ' --with-hg=%s ' % shellquote(_strpath(withhg))
rtc = '%s %s %s %s' % (sys.executable, sys.argv[0], opts,
test)
Jun Wu
run-tests: extract Popen logic to a single method...
r34804 data = pread(bisectcmd + ['--command', rtc])
Jun Wu
run-tests: move bisect logic to a separate method...
r34803 m = re.search(
(br'\nThe first (?P<goodbad>bad|good) revision '
br'is:\nchangeset: +\d+:(?P<node>[a-f0-9]+)\n.*\n'
br'summary: +(?P<summary>[^\n]+)\n'),
data, (re.MULTILINE | re.DOTALL))
if m is None:
self.stream.writeln(
'Failed to identify failure point for %s' % test)
continue
dat = m.groupdict()
Augie Fackler
tests: fix up a couple of minor bytes inconsistencies in run-tests.py...
r37759 verb = 'broken' if dat['goodbad'] == b'bad' else 'fixed'
Jun Wu
run-tests: move bisect logic to a separate method...
r34803 self.stream.writeln(
'%s %s by %s (%s)' % (
Augie Fackler
tests: fix up a couple of minor bytes inconsistencies in run-tests.py...
r37759 test, verb, dat['node'].decode('ascii'),
dat['summary'].decode('utf8', 'ignore')))
Jun Wu
run-tests: move bisect logic to a separate method...
r34803
Gregory Szorc
run-tests: capture execution times in TestResult...
r21495 def printtimes(self, times):
Matt Mackall
run-tests: attempt to fix iolock handling...
r22104 # iolock held by run
Gregory Szorc
run-tests: move outputtimes() into unittest runner class...
r21494 self.stream.writeln('# Producing time report')
anuraggoel
run-tests: '--time' option provide more details to Linux users...
r21977 times.sort(key=lambda t: (t[3]))
Pierre-Yves David
run-tests: include 'start' and 'end' in --time output...
r25098 cols = '%7.3f %7.3f %7.3f %7.3f %7.3f %s'
self.stream.writeln('%-7s %-7s %-7s %-7s %-7s %s' %
('start', 'end', 'cuser', 'csys', 'real', 'Test'))
Pierre-Yves David
run-tests: stop explicit expansion of time data...
r24982 for tdata in times:
test = tdata[0]
Pierre-Yves David
run-tests: include 'start' and 'end' in --time output...
r25098 cuser, csys, real, start, end = tdata[1:6]
self.stream.writeln(cols % (start, end, cuser, csys, real, test))
Gregory Szorc
run-tests: define custom result and runner classes for unittest...
r21429
Siddharth Agarwal
run-tests: factor out xunit write code into another method...
r32700 @staticmethod
def _writexunit(result, outf):
Siddharth Agarwal
run-tests: wrap failures in an XUnit 'failure' element...
r32714 # See http://llg.cubic.org/docs/junit/ for a reference.
Siddharth Agarwal
run-tests: factor out xunit write code into another method...
r32700 timesd = dict((t[0], t[3]) for t in result.times)
doc = minidom.Document()
s = doc.createElement('testsuite')
s.setAttribute('name', 'run-tests')
s.setAttribute('tests', str(result.testsRun))
s.setAttribute('errors', "0") # TODO
s.setAttribute('failures', str(len(result.failures)))
s.setAttribute('skipped', str(len(result.skipped) +
len(result.ignored)))
doc.appendChild(s)
for tc in result.successes:
t = doc.createElement('testcase')
t.setAttribute('name', tc.name)
Siddharth Agarwal
run-tests: make time field optional for xunit report...
r32702 tctime = timesd.get(tc.name)
if tctime is not None:
t.setAttribute('time', '%.3f' % tctime)
Siddharth Agarwal
run-tests: factor out xunit write code into another method...
r32700 s.appendChild(t)
for tc, err in sorted(result.faildata.items()):
t = doc.createElement('testcase')
t.setAttribute('name', tc)
Siddharth Agarwal
run-tests: make time field optional for xunit report...
r32702 tctime = timesd.get(tc)
if tctime is not None:
t.setAttribute('time', '%.3f' % tctime)
Siddharth Agarwal
run-tests: factor out xunit write code into another method...
r32700 # createCDATASection expects a unicode or it will
# convert using default conversion rules, which will
# fail if string isn't ASCII.
err = cdatasafe(err).decode('utf-8', 'replace')
cd = doc.createCDATASection(err)
Siddharth Agarwal
run-tests: wrap failures in an XUnit 'failure' element...
r32714 # Use 'failure' here instead of 'error' to match errors = 0,
# failures = len(result.failures) in the testsuite element.
failelem = doc.createElement('failure')
failelem.setAttribute('message', 'output changed')
failelem.setAttribute('type', 'output-mismatch')
failelem.appendChild(cd)
t.appendChild(failelem)
Siddharth Agarwal
run-tests: factor out xunit write code into another method...
r32700 s.appendChild(t)
Siddharth Agarwal
run-tests: add information about skipped tests to XUnit output...
r32715 for tc, message in result.skipped:
# According to the schema, 'skipped' has no attributes. So store
# the skip message as a text node instead.
t = doc.createElement('testcase')
t.setAttribute('name', tc.name)
Augie Fackler
tests: fix run-tests XML reporting on Python 3...
r34270 binmessage = message.encode('utf-8')
message = cdatasafe(binmessage).decode('utf-8', 'replace')
Siddharth Agarwal
run-tests: add information about skipped tests to XUnit output...
r32715 cd = doc.createCDATASection(message)
skipelem = doc.createElement('skipped')
skipelem.appendChild(cd)
t.appendChild(skipelem)
s.appendChild(t)
Siddharth Agarwal
run-tests: factor out xunit write code into another method...
r32700 outf.write(doc.toprettyxml(indent=' ', encoding='utf-8'))
Siddharth Agarwal
run-tests: factor out json write code into another method...
r32701 @staticmethod
def _writejson(result, outf):
timesd = {}
for tdata in result.times:
test = tdata[0]
timesd[test] = tdata[1:]
outcome = {}
groups = [('success', ((tc, None)
for tc in result.successes)),
('failure', result.failures),
('skip', result.skipped)]
for res, testcases in groups:
for tc, __ in testcases:
if tc.name in timesd:
diff = result.faildata.get(tc.name, b'')
Augie Fackler
tests: try and fail more gracefully with broken unicode escapes
r32853 try:
diff = diff.decode('unicode_escape')
except UnicodeDecodeError as e:
diff = '%r decoding diff, sorry' % e
Siddharth Agarwal
run-tests: factor out json write code into another method...
r32701 tres = {'result': res,
'time': ('%0.3f' % timesd[tc.name][2]),
'cuser': ('%0.3f' % timesd[tc.name][0]),
'csys': ('%0.3f' % timesd[tc.name][1]),
'start': ('%0.3f' % timesd[tc.name][3]),
'end': ('%0.3f' % timesd[tc.name][4]),
Augie Fackler
tests: try and fail more gracefully with broken unicode escapes
r32853 'diff': diff,
Siddharth Agarwal
run-tests: factor out json write code into another method...
r32701 }
else:
# blacklisted test
tres = {'result': res}
outcome[tc.name] = tres
jsonout = json.dumps(outcome, sort_keys=True, indent=4,
separators=(',', ': '))
outf.writelines(("testreport =", jsonout))
Martin von Zweigbergk
testrunner: add option to sort tests by previous run time...
r36683 def sorttests(testdescs, previoustimes, shuffle=False):
Gregory Szorc
run-tests: extract sorting of tests to own function...
r35505 """Do an in-place sort of tests."""
if shuffle:
random.shuffle(testdescs)
return
Martin von Zweigbergk
testrunner: add option to sort tests by previous run time...
r36683 if previoustimes:
def sortkey(f):
f = f['path']
if f in previoustimes:
# Use most recent time as estimate
return -previoustimes[f][-1]
else:
# Default to a rather arbitrary value of 1 second for new tests
return -1.0
else:
# keywords for slow tests
slow = {b'svn': 10,
b'cvs': 10,
b'hghave': 10,
b'largefiles-update': 10,
b'run-tests': 10,
b'corruption': 10,
b'race': 10,
b'i18n': 10,
b'check': 100,
b'gendoc': 100,
b'contrib-perf': 200,
}
perf = {}
def sortkey(f):
# run largest tests first, as they tend to take the longest
f = f['path']
Gregory Szorc
run-tests: extract sorting of tests to own function...
r35505 try:
Martin von Zweigbergk
testrunner: add option to sort tests by previous run time...
r36683 return perf[f]
except KeyError:
try:
val = -os.stat(f).st_size
except OSError as e:
if e.errno != errno.ENOENT:
raise
perf[f] = -1e9 # file does not exist, tell early
return -1e9
for kw, mul in slow.items():
if kw in f:
val *= mul
if f.endswith(b'.py'):
val /= 10.0
perf[f] = val / 1000.0
return perf[f]
Gregory Szorc
run-tests: extract sorting of tests to own function...
r35505
testdescs.sort(key=sortkey)
Gregory Szorc
run-tests: establish a class to hold testing state
r21340 class TestRunner(object):
"""Holds context for executing tests.
Tests rely on a lot of state. This object holds it for them.
"""
Gregory Szorc
run-tests: move gettest() into TestRunner
r21357
Gregory Szorc
run-tests: add docstrings
r21536 # Programs required to run tests.
Gregory Szorc
run-tests: move program searching into TestRunner
r21365 REQUIREDTOOLS = [
Augie Fackler
run-tests: even more bytestring annotations for Python 3
r25041 b'diff',
b'grep',
b'unzip',
b'gunzip',
b'bunzip2',
b'sed',
Gregory Szorc
run-tests: move program searching into TestRunner
r21365 ]
Gregory Szorc
run-tests: add docstrings
r21536 # Maps file extensions to test class.
Gregory Szorc
run-tests: move gettest() into TestRunner
r21357 TESTTYPES = [
Augie Fackler
run-tests: even more bytestring annotations for Python 3
r25041 (b'.py', PythonTest),
(b'.t', TTest),
Gregory Szorc
run-tests: move gettest() into TestRunner
r21357 ]
Gregory Szorc
run-tests: move TESTDIR out of a global...
r21341 def __init__(self):
Gregory Szorc
run-tests: add options to runner
r21348 self.options = None
Gregory Szorc
run-tests: report code coverage from source directory...
r24506 self._hgroot = None
Gregory Szorc
run-tests: make attributes of TestRunner internal...
r21534 self._testdir = None
Siddharth Agarwal
run-tests: allow specifying an output dir to write .errs to...
r32716 self._outputdir = None
Gregory Szorc
run-tests: make attributes of TestRunner internal...
r21534 self._hgtmp = None
self._installdir = None
self._bindir = None
self._tmpbinddir = None
self._pythondir = None
self._coveragefile = None
Gregory Szorc
run-tests: move createdfiles out of a global and into TestRunner
r21352 self._createdfiles = []
Yuya Nishihara
run-tests: allow to specify executable of any name by --with-hg...
r28099 self._hgcommand = None
Gregory Szorc
run-tests: move _gethgpath() into TestRunner
r21385 self._hgpath = None
Pierre-Yves David
run-test: ensure the test ports are available before launching test...
r24967 self._portoffset = 0
self._ports = {}
Gregory Szorc
run-tests: establish a class to hold testing state
r21340
Gregory Szorc
run-tests: move option parser logic to TestRunner.run()
r21376 def run(self, args, parser=None):
Gregory Szorc
run-tests: establish TestRunner.run()...
r21366 """Run the test suite."""
Augie Fackler
python3: update killdaemons and run-tests print and exception syntax...
r25031 oldmask = os.umask(0o22)
Gregory Szorc
run-tests: move umask into TestRunner.run()...
r21375 try:
Gregory Szorc
run-tests: move option parser logic to TestRunner.run()
r21376 parser = parser or getparser()
Gregory Szorc
run-tests: convert to argparse...
r35188 options = parseargs(args, parser)
tests = [_bytespath(a) for a in options.tests]
Augie Fackler
tests: add support for listing tests to run in a file...
r34264 if options.test_list is not None:
for listfile in options.test_list:
with open(listfile, 'rb') as f:
Gregory Szorc
run-tests: convert to argparse...
r35188 tests.extend(t for t in f.read().splitlines() if t)
Gregory Szorc
run-tests: move option parser logic to TestRunner.run()
r21376 self.options = options
Gregory Szorc
run-tests: move umask into TestRunner.run()...
r21375 self._checktools()
Gregory Szorc
run-tests: convert to argparse...
r35188 testdescs = self.findtests(tests)
Augie Fackler
run-tests: add a --profile-runner option...
r25107 if options.profile_runner:
import statprof
statprof.start()
Jun Wu
run-tests: rename test description dict to testdesc...
r32311 result = self._run(testdescs)
Augie Fackler
run-tests: add a --profile-runner option...
r25107 if options.profile_runner:
statprof.stop()
statprof.display()
return result
Gregory Szorc
run-tests: move umask into TestRunner.run()...
r21375 finally:
os.umask(oldmask)
Gregory Szorc
run-tests: establish TestRunner.run()...
r21366
Jun Wu
run-tests: rename test description dict to testdesc...
r32311 def _run(self, testdescs):
Augie Fackler
run-tests: even more bytestring annotations for Python 3
r25041 self._testdir = osenvironb[b'TESTDIR'] = getattr(
os, 'getcwdb', os.getcwd)()
Matthieu Laneuville
run-tests: $TESTDIR can be something else than $PWD...
r34963 # assume all tests in same folder for now
if testdescs:
pathname = os.path.dirname(testdescs[0]['path'])
Kyle Lippincott
run-tests: fix TESTDIR if testdescs are absolute paths...
r35065 if pathname:
osenvironb[b'TESTDIR'] = os.path.join(osenvironb[b'TESTDIR'],
pathname)
Siddharth Agarwal
run-tests: allow specifying an output dir to write .errs to...
r32716 if self.options.outputdir:
self._outputdir = canonpath(_bytespath(self.options.outputdir))
else:
self._outputdir = self._testdir
Matthieu Laneuville
run-tests: outputdir also has to be changed if $TESTDIR is not $PWD...
r35096 if testdescs and pathname:
self._outputdir = os.path.join(self._outputdir, pathname)
Martin von Zweigbergk
testrunner: add option to sort tests by previous run time...
r36683 previoustimes = {}
if self.options.order_by_runtime:
previoustimes = dict(loadtimes(self._outputdir))
sorttests(testdescs, previoustimes, shuffle=self.options.random)
Gregory Szorc
run-tests: assign testdir in TestRunner
r21371
Gregory Szorc
run-tests: move hash seed logic to TestRunner
r21370 if 'PYTHONHASHSEED' not in os.environ:
# use a random python hash seed all the time
# we do the randomness ourself to know what seed is used
os.environ['PYTHONHASHSEED'] = str(random.getrandbits(32))
Gregory Szorc
run-tests: move tmpdir calculations into TestRunner
r21369 if self.options.tmpdir:
self.options.keep_tmpdir = True
Augie Fackler
run-tests: move unicode-to-bytes operations on paths to a helper (issue4667)...
r25161 tmpdir = _bytespath(self.options.tmpdir)
Gregory Szorc
run-tests: move tmpdir calculations into TestRunner
r21369 if os.path.exists(tmpdir):
# Meaning of tmpdir has changed since 1.3: we used to create
# HGTMP inside tmpdir; now HGTMP is tmpdir. So fail if
# tmpdir already exists.
Augie Fackler
python3: update killdaemons and run-tests print and exception syntax...
r25031 print("error: temp dir %r already exists" % tmpdir)
Gregory Szorc
run-tests: move tmpdir calculations into TestRunner
r21369 return 1
os.makedirs(tmpdir)
else:
d = None
if os.name == 'nt':
# without this, we get the default temp dir location, but
# in all lowercase, which causes troubles with paths (issue3490)
Augie Fackler
run-tests: even more bytestring annotations for Python 3
r25041 d = osenvironb.get(b'TMP', None)
Augie Fackler
run-tests: python3.5 now supports mkdtemp using bytes for paths...
r25262 tmpdir = tempfile.mkdtemp(b'', b'hgtests.', d)
Augie Fackler
run-tests: even more bytestring annotations for Python 3
r25041
self._hgtmp = osenvironb[b'HGTMP'] = (
os.path.realpath(tmpdir))
Gregory Szorc
run-tests: move tmpdir calculations into TestRunner
r21369
Gregory Szorc
run-tests: move more path calculations into TestRunner
r21368 if self.options.with_hg:
Gregory Szorc
run-tests: make attributes of TestRunner internal...
r21534 self._installdir = None
Augie Fackler
run-tests: work around with_hg being bytes or string depending on provenance
r25042 whg = self.options.with_hg
self._bindir = os.path.dirname(os.path.realpath(whg))
assert isinstance(self._bindir, bytes)
Yuya Nishihara
run-tests: allow to specify executable of any name by --with-hg...
r28099 self._hgcommand = os.path.basename(whg)
Augie Fackler
run-tests: even more bytestring annotations for Python 3
r25041 self._tmpbindir = os.path.join(self._hgtmp, b'install', b'bin')
Gregory Szorc
run-tests: make attributes of TestRunner internal...
r21534 os.makedirs(self._tmpbindir)
Gregory Szorc
run-tests: move more path calculations into TestRunner
r21368
Gregory Szorc
rust: implementation of `hg`...
r35587 normbin = os.path.normpath(os.path.abspath(whg))
normbin = normbin.replace(os.sep.encode('ascii'), b'/')
# Other Python scripts in the test harness need to
# `import mercurial`. If `hg` is a Python script, we assume
# the Mercurial modules are relative to its path and tell the tests
# to load Python modules from its directory.
with open(whg, 'rb') as fh:
initial = fh.read(1024)
if re.match(b'#!.*python', initial):
self._pythondir = self._bindir
# If it looks like our in-repo Rust binary, use the source root.
# This is a bit hacky. But rhg is still not supported outside the
# source directory. So until it is, do the simple thing.
Gregory Szorc
run-tests: fix regular expression for path test...
r35618 elif re.search(b'/rust/target/[^/]+/hg', normbin):
Gregory Szorc
rust: implementation of `hg`...
r35587 self._pythondir = os.path.dirname(self._testdir)
# Fall back to the legacy behavior.
else:
self._pythondir = self._bindir
Gregory Szorc
run-tests: move more path calculations into TestRunner
r21368 else:
Augie Fackler
run-tests: even more bytestring annotations for Python 3
r25041 self._installdir = os.path.join(self._hgtmp, b"install")
Yuya Nishihara
run-tests: drop redundant assignment to BINDIR...
r28098 self._bindir = os.path.join(self._installdir, b"bin")
Yuya Nishihara
run-tests: allow to specify executable of any name by --with-hg...
r28099 self._hgcommand = b'hg'
Gregory Szorc
run-tests: make attributes of TestRunner internal...
r21534 self._tmpbindir = self._bindir
Augie Fackler
run-tests: even more bytestring annotations for Python 3
r25041 self._pythondir = os.path.join(self._installdir, b"lib", b"python")
Gregory Szorc
run-tests: move more path calculations into TestRunner
r21368
Jun Wu
run-tests: use different chg socket directories for different tests...
r28620 # set CHGHG, then replace "hg" command by "chg"
Yuya Nishihara
run-tests: add --with-chg option to run tests using chg...
r28142 chgbindir = self._bindir
Yuya Nishihara
run-tests: add --chg option to install and run tests using chg...
r28143 if self.options.chg or self.options.with_chg:
Yuya Nishihara
run-tests: add --with-chg option to run tests using chg...
r28142 osenvironb[b'CHGHG'] = os.path.join(self._bindir, self._hgcommand)
Yuya Nishihara
hghave: add "chg" flag to skip tests that can't be compatible with chg...
r28880 else:
osenvironb.pop(b'CHGHG', None) # drop flag for hghave
Yuya Nishihara
run-tests: add --chg option to install and run tests using chg...
r28143 if self.options.chg:
self._hgcommand = b'chg'
elif self.options.with_chg:
Yuya Nishihara
run-tests: add --with-chg option to run tests using chg...
r28142 chgbindir = os.path.dirname(os.path.realpath(self.options.with_chg))
self._hgcommand = os.path.basename(self.options.with_chg)
Augie Fackler
run-tests: even more bytestring annotations for Python 3
r25041 osenvironb[b"BINDIR"] = self._bindir
Augie Fackler
run-tests: unblock running python tests in python 3...
r25058 osenvironb[b"PYTHON"] = PYTHON
Gregory Szorc
run-tests: move more path calculations into TestRunner
r21368
Gregory Szorc
run-tests: add --with-python3 to define a Python 3 interpreter...
r28582 if self.options.with_python3:
osenvironb[b'PYTHON3'] = self.options.with_python3
Augie Fackler
run-tests: move unicode-to-bytes operations on paths to a helper (issue4667)...
r25161 fileb = _bytespath(__file__)
Augie Fackler
run-tests: even more bytestring annotations for Python 3
r25041 runtestdir = os.path.abspath(os.path.dirname(fileb))
FUJIWARA Katsunori
run-tests.py: add RUNTESTDIR to refer `tests` of Mercurial...
r25729 osenvironb[b'RUNTESTDIR'] = runtestdir
Augie Fackler
run-tests: move all open-coded sys.version_info checks to PYTHON3 (issue4668)...
r25159 if PYTHON3:
Augie Fackler
run-tests: move unicode-to-bytes operations on paths to a helper (issue4667)...
r25161 sepb = _bytespath(os.pathsep)
Augie Fackler
run-tests: even more bytestring annotations for Python 3
r25041 else:
sepb = os.pathsep
path = [self._bindir, runtestdir] + osenvironb[b"PATH"].split(sepb)
Pierre-Yves David
run-tests: also follow symlink when update PATH with 'run-tests.py' dir...
r24742 if os.path.islink(__file__):
# test helper will likely be at the end of the symlink
Augie Fackler
run-tests: even more bytestring annotations for Python 3
r25041 realfile = os.path.realpath(fileb)
Pierre-Yves David
run-tests: also follow symlink when update PATH with 'run-tests.py' dir...
r24742 realdir = os.path.abspath(os.path.dirname(realfile))
path.insert(2, realdir)
Yuya Nishihara
run-tests: add --with-chg option to run tests using chg...
r28142 if chgbindir != self._bindir:
path.insert(1, chgbindir)
FUJIWARA Katsunori
run-tests.py: add TESTDIR to PATH if it differs from RUNTESTDIR...
r25730 if self._testdir != runtestdir:
path = [self._testdir] + path
Gregory Szorc
run-tests: make attributes of TestRunner internal...
r21534 if self._tmpbindir != self._bindir:
path = [self._tmpbindir] + path
Augie Fackler
run-tests: even more bytestring annotations for Python 3
r25041 osenvironb[b"PATH"] = sepb.join(path)
Gregory Szorc
run-tests: move more path calculations into TestRunner
r21368
Gregory Szorc
run-tests: move pypath manipulation into TestRunner
r21367 # Include TESTDIR in PYTHONPATH so that out-of-tree extensions
# can run .../tests/run-tests.py test-foo where test-foo
# adds an extension to HGRC. Also include run-test.py directory to
# import modules like heredoctest.
Mads Kiilerich
run-tests: include testdir in $PATH so tests easily can use helper tools...
r23859 pypath = [self._pythondir, self._testdir, runtestdir]
Gregory Szorc
run-tests: move pypath manipulation into TestRunner
r21367 # We have to augment PYTHONPATH, rather than simply replacing
# it, in case external libraries are only available via current
# PYTHONPATH. (In particular, the Subversion bindings on OS X
# are in /opt/subversion.)
Augie Fackler
run-tests: even more bytestring annotations for Python 3
r25041 oldpypath = osenvironb.get(IMPL_PATH)
Gregory Szorc
run-tests: move pypath manipulation into TestRunner
r21367 if oldpypath:
pypath.append(oldpypath)
Augie Fackler
run-tests: even more bytestring annotations for Python 3
r25041 osenvironb[IMPL_PATH] = sepb.join(pypath)
Gregory Szorc
run-tests: move pypath manipulation into TestRunner
r21367
FUJIWARA Katsunori
run-tests.py: inherit --pure option from outer run-tests.py execution...
r23935 if self.options.pure:
os.environ["HGTEST_RUN_TESTS_PURE"] = "--pure"
timeless
run-tests: set HGMODULEPOLICY for --pure...
r28905 os.environ["HGMODULEPOLICY"] = "py"
FUJIWARA Katsunori
run-tests.py: inherit --pure option from outer run-tests.py execution...
r23935
Augie Fackler
run-tests: add support for marking tests as very slow...
r26109 if self.options.allow_slow_tests:
os.environ["HGTEST_SLOW"] = "slow"
elif 'HGTEST_SLOW' in os.environ:
del os.environ['HGTEST_SLOW']
Augie Fackler
run-tests: even more bytestring annotations for Python 3
r25041 self._coveragefile = os.path.join(self._testdir, b'.coverage')
Gregory Szorc
run-tests: move pypath manipulation into TestRunner
r21367
Gregory Szorc
run-tests: mechanism to report exceptions during test execution...
r35191 if self.options.exceptions:
exceptionsdir = os.path.join(self._outputdir, b'exceptions')
try:
os.makedirs(exceptionsdir)
except OSError as e:
if e.errno != errno.EEXIST:
raise
# Remove all existing exception reports.
for f in os.listdir(exceptionsdir):
os.unlink(os.path.join(exceptionsdir, f))
osenvironb[b'HGEXCEPTIONSDIR'] = exceptionsdir
logexceptions = os.path.join(self._testdir, b'logexceptions.py')
self.options.extra_config_opt.append(
'extensions.logexceptions=%s' % logexceptions.decode('utf-8'))
Gregory Szorc
run-tests: make attributes of TestRunner internal...
r21534 vlog("# Using TESTDIR", self._testdir)
FUJIWARA Katsunori
run-tests.py: add RUNTESTDIR to refer `tests` of Mercurial...
r25729 vlog("# Using RUNTESTDIR", osenvironb[b'RUNTESTDIR'])
Gregory Szorc
run-tests: make attributes of TestRunner internal...
r21534 vlog("# Using HGTMP", self._hgtmp)
Gregory Szorc
run-tests: establish TestRunner.run()...
r21366 vlog("# Using PATH", os.environ["PATH"])
Augie Fackler
run-tests: even more bytestring annotations for Python 3
r25041 vlog("# Using", IMPL_PATH, osenvironb[IMPL_PATH])
Siddharth Agarwal
run-tests: allow specifying an output dir to write .errs to...
r32716 vlog("# Writing to directory", self._outputdir)
Gregory Szorc
run-tests: establish TestRunner.run()...
r21366
try:
Jun Wu
run-tests: rename test description dict to testdesc...
r32311 return self._runtests(testdescs) or 0
Gregory Szorc
run-tests: establish TestRunner.run()...
r21366 finally:
time.sleep(.1)
self._cleanup()
Gregory Szorc
run-tests: move test discovery logic into a function...
r21363 def findtests(self, args):
"""Finds possible test files from arguments.
If you wish to inject custom tests into the test harness, this would
be a good function to monkeypatch or override in a derived class.
"""
if not args:
if self.options.changed:
proc = Popen4('hg st --rev "%s" -man0 .' %
self.options.changed, None, 0)
stdout, stderr = proc.communicate()
Augie Fackler
run-tests: even more bytestring annotations for Python 3
r25041 args = stdout.strip(b'\0').split(b'\0')
Gregory Szorc
run-tests: move test discovery logic into a function...
r21363 else:
Augie Fackler
run-tests: even more bytestring annotations for Python 3
r25041 args = os.listdir(b'.')
Gregory Szorc
run-tests: move test discovery logic into a function...
r21363
Matthieu Laneuville
run-tests: allow automatic test discovery when providing folder as argument...
r34970 expanded_args = []
for arg in args:
if os.path.isdir(arg):
if not arg.endswith(b'/'):
arg += b'/'
expanded_args.extend([arg + a for a in os.listdir(arg)])
else:
expanded_args.append(arg)
args = expanded_args
Boris Feld
run-tests: restrict the test cases allowed characters...
r38309 testcasepattern = re.compile(br'([\w-]+\.t|py)(#([a-zA-Z0-9_\-\.]+))')
Jun Wu
run-tests: support multiple cases in .t test...
r32317 tests = []
for t in args:
Boris Feld
run-tests: add support for running specific test cases...
r38224 case = None
Jun Wu
run-tests: support multiple cases in .t test...
r32317 if not (os.path.basename(t).startswith(b'test-')
and (t.endswith(b'.py') or t.endswith(b'.t'))):
Boris Feld
run-tests: add support for running specific test cases...
r38224
m = testcasepattern.match(t)
if m is not None:
t, _, case = m.groups()
else:
continue
Jun Wu
run-tests: support multiple cases in .t test...
r32317 if t.endswith(b'.t'):
# .t file may contain multiple test cases
cases = sorted(parsettestcases(t))
if cases:
Boris Feld
run-tests: add support for running specific test cases...
r38224 if case is not None and case in cases:
tests += [{'path': t, 'case': case}]
elif case is not None and case not in cases:
# Ignore invalid cases
pass
else:
tests += [{'path': t, 'case': c} for c in sorted(cases)]
Jun Wu
run-tests: support multiple cases in .t test...
r32317 else:
tests.append({'path': t})
else:
tests.append({'path': t})
return tests
Gregory Szorc
run-tests: move test discovery logic into a function...
r21363
Jun Wu
run-tests: rename test description dict to testdesc...
r32311 def _runtests(self, testdescs):
Jun Wu
run-tests: change test identity from a path to a dict...
r32310 def _reloadtest(test, i):
# convert a test back to its description dict
desc = {'path': test.path}
Jun Wu
run-tests: support multiple cases in .t test...
r32317 case = getattr(test, '_case', None)
if case:
desc['case'] = case
Jun Wu
run-tests: change test identity from a path to a dict...
r32310 return self._gettest(desc, i)
Gregory Szorc
run-tests: move runtests() into TestRunner
r21360 try:
if self.options.restart:
Jun Wu
run-tests: rename test description dict to testdesc...
r32311 orig = list(testdescs)
while testdescs:
Jun Wu
run-tests: support multiple cases in .t test...
r32317 desc = testdescs[0]
Siddharth Agarwal
run-tests: make --restart work with output dir
r32720 # desc['path'] is a relative path
Jun Wu
run-tests: support multiple cases in .t test...
r32317 if 'case' in desc:
errpath = b'%s.%s.err' % (desc['path'], desc['case'])
else:
errpath = b'%s.err' % desc['path']
Siddharth Agarwal
run-tests: make --restart work with output dir
r32720 errpath = os.path.join(self._outputdir, errpath)
Jun Wu
run-tests: support multiple cases in .t test...
r32317 if os.path.exists(errpath):
Gregory Szorc
run-tests: move runtests() into TestRunner
r21360 break
Jun Wu
run-tests: rename test description dict to testdesc...
r32311 testdescs.pop(0)
if not testdescs:
Augie Fackler
python3: update killdaemons and run-tests print and exception syntax...
r25031 print("running all tests")
Jun Wu
run-tests: rename test description dict to testdesc...
r32311 testdescs = orig
Gregory Szorc
run-tests: move runtests() into TestRunner
r21360
Jun Wu
run-tests: rename test description dict to testdesc...
r32311 tests = [self._gettest(d, i) for i, d in enumerate(testdescs)]
Gregory Szorc
run-tests: pass Test instances into TestRunner._executetests()...
r21437
Gregory Szorc
run-tests: don't print results in unittest mode...
r21458 failed = False
Augie Fackler
run-tests: make sure keyword(s) are in bytes and not str
r25050 kws = self.options.keywords
Augie Fackler
run-tests: move all open-coded sys.version_info checks to PYTHON3 (issue4668)...
r25159 if kws is not None and PYTHON3:
Augie Fackler
run-tests: make sure keyword(s) are in bytes and not str
r25050 kws = kws.encode('utf-8')
Gregory Szorc
run-tests: don't print results in unittest mode...
r21458
Gregory Szorc
run-tests: make attributes of TestRunner internal...
r21534 suite = TestSuite(self._testdir,
Gregory Szorc
run-tests: make testdir an argument of TestSuite.__init__...
r21533 jobs=self.options.jobs,
Gregory Szorc
run-tests: move whitelist and blacklist to named arguments of TestSuite
r21529 whitelist=self.options.whitelisted,
blacklist=self.options.blacklist,
Gregory Szorc
run-tests: make retest a named argument of TestSuite.__init__
r21530 retest=self.options.retest,
Augie Fackler
run-tests: make sure keyword(s) are in bytes and not str
r25050 keywords=kws,
Gregory Szorc
run-tests: move loop to a named argument of TestSuite.__init__
r21532 loop=self.options.loop,
Augie Fackler
run-tests: add --runs-per-test flag...
r24329 runs_per_test=self.options.runs_per_test,
Matt Mackall
run-tests: show scheduling with --showchannels...
r27396 showchannels=self.options.showchannels,
Jun Wu
run-tests: change test identity from a path to a dict...
r32310 tests=tests, loadtest=_reloadtest)
Gregory Szorc
run-tests: execute tests via unittest...
r21464 verbosity = 1
if self.options.verbose:
verbosity = 2
runner = TextTestRunner(self, verbosity=verbosity)
Siddharth Agarwal
run-tests: install hg after computing tests to run...
r32703
Siddharth Agarwal
run-tests: add a way to list tests, with JSON and XUnit support...
r32704 if self.options.list_tests:
result = runner.listtests(suite)
Siddharth Agarwal
run-tests: install hg after computing tests to run...
r32703 else:
Siddharth Agarwal
run-tests: add a way to list tests, with JSON and XUnit support...
r32704 if self._installdir:
self._installhg()
self._checkhglib("Testing")
else:
self._usecorrectpython()
if self.options.chg:
assert self._installdir
self._installchg()
Siddharth Agarwal
run-tests: install hg after computing tests to run...
r32703
Siddharth Agarwal
run-tests: add a way to list tests, with JSON and XUnit support...
r32704 result = runner.run(suite)
Gregory Szorc
run-tests: exit with non-0 exit code when tests fail or warn...
r21613
if result.failures:
failed = True
Gregory Szorc
run-tests: move runtests() into TestRunner
r21360
if self.options.anycoverage:
Gregory Szorc
run-tests: make some methods of TestRunner internal
r21378 self._outputcoverage()
Gregory Szorc
run-tests: move runtests() into TestRunner
r21360 except KeyboardInterrupt:
failed = True
Augie Fackler
python3: update killdaemons and run-tests print and exception syntax...
r25031 print("\ninterrupted!")
Gregory Szorc
run-tests: move runtests() into TestRunner
r21360
if failed:
return 1
Pierre-Yves David
run-test: ensure the test ports are available before launching test...
r24967 def _getport(self, count):
port = self._ports.get(count) # do we have a cached entry?
if port is None:
portneeded = 3
# above 100 tries we just give up and let test reports failure
for tries in xrange(100):
allfree = True
timeless
run-tests: fix get port to try differing ports...
r27602 port = self.options.port + self._portoffset
Pierre-Yves David
run-test: ensure the test ports are available before launching test...
r24967 for idx in xrange(portneeded):
if not checkportisavailable(port + idx):
allfree = False
break
self._portoffset += portneeded
if allfree:
break
self._ports[count] = port
return port
Jun Wu
run-tests: rename test description dict to testdesc...
r32311 def _gettest(self, testdesc, count):
Gregory Szorc
run-tests: move gettest() into TestRunner
r21357 """Obtain a Test by looking at its filename.
Returns a Test instance. The Test may not be runnable if it doesn't
map to a known type.
"""
Jun Wu
run-tests: rename test description dict to testdesc...
r32311 path = testdesc['path']
Jun Wu
run-tests: change test identity from a path to a dict...
r32310 lctest = path.lower()
Gregory Szorc
run-tests: move gettest() into TestRunner
r21357 testcls = Test
Gregory Szorc
run-tests: factor refpath into Test classes...
r21501 for ext, cls in self.TESTTYPES:
Gregory Szorc
run-tests: move gettest() into TestRunner
r21357 if lctest.endswith(ext):
testcls = cls
break
Jun Wu
run-tests: change test identity from a path to a dict...
r32310 refpath = os.path.join(self._testdir, path)
Augie Fackler
run-tests: even more bytestring annotations for Python 3
r25041 tmpdir = os.path.join(self._hgtmp, b'child%d' % count)
Gregory Szorc
run-tests: pass temp dir into Test.__init__...
r21504
Jun Wu
run-tests: support multiple cases in .t test...
r32317 # extra keyword parameters. 'case' is used by .t tests
kwds = dict((k, testdesc[k]) for k in ['case'] if k in testdesc)
Siddharth Agarwal
run-tests: allow specifying an output dir to write .errs to...
r32716 t = testcls(refpath, self._outputdir, tmpdir,
Augie Fackler
run-tests: avoid running the same test instance concurrently...
r24330 keeptmpdir=self.options.keep_tmpdir,
debug=self.options.debug,
Jun Wu
test-run-tests: stabilize the test (issue5735)...
r35586 first=self.options.first,
Augie Fackler
run-tests: avoid running the same test instance concurrently...
r24330 timeout=self.options.timeout,
Pierre-Yves David
run-test: ensure the test ports are available before launching test...
r24967 startport=self._getport(count),
Augie Fackler
run-tests: avoid running the same test instance concurrently...
r24330 extraconfigopts=self.options.extra_config_opt,
py3kwarnings=self.options.py3k_warnings,
Yuya Nishihara
run-tests: allow to specify executable of any name by --with-hg...
r28099 shell=self.options.shell,
Jun Wu
run-tests: use different chg socket directories for different tests...
r28620 hgcommand=self._hgcommand,
Jun Wu
runtests: set web.ipv6 if we use IPv6...
r30986 usechg=bool(self.options.with_chg or self.options.chg),
Jun Wu
run-tests: support multiple cases in .t test...
r32317 useipv6=useipv6, **kwds)
Augie Fackler
run-tests: avoid running the same test instance concurrently...
r24330 t.should_reload = True
return t
Gregory Szorc
run-tests: move gettest() into TestRunner
r21357
Gregory Szorc
run-tests: establish TestRunner.run()...
r21366 def _cleanup(self):
Gregory Szorc
run-tests: move cleanup() into TestRunner
r21350 """Clean up state from this test invocation."""
if self.options.keep_tmpdir:
return
Gregory Szorc
run-tests: make attributes of TestRunner internal...
r21534 vlog("# Cleaning up HGTMP", self._hgtmp)
shutil.rmtree(self._hgtmp, True)
Gregory Szorc
run-tests: move createdfiles out of a global and into TestRunner
r21352 for f in self._createdfiles:
Gregory Szorc
run-tests: move cleanup() into TestRunner
r21350 try:
os.remove(f)
except OSError:
pass
Gregory Szorc
run-tests: make some methods of TestRunner internal
r21378 def _usecorrectpython(self):
Gregory Szorc
run-tests: add docstrings
r21536 """Configure the environment to use the appropriate Python in tests."""
# Tests must use the same interpreter as us or bad things will happen.
Augie Fackler
run-tests: even more bytestring annotations for Python 3
r25041 pyexename = sys.platform == 'win32' and b'python.exe' or b'python'
Gregory Szorc
run-tests: move usecorrectpython() into TestRunner
r21351 if getattr(os, 'symlink', None):
vlog("# Making python executable in test path a symlink to '%s'" %
sys.executable)
Gregory Szorc
run-tests: make attributes of TestRunner internal...
r21534 mypython = os.path.join(self._tmpbindir, pyexename)
Gregory Szorc
run-tests: move usecorrectpython() into TestRunner
r21351 try:
if os.readlink(mypython) == sys.executable:
return
os.unlink(mypython)
Augie Fackler
python3: update killdaemons and run-tests print and exception syntax...
r25031 except OSError as err:
Gregory Szorc
run-tests: move usecorrectpython() into TestRunner
r21351 if err.errno != errno.ENOENT:
raise
Gregory Szorc
run-tests: move program searching into TestRunner
r21365 if self._findprogram(pyexename) != sys.executable:
Gregory Szorc
run-tests: move usecorrectpython() into TestRunner
r21351 try:
os.symlink(sys.executable, mypython)
Gregory Szorc
run-tests: move createdfiles out of a global and into TestRunner
r21352 self._createdfiles.append(mypython)
Augie Fackler
python3: update killdaemons and run-tests print and exception syntax...
r25031 except OSError as err:
Gregory Szorc
run-tests: move usecorrectpython() into TestRunner
r21351 # child processes may race, which is harmless
if err.errno != errno.EEXIST:
raise
else:
exedir, exename = os.path.split(sys.executable)
vlog("# Modifying search path to find %s as %s in '%s'" %
(exename, pyexename, exedir))
path = os.environ['PATH'].split(os.pathsep)
while exedir in path:
path.remove(exedir)
os.environ['PATH'] = os.pathsep.join([exedir] + path)
Gregory Szorc
run-tests: move program searching into TestRunner
r21365 if not self._findprogram(pyexename):
Augie Fackler
python3: update killdaemons and run-tests print and exception syntax...
r25031 print("WARNING: Cannot find %s in search path" % pyexename)
Gregory Szorc
run-tests: move usecorrectpython() into TestRunner
r21351
Gregory Szorc
run-tests: make some methods of TestRunner internal
r21378 def _installhg(self):
Gregory Szorc
run-tests: add docstrings
r21536 """Install hg into the test environment.
This will also configure hg with the appropriate testing settings.
"""
Gregory Szorc
run-tests: move installhg() into TestRunner
r21353 vlog("# Performing temporary installation of HG")
timeless
run-tests: move install.err into test area...
r28829 installerrs = os.path.join(self._hgtmp, b"install.err")
Gregory Szorc
run-tests: move installhg() into TestRunner
r21353 compiler = ''
if self.options.compiler:
compiler = '--compiler ' + self.options.compiler
Jordi Gutiérrez Hermoso
style: kill ersatz if-else ternary operators...
r24306 if self.options.pure:
Augie Fackler
run-tests: fix installation of hg by bytesifying more constants
r25044 pure = b"--pure"
Jordi Gutiérrez Hermoso
style: kill ersatz if-else ternary operators...
r24306 else:
Augie Fackler
run-tests: fix installation of hg by bytesifying more constants
r25044 pure = b""
Gregory Szorc
run-tests: move installhg() into TestRunner
r21353
# Run installer in hg root
script = os.path.realpath(sys.argv[0])
Augie Fackler
run-tests: fix installation of hg by bytesifying more constants
r25044 exe = sys.executable
Augie Fackler
run-tests: move all open-coded sys.version_info checks to PYTHON3 (issue4668)...
r25159 if PYTHON3:
Augie Fackler
run-tests: move unicode-to-bytes operations on paths to a helper (issue4667)...
r25161 compiler = _bytespath(compiler)
script = _bytespath(script)
exe = _bytespath(exe)
Gregory Szorc
run-tests: move installhg() into TestRunner
r21353 hgroot = os.path.dirname(os.path.dirname(script))
Gregory Szorc
run-tests: report code coverage from source directory...
r24506 self._hgroot = hgroot
Gregory Szorc
run-tests: move installhg() into TestRunner
r21353 os.chdir(hgroot)
Augie Fackler
run-tests: fix installation of hg by bytesifying more constants
r25044 nohome = b'--home=""'
Gregory Szorc
run-tests: move installhg() into TestRunner
r21353 if os.name == 'nt':
# The --home="" trick works only on OS where os.sep == '/'
# because of a distutils convert_path() fast-path. Avoid it at
# least on Windows for now, deal with .pydistutils.cfg bugs
# when they happen.
Augie Fackler
run-tests: fix installation of hg by bytesifying more constants
r25044 nohome = b''
Gregory Szorc
run-tests: remove 2to3 support...
r28397 cmd = (b'%(exe)s setup.py %(pure)s clean --all'
Augie Fackler
run-tests: fix installation of hg by bytesifying more constants
r25044 b' build %(compiler)s --build-base="%(base)s"'
b' install --force --prefix="%(prefix)s"'
b' --install-lib="%(libdir)s"'
b' --install-scripts="%(bindir)s" %(nohome)s >%(logfile)s 2>&1'
Gregory Szorc
run-tests: remove 2to3 support...
r28397 % {b'exe': exe, b'pure': pure,
Augie Fackler
run-tests: fix installation of hg by bytesifying more constants
r25044 b'compiler': compiler,
b'base': os.path.join(self._hgtmp, b"build"),
b'prefix': self._installdir, b'libdir': self._pythondir,
b'bindir': self._bindir,
b'nohome': nohome, b'logfile': installerrs})
Gregory Szorc
run-tests: ensure install directories exist...
r24075
# setuptools requires install directories to exist.
def makedirs(p):
try:
os.makedirs(p)
Augie Fackler
python3: update killdaemons and run-tests print and exception syntax...
r25031 except OSError as e:
Gregory Szorc
run-tests: ensure install directories exist...
r24075 if e.errno != errno.EEXIST:
raise
makedirs(self._pythondir)
makedirs(self._bindir)
Gregory Szorc
run-tests: move installhg() into TestRunner
r21353 vlog("# Running", cmd)
if os.system(cmd) == 0:
if not self.options.verbose:
Augie Fackler
run-tests: ignore failed removal of nonexistent installerrs...
r26087 try:
os.remove(installerrs)
except OSError as e:
if e.errno != errno.ENOENT:
raise
Gregory Szorc
run-tests: move installhg() into TestRunner
r21353 else:
Matt Harbison
run-tests: use context managers for file descriptors...
r35466 with open(installerrs, 'rb') as f:
for line in f:
if PYTHON3:
sys.stdout.buffer.write(line)
else:
sys.stdout.write(line)
Gregory Szorc
run-tests: move installhg() into TestRunner
r21353 sys.exit(1)
Gregory Szorc
run-tests: make attributes of TestRunner internal...
r21534 os.chdir(self._testdir)
Gregory Szorc
run-tests: move installhg() into TestRunner
r21353
Gregory Szorc
run-tests: make some methods of TestRunner internal
r21378 self._usecorrectpython()
Gregory Szorc
run-tests: move installhg() into TestRunner
r21353
if self.options.py3k_warnings and not self.options.anycoverage:
vlog("# Updating hg command to enable Py3k Warnings switch")
Matt Harbison
run-tests: use context managers for file descriptors...
r35466 with open(os.path.join(self._bindir, 'hg'), 'rb') as f:
lines = [line.rstrip() for line in f]
lines[0] += ' -3'
with open(os.path.join(self._bindir, 'hg'), 'wb') as f:
for line in lines:
f.write(line + '\n')
Gregory Szorc
run-tests: move installhg() into TestRunner
r21353
Augie Fackler
run-tests: fix installation of hg by bytesifying more constants
r25044 hgbat = os.path.join(self._bindir, b'hg.bat')
Gregory Szorc
run-tests: move installhg() into TestRunner
r21353 if os.path.isfile(hgbat):
# hg.bat expects to be put in bin/scripts while run-tests.py
# installation layout put it in bin/ directly. Fix it
Matt Harbison
run-tests: use context managers for file descriptors...
r35466 with open(hgbat, 'rb') as f:
data = f.read()
Augie Fackler
run-tests: fix installation of hg by bytesifying more constants
r25044 if b'"%~dp0..\python" "%~dp0hg" %*' in data:
data = data.replace(b'"%~dp0..\python" "%~dp0hg" %*',
b'"%~dp0python" "%~dp0hg" %*')
Matt Harbison
run-tests: use context managers for file descriptors...
r35466 with open(hgbat, 'wb') as f:
f.write(data)
Gregory Szorc
run-tests: move installhg() into TestRunner
r21353 else:
Augie Fackler
python3: update killdaemons and run-tests print and exception syntax...
r25031 print('WARNING: cannot fix hg.bat reference to python.exe')
Gregory Szorc
run-tests: move installhg() into TestRunner
r21353
if self.options.anycoverage:
Gregory Szorc
run-tests: make attributes of TestRunner internal...
r21534 custom = os.path.join(self._testdir, 'sitecustomize.py')
target = os.path.join(self._pythondir, 'sitecustomize.py')
Gregory Szorc
run-tests: move installhg() into TestRunner
r21353 vlog('# Installing coverage trigger to %s' % target)
shutil.copyfile(custom, target)
Gregory Szorc
run-tests: make attributes of TestRunner internal...
r21534 rc = os.path.join(self._testdir, '.coveragerc')
Gregory Szorc
run-tests: move installhg() into TestRunner
r21353 vlog('# Installing coverage rc to %s' % rc)
os.environ['COVERAGE_PROCESS_START'] = rc
Gregory Szorc
run-tests: collect aggregate code coverage...
r24505 covdir = os.path.join(self._installdir, '..', 'coverage')
try:
os.mkdir(covdir)
Augie Fackler
python3: update killdaemons and run-tests print and exception syntax...
r25031 except OSError as e:
Gregory Szorc
run-tests: collect aggregate code coverage...
r24505 if e.errno != errno.EEXIST:
raise
os.environ['COVERAGE_DIR'] = covdir
Gregory Szorc
run-tests: move installhg() into TestRunner
r21353
Gregory Szorc
run-tests: make some methods of TestRunner internal
r21378 def _checkhglib(self, verb):
Gregory Szorc
run-tests: move checkhglib into TestRunner
r21354 """Ensure that the 'mercurial' package imported by python is
the one we expect it to be. If not, print a warning to stderr."""
Pierre-Yves David
run-tests: don't check for the mercurial library used when using --with-hg...
r21733 if ((self._bindir == self._pythondir) and
(self._bindir != self._tmpbindir)):
Mads Kiilerich
spelling: fixes from proofreading of spell checker issues
r23139 # The pythondir has been inferred from --with-hg flag.
# We cannot expect anything sensible here.
Pierre-Yves David
run-tests: don't check for the mercurial library used when using --with-hg...
r21733 return
Augie Fackler
run-tests: fix installation of hg by bytesifying more constants
r25044 expecthg = os.path.join(self._pythondir, b'mercurial')
Gregory Szorc
run-tests: move _gethgpath() into TestRunner
r21385 actualhg = self._gethgpath()
Gregory Szorc
run-tests: move checkhglib into TestRunner
r21354 if os.path.abspath(actualhg) != os.path.abspath(expecthg):
sys.stderr.write('warning: %s with unexpected mercurial lib: %s\n'
' (expected %s)\n'
% (verb, actualhg, expecthg))
Gregory Szorc
run-tests: move _gethgpath() into TestRunner
r21385 def _gethgpath(self):
"""Return the path to the mercurial package that is actually found by
the current Python interpreter."""
if self._hgpath is not None:
return self._hgpath
Augie Fackler
run-tests: unblock running python tests in python 3...
r25058 cmd = b'%s -c "import mercurial; print (mercurial.__path__[0])"'
cmd = cmd % PYTHON
Augie Fackler
run-tests: move all open-coded sys.version_info checks to PYTHON3 (issue4668)...
r25159 if PYTHON3:
Augie Fackler
run-tests: replace open-coded .decode()s on paths with a helper (issue4667)...
r25162 cmd = _strpath(cmd)
Augie Fackler
run-tests: unblock running python tests in python 3...
r25058 pipe = os.popen(cmd)
Gregory Szorc
run-tests: move _gethgpath() into TestRunner
r21385 try:
Augie Fackler
run-tests: move unicode-to-bytes operations on paths to a helper (issue4667)...
r25161 self._hgpath = _bytespath(pipe.read().strip())
Gregory Szorc
run-tests: move _gethgpath() into TestRunner
r21385 finally:
pipe.close()
return self._hgpath
Gregory Szorc
run-tests: move checkhglib into TestRunner
r21354
Yuya Nishihara
run-tests: add --chg option to install and run tests using chg...
r28143 def _installchg(self):
"""Install chg into the test environment"""
vlog('# Performing temporary installation of CHG')
assert os.path.dirname(self._bindir) == self._installdir
assert self._hgroot, 'must be called after _installhg()'
cmd = (b'"%(make)s" clean install PREFIX="%(prefix)s"'
% {b'make': 'make', # TODO: switch by option or environment?
b'prefix': self._installdir})
cwd = os.path.join(self._hgroot, b'contrib', b'chg')
vlog("# Running", cmd)
proc = subprocess.Popen(cmd, shell=True, cwd=cwd,
stdin=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
out, _err = proc.communicate()
if proc.returncode != 0:
if PYTHON3:
sys.stdout.buffer.write(out)
else:
sys.stdout.write(out)
sys.exit(1)
Gregory Szorc
run-tests: make some methods of TestRunner internal
r21378 def _outputcoverage(self):
Gregory Szorc
run-tests: add docstrings
r21536 """Produce code coverage output."""
Pulkit Goyal
py3: make files use absolute_import and print_function...
r29485 import coverage
coverage = coverage.coverage
Gregory Szorc
run-tests: move outputcoverage() into TestRunner
r21356
Gregory Szorc
run-tests: obtain code coverage via Python API...
r24504 vlog('# Producing coverage report')
# chdir is the easiest way to get short, relative paths in the
# output.
Gregory Szorc
run-tests: report code coverage from source directory...
r24506 os.chdir(self._hgroot)
Gregory Szorc
run-tests: collect aggregate code coverage...
r24505 covdir = os.path.join(self._installdir, '..', 'coverage')
cov = coverage(data_file=os.path.join(covdir, 'cov'))
Gregory Szorc
run-tests: report code coverage from source directory...
r24506
# Map install directory paths back to source directory.
cov.config.paths['srcdir'] = ['.', self._pythondir]
Gregory Szorc
run-tests: collect aggregate code coverage...
r24505 cov.combine()
Gregory Szorc
run-tests: move outputcoverage() into TestRunner
r21356
Gregory Szorc
run-tests: obtain code coverage via Python API...
r24504 omit = [os.path.join(x, '*') for x in [self._bindir, self._testdir]]
cov.report(ignore_errors=True, omit=omit)
Gregory Szorc
run-tests: move outputcoverage() into TestRunner
r21356 if self.options.htmlcov:
Siddharth Agarwal
run-tests: output coverage to output dir...
r32719 htmldir = os.path.join(self._outputdir, 'htmlcov')
Gregory Szorc
run-tests: obtain code coverage via Python API...
r24504 cov.html_report(directory=htmldir, omit=omit)
Gregory Szorc
run-tests: move outputcoverage() into TestRunner
r21356 if self.options.annotate:
Siddharth Agarwal
run-tests: output coverage to output dir...
r32719 adir = os.path.join(self._outputdir, 'annotated')
Gregory Szorc
run-tests: move outputcoverage() into TestRunner
r21356 if not os.path.isdir(adir):
os.mkdir(adir)
Gregory Szorc
run-tests: obtain code coverage via Python API...
r24504 cov.annotate(directory=adir, omit=omit)
Gregory Szorc
run-tests: move outputcoverage() into TestRunner
r21356
Gregory Szorc
run-tests: move program searching into TestRunner
r21365 def _findprogram(self, program):
"""Search PATH for a executable program"""
Augie Fackler
run-tests: move unicode-to-bytes operations on paths to a helper (issue4667)...
r25161 dpb = _bytespath(os.defpath)
sepb = _bytespath(os.pathsep)
Augie Fackler
run-tests: fix _findprogram to reliably return bytes
r25038 for p in osenvironb.get(b'PATH', dpb).split(sepb):
Gregory Szorc
run-tests: move program searching into TestRunner
r21365 name = os.path.join(p, program)
if os.name == 'nt' or os.access(name, os.X_OK):
return name
return None
Gregory Szorc
run-tests: move checktools into TestRunner.run()
r21374 def _checktools(self):
Gregory Szorc
run-tests: add docstrings
r21536 """Ensure tools required to run tests are present."""
Gregory Szorc
run-tests: move program searching into TestRunner
r21365 for p in self.REQUIREDTOOLS:
if os.name == 'nt' and not p.endswith('.exe'):
p += '.exe'
found = self._findprogram(p)
if found:
vlog("# Found prerequisite", p, "at", found)
else:
timeless
py3: convert prereq bytes to string in run-tests...
r28698 print("WARNING: Did not find prerequisite tool: %s " %
p.decode("utf-8"))
Gregory Szorc
run-tests: move program searching into TestRunner
r21365
Gregory Szorc
run-tests: mechanism to report exceptions during test execution...
r35191 def aggregateexceptions(path):
Gregory Szorc
run-tests: report tests that exception occurred in...
r36054 exceptioncounts = collections.Counter()
testsbyfailure = collections.defaultdict(set)
failuresbytest = collections.defaultdict(set)
Gregory Szorc
run-tests: mechanism to report exceptions during test execution...
r35191
for f in os.listdir(path):
with open(os.path.join(path, f), 'rb') as fh:
data = fh.read().split(b'\0')
Gregory Szorc
run-tests: report tests that exception occurred in...
r36054 if len(data) != 5:
Gregory Szorc
run-tests: mechanism to report exceptions during test execution...
r35191 continue
Gregory Szorc
run-tests: report tests that exception occurred in...
r36054 exc, mainframe, hgframe, hgline, testname = data
Gregory Szorc
run-tests: mechanism to report exceptions during test execution...
r35191 exc = exc.decode('utf-8')
mainframe = mainframe.decode('utf-8')
hgframe = hgframe.decode('utf-8')
hgline = hgline.decode('utf-8')
Gregory Szorc
run-tests: report tests that exception occurred in...
r36054 testname = testname.decode('utf-8')
key = (hgframe, hgline, exc)
exceptioncounts[key] += 1
testsbyfailure[key].add(testname)
failuresbytest[testname].add(key)
# Find test having fewest failures for each failure.
leastfailing = {}
for key, tests in testsbyfailure.items():
fewesttest = None
fewestcount = 99999999
for test in sorted(tests):
if len(failuresbytest[test]) < fewestcount:
fewesttest = test
fewestcount = len(failuresbytest[test])
leastfailing[key] = (fewestcount, fewesttest)
# Create a combined counter so we can sort by total occurrences and
# impacted tests.
combined = {}
for key in exceptioncounts:
combined[key] = (exceptioncounts[key],
len(testsbyfailure[key]),
leastfailing[key][0],
leastfailing[key][1])
return {
'exceptioncounts': exceptioncounts,
'total': sum(exceptioncounts.values()),
'combined': combined,
'leastfailing': leastfailing,
'byfailure': testsbyfailure,
'bytest': failuresbytest,
}
Gregory Szorc
run-tests: mechanism to report exceptions during test execution...
r35191
Simon Heimberg
run-tests: loadable as module
r13347 if __name__ == '__main__':
Gregory Szorc
run-tests: eliminate main()
r21377 runner = TestRunner()
Matt Mackall
run-tests: self-test on Windows needs binary streams
r22120
try:
import msvcrt
msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY)
msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
msvcrt.setmode(sys.stderr.fileno(), os.O_BINARY)
except ImportError:
pass
Gregory Szorc
run-tests: eliminate main()
r21377 sys.exit(runner.run(sys.argv[1:]))