summaryrefslogtreecommitdiff
path: root/tests/run-tests.py
diff options
context:
space:
mode:
Diffstat (limited to 'tests/run-tests.py')
-rwxr-xr-xtests/run-tests.py248
1 files changed, 65 insertions, 183 deletions
diff --git a/tests/run-tests.py b/tests/run-tests.py
index c9ef7d5..b9af4cb 100755
--- a/tests/run-tests.py
+++ b/tests/run-tests.py
@@ -75,7 +75,7 @@ def Popen4(cmd, wd, timeout):
def t():
start = time.time()
while time.time() - start < timeout and p.returncode is None:
- time.sleep(.1)
+ time.sleep(1)
p.timeout = True
if p.returncode is None:
terminate(p)
@@ -87,7 +87,7 @@ def Popen4(cmd, wd, timeout):
SKIPPED_STATUS = 80
SKIPPED_PREFIX = 'skipped: '
FAILED_PREFIX = 'hghave check failed: '
-PYTHON = sys.executable.replace('\\', '/')
+PYTHON = sys.executable
IMPL_PATH = 'PYTHONPATH'
if 'java' in sys.platform:
IMPL_PATH = 'JYTHONPATH'
@@ -98,7 +98,7 @@ defaults = {
'jobs': ('HGTEST_JOBS', 1),
'timeout': ('HGTEST_TIMEOUT', 180),
'port': ('HGTEST_PORT', 20059),
- 'shell': ('HGTEST_SHELL', 'sh'),
+ 'shell': ('HGTEST_SHELL', '/bin/sh'),
}
def parselistfiles(files, listtype, warn=True):
@@ -141,8 +141,6 @@ def parseargs():
" rather than capturing and diff'ing it (disables timeout)")
parser.add_option("-f", "--first", action="store_true",
help="exit on the first test failure")
- parser.add_option("-H", "--htmlcov", action="store_true",
- help="create an HTML report of the coverage of the files")
parser.add_option("--inotify", action="store_true",
help="enable inotify extension when running tests")
parser.add_option("-i", "--interactive", action="store_true",
@@ -200,7 +198,6 @@ def parseargs():
options.pure = True
if options.with_hg:
- options.with_hg = os.path.expanduser(options.with_hg)
if not (os.path.isfile(options.with_hg) and
os.access(options.with_hg, os.X_OK)):
parser.error('--with-hg must specify an executable hg script')
@@ -209,12 +206,12 @@ def parseargs():
if options.local:
testdir = os.path.dirname(os.path.realpath(sys.argv[0]))
hgbin = os.path.join(os.path.dirname(testdir), 'hg')
- if os.name != 'nt' and not os.access(hgbin, os.X_OK):
+ if not os.access(hgbin, os.X_OK):
parser.error('--local specified, but %r not found or not executable'
% hgbin)
options.with_hg = hgbin
- options.anycoverage = options.cover or options.annotate or options.htmlcov
+ options.anycoverage = options.cover or options.annotate
if options.anycoverage:
try:
import coverage
@@ -343,7 +340,10 @@ def terminate(proc):
"""Terminate subprocess (with fallback for Python versions < 2.6)"""
vlog('# Terminating process %d' % proc.pid)
try:
- getattr(proc, 'terminate', lambda : os.kill(proc.pid, signal.SIGTERM))()
+ if hasattr(proc, 'terminate'):
+ proc.terminate()
+ else:
+ os.kill(proc.pid, signal.SIGTERM)
except OSError:
pass
@@ -360,7 +360,7 @@ def killdaemons():
os.kill(pid, 0)
vlog('# Killing daemon process %d' % pid)
os.kill(pid, signal.SIGTERM)
- time.sleep(0.1)
+ time.sleep(0.25)
os.kill(pid, 0)
vlog('# Daemon process %d is stuck - really killing it' % pid)
os.kill(pid, signal.SIGKILL)
@@ -496,11 +496,8 @@ def outputcoverage(options):
return
covrun('-c')
- omit = ','.join(os.path.join(x, '*') for x in [BINDIR, TESTDIR])
+ omit = ','.join([BINDIR, TESTDIR])
covrun('-i', '-r', '"--omit=%s"' % omit) # report
- if options.htmlcov:
- htmldir = os.path.join(TESTDIR, 'htmlcov')
- covrun('-i', '-b', '"--directory=%s"' % htmldir, '"--omit=%s"' % omit)
if options.annotate:
adir = os.path.join(TESTDIR, 'annotated')
if not os.path.isdir(adir):
@@ -514,7 +511,7 @@ def pytest(test, wd, options, replacements):
return run(cmd, wd, options, replacements)
def shtest(test, wd, options, replacements):
- cmd = '%s "%s"' % (options.shell, test)
+ cmd = '"%s"' % test
vlog("# Running", cmd)
return run(cmd, wd, options, replacements)
@@ -527,141 +524,23 @@ def escapef(m):
def stringescape(s):
return escapesub(escapef, s)
-def rematch(el, l):
- try:
- # ensure that the regex matches to the end of the string
- return re.match(el + r'\Z', l)
- except re.error:
- # el is an invalid regex
- return False
-
-def globmatch(el, l):
- # The only supported special characters are * and ? plus / which also
- # matches \ on windows. Escaping of these caracters is supported.
- i, n = 0, len(el)
- res = ''
- while i < n:
- c = el[i]
- i += 1
- if c == '\\' and el[i] in '*?\\/':
- res += el[i - 1:i + 1]
- i += 1
- elif c == '*':
- res += '.*'
- elif c == '?':
- res += '.'
- elif c == '/' and os.name == 'nt':
- res += '[/\\\\]'
- else:
- res += re.escape(c)
- return rematch(res, l)
-
-def linematch(el, l):
- if el == l: # perfect match (fast)
- return True
- if (el and
- (el.endswith(" (re)\n") and rematch(el[:-6] + '\n', l) or
- el.endswith(" (glob)\n") and globmatch(el[:-8] + '\n', l) or
- el.endswith(" (esc)\n") and
- (el[:-7].decode('string-escape') + '\n' == l or
- el[:-7].decode('string-escape').replace('\r', '') +
- '\n' == l and os.name == 'nt'))):
- return True
- return False
-
def tsttest(test, wd, options, replacements):
- # 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
+ t = open(test)
+ out = []
+ script = []
salt = "SALT" + str(time.time())
- def addsalt(line, inpython):
- if inpython:
- script.append('%s %d 0\n' % (salt, line))
- else:
- script.append('echo %s %s $?\n' % (salt, line))
- # 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 = {}
pos = prepos = -1
-
- # Expected shellscript output
+ after = {}
expected = {}
-
- # We keep track of whether or not we're in a Python block so we
- # can generate the surrounding doctest magic
- inpython = False
-
- # True or False when in a true or false conditional section
- skipping = None
-
- def hghave(reqs):
- # TODO: do something smarter when all other uses of hghave is gone
- tdir = TESTDIR.replace('\\', '/')
- proc = Popen4('%s -c "%s/hghave %s"' %
- (options.shell, tdir, ' '.join(reqs)), wd, 0)
- proc.communicate()
- ret = proc.wait()
- if wifexited(ret):
- ret = os.WEXITSTATUS(ret)
- return ret == 0
-
- f = open(test)
- t = f.readlines()
- f.close()
-
- script = []
- if options.debug:
- script.append('set -x\n')
- if os.getenv('MSYSTEM'):
- script.append('alias pwd="pwd -W"\n')
for n, l in enumerate(t):
if not l.endswith('\n'):
l += '\n'
- if l.startswith('#if'):
- if skipping is not None:
- after.setdefault(pos, []).append(' !!! nested #if\n')
- skipping = not hghave(l.split()[1:])
- after.setdefault(pos, []).append(l)
- elif l.startswith('#else'):
- if skipping is None:
- after.setdefault(pos, []).append(' !!! missing #if\n')
- skipping = not skipping
- after.setdefault(pos, []).append(l)
- elif l.startswith('#endif'):
- if skipping is None:
- after.setdefault(pos, []).append(' !!! missing #if\n')
- skipping = None
- after.setdefault(pos, []).append(l)
- elif skipping:
- after.setdefault(pos, []).append(l)
- elif l.startswith(' >>> '): # python inlines
- after.setdefault(pos, []).append(l)
- prepos = pos
- pos = n
- if not inpython:
- # we've just entered a Python block, add the header
- inpython = True
- addsalt(prepos, False) # make sure we report the exit code
- script.append('%s -m heredoctest <<EOF\n' % PYTHON)
- addsalt(n, True)
- script.append(l[2:])
- elif l.startswith(' ... '): # python inlines
- after.setdefault(prepos, []).append(l)
- script.append(l[2:])
- elif l.startswith(' $ '): # commands
- if inpython:
- script.append("EOF\n")
- inpython = False
+ if l.startswith(' $ '): # commands
after.setdefault(pos, []).append(l)
prepos = pos
pos = n
- addsalt(n, False)
- cmd = l[4:].split()
- if len(cmd) == 2 and cmd[0] == 'cd':
- l = ' $ cd %s || exit 1\n' % cmd[1]
+ script.append('echo %s %s $?\n' % (salt, n))
script.append(l[4:])
elif l.startswith(' > '): # continuations
after.setdefault(prepos, []).append(l)
@@ -670,26 +549,21 @@ def tsttest(test, wd, options, replacements):
# queue up a list of expected results
expected.setdefault(pos, []).append(l[2:])
else:
- if inpython:
- script.append("EOF\n")
- inpython = False
# non-command/result - queue up for merged output
after.setdefault(pos, []).append(l)
- if inpython:
- script.append("EOF\n")
- if skipping is not None:
- after.setdefault(pos, []).append(' !!! missing #endif\n')
- addsalt(n + 1, False)
+ t.close()
+
+ script.append('echo %s %s $?\n' % (salt, n + 1))
- # Write out the script and execute it
fd, name = tempfile.mkstemp(suffix='hg-tst')
+
try:
for l in script:
os.write(fd, l)
os.close(fd)
- cmd = '%s "%s"' % (options.shell, name)
+ cmd = '"%s" "%s"' % (options.shell, name)
vlog("# Running", cmd)
exitcode, output = run(cmd, wd, options, replacements)
# do not merge output if skipped, return hghave message instead
@@ -699,7 +573,32 @@ def tsttest(test, wd, options, replacements):
finally:
os.remove(name)
- # Merge the script output back into a unified test
+ def rematch(el, l):
+ try:
+ # ensure that the regex matches to the end of the string
+ return re.match(el + r'\Z', l)
+ except re.error:
+ # el is an invalid regex
+ return False
+
+ def globmatch(el, l):
+ # The only supported special characters are * and ?. Escaping is
+ # supported.
+ i, n = 0, len(el)
+ res = ''
+ while i < n:
+ c = el[i]
+ i += 1
+ if c == '\\' and el[i] in '*?\\':
+ res += el[i - 1:i + 1]
+ i += 1
+ elif c == '*':
+ res += '.*'
+ elif c == '?':
+ res += '.'
+ else:
+ res += re.escape(c)
+ return rematch(res, l)
pos = -1
postout = []
@@ -711,16 +610,20 @@ def tsttest(test, wd, options, replacements):
if lout:
if lcmd:
- # output block had no trailing newline, clean up
lout += ' (no-eol)\n'
- # find the expected output at the current position
el = None
if pos in expected and expected[pos]:
el = expected[pos].pop(0)
- if linematch(el, lout):
- postout.append(" " + el)
+ if el == lout: # perfect match (fast)
+ postout.append(" " + lout)
+ elif (el and
+ (el.endswith(" (re)\n") and rematch(el[:-6] + '\n', lout) or
+ el.endswith(" (glob)\n") and globmatch(el[:-8] + '\n', lout)
+ or el.endswith(" (esc)\n") and
+ el.decode('string-escape') == l)):
+ postout.append(" " + el) # fallback regex/glob/esc match
else:
if needescape(lout):
lout = stringescape(lout.rstrip('\n')) + " (esc)\n"
@@ -732,7 +635,6 @@ def tsttest(test, wd, options, replacements):
if ret != 0:
postout.append(" [%s]\n" % ret)
if pos in after:
- # merge in non-active test bits
postout += after.pop(pos)
pos = int(lcmd.split()[0])
@@ -824,7 +726,6 @@ def runone(options, test):
rename(testpath + ".err", testpath)
else:
rename(testpath + ".err", testpath + ".out")
- result('p', test)
return
result('f', (test, msg))
@@ -896,7 +797,7 @@ def runone(options, test):
tf = open(testpath)
firstline = tf.readline().rstrip()
tf.close()
- except IOError:
+ except:
firstline = ''
lctest = test.lower()
@@ -915,24 +816,13 @@ def runone(options, test):
testtmp = os.environ["TESTTMP"] = os.environ["HOME"] = \
os.path.join(HGTMP, os.path.basename(test))
- replacements = [
+ os.mkdir(testtmp)
+ ret, out = runner(testpath, testtmp, options, [
+ (re.escape(testtmp), '$TESTTMP'),
(r':%s\b' % options.port, ':$HGPORT'),
(r':%s\b' % (options.port + 1), ':$HGPORT1'),
(r':%s\b' % (options.port + 2), ':$HGPORT2'),
- ]
- if os.name == 'nt':
- replacements.append((r'\r\n', '\n'))
- replacements.append(
- (''.join(c.isalpha() and '[%s%s]' % (c.lower(), c.upper()) or
- c in '/\\' and r'[/\\]' or
- c.isdigit() and c or
- '\\' + c
- for c in testtmp), '$TESTTMP'))
- else:
- replacements.append((re.escape(testtmp), '$TESTTMP'))
-
- os.mkdir(testtmp)
- ret, out = runner(testpath, testtmp, options, replacements)
+ ])
vlog("# Ret was:", ret)
mark = '.'
@@ -945,7 +835,7 @@ def runone(options, test):
refout = None # to match "out is None"
elif os.path.exists(ref):
f = open(ref, "r")
- refout = list(splitnewlines(f.read()))
+ refout = splitnewlines(f.read())
f.close()
else:
refout = []
@@ -1221,9 +1111,6 @@ def main():
os.environ['COLUMNS'] = '80'
os.environ['GREP_OPTIONS'] = ''
os.environ['http_proxy'] = ''
- os.environ['no_proxy'] = ''
- os.environ['NO_PROXY'] = ''
- os.environ['TERM'] = 'xterm'
# unset env related to hooks
for k in os.environ.keys():
@@ -1250,12 +1137,7 @@ def main():
#shutil.rmtree(tmpdir)
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)
- d = os.getenv('TMP')
- tmpdir = tempfile.mkdtemp('', 'hgtests.', d)
+ tmpdir = tempfile.mkdtemp('', 'hgtests.')
HGTMP = os.environ['HGTMP'] = os.path.realpath(tmpdir)
DAEMON_PIDS = None
HGRCPATH = None
@@ -1317,7 +1199,7 @@ def main():
else:
runtests(options, tests)
finally:
- time.sleep(.1)
+ time.sleep(1)
cleanup(options)
if __name__ == '__main__':