blob: f32a621ee460c8a47170b74f5e4dccfb88f173ac [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
36import itertools
Craig Tiller261dd982015-01-16 16:41:45 -080037import json
Nicolas Nobleddef2462015-01-06 18:08:25 -080038import multiprocessing
Craig Tiller1cc11db2015-01-15 22:50:50 -080039import os
David Garcia Quintas79e389f2015-06-02 17:49:42 -070040import platform
41import random
Craig Tillerfe406ec2015-02-24 13:55:12 -080042import re
Craig Tiller82875232015-09-25 13:57:34 -070043import socket
David Garcia Quintas79e389f2015-06-02 17:49:42 -070044import subprocess
Nicolas Nobleddef2462015-01-06 18:08:25 -080045import sys
Craig Tillerf0a293e2015-10-12 10:05:50 -070046import tempfile
47import traceback
ctiller3040cb72015-01-07 12:13:17 -080048import time
Craig Tillerf53d9c82015-08-04 14:19:43 -070049import urllib2
Jan Tattermusch03c01062015-12-11 14:28:56 -080050import uuid
Nicolas Nobleddef2462015-01-06 18:08:25 -080051
52import jobset
Adele Zhoua30f8292015-11-02 13:15:46 -080053import report_utils
ctiller3040cb72015-01-07 12:13:17 -080054import watch_dirs
Nicolas Nobleddef2462015-01-06 18:08:25 -080055
Craig Tillerb361b4e2016-01-06 11:44:17 -080056
Jan Tattermusch3b5121b2016-02-22 17:41:05 -080057_ROOT = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), '../..'))
58os.chdir(_ROOT)
Craig Tiller2cc2b842015-02-27 11:38:31 -080059
60
Craig Tiller06805272015-06-11 14:46:47 -070061_FORCE_ENVIRON_FOR_WRAPPERS = {}
62
63
Craig Tiller123f1372016-06-15 15:06:14 -070064_POLLING_STRATEGIES = {
Sree Kuchibhotlac3a9fae2016-06-21 16:31:08 -070065 'linux': ['epoll', 'poll', 'legacy']
Craig Tiller123f1372016-06-15 15:06:14 -070066}
67
68
Craig Tillerd50993d2015-08-05 08:04:36 -070069def platform_string():
Nicolas "Pixel" Noblef72d7b52015-12-03 03:07:43 +010070 return jobset.platform_string()
Craig Tillerd50993d2015-08-05 08:04:36 -070071
72
Craig Tiller738c3342015-01-12 14:28:33 -080073# SimpleConfig: just compile with CONFIG=config, and run the binary to test
Craig Tillera0f85172016-01-20 15:56:06 -080074class Config(object):
Craig Tillerb50d1662015-01-15 17:28:21 -080075
Craig Tillera0f85172016-01-20 15:56:06 -080076 def __init__(self, config, environ=None, timeout_multiplier=1, tool_prefix=[]):
murgatroid99132ce6a2015-03-04 17:29:14 -080077 if environ is None:
78 environ = {}
Craig Tiller738c3342015-01-12 14:28:33 -080079 self.build_config = config
Craig Tiller547db2b2015-01-30 14:08:39 -080080 self.environ = environ
murgatroid99132ce6a2015-03-04 17:29:14 -080081 self.environ['CONFIG'] = config
Craig Tillera0f85172016-01-20 15:56:06 -080082 self.tool_prefix = tool_prefix
Masood Malekghassemi26ea9e22015-10-09 15:19:17 -070083 self.timeout_multiplier = timeout_multiplier
Craig Tiller738c3342015-01-12 14:28:33 -080084
Craig Tiller74189cd2016-06-23 15:39:06 -070085 def job_spec(self, cmdline, timeout_seconds=5*60,
Craig Tillerde7edf82016-03-20 09:12:16 -070086 shortname=None, environ={}, cpu_cost=1.0, flaky=False):
Craig Tiller49f61322015-03-03 13:02:11 -080087 """Construct a jobset.JobSpec for a test under this config
88
89 Args:
90 cmdline: a list of strings specifying the command line the test
91 would like to run
Craig Tiller49f61322015-03-03 13:02:11 -080092 """
Craig Tiller4fc90032015-05-21 10:39:52 -070093 actual_environ = self.environ.copy()
94 for k, v in environ.iteritems():
95 actual_environ[k] = v
Craig Tillera0f85172016-01-20 15:56:06 -080096 return jobset.JobSpec(cmdline=self.tool_prefix + cmdline,
Jan Tattermusch9a7d30c2015-04-23 16:12:55 -070097 shortname=shortname,
Craig Tiller4fc90032015-05-21 10:39:52 -070098 environ=actual_environ,
Craig Tiller56c6b6a2016-01-20 08:27:37 -080099 cpu_cost=cpu_cost,
Craig Tiller94d04a52016-01-20 10:58:23 -0800100 timeout_seconds=(self.timeout_multiplier * timeout_seconds if timeout_seconds else None),
Craig Tillerde7edf82016-03-20 09:12:16 -0700101 flake_retries=5 if flaky or args.allow_flakes else 0,
Craig Tiller35505de2015-10-08 13:31:33 -0700102 timeout_retries=3 if args.allow_flakes else 0)
Craig Tiller738c3342015-01-12 14:28:33 -0800103
104
murgatroid99cf08daf2015-09-21 15:33:16 -0700105def get_c_tests(travis, test_lang) :
106 out = []
107 platforms_str = 'ci_platforms' if travis else 'platforms'
108 with open('tools/run_tests/tests.json') as f:
murgatroid9989899b12015-09-22 09:14:48 -0700109 js = json.load(f)
murgatroid99a3e244f2015-09-22 11:25:53 -0700110 return [tgt
111 for tgt in js
112 if tgt['language'] == test_lang and
113 platform_string() in tgt[platforms_str] and
114 not (travis and tgt['flaky'])]
murgatroid99cf08daf2015-09-21 15:33:16 -0700115
murgatroid99fafeeb32015-09-22 09:13:03 -0700116
Jan Tattermusch77db4322016-02-20 20:19:35 -0800117def _check_compiler(compiler, supported_compilers):
118 if compiler not in supported_compilers:
Jan Tattermuschb2531e22016-03-25 16:14:41 -0700119 raise Exception('Compiler %s not supported (on this platform).' % compiler)
120
121
122def _check_arch(arch, supported_archs):
123 if arch not in supported_archs:
124 raise Exception('Architecture %s not supported.' % arch)
Jan Tattermusch77db4322016-02-20 20:19:35 -0800125
126
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800127def _is_use_docker_child():
128 """Returns True if running running as a --use_docker child."""
129 return True if os.getenv('RUN_TESTS_COMMAND') else False
130
131
Craig Tillerc7449162015-01-16 14:42:10 -0800132class CLanguage(object):
133
Craig Tillere9c959d2015-01-18 10:23:26 -0800134 def __init__(self, make_target, test_lang):
Craig Tillerc7449162015-01-16 14:42:10 -0800135 self.make_target = make_target
Craig Tillerd50993d2015-08-05 08:04:36 -0700136 self.platform = platform_string()
Craig Tiller711bbe62015-08-19 12:35:16 -0700137 self.test_lang = test_lang
Craig Tillerc7449162015-01-16 14:42:10 -0800138
Jan Tattermusch77db4322016-02-20 20:19:35 -0800139 def configure(self, config, args):
140 self.config = config
141 self.args = args
142 if self.platform == 'windows':
Jan Tattermuschc96caf82016-02-22 17:31:02 -0800143 self._make_options = [_windows_toolset_option(self.args.compiler),
144 _windows_arch_option(self.args.arch)]
Jan Tattermusch77db4322016-02-20 20:19:35 -0800145 else:
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800146 self._docker_distro, self._make_options = self._compiler_options(self.args.use_docker,
147 self.args.compiler)
Jan Tattermusch77db4322016-02-20 20:19:35 -0800148
149 def test_specs(self):
Craig Tiller547db2b2015-01-30 14:08:39 -0800150 out = []
Jan Tattermusch77db4322016-02-20 20:19:35 -0800151 binaries = get_c_tests(self.args.travis, self.test_lang)
Craig Tiller946ce7a2016-04-06 10:35:58 -0700152 for target in binaries:
Craig Tiller123f1372016-06-15 15:06:14 -0700153 polling_strategies = (_POLLING_STRATEGIES.get(self.platform, ['all'])
Craig Tiller946ce7a2016-04-06 10:35:58 -0700154 if target.get('uses_polling', True)
155 else ['all'])
156 for polling_strategy in polling_strategies:
157 env={'GRPC_DEFAULT_SSL_ROOTS_FILE_PATH':
158 _ROOT + '/src/core/lib/tsi/test_creds/ca.pem',
Craig Tillered735102016-04-06 12:59:23 -0700159 'GRPC_POLL_STRATEGY': polling_strategy}
Craig Tiller946ce7a2016-04-06 10:35:58 -0700160 shortname_ext = '' if polling_strategy=='all' else ' polling=%s' % polling_strategy
Craig Tillerb38197e2016-02-26 10:14:54 -0800161 if self.config.build_config in target['exclude_configs']:
162 continue
163 if self.platform == 'windows':
164 binary = 'vsprojects/%s%s/%s.exe' % (
165 'x64/' if self.args.arch == 'x64' else '',
166 _MSBUILD_CONFIG[self.config.build_config],
167 target['name'])
Craig Tillerca62ff02016-02-24 22:22:57 -0800168 else:
Craig Tillerb38197e2016-02-26 10:14:54 -0800169 binary = 'bins/%s/%s' % (self.config.build_config, target['name'])
170 if os.path.isfile(binary):
171 if 'gtest' in target and target['gtest']:
172 # here we parse the output of --gtest_list_tests to build up a
173 # complete list of the tests contained in a binary
174 # for each test, we then add a job to run, filtering for just that
175 # test
176 with open(os.devnull, 'w') as fnull:
177 tests = subprocess.check_output([binary, '--gtest_list_tests'],
178 stderr=fnull)
179 base = None
180 for line in tests.split('\n'):
181 i = line.find('#')
182 if i >= 0: line = line[:i]
183 if not line: continue
184 if line[0] != ' ':
185 base = line.strip()
186 else:
187 assert base is not None
188 assert line[1] == ' '
189 test = base + line.strip()
190 cmdline = [binary] + ['--gtest_filter=%s' % test]
191 out.append(self.config.job_spec(cmdline, [binary],
Craig Tiller334db352016-02-26 15:19:49 -0800192 shortname='%s:%s %s' % (binary, test, shortname_ext),
Craig Tillerb38197e2016-02-26 10:14:54 -0800193 cpu_cost=target['cpu_cost'],
194 environ=env))
195 else:
196 cmdline = [binary] + target['args']
197 out.append(self.config.job_spec(cmdline, [binary],
198 shortname=' '.join(cmdline) + shortname_ext,
199 cpu_cost=target['cpu_cost'],
Craig Tillerc2278152016-03-21 08:59:54 -0700200 flaky=target.get('flaky', False),
Craig Tillerb38197e2016-02-26 10:14:54 -0800201 environ=env))
202 elif self.args.regex == '.*' or self.platform == 'windows':
203 print '\nWARNING: binary not found, skipping', binary
Nicolas Noblee1445362015-05-11 17:40:26 -0700204 return sorted(out)
Craig Tillerc7449162015-01-16 14:42:10 -0800205
Jan Tattermusch77db4322016-02-20 20:19:35 -0800206 def make_targets(self):
207 test_regex = self.args.regex
208 if self.platform != 'windows' and self.args.regex != '.*':
Craig Tiller883064c2015-11-04 10:06:10 -0800209 # use the regex to minimize the number of things to build
Craig Tillerb0f275e2016-01-27 10:45:50 -0800210 return [os.path.basename(target['name'])
Craig Tiller883064c2015-11-04 10:06:10 -0800211 for target in get_c_tests(False, self.test_lang)
Craig Tillerb0f275e2016-01-27 10:45:50 -0800212 if re.search(test_regex, '/' + target['name'])]
Jan Tattermusch77db4322016-02-20 20:19:35 -0800213 if self.platform == 'windows':
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700214 # don't build tools on windows just yet
215 return ['buildtests_%s' % self.make_target]
Craig Tiller7552f0f2015-06-19 17:46:20 -0700216 return ['buildtests_%s' % self.make_target, 'tools_%s' % self.make_target]
Craig Tillerc7449162015-01-16 14:42:10 -0800217
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800218 def make_options(self):
Jan Tattermuschc96caf82016-02-22 17:31:02 -0800219 return self._make_options;
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800220
murgatroid99256d3df2015-09-21 16:58:02 -0700221 def pre_build_steps(self):
Jan Tattermusch874aec02015-10-07 19:26:19 -0700222 if self.platform == 'windows':
223 return [['tools\\run_tests\\pre_build_c.bat']]
224 else:
225 return []
murgatroid99256d3df2015-09-21 16:58:02 -0700226
Craig Tillerc7449162015-01-16 14:42:10 -0800227 def build_steps(self):
228 return []
229
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200230 def post_tests_steps(self):
231 if self.platform == 'windows':
232 return []
233 else:
234 return [['tools/run_tests/post_tests_c.sh']]
235
murgatroid99a3e244f2015-09-22 11:25:53 -0700236 def makefile_name(self):
237 return 'Makefile'
238
Jan Tattermusch6d258c52016-06-10 09:36:51 -0700239 def _clang_make_options(self, version_suffix=''):
240 return ['CC=clang%s' % version_suffix,
241 'CXX=clang++%s' % version_suffix,
242 'LD=clang%s' % version_suffix,
243 'LDXX=clang++%s' % version_suffix]
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800244
Jan Tattermusch6d258c52016-06-10 09:36:51 -0700245 def _gcc_make_options(self, version_suffix):
246 return ['CC=gcc%s' % version_suffix,
247 'CXX=g++%s' % version_suffix,
248 'LD=gcc%s' % version_suffix,
249 'LDXX=g++%s' % version_suffix]
Jan Tattermusch9bb70622016-03-18 10:28:54 -0700250
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800251 def _compiler_options(self, use_docker, compiler):
252 """Returns docker distro and make options to use for given compiler."""
Jan Tattermuschfd3857b2016-06-03 12:24:03 -0700253 if not use_docker and not _is_use_docker_child():
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800254 _check_compiler(compiler, ['default'])
255
256 if compiler == 'gcc4.9' or compiler == 'default':
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800257 return ('jessie', [])
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800258 elif compiler == 'gcc4.4':
Jan Tattermusch6d258c52016-06-10 09:36:51 -0700259 return ('wheezy', self._gcc_make_options(version_suffix='-4.4'))
260 elif compiler == 'gcc4.6':
261 return ('wheezy', self._gcc_make_options(version_suffix='-4.6'))
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800262 elif compiler == 'gcc5.3':
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800263 return ('ubuntu1604', [])
264 elif compiler == 'clang3.4':
Jan Tattermusch6d258c52016-06-10 09:36:51 -0700265 # on ubuntu1404, clang-3.4 alias doesn't exist, just use 'clang'
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800266 return ('ubuntu1404', self._clang_make_options())
Jan Tattermusch6d258c52016-06-10 09:36:51 -0700267 elif compiler == 'clang3.5':
268 return ('jessie', self._clang_make_options(version_suffix='-3.5'))
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800269 elif compiler == 'clang3.6':
Jan Tattermusch6d258c52016-06-10 09:36:51 -0700270 return ('ubuntu1604', self._clang_make_options(version_suffix='-3.6'))
271 elif compiler == 'clang3.7':
272 return ('ubuntu1604', self._clang_make_options(version_suffix='-3.7'))
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800273 else:
274 raise Exception('Compiler %s not supported.' % compiler)
275
Jan Tattermusch77db4322016-02-20 20:19:35 -0800276 def dockerfile_dir(self):
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800277 return 'tools/dockerfile/test/cxx_%s_%s' % (self._docker_distro,
278 _docker_arch_suffix(self.args.arch))
Jan Tattermusch788ee232016-01-26 12:19:44 -0800279
murgatroid99132ce6a2015-03-04 17:29:14 -0800280 def __str__(self):
281 return self.make_target
282
Craig Tillercc0535d2015-12-08 15:14:47 -0800283
murgatroid992c8d5162015-01-26 10:41:21 -0800284class NodeLanguage(object):
285
Jan Tattermusche477b842016-02-06 22:19:01 -0800286 def __init__(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800287 self.platform = platform_string()
Jan Tattermusche477b842016-02-06 22:19:01 -0800288
Jan Tattermusch77db4322016-02-20 20:19:35 -0800289 def configure(self, config, args):
290 self.config = config
291 self.args = args
murgatroid999fab4382016-04-29 15:05:00 -0700292 _check_compiler(self.args.compiler, ['default', 'node0.12',
293 'node4', 'node5'])
294 if self.args.compiler == 'default':
295 self.node_version = '4'
296 else:
297 # Take off the word "node"
298 self.node_version = self.args.compiler[4:]
Jan Tattermusch77db4322016-02-20 20:19:35 -0800299
300 def test_specs(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800301 if self.platform == 'windows':
Jan Tattermusch77db4322016-02-20 20:19:35 -0800302 return [self.config.job_spec(['tools\\run_tests\\run_node.bat'], None)]
Michael Lumishaaa876a2016-02-10 15:27:58 -0800303 else:
Jan Tattermusch77db4322016-02-20 20:19:35 -0800304 return [self.config.job_spec(['tools/run_tests/run_node.sh', self.node_version],
305 None,
306 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
murgatroid992c8d5162015-01-26 10:41:21 -0800307
murgatroid99256d3df2015-09-21 16:58:02 -0700308 def pre_build_steps(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800309 if self.platform == 'windows':
310 return [['tools\\run_tests\\pre_build_node.bat']]
311 else:
312 return [['tools/run_tests/pre_build_node.sh', self.node_version]]
murgatroid99256d3df2015-09-21 16:58:02 -0700313
Jan Tattermusch77db4322016-02-20 20:19:35 -0800314 def make_targets(self):
murgatroid99db5b1602015-10-01 13:20:11 -0700315 return []
murgatroid992c8d5162015-01-26 10:41:21 -0800316
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800317 def make_options(self):
318 return []
319
murgatroid992c8d5162015-01-26 10:41:21 -0800320 def build_steps(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800321 if self.platform == 'windows':
322 return [['tools\\run_tests\\build_node.bat']]
323 else:
324 return [['tools/run_tests/build_node.sh', self.node_version]]
Craig Tillerc7449162015-01-16 14:42:10 -0800325
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200326 def post_tests_steps(self):
327 return []
328
murgatroid99a3e244f2015-09-22 11:25:53 -0700329 def makefile_name(self):
330 return 'Makefile'
331
Jan Tattermusch77db4322016-02-20 20:19:35 -0800332 def dockerfile_dir(self):
333 return 'tools/dockerfile/test/node_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800334
murgatroid99132ce6a2015-03-04 17:29:14 -0800335 def __str__(self):
336 return 'node'
337
Craig Tiller99775822015-01-30 13:07:16 -0800338
Craig Tillerc7449162015-01-16 14:42:10 -0800339class PhpLanguage(object):
340
Jan Tattermusch77db4322016-02-20 20:19:35 -0800341 def configure(self, config, args):
342 self.config = config
343 self.args = args
344 _check_compiler(self.args.compiler, ['default'])
345
346 def test_specs(self):
347 return [self.config.job_spec(['src/php/bin/run_tests.sh'], None,
348 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
Craig Tillerc7449162015-01-16 14:42:10 -0800349
murgatroid99256d3df2015-09-21 16:58:02 -0700350 def pre_build_steps(self):
351 return []
352
Jan Tattermusch77db4322016-02-20 20:19:35 -0800353 def make_targets(self):
Craig Tilleraf7cf542015-05-22 10:07:34 -0700354 return ['static_c', 'shared_c']
Craig Tillerc7449162015-01-16 14:42:10 -0800355
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800356 def make_options(self):
357 return []
358
Craig Tillerc7449162015-01-16 14:42:10 -0800359 def build_steps(self):
360 return [['tools/run_tests/build_php.sh']]
361
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200362 def post_tests_steps(self):
Stanley Cheunga6b95482016-01-13 16:10:48 -0800363 return [['tools/run_tests/post_tests_php.sh']]
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200364
murgatroid99a3e244f2015-09-22 11:25:53 -0700365 def makefile_name(self):
366 return 'Makefile'
367
Jan Tattermusch77db4322016-02-20 20:19:35 -0800368 def dockerfile_dir(self):
369 return 'tools/dockerfile/test/php_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800370
murgatroid99132ce6a2015-03-04 17:29:14 -0800371 def __str__(self):
372 return 'php'
373
Craig Tillerc7449162015-01-16 14:42:10 -0800374
Nathaniel Manista840615e2015-01-22 20:31:47 +0000375class PythonLanguage(object):
376
Jan Tattermusch77db4322016-02-20 20:19:35 -0800377 def configure(self, config, args):
378 self.config = config
379 self.args = args
Ken Payson1efb6012016-06-08 13:06:44 -0700380 self._tox_envs = self._get_tox_envs(self.args.compiler)
Jan Tattermusch77db4322016-02-20 20:19:35 -0800381
382 def test_specs(self):
Jan Tattermusch072ebaa2016-03-01 18:33:12 -0800383 # load list of known test suites
Masood Malekghassemi1ff429d2016-06-02 16:39:20 -0700384 with open('src/python/grpcio_tests/tests/tests.json') as tests_json_file:
Jan Tattermusch072ebaa2016-03-01 18:33:12 -0800385 tests_json = json.load(tests_json_file)
Masood Malekghassemi2b841622015-07-28 17:39:02 -0700386 environment = dict(_FORCE_ENVIRON_FOR_WRAPPERS)
Jan Tattermusch072ebaa2016-03-01 18:33:12 -0800387 if self.config.build_config != 'gcov':
388 return [self.config.job_spec(
Ken Payson1efb6012016-06-08 13:06:44 -0700389 ['tools/run_tests/run_python.sh', tox_env],
Jan Tattermusch072ebaa2016-03-01 18:33:12 -0800390 environ=dict(environment.items() +
Masood Malekghassemif7ff8be2016-03-09 15:27:28 -0800391 [('GRPC_PYTHON_TESTRUNNER_FILTER', suite_name)]),
Ken Payson1efb6012016-06-08 13:06:44 -0700392 shortname='%s.test.%s' % (tox_env, suite_name),
Jan Tattermusch072ebaa2016-03-01 18:33:12 -0800393 timeout_seconds=5*60)
Ken Payson1efb6012016-06-08 13:06:44 -0700394 for suite_name in tests_json
395 for tox_env in self._tox_envs]
Jan Tattermusch072ebaa2016-03-01 18:33:12 -0800396 else:
Ken Payson1efb6012016-06-08 13:06:44 -0700397 return [self.config.job_spec(['tools/run_tests/run_python.sh', tox_env],
Jan Tattermusch072ebaa2016-03-01 18:33:12 -0800398 environ=environment,
Ken Payson1efb6012016-06-08 13:06:44 -0700399 shortname='%s.test.coverage' % tox_env,
400 timeout_seconds=15*60)
401 for tox_env in self._tox_envs]
Jan Tattermusch072ebaa2016-03-01 18:33:12 -0800402
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):
Craig Tiller74189cd2016-06-23 15:39:06 -0700414 return [['tools/run_tests/build_python.sh', tox_env]
Ken Payson1efb6012016-06-08 13:06:44 -0700415 for tox_env in self._tox_envs]
Nathaniel Manista840615e2015-01-22 20:31:47 +0000416
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200417 def post_tests_steps(self):
418 return []
419
murgatroid99a3e244f2015-09-22 11:25:53 -0700420 def makefile_name(self):
421 return 'Makefile'
422
Jan Tattermusch77db4322016-02-20 20:19:35 -0800423 def dockerfile_dir(self):
424 return 'tools/dockerfile/test/python_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800425
Ken Payson1efb6012016-06-08 13:06:44 -0700426 def _get_tox_envs(self, compiler):
Jan Tattermusch825471c2016-04-25 16:52:25 -0700427 """Returns name of tox environment based on selected compiler."""
Ken Payson1efb6012016-06-08 13:06:44 -0700428 if compiler == 'default':
429 return ('py27', 'py34')
430 elif compiler == 'python2.7':
431 return ('py27',)
Jan Tattermusch825471c2016-04-25 16:52:25 -0700432 elif compiler == 'python3.4':
Ken Payson1efb6012016-06-08 13:06:44 -0700433 return ('py34',)
Jan Tattermusch825471c2016-04-25 16:52:25 -0700434 else:
435 raise Exception('Compiler %s not supported.' % compiler)
436
murgatroid99132ce6a2015-03-04 17:29:14 -0800437 def __str__(self):
438 return 'python'
439
Craig Tillerd625d812015-04-08 15:52:35 -0700440
murgatroid996a4c4fa2015-02-27 12:08:57 -0800441class RubyLanguage(object):
442
Jan Tattermusch77db4322016-02-20 20:19:35 -0800443 def configure(self, config, args):
444 self.config = config
445 self.args = args
446 _check_compiler(self.args.compiler, ['default'])
447
448 def test_specs(self):
Craig Tillereb5e4372016-06-23 16:16:10 -0700449 return [self.config.job_spec(['tools/run_tests/run_ruby.sh'],
Jan Tattermusch77db4322016-02-20 20:19:35 -0800450 timeout_seconds=10*60,
451 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
murgatroid996a4c4fa2015-02-27 12:08:57 -0800452
murgatroid99256d3df2015-09-21 16:58:02 -0700453 def pre_build_steps(self):
Nicolas "Pixel" Noblebcf988f2015-10-08 03:00:42 +0200454 return [['tools/run_tests/pre_build_ruby.sh']]
murgatroid99256d3df2015-09-21 16:58:02 -0700455
Jan Tattermusch4651bef2016-02-23 08:31:25 -0800456 def make_targets(self):
murgatroid997d243df2016-02-18 09:58:05 -0800457 return []
murgatroid996a4c4fa2015-02-27 12:08:57 -0800458
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800459 def make_options(self):
460 return []
461
murgatroid996a4c4fa2015-02-27 12:08:57 -0800462 def build_steps(self):
463 return [['tools/run_tests/build_ruby.sh']]
464
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200465 def post_tests_steps(self):
Nicolas "Pixel" Noble7ef1e532015-12-02 00:55:33 +0100466 return [['tools/run_tests/post_tests_ruby.sh']]
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200467
murgatroid99a3e244f2015-09-22 11:25:53 -0700468 def makefile_name(self):
469 return 'Makefile'
470
Jan Tattermusch77db4322016-02-20 20:19:35 -0800471 def dockerfile_dir(self):
472 return 'tools/dockerfile/test/ruby_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800473
murgatroid99132ce6a2015-03-04 17:29:14 -0800474 def __str__(self):
475 return 'ruby'
476
Craig Tillerd625d812015-04-08 15:52:35 -0700477
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800478class CSharpLanguage(object):
Jan Tattermusch77db4322016-02-20 20:19:35 -0800479
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700480 def __init__(self):
Craig Tillerd50993d2015-08-05 08:04:36 -0700481 self.platform = platform_string()
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700482
Jan Tattermusch77db4322016-02-20 20:19:35 -0800483 def configure(self, config, args):
484 self.config = config
485 self.args = args
Jan Tattermusch6d28d352016-03-25 15:07:22 -0700486 if self.platform == 'windows':
Jan Tattermuschb2531e22016-03-25 16:14:41 -0700487 # Explicitly choosing between x86 and x64 arch doesn't work yet
488 _check_arch(self.args.arch, ['default'])
Jan Tattermusch6e2f88c2016-06-21 10:52:40 -0700489 # CoreCLR use 64bit runtime by default.
490 arch_option = 'x64' if self.args.compiler == 'coreclr' else self.args.arch
Jan Tattermusch6d28d352016-03-25 15:07:22 -0700491 self._make_options = [_windows_toolset_option(self.args.compiler),
Jan Tattermusch6e2f88c2016-06-21 10:52:40 -0700492 _windows_arch_option(arch_option)]
Jan Tattermusch6d28d352016-03-25 15:07:22 -0700493 else:
Jan Tattermuschbc98af12016-06-17 18:38:27 -0700494 _check_compiler(self.args.compiler, ['default', 'coreclr'])
495 if self.platform == 'linux' and self.args.compiler == 'coreclr':
496 self._docker_distro = 'coreclr'
Jan Tattermusch743decd2016-06-21 11:40:47 -0700497 else:
498 self._docker_distro = 'jessie'
Jan Tattermusch76511a52016-06-17 14:00:57 -0700499
Jan Tattermusch6d28d352016-03-25 15:07:22 -0700500 if self.platform == 'mac':
Jan Tattermusch2a322c22016-03-30 13:55:07 -0700501 # TODO(jtattermusch): EMBED_ZLIB=true currently breaks the mac build
Jan Tattermusch6d082202016-06-21 10:03:38 -0700502 self._make_options = ['EMBED_OPENSSL=true']
503 if self.args.compiler != 'coreclr':
504 # On Mac, official distribution of mono is 32bit.
505 self._make_options += ['CFLAGS=-m32', 'LDFLAGS=-m32']
Jan Tattermusch6d28d352016-03-25 15:07:22 -0700506 else:
507 self._make_options = ['EMBED_OPENSSL=true', 'EMBED_ZLIB=true']
Jan Tattermusch77db4322016-02-20 20:19:35 -0800508
509 def test_specs(self):
Jan Tattermusch03c01062015-12-11 14:28:56 -0800510 with open('src/csharp/tests.json') as f:
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700511 tests_by_assembly = json.load(f)
Jan Tattermusch03c01062015-12-11 14:28:56 -0800512
Jan Tattermuscha2d964c2016-02-22 17:33:09 -0800513 msbuild_config = _MSBUILD_CONFIG[self.config.build_config]
Jan Tattermuschbc98af12016-06-17 18:38:27 -0700514 nunit_args = ['--labels=All']
Jan Tattermusch76511a52016-06-17 14:00:57 -0700515 assembly_subdir = 'bin/%s' % msbuild_config
516 assembly_extension = '.exe'
517
518 if self.args.compiler == 'coreclr':
Jan Tattermusch64c137c2016-06-20 17:54:19 -0700519 if self.platform == 'linux':
520 assembly_subdir += '/netstandard1.5/debian.8-x64'
521 assembly_extension = ''
Jan Tattermusch14a301d2016-06-27 17:45:29 -0700522 elif self.platform == 'mac':
Jan Tattermusch6d082202016-06-21 10:03:38 -0700523 assembly_subdir += '/netstandard1.5/osx.10.11-x64'
524 assembly_extension = ''
Jan Tattermusch64c137c2016-06-20 17:54:19 -0700525 else:
526 assembly_subdir += '/netstandard1.5/win7-x64'
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700527 runtime_cmd = []
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700528 else:
Jan Tattermuschbc98af12016-06-17 18:38:27 -0700529 nunit_args += ['--noresult', '--workers=1']
530 if self.platform == 'windows':
531 runtime_cmd = []
532 else:
533 runtime_cmd = ['mono']
Jan Tattermuschbf3b1532015-10-26 10:24:42 -0700534
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700535 specs = []
536 for assembly in tests_by_assembly.iterkeys():
Jan Tattermusch76511a52016-06-17 14:00:57 -0700537 assembly_file = 'src/csharp/%s/%s/%s%s' % (assembly,
538 assembly_subdir,
539 assembly,
540 assembly_extension)
Jan Tattermuscha5f1f122016-04-11 15:49:56 -0700541 if self.config.build_config != 'gcov' or self.platform != 'windows':
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700542 # normally, run each test as a separate process
543 for test in tests_by_assembly[assembly]:
544 cmdline = runtime_cmd + [assembly_file, '--test=%s' % test] + nunit_args
545 specs.append(self.config.job_spec(cmdline,
546 None,
547 shortname='csharp.%s' % test,
548 environ=_FORCE_ENVIRON_FOR_WRAPPERS))
549 else:
Jan Tattermuscha5f1f122016-04-11 15:49:56 -0700550 # For C# test coverage, run all tests from the same assembly at once
551 # using OpenCover.Console (only works on Windows).
552 cmdline = ['src\\csharp\\packages\\OpenCover.4.6.519\\tools\\OpenCover.Console.exe',
553 '-target:%s' % assembly_file,
554 '-targetdir:src\\csharp',
555 '-targetargs:%s' % ' '.join(nunit_args),
556 '-filter:+[Grpc.Core]*',
557 '-register:user',
558 '-output:src\\csharp\\coverage_csharp_%s.xml' % assembly]
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700559
Jan Tattermuscha5f1f122016-04-11 15:49:56 -0700560 # set really high cpu_cost to make sure instances of OpenCover.Console run exclusively
561 # to prevent problems with registering the profiler.
562 run_exclusive = 1000000
Jan Tattermusch35e608f2016-04-09 16:35:06 -0700563 specs.append(self.config.job_spec(cmdline,
564 None,
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700565 shortname='csharp.coverage.%s' % assembly,
Jan Tattermuscha5f1f122016-04-11 15:49:56 -0700566 cpu_cost=run_exclusive,
Jan Tattermusch77db4322016-02-20 20:19:35 -0800567 environ=_FORCE_ENVIRON_FOR_WRAPPERS))
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700568 return specs
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800569
murgatroid99256d3df2015-09-21 16:58:02 -0700570 def pre_build_steps(self):
Jan Tattermusch48423fc2015-10-07 18:59:16 -0700571 if self.platform == 'windows':
Jan Tattermusch874aec02015-10-07 19:26:19 -0700572 return [['tools\\run_tests\\pre_build_csharp.bat']]
Jan Tattermusch48423fc2015-10-07 18:59:16 -0700573 else:
574 return [['tools/run_tests/pre_build_csharp.sh']]
murgatroid99256d3df2015-09-21 16:58:02 -0700575
Jan Tattermusch77db4322016-02-20 20:19:35 -0800576 def make_targets(self):
Jan Tattermusch6d28d352016-03-25 15:07:22 -0700577 return ['grpc_csharp_ext']
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800578
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800579 def make_options(self):
Jan Tattermusch6d28d352016-03-25 15:07:22 -0700580 return self._make_options;
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800581
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800582 def build_steps(self):
Jan Tattermusch76511a52016-06-17 14:00:57 -0700583 if self.args.compiler == 'coreclr':
Jan Tattermuschbc98af12016-06-17 18:38:27 -0700584 if self.platform == 'windows':
585 return [['tools\\run_tests\\build_csharp_coreclr.bat']]
586 else:
587 return [['tools/run_tests/build_csharp_coreclr.sh']]
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700588 else:
Jan Tattermusch76511a52016-06-17 14:00:57 -0700589 if self.platform == 'windows':
590 return [[_windows_build_bat(self.args.compiler),
591 'src/csharp/Grpc.sln',
592 '/p:Configuration=%s' % _MSBUILD_CONFIG[self.config.build_config]]]
593 else:
594 return [['tools/run_tests/build_csharp.sh']]
Nathaniel Manista840615e2015-01-22 20:31:47 +0000595
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200596 def post_tests_steps(self):
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700597 if self.platform == 'windows':
598 return [['tools\\run_tests\\post_tests_csharp.bat']]
599 else:
600 return [['tools/run_tests/post_tests_csharp.sh']]
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200601
murgatroid99a3e244f2015-09-22 11:25:53 -0700602 def makefile_name(self):
603 return 'Makefile'
604
Jan Tattermusch77db4322016-02-20 20:19:35 -0800605 def dockerfile_dir(self):
Jan Tattermusch76511a52016-06-17 14:00:57 -0700606 return 'tools/dockerfile/test/csharp_%s_%s' % (self._docker_distro,
607 _docker_arch_suffix(self.args.arch))
Jan Tattermusch788ee232016-01-26 12:19:44 -0800608
murgatroid99132ce6a2015-03-04 17:29:14 -0800609 def __str__(self):
610 return 'csharp'
611
Craig Tillerd625d812015-04-08 15:52:35 -0700612
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700613class ObjCLanguage(object):
614
Jan Tattermusch77db4322016-02-20 20:19:35 -0800615 def configure(self, config, args):
616 self.config = config
617 self.args = args
618 _check_compiler(self.args.compiler, ['default'])
619
620 def test_specs(self):
621 return [self.config.job_spec(['src/objective-c/tests/run_tests.sh'], None,
Yuchen Zengcaca0a12016-06-21 23:07:49 -0700622 environ=_FORCE_ENVIRON_FOR_WRAPPERS),
Yuchen Zengf95a4892016-06-21 23:27:46 -0700623 self.config.job_spec(['src/objective-c/tests/build_example_test.sh'],
Yuchen Zeng82393ef2016-06-22 10:29:17 -0700624 None, timeout_seconds=15*60,
Yuchen Zengc0668c82016-06-22 01:30:47 -0700625 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700626
murgatroid99256d3df2015-09-21 16:58:02 -0700627 def pre_build_steps(self):
628 return []
629
Jan Tattermusch77db4322016-02-20 20:19:35 -0800630 def make_targets(self):
Jorge Canizalesd0b32e92015-07-30 23:08:43 -0700631 return ['grpc_objective_c_plugin', 'interop_server']
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700632
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800633 def make_options(self):
634 return []
635
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700636 def build_steps(self):
Jorge Canizalesd0b32e92015-07-30 23:08:43 -0700637 return [['src/objective-c/tests/build_tests.sh']]
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700638
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200639 def post_tests_steps(self):
640 return []
641
murgatroid99a3e244f2015-09-22 11:25:53 -0700642 def makefile_name(self):
643 return 'Makefile'
644
Jan Tattermusch77db4322016-02-20 20:19:35 -0800645 def dockerfile_dir(self):
Jan Tattermusch788ee232016-01-26 12:19:44 -0800646 return None
647
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700648 def __str__(self):
649 return 'objc'
650
651
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100652class Sanity(object):
653
Jan Tattermusch77db4322016-02-20 20:19:35 -0800654 def configure(self, config, args):
655 self.config = config
656 self.args = args
657 _check_compiler(self.args.compiler, ['default'])
658
659 def test_specs(self):
Craig Tiller94d04a52016-01-20 10:58:23 -0800660 import yaml
Jan Tattermusch788ee232016-01-26 12:19:44 -0800661 with open('tools/run_tests/sanity/sanity_tests.yaml', 'r') as f:
Craig Tiller34226af2016-06-24 16:46:25 -0700662 return [self.config.job_spec(cmd['script'].split(),
Jan Tattermusch77db4322016-02-20 20:19:35 -0800663 timeout_seconds=None, environ={'TEST': 'true'},
664 cpu_cost=cmd.get('cpu_cost', 1))
Craig Tiller94d04a52016-01-20 10:58:23 -0800665 for cmd in yaml.load(f)]
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100666
murgatroid99256d3df2015-09-21 16:58:02 -0700667 def pre_build_steps(self):
668 return []
669
Jan Tattermusch77db4322016-02-20 20:19:35 -0800670 def make_targets(self):
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100671 return ['run_dep_checks']
672
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800673 def make_options(self):
674 return []
675
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100676 def build_steps(self):
677 return []
678
Nicolas "Pixel" Noble87879b32015-10-12 23:28:53 +0200679 def post_tests_steps(self):
680 return []
681
murgatroid99a3e244f2015-09-22 11:25:53 -0700682 def makefile_name(self):
683 return 'Makefile'
684
Jan Tattermusch77db4322016-02-20 20:19:35 -0800685 def dockerfile_dir(self):
Jan Tattermusche70b3c52016-02-07 20:21:02 -0800686 return 'tools/dockerfile/test/sanity'
Jan Tattermusch788ee232016-01-26 12:19:44 -0800687
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100688 def __str__(self):
689 return 'sanity'
690
Nicolas "Pixel" Noblee55cd7f2015-04-14 17:59:13 +0200691
Craig Tiller738c3342015-01-12 14:28:33 -0800692# different configurations we can run under
Craig Tillera0f85172016-01-20 15:56:06 -0800693with open('tools/run_tests/configs.json') as f:
Craig Tiller1dce9062016-01-20 17:01:56 -0800694 _CONFIGS = dict((cfg['config'], Config(**cfg)) for cfg in ast.literal_eval(f.read()))
Craig Tiller738c3342015-01-12 14:28:33 -0800695
696
Craig Tillerc7449162015-01-16 14:42:10 -0800697_LANGUAGES = {
Craig Tillere9c959d2015-01-18 10:23:26 -0800698 'c++': CLanguage('cxx', 'c++'),
699 'c': CLanguage('c', 'c'),
murgatroid992c8d5162015-01-26 10:41:21 -0800700 'node': NodeLanguage(),
Nathaniel Manista840615e2015-01-22 20:31:47 +0000701 'php': PhpLanguage(),
702 'python': PythonLanguage(),
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800703 'ruby': RubyLanguage(),
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100704 'csharp': CSharpLanguage(),
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700705 'objc' : ObjCLanguage(),
Jan Tattermusch70a57e42016-02-20 18:50:27 -0800706 'sanity': Sanity()
Craig Tillereb272bc2015-01-30 13:13:14 -0800707 }
Nicolas Nobleddef2462015-01-06 18:08:25 -0800708
Jan Tattermusch77db4322016-02-20 20:19:35 -0800709
Jan Tattermuscha2d964c2016-02-22 17:33:09 -0800710_MSBUILD_CONFIG = {
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700711 'dbg': 'Debug',
712 'opt': 'Release',
Jan Tattermusche4a69182015-12-15 09:53:01 -0800713 'gcov': 'Debug',
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700714 }
715
David Garcia Quintase90cd372015-05-31 18:15:26 -0700716
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800717def _windows_arch_option(arch):
718 """Returns msbuild cmdline option for selected architecture."""
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800719 if arch == 'default' or arch == 'x86':
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800720 return '/p:Platform=Win32'
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800721 elif arch == 'x64':
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800722 return '/p:Platform=x64'
723 else:
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800724 print 'Architecture %s not supported.' % arch
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800725 sys.exit(1)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800726
Jan Tattermuschf08018a2016-01-26 08:22:09 -0800727
728def _check_arch_option(arch):
729 """Checks that architecture option is valid."""
730 if platform_string() == 'windows':
731 _windows_arch_option(arch)
732 elif platform_string() == 'linux':
733 # On linux, we need to be running under docker with the right architecture.
Jan Tattermusch07fb0422016-01-26 10:46:56 -0800734 runtime_arch = platform.architecture()[0]
Jan Tattermuschf08018a2016-01-26 08:22:09 -0800735 if arch == 'default':
736 return
737 elif runtime_arch == '64bit' and arch == 'x64':
738 return
739 elif runtime_arch == '32bit' and arch == 'x86':
740 return
741 else:
742 print 'Architecture %s does not match current runtime architecture.' % arch
743 sys.exit(1)
744 else:
745 if args.arch != 'default':
746 print 'Architecture %s not supported on current platform.' % args.arch
747 sys.exit(1)
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800748
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800749
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800750def _windows_build_bat(compiler):
751 """Returns name of build.bat for selected compiler."""
Jan Tattermuschbc98af12016-06-17 18:38:27 -0700752 # For CoreCLR, fall back to the default compiler for C core
753 if compiler == 'default' or compiler == 'vs2013' or compiler == 'coreclr':
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800754 return 'vsprojects\\build_vs2013.bat'
755 elif compiler == 'vs2015':
756 return 'vsprojects\\build_vs2015.bat'
757 elif compiler == 'vs2010':
758 return 'vsprojects\\build_vs2010.bat'
759 else:
760 print 'Compiler %s not supported.' % compiler
761 sys.exit(1)
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800762
763
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800764def _windows_toolset_option(compiler):
765 """Returns msbuild PlatformToolset for selected compiler."""
Jan Tattermuschbc98af12016-06-17 18:38:27 -0700766 # For CoreCLR, fall back to the default compiler for C core
767 if compiler == 'default' or compiler == 'vs2013' or compiler == 'coreclr':
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800768 return '/p:PlatformToolset=v120'
769 elif compiler == 'vs2015':
770 return '/p:PlatformToolset=v140'
771 elif compiler == 'vs2010':
772 return '/p:PlatformToolset=v100'
773 else:
774 print 'Compiler %s not supported.' % compiler
775 sys.exit(1)
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800776
777
Jan Tattermusche70b3c52016-02-07 20:21:02 -0800778def _docker_arch_suffix(arch):
779 """Returns suffix to dockerfile dir to use."""
780 if arch == 'default' or arch == 'x64':
781 return 'x64'
782 elif arch == 'x86':
783 return 'x86'
784 else:
785 print 'Architecture %s not supported with current settings.' % arch
786 sys.exit(1)
787
788
David Garcia Quintase90cd372015-05-31 18:15:26 -0700789def runs_per_test_type(arg_str):
790 """Auxilary function to parse the "runs_per_test" flag.
791
792 Returns:
793 A positive integer or 0, the latter indicating an infinite number of
794 runs.
795
796 Raises:
797 argparse.ArgumentTypeError: Upon invalid input.
798 """
799 if arg_str == 'inf':
800 return 0
801 try:
802 n = int(arg_str)
803 if n <= 0: raise ValueError
Craig Tiller50e53e22015-06-01 20:18:21 -0700804 return n
David Garcia Quintase90cd372015-05-31 18:15:26 -0700805 except:
Adele Zhoue4c35612015-10-16 15:34:23 -0700806 msg = '\'{}\' is not a positive integer or \'inf\''.format(arg_str)
David Garcia Quintase90cd372015-05-31 18:15:26 -0700807 raise argparse.ArgumentTypeError(msg)
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700808
809# parse command line
810argp = argparse.ArgumentParser(description='Run grpc tests.')
811argp.add_argument('-c', '--config',
Jan Tattermusch77db4322016-02-20 20:19:35 -0800812 choices=sorted(_CONFIGS.keys()),
813 default='opt')
David Garcia Quintase90cd372015-05-31 18:15:26 -0700814argp.add_argument('-n', '--runs_per_test', default=1, type=runs_per_test_type,
815 help='A positive integer or "inf". If "inf", all tests will run in an '
816 'infinite loop. Especially useful in combination with "-f"')
Craig Tillerfe406ec2015-02-24 13:55:12 -0800817argp.add_argument('-r', '--regex', default='.*', type=str)
Vijay Pai488fd0e2016-06-13 12:37:12 -0700818argp.add_argument('--regex_exclude', default='', type=str)
Craig Tiller5f735a62016-01-20 09:31:15 -0800819argp.add_argument('-j', '--jobs', default=multiprocessing.cpu_count(), type=int)
Craig Tiller8451e872015-02-27 09:25:51 -0800820argp.add_argument('-s', '--slowdown', default=1.0, type=float)
ctiller3040cb72015-01-07 12:13:17 -0800821argp.add_argument('-f', '--forever',
822 default=False,
823 action='store_const',
824 const=True)
Nicolas "Pixel" Noblea7df3f92015-02-26 22:07:04 +0100825argp.add_argument('-t', '--travis',
826 default=False,
827 action='store_const',
828 const=True)
Nicolas Noble044db742015-01-14 16:57:24 -0800829argp.add_argument('--newline_on_success',
830 default=False,
831 action='store_const',
832 const=True)
Craig Tiller686fb262015-01-15 07:39:09 -0800833argp.add_argument('-l', '--language',
Craig Tiller60f15e62015-05-13 09:05:17 -0700834 choices=['all'] + sorted(_LANGUAGES.keys()),
Craig Tiller686fb262015-01-15 07:39:09 -0800835 nargs='+',
Craig Tiller60f15e62015-05-13 09:05:17 -0700836 default=['all'])
Craig Tillercd43da82015-05-29 08:41:29 -0700837argp.add_argument('-S', '--stop_on_failure',
838 default=False,
839 action='store_const',
840 const=True)
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700841argp.add_argument('--use_docker',
842 default=False,
843 action='store_const',
844 const=True,
Adele Zhoue4c35612015-10-16 15:34:23 -0700845 help='Run all the tests under docker. That provides ' +
846 'additional isolation and prevents the need to install ' +
847 'language specific prerequisites. Only available on Linux.')
Craig Tillerd4509a12015-09-28 09:18:40 -0700848argp.add_argument('--allow_flakes',
849 default=False,
850 action='store_const',
851 const=True,
Adele Zhoue4c35612015-10-16 15:34:23 -0700852 help='Allow flaky tests to show as passing (re-runs failed tests up to five times)')
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800853argp.add_argument('--arch',
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800854 choices=['default', 'x86', 'x64'],
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800855 default='default',
856 help='Selects architecture to target. For some platforms "default" is the only supported choice.')
857argp.add_argument('--compiler',
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800858 choices=['default',
Jan Tattermusch6d258c52016-06-10 09:36:51 -0700859 'gcc4.4', 'gcc4.6', 'gcc4.9', 'gcc5.3',
860 'clang3.4', 'clang3.5', 'clang3.6', 'clang3.7',
Jan Tattermusch825471c2016-04-25 16:52:25 -0700861 'vs2010', 'vs2013', 'vs2015',
murgatroid999fab4382016-04-29 15:05:00 -0700862 'python2.7', 'python3.4',
Jan Tattermusch76511a52016-06-17 14:00:57 -0700863 'node0.12', 'node4', 'node5',
864 'coreclr'],
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800865 default='default',
Jan Tattermusch77db4322016-02-20 20:19:35 -0800866 help='Selects compiler to use. Allowed values depend on the platform and language.')
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800867argp.add_argument('--build_only',
868 default=False,
869 action='store_const',
870 const=True,
871 help='Perform all the build steps but dont run any tests.')
Craig Tiller5f735a62016-01-20 09:31:15 -0800872argp.add_argument('--measure_cpu_costs', default=False, action='store_const', const=True,
873 help='Measure the cpu costs of tests')
Craig Tiller1676f912016-01-05 10:49:44 -0800874argp.add_argument('--update_submodules', default=[], nargs='*',
875 help='Update some submodules before building. If any are updated, also run generate_projects. ' +
876 'Submodules are specified as SUBMODULE_NAME:BRANCH; if BRANCH is omitted, master is assumed.')
Craig Tiller234b6e72015-05-23 10:12:40 -0700877argp.add_argument('-a', '--antagonists', default=0, type=int)
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +0200878argp.add_argument('-x', '--xml_report', default=None, type=str,
879 help='Generates a JUnit-compatible XML report')
Craig Tiller123f1372016-06-15 15:06:14 -0700880argp.add_argument('--force_default_poller', default=False, action='store_const', const=True,
881 help='Dont try to iterate over many polling strategies when they exist')
Nicolas Nobleddef2462015-01-06 18:08:25 -0800882args = argp.parse_args()
883
Craig Tiller123f1372016-06-15 15:06:14 -0700884if args.force_default_poller:
885 _POLLING_STRATEGIES = {}
886
Craig Tiller5f735a62016-01-20 09:31:15 -0800887jobset.measure_cpu_costs = args.measure_cpu_costs
888
Craig Tiller1676f912016-01-05 10:49:44 -0800889# update submodules if necessary
Craig Tillerb361b4e2016-01-06 11:44:17 -0800890need_to_regenerate_projects = False
891for spec in args.update_submodules:
892 spec = spec.split(':', 1)
893 if len(spec) == 1:
894 submodule = spec[0]
895 branch = 'master'
896 elif len(spec) == 2:
897 submodule = spec[0]
898 branch = spec[1]
899 cwd = 'third_party/%s' % submodule
900 def git(cmd, cwd=cwd):
901 print 'in %s: git %s' % (cwd, cmd)
902 subprocess.check_call('git %s' % cmd, cwd=cwd, shell=True)
903 git('fetch')
904 git('checkout %s' % branch)
905 git('pull origin %s' % branch)
906 if os.path.exists('src/%s/gen_build_yaml.py' % submodule):
907 need_to_regenerate_projects = True
908if need_to_regenerate_projects:
909 if jobset.platform_string() == 'linux':
910 subprocess.check_call('tools/buildgen/generate_projects.sh', shell=True)
911 else:
912 print 'WARNING: may need to regenerate projects, but since we are not on'
913 print ' Linux this step is being skipped. Compilation MAY fail.'
Craig Tiller1676f912016-01-05 10:49:44 -0800914
915
Nicolas Nobleddef2462015-01-06 18:08:25 -0800916# grab config
Jan Tattermusch77db4322016-02-20 20:19:35 -0800917run_config = _CONFIGS[args.config]
918build_config = run_config.build_config
Craig Tillerf1973b02015-01-16 12:32:13 -0800919
Craig Tiller06805272015-06-11 14:46:47 -0700920if args.travis:
murgatroid99d3b5b7f2015-10-06 17:02:03 -0700921 _FORCE_ENVIRON_FOR_WRAPPERS = {'GRPC_TRACE': 'api'}
Craig Tiller06805272015-06-11 14:46:47 -0700922
Adele Zhou6b9527c2015-11-20 15:56:35 -0800923if 'all' in args.language:
Craig Tiller1676f912016-01-05 10:49:44 -0800924 lang_list = _LANGUAGES.keys()
Adele Zhou6b9527c2015-11-20 15:56:35 -0800925else:
926 lang_list = args.language
Craig Tiller16900662016-01-07 19:30:54 -0800927# We don't support code coverage on some languages
928if 'gcov' in args.config:
Jan Tattermusch3b5121b2016-02-22 17:41:05 -0800929 for bad in ['objc', 'sanity']:
Craig Tiller16900662016-01-07 19:30:54 -0800930 if bad in lang_list:
931 lang_list.remove(bad)
Adele Zhou6b9527c2015-11-20 15:56:35 -0800932
933languages = set(_LANGUAGES[l] for l in lang_list)
Jan Tattermusch77db4322016-02-20 20:19:35 -0800934for l in languages:
935 l.configure(run_config, args)
murgatroid99132ce6a2015-03-04 17:29:14 -0800936
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800937language_make_options=[]
938if any(language.make_options() for language in languages):
Adele Zhou3b6ab812016-05-18 17:04:20 -0700939 if not 'gcov' in args.config and len(languages) != 1:
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800940 print 'languages with custom make options cannot be built simultaneously with other languages'
941 sys.exit(1)
942 else:
943 language_make_options = next(iter(languages)).make_options()
944
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800945if args.use_docker:
946 if not args.travis:
947 print 'Seen --use_docker flag, will run tests under docker.'
948 print
949 print 'IMPORTANT: The changes you are testing need to be locally committed'
950 print 'because only the committed changes in the current branch will be'
951 print 'copied to the docker environment.'
952 time.sleep(5)
953
Jan Tattermusch3b5121b2016-02-22 17:41:05 -0800954 dockerfile_dirs = set([l.dockerfile_dir() for l in languages])
955 if len(dockerfile_dirs) > 1:
Adele Zhou9506ef22016-03-02 13:53:34 -0800956 if 'gcov' in args.config:
957 dockerfile_dir = 'tools/dockerfile/test/multilang_jessie_x64'
958 print ('Using multilang_jessie_x64 docker image for code coverage for '
959 'all languages.')
960 else:
961 print ('Languages to be tested require running under different docker '
962 'images.')
963 sys.exit(1)
964 else:
965 dockerfile_dir = next(iter(dockerfile_dirs))
Craig Tillerde7edf82016-03-20 09:12:16 -0700966
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800967 child_argv = [ arg for arg in sys.argv if not arg == '--use_docker' ]
Jan Tattermusched342b12016-01-26 14:40:31 -0800968 run_tests_cmd = 'python tools/run_tests/run_tests.py %s' % ' '.join(child_argv[1:])
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800969
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800970 env = os.environ.copy()
971 env['RUN_TESTS_COMMAND'] = run_tests_cmd
Jan Tattermusch3b5121b2016-02-22 17:41:05 -0800972 env['DOCKERFILE_DIR'] = dockerfile_dir
Jan Tattermusch9835d4b2016-04-29 15:05:05 -0700973 env['DOCKER_RUN_SCRIPT'] = 'tools/run_tests/dockerize/docker_run_tests.sh'
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800974 if args.xml_report:
975 env['XML_REPORT'] = args.xml_report
976 if not args.travis:
977 env['TTY_FLAG'] = '-t' # enables Ctrl-C when not on Jenkins.
978
Jan Tattermusch9835d4b2016-04-29 15:05:05 -0700979 subprocess.check_call(['tools/run_tests/dockerize/build_docker_and_run_tests.sh'],
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800980 shell=True,
981 env=env)
982 sys.exit(0)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800983
Jan Tattermuschf08018a2016-01-26 08:22:09 -0800984_check_arch_option(args.arch)
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800985
Jan Tattermuschfba65302016-01-25 18:21:14 -0800986def make_jobspec(cfg, targets, makefile='Makefile'):
987 if platform_string() == 'windows':
Craig Tillerfc3c0c42015-09-01 16:47:54 -0700988 extra_args = []
Craig Tillerb5391e12015-09-03 14:35:18 -0700989 # better do parallel compilation
Jan Tattermusch47eeb2b2015-10-07 14:09:18 -0700990 # empirically /m:2 gives the best performance/price and should prevent
991 # overloading the windows workers.
Adele Zhoue4c35612015-10-16 15:34:23 -0700992 extra_args.extend(['/m:2'])
Craig Tillerb5391e12015-09-03 14:35:18 -0700993 # disable PDB generation: it's broken, and we don't need it during CI
Adele Zhoue4c35612015-10-16 15:34:23 -0700994 extra_args.extend(['/p:Jenkins=true'])
Craig Tiller6fd23842015-09-01 07:36:31 -0700995 return [
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800996 jobset.JobSpec([_windows_build_bat(args.compiler),
murgatroid99cf08daf2015-09-21 15:33:16 -0700997 'vsprojects\\%s.sln' % target,
Jan Tattermuscha2d964c2016-02-22 17:33:09 -0800998 '/p:Configuration=%s' % _MSBUILD_CONFIG[cfg]] +
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800999 extra_args +
1000 language_make_options,
Craig Tiller590105a2016-01-19 13:03:46 -08001001 shell=True, timeout_seconds=None)
Craig Tiller6fd23842015-09-01 07:36:31 -07001002 for target in targets]
Jan Tattermuschfba65302016-01-25 18:21:14 -08001003 else:
murgatroid998ae409f2015-10-26 16:39:00 -07001004 if targets:
1005 return [jobset.JobSpec([os.getenv('MAKE', 'make'),
1006 '-f', makefile,
Craig Tillerdd6f7ed2016-01-21 12:54:42 -08001007 '-j', '%d' % args.jobs,
Craig Tiller71a86042016-01-15 14:59:58 -08001008 'EXTRA_DEFINES=GRPC_TEST_SLOWDOWN_MACHINE_FACTOR=%f' % args.slowdown,
1009 'CONFIG=%s' % cfg] +
Jan Tattermuschc895fe02016-01-20 09:13:09 -08001010 language_make_options +
Craig Tiller71a86042016-01-15 14:59:58 -08001011 ([] if not args.travis else ['JENKINS_BUILD=1']) +
1012 targets,
Craig Tiller590105a2016-01-19 13:03:46 -08001013 timeout_seconds=None)]
murgatroid998ae409f2015-10-26 16:39:00 -07001014 else:
1015 return []
Jan Tattermuschfba65302016-01-25 18:21:14 -08001016
murgatroid99a3e244f2015-09-22 11:25:53 -07001017make_targets = {}
1018for l in languages:
1019 makefile = l.makefile_name()
1020 make_targets[makefile] = make_targets.get(makefile, set()).union(
Jan Tattermusch77db4322016-02-20 20:19:35 -08001021 set(l.make_targets()))
Craig Tiller5058c692015-04-08 09:42:04 -07001022
Jan Tattermusche4a69182015-12-15 09:53:01 -08001023def build_step_environ(cfg):
1024 environ = {'CONFIG': cfg}
Jan Tattermuscha2d964c2016-02-22 17:33:09 -08001025 msbuild_cfg = _MSBUILD_CONFIG.get(cfg)
Jan Tattermusche4a69182015-12-15 09:53:01 -08001026 if msbuild_cfg:
1027 environ['MSBUILD_CONFIG'] = msbuild_cfg
1028 return environ
1029
murgatroid99fddac962015-09-22 09:20:11 -07001030build_steps = list(set(
Jan Tattermusch77db4322016-02-20 20:19:35 -08001031 jobset.JobSpec(cmdline, environ=build_step_environ(build_config), flake_retries=5)
murgatroid99256d3df2015-09-21 16:58:02 -07001032 for l in languages
1033 for cmdline in l.pre_build_steps()))
Craig Tillerbd4e3782015-09-01 06:48:55 -07001034if make_targets:
Jan Tattermusch77db4322016-02-20 20:19:35 -08001035 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 -07001036 build_steps.extend(set(make_commands))
Craig Tiller5058c692015-04-08 09:42:04 -07001037build_steps.extend(set(
Jan Tattermusch77db4322016-02-20 20:19:35 -08001038 jobset.JobSpec(cmdline, environ=build_step_environ(build_config), timeout_seconds=None)
Craig Tiller547db2b2015-01-30 14:08:39 -08001039 for l in languages
Craig Tiller533b1a22015-05-29 08:41:29 -07001040 for cmdline in l.build_steps()))
Craig Tillerf1973b02015-01-16 12:32:13 -08001041
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +02001042post_tests_steps = list(set(
Jan Tattermusch77db4322016-02-20 20:19:35 -08001043 jobset.JobSpec(cmdline, environ=build_step_environ(build_config))
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +02001044 for l in languages
1045 for cmdline in l.post_tests_steps()))
Nicolas Nobleddef2462015-01-06 18:08:25 -08001046runs_per_test = args.runs_per_test
ctiller3040cb72015-01-07 12:13:17 -08001047forever = args.forever
Nicolas Nobleddef2462015-01-06 18:08:25 -08001048
Nicolas Nobleddef2462015-01-06 18:08:25 -08001049
Craig Tillerf53d9c82015-08-04 14:19:43 -07001050def _start_port_server(port_server_port):
1051 # check if a compatible port server is running
1052 # if incompatible (version mismatch) ==> start a new one
1053 # if not running ==> start a new one
1054 # otherwise, leave it up
1055 try:
Craig Tillerfe4939f2015-10-06 12:55:36 -07001056 version = int(urllib2.urlopen(
1057 'http://localhost:%d/version_number' % port_server_port,
Jan Tattermusch292d0102016-06-28 10:29:41 -07001058 timeout=10).read())
Craig Tillerfe4939f2015-10-06 12:55:36 -07001059 print 'detected port server running version %d' % version
Craig Tillerf53d9c82015-08-04 14:19:43 -07001060 running = True
Craig Tillerfe4939f2015-10-06 12:55:36 -07001061 except Exception as e:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001062 print 'failed to detect port server: %s' % sys.exc_info()[0]
Craig Tillerfe4939f2015-10-06 12:55:36 -07001063 print e.strerror
Craig Tillerf53d9c82015-08-04 14:19:43 -07001064 running = False
1065 if running:
Craig Tillerfe4939f2015-10-06 12:55:36 -07001066 current_version = int(subprocess.check_output(
Jan Tattermusch3bd08272015-11-04 19:24:37 -08001067 [sys.executable, os.path.abspath('tools/run_tests/port_server.py'),
1068 'dump_version']))
Craig Tillerfe4939f2015-10-06 12:55:36 -07001069 print 'my port server is version %d' % current_version
1070 running = (version >= current_version)
1071 if not running:
1072 print 'port_server version mismatch: killing the old one'
1073 urllib2.urlopen('http://localhost:%d/quitquitquit' % port_server_port).read()
1074 time.sleep(1)
Craig Tillerf53d9c82015-08-04 14:19:43 -07001075 if not running:
Craig Tillerf0a293e2015-10-12 10:05:50 -07001076 fd, logfile = tempfile.mkstemp()
1077 os.close(fd)
1078 print 'starting port_server, with log file %s' % logfile
Jan Tattermusch3bd08272015-11-04 19:24:37 -08001079 args = [sys.executable, os.path.abspath('tools/run_tests/port_server.py'),
1080 '-p', '%d' % port_server_port, '-l', logfile]
Craig Tiller367d41d2015-10-12 13:00:22 -07001081 env = dict(os.environ)
1082 env['BUILD_ID'] = 'pleaseDontKillMeJenkins'
Nicolas "Pixel" Noblef72d7b52015-12-03 03:07:43 +01001083 if platform_string() == 'windows':
Jan Tattermusch3bd08272015-11-04 19:24:37 -08001084 # Working directory of port server needs to be outside of Jenkins
1085 # workspace to prevent file lock issues.
1086 tempdir = tempfile.mkdtemp()
Craig Tillerd2c39712015-10-12 11:08:49 -07001087 port_server = subprocess.Popen(
Craig Tiller367d41d2015-10-12 13:00:22 -07001088 args,
1089 env=env,
Jan Tattermusch3bd08272015-11-04 19:24:37 -08001090 cwd=tempdir,
Craig Tiller367d41d2015-10-12 13:00:22 -07001091 creationflags = 0x00000008, # detached process
1092 close_fds=True)
Craig Tillerd2c39712015-10-12 11:08:49 -07001093 else:
1094 port_server = subprocess.Popen(
1095 args,
Craig Tiller367d41d2015-10-12 13:00:22 -07001096 env=env,
Craig Tillerd2c39712015-10-12 11:08:49 -07001097 preexec_fn=os.setsid,
1098 close_fds=True)
Craig Tillerf0a293e2015-10-12 10:05:50 -07001099 time.sleep(1)
Craig Tiller8b5f4dc2015-08-26 08:02:01 -07001100 # ensure port server is up
Craig Tillerabd37fd2015-08-26 07:54:01 -07001101 waits = 0
Craig Tillerf53d9c82015-08-04 14:19:43 -07001102 while True:
Craig Tillerabd37fd2015-08-26 07:54:01 -07001103 if waits > 10:
Craig Tillerf0a293e2015-10-12 10:05:50 -07001104 print 'killing port server due to excessive start up waits'
Craig Tillerabd37fd2015-08-26 07:54:01 -07001105 port_server.kill()
Craig Tillera2f38b02015-09-24 11:19:17 -07001106 if port_server.poll() is not None:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001107 print 'port_server failed to start'
Craig Tillerf0a293e2015-10-12 10:05:50 -07001108 # try one final time: maybe another build managed to start one
1109 time.sleep(1)
1110 try:
1111 urllib2.urlopen('http://localhost:%d/get' % port_server_port,
1112 timeout=1).read()
1113 print 'last ditch attempt to contact port server succeeded'
1114 break
1115 except:
Jan Tattermusch3b5121b2016-02-22 17:41:05 -08001116 traceback.print_exc()
Craig Tillerf0a293e2015-10-12 10:05:50 -07001117 port_log = open(logfile, 'r').read()
1118 print port_log
1119 sys.exit(1)
Craig Tillerf53d9c82015-08-04 14:19:43 -07001120 try:
Craig Tillerabd37fd2015-08-26 07:54:01 -07001121 urllib2.urlopen('http://localhost:%d/get' % port_server_port,
1122 timeout=1).read()
Craig Tillerf0a293e2015-10-12 10:05:50 -07001123 print 'port server is up and ready'
Craig Tillerf53d9c82015-08-04 14:19:43 -07001124 break
Craig Tiller31fdaa42015-09-25 13:09:59 -07001125 except socket.timeout:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001126 print 'waiting for port_server: timeout'
Craig Tillerf0a293e2015-10-12 10:05:50 -07001127 traceback.print_exc();
1128 time.sleep(1)
Craig Tiller31fdaa42015-09-25 13:09:59 -07001129 waits += 1
Craig Tillerf53d9c82015-08-04 14:19:43 -07001130 except urllib2.URLError:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001131 print 'waiting for port_server: urlerror'
Craig Tillerf0a293e2015-10-12 10:05:50 -07001132 traceback.print_exc();
1133 time.sleep(1)
Craig Tillerabd37fd2015-08-26 07:54:01 -07001134 waits += 1
Craig Tillerf53d9c82015-08-04 14:19:43 -07001135 except:
Jan Tattermusch3b5121b2016-02-22 17:41:05 -08001136 traceback.print_exc()
Craig Tillerf53d9c82015-08-04 14:19:43 -07001137 port_server.kill()
1138 raise
1139
1140
Adele Zhoud5fffa52015-10-23 15:51:42 -07001141def _calculate_num_runs_failures(list_of_results):
1142 """Caculate number of runs and failures for a particular test.
1143
1144 Args:
1145 list_of_results: (List) of JobResult object.
1146 Returns:
1147 A tuple of total number of runs and failures.
1148 """
1149 num_runs = len(list_of_results) # By default, there is 1 run per JobResult.
1150 num_failures = 0
1151 for jobresult in list_of_results:
1152 if jobresult.retries > 0:
1153 num_runs += jobresult.retries
1154 if jobresult.num_failures > 0:
1155 num_failures += jobresult.num_failures
1156 return num_runs, num_failures
1157
Adele Zhou6b9527c2015-11-20 15:56:35 -08001158
Craig Tillereb9de8b2016-01-08 08:57:41 -08001159# _build_and_run results
1160class BuildAndRunError(object):
1161
1162 BUILD = object()
1163 TEST = object()
1164 POST_TEST = object()
1165
1166
1167# returns a list of things that failed (or an empty list on success)
Craig Tillerf53d9c82015-08-04 14:19:43 -07001168def _build_and_run(
Craig Tiller74189cd2016-06-23 15:39:06 -07001169 check_cancelled, newline_on_success, xml_report=None, build_only=False):
ctiller3040cb72015-01-07 12:13:17 -08001170 """Do one pass of building & running tests."""
murgatroid99666450e2015-01-26 13:03:31 -08001171 # build latest sequentially
Jan Tattermuschaab1e512016-01-28 09:30:44 -08001172 num_failures, resultset = jobset.run(
Adele Zhoue4c35612015-10-16 15:34:23 -07001173 build_steps, maxjobs=1, stop_on_failure=True,
Craig Tiller883064c2015-11-04 10:06:10 -08001174 newline_on_success=newline_on_success, travis=args.travis)
Adele Zhoue4c35612015-10-16 15:34:23 -07001175 if num_failures:
Craig Tillereb9de8b2016-01-08 08:57:41 -08001176 return [BuildAndRunError.BUILD]
Craig Tillerb361b4e2016-01-06 11:44:17 -08001177
Jan Tattermusch2dd156e2015-12-04 18:26:17 -08001178 if build_only:
Jan Tattermuschaab1e512016-01-28 09:30:44 -08001179 if xml_report:
1180 report_utils.render_junit_xml_report(resultset, xml_report)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001181 return []
ctiller3040cb72015-01-07 12:13:17 -08001182
Craig Tiller234b6e72015-05-23 10:12:40 -07001183 # start antagonists
David Garcia Quintas79e389f2015-06-02 17:49:42 -07001184 antagonists = [subprocess.Popen(['tools/run_tests/antagonist.py'])
Craig Tiller234b6e72015-05-23 10:12:40 -07001185 for _ in range(0, args.antagonists)]
Craig Tillerfe4939f2015-10-06 12:55:36 -07001186 port_server_port = 32767
Craig Tillerf53d9c82015-08-04 14:19:43 -07001187 _start_port_server(port_server_port)
Adele Zhou7cf72112015-11-04 11:18:43 -08001188 resultset = None
Adele Zhou803af152015-11-30 15:16:16 -08001189 num_test_failures = 0
Craig Tiller234b6e72015-05-23 10:12:40 -07001190 try:
David Garcia Quintase90cd372015-05-31 18:15:26 -07001191 infinite_runs = runs_per_test == 0
yang-g6c1fdc62015-08-18 11:57:42 -07001192 one_run = set(
1193 spec
yang-g6c1fdc62015-08-18 11:57:42 -07001194 for language in languages
Jan Tattermusch77db4322016-02-20 20:19:35 -08001195 for spec in language.test_specs()
Vijay Pai488fd0e2016-06-13 12:37:12 -07001196 if (re.search(args.regex, spec.shortname) and
1197 (args.regex_exclude == '' or
1198 not re.search(args.regex_exclude, spec.shortname))))
David Garcia Quintas79e389f2015-06-02 17:49:42 -07001199 # When running on travis, we want out test runs to be as similar as possible
1200 # for reproducibility purposes.
Craig Tiller883064c2015-11-04 10:06:10 -08001201 if args.travis:
David Garcia Quintas79e389f2015-06-02 17:49:42 -07001202 massaged_one_run = sorted(one_run, key=lambda x: x.shortname)
1203 else:
1204 # whereas otherwise, we want to shuffle things up to give all tests a
1205 # chance to run.
1206 massaged_one_run = list(one_run) # random.shuffle needs an indexable seq.
1207 random.shuffle(massaged_one_run) # which it modifies in-place.
Craig Tillerf7b7c892015-06-22 14:33:25 -07001208 if infinite_runs:
1209 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 -07001210 runs_sequence = (itertools.repeat(massaged_one_run) if infinite_runs
1211 else itertools.repeat(massaged_one_run, runs_per_test))
David Garcia Quintase90cd372015-05-31 18:15:26 -07001212 all_runs = itertools.chain.from_iterable(runs_sequence)
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +02001213
Adele Zhou803af152015-11-30 15:16:16 -08001214 num_test_failures, resultset = jobset.run(
Adele Zhou2271ab52015-10-28 13:59:14 -07001215 all_runs, check_cancelled, newline_on_success=newline_on_success,
Craig Tiller883064c2015-11-04 10:06:10 -08001216 travis=args.travis, infinite_runs=infinite_runs, maxjobs=args.jobs,
murgatroid998ae409f2015-10-26 16:39:00 -07001217 stop_on_failure=args.stop_on_failure,
Adele Zhouf2ca7bc2015-10-23 15:38:00 -07001218 add_env={'GRPC_TEST_PORT_SERVER': 'localhost:%d' % port_server_port})
Adele Zhoud5fffa52015-10-23 15:51:42 -07001219 if resultset:
Craig Tiller2b59dbc2016-05-13 15:59:09 -07001220 for k, v in sorted(resultset.items()):
Adele Zhoud5fffa52015-10-23 15:51:42 -07001221 num_runs, num_failures = _calculate_num_runs_failures(v)
1222 if num_failures == num_runs: # what about infinite_runs???
1223 jobset.message('FAILED', k, do_newline=True)
1224 elif num_failures > 0:
1225 jobset.message(
1226 'FLAKE', '%s [%d/%d runs flaked]' % (k, num_failures, num_runs),
1227 do_newline=True)
1228 else:
1229 jobset.message('PASSED', k, do_newline=True)
Craig Tiller234b6e72015-05-23 10:12:40 -07001230 finally:
1231 for antagonist in antagonists:
1232 antagonist.kill()
Adele Zhou7cf72112015-11-04 11:18:43 -08001233 if xml_report and resultset:
Adele Zhou3bc7ba42015-11-05 10:21:58 -08001234 report_utils.render_junit_xml_report(resultset, xml_report)
Craig Tillerd86a3942015-01-14 12:48:54 -08001235
Adele Zhouf2ca7bc2015-10-23 15:38:00 -07001236 number_failures, _ = jobset.run(
1237 post_tests_steps, maxjobs=1, stop_on_failure=True,
Craig Tiller883064c2015-11-04 10:06:10 -08001238 newline_on_success=newline_on_success, travis=args.travis)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001239
1240 out = []
1241 if number_failures:
1242 out.append(BuildAndRunError.POST_TEST)
1243 if num_test_failures:
1244 out.append(BuildAndRunError.TEST)
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +02001245
Craig Tillereb9de8b2016-01-08 08:57:41 -08001246 return out
ctiller3040cb72015-01-07 12:13:17 -08001247
1248
1249if forever:
Nicolas Noble044db742015-01-14 16:57:24 -08001250 success = True
ctiller3040cb72015-01-07 12:13:17 -08001251 while True:
Craig Tiller42bc87c2015-02-23 08:50:19 -08001252 dw = watch_dirs.DirWatcher(['src', 'include', 'test', 'examples'])
ctiller3040cb72015-01-07 12:13:17 -08001253 initial_time = dw.most_recent_change()
1254 have_files_changed = lambda: dw.most_recent_change() != initial_time
Nicolas Noble044db742015-01-14 16:57:24 -08001255 previous_success = success
Craig Tillereb9de8b2016-01-08 08:57:41 -08001256 errors = _build_and_run(check_cancelled=have_files_changed,
1257 newline_on_success=False,
Craig Tillereb9de8b2016-01-08 08:57:41 -08001258 build_only=args.build_only) == 0
1259 if not previous_success and not errors:
Nicolas Nobleb09078f2015-01-14 18:06:05 -08001260 jobset.message('SUCCESS',
1261 'All tests are now passing properly',
1262 do_newline=True)
Nicolas Noble044db742015-01-14 16:57:24 -08001263 jobset.message('IDLE', 'No change detected')
ctiller3040cb72015-01-07 12:13:17 -08001264 while not have_files_changed():
1265 time.sleep(1)
1266else:
Craig Tillereb9de8b2016-01-08 08:57:41 -08001267 errors = _build_and_run(check_cancelled=lambda: False,
Craig Tiller71735182015-01-15 17:07:13 -08001268 newline_on_success=args.newline_on_success,
Jan Tattermusch2dd156e2015-12-04 18:26:17 -08001269 xml_report=args.xml_report,
1270 build_only=args.build_only)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001271 if not errors:
Nicolas Nobleb09078f2015-01-14 18:06:05 -08001272 jobset.message('SUCCESS', 'All tests passed', do_newline=True)
1273 else:
1274 jobset.message('FAILED', 'Some tests failed', do_newline=True)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001275 exit_code = 0
1276 if BuildAndRunError.BUILD in errors:
1277 exit_code |= 1
Craig Tiller4f2be362016-01-08 08:59:20 -08001278 if BuildAndRunError.TEST in errors and not args.travis:
Craig Tillereb9de8b2016-01-08 08:57:41 -08001279 exit_code |= 2
Craig Tiller4f2be362016-01-08 08:59:20 -08001280 if BuildAndRunError.POST_TEST in errors:
1281 exit_code |= 4
Craig Tillereb9de8b2016-01-08 08:57:41 -08001282 sys.exit(exit_code)