blob: 99bf5df1f9234de1456d15c6f860d0da44b25f8e [file] [log] [blame]
Nathaniel Manistaae4fbcd2015-09-23 16:29:44 +00001#!/usr/bin/env python2.7
Craig Tiller40839772016-01-05 12:34:49 -08002# Copyright 2015-2016, Google Inc.
Craig Tillerc2c79212015-02-16 12:00:01 -08003# 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
Nicolas Nobleddef2462015-01-06 18:08:25 -080031"""Run tests in parallel."""
32
33import argparse
Craig Tiller9279ac22016-01-20 17:05:23 -080034import ast
Nicolas Nobleddef2462015-01-06 18:08:25 -080035import glob
Craig Tillerf53d9c82015-08-04 14:19:43 -070036import hashlib
Nicolas Nobleddef2462015-01-06 18:08:25 -080037import itertools
Craig Tiller261dd982015-01-16 16:41:45 -080038import json
Nicolas Nobleddef2462015-01-06 18:08:25 -080039import multiprocessing
Craig Tiller1cc11db2015-01-15 22:50:50 -080040import os
David Garcia Quintas79e389f2015-06-02 17:49:42 -070041import platform
42import random
Craig Tillerfe406ec2015-02-24 13:55:12 -080043import re
Craig Tiller82875232015-09-25 13:57:34 -070044import socket
David Garcia Quintas79e389f2015-06-02 17:49:42 -070045import subprocess
Nicolas Nobleddef2462015-01-06 18:08:25 -080046import sys
Craig Tillerf0a293e2015-10-12 10:05:50 -070047import tempfile
48import traceback
ctiller3040cb72015-01-07 12:13:17 -080049import time
Craig Tillerf53d9c82015-08-04 14:19:43 -070050import urllib2
Jan Tattermusch03c01062015-12-11 14:28:56 -080051import uuid
Nicolas Nobleddef2462015-01-06 18:08:25 -080052
53import jobset
Adele Zhoua30f8292015-11-02 13:15:46 -080054import report_utils
ctiller3040cb72015-01-07 12:13:17 -080055import watch_dirs
Nicolas Nobleddef2462015-01-06 18:08:25 -080056
Craig Tillerb361b4e2016-01-06 11:44:17 -080057
Jan Tattermusch3b5121b2016-02-22 17:41:05 -080058_ROOT = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), '../..'))
59os.chdir(_ROOT)
Craig Tiller2cc2b842015-02-27 11:38:31 -080060
61
Craig Tiller06805272015-06-11 14:46:47 -070062_FORCE_ENVIRON_FOR_WRAPPERS = {}
63
64
Craig Tillerd50993d2015-08-05 08:04:36 -070065def platform_string():
Nicolas "Pixel" Noblef72d7b52015-12-03 03:07:43 +010066 return jobset.platform_string()
Craig Tillerd50993d2015-08-05 08:04:36 -070067
68
Craig Tiller738c3342015-01-12 14:28:33 -080069# SimpleConfig: just compile with CONFIG=config, and run the binary to test
Craig Tillera0f85172016-01-20 15:56:06 -080070class Config(object):
Craig Tillerb50d1662015-01-15 17:28:21 -080071
Craig Tillera0f85172016-01-20 15:56:06 -080072 def __init__(self, config, environ=None, timeout_multiplier=1, tool_prefix=[]):
murgatroid99132ce6a2015-03-04 17:29:14 -080073 if environ is None:
74 environ = {}
Craig Tiller738c3342015-01-12 14:28:33 -080075 self.build_config = config
Craig Tillerc7449162015-01-16 14:42:10 -080076 self.allow_hashing = (config != 'gcov')
Craig Tiller547db2b2015-01-30 14:08:39 -080077 self.environ = environ
murgatroid99132ce6a2015-03-04 17:29:14 -080078 self.environ['CONFIG'] = config
Craig Tillera0f85172016-01-20 15:56:06 -080079 self.tool_prefix = tool_prefix
Masood Malekghassemi26ea9e22015-10-09 15:19:17 -070080 self.timeout_multiplier = timeout_multiplier
Craig Tiller738c3342015-01-12 14:28:33 -080081
Masood Malekghassemi26ea9e22015-10-09 15:19:17 -070082 def job_spec(self, cmdline, hash_targets, timeout_seconds=5*60,
Craig Tiller56c6b6a2016-01-20 08:27:37 -080083 shortname=None, environ={}, cpu_cost=1.0):
Craig Tiller49f61322015-03-03 13:02:11 -080084 """Construct a jobset.JobSpec for a test under this config
85
86 Args:
87 cmdline: a list of strings specifying the command line the test
88 would like to run
89 hash_targets: either None (don't do caching of test results), or
90 a list of strings specifying files to include in a
91 binary hash to check if a test has changed
92 -- if used, all artifacts needed to run the test must
93 be listed
94 """
Craig Tiller4fc90032015-05-21 10:39:52 -070095 actual_environ = self.environ.copy()
96 for k, v in environ.iteritems():
97 actual_environ[k] = v
Craig Tillera0f85172016-01-20 15:56:06 -080098 return jobset.JobSpec(cmdline=self.tool_prefix + cmdline,
Jan Tattermusch9a7d30c2015-04-23 16:12:55 -070099 shortname=shortname,
Craig Tiller4fc90032015-05-21 10:39:52 -0700100 environ=actual_environ,
Craig Tiller56c6b6a2016-01-20 08:27:37 -0800101 cpu_cost=cpu_cost,
Craig Tiller94d04a52016-01-20 10:58:23 -0800102 timeout_seconds=(self.timeout_multiplier * timeout_seconds if timeout_seconds else None),
Craig Tiller547db2b2015-01-30 14:08:39 -0800103 hash_targets=hash_targets
Craig Tillerd4509a12015-09-28 09:18:40 -0700104 if self.allow_hashing else None,
Craig Tiller35505de2015-10-08 13:31:33 -0700105 flake_retries=5 if args.allow_flakes else 0,
106 timeout_retries=3 if args.allow_flakes else 0)
Craig Tiller738c3342015-01-12 14:28:33 -0800107
108
murgatroid99cf08daf2015-09-21 15:33:16 -0700109def get_c_tests(travis, test_lang) :
110 out = []
111 platforms_str = 'ci_platforms' if travis else 'platforms'
112 with open('tools/run_tests/tests.json') as f:
murgatroid9989899b12015-09-22 09:14:48 -0700113 js = json.load(f)
murgatroid99a3e244f2015-09-22 11:25:53 -0700114 return [tgt
115 for tgt in js
116 if tgt['language'] == test_lang and
117 platform_string() in tgt[platforms_str] and
118 not (travis and tgt['flaky'])]
murgatroid99cf08daf2015-09-21 15:33:16 -0700119
murgatroid99fafeeb32015-09-22 09:13:03 -0700120
Jan Tattermusch77db4322016-02-20 20:19:35 -0800121def _check_compiler(compiler, supported_compilers):
122 if compiler not in supported_compilers:
123 raise Exception('Compiler %s not supported.' % compiler)
124
125
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800126def _is_use_docker_child():
127 """Returns True if running running as a --use_docker child."""
128 return True if os.getenv('RUN_TESTS_COMMAND') else False
129
130
Craig Tillerc7449162015-01-16 14:42:10 -0800131class CLanguage(object):
132
Craig Tillere9c959d2015-01-18 10:23:26 -0800133 def __init__(self, make_target, test_lang):
Craig Tillerc7449162015-01-16 14:42:10 -0800134 self.make_target = make_target
Craig Tillerd50993d2015-08-05 08:04:36 -0700135 self.platform = platform_string()
Craig Tiller711bbe62015-08-19 12:35:16 -0700136 self.test_lang = test_lang
Craig Tillerc7449162015-01-16 14:42:10 -0800137
Jan Tattermusch77db4322016-02-20 20:19:35 -0800138 def configure(self, config, args):
139 self.config = config
140 self.args = args
141 if self.platform == 'windows':
Jan Tattermuschc96caf82016-02-22 17:31:02 -0800142 self._make_options = [_windows_toolset_option(self.args.compiler),
143 _windows_arch_option(self.args.arch)]
Jan Tattermusch77db4322016-02-20 20:19:35 -0800144 else:
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800145 self._docker_distro, self._make_options = self._compiler_options(self.args.use_docker,
146 self.args.compiler)
Jan Tattermusch77db4322016-02-20 20:19:35 -0800147
148 def test_specs(self):
Craig Tiller547db2b2015-01-30 14:08:39 -0800149 out = []
Jan Tattermusch77db4322016-02-20 20:19:35 -0800150 binaries = get_c_tests(self.args.travis, self.test_lang)
Craig Tiller711bbe62015-08-19 12:35:16 -0700151 for target in binaries:
Jan Tattermusch77db4322016-02-20 20:19:35 -0800152 if self.config.build_config in target['exclude_configs']:
murgatroid99fafeeb32015-09-22 09:13:03 -0700153 continue
Nicolas Noblee1445362015-05-11 17:40:26 -0700154 if self.platform == 'windows':
Jan Tattermusch3de6b762016-01-28 11:38:11 -0800155 binary = 'vsprojects/%s%s/%s.exe' % (
Jan Tattermusch77db4322016-02-20 20:19:35 -0800156 'x64/' if self.args.arch == 'x64' else '',
Jan Tattermuscha2d964c2016-02-22 17:33:09 -0800157 _MSBUILD_CONFIG[self.config.build_config],
Jan Tattermusch3de6b762016-01-28 11:38:11 -0800158 target['name'])
Nicolas Noblee1445362015-05-11 17:40:26 -0700159 else:
Jan Tattermusch77db4322016-02-20 20:19:35 -0800160 binary = 'bins/%s/%s' % (self.config.build_config, target['name'])
yang-g6c1fdc62015-08-18 11:57:42 -0700161 if os.path.isfile(binary):
Craig Tillerca62ff02016-02-24 22:22:57 -0800162 if 'gtest' in target and target['gtest']:
Craig Tiller0488d142016-02-24 22:34:48 -0800163 # here we parse the output of --gtest_list_tests to build up a
164 # complete list of the tests contained in a binary
165 # for each test, we then add a job to run, filtering for just that
166 # test
Craig Tillerca62ff02016-02-24 22:22:57 -0800167 with open(os.devnull, 'w') as fnull:
168 tests = subprocess.check_output([binary, '--gtest_list_tests'],
169 stderr=fnull)
170 base = None
171 for line in tests.split('\n'):
172 i = line.find('#')
173 if i >= 0: line = line[:i]
174 if not line: continue
175 if line[0] != ' ':
Craig Tiller184e4232016-02-24 22:48:56 -0800176 base = line.strip()
Craig Tillerca62ff02016-02-24 22:22:57 -0800177 else:
178 assert base is not None
179 assert line[1] == ' '
Craig Tiller184e4232016-02-24 22:48:56 -0800180 test = base + line.strip()
Craig Tillerca62ff02016-02-24 22:22:57 -0800181 cmdline = [binary] + ['--gtest_filter=%s' % test]
182 out.append(self.config.job_spec(cmdline, [binary],
183 shortname='%s:%s' % (binary, test),
184 cpu_cost=target['cpu_cost'],
185 environ={'GRPC_DEFAULT_SSL_ROOTS_FILE_PATH':
186 _ROOT + '/src/core/tsi/test_creds/ca.pem'}))
187 else:
188 cmdline = [binary] + target['args']
189 out.append(self.config.job_spec(cmdline, [binary],
190 shortname=' '.join(cmdline),
191 cpu_cost=target['cpu_cost'],
192 environ={'GRPC_DEFAULT_SSL_ROOTS_FILE_PATH':
193 _ROOT + '/src/core/tsi/test_creds/ca.pem'}))
Jan Tattermusch77db4322016-02-20 20:19:35 -0800194 elif self.args.regex == '.*' or self.platform == 'windows':
Adele Zhoue4c35612015-10-16 15:34:23 -0700195 print '\nWARNING: binary not found, skipping', binary
Nicolas Noblee1445362015-05-11 17:40:26 -0700196 return sorted(out)
Craig Tillerc7449162015-01-16 14:42:10 -0800197
Jan Tattermusch77db4322016-02-20 20:19:35 -0800198 def make_targets(self):
199 test_regex = self.args.regex
200 if self.platform != 'windows' and self.args.regex != '.*':
Craig Tiller883064c2015-11-04 10:06:10 -0800201 # use the regex to minimize the number of things to build
Craig Tillerb0f275e2016-01-27 10:45:50 -0800202 return [os.path.basename(target['name'])
Craig Tiller883064c2015-11-04 10:06:10 -0800203 for target in get_c_tests(False, self.test_lang)
Craig Tillerb0f275e2016-01-27 10:45:50 -0800204 if re.search(test_regex, '/' + target['name'])]
Jan Tattermusch77db4322016-02-20 20:19:35 -0800205 if self.platform == 'windows':
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700206 # don't build tools on windows just yet
207 return ['buildtests_%s' % self.make_target]
Craig Tiller7552f0f2015-06-19 17:46:20 -0700208 return ['buildtests_%s' % self.make_target, 'tools_%s' % self.make_target]
Craig Tillerc7449162015-01-16 14:42:10 -0800209
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800210 def make_options(self):
Jan Tattermuschc96caf82016-02-22 17:31:02 -0800211 return self._make_options;
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800212
murgatroid99256d3df2015-09-21 16:58:02 -0700213 def pre_build_steps(self):
Jan Tattermusch874aec02015-10-07 19:26:19 -0700214 if self.platform == 'windows':
215 return [['tools\\run_tests\\pre_build_c.bat']]
216 else:
217 return []
murgatroid99256d3df2015-09-21 16:58:02 -0700218
Craig Tillerc7449162015-01-16 14:42:10 -0800219 def build_steps(self):
220 return []
221
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200222 def post_tests_steps(self):
223 if self.platform == 'windows':
224 return []
225 else:
226 return [['tools/run_tests/post_tests_c.sh']]
227
murgatroid99a3e244f2015-09-22 11:25:53 -0700228 def makefile_name(self):
229 return 'Makefile'
230
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800231 def _clang_make_options(self):
232 return ['CC=clang', 'CXX=clang++', 'LD=clang', 'LDXX=clang++']
233
234 def _compiler_options(self, use_docker, compiler):
235 """Returns docker distro and make options to use for given compiler."""
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800236 if _is_use_docker_child():
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800237 return ("already_under_docker", [])
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800238 if not use_docker:
239 _check_compiler(compiler, ['default'])
240
241 if compiler == 'gcc4.9' or compiler == 'default':
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800242 return ('jessie', [])
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800243 elif compiler == 'gcc4.4':
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800244 return ('squeeze', [])
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800245 elif compiler == 'gcc5.3':
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800246 return ('ubuntu1604', [])
247 elif compiler == 'clang3.4':
248 return ('ubuntu1404', self._clang_make_options())
249 elif compiler == 'clang3.6':
250 return ('ubuntu1604', self._clang_make_options())
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800251 else:
252 raise Exception('Compiler %s not supported.' % compiler)
253
Jan Tattermusch77db4322016-02-20 20:19:35 -0800254 def dockerfile_dir(self):
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800255 return 'tools/dockerfile/test/cxx_%s_%s' % (self._docker_distro,
256 _docker_arch_suffix(self.args.arch))
Jan Tattermusch788ee232016-01-26 12:19:44 -0800257
murgatroid99132ce6a2015-03-04 17:29:14 -0800258 def __str__(self):
259 return self.make_target
260
Craig Tillercc0535d2015-12-08 15:14:47 -0800261
murgatroid992c8d5162015-01-26 10:41:21 -0800262class NodeLanguage(object):
263
Jan Tattermusche477b842016-02-06 22:19:01 -0800264 def __init__(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800265 self.platform = platform_string()
Jan Tattermusche477b842016-02-06 22:19:01 -0800266 self.node_version = '0.12'
267
Jan Tattermusch77db4322016-02-20 20:19:35 -0800268 def configure(self, config, args):
269 self.config = config
270 self.args = args
271 _check_compiler(self.args.compiler, ['default'])
272
273 def test_specs(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800274 if self.platform == 'windows':
Jan Tattermusch77db4322016-02-20 20:19:35 -0800275 return [self.config.job_spec(['tools\\run_tests\\run_node.bat'], None)]
Michael Lumishaaa876a2016-02-10 15:27:58 -0800276 else:
Jan Tattermusch77db4322016-02-20 20:19:35 -0800277 return [self.config.job_spec(['tools/run_tests/run_node.sh', self.node_version],
278 None,
279 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
murgatroid992c8d5162015-01-26 10:41:21 -0800280
murgatroid99256d3df2015-09-21 16:58:02 -0700281 def pre_build_steps(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800282 if self.platform == 'windows':
283 return [['tools\\run_tests\\pre_build_node.bat']]
284 else:
285 return [['tools/run_tests/pre_build_node.sh', self.node_version]]
murgatroid99256d3df2015-09-21 16:58:02 -0700286
Jan Tattermusch77db4322016-02-20 20:19:35 -0800287 def make_targets(self):
murgatroid99db5b1602015-10-01 13:20:11 -0700288 return []
murgatroid992c8d5162015-01-26 10:41:21 -0800289
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800290 def make_options(self):
291 return []
292
murgatroid992c8d5162015-01-26 10:41:21 -0800293 def build_steps(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800294 if self.platform == 'windows':
295 return [['tools\\run_tests\\build_node.bat']]
296 else:
297 return [['tools/run_tests/build_node.sh', self.node_version]]
Craig Tillerc7449162015-01-16 14:42:10 -0800298
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200299 def post_tests_steps(self):
Michael Lumish60d38cb2016-03-04 13:05:04 -0800300 return []
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200301
murgatroid99a3e244f2015-09-22 11:25:53 -0700302 def makefile_name(self):
303 return 'Makefile'
304
Jan Tattermusch77db4322016-02-20 20:19:35 -0800305 def dockerfile_dir(self):
306 return 'tools/dockerfile/test/node_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800307
murgatroid99132ce6a2015-03-04 17:29:14 -0800308 def __str__(self):
309 return 'node'
310
Craig Tiller99775822015-01-30 13:07:16 -0800311
Craig Tillerc7449162015-01-16 14:42:10 -0800312class PhpLanguage(object):
313
Jan Tattermusch77db4322016-02-20 20:19:35 -0800314 def configure(self, config, args):
315 self.config = config
316 self.args = args
317 _check_compiler(self.args.compiler, ['default'])
318
319 def test_specs(self):
320 return [self.config.job_spec(['src/php/bin/run_tests.sh'], None,
321 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
Craig Tillerc7449162015-01-16 14:42:10 -0800322
murgatroid99256d3df2015-09-21 16:58:02 -0700323 def pre_build_steps(self):
324 return []
325
Jan Tattermusch77db4322016-02-20 20:19:35 -0800326 def make_targets(self):
Craig Tilleraf7cf542015-05-22 10:07:34 -0700327 return ['static_c', 'shared_c']
Craig Tillerc7449162015-01-16 14:42:10 -0800328
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800329 def make_options(self):
330 return []
331
Craig Tillerc7449162015-01-16 14:42:10 -0800332 def build_steps(self):
333 return [['tools/run_tests/build_php.sh']]
334
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200335 def post_tests_steps(self):
Stanley Cheunga6b95482016-01-13 16:10:48 -0800336 return [['tools/run_tests/post_tests_php.sh']]
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200337
murgatroid99a3e244f2015-09-22 11:25:53 -0700338 def makefile_name(self):
339 return 'Makefile'
340
Jan Tattermusch77db4322016-02-20 20:19:35 -0800341 def dockerfile_dir(self):
342 return 'tools/dockerfile/test/php_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800343
murgatroid99132ce6a2015-03-04 17:29:14 -0800344 def __str__(self):
345 return 'php'
346
Craig Tillerc7449162015-01-16 14:42:10 -0800347
Nathaniel Manista840615e2015-01-22 20:31:47 +0000348class PythonLanguage(object):
349
Craig Tiller49f61322015-03-03 13:02:11 -0800350 def __init__(self):
Masood Malekghassemi2b841622015-07-28 17:39:02 -0700351 self._build_python_versions = ['2.7']
Masood Malekghassemie5f70022015-06-29 09:20:26 -0700352 self._has_python_versions = []
Craig Tiller49f61322015-03-03 13:02:11 -0800353
Jan Tattermusch77db4322016-02-20 20:19:35 -0800354 def configure(self, config, args):
355 self.config = config
356 self.args = args
357 _check_compiler(self.args.compiler, ['default'])
358
359 def test_specs(self):
Jan Tattermusch072ebaa2016-03-01 18:33:12 -0800360 # load list of known test suites
361 with open('src/python/grpcio/tests/tests.json') as tests_json_file:
362 tests_json = json.load(tests_json_file)
Masood Malekghassemi2b841622015-07-28 17:39:02 -0700363 environment = dict(_FORCE_ENVIRON_FOR_WRAPPERS)
364 environment['PYVER'] = '2.7'
Jan Tattermusch072ebaa2016-03-01 18:33:12 -0800365 if self.config.build_config != 'gcov':
366 return [self.config.job_spec(
367 ['tools/run_tests/run_python.sh'],
368 None,
369 environ=dict(environment.items() +
Masood Malekghassemif7ff8be2016-03-09 15:27:28 -0800370 [('GRPC_PYTHON_TESTRUNNER_FILTER', suite_name)]),
Jan Tattermusch072ebaa2016-03-01 18:33:12 -0800371 shortname='py.test.%s' % suite_name,
372 timeout_seconds=5*60)
373 for suite_name in tests_json]
374 else:
375 return [self.config.job_spec(['tools/run_tests/run_python.sh'],
376 None,
377 environ=environment,
378 shortname='py.test.coverage',
379 timeout_seconds=15*60)]
380
Nathaniel Manista840615e2015-01-22 20:31:47 +0000381
murgatroid99256d3df2015-09-21 16:58:02 -0700382 def pre_build_steps(self):
383 return []
384
Jan Tattermusch77db4322016-02-20 20:19:35 -0800385 def make_targets(self):
Craig Tilleraf7cf542015-05-22 10:07:34 -0700386 return ['static_c', 'grpc_python_plugin', 'shared_c']
Nathaniel Manista840615e2015-01-22 20:31:47 +0000387
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800388 def make_options(self):
389 return []
390
Nathaniel Manista840615e2015-01-22 20:31:47 +0000391 def build_steps(self):
Masood Malekghassemie5f70022015-06-29 09:20:26 -0700392 commands = []
393 for python_version in self._build_python_versions:
394 try:
395 with open(os.devnull, 'w') as output:
396 subprocess.check_call(['which', 'python' + python_version],
397 stdout=output, stderr=output)
398 commands.append(['tools/run_tests/build_python.sh', python_version])
399 self._has_python_versions.append(python_version)
400 except:
401 jobset.message('WARNING', 'Missing Python ' + python_version,
402 do_newline=True)
403 return commands
Nathaniel Manista840615e2015-01-22 20:31:47 +0000404
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200405 def post_tests_steps(self):
406 return []
407
murgatroid99a3e244f2015-09-22 11:25:53 -0700408 def makefile_name(self):
409 return 'Makefile'
410
Jan Tattermusch77db4322016-02-20 20:19:35 -0800411 def dockerfile_dir(self):
412 return 'tools/dockerfile/test/python_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800413
murgatroid99132ce6a2015-03-04 17:29:14 -0800414 def __str__(self):
415 return 'python'
416
Craig Tillerd625d812015-04-08 15:52:35 -0700417
murgatroid996a4c4fa2015-02-27 12:08:57 -0800418class RubyLanguage(object):
419
Jan Tattermusch77db4322016-02-20 20:19:35 -0800420 def configure(self, config, args):
421 self.config = config
422 self.args = args
423 _check_compiler(self.args.compiler, ['default'])
424
425 def test_specs(self):
426 return [self.config.job_spec(['tools/run_tests/run_ruby.sh'], None,
427 timeout_seconds=10*60,
428 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
murgatroid996a4c4fa2015-02-27 12:08:57 -0800429
murgatroid99256d3df2015-09-21 16:58:02 -0700430 def pre_build_steps(self):
Nicolas "Pixel" Noblebcf988f2015-10-08 03:00:42 +0200431 return [['tools/run_tests/pre_build_ruby.sh']]
murgatroid99256d3df2015-09-21 16:58:02 -0700432
Jan Tattermusch4651bef2016-02-23 08:31:25 -0800433 def make_targets(self):
murgatroid997d243df2016-02-18 09:58:05 -0800434 return []
murgatroid996a4c4fa2015-02-27 12:08:57 -0800435
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800436 def make_options(self):
437 return []
438
murgatroid996a4c4fa2015-02-27 12:08:57 -0800439 def build_steps(self):
440 return [['tools/run_tests/build_ruby.sh']]
441
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200442 def post_tests_steps(self):
Nicolas "Pixel" Noble7ef1e532015-12-02 00:55:33 +0100443 return [['tools/run_tests/post_tests_ruby.sh']]
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200444
murgatroid99a3e244f2015-09-22 11:25:53 -0700445 def makefile_name(self):
446 return 'Makefile'
447
Jan Tattermusch77db4322016-02-20 20:19:35 -0800448 def dockerfile_dir(self):
449 return 'tools/dockerfile/test/ruby_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800450
murgatroid99132ce6a2015-03-04 17:29:14 -0800451 def __str__(self):
452 return 'ruby'
453
Craig Tillerd625d812015-04-08 15:52:35 -0700454
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800455class CSharpLanguage(object):
Jan Tattermusch77db4322016-02-20 20:19:35 -0800456
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700457 def __init__(self):
Craig Tillerd50993d2015-08-05 08:04:36 -0700458 self.platform = platform_string()
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700459
Jan Tattermusch77db4322016-02-20 20:19:35 -0800460 def configure(self, config, args):
461 self.config = config
462 self.args = args
463 _check_compiler(self.args.compiler, ['default'])
464
465 def test_specs(self):
Jan Tattermusch03c01062015-12-11 14:28:56 -0800466 with open('src/csharp/tests.json') as f:
467 tests_json = json.load(f)
468 assemblies = tests_json['assemblies']
469 tests = tests_json['tests']
470
Jan Tattermuscha2d964c2016-02-22 17:33:09 -0800471 msbuild_config = _MSBUILD_CONFIG[self.config.build_config]
Jan Tattermusch03c01062015-12-11 14:28:56 -0800472 assembly_files = ['%s/bin/%s/%s.dll' % (a, msbuild_config, a)
473 for a in assemblies]
474
475 extra_args = ['-labels'] + assembly_files
476
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700477 if self.platform == 'windows':
Jan Tattermusch03c01062015-12-11 14:28:56 -0800478 script_name = 'tools\\run_tests\\run_csharp.bat'
479 extra_args += ['-domain=None']
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700480 else:
Jan Tattermusch03c01062015-12-11 14:28:56 -0800481 script_name = 'tools/run_tests/run_csharp.sh'
Jan Tattermuschbf3b1532015-10-26 10:24:42 -0700482
Jan Tattermusch77db4322016-02-20 20:19:35 -0800483 if self.config.build_config == 'gcov':
Jan Tattermuschbdf4b2e2015-10-28 08:22:34 -0700484 # On Windows, we only collect C# code coverage.
485 # On Linux, we only collect coverage for native extension.
486 # For code coverage all tests need to run as one suite.
Jan Tattermusch77db4322016-02-20 20:19:35 -0800487 return [self.config.job_spec([script_name] + extra_args, None,
488 shortname='csharp.coverage',
489 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
Jan Tattermusch61c3a832015-10-27 17:54:50 -0700490 else:
Jan Tattermusch03c01062015-12-11 14:28:56 -0800491 specs = []
492 for test in tests:
493 cmdline = [script_name, '-run=%s' % test] + extra_args
494 if self.platform == 'windows':
495 # use different output directory for each test to prevent
496 # TestResult.xml clash between parallel test runs.
497 cmdline += ['-work=test-result/%s' % uuid.uuid4()]
Jan Tattermusch77db4322016-02-20 20:19:35 -0800498 specs.append(self.config.job_spec(cmdline, None,
499 shortname='csharp.%s' % test,
500 environ=_FORCE_ENVIRON_FOR_WRAPPERS))
Jan Tattermusch03c01062015-12-11 14:28:56 -0800501 return specs
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800502
murgatroid99256d3df2015-09-21 16:58:02 -0700503 def pre_build_steps(self):
Jan Tattermusch48423fc2015-10-07 18:59:16 -0700504 if self.platform == 'windows':
Jan Tattermusch874aec02015-10-07 19:26:19 -0700505 return [['tools\\run_tests\\pre_build_csharp.bat']]
Jan Tattermusch48423fc2015-10-07 18:59:16 -0700506 else:
507 return [['tools/run_tests/pre_build_csharp.sh']]
murgatroid99256d3df2015-09-21 16:58:02 -0700508
Jan Tattermusch77db4322016-02-20 20:19:35 -0800509 def make_targets(self):
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700510 # For Windows, this target doesn't really build anything,
511 # everything is build by buildall script later.
Craig Tillerd5904822015-08-31 21:30:58 -0700512 if self.platform == 'windows':
513 return []
514 else:
515 return ['grpc_csharp_ext']
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800516
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800517 def make_options(self):
518 if self.platform == 'mac':
519 # On Mac, official distribution of mono is 32bit.
520 return ['CFLAGS=-arch i386', 'LDFLAGS=-arch i386']
521 else:
522 return []
523
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800524 def build_steps(self):
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700525 if self.platform == 'windows':
526 return [['src\\csharp\\buildall.bat']]
527 else:
528 return [['tools/run_tests/build_csharp.sh']]
Nathaniel Manista840615e2015-01-22 20:31:47 +0000529
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200530 def post_tests_steps(self):
531 return []
532
murgatroid99a3e244f2015-09-22 11:25:53 -0700533 def makefile_name(self):
534 return 'Makefile'
535
Jan Tattermusch77db4322016-02-20 20:19:35 -0800536 def dockerfile_dir(self):
537 return 'tools/dockerfile/test/csharp_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800538
murgatroid99132ce6a2015-03-04 17:29:14 -0800539 def __str__(self):
540 return 'csharp'
541
Craig Tillerd625d812015-04-08 15:52:35 -0700542
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700543class ObjCLanguage(object):
544
Jan Tattermusch77db4322016-02-20 20:19:35 -0800545 def configure(self, config, args):
546 self.config = config
547 self.args = args
548 _check_compiler(self.args.compiler, ['default'])
549
550 def test_specs(self):
551 return [self.config.job_spec(['src/objective-c/tests/run_tests.sh'], None,
552 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700553
murgatroid99256d3df2015-09-21 16:58:02 -0700554 def pre_build_steps(self):
555 return []
556
Jan Tattermusch77db4322016-02-20 20:19:35 -0800557 def make_targets(self):
Jorge Canizalesd0b32e92015-07-30 23:08:43 -0700558 return ['grpc_objective_c_plugin', 'interop_server']
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700559
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800560 def make_options(self):
561 return []
562
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700563 def build_steps(self):
Jorge Canizalesd0b32e92015-07-30 23:08:43 -0700564 return [['src/objective-c/tests/build_tests.sh']]
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700565
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200566 def post_tests_steps(self):
567 return []
568
murgatroid99a3e244f2015-09-22 11:25:53 -0700569 def makefile_name(self):
570 return 'Makefile'
571
Jan Tattermusch77db4322016-02-20 20:19:35 -0800572 def dockerfile_dir(self):
Jan Tattermusch788ee232016-01-26 12:19:44 -0800573 return None
574
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700575 def __str__(self):
576 return 'objc'
577
578
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100579class Sanity(object):
580
Jan Tattermusch77db4322016-02-20 20:19:35 -0800581 def configure(self, config, args):
582 self.config = config
583 self.args = args
584 _check_compiler(self.args.compiler, ['default'])
585
586 def test_specs(self):
Craig Tiller94d04a52016-01-20 10:58:23 -0800587 import yaml
Jan Tattermusch788ee232016-01-26 12:19:44 -0800588 with open('tools/run_tests/sanity/sanity_tests.yaml', 'r') as f:
Jan Tattermusch77db4322016-02-20 20:19:35 -0800589 return [self.config.job_spec(cmd['script'].split(), None,
590 timeout_seconds=None, environ={'TEST': 'true'},
591 cpu_cost=cmd.get('cpu_cost', 1))
Craig Tiller94d04a52016-01-20 10:58:23 -0800592 for cmd in yaml.load(f)]
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100593
murgatroid99256d3df2015-09-21 16:58:02 -0700594 def pre_build_steps(self):
595 return []
596
Jan Tattermusch77db4322016-02-20 20:19:35 -0800597 def make_targets(self):
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100598 return ['run_dep_checks']
599
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800600 def make_options(self):
601 return []
602
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100603 def build_steps(self):
604 return []
605
Nicolas "Pixel" Noble87879b32015-10-12 23:28:53 +0200606 def post_tests_steps(self):
607 return []
608
murgatroid99a3e244f2015-09-22 11:25:53 -0700609 def makefile_name(self):
610 return 'Makefile'
611
Jan Tattermusch77db4322016-02-20 20:19:35 -0800612 def dockerfile_dir(self):
Jan Tattermusche70b3c52016-02-07 20:21:02 -0800613 return 'tools/dockerfile/test/sanity'
Jan Tattermusch788ee232016-01-26 12:19:44 -0800614
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100615 def __str__(self):
616 return 'sanity'
617
Nicolas "Pixel" Noblee55cd7f2015-04-14 17:59:13 +0200618
Craig Tiller738c3342015-01-12 14:28:33 -0800619# different configurations we can run under
Craig Tillera0f85172016-01-20 15:56:06 -0800620with open('tools/run_tests/configs.json') as f:
Craig Tiller1dce9062016-01-20 17:01:56 -0800621 _CONFIGS = dict((cfg['config'], Config(**cfg)) for cfg in ast.literal_eval(f.read()))
Craig Tiller738c3342015-01-12 14:28:33 -0800622
623
Craig Tillerc7449162015-01-16 14:42:10 -0800624_LANGUAGES = {
Craig Tillere9c959d2015-01-18 10:23:26 -0800625 'c++': CLanguage('cxx', 'c++'),
626 'c': CLanguage('c', 'c'),
murgatroid992c8d5162015-01-26 10:41:21 -0800627 'node': NodeLanguage(),
Nathaniel Manista840615e2015-01-22 20:31:47 +0000628 'php': PhpLanguage(),
629 'python': PythonLanguage(),
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800630 'ruby': RubyLanguage(),
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100631 'csharp': CSharpLanguage(),
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700632 'objc' : ObjCLanguage(),
Jan Tattermusch70a57e42016-02-20 18:50:27 -0800633 'sanity': Sanity()
Craig Tillereb272bc2015-01-30 13:13:14 -0800634 }
Nicolas Nobleddef2462015-01-06 18:08:25 -0800635
Jan Tattermusch77db4322016-02-20 20:19:35 -0800636
Jan Tattermuscha2d964c2016-02-22 17:33:09 -0800637_MSBUILD_CONFIG = {
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700638 'dbg': 'Debug',
639 'opt': 'Release',
Jan Tattermusche4a69182015-12-15 09:53:01 -0800640 'gcov': 'Debug',
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700641 }
642
David Garcia Quintase90cd372015-05-31 18:15:26 -0700643
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800644def _windows_arch_option(arch):
645 """Returns msbuild cmdline option for selected architecture."""
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800646 if arch == 'default' or arch == 'x86':
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800647 return '/p:Platform=Win32'
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800648 elif arch == 'x64':
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800649 return '/p:Platform=x64'
650 else:
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800651 print 'Architecture %s not supported.' % arch
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800652 sys.exit(1)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800653
Jan Tattermuschf08018a2016-01-26 08:22:09 -0800654
655def _check_arch_option(arch):
656 """Checks that architecture option is valid."""
657 if platform_string() == 'windows':
658 _windows_arch_option(arch)
659 elif platform_string() == 'linux':
660 # On linux, we need to be running under docker with the right architecture.
Jan Tattermusch07fb0422016-01-26 10:46:56 -0800661 runtime_arch = platform.architecture()[0]
Jan Tattermuschf08018a2016-01-26 08:22:09 -0800662 if arch == 'default':
663 return
664 elif runtime_arch == '64bit' and arch == 'x64':
665 return
666 elif runtime_arch == '32bit' and arch == 'x86':
667 return
668 else:
669 print 'Architecture %s does not match current runtime architecture.' % arch
670 sys.exit(1)
671 else:
672 if args.arch != 'default':
673 print 'Architecture %s not supported on current platform.' % args.arch
674 sys.exit(1)
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800675
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800676
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800677def _windows_build_bat(compiler):
678 """Returns name of build.bat for selected compiler."""
679 if compiler == 'default' or compiler == 'vs2013':
680 return 'vsprojects\\build_vs2013.bat'
681 elif compiler == 'vs2015':
682 return 'vsprojects\\build_vs2015.bat'
683 elif compiler == 'vs2010':
684 return 'vsprojects\\build_vs2010.bat'
685 else:
686 print 'Compiler %s not supported.' % compiler
687 sys.exit(1)
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800688
689
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800690def _windows_toolset_option(compiler):
691 """Returns msbuild PlatformToolset for selected compiler."""
692 if compiler == 'default' or compiler == 'vs2013':
693 return '/p:PlatformToolset=v120'
694 elif compiler == 'vs2015':
695 return '/p:PlatformToolset=v140'
696 elif compiler == 'vs2010':
697 return '/p:PlatformToolset=v100'
698 else:
699 print 'Compiler %s not supported.' % compiler
700 sys.exit(1)
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800701
702
Jan Tattermusche70b3c52016-02-07 20:21:02 -0800703def _docker_arch_suffix(arch):
704 """Returns suffix to dockerfile dir to use."""
705 if arch == 'default' or arch == 'x64':
706 return 'x64'
707 elif arch == 'x86':
708 return 'x86'
709 else:
710 print 'Architecture %s not supported with current settings.' % arch
711 sys.exit(1)
712
713
David Garcia Quintase90cd372015-05-31 18:15:26 -0700714def runs_per_test_type(arg_str):
715 """Auxilary function to parse the "runs_per_test" flag.
716
717 Returns:
718 A positive integer or 0, the latter indicating an infinite number of
719 runs.
720
721 Raises:
722 argparse.ArgumentTypeError: Upon invalid input.
723 """
724 if arg_str == 'inf':
725 return 0
726 try:
727 n = int(arg_str)
728 if n <= 0: raise ValueError
Craig Tiller50e53e22015-06-01 20:18:21 -0700729 return n
David Garcia Quintase90cd372015-05-31 18:15:26 -0700730 except:
Adele Zhoue4c35612015-10-16 15:34:23 -0700731 msg = '\'{}\' is not a positive integer or \'inf\''.format(arg_str)
David Garcia Quintase90cd372015-05-31 18:15:26 -0700732 raise argparse.ArgumentTypeError(msg)
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700733
734# parse command line
735argp = argparse.ArgumentParser(description='Run grpc tests.')
736argp.add_argument('-c', '--config',
Jan Tattermusch77db4322016-02-20 20:19:35 -0800737 choices=sorted(_CONFIGS.keys()),
738 default='opt')
David Garcia Quintase90cd372015-05-31 18:15:26 -0700739argp.add_argument('-n', '--runs_per_test', default=1, type=runs_per_test_type,
740 help='A positive integer or "inf". If "inf", all tests will run in an '
741 'infinite loop. Especially useful in combination with "-f"')
Craig Tillerfe406ec2015-02-24 13:55:12 -0800742argp.add_argument('-r', '--regex', default='.*', type=str)
Craig Tiller5f735a62016-01-20 09:31:15 -0800743argp.add_argument('-j', '--jobs', default=multiprocessing.cpu_count(), type=int)
Craig Tiller8451e872015-02-27 09:25:51 -0800744argp.add_argument('-s', '--slowdown', default=1.0, type=float)
ctiller3040cb72015-01-07 12:13:17 -0800745argp.add_argument('-f', '--forever',
746 default=False,
747 action='store_const',
748 const=True)
Nicolas "Pixel" Noblea7df3f92015-02-26 22:07:04 +0100749argp.add_argument('-t', '--travis',
750 default=False,
751 action='store_const',
752 const=True)
Nicolas Noble044db742015-01-14 16:57:24 -0800753argp.add_argument('--newline_on_success',
754 default=False,
755 action='store_const',
756 const=True)
Craig Tiller686fb262015-01-15 07:39:09 -0800757argp.add_argument('-l', '--language',
Craig Tiller60f15e62015-05-13 09:05:17 -0700758 choices=['all'] + sorted(_LANGUAGES.keys()),
Craig Tiller686fb262015-01-15 07:39:09 -0800759 nargs='+',
Craig Tiller60f15e62015-05-13 09:05:17 -0700760 default=['all'])
Craig Tillercd43da82015-05-29 08:41:29 -0700761argp.add_argument('-S', '--stop_on_failure',
762 default=False,
763 action='store_const',
764 const=True)
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700765argp.add_argument('--use_docker',
766 default=False,
767 action='store_const',
768 const=True,
Adele Zhoue4c35612015-10-16 15:34:23 -0700769 help='Run all the tests under docker. That provides ' +
770 'additional isolation and prevents the need to install ' +
771 'language specific prerequisites. Only available on Linux.')
Craig Tillerd4509a12015-09-28 09:18:40 -0700772argp.add_argument('--allow_flakes',
773 default=False,
774 action='store_const',
775 const=True,
Adele Zhoue4c35612015-10-16 15:34:23 -0700776 help='Allow flaky tests to show as passing (re-runs failed tests up to five times)')
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800777argp.add_argument('--arch',
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800778 choices=['default', 'x86', 'x64'],
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800779 default='default',
780 help='Selects architecture to target. For some platforms "default" is the only supported choice.')
781argp.add_argument('--compiler',
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800782 choices=['default',
783 'gcc4.4', 'gcc4.9', 'gcc5.3',
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800784 'clang3.4', 'clang3.6',
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800785 'vs2010', 'vs2013', 'vs2015'],
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800786 default='default',
Jan Tattermusch77db4322016-02-20 20:19:35 -0800787 help='Selects compiler to use. Allowed values depend on the platform and language.')
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800788argp.add_argument('--build_only',
789 default=False,
790 action='store_const',
791 const=True,
792 help='Perform all the build steps but dont run any tests.')
Craig Tiller5f735a62016-01-20 09:31:15 -0800793argp.add_argument('--measure_cpu_costs', default=False, action='store_const', const=True,
794 help='Measure the cpu costs of tests')
Craig Tiller1676f912016-01-05 10:49:44 -0800795argp.add_argument('--update_submodules', default=[], nargs='*',
796 help='Update some submodules before building. If any are updated, also run generate_projects. ' +
797 'Submodules are specified as SUBMODULE_NAME:BRANCH; if BRANCH is omitted, master is assumed.')
Craig Tiller234b6e72015-05-23 10:12:40 -0700798argp.add_argument('-a', '--antagonists', default=0, type=int)
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +0200799argp.add_argument('-x', '--xml_report', default=None, type=str,
800 help='Generates a JUnit-compatible XML report')
Nicolas Nobleddef2462015-01-06 18:08:25 -0800801args = argp.parse_args()
802
Craig Tiller5f735a62016-01-20 09:31:15 -0800803jobset.measure_cpu_costs = args.measure_cpu_costs
804
Craig Tiller1676f912016-01-05 10:49:44 -0800805# update submodules if necessary
Craig Tillerb361b4e2016-01-06 11:44:17 -0800806need_to_regenerate_projects = False
807for spec in args.update_submodules:
808 spec = spec.split(':', 1)
809 if len(spec) == 1:
810 submodule = spec[0]
811 branch = 'master'
812 elif len(spec) == 2:
813 submodule = spec[0]
814 branch = spec[1]
815 cwd = 'third_party/%s' % submodule
816 def git(cmd, cwd=cwd):
817 print 'in %s: git %s' % (cwd, cmd)
818 subprocess.check_call('git %s' % cmd, cwd=cwd, shell=True)
819 git('fetch')
820 git('checkout %s' % branch)
821 git('pull origin %s' % branch)
822 if os.path.exists('src/%s/gen_build_yaml.py' % submodule):
823 need_to_regenerate_projects = True
824if need_to_regenerate_projects:
825 if jobset.platform_string() == 'linux':
826 subprocess.check_call('tools/buildgen/generate_projects.sh', shell=True)
827 else:
828 print 'WARNING: may need to regenerate projects, but since we are not on'
829 print ' Linux this step is being skipped. Compilation MAY fail.'
Craig Tiller1676f912016-01-05 10:49:44 -0800830
831
Nicolas Nobleddef2462015-01-06 18:08:25 -0800832# grab config
Jan Tattermusch77db4322016-02-20 20:19:35 -0800833run_config = _CONFIGS[args.config]
834build_config = run_config.build_config
Craig Tillerf1973b02015-01-16 12:32:13 -0800835
Craig Tiller06805272015-06-11 14:46:47 -0700836if args.travis:
murgatroid99d3b5b7f2015-10-06 17:02:03 -0700837 _FORCE_ENVIRON_FOR_WRAPPERS = {'GRPC_TRACE': 'api'}
Craig Tiller06805272015-06-11 14:46:47 -0700838
Adele Zhou6b9527c2015-11-20 15:56:35 -0800839if 'all' in args.language:
Craig Tiller1676f912016-01-05 10:49:44 -0800840 lang_list = _LANGUAGES.keys()
Adele Zhou6b9527c2015-11-20 15:56:35 -0800841else:
842 lang_list = args.language
Craig Tiller16900662016-01-07 19:30:54 -0800843# We don't support code coverage on some languages
844if 'gcov' in args.config:
Jan Tattermusch3b5121b2016-02-22 17:41:05 -0800845 for bad in ['objc', 'sanity']:
Craig Tiller16900662016-01-07 19:30:54 -0800846 if bad in lang_list:
847 lang_list.remove(bad)
Adele Zhou6b9527c2015-11-20 15:56:35 -0800848
849languages = set(_LANGUAGES[l] for l in lang_list)
Jan Tattermusch77db4322016-02-20 20:19:35 -0800850for l in languages:
851 l.configure(run_config, args)
murgatroid99132ce6a2015-03-04 17:29:14 -0800852
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800853language_make_options=[]
854if any(language.make_options() for language in languages):
855 if len(languages) != 1:
856 print 'languages with custom make options cannot be built simultaneously with other languages'
857 sys.exit(1)
858 else:
859 language_make_options = next(iter(languages)).make_options()
860
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800861if args.use_docker:
862 if not args.travis:
863 print 'Seen --use_docker flag, will run tests under docker.'
864 print
865 print 'IMPORTANT: The changes you are testing need to be locally committed'
866 print 'because only the committed changes in the current branch will be'
867 print 'copied to the docker environment.'
868 time.sleep(5)
869
Jan Tattermusch3b5121b2016-02-22 17:41:05 -0800870 dockerfile_dirs = set([l.dockerfile_dir() for l in languages])
871 if len(dockerfile_dirs) > 1:
Adele Zhou9506ef22016-03-02 13:53:34 -0800872 if 'gcov' in args.config:
873 dockerfile_dir = 'tools/dockerfile/test/multilang_jessie_x64'
874 print ('Using multilang_jessie_x64 docker image for code coverage for '
875 'all languages.')
876 else:
877 print ('Languages to be tested require running under different docker '
878 'images.')
879 sys.exit(1)
880 else:
881 dockerfile_dir = next(iter(dockerfile_dirs))
882
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800883 child_argv = [ arg for arg in sys.argv if not arg == '--use_docker' ]
Jan Tattermusched342b12016-01-26 14:40:31 -0800884 run_tests_cmd = 'python tools/run_tests/run_tests.py %s' % ' '.join(child_argv[1:])
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800885
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800886 env = os.environ.copy()
887 env['RUN_TESTS_COMMAND'] = run_tests_cmd
Jan Tattermusch3b5121b2016-02-22 17:41:05 -0800888 env['DOCKERFILE_DIR'] = dockerfile_dir
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800889 env['DOCKER_RUN_SCRIPT'] = 'tools/jenkins/docker_run_tests.sh'
890 if args.xml_report:
891 env['XML_REPORT'] = args.xml_report
892 if not args.travis:
893 env['TTY_FLAG'] = '-t' # enables Ctrl-C when not on Jenkins.
894
895 subprocess.check_call(['tools/jenkins/build_docker_and_run_tests.sh'],
896 shell=True,
897 env=env)
898 sys.exit(0)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800899
Jan Tattermuschf08018a2016-01-26 08:22:09 -0800900_check_arch_option(args.arch)
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800901
Jan Tattermuschfba65302016-01-25 18:21:14 -0800902def make_jobspec(cfg, targets, makefile='Makefile'):
903 if platform_string() == 'windows':
Craig Tillerfc3c0c42015-09-01 16:47:54 -0700904 extra_args = []
Craig Tillerb5391e12015-09-03 14:35:18 -0700905 # better do parallel compilation
Jan Tattermusch47eeb2b2015-10-07 14:09:18 -0700906 # empirically /m:2 gives the best performance/price and should prevent
907 # overloading the windows workers.
Adele Zhoue4c35612015-10-16 15:34:23 -0700908 extra_args.extend(['/m:2'])
Craig Tillerb5391e12015-09-03 14:35:18 -0700909 # disable PDB generation: it's broken, and we don't need it during CI
Adele Zhoue4c35612015-10-16 15:34:23 -0700910 extra_args.extend(['/p:Jenkins=true'])
Craig Tiller6fd23842015-09-01 07:36:31 -0700911 return [
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800912 jobset.JobSpec([_windows_build_bat(args.compiler),
murgatroid99cf08daf2015-09-21 15:33:16 -0700913 'vsprojects\\%s.sln' % target,
Jan Tattermuscha2d964c2016-02-22 17:33:09 -0800914 '/p:Configuration=%s' % _MSBUILD_CONFIG[cfg]] +
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800915 extra_args +
916 language_make_options,
Craig Tiller590105a2016-01-19 13:03:46 -0800917 shell=True, timeout_seconds=None)
Craig Tiller6fd23842015-09-01 07:36:31 -0700918 for target in targets]
Jan Tattermuschfba65302016-01-25 18:21:14 -0800919 else:
murgatroid998ae409f2015-10-26 16:39:00 -0700920 if targets:
921 return [jobset.JobSpec([os.getenv('MAKE', 'make'),
922 '-f', makefile,
Craig Tillerdd6f7ed2016-01-21 12:54:42 -0800923 '-j', '%d' % args.jobs,
Craig Tiller71a86042016-01-15 14:59:58 -0800924 'EXTRA_DEFINES=GRPC_TEST_SLOWDOWN_MACHINE_FACTOR=%f' % args.slowdown,
925 'CONFIG=%s' % cfg] +
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800926 language_make_options +
Craig Tiller71a86042016-01-15 14:59:58 -0800927 ([] if not args.travis else ['JENKINS_BUILD=1']) +
928 targets,
Craig Tiller590105a2016-01-19 13:03:46 -0800929 timeout_seconds=None)]
murgatroid998ae409f2015-10-26 16:39:00 -0700930 else:
931 return []
Jan Tattermuschfba65302016-01-25 18:21:14 -0800932
murgatroid99a3e244f2015-09-22 11:25:53 -0700933make_targets = {}
934for l in languages:
935 makefile = l.makefile_name()
936 make_targets[makefile] = make_targets.get(makefile, set()).union(
Jan Tattermusch77db4322016-02-20 20:19:35 -0800937 set(l.make_targets()))
Craig Tiller5058c692015-04-08 09:42:04 -0700938
Jan Tattermusche4a69182015-12-15 09:53:01 -0800939def build_step_environ(cfg):
940 environ = {'CONFIG': cfg}
Jan Tattermuscha2d964c2016-02-22 17:33:09 -0800941 msbuild_cfg = _MSBUILD_CONFIG.get(cfg)
Jan Tattermusche4a69182015-12-15 09:53:01 -0800942 if msbuild_cfg:
943 environ['MSBUILD_CONFIG'] = msbuild_cfg
944 return environ
945
murgatroid99fddac962015-09-22 09:20:11 -0700946build_steps = list(set(
Jan Tattermusch77db4322016-02-20 20:19:35 -0800947 jobset.JobSpec(cmdline, environ=build_step_environ(build_config), flake_retries=5)
murgatroid99256d3df2015-09-21 16:58:02 -0700948 for l in languages
949 for cmdline in l.pre_build_steps()))
Craig Tillerbd4e3782015-09-01 06:48:55 -0700950if make_targets:
Jan Tattermusch77db4322016-02-20 20:19:35 -0800951 make_commands = itertools.chain.from_iterable(make_jobspec(build_config, list(targets), makefile) for (makefile, targets) in make_targets.iteritems())
Craig Tiller6fd23842015-09-01 07:36:31 -0700952 build_steps.extend(set(make_commands))
Craig Tiller5058c692015-04-08 09:42:04 -0700953build_steps.extend(set(
Jan Tattermusch77db4322016-02-20 20:19:35 -0800954 jobset.JobSpec(cmdline, environ=build_step_environ(build_config), timeout_seconds=None)
Craig Tiller547db2b2015-01-30 14:08:39 -0800955 for l in languages
Craig Tiller533b1a22015-05-29 08:41:29 -0700956 for cmdline in l.build_steps()))
Craig Tillerf1973b02015-01-16 12:32:13 -0800957
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200958post_tests_steps = list(set(
Jan Tattermusch77db4322016-02-20 20:19:35 -0800959 jobset.JobSpec(cmdline, environ=build_step_environ(build_config))
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200960 for l in languages
961 for cmdline in l.post_tests_steps()))
Nicolas Nobleddef2462015-01-06 18:08:25 -0800962runs_per_test = args.runs_per_test
ctiller3040cb72015-01-07 12:13:17 -0800963forever = args.forever
Nicolas Nobleddef2462015-01-06 18:08:25 -0800964
Nicolas Nobleddef2462015-01-06 18:08:25 -0800965
Craig Tiller71735182015-01-15 17:07:13 -0800966class TestCache(object):
Craig Tillerb50d1662015-01-15 17:28:21 -0800967 """Cache for running tests."""
968
David Klempner25739582015-02-11 15:57:32 -0800969 def __init__(self, use_cache_results):
Craig Tiller71735182015-01-15 17:07:13 -0800970 self._last_successful_run = {}
David Klempner25739582015-02-11 15:57:32 -0800971 self._use_cache_results = use_cache_results
Craig Tiller69cd2372015-06-11 09:38:09 -0700972 self._last_save = time.time()
Craig Tiller71735182015-01-15 17:07:13 -0800973
974 def should_run(self, cmdline, bin_hash):
Craig Tiller71735182015-01-15 17:07:13 -0800975 if cmdline not in self._last_successful_run:
976 return True
977 if self._last_successful_run[cmdline] != bin_hash:
978 return True
David Klempner25739582015-02-11 15:57:32 -0800979 if not self._use_cache_results:
980 return True
Craig Tiller71735182015-01-15 17:07:13 -0800981 return False
982
983 def finished(self, cmdline, bin_hash):
Craig Tiller547db2b2015-01-30 14:08:39 -0800984 self._last_successful_run[cmdline] = bin_hash
Craig Tiller69cd2372015-06-11 09:38:09 -0700985 if time.time() - self._last_save > 1:
986 self.save()
Craig Tiller71735182015-01-15 17:07:13 -0800987
988 def dump(self):
Craig Tillerb50d1662015-01-15 17:28:21 -0800989 return [{'cmdline': k, 'hash': v}
990 for k, v in self._last_successful_run.iteritems()]
Craig Tiller71735182015-01-15 17:07:13 -0800991
992 def parse(self, exdump):
993 self._last_successful_run = dict((o['cmdline'], o['hash']) for o in exdump)
994
995 def save(self):
996 with open('.run_tests_cache', 'w') as f:
Craig Tiller261dd982015-01-16 16:41:45 -0800997 f.write(json.dumps(self.dump()))
Craig Tiller69cd2372015-06-11 09:38:09 -0700998 self._last_save = time.time()
Craig Tiller71735182015-01-15 17:07:13 -0800999
Craig Tiller1cc11db2015-01-15 22:50:50 -08001000 def maybe_load(self):
1001 if os.path.exists('.run_tests_cache'):
1002 with open('.run_tests_cache') as f:
Craig Tiller261dd982015-01-16 16:41:45 -08001003 self.parse(json.loads(f.read()))
Craig Tiller71735182015-01-15 17:07:13 -08001004
1005
Craig Tillerf53d9c82015-08-04 14:19:43 -07001006def _start_port_server(port_server_port):
1007 # check if a compatible port server is running
1008 # if incompatible (version mismatch) ==> start a new one
1009 # if not running ==> start a new one
1010 # otherwise, leave it up
1011 try:
Craig Tillerfe4939f2015-10-06 12:55:36 -07001012 version = int(urllib2.urlopen(
1013 'http://localhost:%d/version_number' % port_server_port,
1014 timeout=1).read())
1015 print 'detected port server running version %d' % version
Craig Tillerf53d9c82015-08-04 14:19:43 -07001016 running = True
Craig Tillerfe4939f2015-10-06 12:55:36 -07001017 except Exception as e:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001018 print 'failed to detect port server: %s' % sys.exc_info()[0]
Craig Tillerfe4939f2015-10-06 12:55:36 -07001019 print e.strerror
Craig Tillerf53d9c82015-08-04 14:19:43 -07001020 running = False
1021 if running:
Craig Tillerfe4939f2015-10-06 12:55:36 -07001022 current_version = int(subprocess.check_output(
Jan Tattermusch3bd08272015-11-04 19:24:37 -08001023 [sys.executable, os.path.abspath('tools/run_tests/port_server.py'),
1024 'dump_version']))
Craig Tillerfe4939f2015-10-06 12:55:36 -07001025 print 'my port server is version %d' % current_version
1026 running = (version >= current_version)
1027 if not running:
1028 print 'port_server version mismatch: killing the old one'
1029 urllib2.urlopen('http://localhost:%d/quitquitquit' % port_server_port).read()
1030 time.sleep(1)
Craig Tillerf53d9c82015-08-04 14:19:43 -07001031 if not running:
Craig Tillerf0a293e2015-10-12 10:05:50 -07001032 fd, logfile = tempfile.mkstemp()
1033 os.close(fd)
1034 print 'starting port_server, with log file %s' % logfile
Jan Tattermusch3bd08272015-11-04 19:24:37 -08001035 args = [sys.executable, os.path.abspath('tools/run_tests/port_server.py'),
1036 '-p', '%d' % port_server_port, '-l', logfile]
Craig Tiller367d41d2015-10-12 13:00:22 -07001037 env = dict(os.environ)
1038 env['BUILD_ID'] = 'pleaseDontKillMeJenkins'
Nicolas "Pixel" Noblef72d7b52015-12-03 03:07:43 +01001039 if platform_string() == 'windows':
Jan Tattermusch3bd08272015-11-04 19:24:37 -08001040 # Working directory of port server needs to be outside of Jenkins
1041 # workspace to prevent file lock issues.
1042 tempdir = tempfile.mkdtemp()
Craig Tillerd2c39712015-10-12 11:08:49 -07001043 port_server = subprocess.Popen(
Craig Tiller367d41d2015-10-12 13:00:22 -07001044 args,
1045 env=env,
Jan Tattermusch3bd08272015-11-04 19:24:37 -08001046 cwd=tempdir,
Craig Tiller367d41d2015-10-12 13:00:22 -07001047 creationflags = 0x00000008, # detached process
1048 close_fds=True)
Craig Tillerd2c39712015-10-12 11:08:49 -07001049 else:
1050 port_server = subprocess.Popen(
1051 args,
Craig Tiller367d41d2015-10-12 13:00:22 -07001052 env=env,
Craig Tillerd2c39712015-10-12 11:08:49 -07001053 preexec_fn=os.setsid,
1054 close_fds=True)
Craig Tillerf0a293e2015-10-12 10:05:50 -07001055 time.sleep(1)
Craig Tiller8b5f4dc2015-08-26 08:02:01 -07001056 # ensure port server is up
Craig Tillerabd37fd2015-08-26 07:54:01 -07001057 waits = 0
Craig Tillerf53d9c82015-08-04 14:19:43 -07001058 while True:
Craig Tillerabd37fd2015-08-26 07:54:01 -07001059 if waits > 10:
Craig Tillerf0a293e2015-10-12 10:05:50 -07001060 print 'killing port server due to excessive start up waits'
Craig Tillerabd37fd2015-08-26 07:54:01 -07001061 port_server.kill()
Craig Tillera2f38b02015-09-24 11:19:17 -07001062 if port_server.poll() is not None:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001063 print 'port_server failed to start'
Craig Tillerf0a293e2015-10-12 10:05:50 -07001064 # try one final time: maybe another build managed to start one
1065 time.sleep(1)
1066 try:
1067 urllib2.urlopen('http://localhost:%d/get' % port_server_port,
1068 timeout=1).read()
1069 print 'last ditch attempt to contact port server succeeded'
1070 break
1071 except:
Jan Tattermusch3b5121b2016-02-22 17:41:05 -08001072 traceback.print_exc()
Craig Tillerf0a293e2015-10-12 10:05:50 -07001073 port_log = open(logfile, 'r').read()
1074 print port_log
1075 sys.exit(1)
Craig Tillerf53d9c82015-08-04 14:19:43 -07001076 try:
Craig Tillerabd37fd2015-08-26 07:54:01 -07001077 urllib2.urlopen('http://localhost:%d/get' % port_server_port,
1078 timeout=1).read()
Craig Tillerf0a293e2015-10-12 10:05:50 -07001079 print 'port server is up and ready'
Craig Tillerf53d9c82015-08-04 14:19:43 -07001080 break
Craig Tiller31fdaa42015-09-25 13:09:59 -07001081 except socket.timeout:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001082 print 'waiting for port_server: timeout'
Craig Tillerf0a293e2015-10-12 10:05:50 -07001083 traceback.print_exc();
1084 time.sleep(1)
Craig Tiller31fdaa42015-09-25 13:09:59 -07001085 waits += 1
Craig Tillerf53d9c82015-08-04 14:19:43 -07001086 except urllib2.URLError:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001087 print 'waiting for port_server: urlerror'
Craig Tillerf0a293e2015-10-12 10:05:50 -07001088 traceback.print_exc();
1089 time.sleep(1)
Craig Tillerabd37fd2015-08-26 07:54:01 -07001090 waits += 1
Craig Tillerf53d9c82015-08-04 14:19:43 -07001091 except:
Jan Tattermusch3b5121b2016-02-22 17:41:05 -08001092 traceback.print_exc()
Craig Tillerf53d9c82015-08-04 14:19:43 -07001093 port_server.kill()
1094 raise
1095
1096
Adele Zhoud5fffa52015-10-23 15:51:42 -07001097def _calculate_num_runs_failures(list_of_results):
1098 """Caculate number of runs and failures for a particular test.
1099
1100 Args:
1101 list_of_results: (List) of JobResult object.
1102 Returns:
1103 A tuple of total number of runs and failures.
1104 """
1105 num_runs = len(list_of_results) # By default, there is 1 run per JobResult.
1106 num_failures = 0
1107 for jobresult in list_of_results:
1108 if jobresult.retries > 0:
1109 num_runs += jobresult.retries
1110 if jobresult.num_failures > 0:
1111 num_failures += jobresult.num_failures
1112 return num_runs, num_failures
1113
Adele Zhou6b9527c2015-11-20 15:56:35 -08001114
Craig Tillereb9de8b2016-01-08 08:57:41 -08001115# _build_and_run results
1116class BuildAndRunError(object):
1117
1118 BUILD = object()
1119 TEST = object()
1120 POST_TEST = object()
1121
1122
1123# returns a list of things that failed (or an empty list on success)
Craig Tillerf53d9c82015-08-04 14:19:43 -07001124def _build_and_run(
Jan Tattermusch2dd156e2015-12-04 18:26:17 -08001125 check_cancelled, newline_on_success, cache, xml_report=None, build_only=False):
ctiller3040cb72015-01-07 12:13:17 -08001126 """Do one pass of building & running tests."""
murgatroid99666450e2015-01-26 13:03:31 -08001127 # build latest sequentially
Jan Tattermuschaab1e512016-01-28 09:30:44 -08001128 num_failures, resultset = jobset.run(
Adele Zhoue4c35612015-10-16 15:34:23 -07001129 build_steps, maxjobs=1, stop_on_failure=True,
Craig Tiller883064c2015-11-04 10:06:10 -08001130 newline_on_success=newline_on_success, travis=args.travis)
Adele Zhoue4c35612015-10-16 15:34:23 -07001131 if num_failures:
Craig Tillereb9de8b2016-01-08 08:57:41 -08001132 return [BuildAndRunError.BUILD]
Craig Tillerb361b4e2016-01-06 11:44:17 -08001133
Jan Tattermusch2dd156e2015-12-04 18:26:17 -08001134 if build_only:
Jan Tattermuschaab1e512016-01-28 09:30:44 -08001135 if xml_report:
1136 report_utils.render_junit_xml_report(resultset, xml_report)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001137 return []
ctiller3040cb72015-01-07 12:13:17 -08001138
Craig Tiller234b6e72015-05-23 10:12:40 -07001139 # start antagonists
David Garcia Quintas79e389f2015-06-02 17:49:42 -07001140 antagonists = [subprocess.Popen(['tools/run_tests/antagonist.py'])
Craig Tiller234b6e72015-05-23 10:12:40 -07001141 for _ in range(0, args.antagonists)]
Craig Tillerfe4939f2015-10-06 12:55:36 -07001142 port_server_port = 32767
Craig Tillerf53d9c82015-08-04 14:19:43 -07001143 _start_port_server(port_server_port)
Adele Zhou7cf72112015-11-04 11:18:43 -08001144 resultset = None
Adele Zhou803af152015-11-30 15:16:16 -08001145 num_test_failures = 0
Craig Tiller234b6e72015-05-23 10:12:40 -07001146 try:
David Garcia Quintase90cd372015-05-31 18:15:26 -07001147 infinite_runs = runs_per_test == 0
yang-g6c1fdc62015-08-18 11:57:42 -07001148 one_run = set(
1149 spec
yang-g6c1fdc62015-08-18 11:57:42 -07001150 for language in languages
Jan Tattermusch77db4322016-02-20 20:19:35 -08001151 for spec in language.test_specs()
yang-g6c1fdc62015-08-18 11:57:42 -07001152 if re.search(args.regex, spec.shortname))
David Garcia Quintas79e389f2015-06-02 17:49:42 -07001153 # When running on travis, we want out test runs to be as similar as possible
1154 # for reproducibility purposes.
Craig Tiller883064c2015-11-04 10:06:10 -08001155 if args.travis:
David Garcia Quintas79e389f2015-06-02 17:49:42 -07001156 massaged_one_run = sorted(one_run, key=lambda x: x.shortname)
1157 else:
1158 # whereas otherwise, we want to shuffle things up to give all tests a
1159 # chance to run.
1160 massaged_one_run = list(one_run) # random.shuffle needs an indexable seq.
1161 random.shuffle(massaged_one_run) # which it modifies in-place.
Craig Tillerf7b7c892015-06-22 14:33:25 -07001162 if infinite_runs:
1163 assert len(massaged_one_run) > 0, 'Must have at least one test for a -n inf run'
David Garcia Quintas79e389f2015-06-02 17:49:42 -07001164 runs_sequence = (itertools.repeat(massaged_one_run) if infinite_runs
1165 else itertools.repeat(massaged_one_run, runs_per_test))
David Garcia Quintase90cd372015-05-31 18:15:26 -07001166 all_runs = itertools.chain.from_iterable(runs_sequence)
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +02001167
Adele Zhou803af152015-11-30 15:16:16 -08001168 num_test_failures, resultset = jobset.run(
Adele Zhou2271ab52015-10-28 13:59:14 -07001169 all_runs, check_cancelled, newline_on_success=newline_on_success,
Craig Tiller883064c2015-11-04 10:06:10 -08001170 travis=args.travis, infinite_runs=infinite_runs, maxjobs=args.jobs,
murgatroid998ae409f2015-10-26 16:39:00 -07001171 stop_on_failure=args.stop_on_failure,
Adele Zhouf2ca7bc2015-10-23 15:38:00 -07001172 cache=cache if not xml_report else None,
Adele Zhouf2ca7bc2015-10-23 15:38:00 -07001173 add_env={'GRPC_TEST_PORT_SERVER': 'localhost:%d' % port_server_port})
Adele Zhoud5fffa52015-10-23 15:51:42 -07001174 if resultset:
1175 for k, v in resultset.iteritems():
1176 num_runs, num_failures = _calculate_num_runs_failures(v)
1177 if num_failures == num_runs: # what about infinite_runs???
1178 jobset.message('FAILED', k, do_newline=True)
1179 elif num_failures > 0:
1180 jobset.message(
1181 'FLAKE', '%s [%d/%d runs flaked]' % (k, num_failures, num_runs),
1182 do_newline=True)
1183 else:
1184 jobset.message('PASSED', k, do_newline=True)
Craig Tiller234b6e72015-05-23 10:12:40 -07001185 finally:
1186 for antagonist in antagonists:
1187 antagonist.kill()
Adele Zhou7cf72112015-11-04 11:18:43 -08001188 if xml_report and resultset:
Adele Zhou3bc7ba42015-11-05 10:21:58 -08001189 report_utils.render_junit_xml_report(resultset, xml_report)
Craig Tillerd86a3942015-01-14 12:48:54 -08001190
Adele Zhouf2ca7bc2015-10-23 15:38:00 -07001191 number_failures, _ = jobset.run(
1192 post_tests_steps, maxjobs=1, stop_on_failure=True,
Craig Tiller883064c2015-11-04 10:06:10 -08001193 newline_on_success=newline_on_success, travis=args.travis)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001194
1195 out = []
1196 if number_failures:
1197 out.append(BuildAndRunError.POST_TEST)
1198 if num_test_failures:
1199 out.append(BuildAndRunError.TEST)
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +02001200
Craig Tiller69cd2372015-06-11 09:38:09 -07001201 if cache: cache.save()
1202
Craig Tillereb9de8b2016-01-08 08:57:41 -08001203 return out
ctiller3040cb72015-01-07 12:13:17 -08001204
1205
David Klempner25739582015-02-11 15:57:32 -08001206test_cache = TestCache(runs_per_test == 1)
Craig Tiller547db2b2015-01-30 14:08:39 -08001207test_cache.maybe_load()
Craig Tiller71735182015-01-15 17:07:13 -08001208
ctiller3040cb72015-01-07 12:13:17 -08001209if forever:
Nicolas Noble044db742015-01-14 16:57:24 -08001210 success = True
ctiller3040cb72015-01-07 12:13:17 -08001211 while True:
Craig Tiller42bc87c2015-02-23 08:50:19 -08001212 dw = watch_dirs.DirWatcher(['src', 'include', 'test', 'examples'])
ctiller3040cb72015-01-07 12:13:17 -08001213 initial_time = dw.most_recent_change()
1214 have_files_changed = lambda: dw.most_recent_change() != initial_time
Nicolas Noble044db742015-01-14 16:57:24 -08001215 previous_success = success
Craig Tillereb9de8b2016-01-08 08:57:41 -08001216 errors = _build_and_run(check_cancelled=have_files_changed,
1217 newline_on_success=False,
1218 cache=test_cache,
1219 build_only=args.build_only) == 0
1220 if not previous_success and not errors:
Nicolas Nobleb09078f2015-01-14 18:06:05 -08001221 jobset.message('SUCCESS',
1222 'All tests are now passing properly',
1223 do_newline=True)
Nicolas Noble044db742015-01-14 16:57:24 -08001224 jobset.message('IDLE', 'No change detected')
ctiller3040cb72015-01-07 12:13:17 -08001225 while not have_files_changed():
1226 time.sleep(1)
1227else:
Craig Tillereb9de8b2016-01-08 08:57:41 -08001228 errors = _build_and_run(check_cancelled=lambda: False,
Craig Tiller71735182015-01-15 17:07:13 -08001229 newline_on_success=args.newline_on_success,
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +02001230 cache=test_cache,
Jan Tattermusch2dd156e2015-12-04 18:26:17 -08001231 xml_report=args.xml_report,
1232 build_only=args.build_only)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001233 if not errors:
Nicolas Nobleb09078f2015-01-14 18:06:05 -08001234 jobset.message('SUCCESS', 'All tests passed', do_newline=True)
1235 else:
1236 jobset.message('FAILED', 'Some tests failed', do_newline=True)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001237 exit_code = 0
1238 if BuildAndRunError.BUILD in errors:
1239 exit_code |= 1
Craig Tiller4f2be362016-01-08 08:59:20 -08001240 if BuildAndRunError.TEST in errors and not args.travis:
Craig Tillereb9de8b2016-01-08 08:57:41 -08001241 exit_code |= 2
Craig Tiller4f2be362016-01-08 08:59:20 -08001242 if BuildAndRunError.POST_TEST in errors:
1243 exit_code |= 4
Craig Tillereb9de8b2016-01-08 08:57:41 -08001244 sys.exit(exit_code)