blob: 154b4f1ba523b742d0bd2144057db0351701b3e7 [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
Yuchen Zengfdae4bd2016-11-07 17:46:16 -080052def _docker_jobspec(name, runtests_args=[], runtests_envs={},
53 inner_jobs=_DEFAULT_INNER_JOBS):
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +020054 """Run a single instance of run_tests.py in a docker container"""
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +020055 test_job = jobset.JobSpec(
56 cmdline=['python', 'tools/run_tests/run_tests.py',
57 '--use_docker',
58 '-t',
Matt Kwongfef98962016-10-27 10:45:47 -070059 '-j', str(inner_jobs),
Jan Tattermuschcfcc0752016-10-09 17:02:34 +020060 '-x', 'report_%s.xml' % name,
61 '--report_suite_name', '%s' % name] + runtests_args,
Yuchen Zengfdae4bd2016-11-07 17:46:16 -080062 environ=runtests_envs,
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +020063 shortname='run_tests_%s' % name,
64 timeout_seconds=_RUNTESTS_TIMEOUT)
65 return test_job
66
67
Yuchen Zengfdae4bd2016-11-07 17:46:16 -080068def _workspace_jobspec(name, runtests_args=[], workspace_name=None,
69 runtests_envs={}, inner_jobs=_DEFAULT_INNER_JOBS):
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +020070 """Run a single instance of run_tests.py in a separate workspace"""
Jan Tattermuscha1906d52016-09-19 18:37:17 +020071 if not workspace_name:
72 workspace_name = 'workspace_%s' % name
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +020073 env = {'WORKSPACE_NAME': workspace_name}
Yuchen Zengfdae4bd2016-11-07 17:46:16 -080074 env.update(runtests_envs)
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +020075 test_job = jobset.JobSpec(
76 cmdline=['tools/run_tests/run_tests_in_workspace.sh',
77 '-t',
Matt Kwongfef98962016-10-27 10:45:47 -070078 '-j', str(inner_jobs),
Jan Tattermuschcfcc0752016-10-09 17:02:34 +020079 '-x', '../report_%s.xml' % name,
80 '--report_suite_name', '%s' % name] + runtests_args,
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +020081 environ=env,
82 shortname='run_tests_%s' % name,
83 timeout_seconds=_RUNTESTS_TIMEOUT)
84 return test_job
85
86
87def _generate_jobs(languages, configs, platforms,
88 arch=None, compiler=None,
Yuchen Zengfdae4bd2016-11-07 17:46:16 -080089 labels=[], extra_args=[], extra_envs={},
Matt Kwongfef98962016-10-27 10:45:47 -070090 inner_jobs=_DEFAULT_INNER_JOBS):
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +020091 result = []
92 for language in languages:
93 for platform in platforms:
94 for config in configs:
95 name = '%s_%s_%s' % (language, platform, config)
96 runtests_args = ['-l', language,
97 '-c', config]
98 if arch or compiler:
99 name += '_%s_%s' % (arch, compiler)
100 runtests_args += ['--arch', arch,
101 '--compiler', compiler]
Yuchen Zengfdae4bd2016-11-07 17:46:16 -0800102 for extra_env in extra_envs:
Yuchen Zeng87b59102016-11-08 10:50:12 -0800103 name += '_%s_%s' % (extra_env, extra_envs[extra_env])
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200104
Jan Tattermusch6d7c6ef2016-09-22 13:40:48 +0200105 runtests_args += extra_args
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200106 if platform == 'linux':
Yuchen Zengfdae4bd2016-11-07 17:46:16 -0800107 job = _docker_jobspec(name=name, runtests_args=runtests_args,
108 runtests_envs=extra_envs, inner_jobs=inner_jobs)
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200109 else:
Yuchen Zengfdae4bd2016-11-07 17:46:16 -0800110 job = _workspace_jobspec(name=name, runtests_args=runtests_args,
111 runtests_envs=extra_envs, inner_jobs=inner_jobs)
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200112
113 job.labels = [platform, config, language] + labels
114 result.append(job)
115 return result
116
117
Matt Kwongfef98962016-10-27 10:45:47 -0700118def _create_test_jobs(extra_args=[], inner_jobs=_DEFAULT_INNER_JOBS):
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200119 test_jobs = []
120 # supported on linux only
121 test_jobs += _generate_jobs(languages=['sanity', 'php7'],
122 configs=['dbg', 'opt'],
123 platforms=['linux'],
Jan Tattermusch6d7c6ef2016-09-22 13:40:48 +0200124 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 all platforms.
129 test_jobs += _generate_jobs(languages=['c', 'csharp', 'node', 'python'],
Jan Tattermusch6d7c6ef2016-09-22 13:40:48 +0200130 configs=['dbg', 'opt'],
131 platforms=['linux', 'macos', 'windows'],
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 linux and mac.
137 test_jobs += _generate_jobs(languages=['c++', 'ruby', 'php'],
Jan Tattermusch6d7c6ef2016-09-22 13:40:48 +0200138 configs=['dbg', 'opt'],
139 platforms=['linux', 'macos'],
140 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 # supported on mac only.
145 test_jobs += _generate_jobs(languages=['objc'],
146 configs=['dbg', 'opt'],
147 platforms=['macos'],
Jan Tattermusch6d7c6ef2016-09-22 13:40:48 +0200148 labels=['basictests'],
Matt Kwongfef98962016-10-27 10:45:47 -0700149 extra_args=extra_args,
150 inner_jobs=inner_jobs)
murgatroid991687cab2016-10-11 11:42:01 -0700151
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200152 # sanitizers
153 test_jobs += _generate_jobs(languages=['c'],
154 configs=['msan', 'asan', 'tsan'],
155 platforms=['linux'],
Jan Tattermusch6d7c6ef2016-09-22 13:40:48 +0200156 labels=['sanitizers'],
Matt Kwongfef98962016-10-27 10:45:47 -0700157 extra_args=extra_args,
158 inner_jobs=inner_jobs)
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200159 test_jobs += _generate_jobs(languages=['c++'],
160 configs=['asan', 'tsan'],
161 platforms=['linux'],
Jan Tattermusch6d7c6ef2016-09-22 13:40:48 +0200162 labels=['sanitizers'],
Matt Kwongfef98962016-10-27 10:45:47 -0700163 extra_args=extra_args,
164 inner_jobs=inner_jobs)
murgatroid991687cab2016-10-11 11:42:01 -0700165
166 # libuv tests
167 test_jobs += _generate_jobs(languages=['c'],
168 configs=['dbg', 'opt'],
169 platforms=['linux'],
170 labels=['libuv'],
Matt Kwongfef98962016-10-27 10:45:47 -0700171 extra_args=extra_args + ['--iomgr_platform=uv'],
172 inner_jobs=inner_jobs)
murgatroid991687cab2016-10-11 11:42:01 -0700173
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200174 return test_jobs
175
murgatroid991687cab2016-10-11 11:42:01 -0700176
Matt Kwongfef98962016-10-27 10:45:47 -0700177def _create_portability_test_jobs(extra_args=[], inner_jobs=_DEFAULT_INNER_JOBS):
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200178 test_jobs = []
179 # portability C x86
180 test_jobs += _generate_jobs(languages=['c'],
181 configs=['dbg'],
182 platforms=['linux'],
183 arch='x86',
184 compiler='default',
Jan Tattermusch6d7c6ef2016-09-22 13:40:48 +0200185 labels=['portability'],
Matt Kwongfef98962016-10-27 10:45:47 -0700186 extra_args=extra_args,
187 inner_jobs=inner_jobs)
murgatroid991687cab2016-10-11 11:42:01 -0700188
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200189 # portability C and C++ on x64
190 for compiler in ['gcc4.4', 'gcc4.6', 'gcc5.3',
191 'clang3.5', 'clang3.6', 'clang3.7']:
Matt Kwonge3beac92016-11-01 12:53:04 -0700192 test_jobs += _generate_jobs(languages=['c'],
193 configs=['dbg'],
194 platforms=['linux'],
195 arch='x64',
196 compiler=compiler,
197 labels=['portability'],
198 extra_args=extra_args,
199 inner_jobs=inner_jobs)
200 for compiler in ['gcc4.8', 'gcc5.3',
201 'clang3.5', 'clang3.6', 'clang3.7']:
202 test_jobs += _generate_jobs(languages=['c++'],
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200203 configs=['dbg'],
204 platforms=['linux'],
205 arch='x64',
206 compiler=compiler,
Jan Tattermusch6d7c6ef2016-09-22 13:40:48 +0200207 labels=['portability'],
Matt Kwongfef98962016-10-27 10:45:47 -0700208 extra_args=extra_args,
209 inner_jobs=inner_jobs)
murgatroid991687cab2016-10-11 11:42:01 -0700210
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200211 # portability C on Windows
212 for arch in ['x86', 'x64']:
213 for compiler in ['vs2013', 'vs2015']:
214 test_jobs += _generate_jobs(languages=['c'],
215 configs=['dbg'],
216 platforms=['windows'],
217 arch=arch,
218 compiler=compiler,
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
Yuchen Zeng87b59102016-11-08 10:50:12 -0800223 # C and C++ with the native DNS resolver on Linux
Yuchen Zengfdae4bd2016-11-07 17:46:16 -0800224 test_jobs += _generate_jobs(languages=['c', 'c++'],
Yuchen Zeng87b59102016-11-08 10:50:12 -0800225 configs=['dbg'], platforms=['linux'],
226 labels=['portability'],
227 extra_args=extra_args,
228 extra_envs={'GRPC_DNS_RESOLVER': 'native'})
229
230 # C with the native DNS resolver on Windonws
231 test_jobs += _generate_jobs(languages=['c'],
232 configs=['dbg'], platforms=['windows'],
Yuchen Zengfdae4bd2016-11-07 17:46:16 -0800233 labels=['portability'],
234 extra_args=extra_args,
235 extra_envs={'GRPC_DNS_RESOLVER': 'native'})
236
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200237 test_jobs += _generate_jobs(languages=['python'],
238 configs=['dbg'],
239 platforms=['linux'],
240 arch='default',
241 compiler='python3.4',
Jan Tattermusch6d7c6ef2016-09-22 13:40:48 +0200242 labels=['portability'],
Matt Kwongfef98962016-10-27 10:45:47 -0700243 extra_args=extra_args,
244 inner_jobs=inner_jobs)
murgatroid991687cab2016-10-11 11:42:01 -0700245
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200246 test_jobs += _generate_jobs(languages=['csharp'],
247 configs=['dbg'],
248 platforms=['linux'],
249 arch='default',
250 compiler='coreclr',
Jan Tattermusch6d7c6ef2016-09-22 13:40:48 +0200251 labels=['portability'],
Matt Kwongfef98962016-10-27 10:45:47 -0700252 extra_args=extra_args,
253 inner_jobs=inner_jobs)
murgatroid991687cab2016-10-11 11:42:01 -0700254 return test_jobs
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200255
256
Jan Tattermusch6d7c6ef2016-09-22 13:40:48 +0200257def _allowed_labels():
258 """Returns a list of existing job labels."""
259 all_labels = set()
260 for job in _create_test_jobs() + _create_portability_test_jobs():
261 for label in job.labels:
262 all_labels.add(label)
263 return sorted(all_labels)
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200264
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200265
266argp = argparse.ArgumentParser(description='Run a matrix of run_tests.py tests.')
Jan Tattermuscha1906d52016-09-19 18:37:17 +0200267argp.add_argument('-j', '--jobs',
Matt Kwongfef98962016-10-27 10:45:47 -0700268 default=multiprocessing.cpu_count()/_DEFAULT_INNER_JOBS,
Jan Tattermuscha1906d52016-09-19 18:37:17 +0200269 type=int,
270 help='Number of concurrent run_tests.py instances.')
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200271argp.add_argument('-f', '--filter',
Jan Tattermusch6d7c6ef2016-09-22 13:40:48 +0200272 choices=_allowed_labels(),
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200273 nargs='+',
274 default=[],
275 help='Filter targets to run by label with AND semantics.')
Jan Tattermusch6d7c6ef2016-09-22 13:40:48 +0200276argp.add_argument('--build_only',
277 default=False,
278 action='store_const',
279 const=True,
280 help='Pass --build_only flag to run_tests.py instances.')
281argp.add_argument('--force_default_poller', default=False, action='store_const', const=True,
282 help='Pass --force_default_poller to run_tests.py instances.')
Jan Tattermuschc1e44902016-09-22 14:31:10 +0200283argp.add_argument('--dry_run',
284 default=False,
285 action='store_const',
286 const=True,
287 help='Only print what would be run.')
Matt Kwonge9163f02016-10-05 11:42:55 -0700288argp.add_argument('--filter_pr_tests',
289 default=False,
290 action='store_const',
291 const=True,
292 help='Filters out tests irrelavant to pull request changes.')
Matt Kwongf3f28722016-10-07 15:25:56 -0700293argp.add_argument('--base_branch',
294 default='origin/master',
295 type=str,
296 help='Branch that pull request is requesting to merge into')
Matt Kwongfef98962016-10-27 10:45:47 -0700297argp.add_argument('--inner_jobs',
298 default=_DEFAULT_INNER_JOBS,
299 type=int,
300 help='Number of jobs in each run_tests.py instance')
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200301args = argp.parse_args()
302
Matt Kwongfef98962016-10-27 10:45:47 -0700303
Jan Tattermusch6d7c6ef2016-09-22 13:40:48 +0200304extra_args = []
305if args.build_only:
306 extra_args.append('--build_only')
307if args.force_default_poller:
308 extra_args.append('--force_default_poller')
309
Matt Kwongfef98962016-10-27 10:45:47 -0700310all_jobs = _create_test_jobs(extra_args=extra_args, inner_jobs=args.inner_jobs) + \
311 _create_portability_test_jobs(extra_args=extra_args, inner_jobs=args.inner_jobs)
Jan Tattermusch6d7c6ef2016-09-22 13:40:48 +0200312
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200313jobs = []
314for job in all_jobs:
315 if not args.filter or all(filter in job.labels for filter in args.filter):
316 jobs.append(job)
317
318if not jobs:
319 jobset.message('FAILED', 'No test suites match given criteria.',
320 do_newline=True)
321 sys.exit(1)
murgatroid991687cab2016-10-11 11:42:01 -0700322
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200323print('IMPORTANT: The changes you are testing need to be locally committed')
324print('because only the committed changes in the current branch will be')
325print('copied to the docker environment or into subworkspaces.')
326
murgatroid991687cab2016-10-11 11:42:01 -0700327print
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200328print 'Will run these tests:'
329for job in jobs:
Jan Tattermusch7b9c21a2016-09-22 14:44:27 +0200330 if args.dry_run:
331 print ' %s: "%s"' % (job.shortname, ' '.join(job.cmdline))
332 else:
333 print ' %s' % job.shortname
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200334print
335
Matt Kwonge9163f02016-10-05 11:42:55 -0700336if args.filter_pr_tests:
337 print 'IMPORTANT: Test filtering is not active; this is only for testing.'
Matt Kwongf3f28722016-10-07 15:25:56 -0700338 relevant_jobs = filter_tests(jobs, args.base_branch)
Matt Kwongf01122c2016-10-12 18:24:53 -0700339 # todo(mattkwong): add skipped tests to report.xml
Matt Kwonge9163f02016-10-05 11:42:55 -0700340 print
341 if len(relevant_jobs) == len(jobs):
Matt Kwongf3f28722016-10-07 15:25:56 -0700342 print '(TESTING) No tests will be skipped.'
Matt Kwonge9163f02016-10-05 11:42:55 -0700343 else:
Matt Kwongf3f28722016-10-07 15:25:56 -0700344 print '(TESTING) These tests will be skipped:'
Matt Kwonge9163f02016-10-05 11:42:55 -0700345 for job in list(set(jobs) - set(relevant_jobs)):
346 print ' %s' % job.shortname
347 print
348
Jan Tattermuschc1e44902016-09-22 14:31:10 +0200349if args.dry_run:
350 print '--dry_run was used, exiting'
351 sys.exit(1)
352
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200353jobset.message('START', 'Running test matrix.', do_newline=True)
354num_failures, resultset = jobset.run(jobs,
355 newline_on_success=True,
356 travis=True,
Jan Tattermuscha1906d52016-09-19 18:37:17 +0200357 maxjobs=args.jobs)
Jan Tattermuschcfcc0752016-10-09 17:02:34 +0200358report_utils.render_junit_xml_report(resultset, 'report.xml',
359 suite_name='aggregate_tests')
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200360
361if num_failures == 0:
362 jobset.message('SUCCESS', 'All run_tests.py instance finished successfully.',
363 do_newline=True)
364else:
365 jobset.message('FAILED', 'Some run_tests.py instance have failed.',
366 do_newline=True)
367 sys.exit(1)