diff options
Diffstat (limited to 'tests/run-tests.py')
-rwxr-xr-x | tests/run-tests.py | 248 |
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__': |