| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142 | #!/usr/bin/python"""Run tests in parallel."""import argparseimport globimport itertoolsimport multiprocessingimport sysimport timeimport jobsetimport watch_dirs# SimpleConfig: just compile with CONFIG=config, and run the binary to testclass SimpleConfig(object):  def __init__(self, config):    self.build_config = config    self.maxjobs = 32 * multiprocessing.cpu_count()  def run_command(self, binary):    return [binary]# ValgrindConfig: compile with some CONFIG=config, but use valgrind to runclass ValgrindConfig(object):  def __init__(self, config, tool):    self.build_config = config    self.tool = tool    self.maxjobs = 4 * multiprocessing.cpu_count()  def run_command(self, binary):    return ['valgrind', binary, '--tool=%s' % self.tool]# different configurations we can run under_CONFIGS = {  'dbg': SimpleConfig('dbg'),  'opt': SimpleConfig('opt'),  'tsan': SimpleConfig('tsan'),  'msan': SimpleConfig('msan'),  'asan': SimpleConfig('asan'),  'gcov': SimpleConfig('gcov'),  'memcheck': ValgrindConfig('dbg', 'memcheck'),  'helgrind': ValgrindConfig('dbg', 'helgrind')  }_DEFAULT = ['dbg', 'opt']_LANGUAGE_TEST_TARGETS = {    'c++': 'buildtests_cxx',    'c': 'buildtests_c',}# parse command lineargp = argparse.ArgumentParser(description='Run grpc tests.')argp.add_argument('-c', '--config',                  choices=['all'] + sorted(_CONFIGS.keys()),                  nargs='+',                  default=_DEFAULT)argp.add_argument('-t', '--test-filter', nargs='*', default=['*'])argp.add_argument('-n', '--runs_per_test', default=1, type=int)argp.add_argument('-f', '--forever',                  default=False,                  action='store_const',                  const=True)argp.add_argument('--newline_on_success',                  default=False,                  action='store_const',                  const=True)argp.add_argument('-l', '--language',                  choices=sorted(_LANGUAGE_TEST_TARGETS.keys()),                  nargs='+',                  default=sorted(_LANGUAGE_TEST_TARGETS.keys()))args = argp.parse_args()# grab configrun_configs = set(_CONFIGS[cfg]                  for cfg in itertools.chain.from_iterable(                      _CONFIGS.iterkeys() if x == 'all' else [x]                      for x in args.config))build_configs = set(cfg.build_config for cfg in run_configs)make_targets = set(_LANGUAGE_TEST_TARGETS[x] for x in args.language)filters = args.test_filterruns_per_test = args.runs_per_testforever = args.foreverdef _build_and_run(check_cancelled, newline_on_success, forever=False):  """Do one pass of building & running tests."""  # build latest, sharing cpu between the various makes  if not jobset.run(      (['make',        '-j', '%d' % (multiprocessing.cpu_count() + 1),        'CONFIG=%s' % cfg] + list(make_targets)       for cfg in build_configs),      check_cancelled, maxjobs=1):    return 1  # run all the tests  if not jobset.run(      itertools.ifilter(          lambda x: x is not None, (              config.run_command(x)              for config in run_configs              for filt in filters              for x in itertools.chain.from_iterable(itertools.repeat(                  glob.glob('bins/%s/%s_test' % (                      config.build_config, filt)),                  runs_per_test)))),              check_cancelled,              newline_on_success=newline_on_success,              maxjobs=min(c.maxjobs for c in run_configs)):    return 2  return 0if forever:  success = True  while True:    dw = watch_dirs.DirWatcher(['src', 'include', 'test'])    initial_time = dw.most_recent_change()    have_files_changed = lambda: dw.most_recent_change() != initial_time    previous_success = success    success = _build_and_run(have_files_changed,                             newline_on_success=False,                             forever=True) == 0    if not previous_success and success:      jobset.message('SUCCESS',                     'All tests are now passing properly',                     do_newline=True)    jobset.message('IDLE', 'No change detected')    while not have_files_changed():      time.sleep(1)else:  result = _build_and_run(lambda: False,                          newline_on_success=args.newline_on_success)  if result == 0:    jobset.message('SUCCESS', 'All tests passed', do_newline=True)  else:    jobset.message('FAILED', 'Some tests failed', do_newline=True)  sys.exit(result)
 |