blob: 25fbe8110f0848e82893a1e82ab67e8bf5a93595 [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']:
184 test_jobs += _generate_jobs(languages=['c', 'c++'],
185 configs=['dbg'],
186 platforms=['linux'],
187 arch='x64',
188 compiler=compiler,
Jan Tattermusch6d7c6ef2016-09-22 13:40:48 +0200189 labels=['portability'],
Matt Kwongfef98962016-10-27 10:45:47 -0700190 extra_args=extra_args,
191 inner_jobs=inner_jobs)
murgatroid991687cab2016-10-11 11:42:01 -0700192
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200193 # portability C on Windows
194 for arch in ['x86', 'x64']:
195 for compiler in ['vs2013', 'vs2015']:
196 test_jobs += _generate_jobs(languages=['c'],
197 configs=['dbg'],
198 platforms=['windows'],
199 arch=arch,
200 compiler=compiler,
Jan Tattermusch6d7c6ef2016-09-22 13:40:48 +0200201 labels=['portability'],
Matt Kwongfef98962016-10-27 10:45:47 -0700202 extra_args=extra_args,
203 inner_jobs=inner_jobs)
murgatroid991687cab2016-10-11 11:42:01 -0700204
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200205 test_jobs += _generate_jobs(languages=['python'],
206 configs=['dbg'],
207 platforms=['linux'],
208 arch='default',
209 compiler='python3.4',
Jan Tattermusch6d7c6ef2016-09-22 13:40:48 +0200210 labels=['portability'],
Matt Kwongfef98962016-10-27 10:45:47 -0700211 extra_args=extra_args,
212 inner_jobs=inner_jobs)
murgatroid991687cab2016-10-11 11:42:01 -0700213
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200214 test_jobs += _generate_jobs(languages=['csharp'],
215 configs=['dbg'],
216 platforms=['linux'],
217 arch='default',
218 compiler='coreclr',
Jan Tattermusch6d7c6ef2016-09-22 13:40:48 +0200219 labels=['portability'],
Matt Kwongfef98962016-10-27 10:45:47 -0700220 extra_args=extra_args,
221 inner_jobs=inner_jobs)
murgatroid991687cab2016-10-11 11:42:01 -0700222 return test_jobs
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200223
224
Jan Tattermusch6d7c6ef2016-09-22 13:40:48 +0200225def _allowed_labels():
226 """Returns a list of existing job labels."""
227 all_labels = set()
228 for job in _create_test_jobs() + _create_portability_test_jobs():
229 for label in job.labels:
230 all_labels.add(label)
231 return sorted(all_labels)
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200232
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200233
Matt Kwong7e9bd6c2016-10-24 17:30:25 -0700234if __name__ == "__main__":
235 argp = argparse.ArgumentParser(description='Run a matrix of run_tests.py tests.')
236 argp.add_argument('-j', '--jobs',
237 default=multiprocessing.cpu_count()/_DEFAULT_INNER_JOBS,
238 type=int,
239 help='Number of concurrent run_tests.py instances.')
240 argp.add_argument('-f', '--filter',
241 choices=_allowed_labels(),
242 nargs='+',
243 default=[],
244 help='Filter targets to run by label with AND semantics.')
245 argp.add_argument('--build_only',
246 default=False,
247 action='store_const',
248 const=True,
249 help='Pass --build_only flag to run_tests.py instances.')
250 argp.add_argument('--force_default_poller', default=False, action='store_const', const=True,
251 help='Pass --force_default_poller to run_tests.py instances.')
252 argp.add_argument('--dry_run',
253 default=False,
254 action='store_const',
255 const=True,
256 help='Only print what would be run.')
257 argp.add_argument('--filter_pr_tests',
258 default=False,
259 action='store_const',
260 const=True,
261 help='Filters out tests irrelavant to pull request changes.')
262 argp.add_argument('--base_branch',
263 default='origin/master',
264 type=str,
265 help='Branch that pull request is requesting to merge into')
266 argp.add_argument('--inner_jobs',
267 default=_DEFAULT_INNER_JOBS,
268 type=int,
269 help='Number of jobs in each run_tests.py instance')
270 args = argp.parse_args()
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200271
Matt Kwong7e9bd6c2016-10-24 17:30:25 -0700272 extra_args = []
273 if args.build_only:
274 extra_args.append('--build_only')
275 if args.force_default_poller:
276 extra_args.append('--force_default_poller')
Matt Kwongfef98962016-10-27 10:45:47 -0700277
Matt Kwong7e9bd6c2016-10-24 17:30:25 -0700278 all_jobs = _create_test_jobs(extra_args=extra_args, inner_jobs=args.inner_jobs) + \
279 _create_portability_test_jobs(extra_args=extra_args, inner_jobs=args.inner_jobs)
Jan Tattermusch6d7c6ef2016-09-22 13:40:48 +0200280
Matt Kwong7e9bd6c2016-10-24 17:30:25 -0700281 jobs = []
282 for job in all_jobs:
283 if not args.filter or all(filter in job.labels for filter in args.filter):
284 jobs.append(job)
Jan Tattermusch6d7c6ef2016-09-22 13:40:48 +0200285
Matt Kwong7e9bd6c2016-10-24 17:30:25 -0700286 if not jobs:
287 jobset.message('FAILED', 'No test suites match given criteria.',
288 do_newline=True)
289 sys.exit(1)
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200290
Matt Kwong7e9bd6c2016-10-24 17:30:25 -0700291 print('IMPORTANT: The changes you are testing need to be locally committed')
292 print('because only the committed changes in the current branch will be')
293 print('copied to the docker environment or into subworkspaces.')
murgatroid991687cab2016-10-11 11:42:01 -0700294
Matt Kwong7e9bd6c2016-10-24 17:30:25 -0700295 skipped_jobs = []
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200296
Matt Kwong7e9bd6c2016-10-24 17:30:25 -0700297 if args.filter_pr_tests:
298 print('Looking for irrelevant tests to skip...')
299 relevant_jobs = filter_tests(jobs, args.base_branch)
300 if len(relevant_jobs) == len(jobs):
301 print('No tests will be skipped.')
302 else:
303 print('These tests will be skipped:')
304 skipped_jobs = [job for job in jobs if job not in relevant_jobs]
305 for job in list(skipped_jobs):
306 print(' %s' % job.shortname)
307 jobs = relevant_jobs
308
309 print('Will run these tests:')
310 for job in jobs:
311 if args.dry_run:
312 print(' %s: "%s"' % (job.shortname, ' '.join(job.cmdline)))
313 else:
314 print(' %s' % job.shortname)
Matt Kwong5c691c62016-10-20 17:11:18 -0700315 print
316
Jan Tattermusch7b9c21a2016-09-22 14:44:27 +0200317 if args.dry_run:
Matt Kwong7e9bd6c2016-10-24 17:30:25 -0700318 print('--dry_run was used, exiting')
319 sys.exit(1)
320
321 jobset.message('START', 'Running test matrix.', do_newline=True)
322 num_failures, resultset = jobset.run(jobs,
323 newline_on_success=True,
324 travis=True,
325 maxjobs=args.jobs)
326 # Merge skipped tests into results to show skipped tests on report.xml
327 if skipped_jobs:
328 skipped_results = jobset.run(skipped_jobs,
329 skip_jobs=True)
330 resultset.update(skipped_results)
331 report_utils.render_junit_xml_report(resultset, 'report.xml',
332 suite_name='aggregate_tests')
333
334 if num_failures == 0:
335 jobset.message('SUCCESS', 'All run_tests.py instance finished successfully.',
336 do_newline=True)
Jan Tattermusch7b9c21a2016-09-22 14:44:27 +0200337 else:
Matt Kwong7e9bd6c2016-10-24 17:30:25 -0700338 jobset.message('FAILED', 'Some run_tests.py instance have failed.',
339 do_newline=True)
340 sys.exit(1)