blob: 2bd2e6d830cbf9aaa5d2b163004d8d59cc0609be [file] [log] [blame]
Nicolas Nobleddef2462015-01-06 18:08:25 -08001#!/usr/bin/python
2"""Run tests in parallel."""
3
4import argparse
5import glob
6import itertools
7import multiprocessing
8import sys
ctiller3040cb72015-01-07 12:13:17 -08009import time
Nicolas Nobleddef2462015-01-06 18:08:25 -080010
11import jobset
ctiller3040cb72015-01-07 12:13:17 -080012import watch_dirs
Nicolas Nobleddef2462015-01-06 18:08:25 -080013
Craig Tiller738c3342015-01-12 14:28:33 -080014
15# SimpleConfig: just compile with CONFIG=config, and run the binary to test
16class SimpleConfig(object):
17 def __init__(self, config):
18 self.build_config = config
19
20 def run_command(self, binary):
21 return [binary]
22
23
24# ValgrindConfig: compile with some CONFIG=config, but use valgrind to run
25class ValgrindConfig(object):
26 def __init__(self, config):
27 self.build_config = config
28
29 def run_command(self, binary):
30 return ['valgrind', binary]
31
32
33# different configurations we can run under
34_CONFIGS = {
35 'dbg': SimpleConfig('dbg'),
36 'opt': SimpleConfig('opt'),
37 'tsan': SimpleConfig('tsan'),
38 'msan': SimpleConfig('msan'),
39 'asan': SimpleConfig('asan'),
40 'valgrind': ValgrindConfig('dbg'),
41 }
42
43
Craig Tillerb29797b2015-01-12 13:51:54 -080044_DEFAULT = ['dbg', 'opt']
Nicolas Nobleddef2462015-01-06 18:08:25 -080045
46# parse command line
47argp = argparse.ArgumentParser(description='Run grpc tests.')
48argp.add_argument('-c', '--config',
Craig Tiller738c3342015-01-12 14:28:33 -080049 choices=['all'] + sorted(_CONFIGS.keys()),
Nicolas Nobleddef2462015-01-06 18:08:25 -080050 nargs='+',
Craig Tillerb29797b2015-01-12 13:51:54 -080051 default=_DEFAULT)
Nicolas Nobleddef2462015-01-06 18:08:25 -080052argp.add_argument('-t', '--test-filter', nargs='*', default=['*'])
53argp.add_argument('-n', '--runs_per_test', default=1, type=int)
ctiller3040cb72015-01-07 12:13:17 -080054argp.add_argument('-f', '--forever',
55 default=False,
56 action='store_const',
57 const=True)
Nicolas Nobleddef2462015-01-06 18:08:25 -080058args = argp.parse_args()
59
60# grab config
Craig Tiller738c3342015-01-12 14:28:33 -080061run_configs = set(_CONFIGS[cfg]
62 for cfg in itertools.chain.from_iterable(
63 _CONFIGS.iterkeys() if x == 'all' else [x]
64 for x in args.config))
65build_configs = set(cfg.build_config for cfg in run_configs)
Nicolas Nobleddef2462015-01-06 18:08:25 -080066filters = args.test_filter
67runs_per_test = args.runs_per_test
ctiller3040cb72015-01-07 12:13:17 -080068forever = args.forever
Nicolas Nobleddef2462015-01-06 18:08:25 -080069
Nicolas Nobleddef2462015-01-06 18:08:25 -080070
ctiller3040cb72015-01-07 12:13:17 -080071def _build_and_run(check_cancelled):
72 """Do one pass of building & running tests."""
73 # build latest, sharing cpu between the various makes
74 if not jobset.run(
75 (['make',
Craig Tiller738c3342015-01-12 14:28:33 -080076 '-j', '%d' % (multiprocessing.cpu_count() + 1),
ctiller3040cb72015-01-07 12:13:17 -080077 'buildtests_c',
78 'CONFIG=%s' % cfg]
Craig Tiller738c3342015-01-12 14:28:33 -080079 for cfg in build_configs), check_cancelled):
ctiller3040cb72015-01-07 12:13:17 -080080 sys.exit(1)
81
82 # run all the tests
Craig Tiller738c3342015-01-12 14:28:33 -080083 jobset.run((
84 config.run_command(x)
85 for config in run_configs
86 for filt in filters
87 for x in itertools.chain.from_iterable(itertools.repeat(
88 glob.glob('bins/%s/%s_test' % (
89 config.build_config, filt)),
90 runs_per_test))), check_cancelled)
ctiller3040cb72015-01-07 12:13:17 -080091
92
93if forever:
94 while True:
95 dw = watch_dirs.DirWatcher(['src', 'include', 'test'])
96 initial_time = dw.most_recent_change()
97 have_files_changed = lambda: dw.most_recent_change() != initial_time
98 _build_and_run(have_files_changed)
99 while not have_files_changed():
100 time.sleep(1)
101else:
102 _build_and_run(lambda: False)
103