aboutsummaryrefslogtreecommitdiffhomepage
path: root/tools/run_tests/run_tests_matrix.py
diff options
context:
space:
mode:
Diffstat (limited to 'tools/run_tests/run_tests_matrix.py')
-rwxr-xr-xtools/run_tests/run_tests_matrix.py304
1 files changed, 183 insertions, 121 deletions
diff --git a/tools/run_tests/run_tests_matrix.py b/tools/run_tests/run_tests_matrix.py
index b65010ad8b..6e83180c66 100755
--- a/tools/run_tests/run_tests_matrix.py
+++ b/tools/run_tests/run_tests_matrix.py
@@ -31,12 +31,13 @@
"""Run test matrix."""
import argparse
-import jobset
import multiprocessing
import os
-import report_utils
import sys
-from filter_pull_request_tests import filter_tests
+
+import python_utils.jobset as jobset
+import python_utils.report_utils as report_utils
+from python_utils.filter_pull_request_tests import filter_tests
_ROOT = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), '../..'))
os.chdir(_ROOT)
@@ -46,16 +47,16 @@ os.chdir(_ROOT)
_RUNTESTS_TIMEOUT = 4*60*60
# Number of jobs assigned to each run_tests.py instance
-_INNER_JOBS = 2
+_DEFAULT_INNER_JOBS = 2
-def _docker_jobspec(name, runtests_args=[]):
+def _docker_jobspec(name, runtests_args=[], inner_jobs=_DEFAULT_INNER_JOBS):
"""Run a single instance of run_tests.py in a docker container"""
test_job = jobset.JobSpec(
cmdline=['python', 'tools/run_tests/run_tests.py',
'--use_docker',
'-t',
- '-j', str(_INNER_JOBS),
+ '-j', str(inner_jobs),
'-x', 'report_%s.xml' % name,
'--report_suite_name', '%s' % name] + runtests_args,
shortname='run_tests_%s' % name,
@@ -63,15 +64,15 @@ def _docker_jobspec(name, runtests_args=[]):
return test_job
-def _workspace_jobspec(name, runtests_args=[], workspace_name=None):
+def _workspace_jobspec(name, runtests_args=[], workspace_name=None, inner_jobs=_DEFAULT_INNER_JOBS):
"""Run a single instance of run_tests.py in a separate workspace"""
if not workspace_name:
workspace_name = 'workspace_%s' % name
env = {'WORKSPACE_NAME': workspace_name}
test_job = jobset.JobSpec(
- cmdline=['tools/run_tests/run_tests_in_workspace.sh',
+ cmdline=['tools/run_tests/helper_scripts/run_tests_in_workspace.sh',
'-t',
- '-j', str(_INNER_JOBS),
+ '-j', str(inner_jobs),
'-x', '../report_%s.xml' % name,
'--report_suite_name', '%s' % name] + runtests_args,
environ=env,
@@ -82,7 +83,8 @@ def _workspace_jobspec(name, runtests_args=[], workspace_name=None):
def _generate_jobs(languages, configs, platforms,
arch=None, compiler=None,
- labels=[], extra_args=[]):
+ labels=[], extra_args=[],
+ inner_jobs=_DEFAULT_INNER_JOBS):
result = []
for language in languages:
for platform in platforms:
@@ -97,68 +99,75 @@ def _generate_jobs(languages, configs, platforms,
runtests_args += extra_args
if platform == 'linux':
- job = _docker_jobspec(name=name, runtests_args=runtests_args)
+ job = _docker_jobspec(name=name, runtests_args=runtests_args, inner_jobs=inner_jobs)
else:
- job = _workspace_jobspec(name=name, runtests_args=runtests_args)
+ job = _workspace_jobspec(name=name, runtests_args=runtests_args, inner_jobs=inner_jobs)
job.labels = [platform, config, language] + labels
result.append(job)
return result
-def _create_test_jobs(extra_args=[]):
+def _create_test_jobs(extra_args=[], inner_jobs=_DEFAULT_INNER_JOBS):
test_jobs = []
# supported on linux only
test_jobs += _generate_jobs(languages=['sanity', 'php7'],
configs=['dbg', 'opt'],
platforms=['linux'],
labels=['basictests'],
- extra_args=extra_args)
+ extra_args=extra_args,
+ inner_jobs=inner_jobs)
# supported on all platforms.
test_jobs += _generate_jobs(languages=['c', 'csharp', 'node', 'python'],
configs=['dbg', 'opt'],
platforms=['linux', 'macos', 'windows'],
labels=['basictests'],
- extra_args=extra_args)
+ extra_args=extra_args,
+ inner_jobs=inner_jobs)
# supported on linux and mac.
test_jobs += _generate_jobs(languages=['c++', 'ruby', 'php'],
configs=['dbg', 'opt'],
platforms=['linux', 'macos'],
labels=['basictests'],
- extra_args=extra_args)
+ extra_args=extra_args,
+ inner_jobs=inner_jobs)
# supported on mac only.
test_jobs += _generate_jobs(languages=['objc'],
configs=['dbg', 'opt'],
platforms=['macos'],
labels=['basictests'],
- extra_args=extra_args)
+ extra_args=extra_args,
+ inner_jobs=inner_jobs)
# sanitizers
test_jobs += _generate_jobs(languages=['c'],
configs=['msan', 'asan', 'tsan'],
platforms=['linux'],
labels=['sanitizers'],
- extra_args=extra_args)
+ extra_args=extra_args,
+ inner_jobs=inner_jobs)
test_jobs += _generate_jobs(languages=['c++'],
configs=['asan', 'tsan'],
platforms=['linux'],
labels=['sanitizers'],
- extra_args=extra_args)
+ extra_args=extra_args,
+ inner_jobs=inner_jobs)
# libuv tests
test_jobs += _generate_jobs(languages=['c'],
configs=['dbg', 'opt'],
platforms=['linux'],
labels=['libuv'],
- extra_args=extra_args + ['--iomgr_platform=uv'])
+ extra_args=extra_args + ['--iomgr_platform=uv'],
+ inner_jobs=inner_jobs)
return test_jobs
-def _create_portability_test_jobs(extra_args=[]):
+def _create_portability_test_jobs(extra_args=[], inner_jobs=_DEFAULT_INNER_JOBS):
test_jobs = []
# portability C x86
test_jobs += _generate_jobs(languages=['c'],
@@ -167,18 +176,31 @@ def _create_portability_test_jobs(extra_args=[]):
arch='x86',
compiler='default',
labels=['portability'],
- extra_args=extra_args)
+ extra_args=extra_args,
+ inner_jobs=inner_jobs)
# portability C and C++ on x64
for compiler in ['gcc4.4', 'gcc4.6', 'gcc5.3',
'clang3.5', 'clang3.6', 'clang3.7']:
- test_jobs += _generate_jobs(languages=['c', 'c++'],
+ test_jobs += _generate_jobs(languages=['c'],
+ configs=['dbg'],
+ platforms=['linux'],
+ arch='x64',
+ compiler=compiler,
+ labels=['portability'],
+ extra_args=extra_args,
+ inner_jobs=inner_jobs)
+
+ for compiler in ['gcc4.8', 'gcc5.3',
+ 'clang3.5', 'clang3.6', 'clang3.7']:
+ test_jobs += _generate_jobs(languages=['c++'],
configs=['dbg'],
platforms=['linux'],
arch='x64',
compiler=compiler,
labels=['portability'],
- extra_args=extra_args)
+ extra_args=extra_args,
+ inner_jobs=inner_jobs)
# portability C on Windows
for arch in ['x86', 'x64']:
@@ -189,7 +211,8 @@ def _create_portability_test_jobs(extra_args=[]):
arch=arch,
compiler=compiler,
labels=['portability'],
- extra_args=extra_args)
+ extra_args=extra_args,
+ inner_jobs=inner_jobs)
test_jobs += _generate_jobs(languages=['python'],
configs=['dbg'],
@@ -197,7 +220,8 @@ def _create_portability_test_jobs(extra_args=[]):
arch='default',
compiler='python3.4',
labels=['portability'],
- extra_args=extra_args)
+ extra_args=extra_args,
+ inner_jobs=inner_jobs)
test_jobs += _generate_jobs(languages=['csharp'],
configs=['dbg'],
@@ -205,7 +229,8 @@ def _create_portability_test_jobs(extra_args=[]):
arch='default',
compiler='coreclr',
labels=['portability'],
- extra_args=extra_args)
+ extra_args=extra_args,
+ inner_jobs=inner_jobs)
return test_jobs
@@ -218,99 +243,136 @@ def _allowed_labels():
return sorted(all_labels)
-argp = argparse.ArgumentParser(description='Run a matrix of run_tests.py tests.')
-argp.add_argument('-j', '--jobs',
- default=multiprocessing.cpu_count()/_INNER_JOBS,
- type=int,
- help='Number of concurrent run_tests.py instances.')
-argp.add_argument('-f', '--filter',
- choices=_allowed_labels(),
- nargs='+',
- default=[],
- help='Filter targets to run by label with AND semantics.')
-argp.add_argument('--build_only',
- default=False,
- action='store_const',
- const=True,
- help='Pass --build_only flag to run_tests.py instances.')
-argp.add_argument('--force_default_poller', default=False, action='store_const', const=True,
- help='Pass --force_default_poller to run_tests.py instances.')
-argp.add_argument('--dry_run',
- default=False,
- action='store_const',
- const=True,
- help='Only print what would be run.')
-argp.add_argument('--filter_pr_tests',
- default=False,
- action='store_const',
- const=True,
- help='Filters out tests irrelavant to pull request changes.')
-argp.add_argument('--base_branch',
- default='origin/master',
- type=str,
- help='Branch that pull request is requesting to merge into')
-args = argp.parse_args()
-
-extra_args = []
-if args.build_only:
- extra_args.append('--build_only')
-if args.force_default_poller:
- extra_args.append('--force_default_poller')
-
-all_jobs = _create_test_jobs(extra_args=extra_args) + _create_portability_test_jobs(extra_args=extra_args)
-
-jobs = []
-for job in all_jobs:
- if not args.filter or all(filter in job.labels for filter in args.filter):
- jobs.append(job)
-
-if not jobs:
- jobset.message('FAILED', 'No test suites match given criteria.',
- do_newline=True)
- sys.exit(1)
-
-print('IMPORTANT: The changes you are testing need to be locally committed')
-print('because only the committed changes in the current branch will be')
-print('copied to the docker environment or into subworkspaces.')
-
-print
-print 'Will run these tests:'
-for job in jobs:
- if args.dry_run:
- print ' %s: "%s"' % (job.shortname, ' '.join(job.cmdline))
- else:
- print ' %s' % job.shortname
-print
-
-if args.filter_pr_tests:
- print 'IMPORTANT: Test filtering is not active; this is only for testing.'
- relevant_jobs = filter_tests(jobs, args.base_branch)
- # todo(mattkwong): add skipped tests to report.xml
- print
- if len(relevant_jobs) == len(jobs):
- print '(TESTING) No tests will be skipped.'
- else:
- print '(TESTING) These tests will be skipped:'
- for job in list(set(jobs) - set(relevant_jobs)):
- print ' %s' % job.shortname
+def _runs_per_test_type(arg_str):
+ """Auxiliary function to parse the "runs_per_test" flag."""
+ try:
+ n = int(arg_str)
+ if n <= 0: raise ValueError
+ return n
+ except:
+ msg = '\'{}\' is not a positive integer'.format(arg_str)
+ raise argparse.ArgumentTypeError(msg)
+
+
+if __name__ == "__main__":
+ argp = argparse.ArgumentParser(description='Run a matrix of run_tests.py tests.')
+ argp.add_argument('-j', '--jobs',
+ default=multiprocessing.cpu_count()/_DEFAULT_INNER_JOBS,
+ type=int,
+ help='Number of concurrent run_tests.py instances.')
+ argp.add_argument('-f', '--filter',
+ choices=_allowed_labels(),
+ nargs='+',
+ default=[],
+ help='Filter targets to run by label with AND semantics.')
+ argp.add_argument('--exclude',
+ choices=_allowed_labels(),
+ nargs='+',
+ default=[],
+ help='Exclude targets with any of given labels.')
+ argp.add_argument('--build_only',
+ default=False,
+ action='store_const',
+ const=True,
+ help='Pass --build_only flag to run_tests.py instances.')
+ argp.add_argument('--force_default_poller', default=False, action='store_const', const=True,
+ help='Pass --force_default_poller to run_tests.py instances.')
+ argp.add_argument('--dry_run',
+ default=False,
+ action='store_const',
+ const=True,
+ help='Only print what would be run.')
+ argp.add_argument('--filter_pr_tests',
+ default=False,
+ action='store_const',
+ const=True,
+ help='Filters out tests irrelevant to pull request changes.')
+ argp.add_argument('--base_branch',
+ default='origin/master',
+ type=str,
+ help='Branch that pull request is requesting to merge into')
+ argp.add_argument('--inner_jobs',
+ default=_DEFAULT_INNER_JOBS,
+ type=int,
+ help='Number of jobs in each run_tests.py instance')
+ argp.add_argument('-n', '--runs_per_test', default=1, type=_runs_per_test_type,
+ help='How many times to run each tests. >1 runs implies ' +
+ 'omitting passing test from the output & reports.')
+ args = argp.parse_args()
+
+ extra_args = []
+ if args.build_only:
+ extra_args.append('--build_only')
+ if args.force_default_poller:
+ extra_args.append('--force_default_poller')
+ if args.runs_per_test > 1:
+ extra_args.append('-n')
+ extra_args.append('%s' % args.runs_per_test)
+ extra_args.append('--quiet_success')
+
+ all_jobs = _create_test_jobs(extra_args=extra_args, inner_jobs=args.inner_jobs) + \
+ _create_portability_test_jobs(extra_args=extra_args, inner_jobs=args.inner_jobs)
+
+ jobs = []
+ for job in all_jobs:
+ if not args.filter or all(filter in job.labels for filter in args.filter):
+ if not any(exclude_label in job.labels for exclude_label in args.exclude):
+ jobs.append(job)
+
+ if not jobs:
+ jobset.message('FAILED', 'No test suites match given criteria.',
+ do_newline=True)
+ sys.exit(1)
+
+ print('IMPORTANT: The changes you are testing need to be locally committed')
+ print('because only the committed changes in the current branch will be')
+ print('copied to the docker environment or into subworkspaces.')
+
+ skipped_jobs = []
+
+ if args.filter_pr_tests:
+ print('Looking for irrelevant tests to skip...')
+ relevant_jobs = filter_tests(jobs, args.base_branch)
+ if len(relevant_jobs) == len(jobs):
+ print('No tests will be skipped.')
+ else:
+ print('These tests will be skipped:')
+ skipped_jobs = list(set(jobs) - set(relevant_jobs))
+ # Sort by shortnames to make printing of skipped tests consistent
+ skipped_jobs.sort(key=lambda job: job.shortname)
+ for job in list(skipped_jobs):
+ print(' %s' % job.shortname)
+ jobs = relevant_jobs
+
+ print('Will run these tests:')
+ for job in jobs:
+ if args.dry_run:
+ print(' %s: "%s"' % (job.shortname, ' '.join(job.cmdline)))
+ else:
+ print(' %s' % job.shortname)
print
-if args.dry_run:
- print '--dry_run was used, exiting'
- sys.exit(1)
-
-jobset.message('START', 'Running test matrix.', do_newline=True)
-num_failures, resultset = jobset.run(jobs,
- newline_on_success=True,
- travis=True,
- maxjobs=args.jobs)
-report_utils.render_junit_xml_report(resultset, 'report.xml',
- suite_name='aggregate_tests')
-
-if num_failures == 0:
- jobset.message('SUCCESS', 'All run_tests.py instance finished successfully.',
- do_newline=True)
-else:
- jobset.message('FAILED', 'Some run_tests.py instance have failed.',
- do_newline=True)
- sys.exit(1)
+ if args.dry_run:
+ print('--dry_run was used, exiting')
+ sys.exit(1)
+
+ jobset.message('START', 'Running test matrix.', do_newline=True)
+ num_failures, resultset = jobset.run(jobs,
+ newline_on_success=True,
+ travis=True,
+ maxjobs=args.jobs)
+ # Merge skipped tests into results to show skipped tests on report.xml
+ if skipped_jobs:
+ skipped_results = jobset.run(skipped_jobs,
+ skip_jobs=True)
+ resultset.update(skipped_results)
+ report_utils.render_junit_xml_report(resultset, 'report.xml',
+ suite_name='aggregate_tests')
+
+ if num_failures == 0:
+ jobset.message('SUCCESS', 'All run_tests.py instance finished successfully.',
+ do_newline=True)
+ else:
+ jobset.message('FAILED', 'Some run_tests.py instance have failed.',
+ do_newline=True)
+ sys.exit(1)