Allow specifying environment variables.
Refactor the code a little to make this easier to munge around.
diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py
index a4cb08f..8cc029e 100755
--- a/tools/run_tests/run_tests.py
+++ b/tools/run_tests/run_tests.py
@@ -17,13 +17,17 @@
# SimpleConfig: just compile with CONFIG=config, and run the binary to test
class SimpleConfig(object):
- def __init__(self, config):
+ def __init__(self, config, environ={}):
self.build_config = config
self.maxjobs = 2 * multiprocessing.cpu_count()
self.allow_hashing = (config != 'gcov')
+ self.environ = environ
- def run_command(self, binary):
- return [binary]
+ def job_spec(self, binary, hash_targets):
+ return jobset.JobSpec(cmdline=[binary],
+ environ=self.environ,
+ hash_targets=hash_targets
+ if self.allow_hashing else None)
# ValgrindConfig: compile with some CONFIG=config, but use valgrind to run
@@ -35,14 +39,14 @@
self.maxjobs = 2 * multiprocessing.cpu_count()
self.allow_hashing = False
- def run_command(self, binary):
- return ['valgrind', '--tool=%s' % self.tool, binary]
+ def job_spec(self, binary, hash_targets):
+ return JobSpec(cmdline=['valgrind', '--tool=%s' % self.tool, binary],
+ hash_targets=None)
class CLanguage(object):
def __init__(self, make_target, test_lang):
- self.allow_hashing = True
self.make_target = make_target
with open('tools/run_tests/tests.json') as f:
js = json.load(f)
@@ -50,8 +54,12 @@
for tgt in js
if tgt['language'] == test_lang]
- def test_binaries(self, config):
- return ['bins/%s/%s' % (config, binary) for binary in self.binaries]
+ def test_specs(self, config):
+ out = []
+ for name in self.binaries:
+ binary = 'bins/%s/%s' % (config.build_config, name)
+ out.append(config.job_spec(binary, [binary]))
+ return out
def make_targets(self):
return ['buildtests_%s' % self.make_target]
@@ -62,11 +70,8 @@
class NodeLanguage(object):
- def __init__(self):
- self.allow_hashing = False
-
- def test_binaries(self, config):
- return ['tools/run_tests/run_node.sh']
+ def test_specs(self, config):
+ return [config.job_spec('tools/run_tests/run_node.sh', None)]
def make_targets(self):
return ['static_c']
@@ -77,11 +82,8 @@
class PhpLanguage(object):
- def __init__(self):
- self.allow_hashing = False
-
- def test_binaries(self, config):
- return ['src/php/bin/run_tests.sh']
+ def test_specs(self, config):
+ return [config.job_spec('src/php/bin/run_tests.sh', None)]
def make_targets(self):
return ['static_c']
@@ -92,11 +94,8 @@
class PythonLanguage(object):
- def __init__(self):
- self.allow_hashing = False
-
- def test_binaries(self, config):
- return ['tools/run_tests/run_python.sh']
+ def test_specs(self, config):
+ return [config.job_spec('tools/run_tests/run_python.sh', None)]
def make_targets(self):
return[]
@@ -111,7 +110,8 @@
'opt': SimpleConfig('opt'),
'tsan': SimpleConfig('tsan'),
'msan': SimpleConfig('msan'),
- 'asan': SimpleConfig('asan'),
+ 'asan': SimpleConfig('asan', environ={
+ 'ASAN_OPTIONS': 'detect_leaks=1:color=always'}),
'gcov': SimpleConfig('gcov'),
'memcheck': ValgrindConfig('valgrind', 'memcheck'),
'helgrind': ValgrindConfig('dbg', 'helgrind')
@@ -157,14 +157,20 @@
make_targets = []
languages = set(_LANGUAGES[l] for l in args.language)
-build_steps = [['make',
- '-j', '%d' % (multiprocessing.cpu_count() + 1),
- 'CONFIG=%s' % cfg] + list(set(
- itertools.chain.from_iterable(l.make_targets()
- for l in languages)))
- for cfg in build_configs] + list(
- itertools.chain.from_iterable(l.build_steps()
- for l in languages))
+build_steps = [jobset.JobSpec(['make',
+ '-j', '%d' % (multiprocessing.cpu_count() + 1),
+ 'CONFIG=%s' % cfg] + list(set(
+ itertools.chain.from_iterable(
+ l.make_targets() for l in languages))))
+ for cfg in build_configs] + list(set(
+ jobset.JobSpec(cmdline)
+ for l in languages
+ for cmdline in l.build_steps()))
+one_run = set(
+ spec
+ for config in run_configs
+ for language in args.language
+ for spec in _LANGUAGES[language].test_specs(config))
runs_per_test = args.runs_per_test
forever = args.forever
@@ -177,7 +183,6 @@
self._last_successful_run = {}
def should_run(self, cmdline, bin_hash):
- cmdline = ' '.join(cmdline)
if cmdline not in self._last_successful_run:
return True
if self._last_successful_run[cmdline] != bin_hash:
@@ -185,7 +190,7 @@
return False
def finished(self, cmdline, bin_hash):
- self._last_successful_run[' '.join(cmdline)] = bin_hash
+ self._last_successful_run[cmdline] = bin_hash
def dump(self):
return [{'cmdline': k, 'hash': v}
@@ -211,12 +216,6 @@
return 1
# run all the tests
- one_run = dict(
- (' '.join(config.run_command(x)), config.run_command(x))
- for config in run_configs
- for language in args.language
- for x in _LANGUAGES[language].test_binaries(config.build_config)
- ).values()
all_runs = itertools.chain.from_iterable(
itertools.repeat(one_run, runs_per_test))
if not jobset.run(all_runs, check_cancelled,
@@ -228,12 +227,8 @@
return 0
-test_cache = (None
- if not all(x.allow_hashing
- for x in itertools.chain(languages, run_configs))
- else TestCache())
-if test_cache:
- test_cache.maybe_load()
+test_cache = TestCache()
+test_cache.maybe_load()
if forever:
success = True
@@ -250,7 +245,7 @@
'All tests are now passing properly',
do_newline=True)
jobset.message('IDLE', 'No change detected')
- if test_cache: test_cache.save()
+ test_cache.save()
while not have_files_changed():
time.sleep(1)
else:
@@ -261,5 +256,5 @@
jobset.message('SUCCESS', 'All tests passed', do_newline=True)
else:
jobset.message('FAILED', 'Some tests failed', do_newline=True)
- if test_cache: test_cache.save()
+ test_cache.save()
sys.exit(result)