run-tests: allow whitelisting tests that should always run
It's desirable to run some tests all the time, for example
test-check-pyflakes.t and test-check-code-hg.py. This allows passing
--whitelist as a path to a file (flag can be specified more than once)
which contains a list of files to whitelist. Whitelisted tests are run
even if they're blacklisted or wouldn't match a --keyword test
run. For example, to do a quick test of usehttp2, one can now do
$ cat > test-whitelist <<EOF
> test-check-pyflakes.t
> test-check-code-hg.py
> EOF
$ (cd tests && ./run-tests.py --extra-config-opt 'ui.usehttp2=true'
> -k http -j 8 --whitelist test-whitelist)
and have all http-specific tests run as well as the two code linters.
--- a/tests/run-tests.py Tue May 31 19:49:17 2011 -0500
+++ b/tests/run-tests.py Tue May 31 20:39:04 2011 -0500
@@ -104,12 +104,35 @@
'shell': ('HGTEST_SHELL', '/bin/sh'),
}
+def parselistfiles(files, listtype, warn=True):
+ entries = dict()
+ for filename in files:
+ try:
+ path = os.path.expanduser(os.path.expandvars(filename))
+ f = open(path, "r")
+ except IOError, err:
+ if err.errno != errno.ENOENT:
+ raise
+ if warn:
+ print "warning: no such %s file: %s" % (listtype, filename)
+ continue
+
+ for line in f.readlines():
+ line = line.split('#', 1)[0].strip()
+ if line:
+ entries[line] = filename
+
+ f.close()
+ return entries
+
def parseargs():
parser = optparse.OptionParser("%prog [options] [tests]")
# keep these sorted
parser.add_option("--blacklist", action="append",
help="skip tests listed in the specified blacklist file")
+ parser.add_option("--whitelist", action="append",
+ help="always run tests listed in the specified whitelist file")
parser.add_option("-C", "--annotate", action="store_true",
help="output files annotated with coverage")
parser.add_option("--child", type="int",
@@ -247,25 +270,12 @@
if sys.version_info[:2] < (2, 6) or sys.version_info[:2] >= (3, 0):
parser.error('--py3k-warnings can only be used on Python 2.6+')
if options.blacklist:
- blacklist = dict()
- for filename in options.blacklist:
- try:
- path = os.path.expanduser(os.path.expandvars(filename))
- f = open(path, "r")
- except IOError, err:
- if err.errno != errno.ENOENT:
- raise
- print "warning: no such blacklist file: %s" % filename
- continue
-
- for line in f.readlines():
- line = line.split('#', 1)[0].strip()
- if line:
- blacklist[line] = filename
-
- f.close()
-
- options.blacklist = blacklist
+ options.blacklist = parselistfiles(options.blacklist, 'blacklist')
+ if options.whitelist:
+ options.whitelisted = parselistfiles(options.whitelist, 'whitelist',
+ warn=options.child is None)
+ else:
+ options.whitelisted = {}
return (options, args)
@@ -733,24 +743,25 @@
else:
return None # not a supported test, don't record
- if options.blacklist and test in options.blacklist:
- skip("blacklisted")
- return None
+ if not (options.whitelisted and test in options.whitelisted):
+ if options.blacklist and test in options.blacklist:
+ skip("blacklisted")
+ return None
- if options.retest and not os.path.exists(test + ".err"):
- ignore("not retesting")
- return None
+ if options.retest and not os.path.exists(test + ".err"):
+ ignore("not retesting")
+ return None
- if options.keywords:
- fp = open(test)
- t = fp.read().lower() + test.lower()
- fp.close()
- for k in options.keywords.lower().split():
- if k in t:
- break
- else:
- ignore("doesn't match keyword")
- return None
+ if options.keywords:
+ fp = open(test)
+ t = fp.read().lower() + test.lower()
+ fp.close()
+ for k in options.keywords.lower().split():
+ if k in t:
+ break
+ else:
+ ignore("doesn't match keyword")
+ return None
vlog("# Test", test)
@@ -920,6 +931,14 @@
optcopy = dict(options.__dict__)
optcopy['jobs'] = 1
+ # Because whitelist has to override keyword matches, we have to
+ # actually load the whitelist in the children as well, so we allow
+ # the list of whitelist files to pass through and be parsed in the
+ # children, but not the dict of whitelisted tests resulting from
+ # the parse, used here to override blacklisted tests.
+ whitelist = optcopy['whitelisted'] or []
+ del optcopy['whitelisted']
+
blacklist = optcopy['blacklist'] or []
del optcopy['blacklist']
blacklisted = []
@@ -946,7 +965,7 @@
if not tests:
break
test = tests.pop()
- if test in blacklist:
+ if test not in whitelist and test in blacklist:
blacklisted.append(test)
else:
job.append(test)