blob: 4201402b06f1e702253f99554ff44dd685e20298 [file] [log] [blame]
Nathaniel Manistaae4fbcd2015-09-23 16:29:44 +00001#!/usr/bin/env python2.7
Craig Tiller6169d5f2016-03-31 07:46:18 -07002# Copyright 2015, 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 Tillerde7edf82016-03-20 09:12:16 -070083 shortname=None, environ={}, cpu_cost=1.0, flaky=False):
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 Tillerde7edf82016-03-20 09:12:16 -0700105 flake_retries=5 if flaky or args.allow_flakes else 0,
Craig Tiller35505de2015-10-08 13:31:33 -0700106 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:
Jan Tattermuschb2531e22016-03-25 16:14:41 -0700123 raise Exception('Compiler %s not supported (on this platform).' % compiler)
124
125
126def _check_arch(arch, supported_archs):
127 if arch not in supported_archs:
128 raise Exception('Architecture %s not supported.' % arch)
Jan Tattermusch77db4322016-02-20 20:19:35 -0800129
130
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800131def _is_use_docker_child():
132 """Returns True if running running as a --use_docker child."""
133 return True if os.getenv('RUN_TESTS_COMMAND') else False
134
135
Craig Tillerc7449162015-01-16 14:42:10 -0800136class CLanguage(object):
137
Craig Tillere9c959d2015-01-18 10:23:26 -0800138 def __init__(self, make_target, test_lang):
Craig Tillerc7449162015-01-16 14:42:10 -0800139 self.make_target = make_target
Craig Tillerd50993d2015-08-05 08:04:36 -0700140 self.platform = platform_string()
Craig Tiller711bbe62015-08-19 12:35:16 -0700141 self.test_lang = test_lang
Craig Tillerc7449162015-01-16 14:42:10 -0800142
Jan Tattermusch77db4322016-02-20 20:19:35 -0800143 def configure(self, config, args):
144 self.config = config
145 self.args = args
146 if self.platform == 'windows':
Jan Tattermuschc96caf82016-02-22 17:31:02 -0800147 self._make_options = [_windows_toolset_option(self.args.compiler),
148 _windows_arch_option(self.args.arch)]
Jan Tattermusch77db4322016-02-20 20:19:35 -0800149 else:
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800150 self._docker_distro, self._make_options = self._compiler_options(self.args.use_docker,
151 self.args.compiler)
Jan Tattermusch77db4322016-02-20 20:19:35 -0800152
153 def test_specs(self):
Craig Tiller547db2b2015-01-30 14:08:39 -0800154 out = []
Jan Tattermusch77db4322016-02-20 20:19:35 -0800155 binaries = get_c_tests(self.args.travis, self.test_lang)
Craig Tillerb38197e2016-02-26 10:14:54 -0800156 POLLING_STRATEGIES = {
157 'windows': ['all'],
158 'mac': ['all'],
159 'posix': ['all'],
Craig Tillerc29298d2016-05-31 13:45:38 -0700160 'linux': ['poll', 'legacy']
Craig Tillerb38197e2016-02-26 10:14:54 -0800161 }
Craig Tiller946ce7a2016-04-06 10:35:58 -0700162 for target in binaries:
163 polling_strategies = (POLLING_STRATEGIES[self.platform]
164 if target.get('uses_polling', True)
165 else ['all'])
166 for polling_strategy in polling_strategies:
167 env={'GRPC_DEFAULT_SSL_ROOTS_FILE_PATH':
168 _ROOT + '/src/core/lib/tsi/test_creds/ca.pem',
Craig Tillered735102016-04-06 12:59:23 -0700169 'GRPC_POLL_STRATEGY': polling_strategy}
Craig Tiller946ce7a2016-04-06 10:35:58 -0700170 shortname_ext = '' if polling_strategy=='all' else ' polling=%s' % polling_strategy
Craig Tillerb38197e2016-02-26 10:14:54 -0800171 if self.config.build_config in target['exclude_configs']:
172 continue
173 if self.platform == 'windows':
174 binary = 'vsprojects/%s%s/%s.exe' % (
175 'x64/' if self.args.arch == 'x64' else '',
176 _MSBUILD_CONFIG[self.config.build_config],
177 target['name'])
Craig Tillerca62ff02016-02-24 22:22:57 -0800178 else:
Craig Tillerb38197e2016-02-26 10:14:54 -0800179 binary = 'bins/%s/%s' % (self.config.build_config, target['name'])
180 if os.path.isfile(binary):
181 if 'gtest' in target and target['gtest']:
182 # here we parse the output of --gtest_list_tests to build up a
183 # complete list of the tests contained in a binary
184 # for each test, we then add a job to run, filtering for just that
185 # test
186 with open(os.devnull, 'w') as fnull:
187 tests = subprocess.check_output([binary, '--gtest_list_tests'],
188 stderr=fnull)
189 base = None
190 for line in tests.split('\n'):
191 i = line.find('#')
192 if i >= 0: line = line[:i]
193 if not line: continue
194 if line[0] != ' ':
195 base = line.strip()
196 else:
197 assert base is not None
198 assert line[1] == ' '
199 test = base + line.strip()
200 cmdline = [binary] + ['--gtest_filter=%s' % test]
201 out.append(self.config.job_spec(cmdline, [binary],
Craig Tiller334db352016-02-26 15:19:49 -0800202 shortname='%s:%s %s' % (binary, test, shortname_ext),
Craig Tillerb38197e2016-02-26 10:14:54 -0800203 cpu_cost=target['cpu_cost'],
204 environ=env))
205 else:
206 cmdline = [binary] + target['args']
207 out.append(self.config.job_spec(cmdline, [binary],
208 shortname=' '.join(cmdline) + shortname_ext,
209 cpu_cost=target['cpu_cost'],
Craig Tillerc2278152016-03-21 08:59:54 -0700210 flaky=target.get('flaky', False),
Craig Tillerb38197e2016-02-26 10:14:54 -0800211 environ=env))
212 elif self.args.regex == '.*' or self.platform == 'windows':
213 print '\nWARNING: binary not found, skipping', binary
Nicolas Noblee1445362015-05-11 17:40:26 -0700214 return sorted(out)
Craig Tillerc7449162015-01-16 14:42:10 -0800215
Jan Tattermusch77db4322016-02-20 20:19:35 -0800216 def make_targets(self):
217 test_regex = self.args.regex
218 if self.platform != 'windows' and self.args.regex != '.*':
Craig Tiller883064c2015-11-04 10:06:10 -0800219 # use the regex to minimize the number of things to build
Craig Tillerb0f275e2016-01-27 10:45:50 -0800220 return [os.path.basename(target['name'])
Craig Tiller883064c2015-11-04 10:06:10 -0800221 for target in get_c_tests(False, self.test_lang)
Craig Tillerb0f275e2016-01-27 10:45:50 -0800222 if re.search(test_regex, '/' + target['name'])]
Jan Tattermusch77db4322016-02-20 20:19:35 -0800223 if self.platform == 'windows':
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700224 # don't build tools on windows just yet
225 return ['buildtests_%s' % self.make_target]
Craig Tiller7552f0f2015-06-19 17:46:20 -0700226 return ['buildtests_%s' % self.make_target, 'tools_%s' % self.make_target]
Craig Tillerc7449162015-01-16 14:42:10 -0800227
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800228 def make_options(self):
Jan Tattermuschc96caf82016-02-22 17:31:02 -0800229 return self._make_options;
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800230
murgatroid99256d3df2015-09-21 16:58:02 -0700231 def pre_build_steps(self):
Jan Tattermusch874aec02015-10-07 19:26:19 -0700232 if self.platform == 'windows':
233 return [['tools\\run_tests\\pre_build_c.bat']]
234 else:
235 return []
murgatroid99256d3df2015-09-21 16:58:02 -0700236
Craig Tillerc7449162015-01-16 14:42:10 -0800237 def build_steps(self):
238 return []
239
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200240 def post_tests_steps(self):
241 if self.platform == 'windows':
242 return []
243 else:
244 return [['tools/run_tests/post_tests_c.sh']]
245
murgatroid99a3e244f2015-09-22 11:25:53 -0700246 def makefile_name(self):
247 return 'Makefile'
248
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800249 def _clang_make_options(self):
250 return ['CC=clang', 'CXX=clang++', 'LD=clang', 'LDXX=clang++']
251
Jan Tattermusch9bb70622016-03-18 10:28:54 -0700252 def _gcc44_make_options(self):
253 return ['CC=gcc-4.4', 'CXX=g++-4.4', 'LD=gcc-4.4', 'LDXX=g++-4.4']
254
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800255 def _compiler_options(self, use_docker, compiler):
256 """Returns docker distro and make options to use for given compiler."""
Jan Tattermuschfd3857b2016-06-03 12:24:03 -0700257 if not use_docker and not _is_use_docker_child():
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800258 _check_compiler(compiler, ['default'])
259
260 if compiler == 'gcc4.9' or compiler == 'default':
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800261 return ('jessie', [])
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800262 elif compiler == 'gcc4.4':
Jan Tattermusch9bb70622016-03-18 10:28:54 -0700263 return ('wheezy', self._gcc44_make_options())
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800264 elif compiler == 'gcc5.3':
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800265 return ('ubuntu1604', [])
266 elif compiler == 'clang3.4':
267 return ('ubuntu1404', self._clang_make_options())
268 elif compiler == 'clang3.6':
269 return ('ubuntu1604', self._clang_make_options())
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800270 else:
271 raise Exception('Compiler %s not supported.' % compiler)
272
Jan Tattermusch77db4322016-02-20 20:19:35 -0800273 def dockerfile_dir(self):
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800274 return 'tools/dockerfile/test/cxx_%s_%s' % (self._docker_distro,
275 _docker_arch_suffix(self.args.arch))
Jan Tattermusch788ee232016-01-26 12:19:44 -0800276
murgatroid99132ce6a2015-03-04 17:29:14 -0800277 def __str__(self):
278 return self.make_target
279
Craig Tillercc0535d2015-12-08 15:14:47 -0800280
murgatroid992c8d5162015-01-26 10:41:21 -0800281class NodeLanguage(object):
282
Jan Tattermusche477b842016-02-06 22:19:01 -0800283 def __init__(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800284 self.platform = platform_string()
Jan Tattermusche477b842016-02-06 22:19:01 -0800285
Jan Tattermusch77db4322016-02-20 20:19:35 -0800286 def configure(self, config, args):
287 self.config = config
288 self.args = args
murgatroid999fab4382016-04-29 15:05:00 -0700289 _check_compiler(self.args.compiler, ['default', 'node0.12',
290 'node4', 'node5'])
291 if self.args.compiler == 'default':
292 self.node_version = '4'
293 else:
294 # Take off the word "node"
295 self.node_version = self.args.compiler[4:]
Jan Tattermusch77db4322016-02-20 20:19:35 -0800296
297 def test_specs(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800298 if self.platform == 'windows':
Jan Tattermusch77db4322016-02-20 20:19:35 -0800299 return [self.config.job_spec(['tools\\run_tests\\run_node.bat'], None)]
Michael Lumishaaa876a2016-02-10 15:27:58 -0800300 else:
Jan Tattermusch77db4322016-02-20 20:19:35 -0800301 return [self.config.job_spec(['tools/run_tests/run_node.sh', self.node_version],
302 None,
303 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
murgatroid992c8d5162015-01-26 10:41:21 -0800304
murgatroid99256d3df2015-09-21 16:58:02 -0700305 def pre_build_steps(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800306 if self.platform == 'windows':
307 return [['tools\\run_tests\\pre_build_node.bat']]
308 else:
309 return [['tools/run_tests/pre_build_node.sh', self.node_version]]
murgatroid99256d3df2015-09-21 16:58:02 -0700310
Jan Tattermusch77db4322016-02-20 20:19:35 -0800311 def make_targets(self):
murgatroid99db5b1602015-10-01 13:20:11 -0700312 return []
murgatroid992c8d5162015-01-26 10:41:21 -0800313
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800314 def make_options(self):
315 return []
316
murgatroid992c8d5162015-01-26 10:41:21 -0800317 def build_steps(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800318 if self.platform == 'windows':
319 return [['tools\\run_tests\\build_node.bat']]
320 else:
321 return [['tools/run_tests/build_node.sh', self.node_version]]
Craig Tillerc7449162015-01-16 14:42:10 -0800322
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200323 def post_tests_steps(self):
324 return []
325
murgatroid99a3e244f2015-09-22 11:25:53 -0700326 def makefile_name(self):
327 return 'Makefile'
328
Jan Tattermusch77db4322016-02-20 20:19:35 -0800329 def dockerfile_dir(self):
330 return 'tools/dockerfile/test/node_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800331
murgatroid99132ce6a2015-03-04 17:29:14 -0800332 def __str__(self):
333 return 'node'
334
Craig Tiller99775822015-01-30 13:07:16 -0800335
Craig Tillerc7449162015-01-16 14:42:10 -0800336class PhpLanguage(object):
337
Jan Tattermusch77db4322016-02-20 20:19:35 -0800338 def configure(self, config, args):
339 self.config = config
340 self.args = args
341 _check_compiler(self.args.compiler, ['default'])
342
343 def test_specs(self):
344 return [self.config.job_spec(['src/php/bin/run_tests.sh'], None,
345 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
Craig Tillerc7449162015-01-16 14:42:10 -0800346
murgatroid99256d3df2015-09-21 16:58:02 -0700347 def pre_build_steps(self):
348 return []
349
Jan Tattermusch77db4322016-02-20 20:19:35 -0800350 def make_targets(self):
Craig Tilleraf7cf542015-05-22 10:07:34 -0700351 return ['static_c', 'shared_c']
Craig Tillerc7449162015-01-16 14:42:10 -0800352
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800353 def make_options(self):
354 return []
355
Craig Tillerc7449162015-01-16 14:42:10 -0800356 def build_steps(self):
357 return [['tools/run_tests/build_php.sh']]
358
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200359 def post_tests_steps(self):
Stanley Cheunga6b95482016-01-13 16:10:48 -0800360 return [['tools/run_tests/post_tests_php.sh']]
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200361
murgatroid99a3e244f2015-09-22 11:25:53 -0700362 def makefile_name(self):
363 return 'Makefile'
364
Jan Tattermusch77db4322016-02-20 20:19:35 -0800365 def dockerfile_dir(self):
366 return 'tools/dockerfile/test/php_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800367
murgatroid99132ce6a2015-03-04 17:29:14 -0800368 def __str__(self):
369 return 'php'
370
Craig Tillerc7449162015-01-16 14:42:10 -0800371
Nathaniel Manista840615e2015-01-22 20:31:47 +0000372class PythonLanguage(object):
373
Jan Tattermusch77db4322016-02-20 20:19:35 -0800374 def configure(self, config, args):
375 self.config = config
376 self.args = args
Jan Tattermusch825471c2016-04-25 16:52:25 -0700377 self._tox_env = self._get_tox_env(self.args.compiler)
Jan Tattermusch77db4322016-02-20 20:19:35 -0800378
379 def test_specs(self):
Jan Tattermusch072ebaa2016-03-01 18:33:12 -0800380 # load list of known test suites
381 with open('src/python/grpcio/tests/tests.json') as tests_json_file:
382 tests_json = json.load(tests_json_file)
Masood Malekghassemi2b841622015-07-28 17:39:02 -0700383 environment = dict(_FORCE_ENVIRON_FOR_WRAPPERS)
Ken Paysonc47e43d2016-05-04 18:46:16 -0700384 environment['PYTHONPATH'] = '{}:{}'.format(
385 os.path.abspath('src/python/gens'),
386 os.path.abspath('src/python/grpcio_health_checking'))
Jan Tattermusch072ebaa2016-03-01 18:33:12 -0800387 if self.config.build_config != 'gcov':
388 return [self.config.job_spec(
Jan Tattermusch825471c2016-04-25 16:52:25 -0700389 ['tools/run_tests/run_python.sh', self._tox_env],
Jan Tattermusch072ebaa2016-03-01 18:33:12 -0800390 None,
391 environ=dict(environment.items() +
Masood Malekghassemif7ff8be2016-03-09 15:27:28 -0800392 [('GRPC_PYTHON_TESTRUNNER_FILTER', suite_name)]),
Jan Tattermusch072ebaa2016-03-01 18:33:12 -0800393 shortname='py.test.%s' % suite_name,
394 timeout_seconds=5*60)
395 for suite_name in tests_json]
396 else:
397 return [self.config.job_spec(['tools/run_tests/run_python.sh'],
398 None,
399 environ=environment,
400 shortname='py.test.coverage',
401 timeout_seconds=15*60)]
402
Nathaniel Manista840615e2015-01-22 20:31:47 +0000403
murgatroid99256d3df2015-09-21 16:58:02 -0700404 def pre_build_steps(self):
405 return []
406
Jan Tattermusch77db4322016-02-20 20:19:35 -0800407 def make_targets(self):
Craig Tilleraf7cf542015-05-22 10:07:34 -0700408 return ['static_c', 'grpc_python_plugin', 'shared_c']
Nathaniel Manista840615e2015-01-22 20:31:47 +0000409
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800410 def make_options(self):
411 return []
412
Nathaniel Manista840615e2015-01-22 20:31:47 +0000413 def build_steps(self):
Jan Tattermusch825471c2016-04-25 16:52:25 -0700414 return [['tools/run_tests/build_python.sh', self._tox_env]]
Nathaniel Manista840615e2015-01-22 20:31:47 +0000415
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200416 def post_tests_steps(self):
417 return []
418
murgatroid99a3e244f2015-09-22 11:25:53 -0700419 def makefile_name(self):
420 return 'Makefile'
421
Jan Tattermusch77db4322016-02-20 20:19:35 -0800422 def dockerfile_dir(self):
423 return 'tools/dockerfile/test/python_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800424
Jan Tattermusch825471c2016-04-25 16:52:25 -0700425 def _get_tox_env(self, compiler):
426 """Returns name of tox environment based on selected compiler."""
427 if compiler == 'python2.7' or compiler == 'default':
428 return 'py27'
429 elif compiler == 'python3.4':
430 return 'py34'
431 else:
432 raise Exception('Compiler %s not supported.' % compiler)
433
murgatroid99132ce6a2015-03-04 17:29:14 -0800434 def __str__(self):
435 return 'python'
436
Craig Tillerd625d812015-04-08 15:52:35 -0700437
murgatroid996a4c4fa2015-02-27 12:08:57 -0800438class RubyLanguage(object):
439
Jan Tattermusch77db4322016-02-20 20:19:35 -0800440 def configure(self, config, args):
441 self.config = config
442 self.args = args
443 _check_compiler(self.args.compiler, ['default'])
444
445 def test_specs(self):
446 return [self.config.job_spec(['tools/run_tests/run_ruby.sh'], None,
447 timeout_seconds=10*60,
448 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
murgatroid996a4c4fa2015-02-27 12:08:57 -0800449
murgatroid99256d3df2015-09-21 16:58:02 -0700450 def pre_build_steps(self):
Nicolas "Pixel" Noblebcf988f2015-10-08 03:00:42 +0200451 return [['tools/run_tests/pre_build_ruby.sh']]
murgatroid99256d3df2015-09-21 16:58:02 -0700452
Jan Tattermusch4651bef2016-02-23 08:31:25 -0800453 def make_targets(self):
murgatroid997d243df2016-02-18 09:58:05 -0800454 return []
murgatroid996a4c4fa2015-02-27 12:08:57 -0800455
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800456 def make_options(self):
457 return []
458
murgatroid996a4c4fa2015-02-27 12:08:57 -0800459 def build_steps(self):
460 return [['tools/run_tests/build_ruby.sh']]
461
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200462 def post_tests_steps(self):
Nicolas "Pixel" Noble7ef1e532015-12-02 00:55:33 +0100463 return [['tools/run_tests/post_tests_ruby.sh']]
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200464
murgatroid99a3e244f2015-09-22 11:25:53 -0700465 def makefile_name(self):
466 return 'Makefile'
467
Jan Tattermusch77db4322016-02-20 20:19:35 -0800468 def dockerfile_dir(self):
469 return 'tools/dockerfile/test/ruby_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800470
murgatroid99132ce6a2015-03-04 17:29:14 -0800471 def __str__(self):
472 return 'ruby'
473
Craig Tillerd625d812015-04-08 15:52:35 -0700474
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800475class CSharpLanguage(object):
Jan Tattermusch77db4322016-02-20 20:19:35 -0800476
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700477 def __init__(self):
Craig Tillerd50993d2015-08-05 08:04:36 -0700478 self.platform = platform_string()
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700479
Jan Tattermusch77db4322016-02-20 20:19:35 -0800480 def configure(self, config, args):
481 self.config = config
482 self.args = args
Jan Tattermusch6d28d352016-03-25 15:07:22 -0700483 if self.platform == 'windows':
Jan Tattermuschb2531e22016-03-25 16:14:41 -0700484 # Explicitly choosing between x86 and x64 arch doesn't work yet
485 _check_arch(self.args.arch, ['default'])
Jan Tattermusch6d28d352016-03-25 15:07:22 -0700486 self._make_options = [_windows_toolset_option(self.args.compiler),
487 _windows_arch_option(self.args.arch)]
488 else:
489 _check_compiler(self.args.compiler, ['default'])
490 if self.platform == 'mac':
491 # On Mac, official distribution of mono is 32bit.
Jan Tattermusch2a322c22016-03-30 13:55:07 -0700492 # TODO(jtattermusch): EMBED_ZLIB=true currently breaks the mac build
493 self._make_options = ['EMBED_OPENSSL=true',
Jan Tattermuschd9ff4562016-03-30 13:40:48 -0700494 'CFLAGS=-m32', 'LDFLAGS=-m32']
Jan Tattermusch6d28d352016-03-25 15:07:22 -0700495 else:
496 self._make_options = ['EMBED_OPENSSL=true', 'EMBED_ZLIB=true']
Jan Tattermusch77db4322016-02-20 20:19:35 -0800497
498 def test_specs(self):
Jan Tattermusch03c01062015-12-11 14:28:56 -0800499 with open('src/csharp/tests.json') as f:
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700500 tests_by_assembly = json.load(f)
Jan Tattermusch03c01062015-12-11 14:28:56 -0800501
Jan Tattermuscha2d964c2016-02-22 17:33:09 -0800502 msbuild_config = _MSBUILD_CONFIG[self.config.build_config]
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700503 nunit_args = ['--labels=All',
Jan Tattermuschf6824c22016-04-08 17:18:44 -0700504 '--noresult',
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700505 '--workers=1']
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700506 if self.platform == 'windows':
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700507 runtime_cmd = []
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700508 else:
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700509 runtime_cmd = ['mono']
Jan Tattermuschbf3b1532015-10-26 10:24:42 -0700510
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700511 specs = []
512 for assembly in tests_by_assembly.iterkeys():
513 assembly_file = 'src/csharp/%s/bin/%s/%s.exe' % (assembly, msbuild_config, assembly)
Jan Tattermuscha5f1f122016-04-11 15:49:56 -0700514 if self.config.build_config != 'gcov' or self.platform != 'windows':
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700515 # normally, run each test as a separate process
516 for test in tests_by_assembly[assembly]:
517 cmdline = runtime_cmd + [assembly_file, '--test=%s' % test] + nunit_args
518 specs.append(self.config.job_spec(cmdline,
519 None,
520 shortname='csharp.%s' % test,
521 environ=_FORCE_ENVIRON_FOR_WRAPPERS))
522 else:
Jan Tattermuscha5f1f122016-04-11 15:49:56 -0700523 # For C# test coverage, run all tests from the same assembly at once
524 # using OpenCover.Console (only works on Windows).
525 cmdline = ['src\\csharp\\packages\\OpenCover.4.6.519\\tools\\OpenCover.Console.exe',
526 '-target:%s' % assembly_file,
527 '-targetdir:src\\csharp',
528 '-targetargs:%s' % ' '.join(nunit_args),
529 '-filter:+[Grpc.Core]*',
530 '-register:user',
531 '-output:src\\csharp\\coverage_csharp_%s.xml' % assembly]
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700532
Jan Tattermuscha5f1f122016-04-11 15:49:56 -0700533 # set really high cpu_cost to make sure instances of OpenCover.Console run exclusively
534 # to prevent problems with registering the profiler.
535 run_exclusive = 1000000
Jan Tattermusch35e608f2016-04-09 16:35:06 -0700536 specs.append(self.config.job_spec(cmdline,
537 None,
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700538 shortname='csharp.coverage.%s' % assembly,
Jan Tattermuscha5f1f122016-04-11 15:49:56 -0700539 cpu_cost=run_exclusive,
Jan Tattermusch77db4322016-02-20 20:19:35 -0800540 environ=_FORCE_ENVIRON_FOR_WRAPPERS))
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700541 return specs
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800542
murgatroid99256d3df2015-09-21 16:58:02 -0700543 def pre_build_steps(self):
Jan Tattermusch48423fc2015-10-07 18:59:16 -0700544 if self.platform == 'windows':
Jan Tattermusch874aec02015-10-07 19:26:19 -0700545 return [['tools\\run_tests\\pre_build_csharp.bat']]
Jan Tattermusch48423fc2015-10-07 18:59:16 -0700546 else:
547 return [['tools/run_tests/pre_build_csharp.sh']]
murgatroid99256d3df2015-09-21 16:58:02 -0700548
Jan Tattermusch77db4322016-02-20 20:19:35 -0800549 def make_targets(self):
Jan Tattermusch6d28d352016-03-25 15:07:22 -0700550 return ['grpc_csharp_ext']
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800551
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800552 def make_options(self):
Jan Tattermusch6d28d352016-03-25 15:07:22 -0700553 return self._make_options;
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800554
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800555 def build_steps(self):
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700556 if self.platform == 'windows':
Jan Tattermusch6d28d352016-03-25 15:07:22 -0700557 return [[_windows_build_bat(self.args.compiler),
558 'src/csharp/Grpc.sln',
559 '/p:Configuration=%s' % _MSBUILD_CONFIG[self.config.build_config]]]
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700560 else:
561 return [['tools/run_tests/build_csharp.sh']]
Nathaniel Manista840615e2015-01-22 20:31:47 +0000562
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200563 def post_tests_steps(self):
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700564 if self.platform == 'windows':
565 return [['tools\\run_tests\\post_tests_csharp.bat']]
566 else:
567 return [['tools/run_tests/post_tests_csharp.sh']]
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200568
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):
573 return 'tools/dockerfile/test/csharp_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800574
murgatroid99132ce6a2015-03-04 17:29:14 -0800575 def __str__(self):
576 return 'csharp'
577
Craig Tillerd625d812015-04-08 15:52:35 -0700578
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700579class ObjCLanguage(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):
587 return [self.config.job_spec(['src/objective-c/tests/run_tests.sh'], None,
588 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700589
murgatroid99256d3df2015-09-21 16:58:02 -0700590 def pre_build_steps(self):
591 return []
592
Jan Tattermusch77db4322016-02-20 20:19:35 -0800593 def make_targets(self):
Jorge Canizalesd0b32e92015-07-30 23:08:43 -0700594 return ['grpc_objective_c_plugin', 'interop_server']
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700595
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800596 def make_options(self):
597 return []
598
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700599 def build_steps(self):
Jorge Canizalesd0b32e92015-07-30 23:08:43 -0700600 return [['src/objective-c/tests/build_tests.sh']]
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700601
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200602 def post_tests_steps(self):
603 return []
604
murgatroid99a3e244f2015-09-22 11:25:53 -0700605 def makefile_name(self):
606 return 'Makefile'
607
Jan Tattermusch77db4322016-02-20 20:19:35 -0800608 def dockerfile_dir(self):
Jan Tattermusch788ee232016-01-26 12:19:44 -0800609 return None
610
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700611 def __str__(self):
612 return 'objc'
613
614
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100615class Sanity(object):
616
Jan Tattermusch77db4322016-02-20 20:19:35 -0800617 def configure(self, config, args):
618 self.config = config
619 self.args = args
620 _check_compiler(self.args.compiler, ['default'])
621
622 def test_specs(self):
Craig Tiller94d04a52016-01-20 10:58:23 -0800623 import yaml
Jan Tattermusch788ee232016-01-26 12:19:44 -0800624 with open('tools/run_tests/sanity/sanity_tests.yaml', 'r') as f:
Jan Tattermusch77db4322016-02-20 20:19:35 -0800625 return [self.config.job_spec(cmd['script'].split(), None,
626 timeout_seconds=None, environ={'TEST': 'true'},
627 cpu_cost=cmd.get('cpu_cost', 1))
Craig Tiller94d04a52016-01-20 10:58:23 -0800628 for cmd in yaml.load(f)]
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100629
murgatroid99256d3df2015-09-21 16:58:02 -0700630 def pre_build_steps(self):
631 return []
632
Jan Tattermusch77db4322016-02-20 20:19:35 -0800633 def make_targets(self):
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100634 return ['run_dep_checks']
635
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800636 def make_options(self):
637 return []
638
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100639 def build_steps(self):
640 return []
641
Nicolas "Pixel" Noble87879b32015-10-12 23:28:53 +0200642 def post_tests_steps(self):
643 return []
644
murgatroid99a3e244f2015-09-22 11:25:53 -0700645 def makefile_name(self):
646 return 'Makefile'
647
Jan Tattermusch77db4322016-02-20 20:19:35 -0800648 def dockerfile_dir(self):
Jan Tattermusche70b3c52016-02-07 20:21:02 -0800649 return 'tools/dockerfile/test/sanity'
Jan Tattermusch788ee232016-01-26 12:19:44 -0800650
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100651 def __str__(self):
652 return 'sanity'
653
Nicolas "Pixel" Noblee55cd7f2015-04-14 17:59:13 +0200654
Craig Tiller738c3342015-01-12 14:28:33 -0800655# different configurations we can run under
Craig Tillera0f85172016-01-20 15:56:06 -0800656with open('tools/run_tests/configs.json') as f:
Craig Tiller1dce9062016-01-20 17:01:56 -0800657 _CONFIGS = dict((cfg['config'], Config(**cfg)) for cfg in ast.literal_eval(f.read()))
Craig Tiller738c3342015-01-12 14:28:33 -0800658
659
Craig Tillerc7449162015-01-16 14:42:10 -0800660_LANGUAGES = {
Craig Tillere9c959d2015-01-18 10:23:26 -0800661 'c++': CLanguage('cxx', 'c++'),
662 'c': CLanguage('c', 'c'),
murgatroid992c8d5162015-01-26 10:41:21 -0800663 'node': NodeLanguage(),
Nathaniel Manista840615e2015-01-22 20:31:47 +0000664 'php': PhpLanguage(),
665 'python': PythonLanguage(),
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800666 'ruby': RubyLanguage(),
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100667 'csharp': CSharpLanguage(),
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700668 'objc' : ObjCLanguage(),
Jan Tattermusch70a57e42016-02-20 18:50:27 -0800669 'sanity': Sanity()
Craig Tillereb272bc2015-01-30 13:13:14 -0800670 }
Nicolas Nobleddef2462015-01-06 18:08:25 -0800671
Jan Tattermusch77db4322016-02-20 20:19:35 -0800672
Jan Tattermuscha2d964c2016-02-22 17:33:09 -0800673_MSBUILD_CONFIG = {
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700674 'dbg': 'Debug',
675 'opt': 'Release',
Jan Tattermusche4a69182015-12-15 09:53:01 -0800676 'gcov': 'Debug',
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700677 }
678
David Garcia Quintase90cd372015-05-31 18:15:26 -0700679
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800680def _windows_arch_option(arch):
681 """Returns msbuild cmdline option for selected architecture."""
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800682 if arch == 'default' or arch == 'x86':
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800683 return '/p:Platform=Win32'
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800684 elif arch == 'x64':
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800685 return '/p:Platform=x64'
686 else:
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800687 print 'Architecture %s not supported.' % arch
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800688 sys.exit(1)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800689
Jan Tattermuschf08018a2016-01-26 08:22:09 -0800690
691def _check_arch_option(arch):
692 """Checks that architecture option is valid."""
693 if platform_string() == 'windows':
694 _windows_arch_option(arch)
695 elif platform_string() == 'linux':
696 # On linux, we need to be running under docker with the right architecture.
Jan Tattermusch07fb0422016-01-26 10:46:56 -0800697 runtime_arch = platform.architecture()[0]
Jan Tattermuschf08018a2016-01-26 08:22:09 -0800698 if arch == 'default':
699 return
700 elif runtime_arch == '64bit' and arch == 'x64':
701 return
702 elif runtime_arch == '32bit' and arch == 'x86':
703 return
704 else:
705 print 'Architecture %s does not match current runtime architecture.' % arch
706 sys.exit(1)
707 else:
708 if args.arch != 'default':
709 print 'Architecture %s not supported on current platform.' % args.arch
710 sys.exit(1)
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800711
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800712
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800713def _windows_build_bat(compiler):
714 """Returns name of build.bat for selected compiler."""
715 if compiler == 'default' or compiler == 'vs2013':
716 return 'vsprojects\\build_vs2013.bat'
717 elif compiler == 'vs2015':
718 return 'vsprojects\\build_vs2015.bat'
719 elif compiler == 'vs2010':
720 return 'vsprojects\\build_vs2010.bat'
721 else:
722 print 'Compiler %s not supported.' % compiler
723 sys.exit(1)
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800724
725
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800726def _windows_toolset_option(compiler):
727 """Returns msbuild PlatformToolset for selected compiler."""
728 if compiler == 'default' or compiler == 'vs2013':
729 return '/p:PlatformToolset=v120'
730 elif compiler == 'vs2015':
731 return '/p:PlatformToolset=v140'
732 elif compiler == 'vs2010':
733 return '/p:PlatformToolset=v100'
734 else:
735 print 'Compiler %s not supported.' % compiler
736 sys.exit(1)
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800737
738
Jan Tattermusche70b3c52016-02-07 20:21:02 -0800739def _docker_arch_suffix(arch):
740 """Returns suffix to dockerfile dir to use."""
741 if arch == 'default' or arch == 'x64':
742 return 'x64'
743 elif arch == 'x86':
744 return 'x86'
745 else:
746 print 'Architecture %s not supported with current settings.' % arch
747 sys.exit(1)
748
749
David Garcia Quintase90cd372015-05-31 18:15:26 -0700750def runs_per_test_type(arg_str):
751 """Auxilary function to parse the "runs_per_test" flag.
752
753 Returns:
754 A positive integer or 0, the latter indicating an infinite number of
755 runs.
756
757 Raises:
758 argparse.ArgumentTypeError: Upon invalid input.
759 """
760 if arg_str == 'inf':
761 return 0
762 try:
763 n = int(arg_str)
764 if n <= 0: raise ValueError
Craig Tiller50e53e22015-06-01 20:18:21 -0700765 return n
David Garcia Quintase90cd372015-05-31 18:15:26 -0700766 except:
Adele Zhoue4c35612015-10-16 15:34:23 -0700767 msg = '\'{}\' is not a positive integer or \'inf\''.format(arg_str)
David Garcia Quintase90cd372015-05-31 18:15:26 -0700768 raise argparse.ArgumentTypeError(msg)
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700769
770# parse command line
771argp = argparse.ArgumentParser(description='Run grpc tests.')
772argp.add_argument('-c', '--config',
Jan Tattermusch77db4322016-02-20 20:19:35 -0800773 choices=sorted(_CONFIGS.keys()),
774 default='opt')
David Garcia Quintase90cd372015-05-31 18:15:26 -0700775argp.add_argument('-n', '--runs_per_test', default=1, type=runs_per_test_type,
776 help='A positive integer or "inf". If "inf", all tests will run in an '
777 'infinite loop. Especially useful in combination with "-f"')
Craig Tillerfe406ec2015-02-24 13:55:12 -0800778argp.add_argument('-r', '--regex', default='.*', type=str)
Vijay Pai488fd0e2016-06-13 12:37:12 -0700779argp.add_argument('--regex_exclude', default='', type=str)
Craig Tiller5f735a62016-01-20 09:31:15 -0800780argp.add_argument('-j', '--jobs', default=multiprocessing.cpu_count(), type=int)
Craig Tiller8451e872015-02-27 09:25:51 -0800781argp.add_argument('-s', '--slowdown', default=1.0, type=float)
ctiller3040cb72015-01-07 12:13:17 -0800782argp.add_argument('-f', '--forever',
783 default=False,
784 action='store_const',
785 const=True)
Nicolas "Pixel" Noblea7df3f92015-02-26 22:07:04 +0100786argp.add_argument('-t', '--travis',
787 default=False,
788 action='store_const',
789 const=True)
Nicolas Noble044db742015-01-14 16:57:24 -0800790argp.add_argument('--newline_on_success',
791 default=False,
792 action='store_const',
793 const=True)
Craig Tiller686fb262015-01-15 07:39:09 -0800794argp.add_argument('-l', '--language',
Craig Tiller60f15e62015-05-13 09:05:17 -0700795 choices=['all'] + sorted(_LANGUAGES.keys()),
Craig Tiller686fb262015-01-15 07:39:09 -0800796 nargs='+',
Craig Tiller60f15e62015-05-13 09:05:17 -0700797 default=['all'])
Craig Tillercd43da82015-05-29 08:41:29 -0700798argp.add_argument('-S', '--stop_on_failure',
799 default=False,
800 action='store_const',
801 const=True)
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700802argp.add_argument('--use_docker',
803 default=False,
804 action='store_const',
805 const=True,
Adele Zhoue4c35612015-10-16 15:34:23 -0700806 help='Run all the tests under docker. That provides ' +
807 'additional isolation and prevents the need to install ' +
808 'language specific prerequisites. Only available on Linux.')
Craig Tillerd4509a12015-09-28 09:18:40 -0700809argp.add_argument('--allow_flakes',
810 default=False,
811 action='store_const',
812 const=True,
Adele Zhoue4c35612015-10-16 15:34:23 -0700813 help='Allow flaky tests to show as passing (re-runs failed tests up to five times)')
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800814argp.add_argument('--arch',
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800815 choices=['default', 'x86', 'x64'],
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800816 default='default',
817 help='Selects architecture to target. For some platforms "default" is the only supported choice.')
818argp.add_argument('--compiler',
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800819 choices=['default',
820 'gcc4.4', 'gcc4.9', 'gcc5.3',
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800821 'clang3.4', 'clang3.6',
Jan Tattermusch825471c2016-04-25 16:52:25 -0700822 'vs2010', 'vs2013', 'vs2015',
murgatroid999fab4382016-04-29 15:05:00 -0700823 'python2.7', 'python3.4',
824 'node0.12', 'node4', 'node5'],
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800825 default='default',
Jan Tattermusch77db4322016-02-20 20:19:35 -0800826 help='Selects compiler to use. Allowed values depend on the platform and language.')
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800827argp.add_argument('--build_only',
828 default=False,
829 action='store_const',
830 const=True,
831 help='Perform all the build steps but dont run any tests.')
Craig Tiller5f735a62016-01-20 09:31:15 -0800832argp.add_argument('--measure_cpu_costs', default=False, action='store_const', const=True,
833 help='Measure the cpu costs of tests')
Craig Tiller1676f912016-01-05 10:49:44 -0800834argp.add_argument('--update_submodules', default=[], nargs='*',
835 help='Update some submodules before building. If any are updated, also run generate_projects. ' +
836 'Submodules are specified as SUBMODULE_NAME:BRANCH; if BRANCH is omitted, master is assumed.')
Craig Tiller234b6e72015-05-23 10:12:40 -0700837argp.add_argument('-a', '--antagonists', default=0, type=int)
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +0200838argp.add_argument('-x', '--xml_report', default=None, type=str,
839 help='Generates a JUnit-compatible XML report')
Nicolas Nobleddef2462015-01-06 18:08:25 -0800840args = argp.parse_args()
841
Craig Tiller5f735a62016-01-20 09:31:15 -0800842jobset.measure_cpu_costs = args.measure_cpu_costs
843
Craig Tiller1676f912016-01-05 10:49:44 -0800844# update submodules if necessary
Craig Tillerb361b4e2016-01-06 11:44:17 -0800845need_to_regenerate_projects = False
846for spec in args.update_submodules:
847 spec = spec.split(':', 1)
848 if len(spec) == 1:
849 submodule = spec[0]
850 branch = 'master'
851 elif len(spec) == 2:
852 submodule = spec[0]
853 branch = spec[1]
854 cwd = 'third_party/%s' % submodule
855 def git(cmd, cwd=cwd):
856 print 'in %s: git %s' % (cwd, cmd)
857 subprocess.check_call('git %s' % cmd, cwd=cwd, shell=True)
858 git('fetch')
859 git('checkout %s' % branch)
860 git('pull origin %s' % branch)
861 if os.path.exists('src/%s/gen_build_yaml.py' % submodule):
862 need_to_regenerate_projects = True
863if need_to_regenerate_projects:
864 if jobset.platform_string() == 'linux':
865 subprocess.check_call('tools/buildgen/generate_projects.sh', shell=True)
866 else:
867 print 'WARNING: may need to regenerate projects, but since we are not on'
868 print ' Linux this step is being skipped. Compilation MAY fail.'
Craig Tiller1676f912016-01-05 10:49:44 -0800869
870
Nicolas Nobleddef2462015-01-06 18:08:25 -0800871# grab config
Jan Tattermusch77db4322016-02-20 20:19:35 -0800872run_config = _CONFIGS[args.config]
873build_config = run_config.build_config
Craig Tillerf1973b02015-01-16 12:32:13 -0800874
Craig Tiller06805272015-06-11 14:46:47 -0700875if args.travis:
murgatroid99d3b5b7f2015-10-06 17:02:03 -0700876 _FORCE_ENVIRON_FOR_WRAPPERS = {'GRPC_TRACE': 'api'}
Craig Tiller06805272015-06-11 14:46:47 -0700877
Adele Zhou6b9527c2015-11-20 15:56:35 -0800878if 'all' in args.language:
Craig Tiller1676f912016-01-05 10:49:44 -0800879 lang_list = _LANGUAGES.keys()
Adele Zhou6b9527c2015-11-20 15:56:35 -0800880else:
881 lang_list = args.language
Craig Tiller16900662016-01-07 19:30:54 -0800882# We don't support code coverage on some languages
883if 'gcov' in args.config:
Jan Tattermusch3b5121b2016-02-22 17:41:05 -0800884 for bad in ['objc', 'sanity']:
Craig Tiller16900662016-01-07 19:30:54 -0800885 if bad in lang_list:
886 lang_list.remove(bad)
Adele Zhou6b9527c2015-11-20 15:56:35 -0800887
888languages = set(_LANGUAGES[l] for l in lang_list)
Jan Tattermusch77db4322016-02-20 20:19:35 -0800889for l in languages:
890 l.configure(run_config, args)
murgatroid99132ce6a2015-03-04 17:29:14 -0800891
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800892language_make_options=[]
893if any(language.make_options() for language in languages):
Adele Zhou3b6ab812016-05-18 17:04:20 -0700894 if not 'gcov' in args.config and len(languages) != 1:
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800895 print 'languages with custom make options cannot be built simultaneously with other languages'
896 sys.exit(1)
897 else:
898 language_make_options = next(iter(languages)).make_options()
899
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800900if args.use_docker:
901 if not args.travis:
902 print 'Seen --use_docker flag, will run tests under docker.'
903 print
904 print 'IMPORTANT: The changes you are testing need to be locally committed'
905 print 'because only the committed changes in the current branch will be'
906 print 'copied to the docker environment.'
907 time.sleep(5)
908
Jan Tattermusch3b5121b2016-02-22 17:41:05 -0800909 dockerfile_dirs = set([l.dockerfile_dir() for l in languages])
910 if len(dockerfile_dirs) > 1:
Adele Zhou9506ef22016-03-02 13:53:34 -0800911 if 'gcov' in args.config:
912 dockerfile_dir = 'tools/dockerfile/test/multilang_jessie_x64'
913 print ('Using multilang_jessie_x64 docker image for code coverage for '
914 'all languages.')
915 else:
916 print ('Languages to be tested require running under different docker '
917 'images.')
918 sys.exit(1)
919 else:
920 dockerfile_dir = next(iter(dockerfile_dirs))
Craig Tillerde7edf82016-03-20 09:12:16 -0700921
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800922 child_argv = [ arg for arg in sys.argv if not arg == '--use_docker' ]
Jan Tattermusched342b12016-01-26 14:40:31 -0800923 run_tests_cmd = 'python tools/run_tests/run_tests.py %s' % ' '.join(child_argv[1:])
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800924
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800925 env = os.environ.copy()
926 env['RUN_TESTS_COMMAND'] = run_tests_cmd
Jan Tattermusch3b5121b2016-02-22 17:41:05 -0800927 env['DOCKERFILE_DIR'] = dockerfile_dir
Jan Tattermusch9835d4b2016-04-29 15:05:05 -0700928 env['DOCKER_RUN_SCRIPT'] = 'tools/run_tests/dockerize/docker_run_tests.sh'
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800929 if args.xml_report:
930 env['XML_REPORT'] = args.xml_report
931 if not args.travis:
932 env['TTY_FLAG'] = '-t' # enables Ctrl-C when not on Jenkins.
933
Jan Tattermusch9835d4b2016-04-29 15:05:05 -0700934 subprocess.check_call(['tools/run_tests/dockerize/build_docker_and_run_tests.sh'],
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800935 shell=True,
936 env=env)
937 sys.exit(0)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800938
Jan Tattermuschf08018a2016-01-26 08:22:09 -0800939_check_arch_option(args.arch)
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800940
Jan Tattermuschfba65302016-01-25 18:21:14 -0800941def make_jobspec(cfg, targets, makefile='Makefile'):
942 if platform_string() == 'windows':
Craig Tillerfc3c0c42015-09-01 16:47:54 -0700943 extra_args = []
Craig Tillerb5391e12015-09-03 14:35:18 -0700944 # better do parallel compilation
Jan Tattermusch47eeb2b2015-10-07 14:09:18 -0700945 # empirically /m:2 gives the best performance/price and should prevent
946 # overloading the windows workers.
Adele Zhoue4c35612015-10-16 15:34:23 -0700947 extra_args.extend(['/m:2'])
Craig Tillerb5391e12015-09-03 14:35:18 -0700948 # disable PDB generation: it's broken, and we don't need it during CI
Adele Zhoue4c35612015-10-16 15:34:23 -0700949 extra_args.extend(['/p:Jenkins=true'])
Craig Tiller6fd23842015-09-01 07:36:31 -0700950 return [
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800951 jobset.JobSpec([_windows_build_bat(args.compiler),
murgatroid99cf08daf2015-09-21 15:33:16 -0700952 'vsprojects\\%s.sln' % target,
Jan Tattermuscha2d964c2016-02-22 17:33:09 -0800953 '/p:Configuration=%s' % _MSBUILD_CONFIG[cfg]] +
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800954 extra_args +
955 language_make_options,
Craig Tiller590105a2016-01-19 13:03:46 -0800956 shell=True, timeout_seconds=None)
Craig Tiller6fd23842015-09-01 07:36:31 -0700957 for target in targets]
Jan Tattermuschfba65302016-01-25 18:21:14 -0800958 else:
murgatroid998ae409f2015-10-26 16:39:00 -0700959 if targets:
960 return [jobset.JobSpec([os.getenv('MAKE', 'make'),
961 '-f', makefile,
Craig Tillerdd6f7ed2016-01-21 12:54:42 -0800962 '-j', '%d' % args.jobs,
Craig Tiller71a86042016-01-15 14:59:58 -0800963 'EXTRA_DEFINES=GRPC_TEST_SLOWDOWN_MACHINE_FACTOR=%f' % args.slowdown,
964 'CONFIG=%s' % cfg] +
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800965 language_make_options +
Craig Tiller71a86042016-01-15 14:59:58 -0800966 ([] if not args.travis else ['JENKINS_BUILD=1']) +
967 targets,
Craig Tiller590105a2016-01-19 13:03:46 -0800968 timeout_seconds=None)]
murgatroid998ae409f2015-10-26 16:39:00 -0700969 else:
970 return []
Jan Tattermuschfba65302016-01-25 18:21:14 -0800971
murgatroid99a3e244f2015-09-22 11:25:53 -0700972make_targets = {}
973for l in languages:
974 makefile = l.makefile_name()
975 make_targets[makefile] = make_targets.get(makefile, set()).union(
Jan Tattermusch77db4322016-02-20 20:19:35 -0800976 set(l.make_targets()))
Craig Tiller5058c692015-04-08 09:42:04 -0700977
Jan Tattermusche4a69182015-12-15 09:53:01 -0800978def build_step_environ(cfg):
979 environ = {'CONFIG': cfg}
Jan Tattermuscha2d964c2016-02-22 17:33:09 -0800980 msbuild_cfg = _MSBUILD_CONFIG.get(cfg)
Jan Tattermusche4a69182015-12-15 09:53:01 -0800981 if msbuild_cfg:
982 environ['MSBUILD_CONFIG'] = msbuild_cfg
983 return environ
984
murgatroid99fddac962015-09-22 09:20:11 -0700985build_steps = list(set(
Jan Tattermusch77db4322016-02-20 20:19:35 -0800986 jobset.JobSpec(cmdline, environ=build_step_environ(build_config), flake_retries=5)
murgatroid99256d3df2015-09-21 16:58:02 -0700987 for l in languages
988 for cmdline in l.pre_build_steps()))
Craig Tillerbd4e3782015-09-01 06:48:55 -0700989if make_targets:
Jan Tattermusch77db4322016-02-20 20:19:35 -0800990 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 -0700991 build_steps.extend(set(make_commands))
Craig Tiller5058c692015-04-08 09:42:04 -0700992build_steps.extend(set(
Jan Tattermusch77db4322016-02-20 20:19:35 -0800993 jobset.JobSpec(cmdline, environ=build_step_environ(build_config), timeout_seconds=None)
Craig Tiller547db2b2015-01-30 14:08:39 -0800994 for l in languages
Craig Tiller533b1a22015-05-29 08:41:29 -0700995 for cmdline in l.build_steps()))
Craig Tillerf1973b02015-01-16 12:32:13 -0800996
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200997post_tests_steps = list(set(
Jan Tattermusch77db4322016-02-20 20:19:35 -0800998 jobset.JobSpec(cmdline, environ=build_step_environ(build_config))
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200999 for l in languages
1000 for cmdline in l.post_tests_steps()))
Nicolas Nobleddef2462015-01-06 18:08:25 -08001001runs_per_test = args.runs_per_test
ctiller3040cb72015-01-07 12:13:17 -08001002forever = args.forever
Nicolas Nobleddef2462015-01-06 18:08:25 -08001003
Nicolas Nobleddef2462015-01-06 18:08:25 -08001004
Craig Tiller71735182015-01-15 17:07:13 -08001005class TestCache(object):
Craig Tillerb50d1662015-01-15 17:28:21 -08001006 """Cache for running tests."""
1007
David Klempner25739582015-02-11 15:57:32 -08001008 def __init__(self, use_cache_results):
Craig Tiller71735182015-01-15 17:07:13 -08001009 self._last_successful_run = {}
David Klempner25739582015-02-11 15:57:32 -08001010 self._use_cache_results = use_cache_results
Craig Tiller69cd2372015-06-11 09:38:09 -07001011 self._last_save = time.time()
Craig Tiller71735182015-01-15 17:07:13 -08001012
1013 def should_run(self, cmdline, bin_hash):
Craig Tiller71735182015-01-15 17:07:13 -08001014 if cmdline not in self._last_successful_run:
1015 return True
1016 if self._last_successful_run[cmdline] != bin_hash:
1017 return True
David Klempner25739582015-02-11 15:57:32 -08001018 if not self._use_cache_results:
1019 return True
Craig Tiller71735182015-01-15 17:07:13 -08001020 return False
1021
1022 def finished(self, cmdline, bin_hash):
Craig Tiller547db2b2015-01-30 14:08:39 -08001023 self._last_successful_run[cmdline] = bin_hash
Craig Tiller69cd2372015-06-11 09:38:09 -07001024 if time.time() - self._last_save > 1:
1025 self.save()
Craig Tiller71735182015-01-15 17:07:13 -08001026
1027 def dump(self):
Craig Tillerb50d1662015-01-15 17:28:21 -08001028 return [{'cmdline': k, 'hash': v}
1029 for k, v in self._last_successful_run.iteritems()]
Craig Tiller71735182015-01-15 17:07:13 -08001030
1031 def parse(self, exdump):
1032 self._last_successful_run = dict((o['cmdline'], o['hash']) for o in exdump)
1033
1034 def save(self):
1035 with open('.run_tests_cache', 'w') as f:
Craig Tiller261dd982015-01-16 16:41:45 -08001036 f.write(json.dumps(self.dump()))
Craig Tiller69cd2372015-06-11 09:38:09 -07001037 self._last_save = time.time()
Craig Tiller71735182015-01-15 17:07:13 -08001038
Craig Tiller1cc11db2015-01-15 22:50:50 -08001039 def maybe_load(self):
1040 if os.path.exists('.run_tests_cache'):
1041 with open('.run_tests_cache') as f:
Craig Tiller261dd982015-01-16 16:41:45 -08001042 self.parse(json.loads(f.read()))
Craig Tiller71735182015-01-15 17:07:13 -08001043
1044
Craig Tillerf53d9c82015-08-04 14:19:43 -07001045def _start_port_server(port_server_port):
1046 # check if a compatible port server is running
1047 # if incompatible (version mismatch) ==> start a new one
1048 # if not running ==> start a new one
1049 # otherwise, leave it up
1050 try:
Craig Tillerfe4939f2015-10-06 12:55:36 -07001051 version = int(urllib2.urlopen(
1052 'http://localhost:%d/version_number' % port_server_port,
1053 timeout=1).read())
1054 print 'detected port server running version %d' % version
Craig Tillerf53d9c82015-08-04 14:19:43 -07001055 running = True
Craig Tillerfe4939f2015-10-06 12:55:36 -07001056 except Exception as e:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001057 print 'failed to detect port server: %s' % sys.exc_info()[0]
Craig Tillerfe4939f2015-10-06 12:55:36 -07001058 print e.strerror
Craig Tillerf53d9c82015-08-04 14:19:43 -07001059 running = False
1060 if running:
Craig Tillerfe4939f2015-10-06 12:55:36 -07001061 current_version = int(subprocess.check_output(
Jan Tattermusch3bd08272015-11-04 19:24:37 -08001062 [sys.executable, os.path.abspath('tools/run_tests/port_server.py'),
1063 'dump_version']))
Craig Tillerfe4939f2015-10-06 12:55:36 -07001064 print 'my port server is version %d' % current_version
1065 running = (version >= current_version)
1066 if not running:
1067 print 'port_server version mismatch: killing the old one'
1068 urllib2.urlopen('http://localhost:%d/quitquitquit' % port_server_port).read()
1069 time.sleep(1)
Craig Tillerf53d9c82015-08-04 14:19:43 -07001070 if not running:
Craig Tillerf0a293e2015-10-12 10:05:50 -07001071 fd, logfile = tempfile.mkstemp()
1072 os.close(fd)
1073 print 'starting port_server, with log file %s' % logfile
Jan Tattermusch3bd08272015-11-04 19:24:37 -08001074 args = [sys.executable, os.path.abspath('tools/run_tests/port_server.py'),
1075 '-p', '%d' % port_server_port, '-l', logfile]
Craig Tiller367d41d2015-10-12 13:00:22 -07001076 env = dict(os.environ)
1077 env['BUILD_ID'] = 'pleaseDontKillMeJenkins'
Nicolas "Pixel" Noblef72d7b52015-12-03 03:07:43 +01001078 if platform_string() == 'windows':
Jan Tattermusch3bd08272015-11-04 19:24:37 -08001079 # Working directory of port server needs to be outside of Jenkins
1080 # workspace to prevent file lock issues.
1081 tempdir = tempfile.mkdtemp()
Craig Tillerd2c39712015-10-12 11:08:49 -07001082 port_server = subprocess.Popen(
Craig Tiller367d41d2015-10-12 13:00:22 -07001083 args,
1084 env=env,
Jan Tattermusch3bd08272015-11-04 19:24:37 -08001085 cwd=tempdir,
Craig Tiller367d41d2015-10-12 13:00:22 -07001086 creationflags = 0x00000008, # detached process
1087 close_fds=True)
Craig Tillerd2c39712015-10-12 11:08:49 -07001088 else:
1089 port_server = subprocess.Popen(
1090 args,
Craig Tiller367d41d2015-10-12 13:00:22 -07001091 env=env,
Craig Tillerd2c39712015-10-12 11:08:49 -07001092 preexec_fn=os.setsid,
1093 close_fds=True)
Craig Tillerf0a293e2015-10-12 10:05:50 -07001094 time.sleep(1)
Craig Tiller8b5f4dc2015-08-26 08:02:01 -07001095 # ensure port server is up
Craig Tillerabd37fd2015-08-26 07:54:01 -07001096 waits = 0
Craig Tillerf53d9c82015-08-04 14:19:43 -07001097 while True:
Craig Tillerabd37fd2015-08-26 07:54:01 -07001098 if waits > 10:
Craig Tillerf0a293e2015-10-12 10:05:50 -07001099 print 'killing port server due to excessive start up waits'
Craig Tillerabd37fd2015-08-26 07:54:01 -07001100 port_server.kill()
Craig Tillera2f38b02015-09-24 11:19:17 -07001101 if port_server.poll() is not None:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001102 print 'port_server failed to start'
Craig Tillerf0a293e2015-10-12 10:05:50 -07001103 # try one final time: maybe another build managed to start one
1104 time.sleep(1)
1105 try:
1106 urllib2.urlopen('http://localhost:%d/get' % port_server_port,
1107 timeout=1).read()
1108 print 'last ditch attempt to contact port server succeeded'
1109 break
1110 except:
Jan Tattermusch3b5121b2016-02-22 17:41:05 -08001111 traceback.print_exc()
Craig Tillerf0a293e2015-10-12 10:05:50 -07001112 port_log = open(logfile, 'r').read()
1113 print port_log
1114 sys.exit(1)
Craig Tillerf53d9c82015-08-04 14:19:43 -07001115 try:
Craig Tillerabd37fd2015-08-26 07:54:01 -07001116 urllib2.urlopen('http://localhost:%d/get' % port_server_port,
1117 timeout=1).read()
Craig Tillerf0a293e2015-10-12 10:05:50 -07001118 print 'port server is up and ready'
Craig Tillerf53d9c82015-08-04 14:19:43 -07001119 break
Craig Tiller31fdaa42015-09-25 13:09:59 -07001120 except socket.timeout:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001121 print 'waiting for port_server: timeout'
Craig Tillerf0a293e2015-10-12 10:05:50 -07001122 traceback.print_exc();
1123 time.sleep(1)
Craig Tiller31fdaa42015-09-25 13:09:59 -07001124 waits += 1
Craig Tillerf53d9c82015-08-04 14:19:43 -07001125 except urllib2.URLError:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001126 print 'waiting for port_server: urlerror'
Craig Tillerf0a293e2015-10-12 10:05:50 -07001127 traceback.print_exc();
1128 time.sleep(1)
Craig Tillerabd37fd2015-08-26 07:54:01 -07001129 waits += 1
Craig Tillerf53d9c82015-08-04 14:19:43 -07001130 except:
Jan Tattermusch3b5121b2016-02-22 17:41:05 -08001131 traceback.print_exc()
Craig Tillerf53d9c82015-08-04 14:19:43 -07001132 port_server.kill()
1133 raise
1134
1135
Adele Zhoud5fffa52015-10-23 15:51:42 -07001136def _calculate_num_runs_failures(list_of_results):
1137 """Caculate number of runs and failures for a particular test.
1138
1139 Args:
1140 list_of_results: (List) of JobResult object.
1141 Returns:
1142 A tuple of total number of runs and failures.
1143 """
1144 num_runs = len(list_of_results) # By default, there is 1 run per JobResult.
1145 num_failures = 0
1146 for jobresult in list_of_results:
1147 if jobresult.retries > 0:
1148 num_runs += jobresult.retries
1149 if jobresult.num_failures > 0:
1150 num_failures += jobresult.num_failures
1151 return num_runs, num_failures
1152
Adele Zhou6b9527c2015-11-20 15:56:35 -08001153
Craig Tillereb9de8b2016-01-08 08:57:41 -08001154# _build_and_run results
1155class BuildAndRunError(object):
1156
1157 BUILD = object()
1158 TEST = object()
1159 POST_TEST = object()
1160
1161
1162# returns a list of things that failed (or an empty list on success)
Craig Tillerf53d9c82015-08-04 14:19:43 -07001163def _build_and_run(
Jan Tattermusch2dd156e2015-12-04 18:26:17 -08001164 check_cancelled, newline_on_success, cache, xml_report=None, build_only=False):
ctiller3040cb72015-01-07 12:13:17 -08001165 """Do one pass of building & running tests."""
murgatroid99666450e2015-01-26 13:03:31 -08001166 # build latest sequentially
Jan Tattermuschaab1e512016-01-28 09:30:44 -08001167 num_failures, resultset = jobset.run(
Adele Zhoue4c35612015-10-16 15:34:23 -07001168 build_steps, maxjobs=1, stop_on_failure=True,
Craig Tiller883064c2015-11-04 10:06:10 -08001169 newline_on_success=newline_on_success, travis=args.travis)
Adele Zhoue4c35612015-10-16 15:34:23 -07001170 if num_failures:
Craig Tillereb9de8b2016-01-08 08:57:41 -08001171 return [BuildAndRunError.BUILD]
Craig Tillerb361b4e2016-01-06 11:44:17 -08001172
Jan Tattermusch2dd156e2015-12-04 18:26:17 -08001173 if build_only:
Jan Tattermuschaab1e512016-01-28 09:30:44 -08001174 if xml_report:
1175 report_utils.render_junit_xml_report(resultset, xml_report)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001176 return []
ctiller3040cb72015-01-07 12:13:17 -08001177
Craig Tiller234b6e72015-05-23 10:12:40 -07001178 # start antagonists
David Garcia Quintas79e389f2015-06-02 17:49:42 -07001179 antagonists = [subprocess.Popen(['tools/run_tests/antagonist.py'])
Craig Tiller234b6e72015-05-23 10:12:40 -07001180 for _ in range(0, args.antagonists)]
Craig Tillerfe4939f2015-10-06 12:55:36 -07001181 port_server_port = 32767
Craig Tillerf53d9c82015-08-04 14:19:43 -07001182 _start_port_server(port_server_port)
Adele Zhou7cf72112015-11-04 11:18:43 -08001183 resultset = None
Adele Zhou803af152015-11-30 15:16:16 -08001184 num_test_failures = 0
Craig Tiller234b6e72015-05-23 10:12:40 -07001185 try:
David Garcia Quintase90cd372015-05-31 18:15:26 -07001186 infinite_runs = runs_per_test == 0
yang-g6c1fdc62015-08-18 11:57:42 -07001187 one_run = set(
1188 spec
yang-g6c1fdc62015-08-18 11:57:42 -07001189 for language in languages
Jan Tattermusch77db4322016-02-20 20:19:35 -08001190 for spec in language.test_specs()
Vijay Pai488fd0e2016-06-13 12:37:12 -07001191 if (re.search(args.regex, spec.shortname) and
1192 (args.regex_exclude == '' or
1193 not re.search(args.regex_exclude, spec.shortname))))
David Garcia Quintas79e389f2015-06-02 17:49:42 -07001194 # When running on travis, we want out test runs to be as similar as possible
1195 # for reproducibility purposes.
Craig Tiller883064c2015-11-04 10:06:10 -08001196 if args.travis:
David Garcia Quintas79e389f2015-06-02 17:49:42 -07001197 massaged_one_run = sorted(one_run, key=lambda x: x.shortname)
1198 else:
1199 # whereas otherwise, we want to shuffle things up to give all tests a
1200 # chance to run.
1201 massaged_one_run = list(one_run) # random.shuffle needs an indexable seq.
1202 random.shuffle(massaged_one_run) # which it modifies in-place.
Craig Tillerf7b7c892015-06-22 14:33:25 -07001203 if infinite_runs:
1204 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 -07001205 runs_sequence = (itertools.repeat(massaged_one_run) if infinite_runs
1206 else itertools.repeat(massaged_one_run, runs_per_test))
David Garcia Quintase90cd372015-05-31 18:15:26 -07001207 all_runs = itertools.chain.from_iterable(runs_sequence)
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +02001208
Adele Zhou803af152015-11-30 15:16:16 -08001209 num_test_failures, resultset = jobset.run(
Adele Zhou2271ab52015-10-28 13:59:14 -07001210 all_runs, check_cancelled, newline_on_success=newline_on_success,
Craig Tiller883064c2015-11-04 10:06:10 -08001211 travis=args.travis, infinite_runs=infinite_runs, maxjobs=args.jobs,
murgatroid998ae409f2015-10-26 16:39:00 -07001212 stop_on_failure=args.stop_on_failure,
Adele Zhouf2ca7bc2015-10-23 15:38:00 -07001213 cache=cache if not xml_report else None,
Adele Zhouf2ca7bc2015-10-23 15:38:00 -07001214 add_env={'GRPC_TEST_PORT_SERVER': 'localhost:%d' % port_server_port})
Adele Zhoud5fffa52015-10-23 15:51:42 -07001215 if resultset:
1216 for k, v in resultset.iteritems():
1217 num_runs, num_failures = _calculate_num_runs_failures(v)
1218 if num_failures == num_runs: # what about infinite_runs???
1219 jobset.message('FAILED', k, do_newline=True)
1220 elif num_failures > 0:
1221 jobset.message(
1222 'FLAKE', '%s [%d/%d runs flaked]' % (k, num_failures, num_runs),
1223 do_newline=True)
1224 else:
1225 jobset.message('PASSED', k, do_newline=True)
Craig Tiller234b6e72015-05-23 10:12:40 -07001226 finally:
1227 for antagonist in antagonists:
1228 antagonist.kill()
Adele Zhou7cf72112015-11-04 11:18:43 -08001229 if xml_report and resultset:
Adele Zhou3bc7ba42015-11-05 10:21:58 -08001230 report_utils.render_junit_xml_report(resultset, xml_report)
Craig Tillerd86a3942015-01-14 12:48:54 -08001231
Adele Zhouf2ca7bc2015-10-23 15:38:00 -07001232 number_failures, _ = jobset.run(
1233 post_tests_steps, maxjobs=1, stop_on_failure=True,
Craig Tiller883064c2015-11-04 10:06:10 -08001234 newline_on_success=newline_on_success, travis=args.travis)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001235
1236 out = []
1237 if number_failures:
1238 out.append(BuildAndRunError.POST_TEST)
1239 if num_test_failures:
1240 out.append(BuildAndRunError.TEST)
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +02001241
Craig Tiller69cd2372015-06-11 09:38:09 -07001242 if cache: cache.save()
1243
Craig Tillereb9de8b2016-01-08 08:57:41 -08001244 return out
ctiller3040cb72015-01-07 12:13:17 -08001245
1246
David Klempner25739582015-02-11 15:57:32 -08001247test_cache = TestCache(runs_per_test == 1)
Craig Tiller547db2b2015-01-30 14:08:39 -08001248test_cache.maybe_load()
Craig Tiller71735182015-01-15 17:07:13 -08001249
ctiller3040cb72015-01-07 12:13:17 -08001250if forever:
Nicolas Noble044db742015-01-14 16:57:24 -08001251 success = True
ctiller3040cb72015-01-07 12:13:17 -08001252 while True:
Craig Tiller42bc87c2015-02-23 08:50:19 -08001253 dw = watch_dirs.DirWatcher(['src', 'include', 'test', 'examples'])
ctiller3040cb72015-01-07 12:13:17 -08001254 initial_time = dw.most_recent_change()
1255 have_files_changed = lambda: dw.most_recent_change() != initial_time
Nicolas Noble044db742015-01-14 16:57:24 -08001256 previous_success = success
Craig Tillereb9de8b2016-01-08 08:57:41 -08001257 errors = _build_and_run(check_cancelled=have_files_changed,
1258 newline_on_success=False,
1259 cache=test_cache,
1260 build_only=args.build_only) == 0
1261 if not previous_success and not errors:
Nicolas Nobleb09078f2015-01-14 18:06:05 -08001262 jobset.message('SUCCESS',
1263 'All tests are now passing properly',
1264 do_newline=True)
Nicolas Noble044db742015-01-14 16:57:24 -08001265 jobset.message('IDLE', 'No change detected')
ctiller3040cb72015-01-07 12:13:17 -08001266 while not have_files_changed():
1267 time.sleep(1)
1268else:
Craig Tillereb9de8b2016-01-08 08:57:41 -08001269 errors = _build_and_run(check_cancelled=lambda: False,
Craig Tiller71735182015-01-15 17:07:13 -08001270 newline_on_success=args.newline_on_success,
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +02001271 cache=test_cache,
Jan Tattermusch2dd156e2015-12-04 18:26:17 -08001272 xml_report=args.xml_report,
1273 build_only=args.build_only)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001274 if not errors:
Nicolas Nobleb09078f2015-01-14 18:06:05 -08001275 jobset.message('SUCCESS', 'All tests passed', do_newline=True)
1276 else:
1277 jobset.message('FAILED', 'Some tests failed', do_newline=True)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001278 exit_code = 0
1279 if BuildAndRunError.BUILD in errors:
1280 exit_code |= 1
Craig Tiller4f2be362016-01-08 08:59:20 -08001281 if BuildAndRunError.TEST in errors and not args.travis:
Craig Tillereb9de8b2016-01-08 08:57:41 -08001282 exit_code |= 2
Craig Tiller4f2be362016-01-08 08:59:20 -08001283 if BuildAndRunError.POST_TEST in errors:
1284 exit_code |= 4
Craig Tillereb9de8b2016-01-08 08:57:41 -08001285 sys.exit(exit_code)