##// END OF EJS Templates
store: use `endswith` to detect revlog extension...
store: use `endswith` to detect revlog extension Suggested by Gregory Szorc. Differential Revision: https://phab.mercurial-scm.org/D9865

File last commit:

r47101:2bd77a6d default
r47112:374d7fff default
Show More
run-tests.py
3823 lines | 128.9 KiB | text/x-python | PythonLexer
Gregory Szorc
global: use python3 in shebangs...
r46434 #!/usr/bin/env python3
Stephen Darnell
Add a pure python version of run-tests....
r2110 #
# 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
Matt Harbison
run-tests: use a context manager when looking for available ports...
r46569 import contextlib
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
Gregory Szorc
run-tests: run tests with as many processes as cores by default...
r40281 import multiprocessing
Vadim Gelfer
tests: add timeouts, make run-tests.py clean up dead daemon processes...
r2571 import os
Raphaël Gomès
run-tests: add option for running with and without Rust extensions...
r44973 import platform
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
Augie Fackler
tests: add support for emitting trace events to run-tests...
r39289 import uuid
Pulkit Goyal
py3: make files use absolute_import and print_function...
r29485 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
Augie Fackler
formatting: blacken the codebase...
r43346
Adam Simpkins
tests: more completely restore the environment in syshgenv...
r33121 shellquote = shlex.quote
except (ImportError, AttributeError):
import pipes
Augie Fackler
formatting: blacken the codebase...
r43346
Adam Simpkins
tests: more completely restore the environment in syshgenv...
r33121 shellquote = pipes.quote
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':
Augie Fackler
formatting: blacken the codebase...
r43346 try: # is pygments installed
Matt Harbison
run-tests: disable color on Windows...
r33500 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
Augie Fackler
formatting: blacken the codebase...
r43346
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:
Augie Fackler
formatting: blacken the codebase...
r43346
Matthieu Laneuville
run-tests: also color the summary messages (skipped, failed...)
r33813 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 = {
Augie Fackler
formatting: blacken the codebase...
r43346 skipped: '#e5e5e5',
skippedname: '#00ffff',
failed: '#7f0000',
failedname: '#ff0000',
Matthieu Laneuville
run-tests: also color the summary messages (skipped, failed...)
r33813 }
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),
Augie Fackler
formatting: blacken the codebase...
r43346 ],
Matthieu Laneuville
run-tests: also color the summary messages (skipped, failed...)
r33813 }
Matthieu Laneuville
run-tests: pre instantiate pygments objects...
r33868 runnerformatter = formatters.Terminal256Formatter(style=TestRunnerStyle)
runnerlexer = TestRunnerLexer()
Matt Harbison
py3: ensure run-tests.osenvironb is actually bytes...
r39681 origenviron = os.environ.copy()
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
formatting: blacken the codebase...
r43346 xrange = range # we use xrange in one place, and we'd rather not use range
Manuel Jacob
tests: rename _bytespath() to _sys2bytes() and _strpath() to _sys2str()...
r44935 def _sys2bytes(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
Manuel Jacob
tests: rename _bytespath() to _sys2bytes() and _strpath() to _sys2str()...
r44935 def _bytes2sys(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')
Matt Harbison
py3: ensure run-tests.osenvironb is actually bytes...
r39681 osenvironb = getattr(os, 'environb', None)
if osenvironb is None:
Matt Harbison
py3: make osenvironb a proxy for, instead of a copy of os.environ where needed...
r39750 # Windows lacks os.environb, for instance. A proxy over the real thing
# instead of a copy allows the environment to be updated via bytes on
# all platforms.
class environbytes(object):
def __init__(self, strenv):
self.__len__ = strenv.__len__
self.clear = strenv.clear
self._strenv = strenv
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Harbison
py3: make osenvironb a proxy for, instead of a copy of os.environ where needed...
r39750 def __getitem__(self, k):
Manuel Jacob
tests: rename _bytespath() to _sys2bytes() and _strpath() to _sys2str()...
r44935 v = self._strenv.__getitem__(_bytes2sys(k))
return _sys2bytes(v)
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Harbison
py3: make osenvironb a proxy for, instead of a copy of os.environ where needed...
r39750 def __setitem__(self, k, v):
Manuel Jacob
tests: rename _bytespath() to _sys2bytes() and _strpath() to _sys2str()...
r44935 self._strenv.__setitem__(_bytes2sys(k), _bytes2sys(v))
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Harbison
py3: make osenvironb a proxy for, instead of a copy of os.environ where needed...
r39750 def __delitem__(self, k):
Manuel Jacob
tests: rename _bytespath() to _sys2bytes() and _strpath() to _sys2str()...
r44935 self._strenv.__delitem__(_bytes2sys(k))
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Harbison
py3: make osenvironb a proxy for, instead of a copy of os.environ where needed...
r39750 def __contains__(self, k):
Manuel Jacob
tests: rename _bytespath() to _sys2bytes() and _strpath() to _sys2str()...
r44935 return self._strenv.__contains__(_bytes2sys(k))
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Harbison
py3: make osenvironb a proxy for, instead of a copy of os.environ where needed...
r39750 def __iter__(self):
Manuel Jacob
tests: rename _bytespath() to _sys2bytes() and _strpath() to _sys2str()...
r44935 return iter([_sys2bytes(k) for k in iter(self._strenv)])
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Harbison
py3: make osenvironb a proxy for, instead of a copy of os.environ where needed...
r39750 def get(self, k, default=None):
Manuel Jacob
tests: rename _bytespath() to _sys2bytes() and _strpath() to _sys2str()...
r44935 v = self._strenv.get(_bytes2sys(k), _bytes2sys(default))
return _sys2bytes(v)
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Harbison
py3: make osenvironb a proxy for, instead of a copy of os.environ where needed...
r39750 def pop(self, k, default=None):
Manuel Jacob
tests: rename _bytespath() to _sys2bytes() and _strpath() to _sys2str()...
r44935 v = self._strenv.pop(_bytes2sys(k), _bytes2sys(default))
return _sys2bytes(v)
Matt Harbison
py3: make osenvironb a proxy for, instead of a copy of os.environ where needed...
r39750
osenvironb = environbytes(os.environ)
Matt Harbison
py3: ensure run-tests.osenvironb is actually bytes...
r39681
Matt Harbison
run-tests: avoid os.getcwdb() on Windows...
r39754 getcwdb = getattr(os, 'getcwdb')
if not getcwdb or os.name == 'nt':
Manuel Jacob
tests: rename _bytespath() to _sys2bytes() and _strpath() to _sys2str()...
r44935 getcwdb = lambda: _sys2bytes(os.getcwd())
Matt Harbison
run-tests: avoid os.getcwdb() on Windows...
r39754
Augie Fackler
run-tests: insist that if people use Python 3, they use 3.5.x...
r25160 elif sys.version_info >= (3, 0, 0):
Augie Fackler
formatting: blacken the codebase...
r43346 print(
'%s is only supported on Python 3.5+ and 2.7, not %s'
% (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.
Manuel Jacob
tests: rename _bytespath() to _sys2bytes() and _strpath() to _sys2str()...
r44935 def _sys2bytes(p):
Augie Fackler
run-tests: move unicode-to-bytes operations on paths to a helper (issue4667)...
r25161 return p
Augie Fackler
run-tests: work around the rename of xrange to range
r25033
Manuel Jacob
tests: rename _bytespath() to _sys2bytes() and _strpath() to _sys2str()...
r44935 _bytes2sys = _sys2bytes
Matt Harbison
py3: ensure run-tests.osenvironb is actually bytes...
r39681 osenvironb = os.environ
Matt Harbison
run-tests: avoid os.getcwdb() on Windows...
r39754 getcwdb = os.getcwd
Augie Fackler
run-tests: replace open-coded .decode()s on paths with a helper (issue4667)...
r25162
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
Augie Fackler
formatting: blacken the codebase...
r43346
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
Augie Fackler
formatting: blacken the codebase...
r43346
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:
Matt Harbison
run-tests: use a context manager when looking for available ports...
r46569 with contextlib.closing(socket.socket(family, socket.SOCK_STREAM)) as s:
s.bind(('localhost', port))
Jun Wu
runtests: unindent an "if True" block...
r30987 return True
except socket.error as exc:
Matt Harbison
run-tests: catch a Windows specific error when testing for a free socket...
r47045 if os.name == 'nt' and exc.errno == errno.WSAEACCES:
return False
elif exc.errno not in (
Augie Fackler
formatting: blacken the codebase...
r43346 errno.EADDRINUSE,
errno.EADDRNOTAVAIL,
errno.EPROTONOSUPPORT,
):
Jun Wu
runtests: unindent an "if True" block...
r30987 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
Augie Fackler
formatting: blacken the codebase...
r43346
Martin Geisler
util: always use subprocess
r8280 closefds = os.name == 'posix'
Augie Fackler
formatting: blacken the codebase...
r43346
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()
Augie Fackler
formatting: blacken the codebase...
r43346 p = subprocess.Popen(
Manuel Jacob
tests: rename _bytespath() to _sys2bytes() and _strpath() to _sys2str()...
r44935 _bytes2sys(cmd),
Augie Fackler
formatting: blacken the codebase...
r43346 shell=True,
bufsize=-1,
Manuel Jacob
tests: rename _bytespath() to _sys2bytes() and _strpath() to _sys2str()...
r44935 cwd=_bytes2sys(wd),
Augie Fackler
formatting: blacken the codebase...
r43346 env=env,
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:
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Mackall
run-tests: switch timeout handling from alarm to helper thread...
r14001 def t():
start = time.time()
while time.time() - start < timeout and p.returncode is None:
Augie Fackler
formatting: blacken the codebase...
r43346 time.sleep(0.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)
Augie Fackler
formatting: blacken the codebase...
r43346
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
formatting: blacken the codebase...
r43346
Rodrigo Damazio Bovendorp
pycompat: make fewer assumptions about sys.executable...
r42723 if sys.executable:
sysexecutable = sys.executable
elif os.environ.get('PYTHONEXECUTABLE'):
sysexecutable = os.environ['PYTHONEXECUTABLE']
elif os.environ.get('PYTHON'):
sysexecutable = os.environ['PYTHON']
else:
raise AssertionError('Could not find Python interpreter')
Manuel Jacob
tests: rename _bytespath() to _sys2bytes() and _strpath() to _sys2str()...
r44935 PYTHON = _sys2bytes(sysexecutable.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
testlib: adjust wait-on-file timeout according to the global test timeout...
r45122 default_defaults = {
Gregory Szorc
run-tests: run tests with as many processes as cores by default...
r40281 'jobs': ('HGTEST_JOBS', multiprocessing.cpu_count()),
Thomas Arendsen Hein
run-tests.py: Allow environment variables to set jobs/timeout/port.
r6366 'timeout': ('HGTEST_TIMEOUT', 180),
tests: increase timeout for slow test...
r41966 'slowtimeout': ('HGTEST_SLOWTIMEOUT', 1500),
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 }
testlib: adjust wait-on-file timeout according to the global test timeout...
r45122 defaults = default_defaults.copy()
Augie Fackler
formatting: blacken the codebase...
r43346
timeless
run-tests: add canonpath function...
r28644 def canonpath(path):
return os.path.realpath(os.path.expanduser(path))
Augie Fackler
formatting: blacken the codebase...
r43346
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
Augie Fackler
formatting: blacken the codebase...
r43346
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.
"""
Martin von Zweigbergk
testrunner: allow multiple #testcases...
r38860 cases = []
Jun Wu
run-tests: support multiple cases in .t test...
r32317 try:
with open(path, 'rb') as f:
for l in f:
if l.startswith(b'#testcases '):
Martin von Zweigbergk
testrunner: allow multiple #testcases...
r38860 cases.append(sorted(l[11:].split()))
Jun Wu
run-tests: support multiple cases in .t test...
r32317 except IOError as ex:
if ex.errno != errno.ENOENT:
raise
return cases
Augie Fackler
formatting: blacken the codebase...
r43346
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')
Augie Fackler
formatting: blacken the codebase...
r43346 selection.add_argument(
'--allow-slow-tests',
action='store_true',
help='allow extremely slow tests',
)
selection.add_argument(
"--blacklist",
action="append",
help="skip tests listed in the specified blacklist file",
)
selection.add_argument(
"--changed",
help="run tests that are changed in parent rev or working directory",
)
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",
help="always run tests listed in the specified whitelist file",
)
selection.add_argument(
'tests', metavar='TESTS', nargs='*', help='Tests to run'
)
Gregory Szorc
run-tests: organize options into argument groups...
r35189
harness = parser.add_argument_group('Test Harness Behavior')
Augie Fackler
formatting: blacken the codebase...
r43346 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"
Augie Fackler
formatting: blacken the codebase...
r43346 " rather than capturing and diffing it (disables timeout)",
)
harness.add_argument(
"-f",
"--first",
action="store_true",
help="exit on the first test failure",
)
harness.add_argument(
"-i",
"--interactive",
action="store_true",
help="prompt to accept changed output",
)
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"
Augie Fackler
formatting: blacken the codebase...
r43346 " (default: $%s or %d)" % defaults['jobs'],
)
harness.add_argument(
"--keep-tmpdir",
action="store_true",
help="keep temporary directory after running tests",
)
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",
help="list tests instead of running them",
)
harness.add_argument(
"--loop", action="store_true", help="loop tests repeatedly"
)
harness.add_argument(
'--random', action="store_true", help='run tests in random order'
)
harness.add_argument(
'--order-by-runtime',
action="store_true",
help='run slowest tests first, according to .testtimes',
)
harness.add_argument(
"-p",
"--port",
type=int,
Gregory Szorc
run-tests: organize options into argument groups...
r35189 help="port on which servers should listen"
Augie Fackler
formatting: blacken the codebase...
r43346 " (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,
Gregory Szorc
run-tests: organize options into argument groups...
r35189 help="kill errant slow tests after SLOWTIMEOUT seconds"
Augie Fackler
formatting: blacken the codebase...
r43346 " (default: $%s or %d)" % defaults['slowtimeout'],
)
harness.add_argument(
"-t",
"--timeout",
type=int,
Gregory Szorc
run-tests: organize options into argument groups...
r35189 help="kill errant tests after TIMEOUT seconds"
Augie Fackler
formatting: blacken the codebase...
r43346 " (default: $%s or %d)" % defaults['timeout'],
)
harness.add_argument(
"--tmpdir",
Gregory Szorc
run-tests: organize options into argument groups...
r35189 help="run tests in the given temporary directory"
Augie Fackler
formatting: blacken the codebase...
r43346 " (implies --keep-tmpdir)",
)
harness.add_argument(
"-v", "--verbose", action="store_true", help="output verbose messages"
)
Gregory Szorc
run-tests: organize options into argument groups...
r35189
hgconf = parser.add_argument_group('Mercurial Configuration')
Augie Fackler
formatting: blacken the codebase...
r43346 hgconf.add_argument(
"--chg",
action="store_true",
help="install and use chg wrapper in place of hg",
)
Pulkit Goyal
run-tests: add --chg-debug flag to show chg debug output...
r45105 hgconf.add_argument(
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 "--chg-debug",
action="store_true",
help="show chg debug logs",
Pulkit Goyal
run-tests: add --chg-debug flag to show chg debug output...
r45105 )
Augie Fackler
formatting: blacken the codebase...
r43346 hgconf.add_argument("--compiler", help="compiler to build with")
hgconf.add_argument(
'--extra-config-opt',
action="append",
default=[],
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, "
Augie Fackler
formatting: blacken the codebase...
r43346 "and --with-chg=<testdir>/../contrib/chg/chg if --chg is set",
)
hgconf.add_argument(
"--ipv6",
action="store_true",
help="prefer IPv6 to IPv4 for network related tests",
)
hgconf.add_argument(
"--pure",
action="store_true",
help="use pure Python code instead of C extensions",
)
hgconf.add_argument(
Raphaël Gomès
run-tests: add option for running with and without Rust extensions...
r44973 "--rust",
Augie Fackler
formatting: blacken the codebase...
r43346 action="store_true",
Raphaël Gomès
run-tests: add option for running with and without Rust extensions...
r44973 help="use Rust code alongside C extensions",
)
hgconf.add_argument(
"--no-rust",
action="store_true",
help="do not use Rust code even if compiled",
Augie Fackler
formatting: blacken the codebase...
r43346 )
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 "
Augie Fackler
formatting: blacken the codebase...
r43346 "temporary installation",
)
Gregory Szorc
run-tests: organize options into argument groups...
r35189
reporting = parser.add_argument_group('Results Reporting')
Augie Fackler
formatting: blacken the codebase...
r43346 reporting.add_argument(
"-C",
"--annotate",
action="store_true",
help="output files annotated with coverage",
)
reporting.add_argument(
"--color",
choices=["always", "auto", "never"],
Gregory Szorc
run-tests: organize options into argument groups...
r35189 default=os.environ.get('HGRUNTESTSCOLOR', 'auto'),
Augie Fackler
formatting: blacken the codebase...
r43346 help="colorisation: always|auto|never (default: auto)",
)
reporting.add_argument(
"-c",
"--cover",
action="store_true",
help="print a test coverage report",
)
reporting.add_argument(
'--exceptions',
action='store_true',
help='log all exceptions and generate an exception report',
)
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
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
run-tests: allow option parser to be extended...
r21008 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
Raphaël Gomès
run-tests: add option for running with and without Rust extensions...
r44973 if platform.python_implementation() != 'CPython' and options.rust:
parser.error('Rust extensions are only available with CPython')
if options.pure and options.rust:
parser.error('--rust cannot be used with --pure')
if options.rust and options.no_rust:
parser.error('--rust cannot be used with --no-rust')
Greg Ward
run-tests: redefine --with-hg so it takes the 'hg' script to run....
r8674 if options.local:
Martin von Zweigbergk
run-tests: error out on `--local --with-[c]hg`...
r43084 if options.with_hg or options.with_chg:
parser.error('--local cannot be used with --with-hg or --with-chg')
Manuel Jacob
tests: rename _bytespath() to _sys2bytes() and _strpath() to _sys2str()...
r44935 testdir = os.path.dirname(_sys2bytes(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):
Augie Fackler
formatting: blacken the codebase...
r43346 parser.error(
'--local specified, but %r not found or '
'not executable' % binpath
)
Manuel Jacob
tests: rename _bytespath() to _sys2bytes() and _strpath() to _sys2str()...
r44935 setattr(options, attr, _bytes2sys(binpath))
Martin von Zweigbergk
run-tests: handle --local before --with-hg...
r43085
if options.with_hg:
Manuel Jacob
tests: rename _bytespath() to _sys2bytes() and _strpath() to _sys2str()...
r44935 options.with_hg = canonpath(_sys2bytes(options.with_hg))
Augie Fackler
formatting: blacken the codebase...
r43346 if not (
os.path.isfile(options.with_hg)
and os.access(options.with_hg, os.X_OK)
):
Martin von Zweigbergk
run-tests: handle --local before --with-hg...
r43085 parser.error('--with-hg must specify an executable hg script')
if os.path.basename(options.with_hg) not in [b'hg', b'hg.exe']:
sys.stderr.write('warning: --with-hg should specify an hg script\n')
sys.stderr.flush()
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
Manuel Jacob
tests: rename _bytespath() to _sys2bytes() and _strpath() to _sys2str()...
r44935 options.with_chg = canonpath(_sys2bytes(options.with_chg))
Augie Fackler
formatting: blacken the codebase...
r43346 if not (
os.path.isfile(options.with_chg)
and os.access(options.with_chg, os.X_OK)
):
Yuya Nishihara
run-tests: add --with-chg option to run tests using chg...
r28142 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
Augie Fackler
formatting: blacken the codebase...
r43346 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:
Augie Fackler
formatting: blacken the codebase...
r43346 sys.stderr.write(
'warning: --color=always ignored because '
'pygments is not installed\n'
)
Martin von Zweigbergk
run-tests: warn if --color=always and no pygments installed...
r33567
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
Augie Fackler
formatting: blacken the codebase...
r43346 useipv6 = (not checksocketfamily('AF_INET')) and checksocketfamily(
'AF_INET6'
)
Jun Wu
runtests: add an IPv6 command line flag...
r31011
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
Augie Fackler
formatting: blacken the codebase...
r43346
Dirkjan Ochtman
tests: use external coverage, mandate newer version...
r10648 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
Augie Fackler
formatting: blacken the codebase...
r43346 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:
Augie Fackler
formatting: blacken the codebase...
r43346 parser.error(
"sorry, coverage options do not work when --with-hg " "is specified"
)
Gregory Szorc
run-tests: report code coverage from source directory...
r24506
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']:
Augie Fackler
formatting: blacken the codebase...
r43346 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(
Augie Fackler
formatting: blacken the codebase...
r43346 '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
Gregory Szorc
run-tests: add --with-python3 to define a Python 3 interpreter...
r28582
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
Augie Fackler
formatting: blacken the codebase...
r43346
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
formatting: blacken the codebase...
r43346
Yuya Nishihara
run-tests: fix permission to clean up unreadable directories...
r41023 def makecleanable(path):
"""Try to fix directory permission recursively so that the entire tree
can be deleted"""
for dirpath, dirnames, _filenames in os.walk(path, topdown=True):
for d in dirnames:
p = os.path.join(dirpath, d)
try:
os.chmod(p, os.stat(p).st_mode & 0o777 | 0o700) # chmod u+rwx
except OSError:
pass
Augie Fackler
formatting: blacken the codebase...
r43346
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
Augie Fackler
formatting: blacken the codebase...
r43346
Augie Fackler
run-tests: use difflib.diff_bytes on Python 3...
r25045 _unified_diff = functools.partial(difflib.diff_bytes, difflib.unified_diff)
Augie Fackler
formatting: blacken the codebase...
r43346
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
formatting: blacken the codebase...
r43346 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
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Mackall
run-tests: make vlog a proper function
r19250 verbose = False
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Mackall
run-tests: make vlog a proper function
r19250 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
formatting: blacken the codebase...
r43346
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
Gregory Szorc
run-tests: use raw strings for regular expressions...
r41681 optline = re.compile(br'(.*) \((.+?) !\)\n$')
Matt Harbison
run-tests: support per-line conditional output in tests...
r31829
Augie Fackler
formatting: blacken the codebase...
r43346
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
Augie Fackler
formatting: blacken the codebase...
r43346
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
Augie Fackler
formatting: blacken the codebase...
r43346
Yuya Nishihara
run-tests: factor out highlight functions
r33931 def highlightdiff(line, color):
if not color:
return line
assert pygmentspresent
Augie Fackler
formatting: blacken the codebase...
r43346 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)
Augie Fackler
formatting: blacken the codebase...
r43346
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
Augie Fackler
formatting: blacken the codebase...
r43346
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
Augie Fackler
formatting: blacken the codebase...
r43346
return killmod.killdaemons(pidfile, tryhard=False, remove=True, 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
Augie Fackler
formatting: blacken the codebase...
r43346 def __init__(
self,
path,
outputdir,
tmpdir,
keeptmpdir=False,
debug=False,
first=False,
timeout=None,
startport=None,
extraconfigopts=None,
shell=None,
hgcommand=None,
slowtimeout=None,
usechg=False,
Pulkit Goyal
run-tests: add --chg-debug flag to show chg debug output...
r45105 chgdebug=False,
Augie Fackler
formatting: blacken the codebase...
r43346 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
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
Antoine cezar
run-test: allow relative path in `--blacklist` and `--whitelist` (issue6351)...
r46086 self.relpath = os.path.relpath(path)
Augie Fackler
run-tests: be more judicious about bytes vs string on test attrs...
r25039 self.bname = os.path.basename(path)
Manuel Jacob
tests: rename _bytespath() to _sys2bytes() and _strpath() to _sys2str()...
r44935 self.name = _bytes2sys(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 []
Manuel Jacob
tests: rename _bytespath() to _sys2bytes() and _strpath() to _sys2str()...
r44935 self._shell = _sys2bytes(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
Pulkit Goyal
run-tests: add --chg-debug flag to show chg debug output...
r45105 self._chgdebug = chgdebug
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:
Augie Fackler
formatting: blacken the codebase...
r43346 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:
Augie Fackler
formatting: blacken the codebase...
r43346 self._chgsockdir = os.path.join(
self._threadtmp, b'%s.chgsock' % name
)
Jun Wu
run-tests: use different chg socket directories for different tests...
r28620 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:
Augie Fackler
formatting: blacken the codebase...
r43346 if out is None: # Debug mode, nothing to parse.
Gregory Szorc
run-tests: add skip processing to Test
r21324 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.
Augie Fackler
formatting: blacken the codebase...
r43346 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:
Augie Fackler
formatting: blacken the codebase...
r43346 log(
'\nKeeping testtmp dir: %s\nKeeping threadtmp dir: %s'
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 % (
_bytes2sys(self._testtmp),
_bytes2sys(self._threadtmp),
)
Augie Fackler
formatting: blacken the codebase...
r43346 )
timeless@mozdev.org
run-tests: report paths saved by --keep-tmpdir
r26422 else:
Yuya Nishihara
run-tests: fix permission to clean up unreadable directories...
r41023 try:
shutil.rmtree(self._testtmp)
except OSError:
# unreadable directory may be left in $TESTTMP; fix permission
# and try again
makecleanable(self._testtmp)
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)
Augie Fackler
formatting: blacken the codebase...
r43346 if (
(self._ret != 0 or self._out != self._refout)
and not self._skipped
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$'),
Augie Fackler
formatting: blacken the codebase...
r43346 ]
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':
Augie Fackler
formatting: blacken the codebase...
r43346 return 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
for c in [p[i : i + 1] for i in range(len(p))]
timeless
run-tests: factor out _escapepath
r28055 )
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')
Manuel Jacob
tests: rename _bytespath() to _sys2bytes() and _strpath() to _sys2str()...
r44935 testenv['HGTEST_RESTOREENV'] = _bytes2sys(scriptpath)
Adam Simpkins
tests: more completely restore the environment in syshgenv...
r33121
# 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."""
Augie Fackler
formatting: blacken the codebase...
r43346
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)
Augie Fackler
formatting: blacken the codebase...
r43346
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'
Manuel Jacob
tests: rename _bytespath() to _sys2bytes() and _strpath() to _sys2str()...
r44935 env['TESTTMP'] = _bytes2sys(self._testtmp)
Gregory Szorc
run-tests: report tests that exception occurred in...
r36054 env['TESTNAME'] = self.name
Manuel Jacob
tests: rename _bytespath() to _sys2bytes() and _strpath() to _sys2str()...
r44935 env['HOME'] = _bytes2sys(self._testtmp)
Matt Harbison
run-tests: configure the environment to expand `~` properly with Windows py38+...
r46708 if os.name == 'nt':
# py3.8+ ignores HOME: https://bugs.python.org/issue36264
env['USERPROFILE'] = env['HOME']
testlib: adjust wait-on-file timeout according to the global test timeout...
r45122 formated_timeout = _bytes2sys(b"%d" % default_defaults['timeout'][1])
env['HGTEST_TIMEOUT_DEFAULT'] = formated_timeout
env['HGTEST_TIMEOUT'] = _bytes2sys(b"%d" % self._timeout)
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)
Manuel Jacob
tests: rename _bytespath() to _sys2bytes() and _strpath() to _sys2str()...
r44935 env["HGRCPATH"] = _bytes2sys(os.path.join(self._threadtmp, b'.hgrc'))
env["DAEMON_PIDS"] = _bytes2sys(
Augie Fackler
formatting: blacken the codebase...
r43346 os.path.join(self._threadtmp, b'daemon.pids')
)
env["HGEDITOR"] = (
'"' + sysexecutable + '"' + ' -c "import sys; sys.exit(0)"'
)
env["HGUSER"] = "test"
Gregory Szorc
run-tests: move createenv() into Test...
r21299 env["HGENCODING"] = "ascii"
env["HGENCODINGMODE"] = "strict"
Augie Fackler
tests: force a stable hostname in patchbomb tests...
r39155 env["HGHOSTNAME"] = "test-hostname"
Jun Wu
runtests: export HGIPV6 to hint test scripts whether to use IPv6...
r31003 env['HGIPV6'] = str(int(self._useipv6))
Kyle Lippincott
catapult: add a bit more documentation on how to use catapult tracing...
r40526 # See contrib/catapipe.py for how to use this functionality.
Kyle Lippincott
catapult: introduce HGTESTCATAPULTSERVERPIPE to control run-tests' tracing...
r40525 if 'HGTESTCATAPULTSERVERPIPE' not in env:
# If we don't have HGTESTCATAPULTSERVERPIPE explicitly set, pull the
# non-test one in as a default, otherwise set to devnull
Augie Fackler
cleanup: use () to wrap long lines instead of \...
r41925 env['HGTESTCATAPULTSERVERPIPE'] = env.get(
Augie Fackler
formatting: blacken the codebase...
r43346 'HGCATAPULTSERVERPIPE', os.devnull
)
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:
Matt Harbison
run-tests: fix `HGTESTEXTRAEXTENSIONS` with py3...
r46707 section, key = opt.split('.', 1)
Gregory Szorc
tests: conditionalize tests based on presence of custom extensions...
r37360 if section != 'extensions':
continue
Matt Harbison
run-tests: fix `HGTESTEXTRAEXTENSIONS` with py3...
r46707 name = key.split('=', 1)[0]
Gregory Szorc
tests: conditionalize tests based on presence of custom extensions...
r37360 extraextensions.append(name)
if extraextensions:
Matt Harbison
run-tests: fix `HGTESTEXTRAEXTENSIONS` with py3...
r46707 env['HGTESTEXTRAEXTENSIONS'] = ' '.join(extraextensions)
Gregory Szorc
tests: conditionalize tests based on presence of custom extensions...
r37360
Jun Wu
runtests: export LOCALIP...
r31006 # LOCALIP could be ::1 or 127.0.0.1. Useful for tests that require raw
# IP addresses.
Manuel Jacob
tests: rename _bytespath() to _sys2bytes() and _strpath() to _sys2str()...
r44935 env['LOCALIP'] = _bytes2sys(self._localip())
Jun Wu
runtests: export LOCALIP...
r31006
Matt Harbison
py3: spawn all python instances with legacy stdio enabled on Windows...
r41017 # This has the same effect as Py_LegacyWindowsStdioFlag in exewrapper.c,
# but this is needed for testing python instances like dummyssh,
# dummysmtpd.py, and dumbhttp.py.
if PYTHON3 and os.name == 'nt':
env['PYTHONLEGACYWINDOWSSTDIO'] = '1'
Gregory Szorc
tests: add test for Rust formatting...
r44271 # Modified HOME in test environment can confuse Rust tools. So set
# CARGO_HOME and RUSTUP_HOME automatically if a Rust toolchain is
# present and these variables aren't already defined.
cargo_home_path = os.path.expanduser('~/.cargo')
rustup_home_path = os.path.expanduser('~/.rustup')
if os.path.exists(cargo_home_path) and b'CARGO_HOME' not in osenvironb:
env['CARGO_HOME'] = cargo_home_path
if (
os.path.exists(rustup_home_path)
and b'RUSTUP_HOME' not in osenvironb
):
env['RUSTUP_HOME'] = rustup_home_path
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'
Boris Feld
run-tests: explicitly declare the list of dropped environment variable...
r40505 dropped = [
'CDPATH',
'CHGDEBUG',
'EDITOR',
'GREP_OPTIONS',
'HG',
Boris Feld
run-tests: define the default merge tool through configuration...
r40506 'HGMERGE',
Boris Feld
run-tests: explicitly declare the list of dropped environment variable...
r40505 'HGPLAIN',
'HGPLAINEXCEPT',
'HGPROF',
'http_proxy',
'no_proxy',
'NO_PROXY',
'PAGER',
'VISUAL',
]
for k in dropped:
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')
Pulkit Goyal
run-tests: add --chg-debug flag to show chg debug output...
r45105 if self._chgdebug:
env['CHGDEBUG'] = 'true'
Jun Wu
run-tests: use different chg socket directories for different tests...
r28620
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')
Martin von Zweigbergk
errors: add config that lets user get more detailed exit codes...
r46430 hgrc.write(b'detailed-exit-code = True\n')
Boris Feld
run-tests: define the default merge tool through configuration...
r40506 hgrc.write(b'merge = internal:merge\n')
Matt Harbison
run-tests: use context managers for file descriptors...
r35466 hgrc.write(b'mergemarkers = detailed\n')
hgrc.write(b'promptecho = True\n')
run-tests: allow some slack about 'waiting on lock' message...
r46636 hgrc.write(b'timeout.warn=15\n')
Matt Harbison
run-tests: use context managers for file descriptors...
r35466 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')
Augie Fackler
formatting: blacken the codebase...
r43346 hgrc.write(
b'usercache = %s\n'
% (os.path.join(self._testtmp, b'.cache/largefiles'))
)
Matt Harbison
run-tests: use context managers for file descriptors...
r35466 hgrc.write(b'[lfs]\n')
Augie Fackler
formatting: blacken the codebase...
r43346 hgrc.write(
b'usercache = %s\n'
% (os.path.join(self._testtmp, b'.cache/lfs'))
)
Matt Harbison
run-tests: use context managers for file descriptors...
r35466 hgrc.write(b'[web]\n')
hgrc.write(b'address = localhost\n')
Manuel Jacob
tests: avoid implicit conversion of str to unicode...
r44933 hgrc.write(b'ipv6 = %r\n' % self._useipv6)
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:
Manuel Jacob
tests: avoid implicit conversion of str to unicode...
r44936 section, key = _sys2bytes(opt).split(b'.', 1)
Augie Fackler
formatting: blacken the codebase...
r43346 assert b'=' in key, (
'extra config opt %s must ' 'have an = for assignment' % opt
)
Matt Harbison
run-tests: use context managers for file descriptors...
r35466 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:
Augie Fackler
formatting: blacken the codebase...
r43346 proc = subprocess.Popen(
Manuel Jacob
tests: rename _bytespath() to _sys2bytes() and _strpath() to _sys2str()...
r44935 _bytes2sys(cmd),
shell=True,
cwd=_bytes2sys(self._testtmp),
env=env,
Augie Fackler
formatting: blacken the codebase...
r43346 )
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)
Augie Fackler
formatting: blacken the codebase...
r43346
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
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:
Matt Harbison
py3: add a missing b'' for Windows...
r39742 output = output.replace(b'\r\n', b'\n')
Gregory Szorc
run-tests: separate newline normalization from replacements...
r24510
Gregory Szorc
run-tests: move run into Test class...
r24508 return ret, output.splitlines(True)
Augie Fackler
formatting: blacken the codebase...
r43346
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):
Matt Harbison
run-tests: restore quoting the python executable for running *.py tests...
r40306 # Quote the python(3) executable for Windows
Gregory Szorc
run-tests: remove --py3-warnings...
r44602 cmd = b'"%s" "%s"' % (PYTHON, self.path)
Denis Laxalde
py3: decode bytes before logging in run-tests.py...
r43614 vlog("# Running", cmd.decode("utf-8"))
Gregory Szorc
run-tests: separate newline normalization from replacements...
r24510 normalizenewlines = os.name == 'nt'
Augie Fackler
formatting: blacken the codebase...
r43346 result = self._runcommand(cmd, env, 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
formatting: blacken the codebase...
r43346
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])
run-tests: use symbolic constant instead of arbitrary number line matching...
r43134 WARN_UNDEFINED = 1
WARN_YES = 2
WARN_NO = 3
run-tests: add a dedicated 'isoptional' function...
r43171 MARK_OPTIONAL = b" (?)\n"
Augie Fackler
formatting: blacken the codebase...
r43346
run-tests: add a dedicated 'isoptional' function...
r43171 def isoptional(line):
return line.endswith(MARK_OPTIONAL)
Augie Fackler
formatting: blacken the codebase...
r43346
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
Augie Fackler
cleanup: run pyupgrade on our source tree to clean up varying things...
r44937 ESCAPEMAP = {bchr(i): br'\x%02x' % i for i in range(256)}
Augie Fackler
run-tests: even more bytestring annotations for Python 3
r25041 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
testrunner: allow multiple #testcases...
r38860 case = kwds.pop('case', [])
Jun Wu
run-tests: support multiple cases in .t test...
r32317 self._case = case
Martin von Zweigbergk
testrunner: allow multiple #testcases...
r38860 self._allcases = {x for y in parsettestcases(path) for x in y}
Jun Wu
run-tests: support multiple cases in .t test...
r32317 super(TTest, self).__init__(path, *args, **kwds)
if case:
Augie Fackler
tests: fix bytes/str issues in run-tests.py caught by python3...
r38969 casepath = b'#'.join(case)
Manuel Jacob
tests: rename _bytespath() to _sys2bytes() and _strpath() to _sys2str()...
r44935 self.name = '%s#%s' % (self.name, _bytes2sys(casepath))
Martin von Zweigbergk
testrunner: allow multiple #testcases...
r38860 self.errpath = b'%s#%s.err' % (self.errpath[:-4], casepath)
Pulkit Goyal
run-tests: replace '#' with '-' in temp path of repos created for tests...
r45668 self._tmpname += b'-%s' % casepath.replace(b'#', b'-')
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)
Denis Laxalde
py3: decode bytes before logging in run-tests.py...
r43614 vlog("# Running", cmd.decode("utf-8"))
Gregory Szorc
run-tests: move t test execution from tsttest() to TTest.run()...
r21313
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)
runtest: move slow timeout process earlier in the `_hghave` method...
r41968
self._detectslow(reqs)
Matt Harbison
run-tests: cache hghave results...
r36480 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.
run-tests: fix conditional when tests are run outside of `tests`...
r44978 runtestdir = osenvironb[b'RUNTESTDIR']
FUJIWARA Katsunori
run-tests.py: execute hghave by the path relative to run-tests.py...
r25728 tdir = runtestdir.replace(b'\\', b'/')
Augie Fackler
formatting: blacken the codebase...
r43346 proc = Popen4(
b'%s -c "%s/hghave %s"' % (self._shell, tdir, allreqs),
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
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
runtest: extract the logic that update timeout for slow tests...
r41967 def _detectslow(self, reqs):
"""update the timeout of slow test when appropriate"""
if b'slow' in reqs:
self._timeout = self._slowtimeout
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:
Martin von Zweigbergk
testrunner: allow multiple #testcases...
r38860 if arg[3:] in self._case:
Jun Wu
run-tests: support multiple cases in .t test...
r32317 return False
elif arg in self._allcases:
Martin von Zweigbergk
testrunner: allow multiple #testcases...
r38860 if arg not in self._case:
Jun Wu
run-tests: support multiple cases in .t test...
r32317 return False
else:
reqs.append(arg)
runtest: also update slow test timeout during `#if` clauses...
r41969 self._detectslow(reqs)
Jun Wu
run-tests: support multiple cases in .t test...
r32317 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()
Augie Fackler
formatting: blacken the codebase...
r43346
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))
Augie Fackler
formatting: blacken the codebase...
r43346
Kyle Lippincott
catapult: rename 'active' to 'activetrace'; this isn't storing a boolean state...
r40524 activetrace = []
Augie Fackler
tests: add support for emitting trace events to run-tests...
r39289 session = str(uuid.uuid4())
if PYTHON3:
session = session.encode('ascii')
Augie Fackler
formatting: blacken the codebase...
r43346 hgcatapult = os.getenv('HGTESTCATAPULTSERVERPIPE') or os.getenv(
'HGCATAPULTSERVERPIPE'
)
Kyle Lippincott
catapult: fix broken run-tests catapult tracing...
r40523 def toggletrace(cmd=None):
if not hgcatapult or hgcatapult == os.devnull:
return
Kyle Lippincott
catapult: rename 'active' to 'activetrace'; this isn't storing a boolean state...
r40524 if activetrace:
Kyle Lippincott
catapult: fix broken run-tests catapult tracing...
r40523 script.append(
Augie Fackler
formatting: blacken the codebase...
r43346 b'echo END %s %s >> "$HGTESTCATAPULTSERVERPIPE"\n'
% (session, activetrace[0])
)
Kyle Lippincott
catapult: fix broken run-tests catapult tracing...
r40523 if cmd is None:
return
Augie Fackler
tests: avoid shellquoting bytes on Python 3...
r39433 if isinstance(cmd, str):
quoted = shellquote(cmd.strip())
else:
quoted = shellquote(cmd.strip().decode('utf8')).encode('utf8')
quoted = quoted.replace(b'\\', b'\\\\')
Kyle Lippincott
catapult: fix broken run-tests catapult tracing...
r40523 script.append(
Augie Fackler
formatting: blacken the codebase...
r43346 b'echo START %s %s >> "$HGTESTCATAPULTSERVERPIPE"\n'
% (session, quoted)
)
Kyle Lippincott
catapult: rename 'active' to 'activetrace'; this isn't storing a boolean state...
r40524 activetrace[0:] = [quoted]
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')
Augie Fackler
tests: add support for emitting trace events to run-tests...
r39289
Matt Harbison
run-tests: replace '/dev/null' with os.devnull for Windows...
r39415 if hgcatapult and hgcatapult != os.devnull:
Rodrigo Damazio Bovendorp
py3: make catapult usable from the test runner in py3...
r42725 if PYTHON3:
hgcatapult = hgcatapult.encode('utf8')
cataname = self.name.encode('utf8')
else:
cataname = self.name
Augie Fackler
tests: add support for emitting trace events to run-tests...
r39289 # Kludge: use a while loop to keep the pipe from getting
# closed by our echo commands. The still-running file gets
# reaped at the end of the script, which causes the while
# loop to exit and closes the pipe. Sigh.
script.append(
b'rtendtracing() {\n'
Kyle Lippincott
catapult: introduce HGTESTCATAPULTSERVERPIPE to control run-tests' tracing...
r40525 b' echo END %(session)s %(name)s >> %(catapult)s\n'
Augie Fackler
tests: add support for emitting trace events to run-tests...
r39289 b' rm -f "$TESTTMP/.still-running"\n'
b'}\n'
b'trap "rtendtracing" 0\n'
b'touch "$TESTTMP/.still-running"\n'
b'while [ -f "$TESTTMP/.still-running" ]; do sleep 1; done '
Kyle Lippincott
catapult: introduce HGTESTCATAPULTSERVERPIPE to control run-tests' tracing...
r40525 b'> %(catapult)s &\n'
Augie Fackler
tests: add support for emitting trace events to run-tests...
r39289 b'HGCATAPULTSESSION=%(session)s ; export HGCATAPULTSESSION\n'
Kyle Lippincott
catapult: introduce HGTESTCATAPULTSERVERPIPE to control run-tests' tracing...
r40525 b'echo START %(session)s %(name)s >> %(catapult)s\n'
Augie Fackler
tests: add support for emitting trace events to run-tests...
r39289 % {
Rodrigo Damazio Bovendorp
py3: make catapult usable from the test runner in py3...
r42725 b'name': cataname,
b'session': session,
b'catapult': hgcatapult,
Augie Fackler
tests: add support for emitting trace events to run-tests...
r39289 }
)
Martin von Zweigbergk
tests: make #testcase available as env var in test...
r35554 if self._case:
Augie Fackler
tests: fix bytes/str issues in run-tests.py caught by python3...
r38969 casestr = b'#'.join(self._case)
Manuel Jacob
tests: fix isinstance test of wrong variable...
r44950 if isinstance(casestr, str):
Martin von Zweigbergk
testrunner: allow multiple #testcases...
r38860 quoted = shellquote(casestr)
Augie Fackler
tests: get run-tests to reliably hand shellquote a string and not a bytes...
r35841 else:
Martin von Zweigbergk
testrunner: allow multiple #testcases...
r38860 quoted = shellquote(casestr.decode('utf8')).encode('utf8')
Augie Fackler
tests: get run-tests to reliably hand shellquote a string and not a bytes...
r35841 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':
Gregory Szorc
run-tests: use byte strings for inserted output...
r43726 after.setdefault(pos, []).append(
b' !!! 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: use byte strings for inserted output...
r43726 after.setdefault(pos, []).append(b' !!! invalid #if\n')
Gregory Szorc
run-tests: move t test parsing into its own function...
r21312 if skipping is not None:
Gregory Szorc
run-tests: use byte strings for inserted output...
r43726 after.setdefault(pos, []).append(b' !!! 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:
Gregory Szorc
run-tests: use byte strings for inserted output...
r43726 after.setdefault(pos, []).append(b' !!! missing #if\n')
Gregory Szorc
run-tests: move t test parsing into its own function...
r21312 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:
Gregory Szorc
run-tests: use byte strings for inserted output...
r43726 after.setdefault(pos, []).append(b' !!! missing #if\n')
Gregory Szorc
run-tests: move t test parsing into its own function...
r21312 skipping = None
after.setdefault(pos, []).append(l)
elif skipping:
after.setdefault(pos, []).append(l)
Augie Fackler
formatting: blacken the codebase...
r43346 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
Augie Fackler
formatting: blacken the codebase...
r43346 addsalt(prepos, False) # Make sure we report the exit code.
Matt Harbison
run-tests: quote PYTHON when spawning a subprocess...
r39753 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
formatting: blacken the codebase...
r43346 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
formatting: blacken the codebase...
r43346 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)
Augie Fackler
tests: add support for emitting trace events to run-tests...
r39289 rawcmd = l[4:]
cmd = rawcmd.split()
toggletrace(rawcmd)
Augie Fackler
run-tests: make sure all script lines are bytes
r25060 if len(cmd) == 2 and cmd[0] == b'cd':
Matt Harbison
run-tests: ensure the script exits when it fails to change directories...
r44434 rawcmd = b'cd %s || exit 1\n' % cmd[1]
Augie Fackler
tests: add support for emitting trace events to run-tests...
r39289 script.append(rawcmd)
Augie Fackler
formatting: blacken the codebase...
r43346 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
formatting: blacken the codebase...
r43346 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:
Gregory Szorc
run-tests: use byte strings for inserted output...
r43726 after.setdefault(pos, []).append(b' !!! missing #endif\n')
Gregory Szorc
run-tests: move t test parsing into its own function...
r21312 addsalt(n + 1, False)
Kyle Lippincott
catapult: fix broken run-tests catapult tracing...
r40523 # Need to end any current per-command trace
Kyle Lippincott
catapult: rename 'active' to 'activetrace'; this isn't storing a boolean state...
r40524 if activetrace:
Kyle Lippincott
catapult: fix broken run-tests catapult tracing...
r40523 toggletrace()
Gregory Szorc
run-tests: move t test parsing into its own function...
r21312 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.
Augie Fackler
formatting: blacken the codebase...
r43346 warnonly = WARN_UNDEFINED # 1: not yet; 2: yes; 3: for sure not
Gregory Szorc
run-tests: finish moving tsttest() into TTest
r21314 if exitcode != 0:
run-tests: use symbolic constant instead of arbitrary number line matching...
r43134 warnonly = WARN_NO
Gregory Szorc
run-tests: finish moving tsttest() into TTest
r21314
pos = -1
postout = []
run-tests: clarify "l" variable as "out_rawline"...
r43135 for out_rawline in output:
run-tests: rename `lcmd` variable to `line_cmd`...
r43137 out_line, cmd_line = out_rawline, None
run-tests: clarify "l" variable as "out_rawline"...
r43135 if salt in out_rawline:
run-tests: rename `lcmd` variable to `line_cmd`...
r43137 out_line, cmd_line = out_rawline.split(salt, 1)
run-tests: rename `lout` variable to `out_line`...
r43136
Augie Fackler
formatting: blacken the codebase...
r43346 pos, postout, warnonly = self._process_out_line(
out_line, pos, postout, expected, warnonly
)
pos, postout = self._process_cmd_line(cmd_line, pos, postout, after)
Gregory Szorc
run-tests: finish moving tsttest() into TTest
r21314
if pos in after:
postout += after.pop(pos)
run-tests: extract a `process_out_line` from the main function...
r43169 if warnonly == WARN_YES:
Augie Fackler
formatting: blacken the codebase...
r43346 exitcode = False # Set exitcode to warned.
Gregory Szorc
run-tests: finish moving tsttest() into TTest
r21314
return exitcode, postout
Gregory Szorc
run-tests: move t test parsing into its own function...
r21312
run-tests: extract a `process_out_line` from the main function...
r43169 def _process_out_line(self, out_line, pos, postout, expected, warnonly):
run-tests: remove the artificial indentation
r43170 while out_line:
if not out_line.endswith(b'\n'):
out_line += b' (no-eol)\n'
# Find the expected output at the current position.
els = [None]
if expected.get(pos, None):
els = expected[pos]
optional = []
for i, el in enumerate(els):
r = False
if el:
r, exact = self.linematch(el, out_line)
if isinstance(r, str):
if r == '-glob':
out_line = ''.join(el.rsplit(' (glob)', 1))
Augie Fackler
formatting: blacken the codebase...
r43346 r = '' # Warn only this line.
run-tests: remove the artificial indentation
r43170 elif r == "retry":
postout.append(b' ' + el)
else:
log('\ninfo, unknown linematch result: %r\n' % r)
r = False
if r:
els.pop(i)
break
if el:
run-tests: add a dedicated 'isoptional' function...
r43171 if isoptional(el):
run-tests: remove the artificial indentation
r43170 optional.append(i)
else:
m = optline.match(el)
if m:
Augie Fackler
formatting: blacken the codebase...
r43346 conditions = [c for c in m.group(2).split(b' ')]
run-tests: remove the artificial indentation
r43170
if not self._iftest(conditions):
optional.append(i)
if exact:
# Don't allow line to be matches against a later
# line in the output
timeless
run-tests: teach _processoutput to handle multiple lines of churn...
r28569 els.pop(i)
break
run-tests: remove the artificial indentation
r43170
if r:
if r == "retry":
continue
# clean up any optional leftovers
for i in optional:
postout.append(b' ' + els[i])
for i in reversed(optional):
del els[i]
postout.append(b' ' + el)
else:
if self.NEEDESCAPE(out_line):
Augie Fackler
formatting: blacken the codebase...
r43346 out_line = TTest._stringescape(
b'%s (esc)\n' % out_line.rstrip(b'\n')
)
postout.append(b' ' + out_line) # Let diff deal with it.
if r != '': # If line failed.
run-tests: remove the artificial indentation
r43170 warnonly = WARN_NO
elif warnonly == WARN_UNDEFINED:
warnonly = WARN_YES
break
else:
# clean up any optional leftovers
while expected.get(pos, None):
el = expected[pos].pop(0)
if el:
run-tests: add a dedicated 'isoptional' function...
r43171 if not isoptional(el):
run-tests: remove the artificial indentation
r43170 m = optline.match(el)
if m:
conditions = [c for c in m.group(2).split(b' ')]
if self._iftest(conditions):
# Don't append as optional line
continue
Matt Harbison
run-tests: support per-line conditional output in tests...
r31829 else:
run-tests: remove the artificial indentation
r43170 continue
postout.append(b' ' + el)
run-tests: extract a `process_out_line` from the main function...
r43169 return pos, postout, warnonly
Gregory Szorc
run-tests: move t test parsing into its own function...
r21312
run-tests: extract a `process_cmd_line` from the main function...
r43168 def _process_cmd_line(self, cmd_line, pos, postout, after):
"""process a "command" part of a line from unified test output"""
if cmd_line:
# Add on last return code.
ret = int(cmd_line.split()[1])
if ret != 0:
postout.append(b' [%d]\n' % ret)
if pos in after:
# Merge in non-active test bits.
postout += after.pop(pos)
pos = int(cmd_line.split()[0])
return pos, postout
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:
Kyle Lippincott
tests: fix deprecation warning about regex flags not at beginning of expr...
r44240 # parse any flags at the beginning of the regex. Only 'i' is
# supported right now, but this should be easy to extend.
flags, el = re.match(br'^(\(\?i\))?(.*)', el).groups()[0:2]
flags = flags or b''
el = flags + 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
formatting: blacken the codebase...
r43346 c = el[i : i + 1]
Gregory Szorc
run-tests: make globmatch a static method of TTest
r21317 i += 1
Augie Fackler
formatting: blacken the codebase...
r43346 if c == b'\\' and i < n and el[i : i + 1] in b'*?\\/':
res += el[i - 1 : 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 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):
Augie Fackler
formatting: blacken the codebase...
r43346 if el == l: # perfect match (fast)
Martin von Zweigbergk
tests: don't allow reodering of glob/re lines across non-glob/re lines...
r38572 return True, True
Martin von Zweigbergk
tests: move handling of None "el" out of linematch()...
r38570 retry = False
run-tests: add a dedicated 'isoptional' function...
r43171 if isoptional(el):
Martin von Zweigbergk
tests: move handling of None "el" out of linematch()...
r38570 retry = "retry"
Augie Fackler
formatting: blacken the codebase...
r43346 el = el[: -len(MARK_OPTIONAL)] + b"\n"
Martin von Zweigbergk
tests: move handling of None "el" out of linematch()...
r38570 else:
m = optline.match(el)
if m:
conditions = [c for c in m.group(2).split(b' ')]
el = m.group(1) + b"\n"
if not self._iftest(conditions):
run-tests: stop matching line for missing feature...
r42705 # listed feature missing, should not match
return "retry", False
Martin von Zweigbergk
tests: move handling of None "el" out of linematch()...
r38570
if el.endswith(b" (esc)\n"):
if PYTHON3:
el = el[:-7].decode('unicode_escape') + '\n'
Manuel Jacob
run-tests: fix escapes with conditions...
r45552 el = el.encode('latin-1')
Matt Harbison
run-tests: support per-line conditional output in tests...
r31829 else:
Martin von Zweigbergk
tests: move handling of None "el" out of linematch()...
r38570 el = el[:-7].decode('string-escape') + '\n'
if el == l or os.name == 'nt' and el[:-1] + b'\r\n' == l:
Martin von Zweigbergk
tests: don't allow reodering of glob/re lines across non-glob/re lines...
r38572 return True, True
Martin von Zweigbergk
tests: move handling of None "el" out of linematch()...
r38570 if el.endswith(b" (re)\n"):
Martin von Zweigbergk
tests: don't allow reodering of glob/re lines across non-glob/re lines...
r38572 return (TTest.rematch(el[:-6], l) or retry), False
Martin von Zweigbergk
tests: move handling of None "el" out of linematch()...
r38570 if el.endswith(b" (glob)\n"):
# ignore '(glob)' added to l by 'replacements'
if l.endswith(b" (glob)\n"):
l = l[:-8] + b"\n"
Martin von Zweigbergk
tests: don't allow reodering of glob/re lines across non-glob/re lines...
r38572 return (TTest.globmatch(el[:-8], l) or retry), False
Martin von Zweigbergk
tests: move handling of None "el" out of linematch()...
r38570 if os.altsep:
_l = l.replace(b'\\', b'/')
if el == _l or os.name == 'nt' and el[:-1] + b'\r\n' == _l:
Martin von Zweigbergk
tests: don't allow reodering of glob/re lines across non-glob/re lines...
r38572 return True, True
return retry, True
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):
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """Parse hghave log lines.
Gregory Szorc
run-tests: move parsehghaveoutput() into TTest...
r21379
Return tuple of lists (missing, failed):
* the missing/unknown features
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 * the features for which existence check failed"""
Gregory Szorc
run-tests: move parsehghaveoutput() into TTest...
r21379 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]
Manuel Jacob
tests: use native string type for parsed hghave log lines...
r44959 missing.append(_bytes2sys(line[len(TTest.SKIPPED_PREFIX) :]))
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]
Manuel Jacob
tests: use native string type for parsed hghave log lines...
r44959 failed.append(_bytes2sys(line[len(TTest.FAILED_PREFIX) :]))
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)
Augie Fackler
formatting: blacken the codebase...
r43346
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
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
run-tests: define custom result and runner classes for unittest...
r21429 class TestResult(unittest._TextTestResult):
"""Holds results when executing via unittest."""
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
run-tests: define custom result and runner classes for unittest...
r21429 # 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
Augie Fackler
formatting: blacken the codebase...
r43346 else: # 'always', for testing purposes
Martin von Zweigbergk
run-tests: pass color option via test case object , not global var...
r33565 self.color = pygmentspresent
Matthieu Laneuville
run-tests: check if stream is a tty before using color...
r33561
Boris Feld
run-tests: extract onStart and onEnd into the test result...
r38636 def onStart(self, test):
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """Can be overriden by custom TestResult"""
Boris Feld
run-tests: extract onStart and onEnd into the test result...
r38636
def onEnd(self):
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """Can be overriden by custom TestResult"""
Boris Feld
run-tests: extract onStart and onEnd into the test result...
r38636
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
formatting: blacken the codebase...
r43346 subprocess.call(
r'"%s" "%s" "%s"'
Manuel Jacob
tests: rename _bytespath() to _sys2bytes() and _strpath() to _sys2str()...
r44935 % (v, _bytes2sys(test.refpath), _bytes2sys(test.errpath)),
Augie Fackler
formatting: blacken the codebase...
r43346 shell=True,
)
Gregory Szorc
run-tests: move diff generation into TestResult...
r21521 else:
Augie Fackler
formatting: blacken the codebase...
r43346 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(
Augie Fackler
formatting: blacken the codebase...
r43346 'server failed to start (HGPORT=%s)' % test._startport
)
Matt Harbison
run-tests: resume raising an exception when a server fails to start...
r36479
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 '
Augie Fackler
formatting: blacken the codebase...
r43346 'changes)'
)
Jun Wu
run-tests: do not prompt changes (-i) if a race condition is detected...
r32980 else:
Sushil khanchi
tests: make it clear what happen when no response entered...
r45470 self.stream.write('Accept this change? [y/N] ')
Matt Harbison
run-tests: flush output stream before prompting to accept changes...
r39945 self.stream.flush()
Jun Wu
run-tests: do not prompt changes (-i) if a race condition is detected...
r32980 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
Gregory Szorc
tests: use time.time() for relative start and stop times...
r43991 # and not for Windows. Hence why we fall back to another function
# for wall time calculations.
Gregory Szorc
tests: rename stopped and started variables to reflect times...
r43990 test.started_times = os.times()
Gregory Szorc
tests: use time.time() for relative start and stop times...
r43991 # TODO use a monotonic clock once support for Python 2.7 is dropped.
test.started_time = time.time()
Augie Fackler
formatting: blacken the codebase...
r43346 if self._firststarttime is None: # thread racy but irrelevant
Gregory Szorc
tests: use time.time() for relative start and stop times...
r43991 self._firststarttime = test.started_time
Gregory Szorc
run-tests: capture execution times in TestResult...
r21495
def stopTest(self, test, interrupted=False):
super(TestResult, self).stopTest(test)
Gregory Szorc
tests: rename stopped and started variables to reflect times...
r43990 test.stopped_times = os.times()
Gregory Szorc
tests: use time.time() for relative start and stop times...
r43991 stopped_time = time.time()
Gregory Szorc
tests: rename stopped and started variables to reflect times...
r43990
starttime = test.started_times
endtime = test.stopped_times
Pierre-Yves David
run-tests: track start and end time of tests...
r25097 origin = self._firststarttime
Augie Fackler
formatting: blacken the codebase...
r43346 self.times.append(
(
test.name,
endtime[2] - starttime[2], # user space CPU time
endtime[3] - starttime[3], # sys space CPU time
Gregory Szorc
tests: use time.time() for relative start and stop times...
r43991 stopped_time - test.started_time, # real time
test.started_time - origin, # start date in run context
stopped_time - origin, # end date in run context
Augie Fackler
formatting: blacken the codebase...
r43346 )
)
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:
Augie Fackler
formatting: blacken the codebase...
r43346 self.stream.writeln(
'INTERRUPTED: %s (after %d seconds)'
% (test.name, self.times[-1][3])
)
Gregory Szorc
run-tests: capture execution times in TestResult...
r21495
Boris Feld
run-tests: add support for external test result...
r38635 def getTestResult():
"""
Returns the relevant test result
"""
if "CUSTOM_TEST_RESULT" in os.environ:
testresultmodule = __import__(os.environ["CUSTOM_TEST_RESULT"])
return testresultmodule.TestResult
else:
return TestResult
Augie Fackler
formatting: blacken the codebase...
r43346
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
Augie Fackler
formatting: blacken the codebase...
r43346 def __init__(
self,
testdir,
jobs=1,
whitelist=None,
blacklist=None,
keywords=None,
loop=False,
runs_per_test=1,
loadtest=None,
showchannels=False,
*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
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 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
formatting: blacken the codebase...
r43346
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
Augie Fackler
formatting: blacken the codebase...
r43346
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
Antoine cezar
run-test: allow relative path in `--blacklist` and `--whitelist` (issue6351)...
r46086 is_whitelisted = self._whitelist and (
test.relpath in self._whitelist or test.bname in self._whitelist
)
if not is_whitelisted:
is_blacklisted = self._blacklist and (
test.relpath in self._blacklist
or test.bname in self._blacklist
)
if is_blacklisted:
Gregory Szorc
run-tests: move test filtering into TestSuite.run()...
r21507 result.addSkip(test, 'blacklisted')
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
Augie Fackler
formatting: blacken the codebase...
r43346 except: # re-raises
Gregory Szorc
run-tests: move _executetests into TestSuite
r21496 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:
Augie Fackler
formatting: blacken the codebase...
r43346 time.sleep(0.1)
Matt Mackall
run-tests: show scheduling with --showchannels...
r27396 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
Augie Fackler
formatting: blacken the codebase...
r43346 tests.append(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:
Augie Fackler
formatting: blacken the codebase...
r43346 t = threading.Thread(
target=job, name=test.name, args=(test, result)
)
timeless
run-tests: skip threading for a single test...
r27689 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
Augie Fackler
formatting: blacken the codebase...
r43346
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.
Augie Fackler
formatting: blacken the codebase...
r43346
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)
Augie Fackler
formatting: blacken the codebase...
r43346 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
Augie Fackler
formatting: blacken the codebase...
r43346
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
Augie Fackler
cleanup: run pyupgrade on our source tree to clean up varying things...
r44937 skipped = {str(t[0]) for t in result.skipped}
Bryan O'Sullivan
tests: write recent run times to a file named tests/.testtimes...
r27634 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:]
Augie Fackler
formatting: blacken the codebase...
r43346 fd, tmpname = tempfile.mkstemp(
prefix=b'.testtimes', 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
Augie Fackler
formatting: blacken the codebase...
r43346
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
Boris Feld
run-tests: fix test result verbosity...
r38639
Augie Fackler
formatting: blacken the codebase...
r43346 self._result = getTestResult()(
self._runner.options, self.stream, self.descriptions, self.verbosity
)
Gregory Szorc
run-tests: print compatible output from TextTestRunner...
r21459
Siddharth Agarwal
run-tests: add a way to list tests, with JSON and XUnit support...
r32704 def listtests(self, test):
test = sorted(test, key=lambda t: t.name)
Boris Feld
run-tests: extract onStart and onEnd into the test result...
r38636
self._result.onStart(test)
Siddharth Agarwal
run-tests: add a way to list tests, with JSON and XUnit support...
r32704 for t in test:
print(t.name)
Boris Feld
run-tests: extract onStart and onEnd into the test result...
r38636 self._result.addSuccess(t)
Siddharth Agarwal
run-tests: add a way to list tests, with JSON and XUnit support...
r32704
if self._runner.options.xunit:
with open(self._runner.options.xunit, "wb") as xuf:
Boris Feld
run-tests: extract onStart and onEnd into the test result...
r38636 self._writexunit(self._result, xuf)
Siddharth Agarwal
run-tests: add a way to list tests, with JSON and XUnit support...
r32704
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:
Boris Feld
run-tests: extract onStart and onEnd into the test result...
r38636 self._writejson(self._result, fp)
return self._result
Siddharth Agarwal
run-tests: add a way to list tests, with JSON and XUnit support...
r32704
Gregory Szorc
run-tests: print compatible output from TextTestRunner...
r21459 def run(self, test):
Boris Feld
run-tests: extract onStart and onEnd into the test result...
r38636 self._result.onStart(test)
test(self._result)
failed = len(self._result.failures)
skipped = len(self._result.skipped)
ignored = len(self._result.ignored)
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 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:
Augie Fackler
formatting: blacken the codebase...
r43346 for test, msg in sorted(
self._result.skipped, key=lambda s: s[0].name
):
Yuya Nishihara
run-tests: include "\n" in formatted message instead of calling writeln()...
r33930 formatted = 'Skipped %s: %s\n' % (test.name, msg)
Boris Feld
run-tests: fix a too long line...
r38641 msg = highlightmsg(formatted, self._result.color)
self.stream.write(msg)
Augie Fackler
formatting: blacken the codebase...
r43346 for test, msg in sorted(
self._result.failures, key=lambda f: f[0].name
):
Yuya Nishihara
run-tests: include "\n" in formatted message instead of calling writeln()...
r33930 formatted = 'Failed %s: %s\n' % (test.name, msg)
Boris Feld
run-tests: extract onStart and onEnd into the test result...
r38636 self.stream.write(highlightmsg(formatted, self._result.color))
Augie Fackler
formatting: blacken the codebase...
r43346 for test, msg in sorted(
self._result.errors, key=lambda e: e[0].name
):
Augie Fackler
run-tests: switch all uses of iolock.acquire() to a context manager
r25046 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:
Boris Feld
run-tests: extract onStart and onEnd into the test result...
r38636 self._writexunit(self._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:
Boris Feld
run-tests: extract onStart and onEnd into the test result...
r38636 self._writejson(self._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
Boris Feld
run-tests: extract onStart and onEnd into the test result...
r38636 savetimes(self._runner._outputdir, self._result)
Augie Fackler
run-tests: add support for automatically bisecting test failures
r28596
if failed and self._runner.options.known_good_rev:
Boris Feld
run-tests: extract onStart and onEnd into the test result...
r38636 self._bisecttests(t for t, m in self._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.'
Augie Fackler
formatting: blacken the codebase...
r43346 % (self._result.testsRun, skipped + ignored, failed)
)
Augie Fackler
run-tests: switch all uses of iolock.acquire() to a context manager
r25046 if failed:
Augie Fackler
formatting: blacken the codebase...
r43346 self.stream.writeln(
'python hash seed: %s' % os.environ['PYTHONHASHSEED']
)
Augie Fackler
run-tests: switch all uses of iolock.acquire() to a context manager
r25046 if self._runner.options.time:
Boris Feld
run-tests: extract onStart and onEnd into the test result...
r38636 self.printtimes(self._result.times)
Gregory Szorc
run-tests: mechanism to report exceptions during test execution...
r35191
if self._runner.options.exceptions:
exceptions = aggregateexceptions(
Augie Fackler
formatting: blacken the codebase...
r43346 os.path.join(self._runner._outputdir, b'exceptions')
)
Gregory Szorc
run-tests: mechanism to report exceptions during test execution...
r35191
self.stream.writeln('Exceptions Report:')
Augie Fackler
formatting: blacken the codebase...
r43346 self.stream.writeln(
'%d total from %d frames'
% (exceptions['total'], len(exceptions['exceptioncounts']))
)
Gregory Szorc
run-tests: report tests that exception occurred in...
r36054 combined = exceptions['combined']
for key in sorted(combined, key=combined.get, reverse=True):
frame, line, exc = key
totalcount, testcount, leastcount, leasttest = combined[key]
Augie Fackler
formatting: blacken the codebase...
r43346 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
Boris Feld
run-tests: extract onStart and onEnd into the test result...
r38636 return self._result
Gregory Szorc
run-tests: exit with non-0 exit code when tests fail or warn...
r21613
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)])
Augie Fackler
formatting: blacken the codebase...
r43346
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'
Augie Fackler
formatting: blacken the codebase...
r43346 p = subprocess.Popen(
args, stderr=subprocess.STDOUT, 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
Augie Fackler
formatting: blacken the codebase...
r43346
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:
Manuel Jacob
tests: rename _bytespath() to _sys2bytes() and _strpath() to _sys2str()...
r44935 opts += ' --with-hg=%s ' % shellquote(_bytes2sys(withhg))
Augie Fackler
formatting: blacken the codebase...
r43346 rtc = '%s %s %s %s' % (sysexecutable, 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(
Augie Fackler
formatting: blacken the codebase...
r43346 (
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),
)
Jun Wu
run-tests: move bisect logic to a separate method...
r34803 if m is None:
self.stream.writeln(
Augie Fackler
formatting: blacken the codebase...
r43346 'Failed to identify failure point for %s' % test
)
Jun Wu
run-tests: move bisect logic to a separate method...
r34803 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(
Augie Fackler
formatting: blacken the codebase...
r43346 '%s %s by %s (%s)'
% (
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'
Augie Fackler
formatting: blacken the codebase...
r43346 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.
Augie Fackler
cleanup: run pyupgrade on our source tree to clean up varying things...
r44937 timesd = {t[0]: t[3] for t in result.times}
Siddharth Agarwal
run-tests: factor out xunit write code into another method...
r32700 doc = minidom.Document()
s = doc.createElement('testsuite')
Augie Fackler
formatting: blacken the codebase...
r43346 s.setAttribute('errors', "0") # TODO
Siddharth Agarwal
run-tests: factor out xunit write code into another method...
r32700 s.setAttribute('failures', str(len(result.failures)))
Gregory Szorc
run-tests: set attributes in sorted order...
r41687 s.setAttribute('name', 'run-tests')
Augie Fackler
formatting: blacken the codebase...
r43346 s.setAttribute(
'skipped', str(len(result.skipped) + len(result.ignored))
)
Gregory Szorc
run-tests: set attributes in sorted order...
r41687 s.setAttribute('tests', str(result.testsRun))
Siddharth Agarwal
run-tests: factor out xunit write code into another method...
r32700 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 = {}
Augie Fackler
formatting: blacken the codebase...
r43346 groups = [
('success', ((tc, None) for tc in result.successes)),
('failure', result.failures),
('skip', result.skipped),
]
Siddharth Agarwal
run-tests: factor out json write code into another method...
r32701 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
Augie Fackler
formatting: blacken the codebase...
r43346 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]),
'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
Augie Fackler
formatting: blacken the codebase...
r43346 jsonout = json.dumps(
outcome, sort_keys=True, indent=4, separators=(',', ': ')
)
Siddharth Agarwal
run-tests: factor out json write code into another method...
r32701 outf.writelines(("testreport =", jsonout))
Augie Fackler
formatting: blacken the codebase...
r43346
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:
Augie Fackler
formatting: blacken the codebase...
r43346
Martin von Zweigbergk
testrunner: add option to sort tests by previous run time...
r36683 def sortkey(f):
f = f['path']
if f in previoustimes:
# Use most recent time as estimate
Augie Fackler
formatting: blacken the codebase...
r43346 return -(previoustimes[f][-1])
Martin von Zweigbergk
testrunner: add option to sort tests by previous run time...
r36683 else:
# Default to a rather arbitrary value of 1 second for new tests
return -1.0
Augie Fackler
formatting: blacken the codebase...
r43346
Martin von Zweigbergk
testrunner: add option to sort tests by previous run time...
r36683 else:
# keywords for slow tests
Augie Fackler
formatting: blacken the codebase...
r43346 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,
b'merge-combination': 100,
}
Martin von Zweigbergk
testrunner: add option to sort tests by previous run time...
r36683 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)
Augie Fackler
formatting: blacken the codebase...
r43346
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
Matt Harbison
run-tests: fix a typo in an attribute name...
r46683 self._tmpbindir = None
Gregory Szorc
run-tests: make attributes of TestRunner internal...
r21534 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)
Manuel Jacob
tests: rename _bytespath() to _sys2bytes() and _strpath() to _sys2str()...
r44935 tests = [_sys2bytes(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
Augie Fackler
formatting: blacken the codebase...
r43346
Augie Fackler
run-tests: add a --profile-runner option...
r25107 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):
Sangeet Kumar Mishra
test: fix self._testdir to use the right mercurial library during testing...
r40522 testdir = getcwdb()
Matt Harbison
run-tests: avoid os.getcwdb() on Windows...
r39754 self._testdir = osenvironb[b'TESTDIR'] = getcwdb()
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:
Sangeet Kumar Mishra
test: fix self._testdir to use the right mercurial library during testing...
r40522 testdir = os.path.join(testdir, pathname)
self._testdir = osenvironb[b'TESTDIR'] = testdir
Siddharth Agarwal
run-tests: allow specifying an output dir to write .errs to...
r32716 if self.options.outputdir:
Manuel Jacob
tests: rename _bytespath() to _sys2bytes() and _strpath() to _sys2str()...
r44935 self._outputdir = canonpath(_sys2bytes(self.options.outputdir))
Siddharth Agarwal
run-tests: allow specifying an output dir to write .errs to...
r32716 else:
Sangeet Kumar Mishra
test: fix self._testdir to use the right mercurial library during testing...
r40522 self._outputdir = getcwdb()
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))
Raphaël Gomès
run-tests: restrict Rust thread pool to 3 threads during tests...
r45005 # Rayon (Rust crate for multi-threading) will use all logical CPU cores
# by default, causing thrashing on high-cpu-count systems.
# Setting its limit to 3 during tests should still let us uncover
# multi-threading bugs while keeping the thrashing reasonable.
os.environ.setdefault("RAYON_NUM_THREADS", "3")
Gregory Szorc
run-tests: move tmpdir calculations into TestRunner
r21369 if self.options.tmpdir:
self.options.keep_tmpdir = True
Manuel Jacob
tests: rename _bytespath() to _sys2bytes() and _strpath() to _sys2str()...
r44935 tmpdir = _sys2bytes(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
Augie Fackler
formatting: blacken the codebase...
r43346 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))
Manuel Jacob
tests: rename _bytespath() to _sys2bytes() and _strpath() to _sys2str()...
r44935 normbin = normbin.replace(_sys2bytes(os.sep), b'/')
Gregory Szorc
rust: implementation of `hg`...
r35587
# 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
Matt Harbison
py3: enable legacy stdio mode in exewrapper...
r41012 # Force the use of hg.exe instead of relying on MSYS to recognize hg is
# a python script and feed it to python.exe. Legacy stdio is force
# enabled by hg.exe, and this is a more realistic way to launch hg
# anyway.
Matt Harbison
run-tests: alias hg to hg.exe on Windows...
r41011 if os.name == 'nt' and not self._hgcommand.endswith(b'.exe'):
self._hgcommand += b'.exe'
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
Manuel Jacob
tests: rename _bytespath() to _sys2bytes() and _strpath() to _sys2str()...
r44935 fileb = _sys2bytes(__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:
Manuel Jacob
tests: rename _bytespath() to _sys2bytes() and _strpath() to _sys2str()...
r44935 sepb = _sys2bytes(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"
Raphaël Gomès
run-tests: add option for running with and without Rust extensions...
r44973 if self.options.rust:
os.environ["HGMODULEPOLICY"] = "rust+c"
if self.options.no_rust:
current_policy = os.environ.get("HGMODULEPOLICY", "")
if current_policy.startswith("rust+"):
os.environ["HGMODULEPOLICY"] = current_policy[len("rust+") :]
os.environ.pop("HGWITHRUSTEXT", None)
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(
Augie Fackler
formatting: blacken the codebase...
r43346 'extensions.logexceptions=%s' % logexceptions.decode('utf-8')
)
Gregory Szorc
run-tests: mechanism to report exceptions during test execution...
r35191
Manuel Jacob
tests: rename _bytespath() to _sys2bytes() and _strpath() to _sys2str()...
r44935 vlog("# Using TESTDIR", _bytes2sys(self._testdir))
vlog("# Using RUNTESTDIR", _bytes2sys(osenvironb[b'RUNTESTDIR']))
vlog("# Using HGTMP", _bytes2sys(self._hgtmp))
Gregory Szorc
run-tests: establish TestRunner.run()...
r21366 vlog("# Using PATH", os.environ["PATH"])
Denis Laxalde
py3: decode bytes before logging in run-tests.py...
r43614 vlog(
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 "# Using",
_bytes2sys(IMPL_PATH),
_bytes2sys(osenvironb[IMPL_PATH]),
Denis Laxalde
py3: decode bytes before logging in run-tests.py...
r43614 )
Manuel Jacob
tests: rename _bytespath() to _sys2bytes() and _strpath() to _sys2str()...
r44935 vlog("# Writing to directory", _bytes2sys(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:
Augie Fackler
formatting: blacken the codebase...
r43346 time.sleep(0.1)
Gregory Szorc
run-tests: establish TestRunner.run()...
r21366 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:
Augie Fackler
formatting: blacken the codebase...
r43346 proc = Popen4(
b'hg st --rev "%s" -man0 .'
Manuel Jacob
tests: rename _bytespath() to _sys2bytes() and _strpath() to _sys2str()...
r44935 % _sys2bytes(self.options.changed),
Augie Fackler
formatting: blacken the codebase...
r43346 None,
0,
)
Gregory Szorc
run-tests: move test discovery logic into a function...
r21363 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
Matt Harbison
cleanup: drop redundant character escapes from `[]` character sets...
r44473 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:
Martin von Zweigbergk
testrunner: allow multiple #testcases...
r38860 case = []
Boris Feld
run-tests: add support for running specific test cases...
r38224
Augie Fackler
formatting: blacken the codebase...
r43346 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
Kyle Lippincott
tests: support passing testcase after .t paths that have path separators...
r41174 m = testcasepattern.match(os.path.basename(t))
Boris Feld
run-tests: add support for running specific test cases...
r38224 if m is not None:
Martin von Zweigbergk
testrunner: avoid capturing a regex group we don't care about...
r41177 t_basename, casestr = m.groups()
Kyle Lippincott
tests: support passing testcase after .t paths that have path separators...
r41174 t = os.path.join(os.path.dirname(t), t_basename)
Martin von Zweigbergk
testrunner: allow multiple #testcases...
r38860 if casestr:
Augie Fackler
tests: fix bytes/str issues in run-tests.py caught by python3...
r38969 case = casestr.split(b'#')
Boris Feld
run-tests: add support for running specific test cases...
r38224 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
Martin von Zweigbergk
testrunner: allow multiple #testcases...
r38860 casedimensions = parsettestcases(t)
if casedimensions:
cases = []
Augie Fackler
formatting: blacken the codebase...
r43346
Martin von Zweigbergk
testrunner: allow multiple #testcases...
r38860 def addcases(case, casedimensions):
if not casedimensions:
cases.append(case)
else:
for c in casedimensions[0]:
addcases(case + [c], casedimensions[1:])
Augie Fackler
formatting: blacken the codebase...
r43346
Martin von Zweigbergk
testrunner: allow multiple #testcases...
r38860 addcases([], casedimensions)
if case and case in cases:
cases = [case]
elif case:
Boris Feld
run-tests: add support for running specific test cases...
r38224 # Ignore invalid cases
Martin von Zweigbergk
testrunner: allow multiple #testcases...
r38860 cases = []
Boris Feld
run-tests: add support for running specific test cases...
r38224 else:
Martin von Zweigbergk
testrunner: allow multiple #testcases...
r38860 pass
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})
Sushil khanchi
run-tests: refactor filtering logic for --retest flag...
r45967
if self.options.retest:
retest_args = []
for test in tests:
Sushil khanchi
run-tests: extract logic to get errpath in a utility func...
r45968 errpath = self._geterrpath(test)
Sushil khanchi
run-tests: refactor filtering logic for --retest flag...
r45967 if os.path.exists(errpath):
retest_args.append(test)
tests = retest_args
Jun Wu
run-tests: support multiple cases in .t test...
r32317 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}
Martin von Zweigbergk
testrunner: allow multiple #testcases...
r38860 case = getattr(test, '_case', [])
Jun Wu
run-tests: support multiple cases in .t test...
r32317 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]
Sushil khanchi
run-tests: extract logic to get errpath in a utility func...
r45968 errpath = self._geterrpath(desc)
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)]
Martin von Zweigbergk
testrunner: make `-j100 --runs-per-test=100 test-foo.t` use 100 jobs...
r41214 num_tests = len(tests) * self.options.runs_per_test
jobs = min(num_tests, self.options.jobs)
Gregory Szorc
run-tests: print number of tests and parallel process count...
r40280
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
Augie Fackler
formatting: blacken the codebase...
r43346 suite = TestSuite(
self._testdir,
jobs=jobs,
whitelist=self.options.whitelisted,
blacklist=self.options.blacklist,
keywords=kws,
loop=self.options.loop,
runs_per_test=self.options.runs_per_test,
showchannels=self.options.showchannels,
tests=tests,
loadtest=_reloadtest,
)
Gregory Szorc
run-tests: execute tests via unittest...
r21464 verbosity = 1
Boris Feld
run-tests: fix test result verbosity...
r38639 if self.options.list_tests:
verbosity = 0
elif self.options.verbose:
Gregory Szorc
run-tests: execute tests via unittest...
r21464 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
Augie Fackler
formatting: blacken the codebase...
r43346 log(
'running %d tests using %d parallel processes'
% (num_tests, jobs)
)
Gregory Szorc
run-tests: print number of tests and parallel process count...
r40280
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
Kyle Lippincott
tests: make run-tests exit non-zero if there are "errors"...
r42578 if result.failures or result.errors:
Gregory Szorc
run-tests: exit with non-0 exit code when tests fail or warn...
r21613 failed = True
Gregory Szorc
run-tests: move runtests() into TestRunner
r21360
Boris Feld
run-tests: extract onStart and onEnd into the test result...
r38636 result.onEnd()
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
Sushil khanchi
run-tests: extract logic to get errpath in a utility func...
r45968 def _geterrpath(self, test):
# test['path'] is a relative path
if 'case' in test:
# for multiple dimensions test cases
casestr = b'#'.join(test['case'])
errpath = b'%s#%s.err' % (test['path'], casestr)
else:
errpath = b'%s.err' % test['path']
if self.options.outputdir:
Sushil khanchi
py3: fix bytes and str mixup in run-tests...
r46013 self._outputdir = canonpath(_sys2bytes(self.options.outputdir))
errpath = os.path.join(self._outputdir, errpath)
Sushil khanchi
run-tests: extract logic to get errpath in a utility func...
r45968 return errpath
Pierre-Yves David
run-test: ensure the test ports are available before launching test...
r24967 def _getport(self, count):
Augie Fackler
formatting: blacken the codebase...
r43346 port = self._ports.get(count) # do we have a cached entry?
Pierre-Yves David
run-test: ensure the test ports are available before launching test...
r24967 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
Sangeet Kumar Mishra
test: fix self._testdir to use the right mercurial library during testing...
r40522 refpath = os.path.join(getcwdb(), 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
Augie Fackler
cleanup: run pyupgrade on our source tree to clean up varying things...
r44937 kwds = {k: testdesc[k] for k in ['case'] if k in testdesc}
Jun Wu
run-tests: support multiple cases in .t test...
r32317
Augie Fackler
formatting: blacken the codebase...
r43346 t = testcls(
refpath,
self._outputdir,
tmpdir,
keeptmpdir=self.options.keep_tmpdir,
debug=self.options.debug,
first=self.options.first,
timeout=self.options.timeout,
startport=self._getport(count),
extraconfigopts=self.options.extra_config_opt,
shell=self.options.shell,
hgcommand=self._hgcommand,
usechg=bool(self.options.with_chg or self.options.chg),
Pulkit Goyal
run-tests: add --chg-debug flag to show chg debug output...
r45105 chgdebug=self.options.chg_debug,
Augie Fackler
formatting: blacken the codebase...
r43346 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
Manuel Jacob
tests: rename _bytespath() to _sys2bytes() and _strpath() to _sys2str()...
r44935 vlog("# Cleaning up HGTMP", _bytes2sys(self._hgtmp))
Gregory Szorc
run-tests: make attributes of TestRunner internal...
r21534 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.
Gregory Szorc
global: use python3 in shebangs...
r46434 pyexename = sys.platform == 'win32' and b'python.exe' or b'python3'
Matt Harbison
py3: allow run-tests.py to run on Windows...
r39683
# os.symlink() is a thing with py3 on Windows, but it requires
# Administrator rights.
if getattr(os, 'symlink', None) and os.name != 'nt':
Augie Fackler
formatting: blacken the codebase...
r43346 vlog(
"# Making python executable in test path a symlink to '%s'"
% sysexecutable
)
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:
Rodrigo Damazio Bovendorp
pycompat: make fewer assumptions about sys.executable...
r42723 if os.readlink(mypython) == sysexecutable:
Gregory Szorc
run-tests: move usecorrectpython() into TestRunner
r21351 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
Rodrigo Damazio Bovendorp
pycompat: make fewer assumptions about sys.executable...
r42723 if self._findprogram(pyexename) != sysexecutable:
Gregory Szorc
run-tests: move usecorrectpython() into TestRunner
r21351 try:
Rodrigo Damazio Bovendorp
pycompat: make fewer assumptions about sys.executable...
r42723 os.symlink(sysexecutable, 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:
Matt Harbison
run-tests: stuff a `python3.exe` into the test bin directory on Windows...
r46684 # Windows doesn't have `python3.exe`, and MSYS cannot understand the
Matt Harbison
run-tests: work around the Windows firewall popup for server processes...
r47044 # reparse point with that name provided by Microsoft. Create a
# simple script on PATH with that name that delegates to the py3
# launcher so the shebang lines work.
Matt Harbison
run-tests: stuff a `python3.exe` into the test bin directory on Windows...
r46684 if os.getenv('MSYSTEM'):
Matt Harbison
run-tests: work around the Windows firewall popup for server processes...
r47044 with open(osenvironb[b'RUNTESTDIR'] + b'/python3', 'wb') as f:
f.write(b'#!/bin/sh\n')
f.write(b'py -3 "$@"\n')
Matt Harbison
run-tests: stuff a `python3.exe` into the test bin directory on Windows...
r46684
Rodrigo Damazio Bovendorp
pycompat: make fewer assumptions about sys.executable...
r42723 exedir, exename = os.path.split(sysexecutable)
Augie Fackler
formatting: blacken the codebase...
r43346 vlog(
"# Modifying search path to find %s as %s in '%s'"
% (exename, pyexename, exedir)
)
Gregory Szorc
run-tests: move usecorrectpython() into TestRunner
r21351 path = os.environ['PATH'].split(os.pathsep)
while exedir in path:
path.remove(exedir)
Matt Harbison
run-tests: extend PATH on Windows to include user installed scripts...
r46685
# Binaries installed by pip into the user area like pylint.exe may
# not be in PATH by default.
extra_paths = [exedir]
vi = sys.version_info
if 'APPDATA' in os.environ:
scripts_dir = os.path.join(
os.environ['APPDATA'],
'Python',
'Python%d%d' % (vi[0], vi[1]),
'Scripts',
)
if vi.major == 2:
scripts_dir = os.path.join(
os.environ['APPDATA'],
'Python',
'Scripts',
)
extra_paths.append(scripts_dir)
os.environ['PATH'] = os.pathsep.join(extra_paths + 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
run-tests: rename "pure" variable to setup_opts...
r44972 setup_opts = b""
Jordi Gutiérrez Hermoso
style: kill ersatz if-else ternary operators...
r24306 if self.options.pure:
run-tests: rename "pure" variable to setup_opts...
r44972 setup_opts = b"--pure"
Raphaël Gomès
run-tests: add option for running with and without Rust extensions...
r44973 elif self.options.rust:
setup_opts = b"--rust"
elif self.options.no_rust:
setup_opts = b"--no-rust"
Gregory Szorc
run-tests: move installhg() into TestRunner
r21353
# Run installer in hg root
script = os.path.realpath(sys.argv[0])
Rodrigo Damazio Bovendorp
pycompat: make fewer assumptions about sys.executable...
r42723 exe = sysexecutable
Augie Fackler
run-tests: move all open-coded sys.version_info checks to PYTHON3 (issue4668)...
r25159 if PYTHON3:
Manuel Jacob
tests: rename _bytespath() to _sys2bytes() and _strpath() to _sys2str()...
r44935 compiler = _sys2bytes(compiler)
script = _sys2bytes(script)
exe = _sys2bytes(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''
Augie Fackler
formatting: blacken the codebase...
r43346 cmd = (
run-tests: rename "pure" variable to setup_opts...
r44972 b'"%(exe)s" setup.py %(setup_opts)s clean --all'
Augie Fackler
formatting: blacken the codebase...
r43346 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'
% {
b'exe': exe,
run-tests: rename "pure" variable to setup_opts...
r44972 b'setup_opts': setup_opts,
Augie Fackler
formatting: blacken the codebase...
r43346 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
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
run-tests: ensure install directories exist...
r24075 makedirs(self._pythondir)
makedirs(self._bindir)
Denis Laxalde
py3: decode bytes before logging in run-tests.py...
r43614 vlog("# Running", cmd.decode("utf-8"))
Manuel Jacob
tests: rename _bytespath() to _sys2bytes() and _strpath() to _sys2str()...
r44935 if subprocess.call(_bytes2sys(cmd), shell=True) == 0:
Gregory Szorc
run-tests: move installhg() into TestRunner
r21353 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
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()
Gregory Szorc
run-tests: use raw strings for regular expressions...
r41681 if br'"%~dp0..\python" "%~dp0hg" %*' in data:
Augie Fackler
formatting: blacken the codebase...
r43346 data = data.replace(
br'"%~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 code coverage work on Python 3...
r43577 custom = os.path.join(
osenvironb[b'RUNTESTDIR'], b'sitecustomize.py'
)
target = os.path.join(self._pythondir, b'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 code coverage work on Python 3...
r43577 rc = os.path.join(self._testdir, b'.coveragerc')
Gregory Szorc
run-tests: move installhg() into TestRunner
r21353 vlog('# Installing coverage rc to %s' % rc)
Gregory Szorc
run-tests: make code coverage work on Python 3...
r43577 osenvironb[b'COVERAGE_PROCESS_START'] = rc
covdir = os.path.join(self._installdir, b'..', b'coverage')
Gregory Szorc
run-tests: collect aggregate code coverage...
r24505 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
Gregory Szorc
run-tests: make code coverage work on Python 3...
r43577 osenvironb[b'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."""
Augie Fackler
formatting: blacken the codebase...
r43346 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):
Augie Fackler
formatting: blacken the codebase...
r43346 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
Matt Harbison
py3: teach run-tests.py to handle exe with spaces when --local isn't specified...
r40966 cmd = b'"%s" -c "import mercurial; print (mercurial.__path__[0])"'
Augie Fackler
run-tests: unblock running python tests in python 3...
r25058 cmd = cmd % PYTHON
Augie Fackler
run-tests: move all open-coded sys.version_info checks to PYTHON3 (issue4668)...
r25159 if PYTHON3:
Manuel Jacob
tests: rename _bytespath() to _sys2bytes() and _strpath() to _sys2str()...
r44935 cmd = _bytes2sys(cmd)
Matt Harbison
py3: teach run-tests.py to handle exe with spaces when --local isn't specified...
r40966
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
out, err = p.communicate()
self._hgpath = out.strip()
Gregory Szorc
run-tests: move _gethgpath() into TestRunner
r21385
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()'
Augie Fackler
formatting: blacken the codebase...
r43346 cmd = b'"%(make)s" clean install PREFIX="%(prefix)s"' % {
b'make': b'make', # TODO: switch by option or environment?
b'prefix': self._installdir,
}
Yuya Nishihara
run-tests: add --chg option to install and run tests using chg...
r28143 cwd = os.path.join(self._hgroot, b'contrib', b'chg')
vlog("# Running", cmd)
Augie Fackler
formatting: blacken the codebase...
r43346 proc = subprocess.Popen(
cmd,
shell=True,
cwd=cwd,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
)
Yuya Nishihara
run-tests: add --chg option to install and run tests using chg...
r28143 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
Augie Fackler
formatting: blacken the codebase...
r43346
Pulkit Goyal
py3: make files use absolute_import and print_function...
r29485 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)
Manuel Jacob
tests: rename _bytespath() to _sys2bytes() and _strpath() to _sys2str()...
r44935 covdir = os.path.join(_bytes2sys(self._installdir), '..', 'coverage')
Gregory Szorc
run-tests: collect aggregate code coverage...
r24505 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.
Manuel Jacob
tests: rename _bytespath() to _sys2bytes() and _strpath() to _sys2str()...
r44935 cov.config.paths['srcdir'] = ['.', _bytes2sys(self._pythondir)]
Gregory Szorc
run-tests: report code coverage from source directory...
r24506
Gregory Szorc
run-tests: collect aggregate code coverage...
r24505 cov.combine()
Gregory Szorc
run-tests: move outputcoverage() into TestRunner
r21356
Gregory Szorc
run-tests: make code coverage work on Python 3...
r43577 omit = [
Manuel Jacob
tests: rename _bytespath() to _sys2bytes() and _strpath() to _sys2str()...
r44935 _bytes2sys(os.path.join(x, b'*'))
Gregory Szorc
run-tests: make code coverage work on Python 3...
r43577 for x in [self._bindir, self._testdir]
]
Gregory Szorc
run-tests: obtain code coverage via Python API...
r24504 cov.report(ignore_errors=True, omit=omit)
Gregory Szorc
run-tests: move outputcoverage() into TestRunner
r21356 if self.options.htmlcov:
Manuel Jacob
tests: rename _bytespath() to _sys2bytes() and _strpath() to _sys2str()...
r44935 htmldir = os.path.join(_bytes2sys(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:
Manuel Jacob
tests: rename _bytespath() to _sys2bytes() and _strpath() to _sys2str()...
r44935 adir = os.path.join(_bytes2sys(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"""
Manuel Jacob
tests: rename _bytespath() to _sys2bytes() and _strpath() to _sys2str()...
r44935 dpb = _sys2bytes(os.defpath)
sepb = _sys2bytes(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):
Axel Hecht
run-tests: find python binary on Python 3 (issue6361)...
r45573 return _bytes2sys(name)
Gregory Szorc
run-tests: move program searching into TestRunner
r21365 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:
Matt Harbison
py3: add b'' to some run-tests.py strings for Windows...
r39625 if os.name == 'nt' and not p.endswith(b'.exe'):
p += b'.exe'
Gregory Szorc
run-tests: move program searching into TestRunner
r21365 found = self._findprogram(p)
Denis Laxalde
py3: decode bytes before logging in run-tests.py...
r43614 p = p.decode("utf-8")
Gregory Szorc
run-tests: move program searching into TestRunner
r21365 if found:
Axel Hecht
run-tests: find python binary on Python 3 (issue6361)...
r45573 vlog("# Found prerequisite", p, "at", found)
Gregory Szorc
run-tests: move program searching into TestRunner
r21365 else:
Denis Laxalde
py3: decode bytes before logging in run-tests.py...
r43614 print("WARNING: Did not find prerequisite tool: %s " % p)
Augie Fackler
formatting: blacken the codebase...
r43346
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:
Augie Fackler
formatting: blacken the codebase...
r43346 combined[key] = (
exceptioncounts[key],
len(testsbyfailure[key]),
leastfailing[key][0],
leastfailing[key][1],
)
Gregory Szorc
run-tests: report tests that exception occurred in...
r36054
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
Augie Fackler
formatting: blacken the codebase...
r43346
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
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Mackall
run-tests: self-test on Windows needs binary streams
r22120 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:]))