Nicolas Noble | ddef246 | 2015-01-06 18:08:25 -0800 | [diff] [blame] | 1 | #!/usr/bin/python |
| 2 | """Run tests in parallel.""" |
| 3 | |
| 4 | import argparse |
| 5 | import glob |
| 6 | import itertools |
| 7 | import multiprocessing |
| 8 | import sys |
ctiller | 3040cb7 | 2015-01-07 12:13:17 -0800 | [diff] [blame^] | 9 | import time |
Nicolas Noble | ddef246 | 2015-01-06 18:08:25 -0800 | [diff] [blame] | 10 | |
| 11 | import jobset |
ctiller | 3040cb7 | 2015-01-07 12:13:17 -0800 | [diff] [blame^] | 12 | import watch_dirs |
Nicolas Noble | ddef246 | 2015-01-06 18:08:25 -0800 | [diff] [blame] | 13 | |
| 14 | # flags required for make for each configuration |
| 15 | _CONFIGS = ['dbg', 'opt', 'tsan', 'msan', 'asan'] |
| 16 | |
| 17 | # parse command line |
| 18 | argp = argparse.ArgumentParser(description='Run grpc tests.') |
| 19 | argp.add_argument('-c', '--config', |
| 20 | choices=['all'] + _CONFIGS, |
| 21 | nargs='+', |
| 22 | default=['all']) |
| 23 | argp.add_argument('-t', '--test-filter', nargs='*', default=['*']) |
| 24 | argp.add_argument('-n', '--runs_per_test', default=1, type=int) |
ctiller | 3040cb7 | 2015-01-07 12:13:17 -0800 | [diff] [blame^] | 25 | argp.add_argument('-f', '--forever', |
| 26 | default=False, |
| 27 | action='store_const', |
| 28 | const=True) |
Nicolas Noble | ddef246 | 2015-01-06 18:08:25 -0800 | [diff] [blame] | 29 | args = argp.parse_args() |
| 30 | |
| 31 | # grab config |
| 32 | configs = [cfg |
| 33 | for cfg in itertools.chain.from_iterable( |
| 34 | _CONFIGS if x == 'all' else [x] |
| 35 | for x in args.config)] |
| 36 | filters = args.test_filter |
| 37 | runs_per_test = args.runs_per_test |
ctiller | 3040cb7 | 2015-01-07 12:13:17 -0800 | [diff] [blame^] | 38 | forever = args.forever |
Nicolas Noble | ddef246 | 2015-01-06 18:08:25 -0800 | [diff] [blame] | 39 | |
Nicolas Noble | ddef246 | 2015-01-06 18:08:25 -0800 | [diff] [blame] | 40 | |
ctiller | 3040cb7 | 2015-01-07 12:13:17 -0800 | [diff] [blame^] | 41 | def _build_and_run(check_cancelled): |
| 42 | """Do one pass of building & running tests.""" |
| 43 | # build latest, sharing cpu between the various makes |
| 44 | if not jobset.run( |
| 45 | (['make', |
| 46 | '-j', '%d' % max(multiprocessing.cpu_count() / len(configs), 1), |
| 47 | 'buildtests_c', |
| 48 | 'CONFIG=%s' % cfg] |
| 49 | for cfg in configs), check_cancelled): |
| 50 | sys.exit(1) |
| 51 | |
| 52 | # run all the tests |
| 53 | jobset.run(([x] |
| 54 | for x in itertools.chain.from_iterable( |
| 55 | itertools.chain.from_iterable(itertools.repeat( |
| 56 | glob.glob('bins/%s/%s_test' % (config, filt)), |
| 57 | runs_per_test)) |
| 58 | for config in configs |
| 59 | for filt in filters)), check_cancelled) |
| 60 | |
| 61 | |
| 62 | if forever: |
| 63 | while True: |
| 64 | dw = watch_dirs.DirWatcher(['src', 'include', 'test']) |
| 65 | initial_time = dw.most_recent_change() |
| 66 | have_files_changed = lambda: dw.most_recent_change() != initial_time |
| 67 | _build_and_run(have_files_changed) |
| 68 | while not have_files_changed(): |
| 69 | time.sleep(1) |
| 70 | else: |
| 71 | _build_and_run(lambda: False) |
| 72 | |