blob: bc2e37abd89628855843e1ed1da78562b35fed1f [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
43# TODO(jtattermusch): this is not going to be enough for sanitizers.
Jan Tattermuscha1906d52016-09-19 18:37:17 +020044# TODO(jtattermusch): this is not going to be enough for rebuilding clang docker.
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +020045_RUNTESTS_TIMEOUT = 30*60
46
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"""
53 # TODO: fix copying report files from inside docker....
54 test_job = jobset.JobSpec(
55 cmdline=['python', 'tools/run_tests/run_tests.py',
56 '--use_docker',
57 '-t',
Jan Tattermuscha1906d52016-09-19 18:37:17 +020058 '-j', str(_INNER_JOBS),
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +020059 '-x', 'report_%s.xml' % name] + runtests_args,
60 shortname='run_tests_%s' % name,
61 timeout_seconds=_RUNTESTS_TIMEOUT)
62 return test_job
63
64
65def _workspace_jobspec(name, runtests_args=[], workspace_name=None):
66 """Run a single instance of run_tests.py in a separate workspace"""
Jan Tattermuscha1906d52016-09-19 18:37:17 +020067 if not workspace_name:
68 workspace_name = 'workspace_%s' % name
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +020069 env = {'WORKSPACE_NAME': workspace_name}
70 test_job = jobset.JobSpec(
71 cmdline=['tools/run_tests/run_tests_in_workspace.sh',
72 '-t',
Jan Tattermuscha1906d52016-09-19 18:37:17 +020073 '-j', str(_INNER_JOBS),
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +020074 '-x', '../report_%s.xml' % name] + runtests_args,
75 environ=env,
76 shortname='run_tests_%s' % name,
77 timeout_seconds=_RUNTESTS_TIMEOUT)
78 return test_job
79
80
81def _generate_jobs(languages, configs, platforms,
82 arch=None, compiler=None,
83 labels=[]):
84 result = []
85 for language in languages:
86 for platform in platforms:
87 for config in configs:
88 name = '%s_%s_%s' % (language, platform, config)
89 runtests_args = ['-l', language,
90 '-c', config]
91 if arch or compiler:
92 name += '_%s_%s' % (arch, compiler)
93 runtests_args += ['--arch', arch,
94 '--compiler', compiler]
95
96 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
106def _create_test_jobs():
107 test_jobs = []
108 # supported on linux only
109 test_jobs += _generate_jobs(languages=['sanity', 'php7'],
110 configs=['dbg', 'opt'],
111 platforms=['linux'],
112 labels=['basictests'])
113
114 # supported on all platforms.
115 test_jobs += _generate_jobs(languages=['c', 'csharp', 'node', 'python'],
116 configs=['dbg', 'opt'],
117 platforms=['linux', 'macos', 'windows'],
118 labels=['basictests'])
119
120 # supported on linux and mac.
121 test_jobs += _generate_jobs(languages=['c++', 'ruby', 'php'],
122 configs=['dbg', 'opt'],
123 platforms=['linux', 'macos'],
124 labels=['basictests'])
125
126 # supported on mac only.
127 test_jobs += _generate_jobs(languages=['objc'],
128 configs=['dbg', 'opt'],
129 platforms=['macos'],
130 labels=['basictests'])
131
132 # sanitizers
133 test_jobs += _generate_jobs(languages=['c'],
134 configs=['msan', 'asan', 'tsan'],
135 platforms=['linux'],
136 labels=['sanitizers'])
137 test_jobs += _generate_jobs(languages=['c++'],
138 configs=['asan', 'tsan'],
139 platforms=['linux'],
140 labels=['sanitizers'])
141 return test_jobs
142
143
144def _create_portability_test_jobs():
145 test_jobs = []
146 # portability C x86
147 test_jobs += _generate_jobs(languages=['c'],
148 configs=['dbg'],
149 platforms=['linux'],
150 arch='x86',
151 compiler='default',
152 labels=['portability'])
153
154 # portability C and C++ on x64
155 for compiler in ['gcc4.4', 'gcc4.6', 'gcc5.3',
156 'clang3.5', 'clang3.6', 'clang3.7']:
157 test_jobs += _generate_jobs(languages=['c', 'c++'],
158 configs=['dbg'],
159 platforms=['linux'],
160 arch='x64',
161 compiler=compiler,
162 labels=['portability'])
163
164 # portability C on Windows
165 for arch in ['x86', 'x64']:
166 for compiler in ['vs2013', 'vs2015']:
167 test_jobs += _generate_jobs(languages=['c'],
168 configs=['dbg'],
169 platforms=['windows'],
170 arch=arch,
171 compiler=compiler,
172 labels=['portability'])
173
174 test_jobs += _generate_jobs(languages=['python'],
175 configs=['dbg'],
176 platforms=['linux'],
177 arch='default',
178 compiler='python3.4',
179 labels=['portability'])
180
181 test_jobs += _generate_jobs(languages=['csharp'],
182 configs=['dbg'],
183 platforms=['linux'],
184 arch='default',
185 compiler='coreclr',
186 labels=['portability'])
187
188 for compiler in ['node5', 'node6', 'node0.12']:
189 test_jobs += _generate_jobs(languages=['node'],
190 configs=['dbg'],
191 platforms=['linux'],
192 arch='default',
193 compiler=compiler,
194 labels=['portability'])
195 return test_jobs
196
197
198all_jobs = _create_test_jobs() + _create_portability_test_jobs()
199
200all_labels = set()
201for job in all_jobs:
202 for label in job.labels:
203 all_labels.add(label)
204
205argp = argparse.ArgumentParser(description='Run a matrix of run_tests.py tests.')
Jan Tattermuscha1906d52016-09-19 18:37:17 +0200206argp.add_argument('-j', '--jobs',
207 default=multiprocessing.cpu_count()/_INNER_JOBS,
208 type=int,
209 help='Number of concurrent run_tests.py instances.')
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200210argp.add_argument('-f', '--filter',
211 choices=sorted(all_labels),
212 nargs='+',
213 default=[],
214 help='Filter targets to run by label with AND semantics.')
215args = argp.parse_args()
216
217jobs = []
218for job in all_jobs:
219 if not args.filter or all(filter in job.labels for filter in args.filter):
220 jobs.append(job)
221
222if not jobs:
223 jobset.message('FAILED', 'No test suites match given criteria.',
224 do_newline=True)
225 sys.exit(1)
226
227print('IMPORTANT: The changes you are testing need to be locally committed')
228print('because only the committed changes in the current branch will be')
229print('copied to the docker environment or into subworkspaces.')
230
231print
232print 'Will run these tests:'
233for job in jobs:
234 print ' %s' % job.shortname
235print
236
237jobset.message('START', 'Running test matrix.', do_newline=True)
238num_failures, resultset = jobset.run(jobs,
239 newline_on_success=True,
240 travis=True,
Jan Tattermuscha1906d52016-09-19 18:37:17 +0200241 maxjobs=args.jobs)
Jan Tattermusch9c79e8d2016-09-19 14:33:18 +0200242report_utils.render_junit_xml_report(resultset, 'report.xml')
243
244if num_failures == 0:
245 jobset.message('SUCCESS', 'All run_tests.py instance finished successfully.',
246 do_newline=True)
247else:
248 jobset.message('FAILED', 'Some run_tests.py instance have failed.',
249 do_newline=True)
250 sys.exit(1)