blob: d954aad40373dba8291d1e91624606be4aee08ba [file] [log] [blame]
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +02001#!/usr/bin/env python2.7
2# Copyright 2015, Google Inc.
3# All rights reserved.
4#
5# Redistribution and use in source and binary forms, with or without
6# modification, are permitted provided that the following conditions are
7# met:
8#
9# * Redistributions of source code must retain the above copyright
10# notice, this list of conditions and the following disclaimer.
11# * Redistributions in binary form must reproduce the above
12# copyright notice, this list of conditions and the following disclaimer
13# in the documentation and/or other materials provided with the
14# distribution.
15# * Neither the name of Google Inc. nor the names of its
16# contributors may be used to endorse or promote products derived from
17# this software without specific prior written permission.
18#
19# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31"""Run test matrix."""
32
33import argparse
34import jobset
Jan Tattermuscha1906d52016-09-19 18:37:17 +020035import multiprocessing
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +020036import os
37import report_utils
38import sys
Matt Kwonge9163f02016-10-05 11:42:55 -070039from filter_pull_request_tests import filter_tests
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +020040
41_ROOT = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), '../..'))
42os.chdir(_ROOT)
43
Jan Tattermusch060eb872016-09-20 16:06:13 +020044# Set the timeout high to allow enough time for sanitizers and pre-building
45# clang docker.
Ken Payson97e69202016-10-17 09:11:49 -070046_RUNTESTS_TIMEOUT = 4*60*60
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +020047
Jan Tattermuscha1906d52016-09-19 18:37:17 +020048# Number of jobs assigned to each run_tests.py instance
Matt Kwongfef98962016-10-27 10:45:47 -070049_DEFAULT_INNER_JOBS = 2
Jan Tattermuscha1906d52016-09-19 18:37:17 +020050
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +020051
Matt Kwongfef98962016-10-27 10:45:47 -070052def _docker_jobspec(name, runtests_args=[], inner_jobs=_DEFAULT_INNER_JOBS):
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +020053 """Run a single instance of run_tests.py in a docker container"""
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +020054 test_job = jobset.JobSpec(
55 cmdline=['python', 'tools/run_tests/run_tests.py',
56 '--use_docker',
57 '-t',
Matt Kwongfef98962016-10-27 10:45:47 -070058 '-j', str(inner_jobs),
Jan Tattermuschcfcc0752016-10-09 17:02:34 +020059 '-x', 'report_%s.xml' % name,
60 '--report_suite_name', '%s' % name] + runtests_args,
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +020061 shortname='run_tests_%s' % name,
62 timeout_seconds=_RUNTESTS_TIMEOUT)
63 return test_job
64
65
Matt Kwongfef98962016-10-27 10:45:47 -070066def _workspace_jobspec(name, runtests_args=[], workspace_name=None, inner_jobs=_DEFAULT_INNER_JOBS):
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +020067 """Run a single instance of run_tests.py in a separate workspace"""
Jan Tattermuscha1906d52016-09-19 18:37:17 +020068 if not workspace_name:
69 workspace_name = 'workspace_%s' % name
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +020070 env = {'WORKSPACE_NAME': workspace_name}
71 test_job = jobset.JobSpec(
72 cmdline=['tools/run_tests/run_tests_in_workspace.sh',
73 '-t',
Matt Kwongfef98962016-10-27 10:45:47 -070074 '-j', str(inner_jobs),
Jan Tattermuschcfcc0752016-10-09 17:02:34 +020075 '-x', '../report_%s.xml' % name,
76 '--report_suite_name', '%s' % name] + runtests_args,
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +020077 environ=env,
78 shortname='run_tests_%s' % name,
79 timeout_seconds=_RUNTESTS_TIMEOUT)
80 return test_job
81
82
83def _generate_jobs(languages, configs, platforms,
84 arch=None, compiler=None,
Matt Kwongfef98962016-10-27 10:45:47 -070085 labels=[], extra_args=[],
86 inner_jobs=_DEFAULT_INNER_JOBS):
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +020087 result = []
88 for language in languages:
89 for platform in platforms:
90 for config in configs:
91 name = '%s_%s_%s' % (language, platform, config)
92 runtests_args = ['-l', language,
93 '-c', config]
94 if arch or compiler:
95 name += '_%s_%s' % (arch, compiler)
96 runtests_args += ['--arch', arch,
97 '--compiler', compiler]
98
Jan Tattermusch6d7c6ef2016-09-22 13:40:48 +020099 runtests_args += extra_args
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200100 if platform == 'linux':
Matt Kwongfef98962016-10-27 10:45:47 -0700101 job = _docker_jobspec(name=name, runtests_args=runtests_args, inner_jobs=inner_jobs)
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200102 else:
Matt Kwongfef98962016-10-27 10:45:47 -0700103 job = _workspace_jobspec(name=name, runtests_args=runtests_args, inner_jobs=inner_jobs)
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200104
105 job.labels = [platform, config, language] + labels
106 result.append(job)
107 return result
108
109
Matt Kwongfef98962016-10-27 10:45:47 -0700110def _create_test_jobs(extra_args=[], inner_jobs=_DEFAULT_INNER_JOBS):
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200111 test_jobs = []
112 # supported on linux only
113 test_jobs += _generate_jobs(languages=['sanity', 'php7'],
114 configs=['dbg', 'opt'],
115 platforms=['linux'],
Jan Tattermusch6d7c6ef2016-09-22 13:40:48 +0200116 labels=['basictests'],
Matt Kwongfef98962016-10-27 10:45:47 -0700117 extra_args=extra_args,
118 inner_jobs=inner_jobs)
murgatroid991687cab2016-10-11 11:42:01 -0700119
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200120 # supported on all platforms.
121 test_jobs += _generate_jobs(languages=['c', 'csharp', 'node', 'python'],
Jan Tattermusch6d7c6ef2016-09-22 13:40:48 +0200122 configs=['dbg', 'opt'],
123 platforms=['linux', 'macos', 'windows'],
124 labels=['basictests'],
Matt Kwongfef98962016-10-27 10:45:47 -0700125 extra_args=extra_args,
126 inner_jobs=inner_jobs)
murgatroid991687cab2016-10-11 11:42:01 -0700127
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200128 # supported on linux and mac.
129 test_jobs += _generate_jobs(languages=['c++', 'ruby', 'php'],
Jan Tattermusch6d7c6ef2016-09-22 13:40:48 +0200130 configs=['dbg', 'opt'],
131 platforms=['linux', 'macos'],
132 labels=['basictests'],
Matt Kwongfef98962016-10-27 10:45:47 -0700133 extra_args=extra_args,
134 inner_jobs=inner_jobs)
murgatroid991687cab2016-10-11 11:42:01 -0700135
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200136 # supported on mac only.
137 test_jobs += _generate_jobs(languages=['objc'],
138 configs=['dbg', 'opt'],
139 platforms=['macos'],
Jan Tattermusch6d7c6ef2016-09-22 13:40:48 +0200140 labels=['basictests'],
Matt Kwongfef98962016-10-27 10:45:47 -0700141 extra_args=extra_args,
142 inner_jobs=inner_jobs)
murgatroid991687cab2016-10-11 11:42:01 -0700143
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200144 # sanitizers
145 test_jobs += _generate_jobs(languages=['c'],
146 configs=['msan', 'asan', 'tsan'],
147 platforms=['linux'],
Jan Tattermusch6d7c6ef2016-09-22 13:40:48 +0200148 labels=['sanitizers'],
Matt Kwongfef98962016-10-27 10:45:47 -0700149 extra_args=extra_args,
150 inner_jobs=inner_jobs)
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200151 test_jobs += _generate_jobs(languages=['c++'],
152 configs=['asan', 'tsan'],
153 platforms=['linux'],
Jan Tattermusch6d7c6ef2016-09-22 13:40:48 +0200154 labels=['sanitizers'],
Matt Kwongfef98962016-10-27 10:45:47 -0700155 extra_args=extra_args,
156 inner_jobs=inner_jobs)
murgatroid991687cab2016-10-11 11:42:01 -0700157
158 # libuv tests
159 test_jobs += _generate_jobs(languages=['c'],
160 configs=['dbg', 'opt'],
161 platforms=['linux'],
162 labels=['libuv'],
Matt Kwongfef98962016-10-27 10:45:47 -0700163 extra_args=extra_args + ['--iomgr_platform=uv'],
164 inner_jobs=inner_jobs)
murgatroid991687cab2016-10-11 11:42:01 -0700165
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200166 return test_jobs
167
murgatroid991687cab2016-10-11 11:42:01 -0700168
Matt Kwongfef98962016-10-27 10:45:47 -0700169def _create_portability_test_jobs(extra_args=[], inner_jobs=_DEFAULT_INNER_JOBS):
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200170 test_jobs = []
171 # portability C x86
172 test_jobs += _generate_jobs(languages=['c'],
173 configs=['dbg'],
174 platforms=['linux'],
175 arch='x86',
176 compiler='default',
Jan Tattermusch6d7c6ef2016-09-22 13:40:48 +0200177 labels=['portability'],
Matt Kwongfef98962016-10-27 10:45:47 -0700178 extra_args=extra_args,
179 inner_jobs=inner_jobs)
murgatroid991687cab2016-10-11 11:42:01 -0700180
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200181 # portability C and C++ on x64
182 for compiler in ['gcc4.4', 'gcc4.6', 'gcc5.3',
183 'clang3.5', 'clang3.6', 'clang3.7']:
Matt Kwonge3beac92016-11-01 12:53:04 -0700184 test_jobs += _generate_jobs(languages=['c'],
185 configs=['dbg'],
186 platforms=['linux'],
187 arch='x64',
188 compiler=compiler,
189 labels=['portability'],
190 extra_args=extra_args,
191 inner_jobs=inner_jobs)
Jan Tattermusch8613e472016-11-22 11:15:53 +0100192
Matt Kwonge3beac92016-11-01 12:53:04 -0700193 for compiler in ['gcc4.8', 'gcc5.3',
194 'clang3.5', 'clang3.6', 'clang3.7']:
195 test_jobs += _generate_jobs(languages=['c++'],
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200196 configs=['dbg'],
197 platforms=['linux'],
198 arch='x64',
199 compiler=compiler,
Jan Tattermusch6d7c6ef2016-09-22 13:40:48 +0200200 labels=['portability'],
Matt Kwongfef98962016-10-27 10:45:47 -0700201 extra_args=extra_args,
202 inner_jobs=inner_jobs)
murgatroid991687cab2016-10-11 11:42:01 -0700203
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200204 # portability C on Windows
205 for arch in ['x86', 'x64']:
206 for compiler in ['vs2013', 'vs2015']:
207 test_jobs += _generate_jobs(languages=['c'],
208 configs=['dbg'],
209 platforms=['windows'],
210 arch=arch,
211 compiler=compiler,
Jan Tattermusch6d7c6ef2016-09-22 13:40:48 +0200212 labels=['portability'],
Matt Kwongfef98962016-10-27 10:45:47 -0700213 extra_args=extra_args,
214 inner_jobs=inner_jobs)
murgatroid991687cab2016-10-11 11:42:01 -0700215
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200216 test_jobs += _generate_jobs(languages=['python'],
217 configs=['dbg'],
218 platforms=['linux'],
219 arch='default',
220 compiler='python3.4',
Jan Tattermusch6d7c6ef2016-09-22 13:40:48 +0200221 labels=['portability'],
Matt Kwongfef98962016-10-27 10:45:47 -0700222 extra_args=extra_args,
223 inner_jobs=inner_jobs)
murgatroid991687cab2016-10-11 11:42:01 -0700224
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200225 test_jobs += _generate_jobs(languages=['csharp'],
226 configs=['dbg'],
227 platforms=['linux'],
228 arch='default',
229 compiler='coreclr',
Jan Tattermusch6d7c6ef2016-09-22 13:40:48 +0200230 labels=['portability'],
Matt Kwongfef98962016-10-27 10:45:47 -0700231 extra_args=extra_args,
232 inner_jobs=inner_jobs)
murgatroid991687cab2016-10-11 11:42:01 -0700233 return test_jobs
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200234
235
Jan Tattermusch6d7c6ef2016-09-22 13:40:48 +0200236def _allowed_labels():
237 """Returns a list of existing job labels."""
238 all_labels = set()
239 for job in _create_test_jobs() + _create_portability_test_jobs():
240 for label in job.labels:
241 all_labels.add(label)
242 return sorted(all_labels)
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200243
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200244
Jan Tattermusch68e27bf2016-12-16 14:09:03 +0100245def _runs_per_test_type(arg_str):
246 """Auxiliary function to parse the "runs_per_test" flag."""
247 try:
248 n = int(arg_str)
249 if n <= 0: raise ValueError
250 return n
251 except:
252 msg = '\'{}\' is not a positive integer'.format(arg_str)
253 raise argparse.ArgumentTypeError(msg)
254
255
Matt Kwong7e9bd6c2016-10-24 17:30:25 -0700256if __name__ == "__main__":
257 argp = argparse.ArgumentParser(description='Run a matrix of run_tests.py tests.')
258 argp.add_argument('-j', '--jobs',
259 default=multiprocessing.cpu_count()/_DEFAULT_INNER_JOBS,
260 type=int,
261 help='Number of concurrent run_tests.py instances.')
262 argp.add_argument('-f', '--filter',
263 choices=_allowed_labels(),
264 nargs='+',
265 default=[],
266 help='Filter targets to run by label with AND semantics.')
267 argp.add_argument('--build_only',
268 default=False,
269 action='store_const',
270 const=True,
271 help='Pass --build_only flag to run_tests.py instances.')
272 argp.add_argument('--force_default_poller', default=False, action='store_const', const=True,
273 help='Pass --force_default_poller to run_tests.py instances.')
274 argp.add_argument('--dry_run',
275 default=False,
276 action='store_const',
277 const=True,
278 help='Only print what would be run.')
279 argp.add_argument('--filter_pr_tests',
280 default=False,
281 action='store_const',
282 const=True,
Jan Tattermusch68e27bf2016-12-16 14:09:03 +0100283 help='Filters out tests irrelevant to pull request changes.')
Matt Kwong7e9bd6c2016-10-24 17:30:25 -0700284 argp.add_argument('--base_branch',
285 default='origin/master',
286 type=str,
287 help='Branch that pull request is requesting to merge into')
288 argp.add_argument('--inner_jobs',
289 default=_DEFAULT_INNER_JOBS,
290 type=int,
291 help='Number of jobs in each run_tests.py instance')
Jan Tattermusch68e27bf2016-12-16 14:09:03 +0100292 argp.add_argument('-n', '--runs_per_test', default=1, type=_runs_per_test_type,
293 help='How many times to run each tests. >1 runs implies ' +
294 'omitting passing test from the output & reports.')
Matt Kwong7e9bd6c2016-10-24 17:30:25 -0700295 args = argp.parse_args()
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200296
Matt Kwong7e9bd6c2016-10-24 17:30:25 -0700297 extra_args = []
298 if args.build_only:
299 extra_args.append('--build_only')
300 if args.force_default_poller:
301 extra_args.append('--force_default_poller')
Jan Tattermusch68e27bf2016-12-16 14:09:03 +0100302 if args.runs_per_test > 1:
303 extra_args.append('-n')
304 extra_args.append('%s' % args.runs_per_test)
305 extra_args.append('--quiet_success')
Matt Kwongfef98962016-10-27 10:45:47 -0700306
Matt Kwong7e9bd6c2016-10-24 17:30:25 -0700307 all_jobs = _create_test_jobs(extra_args=extra_args, inner_jobs=args.inner_jobs) + \
308 _create_portability_test_jobs(extra_args=extra_args, inner_jobs=args.inner_jobs)
Jan Tattermusch6d7c6ef2016-09-22 13:40:48 +0200309
Matt Kwong7e9bd6c2016-10-24 17:30:25 -0700310 jobs = []
311 for job in all_jobs:
312 if not args.filter or all(filter in job.labels for filter in args.filter):
313 jobs.append(job)
Jan Tattermusch6d7c6ef2016-09-22 13:40:48 +0200314
Matt Kwong7e9bd6c2016-10-24 17:30:25 -0700315 if not jobs:
316 jobset.message('FAILED', 'No test suites match given criteria.',
317 do_newline=True)
318 sys.exit(1)
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200319
Matt Kwong7e9bd6c2016-10-24 17:30:25 -0700320 print('IMPORTANT: The changes you are testing need to be locally committed')
321 print('because only the committed changes in the current branch will be')
322 print('copied to the docker environment or into subworkspaces.')
murgatroid991687cab2016-10-11 11:42:01 -0700323
Matt Kwong7e9bd6c2016-10-24 17:30:25 -0700324 skipped_jobs = []
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200325
Matt Kwong7e9bd6c2016-10-24 17:30:25 -0700326 if args.filter_pr_tests:
327 print('Looking for irrelevant tests to skip...')
328 relevant_jobs = filter_tests(jobs, args.base_branch)
329 if len(relevant_jobs) == len(jobs):
330 print('No tests will be skipped.')
331 else:
332 print('These tests will be skipped:')
Matt Kwongaa6c94c2016-11-09 15:53:23 -0800333 skipped_jobs = list(set(jobs) - set(relevant_jobs))
334 # Sort by shortnames to make printing of skipped tests consistent
335 skipped_jobs.sort(key=lambda job: job.shortname)
Matt Kwong7e9bd6c2016-10-24 17:30:25 -0700336 for job in list(skipped_jobs):
337 print(' %s' % job.shortname)
338 jobs = relevant_jobs
339
340 print('Will run these tests:')
341 for job in jobs:
342 if args.dry_run:
343 print(' %s: "%s"' % (job.shortname, ' '.join(job.cmdline)))
344 else:
345 print(' %s' % job.shortname)
Matt Kwong5c691c62016-10-20 17:11:18 -0700346 print
347
Jan Tattermusch7b9c21a2016-09-22 14:44:27 +0200348 if args.dry_run:
Matt Kwong7e9bd6c2016-10-24 17:30:25 -0700349 print('--dry_run was used, exiting')
350 sys.exit(1)
351
352 jobset.message('START', 'Running test matrix.', do_newline=True)
353 num_failures, resultset = jobset.run(jobs,
354 newline_on_success=True,
355 travis=True,
356 maxjobs=args.jobs)
357 # Merge skipped tests into results to show skipped tests on report.xml
358 if skipped_jobs:
359 skipped_results = jobset.run(skipped_jobs,
360 skip_jobs=True)
361 resultset.update(skipped_results)
362 report_utils.render_junit_xml_report(resultset, 'report.xml',
363 suite_name='aggregate_tests')
364
365 if num_failures == 0:
366 jobset.message('SUCCESS', 'All run_tests.py instance finished successfully.',
367 do_newline=True)
Jan Tattermusch7b9c21a2016-09-22 14:44:27 +0200368 else:
Matt Kwong7e9bd6c2016-10-24 17:30:25 -0700369 jobset.message('FAILED', 'Some run_tests.py instance have failed.',
370 do_newline=True)
371 sys.exit(1)