blob: f81909ab88f12ac6000c6a4e24f2a51cd306fbf6 [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
Jan Tattermusch9bb70622016-03-18 10:28:54 -0700234 def _gcc44_make_options(self):
235 return ['CC=gcc-4.4', 'CXX=g++-4.4', 'LD=gcc-4.4', 'LDXX=g++-4.4']
236
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800237 def _compiler_options(self, use_docker, compiler):
238 """Returns docker distro and make options to use for given compiler."""
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800239 if _is_use_docker_child():
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800240 return ("already_under_docker", [])
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800241 if not use_docker:
242 _check_compiler(compiler, ['default'])
243
244 if compiler == 'gcc4.9' or compiler == 'default':
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800245 return ('jessie', [])
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800246 elif compiler == 'gcc4.4':
Jan Tattermusch9bb70622016-03-18 10:28:54 -0700247 return ('wheezy', self._gcc44_make_options())
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800248 elif compiler == 'gcc5.3':
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800249 return ('ubuntu1604', [])
250 elif compiler == 'clang3.4':
251 return ('ubuntu1404', self._clang_make_options())
252 elif compiler == 'clang3.6':
253 return ('ubuntu1604', self._clang_make_options())
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800254 else:
255 raise Exception('Compiler %s not supported.' % compiler)
256
Jan Tattermusch77db4322016-02-20 20:19:35 -0800257 def dockerfile_dir(self):
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800258 return 'tools/dockerfile/test/cxx_%s_%s' % (self._docker_distro,
259 _docker_arch_suffix(self.args.arch))
Jan Tattermusch788ee232016-01-26 12:19:44 -0800260
murgatroid99132ce6a2015-03-04 17:29:14 -0800261 def __str__(self):
262 return self.make_target
263
Craig Tillercc0535d2015-12-08 15:14:47 -0800264
murgatroid992c8d5162015-01-26 10:41:21 -0800265class NodeLanguage(object):
266
Jan Tattermusche477b842016-02-06 22:19:01 -0800267 def __init__(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800268 self.platform = platform_string()
Jan Tattermusche477b842016-02-06 22:19:01 -0800269 self.node_version = '0.12'
270
Jan Tattermusch77db4322016-02-20 20:19:35 -0800271 def configure(self, config, args):
272 self.config = config
273 self.args = args
274 _check_compiler(self.args.compiler, ['default'])
275
276 def test_specs(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800277 if self.platform == 'windows':
Jan Tattermusch77db4322016-02-20 20:19:35 -0800278 return [self.config.job_spec(['tools\\run_tests\\run_node.bat'], None)]
Michael Lumishaaa876a2016-02-10 15:27:58 -0800279 else:
Jan Tattermusch77db4322016-02-20 20:19:35 -0800280 return [self.config.job_spec(['tools/run_tests/run_node.sh', self.node_version],
281 None,
282 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
murgatroid992c8d5162015-01-26 10:41:21 -0800283
murgatroid99256d3df2015-09-21 16:58:02 -0700284 def pre_build_steps(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800285 if self.platform == 'windows':
286 return [['tools\\run_tests\\pre_build_node.bat']]
287 else:
288 return [['tools/run_tests/pre_build_node.sh', self.node_version]]
murgatroid99256d3df2015-09-21 16:58:02 -0700289
Jan Tattermusch77db4322016-02-20 20:19:35 -0800290 def make_targets(self):
murgatroid99db5b1602015-10-01 13:20:11 -0700291 return []
murgatroid992c8d5162015-01-26 10:41:21 -0800292
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800293 def make_options(self):
294 return []
295
murgatroid992c8d5162015-01-26 10:41:21 -0800296 def build_steps(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800297 if self.platform == 'windows':
298 return [['tools\\run_tests\\build_node.bat']]
299 else:
300 return [['tools/run_tests/build_node.sh', self.node_version]]
Craig Tillerc7449162015-01-16 14:42:10 -0800301
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200302 def post_tests_steps(self):
Michael Lumish60d38cb2016-03-04 13:05:04 -0800303 return []
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200304
murgatroid99a3e244f2015-09-22 11:25:53 -0700305 def makefile_name(self):
306 return 'Makefile'
307
Jan Tattermusch77db4322016-02-20 20:19:35 -0800308 def dockerfile_dir(self):
309 return 'tools/dockerfile/test/node_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800310
murgatroid99132ce6a2015-03-04 17:29:14 -0800311 def __str__(self):
312 return 'node'
313
Craig Tiller99775822015-01-30 13:07:16 -0800314
Craig Tillerc7449162015-01-16 14:42:10 -0800315class PhpLanguage(object):
316
Jan Tattermusch77db4322016-02-20 20:19:35 -0800317 def configure(self, config, args):
318 self.config = config
319 self.args = args
320 _check_compiler(self.args.compiler, ['default'])
321
322 def test_specs(self):
323 return [self.config.job_spec(['src/php/bin/run_tests.sh'], None,
324 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
Craig Tillerc7449162015-01-16 14:42:10 -0800325
murgatroid99256d3df2015-09-21 16:58:02 -0700326 def pre_build_steps(self):
327 return []
328
Jan Tattermusch77db4322016-02-20 20:19:35 -0800329 def make_targets(self):
Craig Tilleraf7cf542015-05-22 10:07:34 -0700330 return ['static_c', 'shared_c']
Craig Tillerc7449162015-01-16 14:42:10 -0800331
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800332 def make_options(self):
333 return []
334
Craig Tillerc7449162015-01-16 14:42:10 -0800335 def build_steps(self):
336 return [['tools/run_tests/build_php.sh']]
337
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200338 def post_tests_steps(self):
Stanley Cheunga6b95482016-01-13 16:10:48 -0800339 return [['tools/run_tests/post_tests_php.sh']]
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200340
murgatroid99a3e244f2015-09-22 11:25:53 -0700341 def makefile_name(self):
342 return 'Makefile'
343
Jan Tattermusch77db4322016-02-20 20:19:35 -0800344 def dockerfile_dir(self):
345 return 'tools/dockerfile/test/php_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800346
murgatroid99132ce6a2015-03-04 17:29:14 -0800347 def __str__(self):
348 return 'php'
349
Craig Tillerc7449162015-01-16 14:42:10 -0800350
Nathaniel Manista840615e2015-01-22 20:31:47 +0000351class PythonLanguage(object):
352
Craig Tiller49f61322015-03-03 13:02:11 -0800353 def __init__(self):
Masood Malekghassemi2b841622015-07-28 17:39:02 -0700354 self._build_python_versions = ['2.7']
Masood Malekghassemie5f70022015-06-29 09:20:26 -0700355 self._has_python_versions = []
Craig Tiller49f61322015-03-03 13:02:11 -0800356
Jan Tattermusch77db4322016-02-20 20:19:35 -0800357 def configure(self, config, args):
358 self.config = config
359 self.args = args
360 _check_compiler(self.args.compiler, ['default'])
361
362 def test_specs(self):
Jan Tattermusch072ebaa2016-03-01 18:33:12 -0800363 # load list of known test suites
364 with open('src/python/grpcio/tests/tests.json') as tests_json_file:
365 tests_json = json.load(tests_json_file)
Masood Malekghassemi2b841622015-07-28 17:39:02 -0700366 environment = dict(_FORCE_ENVIRON_FOR_WRAPPERS)
367 environment['PYVER'] = '2.7'
Jan Tattermusch072ebaa2016-03-01 18:33:12 -0800368 if self.config.build_config != 'gcov':
369 return [self.config.job_spec(
370 ['tools/run_tests/run_python.sh'],
371 None,
372 environ=dict(environment.items() +
Masood Malekghassemif7ff8be2016-03-09 15:27:28 -0800373 [('GRPC_PYTHON_TESTRUNNER_FILTER', suite_name)]),
Jan Tattermusch072ebaa2016-03-01 18:33:12 -0800374 shortname='py.test.%s' % suite_name,
375 timeout_seconds=5*60)
376 for suite_name in tests_json]
377 else:
378 return [self.config.job_spec(['tools/run_tests/run_python.sh'],
379 None,
380 environ=environment,
381 shortname='py.test.coverage',
382 timeout_seconds=15*60)]
383
Nathaniel Manista840615e2015-01-22 20:31:47 +0000384
murgatroid99256d3df2015-09-21 16:58:02 -0700385 def pre_build_steps(self):
386 return []
387
Jan Tattermusch77db4322016-02-20 20:19:35 -0800388 def make_targets(self):
Craig Tilleraf7cf542015-05-22 10:07:34 -0700389 return ['static_c', 'grpc_python_plugin', 'shared_c']
Nathaniel Manista840615e2015-01-22 20:31:47 +0000390
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800391 def make_options(self):
392 return []
393
Nathaniel Manista840615e2015-01-22 20:31:47 +0000394 def build_steps(self):
Masood Malekghassemie5f70022015-06-29 09:20:26 -0700395 commands = []
396 for python_version in self._build_python_versions:
397 try:
398 with open(os.devnull, 'w') as output:
399 subprocess.check_call(['which', 'python' + python_version],
400 stdout=output, stderr=output)
401 commands.append(['tools/run_tests/build_python.sh', python_version])
402 self._has_python_versions.append(python_version)
403 except:
404 jobset.message('WARNING', 'Missing Python ' + python_version,
405 do_newline=True)
406 return commands
Nathaniel Manista840615e2015-01-22 20:31:47 +0000407
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200408 def post_tests_steps(self):
409 return []
410
murgatroid99a3e244f2015-09-22 11:25:53 -0700411 def makefile_name(self):
412 return 'Makefile'
413
Jan Tattermusch77db4322016-02-20 20:19:35 -0800414 def dockerfile_dir(self):
415 return 'tools/dockerfile/test/python_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800416
murgatroid99132ce6a2015-03-04 17:29:14 -0800417 def __str__(self):
418 return 'python'
419
Craig Tillerd625d812015-04-08 15:52:35 -0700420
murgatroid996a4c4fa2015-02-27 12:08:57 -0800421class RubyLanguage(object):
422
Jan Tattermusch77db4322016-02-20 20:19:35 -0800423 def configure(self, config, args):
424 self.config = config
425 self.args = args
426 _check_compiler(self.args.compiler, ['default'])
427
428 def test_specs(self):
429 return [self.config.job_spec(['tools/run_tests/run_ruby.sh'], None,
430 timeout_seconds=10*60,
431 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
murgatroid996a4c4fa2015-02-27 12:08:57 -0800432
murgatroid99256d3df2015-09-21 16:58:02 -0700433 def pre_build_steps(self):
Nicolas "Pixel" Noblebcf988f2015-10-08 03:00:42 +0200434 return [['tools/run_tests/pre_build_ruby.sh']]
murgatroid99256d3df2015-09-21 16:58:02 -0700435
Jan Tattermusch4651bef2016-02-23 08:31:25 -0800436 def make_targets(self):
murgatroid997d243df2016-02-18 09:58:05 -0800437 return []
murgatroid996a4c4fa2015-02-27 12:08:57 -0800438
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800439 def make_options(self):
440 return []
441
murgatroid996a4c4fa2015-02-27 12:08:57 -0800442 def build_steps(self):
443 return [['tools/run_tests/build_ruby.sh']]
444
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200445 def post_tests_steps(self):
Nicolas "Pixel" Noble7ef1e532015-12-02 00:55:33 +0100446 return [['tools/run_tests/post_tests_ruby.sh']]
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200447
murgatroid99a3e244f2015-09-22 11:25:53 -0700448 def makefile_name(self):
449 return 'Makefile'
450
Jan Tattermusch77db4322016-02-20 20:19:35 -0800451 def dockerfile_dir(self):
452 return 'tools/dockerfile/test/ruby_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800453
murgatroid99132ce6a2015-03-04 17:29:14 -0800454 def __str__(self):
455 return 'ruby'
456
Craig Tillerd625d812015-04-08 15:52:35 -0700457
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800458class CSharpLanguage(object):
Jan Tattermusch77db4322016-02-20 20:19:35 -0800459
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700460 def __init__(self):
Craig Tillerd50993d2015-08-05 08:04:36 -0700461 self.platform = platform_string()
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700462
Jan Tattermusch77db4322016-02-20 20:19:35 -0800463 def configure(self, config, args):
464 self.config = config
465 self.args = args
466 _check_compiler(self.args.compiler, ['default'])
467
468 def test_specs(self):
Jan Tattermusch03c01062015-12-11 14:28:56 -0800469 with open('src/csharp/tests.json') as f:
470 tests_json = json.load(f)
471 assemblies = tests_json['assemblies']
472 tests = tests_json['tests']
473
Jan Tattermuscha2d964c2016-02-22 17:33:09 -0800474 msbuild_config = _MSBUILD_CONFIG[self.config.build_config]
Jan Tattermusch03c01062015-12-11 14:28:56 -0800475 assembly_files = ['%s/bin/%s/%s.dll' % (a, msbuild_config, a)
476 for a in assemblies]
477
478 extra_args = ['-labels'] + assembly_files
479
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700480 if self.platform == 'windows':
Jan Tattermusch03c01062015-12-11 14:28:56 -0800481 script_name = 'tools\\run_tests\\run_csharp.bat'
482 extra_args += ['-domain=None']
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700483 else:
Jan Tattermusch03c01062015-12-11 14:28:56 -0800484 script_name = 'tools/run_tests/run_csharp.sh'
Jan Tattermuschbf3b1532015-10-26 10:24:42 -0700485
Jan Tattermusch77db4322016-02-20 20:19:35 -0800486 if self.config.build_config == 'gcov':
Jan Tattermuschbdf4b2e2015-10-28 08:22:34 -0700487 # On Windows, we only collect C# code coverage.
488 # On Linux, we only collect coverage for native extension.
489 # For code coverage all tests need to run as one suite.
Jan Tattermusch77db4322016-02-20 20:19:35 -0800490 return [self.config.job_spec([script_name] + extra_args, None,
491 shortname='csharp.coverage',
492 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
Jan Tattermusch61c3a832015-10-27 17:54:50 -0700493 else:
Jan Tattermusch03c01062015-12-11 14:28:56 -0800494 specs = []
495 for test in tests:
496 cmdline = [script_name, '-run=%s' % test] + extra_args
497 if self.platform == 'windows':
498 # use different output directory for each test to prevent
499 # TestResult.xml clash between parallel test runs.
500 cmdline += ['-work=test-result/%s' % uuid.uuid4()]
Jan Tattermusch77db4322016-02-20 20:19:35 -0800501 specs.append(self.config.job_spec(cmdline, None,
502 shortname='csharp.%s' % test,
503 environ=_FORCE_ENVIRON_FOR_WRAPPERS))
Jan Tattermusch03c01062015-12-11 14:28:56 -0800504 return specs
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800505
murgatroid99256d3df2015-09-21 16:58:02 -0700506 def pre_build_steps(self):
Jan Tattermusch48423fc2015-10-07 18:59:16 -0700507 if self.platform == 'windows':
Jan Tattermusch874aec02015-10-07 19:26:19 -0700508 return [['tools\\run_tests\\pre_build_csharp.bat']]
Jan Tattermusch48423fc2015-10-07 18:59:16 -0700509 else:
510 return [['tools/run_tests/pre_build_csharp.sh']]
murgatroid99256d3df2015-09-21 16:58:02 -0700511
Jan Tattermusch77db4322016-02-20 20:19:35 -0800512 def make_targets(self):
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700513 # For Windows, this target doesn't really build anything,
514 # everything is build by buildall script later.
Craig Tillerd5904822015-08-31 21:30:58 -0700515 if self.platform == 'windows':
516 return []
517 else:
518 return ['grpc_csharp_ext']
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800519
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800520 def make_options(self):
521 if self.platform == 'mac':
522 # On Mac, official distribution of mono is 32bit.
523 return ['CFLAGS=-arch i386', 'LDFLAGS=-arch i386']
524 else:
525 return []
526
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800527 def build_steps(self):
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700528 if self.platform == 'windows':
529 return [['src\\csharp\\buildall.bat']]
530 else:
531 return [['tools/run_tests/build_csharp.sh']]
Nathaniel Manista840615e2015-01-22 20:31:47 +0000532
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200533 def post_tests_steps(self):
534 return []
535
murgatroid99a3e244f2015-09-22 11:25:53 -0700536 def makefile_name(self):
537 return 'Makefile'
538
Jan Tattermusch77db4322016-02-20 20:19:35 -0800539 def dockerfile_dir(self):
540 return 'tools/dockerfile/test/csharp_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800541
murgatroid99132ce6a2015-03-04 17:29:14 -0800542 def __str__(self):
543 return 'csharp'
544
Craig Tillerd625d812015-04-08 15:52:35 -0700545
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700546class ObjCLanguage(object):
547
Jan Tattermusch77db4322016-02-20 20:19:35 -0800548 def configure(self, config, args):
549 self.config = config
550 self.args = args
551 _check_compiler(self.args.compiler, ['default'])
552
553 def test_specs(self):
554 return [self.config.job_spec(['src/objective-c/tests/run_tests.sh'], None,
555 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700556
murgatroid99256d3df2015-09-21 16:58:02 -0700557 def pre_build_steps(self):
558 return []
559
Jan Tattermusch77db4322016-02-20 20:19:35 -0800560 def make_targets(self):
Jorge Canizalesd0b32e92015-07-30 23:08:43 -0700561 return ['grpc_objective_c_plugin', 'interop_server']
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700562
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800563 def make_options(self):
564 return []
565
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700566 def build_steps(self):
Jorge Canizalesd0b32e92015-07-30 23:08:43 -0700567 return [['src/objective-c/tests/build_tests.sh']]
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700568
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200569 def post_tests_steps(self):
570 return []
571
murgatroid99a3e244f2015-09-22 11:25:53 -0700572 def makefile_name(self):
573 return 'Makefile'
574
Jan Tattermusch77db4322016-02-20 20:19:35 -0800575 def dockerfile_dir(self):
Jan Tattermusch788ee232016-01-26 12:19:44 -0800576 return None
577
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700578 def __str__(self):
579 return 'objc'
580
581
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100582class Sanity(object):
583
Jan Tattermusch77db4322016-02-20 20:19:35 -0800584 def configure(self, config, args):
585 self.config = config
586 self.args = args
587 _check_compiler(self.args.compiler, ['default'])
588
589 def test_specs(self):
Craig Tiller94d04a52016-01-20 10:58:23 -0800590 import yaml
Jan Tattermusch788ee232016-01-26 12:19:44 -0800591 with open('tools/run_tests/sanity/sanity_tests.yaml', 'r') as f:
Jan Tattermusch77db4322016-02-20 20:19:35 -0800592 return [self.config.job_spec(cmd['script'].split(), None,
593 timeout_seconds=None, environ={'TEST': 'true'},
594 cpu_cost=cmd.get('cpu_cost', 1))
Craig Tiller94d04a52016-01-20 10:58:23 -0800595 for cmd in yaml.load(f)]
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100596
murgatroid99256d3df2015-09-21 16:58:02 -0700597 def pre_build_steps(self):
598 return []
599
Jan Tattermusch77db4322016-02-20 20:19:35 -0800600 def make_targets(self):
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100601 return ['run_dep_checks']
602
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800603 def make_options(self):
604 return []
605
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100606 def build_steps(self):
607 return []
608
Nicolas "Pixel" Noble87879b32015-10-12 23:28:53 +0200609 def post_tests_steps(self):
610 return []
611
murgatroid99a3e244f2015-09-22 11:25:53 -0700612 def makefile_name(self):
613 return 'Makefile'
614
Jan Tattermusch77db4322016-02-20 20:19:35 -0800615 def dockerfile_dir(self):
Jan Tattermusche70b3c52016-02-07 20:21:02 -0800616 return 'tools/dockerfile/test/sanity'
Jan Tattermusch788ee232016-01-26 12:19:44 -0800617
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100618 def __str__(self):
619 return 'sanity'
620
Nicolas "Pixel" Noblee55cd7f2015-04-14 17:59:13 +0200621
Craig Tiller738c3342015-01-12 14:28:33 -0800622# different configurations we can run under
Craig Tillera0f85172016-01-20 15:56:06 -0800623with open('tools/run_tests/configs.json') as f:
Craig Tiller1dce9062016-01-20 17:01:56 -0800624 _CONFIGS = dict((cfg['config'], Config(**cfg)) for cfg in ast.literal_eval(f.read()))
Craig Tiller738c3342015-01-12 14:28:33 -0800625
626
Craig Tillerc7449162015-01-16 14:42:10 -0800627_LANGUAGES = {
Craig Tillere9c959d2015-01-18 10:23:26 -0800628 'c++': CLanguage('cxx', 'c++'),
629 'c': CLanguage('c', 'c'),
murgatroid992c8d5162015-01-26 10:41:21 -0800630 'node': NodeLanguage(),
Nathaniel Manista840615e2015-01-22 20:31:47 +0000631 'php': PhpLanguage(),
632 'python': PythonLanguage(),
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800633 'ruby': RubyLanguage(),
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100634 'csharp': CSharpLanguage(),
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700635 'objc' : ObjCLanguage(),
Jan Tattermusch70a57e42016-02-20 18:50:27 -0800636 'sanity': Sanity()
Craig Tillereb272bc2015-01-30 13:13:14 -0800637 }
Nicolas Nobleddef2462015-01-06 18:08:25 -0800638
Jan Tattermusch77db4322016-02-20 20:19:35 -0800639
Jan Tattermuscha2d964c2016-02-22 17:33:09 -0800640_MSBUILD_CONFIG = {
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700641 'dbg': 'Debug',
642 'opt': 'Release',
Jan Tattermusche4a69182015-12-15 09:53:01 -0800643 'gcov': 'Debug',
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700644 }
645
David Garcia Quintase90cd372015-05-31 18:15:26 -0700646
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800647def _windows_arch_option(arch):
648 """Returns msbuild cmdline option for selected architecture."""
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800649 if arch == 'default' or arch == 'x86':
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800650 return '/p:Platform=Win32'
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800651 elif arch == 'x64':
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800652 return '/p:Platform=x64'
653 else:
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800654 print 'Architecture %s not supported.' % arch
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800655 sys.exit(1)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800656
Jan Tattermuschf08018a2016-01-26 08:22:09 -0800657
658def _check_arch_option(arch):
659 """Checks that architecture option is valid."""
660 if platform_string() == 'windows':
661 _windows_arch_option(arch)
662 elif platform_string() == 'linux':
663 # On linux, we need to be running under docker with the right architecture.
Jan Tattermusch07fb0422016-01-26 10:46:56 -0800664 runtime_arch = platform.architecture()[0]
Jan Tattermuschf08018a2016-01-26 08:22:09 -0800665 if arch == 'default':
666 return
667 elif runtime_arch == '64bit' and arch == 'x64':
668 return
669 elif runtime_arch == '32bit' and arch == 'x86':
670 return
671 else:
672 print 'Architecture %s does not match current runtime architecture.' % arch
673 sys.exit(1)
674 else:
675 if args.arch != 'default':
676 print 'Architecture %s not supported on current platform.' % args.arch
677 sys.exit(1)
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800678
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800679
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800680def _windows_build_bat(compiler):
681 """Returns name of build.bat for selected compiler."""
682 if compiler == 'default' or compiler == 'vs2013':
683 return 'vsprojects\\build_vs2013.bat'
684 elif compiler == 'vs2015':
685 return 'vsprojects\\build_vs2015.bat'
686 elif compiler == 'vs2010':
687 return 'vsprojects\\build_vs2010.bat'
688 else:
689 print 'Compiler %s not supported.' % compiler
690 sys.exit(1)
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800691
692
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800693def _windows_toolset_option(compiler):
694 """Returns msbuild PlatformToolset for selected compiler."""
695 if compiler == 'default' or compiler == 'vs2013':
696 return '/p:PlatformToolset=v120'
697 elif compiler == 'vs2015':
698 return '/p:PlatformToolset=v140'
699 elif compiler == 'vs2010':
700 return '/p:PlatformToolset=v100'
701 else:
702 print 'Compiler %s not supported.' % compiler
703 sys.exit(1)
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800704
705
Jan Tattermusche70b3c52016-02-07 20:21:02 -0800706def _docker_arch_suffix(arch):
707 """Returns suffix to dockerfile dir to use."""
708 if arch == 'default' or arch == 'x64':
709 return 'x64'
710 elif arch == 'x86':
711 return 'x86'
712 else:
713 print 'Architecture %s not supported with current settings.' % arch
714 sys.exit(1)
715
716
David Garcia Quintase90cd372015-05-31 18:15:26 -0700717def runs_per_test_type(arg_str):
718 """Auxilary function to parse the "runs_per_test" flag.
719
720 Returns:
721 A positive integer or 0, the latter indicating an infinite number of
722 runs.
723
724 Raises:
725 argparse.ArgumentTypeError: Upon invalid input.
726 """
727 if arg_str == 'inf':
728 return 0
729 try:
730 n = int(arg_str)
731 if n <= 0: raise ValueError
Craig Tiller50e53e22015-06-01 20:18:21 -0700732 return n
David Garcia Quintase90cd372015-05-31 18:15:26 -0700733 except:
Adele Zhoue4c35612015-10-16 15:34:23 -0700734 msg = '\'{}\' is not a positive integer or \'inf\''.format(arg_str)
David Garcia Quintase90cd372015-05-31 18:15:26 -0700735 raise argparse.ArgumentTypeError(msg)
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700736
737# parse command line
738argp = argparse.ArgumentParser(description='Run grpc tests.')
739argp.add_argument('-c', '--config',
Jan Tattermusch77db4322016-02-20 20:19:35 -0800740 choices=sorted(_CONFIGS.keys()),
741 default='opt')
David Garcia Quintase90cd372015-05-31 18:15:26 -0700742argp.add_argument('-n', '--runs_per_test', default=1, type=runs_per_test_type,
743 help='A positive integer or "inf". If "inf", all tests will run in an '
744 'infinite loop. Especially useful in combination with "-f"')
Craig Tillerfe406ec2015-02-24 13:55:12 -0800745argp.add_argument('-r', '--regex', default='.*', type=str)
Craig Tiller5f735a62016-01-20 09:31:15 -0800746argp.add_argument('-j', '--jobs', default=multiprocessing.cpu_count(), type=int)
Craig Tiller8451e872015-02-27 09:25:51 -0800747argp.add_argument('-s', '--slowdown', default=1.0, type=float)
ctiller3040cb72015-01-07 12:13:17 -0800748argp.add_argument('-f', '--forever',
749 default=False,
750 action='store_const',
751 const=True)
Nicolas "Pixel" Noblea7df3f92015-02-26 22:07:04 +0100752argp.add_argument('-t', '--travis',
753 default=False,
754 action='store_const',
755 const=True)
Nicolas Noble044db742015-01-14 16:57:24 -0800756argp.add_argument('--newline_on_success',
757 default=False,
758 action='store_const',
759 const=True)
Craig Tiller686fb262015-01-15 07:39:09 -0800760argp.add_argument('-l', '--language',
Craig Tiller60f15e62015-05-13 09:05:17 -0700761 choices=['all'] + sorted(_LANGUAGES.keys()),
Craig Tiller686fb262015-01-15 07:39:09 -0800762 nargs='+',
Craig Tiller60f15e62015-05-13 09:05:17 -0700763 default=['all'])
Craig Tillercd43da82015-05-29 08:41:29 -0700764argp.add_argument('-S', '--stop_on_failure',
765 default=False,
766 action='store_const',
767 const=True)
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700768argp.add_argument('--use_docker',
769 default=False,
770 action='store_const',
771 const=True,
Adele Zhoue4c35612015-10-16 15:34:23 -0700772 help='Run all the tests under docker. That provides ' +
773 'additional isolation and prevents the need to install ' +
774 'language specific prerequisites. Only available on Linux.')
Craig Tillerd4509a12015-09-28 09:18:40 -0700775argp.add_argument('--allow_flakes',
776 default=False,
777 action='store_const',
778 const=True,
Adele Zhoue4c35612015-10-16 15:34:23 -0700779 help='Allow flaky tests to show as passing (re-runs failed tests up to five times)')
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800780argp.add_argument('--arch',
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800781 choices=['default', 'x86', 'x64'],
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800782 default='default',
783 help='Selects architecture to target. For some platforms "default" is the only supported choice.')
784argp.add_argument('--compiler',
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800785 choices=['default',
786 'gcc4.4', 'gcc4.9', 'gcc5.3',
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800787 'clang3.4', 'clang3.6',
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800788 'vs2010', 'vs2013', 'vs2015'],
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800789 default='default',
Jan Tattermusch77db4322016-02-20 20:19:35 -0800790 help='Selects compiler to use. Allowed values depend on the platform and language.')
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800791argp.add_argument('--build_only',
792 default=False,
793 action='store_const',
794 const=True,
795 help='Perform all the build steps but dont run any tests.')
Craig Tiller5f735a62016-01-20 09:31:15 -0800796argp.add_argument('--measure_cpu_costs', default=False, action='store_const', const=True,
797 help='Measure the cpu costs of tests')
Craig Tiller1676f912016-01-05 10:49:44 -0800798argp.add_argument('--update_submodules', default=[], nargs='*',
799 help='Update some submodules before building. If any are updated, also run generate_projects. ' +
800 'Submodules are specified as SUBMODULE_NAME:BRANCH; if BRANCH is omitted, master is assumed.')
Craig Tiller234b6e72015-05-23 10:12:40 -0700801argp.add_argument('-a', '--antagonists', default=0, type=int)
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +0200802argp.add_argument('-x', '--xml_report', default=None, type=str,
803 help='Generates a JUnit-compatible XML report')
Nicolas Nobleddef2462015-01-06 18:08:25 -0800804args = argp.parse_args()
805
Craig Tiller5f735a62016-01-20 09:31:15 -0800806jobset.measure_cpu_costs = args.measure_cpu_costs
807
Craig Tiller1676f912016-01-05 10:49:44 -0800808# update submodules if necessary
Craig Tillerb361b4e2016-01-06 11:44:17 -0800809need_to_regenerate_projects = False
810for spec in args.update_submodules:
811 spec = spec.split(':', 1)
812 if len(spec) == 1:
813 submodule = spec[0]
814 branch = 'master'
815 elif len(spec) == 2:
816 submodule = spec[0]
817 branch = spec[1]
818 cwd = 'third_party/%s' % submodule
819 def git(cmd, cwd=cwd):
820 print 'in %s: git %s' % (cwd, cmd)
821 subprocess.check_call('git %s' % cmd, cwd=cwd, shell=True)
822 git('fetch')
823 git('checkout %s' % branch)
824 git('pull origin %s' % branch)
825 if os.path.exists('src/%s/gen_build_yaml.py' % submodule):
826 need_to_regenerate_projects = True
827if need_to_regenerate_projects:
828 if jobset.platform_string() == 'linux':
829 subprocess.check_call('tools/buildgen/generate_projects.sh', shell=True)
830 else:
831 print 'WARNING: may need to regenerate projects, but since we are not on'
832 print ' Linux this step is being skipped. Compilation MAY fail.'
Craig Tiller1676f912016-01-05 10:49:44 -0800833
834
Nicolas Nobleddef2462015-01-06 18:08:25 -0800835# grab config
Jan Tattermusch77db4322016-02-20 20:19:35 -0800836run_config = _CONFIGS[args.config]
837build_config = run_config.build_config
Craig Tillerf1973b02015-01-16 12:32:13 -0800838
Craig Tiller06805272015-06-11 14:46:47 -0700839if args.travis:
murgatroid99d3b5b7f2015-10-06 17:02:03 -0700840 _FORCE_ENVIRON_FOR_WRAPPERS = {'GRPC_TRACE': 'api'}
Craig Tiller06805272015-06-11 14:46:47 -0700841
Adele Zhou6b9527c2015-11-20 15:56:35 -0800842if 'all' in args.language:
Craig Tiller1676f912016-01-05 10:49:44 -0800843 lang_list = _LANGUAGES.keys()
Adele Zhou6b9527c2015-11-20 15:56:35 -0800844else:
845 lang_list = args.language
Craig Tiller16900662016-01-07 19:30:54 -0800846# We don't support code coverage on some languages
847if 'gcov' in args.config:
Jan Tattermusch3b5121b2016-02-22 17:41:05 -0800848 for bad in ['objc', 'sanity']:
Craig Tiller16900662016-01-07 19:30:54 -0800849 if bad in lang_list:
850 lang_list.remove(bad)
Adele Zhou6b9527c2015-11-20 15:56:35 -0800851
852languages = set(_LANGUAGES[l] for l in lang_list)
Jan Tattermusch77db4322016-02-20 20:19:35 -0800853for l in languages:
854 l.configure(run_config, args)
murgatroid99132ce6a2015-03-04 17:29:14 -0800855
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800856language_make_options=[]
857if any(language.make_options() for language in languages):
858 if len(languages) != 1:
859 print 'languages with custom make options cannot be built simultaneously with other languages'
860 sys.exit(1)
861 else:
862 language_make_options = next(iter(languages)).make_options()
863
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800864if args.use_docker:
865 if not args.travis:
866 print 'Seen --use_docker flag, will run tests under docker.'
867 print
868 print 'IMPORTANT: The changes you are testing need to be locally committed'
869 print 'because only the committed changes in the current branch will be'
870 print 'copied to the docker environment.'
871 time.sleep(5)
872
Jan Tattermusch3b5121b2016-02-22 17:41:05 -0800873 dockerfile_dirs = set([l.dockerfile_dir() for l in languages])
874 if len(dockerfile_dirs) > 1:
Adele Zhou9506ef22016-03-02 13:53:34 -0800875 if 'gcov' in args.config:
876 dockerfile_dir = 'tools/dockerfile/test/multilang_jessie_x64'
877 print ('Using multilang_jessie_x64 docker image for code coverage for '
878 'all languages.')
879 else:
880 print ('Languages to be tested require running under different docker '
881 'images.')
882 sys.exit(1)
883 else:
884 dockerfile_dir = next(iter(dockerfile_dirs))
885
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800886 child_argv = [ arg for arg in sys.argv if not arg == '--use_docker' ]
Jan Tattermusched342b12016-01-26 14:40:31 -0800887 run_tests_cmd = 'python tools/run_tests/run_tests.py %s' % ' '.join(child_argv[1:])
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800888
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800889 env = os.environ.copy()
890 env['RUN_TESTS_COMMAND'] = run_tests_cmd
Jan Tattermusch3b5121b2016-02-22 17:41:05 -0800891 env['DOCKERFILE_DIR'] = dockerfile_dir
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800892 env['DOCKER_RUN_SCRIPT'] = 'tools/jenkins/docker_run_tests.sh'
893 if args.xml_report:
894 env['XML_REPORT'] = args.xml_report
895 if not args.travis:
896 env['TTY_FLAG'] = '-t' # enables Ctrl-C when not on Jenkins.
897
898 subprocess.check_call(['tools/jenkins/build_docker_and_run_tests.sh'],
899 shell=True,
900 env=env)
901 sys.exit(0)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800902
Jan Tattermuschf08018a2016-01-26 08:22:09 -0800903_check_arch_option(args.arch)
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800904
Jan Tattermuschfba65302016-01-25 18:21:14 -0800905def make_jobspec(cfg, targets, makefile='Makefile'):
906 if platform_string() == 'windows':
Craig Tillerfc3c0c42015-09-01 16:47:54 -0700907 extra_args = []
Craig Tillerb5391e12015-09-03 14:35:18 -0700908 # better do parallel compilation
Jan Tattermusch47eeb2b2015-10-07 14:09:18 -0700909 # empirically /m:2 gives the best performance/price and should prevent
910 # overloading the windows workers.
Adele Zhoue4c35612015-10-16 15:34:23 -0700911 extra_args.extend(['/m:2'])
Craig Tillerb5391e12015-09-03 14:35:18 -0700912 # disable PDB generation: it's broken, and we don't need it during CI
Adele Zhoue4c35612015-10-16 15:34:23 -0700913 extra_args.extend(['/p:Jenkins=true'])
Craig Tiller6fd23842015-09-01 07:36:31 -0700914 return [
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800915 jobset.JobSpec([_windows_build_bat(args.compiler),
murgatroid99cf08daf2015-09-21 15:33:16 -0700916 'vsprojects\\%s.sln' % target,
Jan Tattermuscha2d964c2016-02-22 17:33:09 -0800917 '/p:Configuration=%s' % _MSBUILD_CONFIG[cfg]] +
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800918 extra_args +
919 language_make_options,
Craig Tiller590105a2016-01-19 13:03:46 -0800920 shell=True, timeout_seconds=None)
Craig Tiller6fd23842015-09-01 07:36:31 -0700921 for target in targets]
Jan Tattermuschfba65302016-01-25 18:21:14 -0800922 else:
murgatroid998ae409f2015-10-26 16:39:00 -0700923 if targets:
924 return [jobset.JobSpec([os.getenv('MAKE', 'make'),
925 '-f', makefile,
Craig Tillerdd6f7ed2016-01-21 12:54:42 -0800926 '-j', '%d' % args.jobs,
Craig Tiller71a86042016-01-15 14:59:58 -0800927 'EXTRA_DEFINES=GRPC_TEST_SLOWDOWN_MACHINE_FACTOR=%f' % args.slowdown,
928 'CONFIG=%s' % cfg] +
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800929 language_make_options +
Craig Tiller71a86042016-01-15 14:59:58 -0800930 ([] if not args.travis else ['JENKINS_BUILD=1']) +
931 targets,
Craig Tiller590105a2016-01-19 13:03:46 -0800932 timeout_seconds=None)]
murgatroid998ae409f2015-10-26 16:39:00 -0700933 else:
934 return []
Jan Tattermuschfba65302016-01-25 18:21:14 -0800935
murgatroid99a3e244f2015-09-22 11:25:53 -0700936make_targets = {}
937for l in languages:
938 makefile = l.makefile_name()
939 make_targets[makefile] = make_targets.get(makefile, set()).union(
Jan Tattermusch77db4322016-02-20 20:19:35 -0800940 set(l.make_targets()))
Craig Tiller5058c692015-04-08 09:42:04 -0700941
Jan Tattermusche4a69182015-12-15 09:53:01 -0800942def build_step_environ(cfg):
943 environ = {'CONFIG': cfg}
Jan Tattermuscha2d964c2016-02-22 17:33:09 -0800944 msbuild_cfg = _MSBUILD_CONFIG.get(cfg)
Jan Tattermusche4a69182015-12-15 09:53:01 -0800945 if msbuild_cfg:
946 environ['MSBUILD_CONFIG'] = msbuild_cfg
947 return environ
948
murgatroid99fddac962015-09-22 09:20:11 -0700949build_steps = list(set(
Jan Tattermusch77db4322016-02-20 20:19:35 -0800950 jobset.JobSpec(cmdline, environ=build_step_environ(build_config), flake_retries=5)
murgatroid99256d3df2015-09-21 16:58:02 -0700951 for l in languages
952 for cmdline in l.pre_build_steps()))
Craig Tillerbd4e3782015-09-01 06:48:55 -0700953if make_targets:
Jan Tattermusch77db4322016-02-20 20:19:35 -0800954 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 -0700955 build_steps.extend(set(make_commands))
Craig Tiller5058c692015-04-08 09:42:04 -0700956build_steps.extend(set(
Jan Tattermusch77db4322016-02-20 20:19:35 -0800957 jobset.JobSpec(cmdline, environ=build_step_environ(build_config), timeout_seconds=None)
Craig Tiller547db2b2015-01-30 14:08:39 -0800958 for l in languages
Craig Tiller533b1a22015-05-29 08:41:29 -0700959 for cmdline in l.build_steps()))
Craig Tillerf1973b02015-01-16 12:32:13 -0800960
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200961post_tests_steps = list(set(
Jan Tattermusch77db4322016-02-20 20:19:35 -0800962 jobset.JobSpec(cmdline, environ=build_step_environ(build_config))
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200963 for l in languages
964 for cmdline in l.post_tests_steps()))
Nicolas Nobleddef2462015-01-06 18:08:25 -0800965runs_per_test = args.runs_per_test
ctiller3040cb72015-01-07 12:13:17 -0800966forever = args.forever
Nicolas Nobleddef2462015-01-06 18:08:25 -0800967
Nicolas Nobleddef2462015-01-06 18:08:25 -0800968
Craig Tiller71735182015-01-15 17:07:13 -0800969class TestCache(object):
Craig Tillerb50d1662015-01-15 17:28:21 -0800970 """Cache for running tests."""
971
David Klempner25739582015-02-11 15:57:32 -0800972 def __init__(self, use_cache_results):
Craig Tiller71735182015-01-15 17:07:13 -0800973 self._last_successful_run = {}
David Klempner25739582015-02-11 15:57:32 -0800974 self._use_cache_results = use_cache_results
Craig Tiller69cd2372015-06-11 09:38:09 -0700975 self._last_save = time.time()
Craig Tiller71735182015-01-15 17:07:13 -0800976
977 def should_run(self, cmdline, bin_hash):
Craig Tiller71735182015-01-15 17:07:13 -0800978 if cmdline not in self._last_successful_run:
979 return True
980 if self._last_successful_run[cmdline] != bin_hash:
981 return True
David Klempner25739582015-02-11 15:57:32 -0800982 if not self._use_cache_results:
983 return True
Craig Tiller71735182015-01-15 17:07:13 -0800984 return False
985
986 def finished(self, cmdline, bin_hash):
Craig Tiller547db2b2015-01-30 14:08:39 -0800987 self._last_successful_run[cmdline] = bin_hash
Craig Tiller69cd2372015-06-11 09:38:09 -0700988 if time.time() - self._last_save > 1:
989 self.save()
Craig Tiller71735182015-01-15 17:07:13 -0800990
991 def dump(self):
Craig Tillerb50d1662015-01-15 17:28:21 -0800992 return [{'cmdline': k, 'hash': v}
993 for k, v in self._last_successful_run.iteritems()]
Craig Tiller71735182015-01-15 17:07:13 -0800994
995 def parse(self, exdump):
996 self._last_successful_run = dict((o['cmdline'], o['hash']) for o in exdump)
997
998 def save(self):
999 with open('.run_tests_cache', 'w') as f:
Craig Tiller261dd982015-01-16 16:41:45 -08001000 f.write(json.dumps(self.dump()))
Craig Tiller69cd2372015-06-11 09:38:09 -07001001 self._last_save = time.time()
Craig Tiller71735182015-01-15 17:07:13 -08001002
Craig Tiller1cc11db2015-01-15 22:50:50 -08001003 def maybe_load(self):
1004 if os.path.exists('.run_tests_cache'):
1005 with open('.run_tests_cache') as f:
Craig Tiller261dd982015-01-16 16:41:45 -08001006 self.parse(json.loads(f.read()))
Craig Tiller71735182015-01-15 17:07:13 -08001007
1008
Craig Tillerf53d9c82015-08-04 14:19:43 -07001009def _start_port_server(port_server_port):
1010 # check if a compatible port server is running
1011 # if incompatible (version mismatch) ==> start a new one
1012 # if not running ==> start a new one
1013 # otherwise, leave it up
1014 try:
Craig Tillerfe4939f2015-10-06 12:55:36 -07001015 version = int(urllib2.urlopen(
1016 'http://localhost:%d/version_number' % port_server_port,
1017 timeout=1).read())
1018 print 'detected port server running version %d' % version
Craig Tillerf53d9c82015-08-04 14:19:43 -07001019 running = True
Craig Tillerfe4939f2015-10-06 12:55:36 -07001020 except Exception as e:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001021 print 'failed to detect port server: %s' % sys.exc_info()[0]
Craig Tillerfe4939f2015-10-06 12:55:36 -07001022 print e.strerror
Craig Tillerf53d9c82015-08-04 14:19:43 -07001023 running = False
1024 if running:
Craig Tillerfe4939f2015-10-06 12:55:36 -07001025 current_version = int(subprocess.check_output(
Jan Tattermusch3bd08272015-11-04 19:24:37 -08001026 [sys.executable, os.path.abspath('tools/run_tests/port_server.py'),
1027 'dump_version']))
Craig Tillerfe4939f2015-10-06 12:55:36 -07001028 print 'my port server is version %d' % current_version
1029 running = (version >= current_version)
1030 if not running:
1031 print 'port_server version mismatch: killing the old one'
1032 urllib2.urlopen('http://localhost:%d/quitquitquit' % port_server_port).read()
1033 time.sleep(1)
Craig Tillerf53d9c82015-08-04 14:19:43 -07001034 if not running:
Craig Tillerf0a293e2015-10-12 10:05:50 -07001035 fd, logfile = tempfile.mkstemp()
1036 os.close(fd)
1037 print 'starting port_server, with log file %s' % logfile
Jan Tattermusch3bd08272015-11-04 19:24:37 -08001038 args = [sys.executable, os.path.abspath('tools/run_tests/port_server.py'),
1039 '-p', '%d' % port_server_port, '-l', logfile]
Craig Tiller367d41d2015-10-12 13:00:22 -07001040 env = dict(os.environ)
1041 env['BUILD_ID'] = 'pleaseDontKillMeJenkins'
Nicolas "Pixel" Noblef72d7b52015-12-03 03:07:43 +01001042 if platform_string() == 'windows':
Jan Tattermusch3bd08272015-11-04 19:24:37 -08001043 # Working directory of port server needs to be outside of Jenkins
1044 # workspace to prevent file lock issues.
1045 tempdir = tempfile.mkdtemp()
Craig Tillerd2c39712015-10-12 11:08:49 -07001046 port_server = subprocess.Popen(
Craig Tiller367d41d2015-10-12 13:00:22 -07001047 args,
1048 env=env,
Jan Tattermusch3bd08272015-11-04 19:24:37 -08001049 cwd=tempdir,
Craig Tiller367d41d2015-10-12 13:00:22 -07001050 creationflags = 0x00000008, # detached process
1051 close_fds=True)
Craig Tillerd2c39712015-10-12 11:08:49 -07001052 else:
1053 port_server = subprocess.Popen(
1054 args,
Craig Tiller367d41d2015-10-12 13:00:22 -07001055 env=env,
Craig Tillerd2c39712015-10-12 11:08:49 -07001056 preexec_fn=os.setsid,
1057 close_fds=True)
Craig Tillerf0a293e2015-10-12 10:05:50 -07001058 time.sleep(1)
Craig Tiller8b5f4dc2015-08-26 08:02:01 -07001059 # ensure port server is up
Craig Tillerabd37fd2015-08-26 07:54:01 -07001060 waits = 0
Craig Tillerf53d9c82015-08-04 14:19:43 -07001061 while True:
Craig Tillerabd37fd2015-08-26 07:54:01 -07001062 if waits > 10:
Craig Tillerf0a293e2015-10-12 10:05:50 -07001063 print 'killing port server due to excessive start up waits'
Craig Tillerabd37fd2015-08-26 07:54:01 -07001064 port_server.kill()
Craig Tillera2f38b02015-09-24 11:19:17 -07001065 if port_server.poll() is not None:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001066 print 'port_server failed to start'
Craig Tillerf0a293e2015-10-12 10:05:50 -07001067 # try one final time: maybe another build managed to start one
1068 time.sleep(1)
1069 try:
1070 urllib2.urlopen('http://localhost:%d/get' % port_server_port,
1071 timeout=1).read()
1072 print 'last ditch attempt to contact port server succeeded'
1073 break
1074 except:
Jan Tattermusch3b5121b2016-02-22 17:41:05 -08001075 traceback.print_exc()
Craig Tillerf0a293e2015-10-12 10:05:50 -07001076 port_log = open(logfile, 'r').read()
1077 print port_log
1078 sys.exit(1)
Craig Tillerf53d9c82015-08-04 14:19:43 -07001079 try:
Craig Tillerabd37fd2015-08-26 07:54:01 -07001080 urllib2.urlopen('http://localhost:%d/get' % port_server_port,
1081 timeout=1).read()
Craig Tillerf0a293e2015-10-12 10:05:50 -07001082 print 'port server is up and ready'
Craig Tillerf53d9c82015-08-04 14:19:43 -07001083 break
Craig Tiller31fdaa42015-09-25 13:09:59 -07001084 except socket.timeout:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001085 print 'waiting for port_server: timeout'
Craig Tillerf0a293e2015-10-12 10:05:50 -07001086 traceback.print_exc();
1087 time.sleep(1)
Craig Tiller31fdaa42015-09-25 13:09:59 -07001088 waits += 1
Craig Tillerf53d9c82015-08-04 14:19:43 -07001089 except urllib2.URLError:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001090 print 'waiting for port_server: urlerror'
Craig Tillerf0a293e2015-10-12 10:05:50 -07001091 traceback.print_exc();
1092 time.sleep(1)
Craig Tillerabd37fd2015-08-26 07:54:01 -07001093 waits += 1
Craig Tillerf53d9c82015-08-04 14:19:43 -07001094 except:
Jan Tattermusch3b5121b2016-02-22 17:41:05 -08001095 traceback.print_exc()
Craig Tillerf53d9c82015-08-04 14:19:43 -07001096 port_server.kill()
1097 raise
1098
1099
Adele Zhoud5fffa52015-10-23 15:51:42 -07001100def _calculate_num_runs_failures(list_of_results):
1101 """Caculate number of runs and failures for a particular test.
1102
1103 Args:
1104 list_of_results: (List) of JobResult object.
1105 Returns:
1106 A tuple of total number of runs and failures.
1107 """
1108 num_runs = len(list_of_results) # By default, there is 1 run per JobResult.
1109 num_failures = 0
1110 for jobresult in list_of_results:
1111 if jobresult.retries > 0:
1112 num_runs += jobresult.retries
1113 if jobresult.num_failures > 0:
1114 num_failures += jobresult.num_failures
1115 return num_runs, num_failures
1116
Adele Zhou6b9527c2015-11-20 15:56:35 -08001117
Craig Tillereb9de8b2016-01-08 08:57:41 -08001118# _build_and_run results
1119class BuildAndRunError(object):
1120
1121 BUILD = object()
1122 TEST = object()
1123 POST_TEST = object()
1124
1125
1126# returns a list of things that failed (or an empty list on success)
Craig Tillerf53d9c82015-08-04 14:19:43 -07001127def _build_and_run(
Jan Tattermusch2dd156e2015-12-04 18:26:17 -08001128 check_cancelled, newline_on_success, cache, xml_report=None, build_only=False):
ctiller3040cb72015-01-07 12:13:17 -08001129 """Do one pass of building & running tests."""
murgatroid99666450e2015-01-26 13:03:31 -08001130 # build latest sequentially
Jan Tattermuschaab1e512016-01-28 09:30:44 -08001131 num_failures, resultset = jobset.run(
Adele Zhoue4c35612015-10-16 15:34:23 -07001132 build_steps, maxjobs=1, stop_on_failure=True,
Craig Tiller883064c2015-11-04 10:06:10 -08001133 newline_on_success=newline_on_success, travis=args.travis)
Adele Zhoue4c35612015-10-16 15:34:23 -07001134 if num_failures:
Craig Tillereb9de8b2016-01-08 08:57:41 -08001135 return [BuildAndRunError.BUILD]
Craig Tillerb361b4e2016-01-06 11:44:17 -08001136
Jan Tattermusch2dd156e2015-12-04 18:26:17 -08001137 if build_only:
Jan Tattermuschaab1e512016-01-28 09:30:44 -08001138 if xml_report:
1139 report_utils.render_junit_xml_report(resultset, xml_report)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001140 return []
ctiller3040cb72015-01-07 12:13:17 -08001141
Craig Tiller234b6e72015-05-23 10:12:40 -07001142 # start antagonists
David Garcia Quintas79e389f2015-06-02 17:49:42 -07001143 antagonists = [subprocess.Popen(['tools/run_tests/antagonist.py'])
Craig Tiller234b6e72015-05-23 10:12:40 -07001144 for _ in range(0, args.antagonists)]
Craig Tillerfe4939f2015-10-06 12:55:36 -07001145 port_server_port = 32767
Craig Tillerf53d9c82015-08-04 14:19:43 -07001146 _start_port_server(port_server_port)
Adele Zhou7cf72112015-11-04 11:18:43 -08001147 resultset = None
Adele Zhou803af152015-11-30 15:16:16 -08001148 num_test_failures = 0
Craig Tiller234b6e72015-05-23 10:12:40 -07001149 try:
David Garcia Quintase90cd372015-05-31 18:15:26 -07001150 infinite_runs = runs_per_test == 0
yang-g6c1fdc62015-08-18 11:57:42 -07001151 one_run = set(
1152 spec
yang-g6c1fdc62015-08-18 11:57:42 -07001153 for language in languages
Jan Tattermusch77db4322016-02-20 20:19:35 -08001154 for spec in language.test_specs()
yang-g6c1fdc62015-08-18 11:57:42 -07001155 if re.search(args.regex, spec.shortname))
David Garcia Quintas79e389f2015-06-02 17:49:42 -07001156 # When running on travis, we want out test runs to be as similar as possible
1157 # for reproducibility purposes.
Craig Tiller883064c2015-11-04 10:06:10 -08001158 if args.travis:
David Garcia Quintas79e389f2015-06-02 17:49:42 -07001159 massaged_one_run = sorted(one_run, key=lambda x: x.shortname)
1160 else:
1161 # whereas otherwise, we want to shuffle things up to give all tests a
1162 # chance to run.
1163 massaged_one_run = list(one_run) # random.shuffle needs an indexable seq.
1164 random.shuffle(massaged_one_run) # which it modifies in-place.
Craig Tillerf7b7c892015-06-22 14:33:25 -07001165 if infinite_runs:
1166 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 -07001167 runs_sequence = (itertools.repeat(massaged_one_run) if infinite_runs
1168 else itertools.repeat(massaged_one_run, runs_per_test))
David Garcia Quintase90cd372015-05-31 18:15:26 -07001169 all_runs = itertools.chain.from_iterable(runs_sequence)
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +02001170
Adele Zhou803af152015-11-30 15:16:16 -08001171 num_test_failures, resultset = jobset.run(
Adele Zhou2271ab52015-10-28 13:59:14 -07001172 all_runs, check_cancelled, newline_on_success=newline_on_success,
Craig Tiller883064c2015-11-04 10:06:10 -08001173 travis=args.travis, infinite_runs=infinite_runs, maxjobs=args.jobs,
murgatroid998ae409f2015-10-26 16:39:00 -07001174 stop_on_failure=args.stop_on_failure,
Adele Zhouf2ca7bc2015-10-23 15:38:00 -07001175 cache=cache if not xml_report else None,
Adele Zhouf2ca7bc2015-10-23 15:38:00 -07001176 add_env={'GRPC_TEST_PORT_SERVER': 'localhost:%d' % port_server_port})
Adele Zhoud5fffa52015-10-23 15:51:42 -07001177 if resultset:
1178 for k, v in resultset.iteritems():
1179 num_runs, num_failures = _calculate_num_runs_failures(v)
1180 if num_failures == num_runs: # what about infinite_runs???
1181 jobset.message('FAILED', k, do_newline=True)
1182 elif num_failures > 0:
1183 jobset.message(
1184 'FLAKE', '%s [%d/%d runs flaked]' % (k, num_failures, num_runs),
1185 do_newline=True)
1186 else:
1187 jobset.message('PASSED', k, do_newline=True)
Craig Tiller234b6e72015-05-23 10:12:40 -07001188 finally:
1189 for antagonist in antagonists:
1190 antagonist.kill()
Adele Zhou7cf72112015-11-04 11:18:43 -08001191 if xml_report and resultset:
Adele Zhou3bc7ba42015-11-05 10:21:58 -08001192 report_utils.render_junit_xml_report(resultset, xml_report)
Craig Tillerd86a3942015-01-14 12:48:54 -08001193
Adele Zhouf2ca7bc2015-10-23 15:38:00 -07001194 number_failures, _ = jobset.run(
1195 post_tests_steps, maxjobs=1, stop_on_failure=True,
Craig Tiller883064c2015-11-04 10:06:10 -08001196 newline_on_success=newline_on_success, travis=args.travis)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001197
1198 out = []
1199 if number_failures:
1200 out.append(BuildAndRunError.POST_TEST)
1201 if num_test_failures:
1202 out.append(BuildAndRunError.TEST)
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +02001203
Craig Tiller69cd2372015-06-11 09:38:09 -07001204 if cache: cache.save()
1205
Craig Tillereb9de8b2016-01-08 08:57:41 -08001206 return out
ctiller3040cb72015-01-07 12:13:17 -08001207
1208
David Klempner25739582015-02-11 15:57:32 -08001209test_cache = TestCache(runs_per_test == 1)
Craig Tiller547db2b2015-01-30 14:08:39 -08001210test_cache.maybe_load()
Craig Tiller71735182015-01-15 17:07:13 -08001211
ctiller3040cb72015-01-07 12:13:17 -08001212if forever:
Nicolas Noble044db742015-01-14 16:57:24 -08001213 success = True
ctiller3040cb72015-01-07 12:13:17 -08001214 while True:
Craig Tiller42bc87c2015-02-23 08:50:19 -08001215 dw = watch_dirs.DirWatcher(['src', 'include', 'test', 'examples'])
ctiller3040cb72015-01-07 12:13:17 -08001216 initial_time = dw.most_recent_change()
1217 have_files_changed = lambda: dw.most_recent_change() != initial_time
Nicolas Noble044db742015-01-14 16:57:24 -08001218 previous_success = success
Craig Tillereb9de8b2016-01-08 08:57:41 -08001219 errors = _build_and_run(check_cancelled=have_files_changed,
1220 newline_on_success=False,
1221 cache=test_cache,
1222 build_only=args.build_only) == 0
1223 if not previous_success and not errors:
Nicolas Nobleb09078f2015-01-14 18:06:05 -08001224 jobset.message('SUCCESS',
1225 'All tests are now passing properly',
1226 do_newline=True)
Nicolas Noble044db742015-01-14 16:57:24 -08001227 jobset.message('IDLE', 'No change detected')
ctiller3040cb72015-01-07 12:13:17 -08001228 while not have_files_changed():
1229 time.sleep(1)
1230else:
Craig Tillereb9de8b2016-01-08 08:57:41 -08001231 errors = _build_and_run(check_cancelled=lambda: False,
Craig Tiller71735182015-01-15 17:07:13 -08001232 newline_on_success=args.newline_on_success,
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +02001233 cache=test_cache,
Jan Tattermusch2dd156e2015-12-04 18:26:17 -08001234 xml_report=args.xml_report,
1235 build_only=args.build_only)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001236 if not errors:
Nicolas Nobleb09078f2015-01-14 18:06:05 -08001237 jobset.message('SUCCESS', 'All tests passed', do_newline=True)
1238 else:
1239 jobset.message('FAILED', 'Some tests failed', do_newline=True)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001240 exit_code = 0
1241 if BuildAndRunError.BUILD in errors:
1242 exit_code |= 1
Craig Tiller4f2be362016-01-08 08:59:20 -08001243 if BuildAndRunError.TEST in errors and not args.travis:
Craig Tillereb9de8b2016-01-08 08:57:41 -08001244 exit_code |= 2
Craig Tiller4f2be362016-01-08 08:59:20 -08001245 if BuildAndRunError.POST_TEST in errors:
1246 exit_code |= 4
Craig Tillereb9de8b2016-01-08 08:57:41 -08001247 sys.exit(exit_code)