blob: ae7fdd84f9bde22d004aa7ffc45ec3ea4a0390ca [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
39
40_ROOT = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), '../..'))
41os.chdir(_ROOT)
42
Jan Tattermusch060eb872016-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 Tattermusch9c79e8d2016-09-19 14:33:18 +020046
Jan Tattermuscha1906d52016-09-19 18:37:17 +020047# Number of jobs assigned to each run_tests.py instance
48_INNER_JOBS = 2
49
Jan Tattermusch9c79e8d2016-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 Tattermusch9c79e8d2016-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 Tattermuscha1906d52016-09-19 18:37:17 +020057 '-j', str(_INNER_JOBS),
Jan Tattermusch9c79e8d2016-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 Tattermuscha1906d52016-09-19 18:37:17 +020066 if not workspace_name:
67 workspace_name = 'workspace_%s' % name
Jan Tattermusch9c79e8d2016-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 Tattermuscha1906d52016-09-19 18:37:17 +020072 '-j', str(_INNER_JOBS),
Jan Tattermusch9c79e8d2016-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 Tattermusch6d7c6ef2016-09-22 13:40:48 +020082 labels=[], extra_args=[]):
Jan Tattermusch9c79e8d2016-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 Tattermusch6d7c6ef2016-09-22 13:40:48 +020095 runtests_args += extra_args
Jan Tattermusch9c79e8d2016-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 Tattermusch6d7c6ef2016-09-22 13:40:48 +0200106def _create_test_jobs(extra_args=[]):
Jan Tattermusch9c79e8d2016-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 Tattermusch6d7c6ef2016-09-22 13:40:48 +0200112 labels=['basictests'],
113 extra_args=extra_args)
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200114
115 # supported on all platforms.
116 test_jobs += _generate_jobs(languages=['c', 'csharp', 'node', 'python'],
Jan Tattermusch6d7c6ef2016-09-22 13:40:48 +0200117 configs=['dbg', 'opt'],
118 platforms=['linux', 'macos', 'windows'],
119 labels=['basictests'],
120 extra_args=extra_args)
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200121
122 # supported on linux and mac.
123 test_jobs += _generate_jobs(languages=['c++', 'ruby', 'php'],
Jan Tattermusch6d7c6ef2016-09-22 13:40:48 +0200124 configs=['dbg', 'opt'],
125 platforms=['linux', 'macos'],
126 labels=['basictests'],
127 extra_args=extra_args)
Jan Tattermusch9c79e8d2016-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 Tattermusch6d7c6ef2016-09-22 13:40:48 +0200133 labels=['basictests'],
134 extra_args=extra_args)
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200135
136 # sanitizers
137 test_jobs += _generate_jobs(languages=['c'],
138 configs=['msan', 'asan', 'tsan'],
139 platforms=['linux'],
Jan Tattermusch6d7c6ef2016-09-22 13:40:48 +0200140 labels=['sanitizers'],
141 extra_args=extra_args)
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200142 test_jobs += _generate_jobs(languages=['c++'],
143 configs=['asan', 'tsan'],
144 platforms=['linux'],
Jan Tattermusch6d7c6ef2016-09-22 13:40:48 +0200145 labels=['sanitizers'],
146 extra_args=extra_args)
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200147 return test_jobs
148
149
Jan Tattermusch6d7c6ef2016-09-22 13:40:48 +0200150def _create_portability_test_jobs(extra_args=[]):
Jan Tattermusch9c79e8d2016-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 Tattermusch6d7c6ef2016-09-22 13:40:48 +0200158 labels=['portability'],
159 extra_args=extra_args)
Jan Tattermusch9c79e8d2016-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 Tattermusch6d7c6ef2016-09-22 13:40:48 +0200169 labels=['portability'],
170 extra_args=extra_args)
Jan Tattermusch9c79e8d2016-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 Tattermusch6d7c6ef2016-09-22 13:40:48 +0200180 labels=['portability'],
181 extra_args=extra_args)
Jan Tattermusch9c79e8d2016-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 Tattermusch6d7c6ef2016-09-22 13:40:48 +0200188 labels=['portability'],
189 extra_args=extra_args)
Jan Tattermusch9c79e8d2016-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 Tattermusch6d7c6ef2016-09-22 13:40:48 +0200196 labels=['portability'],
197 extra_args=extra_args)
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200198
199 for compiler in ['node5', 'node6', 'node0.12']:
200 test_jobs += _generate_jobs(languages=['node'],
Jan Tattermusch6d7c6ef2016-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 Tattermusch9c79e8d2016-09-19 14:33:18 +0200207 return test_jobs
208
209
Jan Tattermusch6d7c6ef2016-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 Tattermusch9c79e8d2016-09-19 14:33:18 +0200217
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200218
219argp = argparse.ArgumentParser(description='Run a matrix of run_tests.py tests.')
Jan Tattermuscha1906d52016-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 Tattermusch9c79e8d2016-09-19 14:33:18 +0200224argp.add_argument('-f', '--filter',
Jan Tattermusch6d7c6ef2016-09-22 13:40:48 +0200225 choices=_allowed_labels(),
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200226 nargs='+',
227 default=[],
228 help='Filter targets to run by label with AND semantics.')
Jan Tattermusch6d7c6ef2016-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 Tattermusch9c79e8d2016-09-19 14:33:18 +0200236args = argp.parse_args()
237
Jan Tattermusch6d7c6ef2016-09-22 13:40:48 +0200238extra_args = []
239if args.build_only:
240 extra_args.append('--build_only')
241if args.force_default_poller:
242 extra_args.append('--force_default_poller')
243
244all_jobs = _create_test_jobs(extra_args=extra_args) + _create_portability_test_jobs(extra_args=extra_args)
245
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200246jobs = []
247for job in all_jobs:
248 if not args.filter or all(filter in job.labels for filter in args.filter):
249 jobs.append(job)
250
251if not jobs:
252 jobset.message('FAILED', 'No test suites match given criteria.',
253 do_newline=True)
254 sys.exit(1)
255
256print('IMPORTANT: The changes you are testing need to be locally committed')
257print('because only the committed changes in the current branch will be')
258print('copied to the docker environment or into subworkspaces.')
259
260print
261print 'Will run these tests:'
262for job in jobs:
263 print ' %s' % job.shortname
264print
265
266jobset.message('START', 'Running test matrix.', do_newline=True)
267num_failures, resultset = jobset.run(jobs,
268 newline_on_success=True,
269 travis=True,
Jan Tattermuscha1906d52016-09-19 18:37:17 +0200270 maxjobs=args.jobs)
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200271report_utils.render_junit_xml_report(resultset, 'report.xml')
272
273if num_failures == 0:
274 jobset.message('SUCCESS', 'All run_tests.py instance finished successfully.',
275 do_newline=True)
276else:
277 jobset.message('FAILED', 'Some run_tests.py instance have failed.',
278 do_newline=True)
279 sys.exit(1)