blob: a31b0dd9177ea21ed7338428193319416b6000f8 [file] [log] [blame]
Jan Tattermusch3b0d0922016-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 Tattermusch7a7792a2016-09-19 18:37:17 +020035import multiprocessing
Jan Tattermusch3b0d0922016-09-19 14:33:18 +020036import os
37import report_utils
38import sys
39
40_ROOT = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), '../..'))
41os.chdir(_ROOT)
42
Jan Tattermusch5b34c4f2016-09-20 16:06:13 +020043# Set the timeout high to allow enough time for sanitizers and pre-building
44# clang docker.
45_RUNTESTS_TIMEOUT = 2*60*60
Jan Tattermusch3b0d0922016-09-19 14:33:18 +020046
Jan Tattermusch7a7792a2016-09-19 18:37:17 +020047# Number of jobs assigned to each run_tests.py instance
48_INNER_JOBS = 2
49
Jan Tattermusch3b0d0922016-09-19 14:33:18 +020050
51def _docker_jobspec(name, runtests_args=[]):
52 """Run a single instance of run_tests.py in a docker container"""
Jan Tattermusch3b0d0922016-09-19 14:33:18 +020053 test_job = jobset.JobSpec(
54 cmdline=['python', 'tools/run_tests/run_tests.py',
55 '--use_docker',
56 '-t',
Jan Tattermusch7a7792a2016-09-19 18:37:17 +020057 '-j', str(_INNER_JOBS),
Jan Tattermusch3b0d0922016-09-19 14:33:18 +020058 '-x', 'report_%s.xml' % name] + runtests_args,
59 shortname='run_tests_%s' % name,
60 timeout_seconds=_RUNTESTS_TIMEOUT)
61 return test_job
62
63
64def _workspace_jobspec(name, runtests_args=[], workspace_name=None):
65 """Run a single instance of run_tests.py in a separate workspace"""
Jan Tattermusch7a7792a2016-09-19 18:37:17 +020066 if not workspace_name:
67 workspace_name = 'workspace_%s' % name
Jan Tattermusch3b0d0922016-09-19 14:33:18 +020068 env = {'WORKSPACE_NAME': workspace_name}
69 test_job = jobset.JobSpec(
70 cmdline=['tools/run_tests/run_tests_in_workspace.sh',
71 '-t',
Jan Tattermusch7a7792a2016-09-19 18:37:17 +020072 '-j', str(_INNER_JOBS),
Jan Tattermusch3b0d0922016-09-19 14:33:18 +020073 '-x', '../report_%s.xml' % name] + runtests_args,
74 environ=env,
75 shortname='run_tests_%s' % name,
76 timeout_seconds=_RUNTESTS_TIMEOUT)
77 return test_job
78
79
80def _generate_jobs(languages, configs, platforms,
81 arch=None, compiler=None,
Jan Tattermusch7a6c2232016-09-22 13:40:48 +020082 labels=[], extra_args=[]):
Jan Tattermusch3b0d0922016-09-19 14:33:18 +020083 result = []
84 for language in languages:
85 for platform in platforms:
86 for config in configs:
87 name = '%s_%s_%s' % (language, platform, config)
88 runtests_args = ['-l', language,
89 '-c', config]
90 if arch or compiler:
91 name += '_%s_%s' % (arch, compiler)
92 runtests_args += ['--arch', arch,
93 '--compiler', compiler]
94
Jan Tattermusch7a6c2232016-09-22 13:40:48 +020095 runtests_args += extra_args
Jan Tattermusch3b0d0922016-09-19 14:33:18 +020096 if platform == 'linux':
97 job = _docker_jobspec(name=name, runtests_args=runtests_args)
98 else:
99 job = _workspace_jobspec(name=name, runtests_args=runtests_args)
100
101 job.labels = [platform, config, language] + labels
102 result.append(job)
103 return result
104
105
Jan Tattermusch7a6c2232016-09-22 13:40:48 +0200106def _create_test_jobs(extra_args=[]):
Jan Tattermusch3b0d0922016-09-19 14:33:18 +0200107 test_jobs = []
108 # supported on linux only
109 test_jobs += _generate_jobs(languages=['sanity', 'php7'],
110 configs=['dbg', 'opt'],
111 platforms=['linux'],
Jan Tattermusch7a6c2232016-09-22 13:40:48 +0200112 labels=['basictests'],
113 extra_args=extra_args)
Jan Tattermusch3b0d0922016-09-19 14:33:18 +0200114
115 # supported on all platforms.
116 test_jobs += _generate_jobs(languages=['c', 'csharp', 'node', 'python'],
Jan Tattermusch7a6c2232016-09-22 13:40:48 +0200117 configs=['dbg', 'opt'],
118 platforms=['linux', 'macos', 'windows'],
119 labels=['basictests'],
120 extra_args=extra_args)
Jan Tattermusch3b0d0922016-09-19 14:33:18 +0200121
122 # supported on linux and mac.
123 test_jobs += _generate_jobs(languages=['c++', 'ruby', 'php'],
Jan Tattermusch7a6c2232016-09-22 13:40:48 +0200124 configs=['dbg', 'opt'],
125 platforms=['linux', 'macos'],
126 labels=['basictests'],
127 extra_args=extra_args)
Jan Tattermusch3b0d0922016-09-19 14:33:18 +0200128
129 # supported on mac only.
130 test_jobs += _generate_jobs(languages=['objc'],
131 configs=['dbg', 'opt'],
132 platforms=['macos'],
Jan Tattermusch7a6c2232016-09-22 13:40:48 +0200133 labels=['basictests'],
134 extra_args=extra_args)
Jan Tattermusch3b0d0922016-09-19 14:33:18 +0200135
136 # sanitizers
137 test_jobs += _generate_jobs(languages=['c'],
138 configs=['msan', 'asan', 'tsan'],
139 platforms=['linux'],
Jan Tattermusch7a6c2232016-09-22 13:40:48 +0200140 labels=['sanitizers'],
141 extra_args=extra_args)
Jan Tattermusch3b0d0922016-09-19 14:33:18 +0200142 test_jobs += _generate_jobs(languages=['c++'],
143 configs=['asan', 'tsan'],
144 platforms=['linux'],
Jan Tattermusch7a6c2232016-09-22 13:40:48 +0200145 labels=['sanitizers'],
146 extra_args=extra_args)
Jan Tattermusch3b0d0922016-09-19 14:33:18 +0200147 return test_jobs
148
149
Jan Tattermusch7a6c2232016-09-22 13:40:48 +0200150def _create_portability_test_jobs(extra_args=[]):
Jan Tattermusch3b0d0922016-09-19 14:33:18 +0200151 test_jobs = []
152 # portability C x86
153 test_jobs += _generate_jobs(languages=['c'],
154 configs=['dbg'],
155 platforms=['linux'],
156 arch='x86',
157 compiler='default',
Jan Tattermusch7a6c2232016-09-22 13:40:48 +0200158 labels=['portability'],
159 extra_args=extra_args)
Jan Tattermusch3b0d0922016-09-19 14:33:18 +0200160
161 # portability C and C++ on x64
162 for compiler in ['gcc4.4', 'gcc4.6', 'gcc5.3',
163 'clang3.5', 'clang3.6', 'clang3.7']:
164 test_jobs += _generate_jobs(languages=['c', 'c++'],
165 configs=['dbg'],
166 platforms=['linux'],
167 arch='x64',
168 compiler=compiler,
Jan Tattermusch7a6c2232016-09-22 13:40:48 +0200169 labels=['portability'],
170 extra_args=extra_args)
Jan Tattermusch3b0d0922016-09-19 14:33:18 +0200171
172 # portability C on Windows
173 for arch in ['x86', 'x64']:
174 for compiler in ['vs2013', 'vs2015']:
175 test_jobs += _generate_jobs(languages=['c'],
176 configs=['dbg'],
177 platforms=['windows'],
178 arch=arch,
179 compiler=compiler,
Jan Tattermusch7a6c2232016-09-22 13:40:48 +0200180 labels=['portability'],
181 extra_args=extra_args)
Jan Tattermusch3b0d0922016-09-19 14:33:18 +0200182
183 test_jobs += _generate_jobs(languages=['python'],
184 configs=['dbg'],
185 platforms=['linux'],
186 arch='default',
187 compiler='python3.4',
Jan Tattermusch7a6c2232016-09-22 13:40:48 +0200188 labels=['portability'],
189 extra_args=extra_args)
Jan Tattermusch3b0d0922016-09-19 14:33:18 +0200190
191 test_jobs += _generate_jobs(languages=['csharp'],
192 configs=['dbg'],
193 platforms=['linux'],
194 arch='default',
195 compiler='coreclr',
Jan Tattermusch7a6c2232016-09-22 13:40:48 +0200196 labels=['portability'],
197 extra_args=extra_args)
Jan Tattermusch3b0d0922016-09-19 14:33:18 +0200198
Jan Tattermuschf098c752016-09-22 14:28:07 +0200199 for compiler in ['node5', 'node0.12']:
Jan Tattermusch3b0d0922016-09-19 14:33:18 +0200200 test_jobs += _generate_jobs(languages=['node'],
Jan Tattermusch7a6c2232016-09-22 13:40:48 +0200201 configs=['dbg'],
202 platforms=['linux'],
203 arch='default',
204 compiler=compiler,
205 labels=['portability'],
206 extra_args=extra_args)
Jan Tattermusch3b0d0922016-09-19 14:33:18 +0200207 return test_jobs
208
209
Jan Tattermusch7a6c2232016-09-22 13:40:48 +0200210def _allowed_labels():
211 """Returns a list of existing job labels."""
212 all_labels = set()
213 for job in _create_test_jobs() + _create_portability_test_jobs():
214 for label in job.labels:
215 all_labels.add(label)
216 return sorted(all_labels)
Jan Tattermusch3b0d0922016-09-19 14:33:18 +0200217
Jan Tattermusch3b0d0922016-09-19 14:33:18 +0200218
219argp = argparse.ArgumentParser(description='Run a matrix of run_tests.py tests.')
Jan Tattermusch7a7792a2016-09-19 18:37:17 +0200220argp.add_argument('-j', '--jobs',
221 default=multiprocessing.cpu_count()/_INNER_JOBS,
222 type=int,
223 help='Number of concurrent run_tests.py instances.')
Jan Tattermusch3b0d0922016-09-19 14:33:18 +0200224argp.add_argument('-f', '--filter',
Jan Tattermusch7a6c2232016-09-22 13:40:48 +0200225 choices=_allowed_labels(),
Jan Tattermusch3b0d0922016-09-19 14:33:18 +0200226 nargs='+',
227 default=[],
228 help='Filter targets to run by label with AND semantics.')
Jan Tattermusch7a6c2232016-09-22 13:40:48 +0200229argp.add_argument('--build_only',
230 default=False,
231 action='store_const',
232 const=True,
233 help='Pass --build_only flag to run_tests.py instances.')
234argp.add_argument('--force_default_poller', default=False, action='store_const', const=True,
235 help='Pass --force_default_poller to run_tests.py instances.')
Jan Tattermusche922d772016-09-22 14:31:10 +0200236argp.add_argument('--dry_run',
237 default=False,
238 action='store_const',
239 const=True,
240 help='Only print what would be run.')
Jan Tattermusch3b0d0922016-09-19 14:33:18 +0200241args = argp.parse_args()
242
Jan Tattermusch7a6c2232016-09-22 13:40:48 +0200243extra_args = []
244if args.build_only:
245 extra_args.append('--build_only')
246if args.force_default_poller:
247 extra_args.append('--force_default_poller')
248
249all_jobs = _create_test_jobs(extra_args=extra_args) + _create_portability_test_jobs(extra_args=extra_args)
250
Jan Tattermusch3b0d0922016-09-19 14:33:18 +0200251jobs = []
252for job in all_jobs:
253 if not args.filter or all(filter in job.labels for filter in args.filter):
254 jobs.append(job)
255
256if not jobs:
257 jobset.message('FAILED', 'No test suites match given criteria.',
258 do_newline=True)
259 sys.exit(1)
260
261print('IMPORTANT: The changes you are testing need to be locally committed')
262print('because only the committed changes in the current branch will be')
263print('copied to the docker environment or into subworkspaces.')
264
265print
266print 'Will run these tests:'
267for job in jobs:
268 print ' %s' % job.shortname
269print
270
Jan Tattermusche922d772016-09-22 14:31:10 +0200271if args.dry_run:
272 print '--dry_run was used, exiting'
273 sys.exit(1)
274
Jan Tattermusch3b0d0922016-09-19 14:33:18 +0200275jobset.message('START', 'Running test matrix.', do_newline=True)
276num_failures, resultset = jobset.run(jobs,
277 newline_on_success=True,
278 travis=True,
Jan Tattermusch7a7792a2016-09-19 18:37:17 +0200279 maxjobs=args.jobs)
Jan Tattermusch3b0d0922016-09-19 14:33:18 +0200280report_utils.render_junit_xml_report(resultset, 'report.xml')
281
282if num_failures == 0:
283 jobset.message('SUCCESS', 'All run_tests.py instance finished successfully.',
284 do_newline=True)
285else:
286 jobset.message('FAILED', 'Some run_tests.py instance have failed.',
287 do_newline=True)
288 sys.exit(1)