blob: 2de21204c3f4ca5f33123991b2605beb10f9aa7a [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 Tiller123f1372016-06-15 15:06:14 -070065_POLLING_STRATEGIES = {
66 'linux': ['poll', 'legacy']
67}
68
69
Craig Tillerd50993d2015-08-05 08:04:36 -070070def platform_string():
Nicolas "Pixel" Noblef72d7b52015-12-03 03:07:43 +010071 return jobset.platform_string()
Craig Tillerd50993d2015-08-05 08:04:36 -070072
73
Craig Tiller738c3342015-01-12 14:28:33 -080074# SimpleConfig: just compile with CONFIG=config, and run the binary to test
Craig Tillera0f85172016-01-20 15:56:06 -080075class Config(object):
Craig Tillerb50d1662015-01-15 17:28:21 -080076
Craig Tillera0f85172016-01-20 15:56:06 -080077 def __init__(self, config, environ=None, timeout_multiplier=1, tool_prefix=[]):
murgatroid99132ce6a2015-03-04 17:29:14 -080078 if environ is None:
79 environ = {}
Craig Tiller738c3342015-01-12 14:28:33 -080080 self.build_config = config
Craig Tillerc7449162015-01-16 14:42:10 -080081 self.allow_hashing = (config != 'gcov')
Craig Tiller547db2b2015-01-30 14:08:39 -080082 self.environ = environ
murgatroid99132ce6a2015-03-04 17:29:14 -080083 self.environ['CONFIG'] = config
Craig Tillera0f85172016-01-20 15:56:06 -080084 self.tool_prefix = tool_prefix
Masood Malekghassemi26ea9e22015-10-09 15:19:17 -070085 self.timeout_multiplier = timeout_multiplier
Craig Tiller738c3342015-01-12 14:28:33 -080086
Masood Malekghassemi26ea9e22015-10-09 15:19:17 -070087 def job_spec(self, cmdline, hash_targets, timeout_seconds=5*60,
Craig Tillerde7edf82016-03-20 09:12:16 -070088 shortname=None, environ={}, cpu_cost=1.0, flaky=False):
Craig Tiller49f61322015-03-03 13:02:11 -080089 """Construct a jobset.JobSpec for a test under this config
90
91 Args:
92 cmdline: a list of strings specifying the command line the test
93 would like to run
94 hash_targets: either None (don't do caching of test results), or
95 a list of strings specifying files to include in a
96 binary hash to check if a test has changed
97 -- if used, all artifacts needed to run the test must
98 be listed
99 """
Craig Tiller4fc90032015-05-21 10:39:52 -0700100 actual_environ = self.environ.copy()
101 for k, v in environ.iteritems():
102 actual_environ[k] = v
Craig Tillera0f85172016-01-20 15:56:06 -0800103 return jobset.JobSpec(cmdline=self.tool_prefix + cmdline,
Jan Tattermusch9a7d30c2015-04-23 16:12:55 -0700104 shortname=shortname,
Craig Tiller4fc90032015-05-21 10:39:52 -0700105 environ=actual_environ,
Craig Tiller56c6b6a2016-01-20 08:27:37 -0800106 cpu_cost=cpu_cost,
Craig Tiller94d04a52016-01-20 10:58:23 -0800107 timeout_seconds=(self.timeout_multiplier * timeout_seconds if timeout_seconds else None),
Craig Tiller547db2b2015-01-30 14:08:39 -0800108 hash_targets=hash_targets
Craig Tillerd4509a12015-09-28 09:18:40 -0700109 if self.allow_hashing else None,
Craig Tillerde7edf82016-03-20 09:12:16 -0700110 flake_retries=5 if flaky or args.allow_flakes else 0,
Craig Tiller35505de2015-10-08 13:31:33 -0700111 timeout_retries=3 if args.allow_flakes else 0)
Craig Tiller738c3342015-01-12 14:28:33 -0800112
113
murgatroid99cf08daf2015-09-21 15:33:16 -0700114def get_c_tests(travis, test_lang) :
115 out = []
116 platforms_str = 'ci_platforms' if travis else 'platforms'
117 with open('tools/run_tests/tests.json') as f:
murgatroid9989899b12015-09-22 09:14:48 -0700118 js = json.load(f)
murgatroid99a3e244f2015-09-22 11:25:53 -0700119 return [tgt
120 for tgt in js
121 if tgt['language'] == test_lang and
122 platform_string() in tgt[platforms_str] and
123 not (travis and tgt['flaky'])]
murgatroid99cf08daf2015-09-21 15:33:16 -0700124
murgatroid99fafeeb32015-09-22 09:13:03 -0700125
Jan Tattermusch77db4322016-02-20 20:19:35 -0800126def _check_compiler(compiler, supported_compilers):
127 if compiler not in supported_compilers:
Jan Tattermuschb2531e22016-03-25 16:14:41 -0700128 raise Exception('Compiler %s not supported (on this platform).' % compiler)
129
130
131def _check_arch(arch, supported_archs):
132 if arch not in supported_archs:
133 raise Exception('Architecture %s not supported.' % arch)
Jan Tattermusch77db4322016-02-20 20:19:35 -0800134
135
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800136def _is_use_docker_child():
137 """Returns True if running running as a --use_docker child."""
138 return True if os.getenv('RUN_TESTS_COMMAND') else False
139
140
Craig Tillerc7449162015-01-16 14:42:10 -0800141class CLanguage(object):
142
Craig Tillere9c959d2015-01-18 10:23:26 -0800143 def __init__(self, make_target, test_lang):
Craig Tillerc7449162015-01-16 14:42:10 -0800144 self.make_target = make_target
Craig Tillerd50993d2015-08-05 08:04:36 -0700145 self.platform = platform_string()
Craig Tiller711bbe62015-08-19 12:35:16 -0700146 self.test_lang = test_lang
Craig Tillerc7449162015-01-16 14:42:10 -0800147
Jan Tattermusch77db4322016-02-20 20:19:35 -0800148 def configure(self, config, args):
149 self.config = config
150 self.args = args
151 if self.platform == 'windows':
Jan Tattermuschc96caf82016-02-22 17:31:02 -0800152 self._make_options = [_windows_toolset_option(self.args.compiler),
153 _windows_arch_option(self.args.arch)]
Jan Tattermusch77db4322016-02-20 20:19:35 -0800154 else:
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800155 self._docker_distro, self._make_options = self._compiler_options(self.args.use_docker,
156 self.args.compiler)
Jan Tattermusch77db4322016-02-20 20:19:35 -0800157
158 def test_specs(self):
Craig Tiller547db2b2015-01-30 14:08:39 -0800159 out = []
Jan Tattermusch77db4322016-02-20 20:19:35 -0800160 binaries = get_c_tests(self.args.travis, self.test_lang)
Craig Tiller946ce7a2016-04-06 10:35:58 -0700161 for target in binaries:
Craig Tiller123f1372016-06-15 15:06:14 -0700162 polling_strategies = (_POLLING_STRATEGIES.get(self.platform, ['all'])
Craig Tiller946ce7a2016-04-06 10:35:58 -0700163 if target.get('uses_polling', True)
164 else ['all'])
165 for polling_strategy in polling_strategies:
166 env={'GRPC_DEFAULT_SSL_ROOTS_FILE_PATH':
167 _ROOT + '/src/core/lib/tsi/test_creds/ca.pem',
Craig Tillered735102016-04-06 12:59:23 -0700168 'GRPC_POLL_STRATEGY': polling_strategy}
Craig Tiller946ce7a2016-04-06 10:35:58 -0700169 shortname_ext = '' if polling_strategy=='all' else ' polling=%s' % polling_strategy
Craig Tillerb38197e2016-02-26 10:14:54 -0800170 if self.config.build_config in target['exclude_configs']:
171 continue
172 if self.platform == 'windows':
173 binary = 'vsprojects/%s%s/%s.exe' % (
174 'x64/' if self.args.arch == 'x64' else '',
175 _MSBUILD_CONFIG[self.config.build_config],
176 target['name'])
Craig Tillerca62ff02016-02-24 22:22:57 -0800177 else:
Craig Tillerb38197e2016-02-26 10:14:54 -0800178 binary = 'bins/%s/%s' % (self.config.build_config, target['name'])
179 if os.path.isfile(binary):
180 if 'gtest' in target and target['gtest']:
181 # here we parse the output of --gtest_list_tests to build up a
182 # complete list of the tests contained in a binary
183 # for each test, we then add a job to run, filtering for just that
184 # test
185 with open(os.devnull, 'w') as fnull:
186 tests = subprocess.check_output([binary, '--gtest_list_tests'],
187 stderr=fnull)
188 base = None
189 for line in tests.split('\n'):
190 i = line.find('#')
191 if i >= 0: line = line[:i]
192 if not line: continue
193 if line[0] != ' ':
194 base = line.strip()
195 else:
196 assert base is not None
197 assert line[1] == ' '
198 test = base + line.strip()
199 cmdline = [binary] + ['--gtest_filter=%s' % test]
200 out.append(self.config.job_spec(cmdline, [binary],
Craig Tiller334db352016-02-26 15:19:49 -0800201 shortname='%s:%s %s' % (binary, test, shortname_ext),
Craig Tillerb38197e2016-02-26 10:14:54 -0800202 cpu_cost=target['cpu_cost'],
203 environ=env))
204 else:
205 cmdline = [binary] + target['args']
206 out.append(self.config.job_spec(cmdline, [binary],
207 shortname=' '.join(cmdline) + shortname_ext,
208 cpu_cost=target['cpu_cost'],
Craig Tillerc2278152016-03-21 08:59:54 -0700209 flaky=target.get('flaky', False),
Craig Tillerb38197e2016-02-26 10:14:54 -0800210 environ=env))
211 elif self.args.regex == '.*' or self.platform == 'windows':
212 print '\nWARNING: binary not found, skipping', binary
Nicolas Noblee1445362015-05-11 17:40:26 -0700213 return sorted(out)
Craig Tillerc7449162015-01-16 14:42:10 -0800214
Jan Tattermusch77db4322016-02-20 20:19:35 -0800215 def make_targets(self):
216 test_regex = self.args.regex
217 if self.platform != 'windows' and self.args.regex != '.*':
Craig Tiller883064c2015-11-04 10:06:10 -0800218 # use the regex to minimize the number of things to build
Craig Tillerb0f275e2016-01-27 10:45:50 -0800219 return [os.path.basename(target['name'])
Craig Tiller883064c2015-11-04 10:06:10 -0800220 for target in get_c_tests(False, self.test_lang)
Craig Tillerb0f275e2016-01-27 10:45:50 -0800221 if re.search(test_regex, '/' + target['name'])]
Jan Tattermusch77db4322016-02-20 20:19:35 -0800222 if self.platform == 'windows':
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700223 # don't build tools on windows just yet
224 return ['buildtests_%s' % self.make_target]
Craig Tiller7552f0f2015-06-19 17:46:20 -0700225 return ['buildtests_%s' % self.make_target, 'tools_%s' % self.make_target]
Craig Tillerc7449162015-01-16 14:42:10 -0800226
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800227 def make_options(self):
Jan Tattermuschc96caf82016-02-22 17:31:02 -0800228 return self._make_options;
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800229
murgatroid99256d3df2015-09-21 16:58:02 -0700230 def pre_build_steps(self):
Jan Tattermusch874aec02015-10-07 19:26:19 -0700231 if self.platform == 'windows':
232 return [['tools\\run_tests\\pre_build_c.bat']]
233 else:
234 return []
murgatroid99256d3df2015-09-21 16:58:02 -0700235
Craig Tillerc7449162015-01-16 14:42:10 -0800236 def build_steps(self):
237 return []
238
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200239 def post_tests_steps(self):
240 if self.platform == 'windows':
241 return []
242 else:
243 return [['tools/run_tests/post_tests_c.sh']]
244
murgatroid99a3e244f2015-09-22 11:25:53 -0700245 def makefile_name(self):
246 return 'Makefile'
247
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800248 def _clang_make_options(self):
249 return ['CC=clang', 'CXX=clang++', 'LD=clang', 'LDXX=clang++']
250
Jan Tattermusch9bb70622016-03-18 10:28:54 -0700251 def _gcc44_make_options(self):
252 return ['CC=gcc-4.4', 'CXX=g++-4.4', 'LD=gcc-4.4', 'LDXX=g++-4.4']
253
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800254 def _compiler_options(self, use_docker, compiler):
255 """Returns docker distro and make options to use for given compiler."""
Jan Tattermuschfd3857b2016-06-03 12:24:03 -0700256 if not use_docker and not _is_use_docker_child():
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800257 _check_compiler(compiler, ['default'])
258
259 if compiler == 'gcc4.9' or compiler == 'default':
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800260 return ('jessie', [])
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800261 elif compiler == 'gcc4.4':
Jan Tattermusch9bb70622016-03-18 10:28:54 -0700262 return ('wheezy', self._gcc44_make_options())
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800263 elif compiler == 'gcc5.3':
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800264 return ('ubuntu1604', [])
265 elif compiler == 'clang3.4':
266 return ('ubuntu1404', self._clang_make_options())
267 elif compiler == 'clang3.6':
268 return ('ubuntu1604', self._clang_make_options())
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800269 else:
270 raise Exception('Compiler %s not supported.' % compiler)
271
Jan Tattermusch77db4322016-02-20 20:19:35 -0800272 def dockerfile_dir(self):
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800273 return 'tools/dockerfile/test/cxx_%s_%s' % (self._docker_distro,
274 _docker_arch_suffix(self.args.arch))
Jan Tattermusch788ee232016-01-26 12:19:44 -0800275
murgatroid99132ce6a2015-03-04 17:29:14 -0800276 def __str__(self):
277 return self.make_target
278
Craig Tillercc0535d2015-12-08 15:14:47 -0800279
murgatroid992c8d5162015-01-26 10:41:21 -0800280class NodeLanguage(object):
281
Jan Tattermusche477b842016-02-06 22:19:01 -0800282 def __init__(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800283 self.platform = platform_string()
Jan Tattermusche477b842016-02-06 22:19:01 -0800284
Jan Tattermusch77db4322016-02-20 20:19:35 -0800285 def configure(self, config, args):
286 self.config = config
287 self.args = args
murgatroid999fab4382016-04-29 15:05:00 -0700288 _check_compiler(self.args.compiler, ['default', 'node0.12',
289 'node4', 'node5'])
290 if self.args.compiler == 'default':
291 self.node_version = '4'
292 else:
293 # Take off the word "node"
294 self.node_version = self.args.compiler[4:]
Jan Tattermusch77db4322016-02-20 20:19:35 -0800295
296 def test_specs(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800297 if self.platform == 'windows':
Jan Tattermusch77db4322016-02-20 20:19:35 -0800298 return [self.config.job_spec(['tools\\run_tests\\run_node.bat'], None)]
Michael Lumishaaa876a2016-02-10 15:27:58 -0800299 else:
Jan Tattermusch77db4322016-02-20 20:19:35 -0800300 return [self.config.job_spec(['tools/run_tests/run_node.sh', self.node_version],
301 None,
302 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
murgatroid992c8d5162015-01-26 10:41:21 -0800303
murgatroid99256d3df2015-09-21 16:58:02 -0700304 def pre_build_steps(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800305 if self.platform == 'windows':
306 return [['tools\\run_tests\\pre_build_node.bat']]
307 else:
308 return [['tools/run_tests/pre_build_node.sh', self.node_version]]
murgatroid99256d3df2015-09-21 16:58:02 -0700309
Jan Tattermusch77db4322016-02-20 20:19:35 -0800310 def make_targets(self):
murgatroid99db5b1602015-10-01 13:20:11 -0700311 return []
murgatroid992c8d5162015-01-26 10:41:21 -0800312
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800313 def make_options(self):
314 return []
315
murgatroid992c8d5162015-01-26 10:41:21 -0800316 def build_steps(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800317 if self.platform == 'windows':
318 return [['tools\\run_tests\\build_node.bat']]
319 else:
320 return [['tools/run_tests/build_node.sh', self.node_version]]
Craig Tillerc7449162015-01-16 14:42:10 -0800321
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200322 def post_tests_steps(self):
323 return []
324
murgatroid99a3e244f2015-09-22 11:25:53 -0700325 def makefile_name(self):
326 return 'Makefile'
327
Jan Tattermusch77db4322016-02-20 20:19:35 -0800328 def dockerfile_dir(self):
329 return 'tools/dockerfile/test/node_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800330
murgatroid99132ce6a2015-03-04 17:29:14 -0800331 def __str__(self):
332 return 'node'
333
Craig Tiller99775822015-01-30 13:07:16 -0800334
Craig Tillerc7449162015-01-16 14:42:10 -0800335class PhpLanguage(object):
336
Jan Tattermusch77db4322016-02-20 20:19:35 -0800337 def configure(self, config, args):
338 self.config = config
339 self.args = args
340 _check_compiler(self.args.compiler, ['default'])
341
342 def test_specs(self):
343 return [self.config.job_spec(['src/php/bin/run_tests.sh'], None,
344 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
Craig Tillerc7449162015-01-16 14:42:10 -0800345
murgatroid99256d3df2015-09-21 16:58:02 -0700346 def pre_build_steps(self):
347 return []
348
Jan Tattermusch77db4322016-02-20 20:19:35 -0800349 def make_targets(self):
Craig Tilleraf7cf542015-05-22 10:07:34 -0700350 return ['static_c', 'shared_c']
Craig Tillerc7449162015-01-16 14:42:10 -0800351
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800352 def make_options(self):
353 return []
354
Craig Tillerc7449162015-01-16 14:42:10 -0800355 def build_steps(self):
356 return [['tools/run_tests/build_php.sh']]
357
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200358 def post_tests_steps(self):
Stanley Cheunga6b95482016-01-13 16:10:48 -0800359 return [['tools/run_tests/post_tests_php.sh']]
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200360
murgatroid99a3e244f2015-09-22 11:25:53 -0700361 def makefile_name(self):
362 return 'Makefile'
363
Jan Tattermusch77db4322016-02-20 20:19:35 -0800364 def dockerfile_dir(self):
365 return 'tools/dockerfile/test/php_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800366
murgatroid99132ce6a2015-03-04 17:29:14 -0800367 def __str__(self):
368 return 'php'
369
Craig Tillerc7449162015-01-16 14:42:10 -0800370
Nathaniel Manista840615e2015-01-22 20:31:47 +0000371class PythonLanguage(object):
372
Jan Tattermusch77db4322016-02-20 20:19:35 -0800373 def configure(self, config, args):
374 self.config = config
375 self.args = args
Jan Tattermusch825471c2016-04-25 16:52:25 -0700376 self._tox_env = self._get_tox_env(self.args.compiler)
Jan Tattermusch77db4322016-02-20 20:19:35 -0800377
378 def test_specs(self):
Jan Tattermusch072ebaa2016-03-01 18:33:12 -0800379 # load list of known test suites
380 with open('src/python/grpcio/tests/tests.json') as tests_json_file:
381 tests_json = json.load(tests_json_file)
Masood Malekghassemi2b841622015-07-28 17:39:02 -0700382 environment = dict(_FORCE_ENVIRON_FOR_WRAPPERS)
Ken Paysonc47e43d2016-05-04 18:46:16 -0700383 environment['PYTHONPATH'] = '{}:{}'.format(
Craig Tiller123f1372016-06-15 15:06:14 -0700384 os.path.abspath('src/python/gens'),
Ken Paysonc47e43d2016-05-04 18:46:16 -0700385 os.path.abspath('src/python/grpcio_health_checking'))
Jan Tattermusch072ebaa2016-03-01 18:33:12 -0800386 if self.config.build_config != 'gcov':
387 return [self.config.job_spec(
Jan Tattermusch825471c2016-04-25 16:52:25 -0700388 ['tools/run_tests/run_python.sh', self._tox_env],
Jan Tattermusch072ebaa2016-03-01 18:33:12 -0800389 None,
390 environ=dict(environment.items() +
Masood Malekghassemif7ff8be2016-03-09 15:27:28 -0800391 [('GRPC_PYTHON_TESTRUNNER_FILTER', suite_name)]),
Jan Tattermusch072ebaa2016-03-01 18:33:12 -0800392 shortname='py.test.%s' % suite_name,
393 timeout_seconds=5*60)
394 for suite_name in tests_json]
395 else:
396 return [self.config.job_spec(['tools/run_tests/run_python.sh'],
397 None,
398 environ=environment,
399 shortname='py.test.coverage',
400 timeout_seconds=15*60)]
401
Nathaniel Manista840615e2015-01-22 20:31:47 +0000402
murgatroid99256d3df2015-09-21 16:58:02 -0700403 def pre_build_steps(self):
404 return []
405
Jan Tattermusch77db4322016-02-20 20:19:35 -0800406 def make_targets(self):
Craig Tilleraf7cf542015-05-22 10:07:34 -0700407 return ['static_c', 'grpc_python_plugin', 'shared_c']
Nathaniel Manista840615e2015-01-22 20:31:47 +0000408
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800409 def make_options(self):
410 return []
411
Nathaniel Manista840615e2015-01-22 20:31:47 +0000412 def build_steps(self):
Jan Tattermusch825471c2016-04-25 16:52:25 -0700413 return [['tools/run_tests/build_python.sh', self._tox_env]]
Nathaniel Manista840615e2015-01-22 20:31:47 +0000414
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200415 def post_tests_steps(self):
416 return []
417
murgatroid99a3e244f2015-09-22 11:25:53 -0700418 def makefile_name(self):
419 return 'Makefile'
420
Jan Tattermusch77db4322016-02-20 20:19:35 -0800421 def dockerfile_dir(self):
422 return 'tools/dockerfile/test/python_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800423
Jan Tattermusch825471c2016-04-25 16:52:25 -0700424 def _get_tox_env(self, compiler):
425 """Returns name of tox environment based on selected compiler."""
426 if compiler == 'python2.7' or compiler == 'default':
427 return 'py27'
428 elif compiler == 'python3.4':
429 return 'py34'
430 else:
431 raise Exception('Compiler %s not supported.' % compiler)
432
murgatroid99132ce6a2015-03-04 17:29:14 -0800433 def __str__(self):
434 return 'python'
435
Craig Tillerd625d812015-04-08 15:52:35 -0700436
murgatroid996a4c4fa2015-02-27 12:08:57 -0800437class RubyLanguage(object):
438
Jan Tattermusch77db4322016-02-20 20:19:35 -0800439 def configure(self, config, args):
440 self.config = config
441 self.args = args
442 _check_compiler(self.args.compiler, ['default'])
443
444 def test_specs(self):
445 return [self.config.job_spec(['tools/run_tests/run_ruby.sh'], None,
446 timeout_seconds=10*60,
447 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
murgatroid996a4c4fa2015-02-27 12:08:57 -0800448
murgatroid99256d3df2015-09-21 16:58:02 -0700449 def pre_build_steps(self):
Nicolas "Pixel" Noblebcf988f2015-10-08 03:00:42 +0200450 return [['tools/run_tests/pre_build_ruby.sh']]
murgatroid99256d3df2015-09-21 16:58:02 -0700451
Jan Tattermusch4651bef2016-02-23 08:31:25 -0800452 def make_targets(self):
murgatroid997d243df2016-02-18 09:58:05 -0800453 return []
murgatroid996a4c4fa2015-02-27 12:08:57 -0800454
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800455 def make_options(self):
456 return []
457
murgatroid996a4c4fa2015-02-27 12:08:57 -0800458 def build_steps(self):
459 return [['tools/run_tests/build_ruby.sh']]
460
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200461 def post_tests_steps(self):
Nicolas "Pixel" Noble7ef1e532015-12-02 00:55:33 +0100462 return [['tools/run_tests/post_tests_ruby.sh']]
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200463
murgatroid99a3e244f2015-09-22 11:25:53 -0700464 def makefile_name(self):
465 return 'Makefile'
466
Jan Tattermusch77db4322016-02-20 20:19:35 -0800467 def dockerfile_dir(self):
468 return 'tools/dockerfile/test/ruby_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800469
murgatroid99132ce6a2015-03-04 17:29:14 -0800470 def __str__(self):
471 return 'ruby'
472
Craig Tillerd625d812015-04-08 15:52:35 -0700473
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800474class CSharpLanguage(object):
Jan Tattermusch77db4322016-02-20 20:19:35 -0800475
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700476 def __init__(self):
Craig Tillerd50993d2015-08-05 08:04:36 -0700477 self.platform = platform_string()
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700478
Jan Tattermusch77db4322016-02-20 20:19:35 -0800479 def configure(self, config, args):
480 self.config = config
481 self.args = args
Jan Tattermusch6d28d352016-03-25 15:07:22 -0700482 if self.platform == 'windows':
Jan Tattermuschb2531e22016-03-25 16:14:41 -0700483 # Explicitly choosing between x86 and x64 arch doesn't work yet
484 _check_arch(self.args.arch, ['default'])
Jan Tattermusch6d28d352016-03-25 15:07:22 -0700485 self._make_options = [_windows_toolset_option(self.args.compiler),
486 _windows_arch_option(self.args.arch)]
487 else:
488 _check_compiler(self.args.compiler, ['default'])
489 if self.platform == 'mac':
490 # On Mac, official distribution of mono is 32bit.
Jan Tattermusch2a322c22016-03-30 13:55:07 -0700491 # TODO(jtattermusch): EMBED_ZLIB=true currently breaks the mac build
492 self._make_options = ['EMBED_OPENSSL=true',
Jan Tattermuschd9ff4562016-03-30 13:40:48 -0700493 'CFLAGS=-m32', 'LDFLAGS=-m32']
Jan Tattermusch6d28d352016-03-25 15:07:22 -0700494 else:
495 self._make_options = ['EMBED_OPENSSL=true', 'EMBED_ZLIB=true']
Jan Tattermusch77db4322016-02-20 20:19:35 -0800496
497 def test_specs(self):
Jan Tattermusch03c01062015-12-11 14:28:56 -0800498 with open('src/csharp/tests.json') as f:
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700499 tests_by_assembly = json.load(f)
Jan Tattermusch03c01062015-12-11 14:28:56 -0800500
Jan Tattermuscha2d964c2016-02-22 17:33:09 -0800501 msbuild_config = _MSBUILD_CONFIG[self.config.build_config]
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700502 nunit_args = ['--labels=All',
Jan Tattermuschf6824c22016-04-08 17:18:44 -0700503 '--noresult',
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700504 '--workers=1']
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700505 if self.platform == 'windows':
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700506 runtime_cmd = []
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700507 else:
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700508 runtime_cmd = ['mono']
Jan Tattermuschbf3b1532015-10-26 10:24:42 -0700509
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700510 specs = []
511 for assembly in tests_by_assembly.iterkeys():
512 assembly_file = 'src/csharp/%s/bin/%s/%s.exe' % (assembly, msbuild_config, assembly)
Jan Tattermuscha5f1f122016-04-11 15:49:56 -0700513 if self.config.build_config != 'gcov' or self.platform != 'windows':
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700514 # normally, run each test as a separate process
515 for test in tests_by_assembly[assembly]:
516 cmdline = runtime_cmd + [assembly_file, '--test=%s' % test] + nunit_args
517 specs.append(self.config.job_spec(cmdline,
518 None,
519 shortname='csharp.%s' % test,
520 environ=_FORCE_ENVIRON_FOR_WRAPPERS))
521 else:
Jan Tattermuscha5f1f122016-04-11 15:49:56 -0700522 # For C# test coverage, run all tests from the same assembly at once
523 # using OpenCover.Console (only works on Windows).
524 cmdline = ['src\\csharp\\packages\\OpenCover.4.6.519\\tools\\OpenCover.Console.exe',
525 '-target:%s' % assembly_file,
526 '-targetdir:src\\csharp',
527 '-targetargs:%s' % ' '.join(nunit_args),
528 '-filter:+[Grpc.Core]*',
529 '-register:user',
530 '-output:src\\csharp\\coverage_csharp_%s.xml' % assembly]
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700531
Jan Tattermuscha5f1f122016-04-11 15:49:56 -0700532 # set really high cpu_cost to make sure instances of OpenCover.Console run exclusively
533 # to prevent problems with registering the profiler.
534 run_exclusive = 1000000
Jan Tattermusch35e608f2016-04-09 16:35:06 -0700535 specs.append(self.config.job_spec(cmdline,
536 None,
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700537 shortname='csharp.coverage.%s' % assembly,
Jan Tattermuscha5f1f122016-04-11 15:49:56 -0700538 cpu_cost=run_exclusive,
Jan Tattermusch77db4322016-02-20 20:19:35 -0800539 environ=_FORCE_ENVIRON_FOR_WRAPPERS))
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700540 return specs
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800541
murgatroid99256d3df2015-09-21 16:58:02 -0700542 def pre_build_steps(self):
Jan Tattermusch48423fc2015-10-07 18:59:16 -0700543 if self.platform == 'windows':
Jan Tattermusch874aec02015-10-07 19:26:19 -0700544 return [['tools\\run_tests\\pre_build_csharp.bat']]
Jan Tattermusch48423fc2015-10-07 18:59:16 -0700545 else:
546 return [['tools/run_tests/pre_build_csharp.sh']]
murgatroid99256d3df2015-09-21 16:58:02 -0700547
Jan Tattermusch77db4322016-02-20 20:19:35 -0800548 def make_targets(self):
Jan Tattermusch6d28d352016-03-25 15:07:22 -0700549 return ['grpc_csharp_ext']
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800550
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800551 def make_options(self):
Jan Tattermusch6d28d352016-03-25 15:07:22 -0700552 return self._make_options;
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800553
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800554 def build_steps(self):
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700555 if self.platform == 'windows':
Jan Tattermusch6d28d352016-03-25 15:07:22 -0700556 return [[_windows_build_bat(self.args.compiler),
557 'src/csharp/Grpc.sln',
558 '/p:Configuration=%s' % _MSBUILD_CONFIG[self.config.build_config]]]
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700559 else:
560 return [['tools/run_tests/build_csharp.sh']]
Nathaniel Manista840615e2015-01-22 20:31:47 +0000561
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200562 def post_tests_steps(self):
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700563 if self.platform == 'windows':
564 return [['tools\\run_tests\\post_tests_csharp.bat']]
565 else:
566 return [['tools/run_tests/post_tests_csharp.sh']]
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200567
murgatroid99a3e244f2015-09-22 11:25:53 -0700568 def makefile_name(self):
569 return 'Makefile'
570
Jan Tattermusch77db4322016-02-20 20:19:35 -0800571 def dockerfile_dir(self):
572 return 'tools/dockerfile/test/csharp_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800573
murgatroid99132ce6a2015-03-04 17:29:14 -0800574 def __str__(self):
575 return 'csharp'
576
Craig Tillerd625d812015-04-08 15:52:35 -0700577
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700578class ObjCLanguage(object):
579
Jan Tattermusch77db4322016-02-20 20:19:35 -0800580 def configure(self, config, args):
581 self.config = config
582 self.args = args
583 _check_compiler(self.args.compiler, ['default'])
584
585 def test_specs(self):
586 return [self.config.job_spec(['src/objective-c/tests/run_tests.sh'], None,
587 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700588
murgatroid99256d3df2015-09-21 16:58:02 -0700589 def pre_build_steps(self):
590 return []
591
Jan Tattermusch77db4322016-02-20 20:19:35 -0800592 def make_targets(self):
Jorge Canizalesd0b32e92015-07-30 23:08:43 -0700593 return ['grpc_objective_c_plugin', 'interop_server']
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700594
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800595 def make_options(self):
596 return []
597
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700598 def build_steps(self):
Jorge Canizalesd0b32e92015-07-30 23:08:43 -0700599 return [['src/objective-c/tests/build_tests.sh']]
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700600
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200601 def post_tests_steps(self):
602 return []
603
murgatroid99a3e244f2015-09-22 11:25:53 -0700604 def makefile_name(self):
605 return 'Makefile'
606
Jan Tattermusch77db4322016-02-20 20:19:35 -0800607 def dockerfile_dir(self):
Jan Tattermusch788ee232016-01-26 12:19:44 -0800608 return None
609
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700610 def __str__(self):
611 return 'objc'
612
613
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100614class Sanity(object):
615
Jan Tattermusch77db4322016-02-20 20:19:35 -0800616 def configure(self, config, args):
617 self.config = config
618 self.args = args
619 _check_compiler(self.args.compiler, ['default'])
620
621 def test_specs(self):
Craig Tiller94d04a52016-01-20 10:58:23 -0800622 import yaml
Jan Tattermusch788ee232016-01-26 12:19:44 -0800623 with open('tools/run_tests/sanity/sanity_tests.yaml', 'r') as f:
Jan Tattermusch77db4322016-02-20 20:19:35 -0800624 return [self.config.job_spec(cmd['script'].split(), None,
625 timeout_seconds=None, environ={'TEST': 'true'},
626 cpu_cost=cmd.get('cpu_cost', 1))
Craig Tiller94d04a52016-01-20 10:58:23 -0800627 for cmd in yaml.load(f)]
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100628
murgatroid99256d3df2015-09-21 16:58:02 -0700629 def pre_build_steps(self):
630 return []
631
Jan Tattermusch77db4322016-02-20 20:19:35 -0800632 def make_targets(self):
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100633 return ['run_dep_checks']
634
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800635 def make_options(self):
636 return []
637
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100638 def build_steps(self):
639 return []
640
Nicolas "Pixel" Noble87879b32015-10-12 23:28:53 +0200641 def post_tests_steps(self):
642 return []
643
murgatroid99a3e244f2015-09-22 11:25:53 -0700644 def makefile_name(self):
645 return 'Makefile'
646
Jan Tattermusch77db4322016-02-20 20:19:35 -0800647 def dockerfile_dir(self):
Jan Tattermusche70b3c52016-02-07 20:21:02 -0800648 return 'tools/dockerfile/test/sanity'
Jan Tattermusch788ee232016-01-26 12:19:44 -0800649
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100650 def __str__(self):
651 return 'sanity'
652
Nicolas "Pixel" Noblee55cd7f2015-04-14 17:59:13 +0200653
Craig Tiller738c3342015-01-12 14:28:33 -0800654# different configurations we can run under
Craig Tillera0f85172016-01-20 15:56:06 -0800655with open('tools/run_tests/configs.json') as f:
Craig Tiller1dce9062016-01-20 17:01:56 -0800656 _CONFIGS = dict((cfg['config'], Config(**cfg)) for cfg in ast.literal_eval(f.read()))
Craig Tiller738c3342015-01-12 14:28:33 -0800657
658
Craig Tillerc7449162015-01-16 14:42:10 -0800659_LANGUAGES = {
Craig Tillere9c959d2015-01-18 10:23:26 -0800660 'c++': CLanguage('cxx', 'c++'),
661 'c': CLanguage('c', 'c'),
murgatroid992c8d5162015-01-26 10:41:21 -0800662 'node': NodeLanguage(),
Nathaniel Manista840615e2015-01-22 20:31:47 +0000663 'php': PhpLanguage(),
664 'python': PythonLanguage(),
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800665 'ruby': RubyLanguage(),
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100666 'csharp': CSharpLanguage(),
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700667 'objc' : ObjCLanguage(),
Jan Tattermusch70a57e42016-02-20 18:50:27 -0800668 'sanity': Sanity()
Craig Tillereb272bc2015-01-30 13:13:14 -0800669 }
Nicolas Nobleddef2462015-01-06 18:08:25 -0800670
Jan Tattermusch77db4322016-02-20 20:19:35 -0800671
Jan Tattermuscha2d964c2016-02-22 17:33:09 -0800672_MSBUILD_CONFIG = {
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700673 'dbg': 'Debug',
674 'opt': 'Release',
Jan Tattermusche4a69182015-12-15 09:53:01 -0800675 'gcov': 'Debug',
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700676 }
677
David Garcia Quintase90cd372015-05-31 18:15:26 -0700678
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800679def _windows_arch_option(arch):
680 """Returns msbuild cmdline option for selected architecture."""
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800681 if arch == 'default' or arch == 'x86':
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800682 return '/p:Platform=Win32'
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800683 elif arch == 'x64':
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800684 return '/p:Platform=x64'
685 else:
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800686 print 'Architecture %s not supported.' % arch
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800687 sys.exit(1)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800688
Jan Tattermuschf08018a2016-01-26 08:22:09 -0800689
690def _check_arch_option(arch):
691 """Checks that architecture option is valid."""
692 if platform_string() == 'windows':
693 _windows_arch_option(arch)
694 elif platform_string() == 'linux':
695 # On linux, we need to be running under docker with the right architecture.
Jan Tattermusch07fb0422016-01-26 10:46:56 -0800696 runtime_arch = platform.architecture()[0]
Jan Tattermuschf08018a2016-01-26 08:22:09 -0800697 if arch == 'default':
698 return
699 elif runtime_arch == '64bit' and arch == 'x64':
700 return
701 elif runtime_arch == '32bit' and arch == 'x86':
702 return
703 else:
704 print 'Architecture %s does not match current runtime architecture.' % arch
705 sys.exit(1)
706 else:
707 if args.arch != 'default':
708 print 'Architecture %s not supported on current platform.' % args.arch
709 sys.exit(1)
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800710
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800711
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800712def _windows_build_bat(compiler):
713 """Returns name of build.bat for selected compiler."""
714 if compiler == 'default' or compiler == 'vs2013':
715 return 'vsprojects\\build_vs2013.bat'
716 elif compiler == 'vs2015':
717 return 'vsprojects\\build_vs2015.bat'
718 elif compiler == 'vs2010':
719 return 'vsprojects\\build_vs2010.bat'
720 else:
721 print 'Compiler %s not supported.' % compiler
722 sys.exit(1)
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800723
724
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800725def _windows_toolset_option(compiler):
726 """Returns msbuild PlatformToolset for selected compiler."""
727 if compiler == 'default' or compiler == 'vs2013':
728 return '/p:PlatformToolset=v120'
729 elif compiler == 'vs2015':
730 return '/p:PlatformToolset=v140'
731 elif compiler == 'vs2010':
732 return '/p:PlatformToolset=v100'
733 else:
734 print 'Compiler %s not supported.' % compiler
735 sys.exit(1)
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800736
737
Jan Tattermusche70b3c52016-02-07 20:21:02 -0800738def _docker_arch_suffix(arch):
739 """Returns suffix to dockerfile dir to use."""
740 if arch == 'default' or arch == 'x64':
741 return 'x64'
742 elif arch == 'x86':
743 return 'x86'
744 else:
745 print 'Architecture %s not supported with current settings.' % arch
746 sys.exit(1)
747
748
David Garcia Quintase90cd372015-05-31 18:15:26 -0700749def runs_per_test_type(arg_str):
750 """Auxilary function to parse the "runs_per_test" flag.
751
752 Returns:
753 A positive integer or 0, the latter indicating an infinite number of
754 runs.
755
756 Raises:
757 argparse.ArgumentTypeError: Upon invalid input.
758 """
759 if arg_str == 'inf':
760 return 0
761 try:
762 n = int(arg_str)
763 if n <= 0: raise ValueError
Craig Tiller50e53e22015-06-01 20:18:21 -0700764 return n
David Garcia Quintase90cd372015-05-31 18:15:26 -0700765 except:
Adele Zhoue4c35612015-10-16 15:34:23 -0700766 msg = '\'{}\' is not a positive integer or \'inf\''.format(arg_str)
David Garcia Quintase90cd372015-05-31 18:15:26 -0700767 raise argparse.ArgumentTypeError(msg)
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700768
769# parse command line
770argp = argparse.ArgumentParser(description='Run grpc tests.')
771argp.add_argument('-c', '--config',
Jan Tattermusch77db4322016-02-20 20:19:35 -0800772 choices=sorted(_CONFIGS.keys()),
773 default='opt')
David Garcia Quintase90cd372015-05-31 18:15:26 -0700774argp.add_argument('-n', '--runs_per_test', default=1, type=runs_per_test_type,
775 help='A positive integer or "inf". If "inf", all tests will run in an '
776 'infinite loop. Especially useful in combination with "-f"')
Craig Tillerfe406ec2015-02-24 13:55:12 -0800777argp.add_argument('-r', '--regex', default='.*', type=str)
Craig Tiller5f735a62016-01-20 09:31:15 -0800778argp.add_argument('-j', '--jobs', default=multiprocessing.cpu_count(), type=int)
Craig Tiller8451e872015-02-27 09:25:51 -0800779argp.add_argument('-s', '--slowdown', default=1.0, type=float)
ctiller3040cb72015-01-07 12:13:17 -0800780argp.add_argument('-f', '--forever',
781 default=False,
782 action='store_const',
783 const=True)
Nicolas "Pixel" Noblea7df3f92015-02-26 22:07:04 +0100784argp.add_argument('-t', '--travis',
785 default=False,
786 action='store_const',
787 const=True)
Nicolas Noble044db742015-01-14 16:57:24 -0800788argp.add_argument('--newline_on_success',
789 default=False,
790 action='store_const',
791 const=True)
Craig Tiller686fb262015-01-15 07:39:09 -0800792argp.add_argument('-l', '--language',
Craig Tiller60f15e62015-05-13 09:05:17 -0700793 choices=['all'] + sorted(_LANGUAGES.keys()),
Craig Tiller686fb262015-01-15 07:39:09 -0800794 nargs='+',
Craig Tiller60f15e62015-05-13 09:05:17 -0700795 default=['all'])
Craig Tillercd43da82015-05-29 08:41:29 -0700796argp.add_argument('-S', '--stop_on_failure',
797 default=False,
798 action='store_const',
799 const=True)
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700800argp.add_argument('--use_docker',
801 default=False,
802 action='store_const',
803 const=True,
Adele Zhoue4c35612015-10-16 15:34:23 -0700804 help='Run all the tests under docker. That provides ' +
805 'additional isolation and prevents the need to install ' +
806 'language specific prerequisites. Only available on Linux.')
Craig Tillerd4509a12015-09-28 09:18:40 -0700807argp.add_argument('--allow_flakes',
808 default=False,
809 action='store_const',
810 const=True,
Adele Zhoue4c35612015-10-16 15:34:23 -0700811 help='Allow flaky tests to show as passing (re-runs failed tests up to five times)')
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800812argp.add_argument('--arch',
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800813 choices=['default', 'x86', 'x64'],
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800814 default='default',
815 help='Selects architecture to target. For some platforms "default" is the only supported choice.')
816argp.add_argument('--compiler',
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800817 choices=['default',
818 'gcc4.4', 'gcc4.9', 'gcc5.3',
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800819 'clang3.4', 'clang3.6',
Jan Tattermusch825471c2016-04-25 16:52:25 -0700820 'vs2010', 'vs2013', 'vs2015',
murgatroid999fab4382016-04-29 15:05:00 -0700821 'python2.7', 'python3.4',
822 'node0.12', 'node4', 'node5'],
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800823 default='default',
Jan Tattermusch77db4322016-02-20 20:19:35 -0800824 help='Selects compiler to use. Allowed values depend on the platform and language.')
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800825argp.add_argument('--build_only',
826 default=False,
827 action='store_const',
828 const=True,
829 help='Perform all the build steps but dont run any tests.')
Craig Tiller5f735a62016-01-20 09:31:15 -0800830argp.add_argument('--measure_cpu_costs', default=False, action='store_const', const=True,
831 help='Measure the cpu costs of tests')
Craig Tiller1676f912016-01-05 10:49:44 -0800832argp.add_argument('--update_submodules', default=[], nargs='*',
833 help='Update some submodules before building. If any are updated, also run generate_projects. ' +
834 'Submodules are specified as SUBMODULE_NAME:BRANCH; if BRANCH is omitted, master is assumed.')
Craig Tiller234b6e72015-05-23 10:12:40 -0700835argp.add_argument('-a', '--antagonists', default=0, type=int)
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +0200836argp.add_argument('-x', '--xml_report', default=None, type=str,
837 help='Generates a JUnit-compatible XML report')
Craig Tiller123f1372016-06-15 15:06:14 -0700838argp.add_argument('--force_default_poller', default=False, action='store_const', const=True,
839 help='Dont try to iterate over many polling strategies when they exist')
Nicolas Nobleddef2462015-01-06 18:08:25 -0800840args = argp.parse_args()
841
Craig Tiller123f1372016-06-15 15:06:14 -0700842if args.force_default_poller:
843 _POLLING_STRATEGIES = {}
844
Craig Tiller5f735a62016-01-20 09:31:15 -0800845jobset.measure_cpu_costs = args.measure_cpu_costs
846
Craig Tiller1676f912016-01-05 10:49:44 -0800847# update submodules if necessary
Craig Tillerb361b4e2016-01-06 11:44:17 -0800848need_to_regenerate_projects = False
849for spec in args.update_submodules:
850 spec = spec.split(':', 1)
851 if len(spec) == 1:
852 submodule = spec[0]
853 branch = 'master'
854 elif len(spec) == 2:
855 submodule = spec[0]
856 branch = spec[1]
857 cwd = 'third_party/%s' % submodule
858 def git(cmd, cwd=cwd):
859 print 'in %s: git %s' % (cwd, cmd)
860 subprocess.check_call('git %s' % cmd, cwd=cwd, shell=True)
861 git('fetch')
862 git('checkout %s' % branch)
863 git('pull origin %s' % branch)
864 if os.path.exists('src/%s/gen_build_yaml.py' % submodule):
865 need_to_regenerate_projects = True
866if need_to_regenerate_projects:
867 if jobset.platform_string() == 'linux':
868 subprocess.check_call('tools/buildgen/generate_projects.sh', shell=True)
869 else:
870 print 'WARNING: may need to regenerate projects, but since we are not on'
871 print ' Linux this step is being skipped. Compilation MAY fail.'
Craig Tiller1676f912016-01-05 10:49:44 -0800872
873
Nicolas Nobleddef2462015-01-06 18:08:25 -0800874# grab config
Jan Tattermusch77db4322016-02-20 20:19:35 -0800875run_config = _CONFIGS[args.config]
876build_config = run_config.build_config
Craig Tillerf1973b02015-01-16 12:32:13 -0800877
Craig Tiller06805272015-06-11 14:46:47 -0700878if args.travis:
murgatroid99d3b5b7f2015-10-06 17:02:03 -0700879 _FORCE_ENVIRON_FOR_WRAPPERS = {'GRPC_TRACE': 'api'}
Craig Tiller06805272015-06-11 14:46:47 -0700880
Adele Zhou6b9527c2015-11-20 15:56:35 -0800881if 'all' in args.language:
Craig Tiller1676f912016-01-05 10:49:44 -0800882 lang_list = _LANGUAGES.keys()
Adele Zhou6b9527c2015-11-20 15:56:35 -0800883else:
884 lang_list = args.language
Craig Tiller16900662016-01-07 19:30:54 -0800885# We don't support code coverage on some languages
886if 'gcov' in args.config:
Jan Tattermusch3b5121b2016-02-22 17:41:05 -0800887 for bad in ['objc', 'sanity']:
Craig Tiller16900662016-01-07 19:30:54 -0800888 if bad in lang_list:
889 lang_list.remove(bad)
Adele Zhou6b9527c2015-11-20 15:56:35 -0800890
891languages = set(_LANGUAGES[l] for l in lang_list)
Jan Tattermusch77db4322016-02-20 20:19:35 -0800892for l in languages:
893 l.configure(run_config, args)
murgatroid99132ce6a2015-03-04 17:29:14 -0800894
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800895language_make_options=[]
896if any(language.make_options() for language in languages):
Adele Zhou3b6ab812016-05-18 17:04:20 -0700897 if not 'gcov' in args.config and len(languages) != 1:
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800898 print 'languages with custom make options cannot be built simultaneously with other languages'
899 sys.exit(1)
900 else:
901 language_make_options = next(iter(languages)).make_options()
902
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800903if args.use_docker:
904 if not args.travis:
905 print 'Seen --use_docker flag, will run tests under docker.'
906 print
907 print 'IMPORTANT: The changes you are testing need to be locally committed'
908 print 'because only the committed changes in the current branch will be'
909 print 'copied to the docker environment.'
910 time.sleep(5)
911
Jan Tattermusch3b5121b2016-02-22 17:41:05 -0800912 dockerfile_dirs = set([l.dockerfile_dir() for l in languages])
913 if len(dockerfile_dirs) > 1:
Adele Zhou9506ef22016-03-02 13:53:34 -0800914 if 'gcov' in args.config:
915 dockerfile_dir = 'tools/dockerfile/test/multilang_jessie_x64'
916 print ('Using multilang_jessie_x64 docker image for code coverage for '
917 'all languages.')
918 else:
919 print ('Languages to be tested require running under different docker '
920 'images.')
921 sys.exit(1)
922 else:
923 dockerfile_dir = next(iter(dockerfile_dirs))
Craig Tillerde7edf82016-03-20 09:12:16 -0700924
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800925 child_argv = [ arg for arg in sys.argv if not arg == '--use_docker' ]
Jan Tattermusched342b12016-01-26 14:40:31 -0800926 run_tests_cmd = 'python tools/run_tests/run_tests.py %s' % ' '.join(child_argv[1:])
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800927
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800928 env = os.environ.copy()
929 env['RUN_TESTS_COMMAND'] = run_tests_cmd
Jan Tattermusch3b5121b2016-02-22 17:41:05 -0800930 env['DOCKERFILE_DIR'] = dockerfile_dir
Jan Tattermusch9835d4b2016-04-29 15:05:05 -0700931 env['DOCKER_RUN_SCRIPT'] = 'tools/run_tests/dockerize/docker_run_tests.sh'
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800932 if args.xml_report:
933 env['XML_REPORT'] = args.xml_report
934 if not args.travis:
935 env['TTY_FLAG'] = '-t' # enables Ctrl-C when not on Jenkins.
936
Jan Tattermusch9835d4b2016-04-29 15:05:05 -0700937 subprocess.check_call(['tools/run_tests/dockerize/build_docker_and_run_tests.sh'],
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800938 shell=True,
939 env=env)
940 sys.exit(0)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800941
Jan Tattermuschf08018a2016-01-26 08:22:09 -0800942_check_arch_option(args.arch)
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800943
Jan Tattermuschfba65302016-01-25 18:21:14 -0800944def make_jobspec(cfg, targets, makefile='Makefile'):
945 if platform_string() == 'windows':
Craig Tillerfc3c0c42015-09-01 16:47:54 -0700946 extra_args = []
Craig Tillerb5391e12015-09-03 14:35:18 -0700947 # better do parallel compilation
Jan Tattermusch47eeb2b2015-10-07 14:09:18 -0700948 # empirically /m:2 gives the best performance/price and should prevent
949 # overloading the windows workers.
Adele Zhoue4c35612015-10-16 15:34:23 -0700950 extra_args.extend(['/m:2'])
Craig Tillerb5391e12015-09-03 14:35:18 -0700951 # disable PDB generation: it's broken, and we don't need it during CI
Adele Zhoue4c35612015-10-16 15:34:23 -0700952 extra_args.extend(['/p:Jenkins=true'])
Craig Tiller6fd23842015-09-01 07:36:31 -0700953 return [
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800954 jobset.JobSpec([_windows_build_bat(args.compiler),
murgatroid99cf08daf2015-09-21 15:33:16 -0700955 'vsprojects\\%s.sln' % target,
Jan Tattermuscha2d964c2016-02-22 17:33:09 -0800956 '/p:Configuration=%s' % _MSBUILD_CONFIG[cfg]] +
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800957 extra_args +
958 language_make_options,
Craig Tiller590105a2016-01-19 13:03:46 -0800959 shell=True, timeout_seconds=None)
Craig Tiller6fd23842015-09-01 07:36:31 -0700960 for target in targets]
Jan Tattermuschfba65302016-01-25 18:21:14 -0800961 else:
murgatroid998ae409f2015-10-26 16:39:00 -0700962 if targets:
963 return [jobset.JobSpec([os.getenv('MAKE', 'make'),
964 '-f', makefile,
Craig Tillerdd6f7ed2016-01-21 12:54:42 -0800965 '-j', '%d' % args.jobs,
Craig Tiller71a86042016-01-15 14:59:58 -0800966 'EXTRA_DEFINES=GRPC_TEST_SLOWDOWN_MACHINE_FACTOR=%f' % args.slowdown,
967 'CONFIG=%s' % cfg] +
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800968 language_make_options +
Craig Tiller71a86042016-01-15 14:59:58 -0800969 ([] if not args.travis else ['JENKINS_BUILD=1']) +
970 targets,
Craig Tiller590105a2016-01-19 13:03:46 -0800971 timeout_seconds=None)]
murgatroid998ae409f2015-10-26 16:39:00 -0700972 else:
973 return []
Jan Tattermuschfba65302016-01-25 18:21:14 -0800974
murgatroid99a3e244f2015-09-22 11:25:53 -0700975make_targets = {}
976for l in languages:
977 makefile = l.makefile_name()
978 make_targets[makefile] = make_targets.get(makefile, set()).union(
Jan Tattermusch77db4322016-02-20 20:19:35 -0800979 set(l.make_targets()))
Craig Tiller5058c692015-04-08 09:42:04 -0700980
Jan Tattermusche4a69182015-12-15 09:53:01 -0800981def build_step_environ(cfg):
982 environ = {'CONFIG': cfg}
Jan Tattermuscha2d964c2016-02-22 17:33:09 -0800983 msbuild_cfg = _MSBUILD_CONFIG.get(cfg)
Jan Tattermusche4a69182015-12-15 09:53:01 -0800984 if msbuild_cfg:
985 environ['MSBUILD_CONFIG'] = msbuild_cfg
986 return environ
987
murgatroid99fddac962015-09-22 09:20:11 -0700988build_steps = list(set(
Jan Tattermusch77db4322016-02-20 20:19:35 -0800989 jobset.JobSpec(cmdline, environ=build_step_environ(build_config), flake_retries=5)
murgatroid99256d3df2015-09-21 16:58:02 -0700990 for l in languages
991 for cmdline in l.pre_build_steps()))
Craig Tillerbd4e3782015-09-01 06:48:55 -0700992if make_targets:
Jan Tattermusch77db4322016-02-20 20:19:35 -0800993 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 -0700994 build_steps.extend(set(make_commands))
Craig Tiller5058c692015-04-08 09:42:04 -0700995build_steps.extend(set(
Jan Tattermusch77db4322016-02-20 20:19:35 -0800996 jobset.JobSpec(cmdline, environ=build_step_environ(build_config), timeout_seconds=None)
Craig Tiller547db2b2015-01-30 14:08:39 -0800997 for l in languages
Craig Tiller533b1a22015-05-29 08:41:29 -0700998 for cmdline in l.build_steps()))
Craig Tillerf1973b02015-01-16 12:32:13 -0800999
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +02001000post_tests_steps = list(set(
Jan Tattermusch77db4322016-02-20 20:19:35 -08001001 jobset.JobSpec(cmdline, environ=build_step_environ(build_config))
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +02001002 for l in languages
1003 for cmdline in l.post_tests_steps()))
Nicolas Nobleddef2462015-01-06 18:08:25 -08001004runs_per_test = args.runs_per_test
ctiller3040cb72015-01-07 12:13:17 -08001005forever = args.forever
Nicolas Nobleddef2462015-01-06 18:08:25 -08001006
Nicolas Nobleddef2462015-01-06 18:08:25 -08001007
Craig Tiller71735182015-01-15 17:07:13 -08001008class TestCache(object):
Craig Tillerb50d1662015-01-15 17:28:21 -08001009 """Cache for running tests."""
1010
David Klempner25739582015-02-11 15:57:32 -08001011 def __init__(self, use_cache_results):
Craig Tiller71735182015-01-15 17:07:13 -08001012 self._last_successful_run = {}
David Klempner25739582015-02-11 15:57:32 -08001013 self._use_cache_results = use_cache_results
Craig Tiller69cd2372015-06-11 09:38:09 -07001014 self._last_save = time.time()
Craig Tiller71735182015-01-15 17:07:13 -08001015
1016 def should_run(self, cmdline, bin_hash):
Craig Tiller71735182015-01-15 17:07:13 -08001017 if cmdline not in self._last_successful_run:
1018 return True
1019 if self._last_successful_run[cmdline] != bin_hash:
1020 return True
David Klempner25739582015-02-11 15:57:32 -08001021 if not self._use_cache_results:
1022 return True
Craig Tiller71735182015-01-15 17:07:13 -08001023 return False
1024
1025 def finished(self, cmdline, bin_hash):
Craig Tiller547db2b2015-01-30 14:08:39 -08001026 self._last_successful_run[cmdline] = bin_hash
Craig Tiller69cd2372015-06-11 09:38:09 -07001027 if time.time() - self._last_save > 1:
1028 self.save()
Craig Tiller71735182015-01-15 17:07:13 -08001029
1030 def dump(self):
Craig Tillerb50d1662015-01-15 17:28:21 -08001031 return [{'cmdline': k, 'hash': v}
1032 for k, v in self._last_successful_run.iteritems()]
Craig Tiller71735182015-01-15 17:07:13 -08001033
1034 def parse(self, exdump):
1035 self._last_successful_run = dict((o['cmdline'], o['hash']) for o in exdump)
1036
1037 def save(self):
1038 with open('.run_tests_cache', 'w') as f:
Craig Tiller261dd982015-01-16 16:41:45 -08001039 f.write(json.dumps(self.dump()))
Craig Tiller69cd2372015-06-11 09:38:09 -07001040 self._last_save = time.time()
Craig Tiller71735182015-01-15 17:07:13 -08001041
Craig Tiller1cc11db2015-01-15 22:50:50 -08001042 def maybe_load(self):
1043 if os.path.exists('.run_tests_cache'):
1044 with open('.run_tests_cache') as f:
Craig Tiller261dd982015-01-16 16:41:45 -08001045 self.parse(json.loads(f.read()))
Craig Tiller71735182015-01-15 17:07:13 -08001046
1047
Craig Tillerf53d9c82015-08-04 14:19:43 -07001048def _start_port_server(port_server_port):
1049 # check if a compatible port server is running
1050 # if incompatible (version mismatch) ==> start a new one
1051 # if not running ==> start a new one
1052 # otherwise, leave it up
1053 try:
Craig Tillerfe4939f2015-10-06 12:55:36 -07001054 version = int(urllib2.urlopen(
1055 'http://localhost:%d/version_number' % port_server_port,
1056 timeout=1).read())
1057 print 'detected port server running version %d' % version
Craig Tillerf53d9c82015-08-04 14:19:43 -07001058 running = True
Craig Tillerfe4939f2015-10-06 12:55:36 -07001059 except Exception as e:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001060 print 'failed to detect port server: %s' % sys.exc_info()[0]
Craig Tillerfe4939f2015-10-06 12:55:36 -07001061 print e.strerror
Craig Tillerf53d9c82015-08-04 14:19:43 -07001062 running = False
1063 if running:
Craig Tillerfe4939f2015-10-06 12:55:36 -07001064 current_version = int(subprocess.check_output(
Jan Tattermusch3bd08272015-11-04 19:24:37 -08001065 [sys.executable, os.path.abspath('tools/run_tests/port_server.py'),
1066 'dump_version']))
Craig Tillerfe4939f2015-10-06 12:55:36 -07001067 print 'my port server is version %d' % current_version
1068 running = (version >= current_version)
1069 if not running:
1070 print 'port_server version mismatch: killing the old one'
1071 urllib2.urlopen('http://localhost:%d/quitquitquit' % port_server_port).read()
1072 time.sleep(1)
Craig Tillerf53d9c82015-08-04 14:19:43 -07001073 if not running:
Craig Tillerf0a293e2015-10-12 10:05:50 -07001074 fd, logfile = tempfile.mkstemp()
1075 os.close(fd)
1076 print 'starting port_server, with log file %s' % logfile
Jan Tattermusch3bd08272015-11-04 19:24:37 -08001077 args = [sys.executable, os.path.abspath('tools/run_tests/port_server.py'),
1078 '-p', '%d' % port_server_port, '-l', logfile]
Craig Tiller367d41d2015-10-12 13:00:22 -07001079 env = dict(os.environ)
1080 env['BUILD_ID'] = 'pleaseDontKillMeJenkins'
Nicolas "Pixel" Noblef72d7b52015-12-03 03:07:43 +01001081 if platform_string() == 'windows':
Jan Tattermusch3bd08272015-11-04 19:24:37 -08001082 # Working directory of port server needs to be outside of Jenkins
1083 # workspace to prevent file lock issues.
1084 tempdir = tempfile.mkdtemp()
Craig Tillerd2c39712015-10-12 11:08:49 -07001085 port_server = subprocess.Popen(
Craig Tiller367d41d2015-10-12 13:00:22 -07001086 args,
1087 env=env,
Jan Tattermusch3bd08272015-11-04 19:24:37 -08001088 cwd=tempdir,
Craig Tiller367d41d2015-10-12 13:00:22 -07001089 creationflags = 0x00000008, # detached process
1090 close_fds=True)
Craig Tillerd2c39712015-10-12 11:08:49 -07001091 else:
1092 port_server = subprocess.Popen(
1093 args,
Craig Tiller367d41d2015-10-12 13:00:22 -07001094 env=env,
Craig Tillerd2c39712015-10-12 11:08:49 -07001095 preexec_fn=os.setsid,
1096 close_fds=True)
Craig Tillerf0a293e2015-10-12 10:05:50 -07001097 time.sleep(1)
Craig Tiller8b5f4dc2015-08-26 08:02:01 -07001098 # ensure port server is up
Craig Tillerabd37fd2015-08-26 07:54:01 -07001099 waits = 0
Craig Tillerf53d9c82015-08-04 14:19:43 -07001100 while True:
Craig Tillerabd37fd2015-08-26 07:54:01 -07001101 if waits > 10:
Craig Tillerf0a293e2015-10-12 10:05:50 -07001102 print 'killing port server due to excessive start up waits'
Craig Tillerabd37fd2015-08-26 07:54:01 -07001103 port_server.kill()
Craig Tillera2f38b02015-09-24 11:19:17 -07001104 if port_server.poll() is not None:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001105 print 'port_server failed to start'
Craig Tillerf0a293e2015-10-12 10:05:50 -07001106 # try one final time: maybe another build managed to start one
1107 time.sleep(1)
1108 try:
1109 urllib2.urlopen('http://localhost:%d/get' % port_server_port,
1110 timeout=1).read()
1111 print 'last ditch attempt to contact port server succeeded'
1112 break
1113 except:
Jan Tattermusch3b5121b2016-02-22 17:41:05 -08001114 traceback.print_exc()
Craig Tillerf0a293e2015-10-12 10:05:50 -07001115 port_log = open(logfile, 'r').read()
1116 print port_log
1117 sys.exit(1)
Craig Tillerf53d9c82015-08-04 14:19:43 -07001118 try:
Craig Tillerabd37fd2015-08-26 07:54:01 -07001119 urllib2.urlopen('http://localhost:%d/get' % port_server_port,
1120 timeout=1).read()
Craig Tillerf0a293e2015-10-12 10:05:50 -07001121 print 'port server is up and ready'
Craig Tillerf53d9c82015-08-04 14:19:43 -07001122 break
Craig Tiller31fdaa42015-09-25 13:09:59 -07001123 except socket.timeout:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001124 print 'waiting for port_server: timeout'
Craig Tillerf0a293e2015-10-12 10:05:50 -07001125 traceback.print_exc();
1126 time.sleep(1)
Craig Tiller31fdaa42015-09-25 13:09:59 -07001127 waits += 1
Craig Tillerf53d9c82015-08-04 14:19:43 -07001128 except urllib2.URLError:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001129 print 'waiting for port_server: urlerror'
Craig Tillerf0a293e2015-10-12 10:05:50 -07001130 traceback.print_exc();
1131 time.sleep(1)
Craig Tillerabd37fd2015-08-26 07:54:01 -07001132 waits += 1
Craig Tillerf53d9c82015-08-04 14:19:43 -07001133 except:
Jan Tattermusch3b5121b2016-02-22 17:41:05 -08001134 traceback.print_exc()
Craig Tillerf53d9c82015-08-04 14:19:43 -07001135 port_server.kill()
1136 raise
1137
1138
Adele Zhoud5fffa52015-10-23 15:51:42 -07001139def _calculate_num_runs_failures(list_of_results):
1140 """Caculate number of runs and failures for a particular test.
1141
1142 Args:
1143 list_of_results: (List) of JobResult object.
1144 Returns:
1145 A tuple of total number of runs and failures.
1146 """
1147 num_runs = len(list_of_results) # By default, there is 1 run per JobResult.
1148 num_failures = 0
1149 for jobresult in list_of_results:
1150 if jobresult.retries > 0:
1151 num_runs += jobresult.retries
1152 if jobresult.num_failures > 0:
1153 num_failures += jobresult.num_failures
1154 return num_runs, num_failures
1155
Adele Zhou6b9527c2015-11-20 15:56:35 -08001156
Craig Tillereb9de8b2016-01-08 08:57:41 -08001157# _build_and_run results
1158class BuildAndRunError(object):
1159
1160 BUILD = object()
1161 TEST = object()
1162 POST_TEST = object()
1163
1164
1165# returns a list of things that failed (or an empty list on success)
Craig Tillerf53d9c82015-08-04 14:19:43 -07001166def _build_and_run(
Jan Tattermusch2dd156e2015-12-04 18:26:17 -08001167 check_cancelled, newline_on_success, cache, xml_report=None, build_only=False):
ctiller3040cb72015-01-07 12:13:17 -08001168 """Do one pass of building & running tests."""
murgatroid99666450e2015-01-26 13:03:31 -08001169 # build latest sequentially
Jan Tattermuschaab1e512016-01-28 09:30:44 -08001170 num_failures, resultset = jobset.run(
Adele Zhoue4c35612015-10-16 15:34:23 -07001171 build_steps, maxjobs=1, stop_on_failure=True,
Craig Tiller883064c2015-11-04 10:06:10 -08001172 newline_on_success=newline_on_success, travis=args.travis)
Adele Zhoue4c35612015-10-16 15:34:23 -07001173 if num_failures:
Craig Tillereb9de8b2016-01-08 08:57:41 -08001174 return [BuildAndRunError.BUILD]
Craig Tillerb361b4e2016-01-06 11:44:17 -08001175
Jan Tattermusch2dd156e2015-12-04 18:26:17 -08001176 if build_only:
Jan Tattermuschaab1e512016-01-28 09:30:44 -08001177 if xml_report:
1178 report_utils.render_junit_xml_report(resultset, xml_report)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001179 return []
ctiller3040cb72015-01-07 12:13:17 -08001180
Craig Tiller234b6e72015-05-23 10:12:40 -07001181 # start antagonists
David Garcia Quintas79e389f2015-06-02 17:49:42 -07001182 antagonists = [subprocess.Popen(['tools/run_tests/antagonist.py'])
Craig Tiller234b6e72015-05-23 10:12:40 -07001183 for _ in range(0, args.antagonists)]
Craig Tillerfe4939f2015-10-06 12:55:36 -07001184 port_server_port = 32767
Craig Tillerf53d9c82015-08-04 14:19:43 -07001185 _start_port_server(port_server_port)
Adele Zhou7cf72112015-11-04 11:18:43 -08001186 resultset = None
Adele Zhou803af152015-11-30 15:16:16 -08001187 num_test_failures = 0
Craig Tiller234b6e72015-05-23 10:12:40 -07001188 try:
David Garcia Quintase90cd372015-05-31 18:15:26 -07001189 infinite_runs = runs_per_test == 0
yang-g6c1fdc62015-08-18 11:57:42 -07001190 one_run = set(
1191 spec
yang-g6c1fdc62015-08-18 11:57:42 -07001192 for language in languages
Jan Tattermusch77db4322016-02-20 20:19:35 -08001193 for spec in language.test_specs()
yang-g6c1fdc62015-08-18 11:57:42 -07001194 if re.search(args.regex, spec.shortname))
David Garcia Quintas79e389f2015-06-02 17:49:42 -07001195 # When running on travis, we want out test runs to be as similar as possible
1196 # for reproducibility purposes.
Craig Tiller883064c2015-11-04 10:06:10 -08001197 if args.travis:
David Garcia Quintas79e389f2015-06-02 17:49:42 -07001198 massaged_one_run = sorted(one_run, key=lambda x: x.shortname)
1199 else:
1200 # whereas otherwise, we want to shuffle things up to give all tests a
1201 # chance to run.
1202 massaged_one_run = list(one_run) # random.shuffle needs an indexable seq.
1203 random.shuffle(massaged_one_run) # which it modifies in-place.
Craig Tillerf7b7c892015-06-22 14:33:25 -07001204 if infinite_runs:
1205 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 -07001206 runs_sequence = (itertools.repeat(massaged_one_run) if infinite_runs
1207 else itertools.repeat(massaged_one_run, runs_per_test))
David Garcia Quintase90cd372015-05-31 18:15:26 -07001208 all_runs = itertools.chain.from_iterable(runs_sequence)
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +02001209
Adele Zhou803af152015-11-30 15:16:16 -08001210 num_test_failures, resultset = jobset.run(
Adele Zhou2271ab52015-10-28 13:59:14 -07001211 all_runs, check_cancelled, newline_on_success=newline_on_success,
Craig Tiller883064c2015-11-04 10:06:10 -08001212 travis=args.travis, infinite_runs=infinite_runs, maxjobs=args.jobs,
murgatroid998ae409f2015-10-26 16:39:00 -07001213 stop_on_failure=args.stop_on_failure,
Adele Zhouf2ca7bc2015-10-23 15:38:00 -07001214 cache=cache if not xml_report else None,
Adele Zhouf2ca7bc2015-10-23 15:38:00 -07001215 add_env={'GRPC_TEST_PORT_SERVER': 'localhost:%d' % port_server_port})
Adele Zhoud5fffa52015-10-23 15:51:42 -07001216 if resultset:
1217 for k, v in resultset.iteritems():
1218 num_runs, num_failures = _calculate_num_runs_failures(v)
1219 if num_failures == num_runs: # what about infinite_runs???
1220 jobset.message('FAILED', k, do_newline=True)
1221 elif num_failures > 0:
1222 jobset.message(
1223 'FLAKE', '%s [%d/%d runs flaked]' % (k, num_failures, num_runs),
1224 do_newline=True)
1225 else:
1226 jobset.message('PASSED', k, do_newline=True)
Craig Tiller234b6e72015-05-23 10:12:40 -07001227 finally:
1228 for antagonist in antagonists:
1229 antagonist.kill()
Adele Zhou7cf72112015-11-04 11:18:43 -08001230 if xml_report and resultset:
Adele Zhou3bc7ba42015-11-05 10:21:58 -08001231 report_utils.render_junit_xml_report(resultset, xml_report)
Craig Tillerd86a3942015-01-14 12:48:54 -08001232
Adele Zhouf2ca7bc2015-10-23 15:38:00 -07001233 number_failures, _ = jobset.run(
1234 post_tests_steps, maxjobs=1, stop_on_failure=True,
Craig Tiller883064c2015-11-04 10:06:10 -08001235 newline_on_success=newline_on_success, travis=args.travis)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001236
1237 out = []
1238 if number_failures:
1239 out.append(BuildAndRunError.POST_TEST)
1240 if num_test_failures:
1241 out.append(BuildAndRunError.TEST)
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +02001242
Craig Tiller69cd2372015-06-11 09:38:09 -07001243 if cache: cache.save()
1244
Craig Tillereb9de8b2016-01-08 08:57:41 -08001245 return out
ctiller3040cb72015-01-07 12:13:17 -08001246
1247
David Klempner25739582015-02-11 15:57:32 -08001248test_cache = TestCache(runs_per_test == 1)
Craig Tiller547db2b2015-01-30 14:08:39 -08001249test_cache.maybe_load()
Craig Tiller71735182015-01-15 17:07:13 -08001250
ctiller3040cb72015-01-07 12:13:17 -08001251if forever:
Nicolas Noble044db742015-01-14 16:57:24 -08001252 success = True
ctiller3040cb72015-01-07 12:13:17 -08001253 while True:
Craig Tiller42bc87c2015-02-23 08:50:19 -08001254 dw = watch_dirs.DirWatcher(['src', 'include', 'test', 'examples'])
ctiller3040cb72015-01-07 12:13:17 -08001255 initial_time = dw.most_recent_change()
1256 have_files_changed = lambda: dw.most_recent_change() != initial_time
Nicolas Noble044db742015-01-14 16:57:24 -08001257 previous_success = success
Craig Tillereb9de8b2016-01-08 08:57:41 -08001258 errors = _build_and_run(check_cancelled=have_files_changed,
1259 newline_on_success=False,
1260 cache=test_cache,
1261 build_only=args.build_only) == 0
1262 if not previous_success and not errors:
Nicolas Nobleb09078f2015-01-14 18:06:05 -08001263 jobset.message('SUCCESS',
1264 'All tests are now passing properly',
1265 do_newline=True)
Nicolas Noble044db742015-01-14 16:57:24 -08001266 jobset.message('IDLE', 'No change detected')
ctiller3040cb72015-01-07 12:13:17 -08001267 while not have_files_changed():
1268 time.sleep(1)
1269else:
Craig Tillereb9de8b2016-01-08 08:57:41 -08001270 errors = _build_and_run(check_cancelled=lambda: False,
Craig Tiller71735182015-01-15 17:07:13 -08001271 newline_on_success=args.newline_on_success,
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +02001272 cache=test_cache,
Jan Tattermusch2dd156e2015-12-04 18:26:17 -08001273 xml_report=args.xml_report,
1274 build_only=args.build_only)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001275 if not errors:
Nicolas Nobleb09078f2015-01-14 18:06:05 -08001276 jobset.message('SUCCESS', 'All tests passed', do_newline=True)
1277 else:
1278 jobset.message('FAILED', 'Some tests failed', do_newline=True)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001279 exit_code = 0
1280 if BuildAndRunError.BUILD in errors:
1281 exit_code |= 1
Craig Tiller4f2be362016-01-08 08:59:20 -08001282 if BuildAndRunError.TEST in errors and not args.travis:
Craig Tillereb9de8b2016-01-08 08:57:41 -08001283 exit_code |= 2
Craig Tiller4f2be362016-01-08 08:59:20 -08001284 if BuildAndRunError.POST_TEST in errors:
1285 exit_code |= 4
Craig Tillereb9de8b2016-01-08 08:57:41 -08001286 sys.exit(exit_code)