blob: 260e0eee618afc37612c7afd6219a1e1f603735c [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:
103 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 Zengfdae4bd2016-11-07 17:46:16 -0800223 # Test c and C++ with the native DNS resolver
224 test_jobs += _generate_jobs(languages=['c', 'c++'],
225 configs=['dbg'], platforms=['linux', 'windows'],
226 arch='default',
227 compiler='default',
228 labels=['portability'],
229 extra_args=extra_args,
230 extra_envs={'GRPC_DNS_RESOLVER': 'native'})
231
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200232 test_jobs += _generate_jobs(languages=['python'],
233 configs=['dbg'],
234 platforms=['linux'],
235 arch='default',
236 compiler='python3.4',
Jan Tattermusch6d7c6ef2016-09-22 13:40:48 +0200237 labels=['portability'],
Matt Kwongfef98962016-10-27 10:45:47 -0700238 extra_args=extra_args,
239 inner_jobs=inner_jobs)
murgatroid991687cab2016-10-11 11:42:01 -0700240
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200241 test_jobs += _generate_jobs(languages=['csharp'],
242 configs=['dbg'],
243 platforms=['linux'],
244 arch='default',
245 compiler='coreclr',
Jan Tattermusch6d7c6ef2016-09-22 13:40:48 +0200246 labels=['portability'],
Matt Kwongfef98962016-10-27 10:45:47 -0700247 extra_args=extra_args,
248 inner_jobs=inner_jobs)
murgatroid991687cab2016-10-11 11:42:01 -0700249 return test_jobs
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200250
251
Jan Tattermusch6d7c6ef2016-09-22 13:40:48 +0200252def _allowed_labels():
253 """Returns a list of existing job labels."""
254 all_labels = set()
255 for job in _create_test_jobs() + _create_portability_test_jobs():
256 for label in job.labels:
257 all_labels.add(label)
258 return sorted(all_labels)
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200259
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200260
261argp = argparse.ArgumentParser(description='Run a matrix of run_tests.py tests.')
Jan Tattermuscha1906d52016-09-19 18:37:17 +0200262argp.add_argument('-j', '--jobs',
Matt Kwongfef98962016-10-27 10:45:47 -0700263 default=multiprocessing.cpu_count()/_DEFAULT_INNER_JOBS,
Jan Tattermuscha1906d52016-09-19 18:37:17 +0200264 type=int,
265 help='Number of concurrent run_tests.py instances.')
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200266argp.add_argument('-f', '--filter',
Jan Tattermusch6d7c6ef2016-09-22 13:40:48 +0200267 choices=_allowed_labels(),
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200268 nargs='+',
269 default=[],
270 help='Filter targets to run by label with AND semantics.')
Jan Tattermusch6d7c6ef2016-09-22 13:40:48 +0200271argp.add_argument('--build_only',
272 default=False,
273 action='store_const',
274 const=True,
275 help='Pass --build_only flag to run_tests.py instances.')
276argp.add_argument('--force_default_poller', default=False, action='store_const', const=True,
277 help='Pass --force_default_poller to run_tests.py instances.')
Jan Tattermuschc1e44902016-09-22 14:31:10 +0200278argp.add_argument('--dry_run',
279 default=False,
280 action='store_const',
281 const=True,
282 help='Only print what would be run.')
Matt Kwonge9163f02016-10-05 11:42:55 -0700283argp.add_argument('--filter_pr_tests',
284 default=False,
285 action='store_const',
286 const=True,
287 help='Filters out tests irrelavant to pull request changes.')
Matt Kwongf3f28722016-10-07 15:25:56 -0700288argp.add_argument('--base_branch',
289 default='origin/master',
290 type=str,
291 help='Branch that pull request is requesting to merge into')
Matt Kwongfef98962016-10-27 10:45:47 -0700292argp.add_argument('--inner_jobs',
293 default=_DEFAULT_INNER_JOBS,
294 type=int,
295 help='Number of jobs in each run_tests.py instance')
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200296args = argp.parse_args()
297
Matt Kwongfef98962016-10-27 10:45:47 -0700298
Jan Tattermusch6d7c6ef2016-09-22 13:40:48 +0200299extra_args = []
300if args.build_only:
301 extra_args.append('--build_only')
302if args.force_default_poller:
303 extra_args.append('--force_default_poller')
304
Matt Kwongfef98962016-10-27 10:45:47 -0700305all_jobs = _create_test_jobs(extra_args=extra_args, inner_jobs=args.inner_jobs) + \
306 _create_portability_test_jobs(extra_args=extra_args, inner_jobs=args.inner_jobs)
Jan Tattermusch6d7c6ef2016-09-22 13:40:48 +0200307
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200308jobs = []
309for job in all_jobs:
310 if not args.filter or all(filter in job.labels for filter in args.filter):
311 jobs.append(job)
312
313if not jobs:
314 jobset.message('FAILED', 'No test suites match given criteria.',
315 do_newline=True)
316 sys.exit(1)
murgatroid991687cab2016-10-11 11:42:01 -0700317
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200318print('IMPORTANT: The changes you are testing need to be locally committed')
319print('because only the committed changes in the current branch will be')
320print('copied to the docker environment or into subworkspaces.')
321
murgatroid991687cab2016-10-11 11:42:01 -0700322print
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200323print 'Will run these tests:'
324for job in jobs:
Jan Tattermusch7b9c21a2016-09-22 14:44:27 +0200325 if args.dry_run:
326 print ' %s: "%s"' % (job.shortname, ' '.join(job.cmdline))
327 else:
328 print ' %s' % job.shortname
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200329print
330
Matt Kwonge9163f02016-10-05 11:42:55 -0700331if args.filter_pr_tests:
332 print 'IMPORTANT: Test filtering is not active; this is only for testing.'
Matt Kwongf3f28722016-10-07 15:25:56 -0700333 relevant_jobs = filter_tests(jobs, args.base_branch)
Matt Kwongf01122c2016-10-12 18:24:53 -0700334 # todo(mattkwong): add skipped tests to report.xml
Matt Kwonge9163f02016-10-05 11:42:55 -0700335 print
336 if len(relevant_jobs) == len(jobs):
Matt Kwongf3f28722016-10-07 15:25:56 -0700337 print '(TESTING) No tests will be skipped.'
Matt Kwonge9163f02016-10-05 11:42:55 -0700338 else:
Matt Kwongf3f28722016-10-07 15:25:56 -0700339 print '(TESTING) These tests will be skipped:'
Matt Kwonge9163f02016-10-05 11:42:55 -0700340 for job in list(set(jobs) - set(relevant_jobs)):
341 print ' %s' % job.shortname
342 print
343
Jan Tattermuschc1e44902016-09-22 14:31:10 +0200344if args.dry_run:
345 print '--dry_run was used, exiting'
346 sys.exit(1)
347
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200348jobset.message('START', 'Running test matrix.', do_newline=True)
349num_failures, resultset = jobset.run(jobs,
350 newline_on_success=True,
351 travis=True,
Jan Tattermuscha1906d52016-09-19 18:37:17 +0200352 maxjobs=args.jobs)
Jan Tattermuschcfcc0752016-10-09 17:02:34 +0200353report_utils.render_junit_xml_report(resultset, 'report.xml',
354 suite_name='aggregate_tests')
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200355
356if num_failures == 0:
357 jobset.message('SUCCESS', 'All run_tests.py instance finished successfully.',
358 do_newline=True)
359else:
360 jobset.message('FAILED', 'Some run_tests.py instance have failed.',
361 do_newline=True)
362 sys.exit(1)