blob: e687d4634276fb7c6dd9e3f80af697b27e3fd254 [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() +
370 [('GPRC_PYTHON_TESTRUNNER_FILTER', suite_name)]),
371 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:
872 print 'Languages to be tested require running under different docker images.'
873 sys.exit(1)
874 dockerfile_dir = next(iter(dockerfile_dirs))
875
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800876 child_argv = [ arg for arg in sys.argv if not arg == '--use_docker' ]
Jan Tattermusched342b12016-01-26 14:40:31 -0800877 run_tests_cmd = 'python tools/run_tests/run_tests.py %s' % ' '.join(child_argv[1:])
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800878
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800879 env = os.environ.copy()
880 env['RUN_TESTS_COMMAND'] = run_tests_cmd
Jan Tattermusch3b5121b2016-02-22 17:41:05 -0800881 env['DOCKERFILE_DIR'] = dockerfile_dir
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800882 env['DOCKER_RUN_SCRIPT'] = 'tools/jenkins/docker_run_tests.sh'
883 if args.xml_report:
884 env['XML_REPORT'] = args.xml_report
885 if not args.travis:
886 env['TTY_FLAG'] = '-t' # enables Ctrl-C when not on Jenkins.
887
888 subprocess.check_call(['tools/jenkins/build_docker_and_run_tests.sh'],
889 shell=True,
890 env=env)
891 sys.exit(0)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800892
Jan Tattermuschf08018a2016-01-26 08:22:09 -0800893_check_arch_option(args.arch)
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800894
Jan Tattermuschfba65302016-01-25 18:21:14 -0800895def make_jobspec(cfg, targets, makefile='Makefile'):
896 if platform_string() == 'windows':
Craig Tillerfc3c0c42015-09-01 16:47:54 -0700897 extra_args = []
Craig Tillerb5391e12015-09-03 14:35:18 -0700898 # better do parallel compilation
Jan Tattermusch47eeb2b2015-10-07 14:09:18 -0700899 # empirically /m:2 gives the best performance/price and should prevent
900 # overloading the windows workers.
Adele Zhoue4c35612015-10-16 15:34:23 -0700901 extra_args.extend(['/m:2'])
Craig Tillerb5391e12015-09-03 14:35:18 -0700902 # disable PDB generation: it's broken, and we don't need it during CI
Adele Zhoue4c35612015-10-16 15:34:23 -0700903 extra_args.extend(['/p:Jenkins=true'])
Craig Tiller6fd23842015-09-01 07:36:31 -0700904 return [
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800905 jobset.JobSpec([_windows_build_bat(args.compiler),
murgatroid99cf08daf2015-09-21 15:33:16 -0700906 'vsprojects\\%s.sln' % target,
Jan Tattermuscha2d964c2016-02-22 17:33:09 -0800907 '/p:Configuration=%s' % _MSBUILD_CONFIG[cfg]] +
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800908 extra_args +
909 language_make_options,
Craig Tiller590105a2016-01-19 13:03:46 -0800910 shell=True, timeout_seconds=None)
Craig Tiller6fd23842015-09-01 07:36:31 -0700911 for target in targets]
Jan Tattermuschfba65302016-01-25 18:21:14 -0800912 else:
murgatroid998ae409f2015-10-26 16:39:00 -0700913 if targets:
914 return [jobset.JobSpec([os.getenv('MAKE', 'make'),
915 '-f', makefile,
Craig Tillerdd6f7ed2016-01-21 12:54:42 -0800916 '-j', '%d' % args.jobs,
Craig Tiller71a86042016-01-15 14:59:58 -0800917 'EXTRA_DEFINES=GRPC_TEST_SLOWDOWN_MACHINE_FACTOR=%f' % args.slowdown,
918 'CONFIG=%s' % cfg] +
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800919 language_make_options +
Craig Tiller71a86042016-01-15 14:59:58 -0800920 ([] if not args.travis else ['JENKINS_BUILD=1']) +
921 targets,
Craig Tiller590105a2016-01-19 13:03:46 -0800922 timeout_seconds=None)]
murgatroid998ae409f2015-10-26 16:39:00 -0700923 else:
924 return []
Jan Tattermuschfba65302016-01-25 18:21:14 -0800925
murgatroid99a3e244f2015-09-22 11:25:53 -0700926make_targets = {}
927for l in languages:
928 makefile = l.makefile_name()
929 make_targets[makefile] = make_targets.get(makefile, set()).union(
Jan Tattermusch77db4322016-02-20 20:19:35 -0800930 set(l.make_targets()))
Craig Tiller5058c692015-04-08 09:42:04 -0700931
Jan Tattermusche4a69182015-12-15 09:53:01 -0800932def build_step_environ(cfg):
933 environ = {'CONFIG': cfg}
Jan Tattermuscha2d964c2016-02-22 17:33:09 -0800934 msbuild_cfg = _MSBUILD_CONFIG.get(cfg)
Jan Tattermusche4a69182015-12-15 09:53:01 -0800935 if msbuild_cfg:
936 environ['MSBUILD_CONFIG'] = msbuild_cfg
937 return environ
938
murgatroid99fddac962015-09-22 09:20:11 -0700939build_steps = list(set(
Jan Tattermusch77db4322016-02-20 20:19:35 -0800940 jobset.JobSpec(cmdline, environ=build_step_environ(build_config), flake_retries=5)
murgatroid99256d3df2015-09-21 16:58:02 -0700941 for l in languages
942 for cmdline in l.pre_build_steps()))
Craig Tillerbd4e3782015-09-01 06:48:55 -0700943if make_targets:
Jan Tattermusch77db4322016-02-20 20:19:35 -0800944 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 -0700945 build_steps.extend(set(make_commands))
Craig Tiller5058c692015-04-08 09:42:04 -0700946build_steps.extend(set(
Jan Tattermusch77db4322016-02-20 20:19:35 -0800947 jobset.JobSpec(cmdline, environ=build_step_environ(build_config), timeout_seconds=None)
Craig Tiller547db2b2015-01-30 14:08:39 -0800948 for l in languages
Craig Tiller533b1a22015-05-29 08:41:29 -0700949 for cmdline in l.build_steps()))
Craig Tillerf1973b02015-01-16 12:32:13 -0800950
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200951post_tests_steps = list(set(
Jan Tattermusch77db4322016-02-20 20:19:35 -0800952 jobset.JobSpec(cmdline, environ=build_step_environ(build_config))
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200953 for l in languages
954 for cmdline in l.post_tests_steps()))
Nicolas Nobleddef2462015-01-06 18:08:25 -0800955runs_per_test = args.runs_per_test
ctiller3040cb72015-01-07 12:13:17 -0800956forever = args.forever
Nicolas Nobleddef2462015-01-06 18:08:25 -0800957
Nicolas Nobleddef2462015-01-06 18:08:25 -0800958
Craig Tiller71735182015-01-15 17:07:13 -0800959class TestCache(object):
Craig Tillerb50d1662015-01-15 17:28:21 -0800960 """Cache for running tests."""
961
David Klempner25739582015-02-11 15:57:32 -0800962 def __init__(self, use_cache_results):
Craig Tiller71735182015-01-15 17:07:13 -0800963 self._last_successful_run = {}
David Klempner25739582015-02-11 15:57:32 -0800964 self._use_cache_results = use_cache_results
Craig Tiller69cd2372015-06-11 09:38:09 -0700965 self._last_save = time.time()
Craig Tiller71735182015-01-15 17:07:13 -0800966
967 def should_run(self, cmdline, bin_hash):
Craig Tiller71735182015-01-15 17:07:13 -0800968 if cmdline not in self._last_successful_run:
969 return True
970 if self._last_successful_run[cmdline] != bin_hash:
971 return True
David Klempner25739582015-02-11 15:57:32 -0800972 if not self._use_cache_results:
973 return True
Craig Tiller71735182015-01-15 17:07:13 -0800974 return False
975
976 def finished(self, cmdline, bin_hash):
Craig Tiller547db2b2015-01-30 14:08:39 -0800977 self._last_successful_run[cmdline] = bin_hash
Craig Tiller69cd2372015-06-11 09:38:09 -0700978 if time.time() - self._last_save > 1:
979 self.save()
Craig Tiller71735182015-01-15 17:07:13 -0800980
981 def dump(self):
Craig Tillerb50d1662015-01-15 17:28:21 -0800982 return [{'cmdline': k, 'hash': v}
983 for k, v in self._last_successful_run.iteritems()]
Craig Tiller71735182015-01-15 17:07:13 -0800984
985 def parse(self, exdump):
986 self._last_successful_run = dict((o['cmdline'], o['hash']) for o in exdump)
987
988 def save(self):
989 with open('.run_tests_cache', 'w') as f:
Craig Tiller261dd982015-01-16 16:41:45 -0800990 f.write(json.dumps(self.dump()))
Craig Tiller69cd2372015-06-11 09:38:09 -0700991 self._last_save = time.time()
Craig Tiller71735182015-01-15 17:07:13 -0800992
Craig Tiller1cc11db2015-01-15 22:50:50 -0800993 def maybe_load(self):
994 if os.path.exists('.run_tests_cache'):
995 with open('.run_tests_cache') as f:
Craig Tiller261dd982015-01-16 16:41:45 -0800996 self.parse(json.loads(f.read()))
Craig Tiller71735182015-01-15 17:07:13 -0800997
998
Craig Tillerf53d9c82015-08-04 14:19:43 -0700999def _start_port_server(port_server_port):
1000 # check if a compatible port server is running
1001 # if incompatible (version mismatch) ==> start a new one
1002 # if not running ==> start a new one
1003 # otherwise, leave it up
1004 try:
Craig Tillerfe4939f2015-10-06 12:55:36 -07001005 version = int(urllib2.urlopen(
1006 'http://localhost:%d/version_number' % port_server_port,
1007 timeout=1).read())
1008 print 'detected port server running version %d' % version
Craig Tillerf53d9c82015-08-04 14:19:43 -07001009 running = True
Craig Tillerfe4939f2015-10-06 12:55:36 -07001010 except Exception as e:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001011 print 'failed to detect port server: %s' % sys.exc_info()[0]
Craig Tillerfe4939f2015-10-06 12:55:36 -07001012 print e.strerror
Craig Tillerf53d9c82015-08-04 14:19:43 -07001013 running = False
1014 if running:
Craig Tillerfe4939f2015-10-06 12:55:36 -07001015 current_version = int(subprocess.check_output(
Jan Tattermusch3bd08272015-11-04 19:24:37 -08001016 [sys.executable, os.path.abspath('tools/run_tests/port_server.py'),
1017 'dump_version']))
Craig Tillerfe4939f2015-10-06 12:55:36 -07001018 print 'my port server is version %d' % current_version
1019 running = (version >= current_version)
1020 if not running:
1021 print 'port_server version mismatch: killing the old one'
1022 urllib2.urlopen('http://localhost:%d/quitquitquit' % port_server_port).read()
1023 time.sleep(1)
Craig Tillerf53d9c82015-08-04 14:19:43 -07001024 if not running:
Craig Tillerf0a293e2015-10-12 10:05:50 -07001025 fd, logfile = tempfile.mkstemp()
1026 os.close(fd)
1027 print 'starting port_server, with log file %s' % logfile
Jan Tattermusch3bd08272015-11-04 19:24:37 -08001028 args = [sys.executable, os.path.abspath('tools/run_tests/port_server.py'),
1029 '-p', '%d' % port_server_port, '-l', logfile]
Craig Tiller367d41d2015-10-12 13:00:22 -07001030 env = dict(os.environ)
1031 env['BUILD_ID'] = 'pleaseDontKillMeJenkins'
Nicolas "Pixel" Noblef72d7b52015-12-03 03:07:43 +01001032 if platform_string() == 'windows':
Jan Tattermusch3bd08272015-11-04 19:24:37 -08001033 # Working directory of port server needs to be outside of Jenkins
1034 # workspace to prevent file lock issues.
1035 tempdir = tempfile.mkdtemp()
Craig Tillerd2c39712015-10-12 11:08:49 -07001036 port_server = subprocess.Popen(
Craig Tiller367d41d2015-10-12 13:00:22 -07001037 args,
1038 env=env,
Jan Tattermusch3bd08272015-11-04 19:24:37 -08001039 cwd=tempdir,
Craig Tiller367d41d2015-10-12 13:00:22 -07001040 creationflags = 0x00000008, # detached process
1041 close_fds=True)
Craig Tillerd2c39712015-10-12 11:08:49 -07001042 else:
1043 port_server = subprocess.Popen(
1044 args,
Craig Tiller367d41d2015-10-12 13:00:22 -07001045 env=env,
Craig Tillerd2c39712015-10-12 11:08:49 -07001046 preexec_fn=os.setsid,
1047 close_fds=True)
Craig Tillerf0a293e2015-10-12 10:05:50 -07001048 time.sleep(1)
Craig Tiller8b5f4dc2015-08-26 08:02:01 -07001049 # ensure port server is up
Craig Tillerabd37fd2015-08-26 07:54:01 -07001050 waits = 0
Craig Tillerf53d9c82015-08-04 14:19:43 -07001051 while True:
Craig Tillerabd37fd2015-08-26 07:54:01 -07001052 if waits > 10:
Craig Tillerf0a293e2015-10-12 10:05:50 -07001053 print 'killing port server due to excessive start up waits'
Craig Tillerabd37fd2015-08-26 07:54:01 -07001054 port_server.kill()
Craig Tillera2f38b02015-09-24 11:19:17 -07001055 if port_server.poll() is not None:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001056 print 'port_server failed to start'
Craig Tillerf0a293e2015-10-12 10:05:50 -07001057 # try one final time: maybe another build managed to start one
1058 time.sleep(1)
1059 try:
1060 urllib2.urlopen('http://localhost:%d/get' % port_server_port,
1061 timeout=1).read()
1062 print 'last ditch attempt to contact port server succeeded'
1063 break
1064 except:
Jan Tattermusch3b5121b2016-02-22 17:41:05 -08001065 traceback.print_exc()
Craig Tillerf0a293e2015-10-12 10:05:50 -07001066 port_log = open(logfile, 'r').read()
1067 print port_log
1068 sys.exit(1)
Craig Tillerf53d9c82015-08-04 14:19:43 -07001069 try:
Craig Tillerabd37fd2015-08-26 07:54:01 -07001070 urllib2.urlopen('http://localhost:%d/get' % port_server_port,
1071 timeout=1).read()
Craig Tillerf0a293e2015-10-12 10:05:50 -07001072 print 'port server is up and ready'
Craig Tillerf53d9c82015-08-04 14:19:43 -07001073 break
Craig Tiller31fdaa42015-09-25 13:09:59 -07001074 except socket.timeout:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001075 print 'waiting for port_server: timeout'
Craig Tillerf0a293e2015-10-12 10:05:50 -07001076 traceback.print_exc();
1077 time.sleep(1)
Craig Tiller31fdaa42015-09-25 13:09:59 -07001078 waits += 1
Craig Tillerf53d9c82015-08-04 14:19:43 -07001079 except urllib2.URLError:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001080 print 'waiting for port_server: urlerror'
Craig Tillerf0a293e2015-10-12 10:05:50 -07001081 traceback.print_exc();
1082 time.sleep(1)
Craig Tillerabd37fd2015-08-26 07:54:01 -07001083 waits += 1
Craig Tillerf53d9c82015-08-04 14:19:43 -07001084 except:
Jan Tattermusch3b5121b2016-02-22 17:41:05 -08001085 traceback.print_exc()
Craig Tillerf53d9c82015-08-04 14:19:43 -07001086 port_server.kill()
1087 raise
1088
1089
Adele Zhoud5fffa52015-10-23 15:51:42 -07001090def _calculate_num_runs_failures(list_of_results):
1091 """Caculate number of runs and failures for a particular test.
1092
1093 Args:
1094 list_of_results: (List) of JobResult object.
1095 Returns:
1096 A tuple of total number of runs and failures.
1097 """
1098 num_runs = len(list_of_results) # By default, there is 1 run per JobResult.
1099 num_failures = 0
1100 for jobresult in list_of_results:
1101 if jobresult.retries > 0:
1102 num_runs += jobresult.retries
1103 if jobresult.num_failures > 0:
1104 num_failures += jobresult.num_failures
1105 return num_runs, num_failures
1106
Adele Zhou6b9527c2015-11-20 15:56:35 -08001107
Craig Tillereb9de8b2016-01-08 08:57:41 -08001108# _build_and_run results
1109class BuildAndRunError(object):
1110
1111 BUILD = object()
1112 TEST = object()
1113 POST_TEST = object()
1114
1115
1116# returns a list of things that failed (or an empty list on success)
Craig Tillerf53d9c82015-08-04 14:19:43 -07001117def _build_and_run(
Jan Tattermusch2dd156e2015-12-04 18:26:17 -08001118 check_cancelled, newline_on_success, cache, xml_report=None, build_only=False):
ctiller3040cb72015-01-07 12:13:17 -08001119 """Do one pass of building & running tests."""
murgatroid99666450e2015-01-26 13:03:31 -08001120 # build latest sequentially
Jan Tattermuschaab1e512016-01-28 09:30:44 -08001121 num_failures, resultset = jobset.run(
Adele Zhoue4c35612015-10-16 15:34:23 -07001122 build_steps, maxjobs=1, stop_on_failure=True,
Craig Tiller883064c2015-11-04 10:06:10 -08001123 newline_on_success=newline_on_success, travis=args.travis)
Adele Zhoue4c35612015-10-16 15:34:23 -07001124 if num_failures:
Craig Tillereb9de8b2016-01-08 08:57:41 -08001125 return [BuildAndRunError.BUILD]
Craig Tillerb361b4e2016-01-06 11:44:17 -08001126
Jan Tattermusch2dd156e2015-12-04 18:26:17 -08001127 if build_only:
Jan Tattermuschaab1e512016-01-28 09:30:44 -08001128 if xml_report:
1129 report_utils.render_junit_xml_report(resultset, xml_report)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001130 return []
ctiller3040cb72015-01-07 12:13:17 -08001131
Craig Tiller234b6e72015-05-23 10:12:40 -07001132 # start antagonists
David Garcia Quintas79e389f2015-06-02 17:49:42 -07001133 antagonists = [subprocess.Popen(['tools/run_tests/antagonist.py'])
Craig Tiller234b6e72015-05-23 10:12:40 -07001134 for _ in range(0, args.antagonists)]
Craig Tillerfe4939f2015-10-06 12:55:36 -07001135 port_server_port = 32767
Craig Tillerf53d9c82015-08-04 14:19:43 -07001136 _start_port_server(port_server_port)
Adele Zhou7cf72112015-11-04 11:18:43 -08001137 resultset = None
Adele Zhou803af152015-11-30 15:16:16 -08001138 num_test_failures = 0
Craig Tiller234b6e72015-05-23 10:12:40 -07001139 try:
David Garcia Quintase90cd372015-05-31 18:15:26 -07001140 infinite_runs = runs_per_test == 0
yang-g6c1fdc62015-08-18 11:57:42 -07001141 one_run = set(
1142 spec
yang-g6c1fdc62015-08-18 11:57:42 -07001143 for language in languages
Jan Tattermusch77db4322016-02-20 20:19:35 -08001144 for spec in language.test_specs()
yang-g6c1fdc62015-08-18 11:57:42 -07001145 if re.search(args.regex, spec.shortname))
David Garcia Quintas79e389f2015-06-02 17:49:42 -07001146 # When running on travis, we want out test runs to be as similar as possible
1147 # for reproducibility purposes.
Craig Tiller883064c2015-11-04 10:06:10 -08001148 if args.travis:
David Garcia Quintas79e389f2015-06-02 17:49:42 -07001149 massaged_one_run = sorted(one_run, key=lambda x: x.shortname)
1150 else:
1151 # whereas otherwise, we want to shuffle things up to give all tests a
1152 # chance to run.
1153 massaged_one_run = list(one_run) # random.shuffle needs an indexable seq.
1154 random.shuffle(massaged_one_run) # which it modifies in-place.
Craig Tillerf7b7c892015-06-22 14:33:25 -07001155 if infinite_runs:
1156 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 -07001157 runs_sequence = (itertools.repeat(massaged_one_run) if infinite_runs
1158 else itertools.repeat(massaged_one_run, runs_per_test))
David Garcia Quintase90cd372015-05-31 18:15:26 -07001159 all_runs = itertools.chain.from_iterable(runs_sequence)
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +02001160
Adele Zhou803af152015-11-30 15:16:16 -08001161 num_test_failures, resultset = jobset.run(
Adele Zhou2271ab52015-10-28 13:59:14 -07001162 all_runs, check_cancelled, newline_on_success=newline_on_success,
Craig Tiller883064c2015-11-04 10:06:10 -08001163 travis=args.travis, infinite_runs=infinite_runs, maxjobs=args.jobs,
murgatroid998ae409f2015-10-26 16:39:00 -07001164 stop_on_failure=args.stop_on_failure,
Adele Zhouf2ca7bc2015-10-23 15:38:00 -07001165 cache=cache if not xml_report else None,
Adele Zhouf2ca7bc2015-10-23 15:38:00 -07001166 add_env={'GRPC_TEST_PORT_SERVER': 'localhost:%d' % port_server_port})
Adele Zhoud5fffa52015-10-23 15:51:42 -07001167 if resultset:
1168 for k, v in resultset.iteritems():
1169 num_runs, num_failures = _calculate_num_runs_failures(v)
1170 if num_failures == num_runs: # what about infinite_runs???
1171 jobset.message('FAILED', k, do_newline=True)
1172 elif num_failures > 0:
1173 jobset.message(
1174 'FLAKE', '%s [%d/%d runs flaked]' % (k, num_failures, num_runs),
1175 do_newline=True)
1176 else:
1177 jobset.message('PASSED', k, do_newline=True)
Craig Tiller234b6e72015-05-23 10:12:40 -07001178 finally:
1179 for antagonist in antagonists:
1180 antagonist.kill()
Adele Zhou7cf72112015-11-04 11:18:43 -08001181 if xml_report and resultset:
Adele Zhou3bc7ba42015-11-05 10:21:58 -08001182 report_utils.render_junit_xml_report(resultset, xml_report)
Craig Tillerd86a3942015-01-14 12:48:54 -08001183
Adele Zhouf2ca7bc2015-10-23 15:38:00 -07001184 number_failures, _ = jobset.run(
1185 post_tests_steps, maxjobs=1, stop_on_failure=True,
Craig Tiller883064c2015-11-04 10:06:10 -08001186 newline_on_success=newline_on_success, travis=args.travis)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001187
1188 out = []
1189 if number_failures:
1190 out.append(BuildAndRunError.POST_TEST)
1191 if num_test_failures:
1192 out.append(BuildAndRunError.TEST)
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +02001193
Craig Tiller69cd2372015-06-11 09:38:09 -07001194 if cache: cache.save()
1195
Craig Tillereb9de8b2016-01-08 08:57:41 -08001196 return out
ctiller3040cb72015-01-07 12:13:17 -08001197
1198
David Klempner25739582015-02-11 15:57:32 -08001199test_cache = TestCache(runs_per_test == 1)
Craig Tiller547db2b2015-01-30 14:08:39 -08001200test_cache.maybe_load()
Craig Tiller71735182015-01-15 17:07:13 -08001201
ctiller3040cb72015-01-07 12:13:17 -08001202if forever:
Nicolas Noble044db742015-01-14 16:57:24 -08001203 success = True
ctiller3040cb72015-01-07 12:13:17 -08001204 while True:
Craig Tiller42bc87c2015-02-23 08:50:19 -08001205 dw = watch_dirs.DirWatcher(['src', 'include', 'test', 'examples'])
ctiller3040cb72015-01-07 12:13:17 -08001206 initial_time = dw.most_recent_change()
1207 have_files_changed = lambda: dw.most_recent_change() != initial_time
Nicolas Noble044db742015-01-14 16:57:24 -08001208 previous_success = success
Craig Tillereb9de8b2016-01-08 08:57:41 -08001209 errors = _build_and_run(check_cancelled=have_files_changed,
1210 newline_on_success=False,
1211 cache=test_cache,
1212 build_only=args.build_only) == 0
1213 if not previous_success and not errors:
Nicolas Nobleb09078f2015-01-14 18:06:05 -08001214 jobset.message('SUCCESS',
1215 'All tests are now passing properly',
1216 do_newline=True)
Nicolas Noble044db742015-01-14 16:57:24 -08001217 jobset.message('IDLE', 'No change detected')
ctiller3040cb72015-01-07 12:13:17 -08001218 while not have_files_changed():
1219 time.sleep(1)
1220else:
Craig Tillereb9de8b2016-01-08 08:57:41 -08001221 errors = _build_and_run(check_cancelled=lambda: False,
Craig Tiller71735182015-01-15 17:07:13 -08001222 newline_on_success=args.newline_on_success,
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +02001223 cache=test_cache,
Jan Tattermusch2dd156e2015-12-04 18:26:17 -08001224 xml_report=args.xml_report,
1225 build_only=args.build_only)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001226 if not errors:
Nicolas Nobleb09078f2015-01-14 18:06:05 -08001227 jobset.message('SUCCESS', 'All tests passed', do_newline=True)
1228 else:
1229 jobset.message('FAILED', 'Some tests failed', do_newline=True)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001230 exit_code = 0
1231 if BuildAndRunError.BUILD in errors:
1232 exit_code |= 1
Craig Tiller4f2be362016-01-08 08:59:20 -08001233 if BuildAndRunError.TEST in errors and not args.travis:
Craig Tillereb9de8b2016-01-08 08:57:41 -08001234 exit_code |= 2
Craig Tiller4f2be362016-01-08 08:59:20 -08001235 if BuildAndRunError.POST_TEST in errors:
1236 exit_code |= 4
Craig Tillereb9de8b2016-01-08 08:57:41 -08001237 sys.exit(exit_code)