blob: e9c663695b35e541a3d061293f099a501ff006e2 [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
Masood Malekghassemi3b5b2062016-06-02 20:27:20 -070035import collections
Nicolas Nobleddef2462015-01-06 18:08:25 -080036import glob
37import 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
Masood Malekghassemi3b5b2062016-06-02 20:27:20 -070041import os.path
David Garcia Quintas79e389f2015-06-02 17:49:42 -070042import platform
43import random
Craig Tillerfe406ec2015-02-24 13:55:12 -080044import re
Craig Tiller82875232015-09-25 13:57:34 -070045import socket
David Garcia Quintas79e389f2015-06-02 17:49:42 -070046import subprocess
Nicolas Nobleddef2462015-01-06 18:08:25 -080047import sys
Craig Tillerf0a293e2015-10-12 10:05:50 -070048import tempfile
49import traceback
ctiller3040cb72015-01-07 12:13:17 -080050import time
Craig Tillerf53d9c82015-08-04 14:19:43 -070051import urllib2
Jan Tattermusch03c01062015-12-11 14:28:56 -080052import uuid
Nicolas Nobleddef2462015-01-06 18:08:25 -080053
54import jobset
Adele Zhoua30f8292015-11-02 13:15:46 -080055import report_utils
ctiller3040cb72015-01-07 12:13:17 -080056import watch_dirs
Nicolas Nobleddef2462015-01-06 18:08:25 -080057
Craig Tillerb361b4e2016-01-06 11:44:17 -080058
Jan Tattermusch3b5121b2016-02-22 17:41:05 -080059_ROOT = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), '../..'))
60os.chdir(_ROOT)
Craig Tiller2cc2b842015-02-27 11:38:31 -080061
62
Craig Tiller06805272015-06-11 14:46:47 -070063_FORCE_ENVIRON_FOR_WRAPPERS = {}
64
65
Craig Tiller123f1372016-06-15 15:06:14 -070066_POLLING_STRATEGIES = {
Sree Kuchibhotlac3a9fae2016-06-21 16:31:08 -070067 'linux': ['epoll', 'poll', 'legacy']
Craig Tiller123f1372016-06-15 15:06:14 -070068}
69
70
Craig Tillerd50993d2015-08-05 08:04:36 -070071def platform_string():
Nicolas "Pixel" Noblef72d7b52015-12-03 03:07:43 +010072 return jobset.platform_string()
Craig Tillerd50993d2015-08-05 08:04:36 -070073
74
Craig Tiller738c3342015-01-12 14:28:33 -080075# SimpleConfig: just compile with CONFIG=config, and run the binary to test
Craig Tillera0f85172016-01-20 15:56:06 -080076class Config(object):
Craig Tillerb50d1662015-01-15 17:28:21 -080077
Craig Tillera0f85172016-01-20 15:56:06 -080078 def __init__(self, config, environ=None, timeout_multiplier=1, tool_prefix=[]):
murgatroid99132ce6a2015-03-04 17:29:14 -080079 if environ is None:
80 environ = {}
Craig Tiller738c3342015-01-12 14:28:33 -080081 self.build_config = config
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
Craig Tiller74189cd2016-06-23 15:39:06 -070087 def job_spec(self, cmdline, 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
Craig Tiller49f61322015-03-03 13:02:11 -080094 """
Craig Tiller4fc90032015-05-21 10:39:52 -070095 actual_environ = self.environ.copy()
96 for k, v in environ.iteritems():
97 actual_environ[k] = v
Craig Tillera0f85172016-01-20 15:56:06 -080098 return jobset.JobSpec(cmdline=self.tool_prefix + cmdline,
Jan Tattermusch9a7d30c2015-04-23 16:12:55 -070099 shortname=shortname,
Craig Tiller4fc90032015-05-21 10:39:52 -0700100 environ=actual_environ,
Craig Tiller56c6b6a2016-01-20 08:27:37 -0800101 cpu_cost=cpu_cost,
Craig Tiller94d04a52016-01-20 10:58:23 -0800102 timeout_seconds=(self.timeout_multiplier * timeout_seconds if timeout_seconds else None),
Craig Tillerde7edf82016-03-20 09:12:16 -0700103 flake_retries=5 if flaky or args.allow_flakes else 0,
Craig Tiller35505de2015-10-08 13:31:33 -0700104 timeout_retries=3 if args.allow_flakes else 0)
Craig Tiller738c3342015-01-12 14:28:33 -0800105
106
murgatroid99cf08daf2015-09-21 15:33:16 -0700107def get_c_tests(travis, test_lang) :
108 out = []
109 platforms_str = 'ci_platforms' if travis else 'platforms'
110 with open('tools/run_tests/tests.json') as f:
murgatroid9989899b12015-09-22 09:14:48 -0700111 js = json.load(f)
murgatroid99a3e244f2015-09-22 11:25:53 -0700112 return [tgt
113 for tgt in js
114 if tgt['language'] == test_lang and
115 platform_string() in tgt[platforms_str] and
116 not (travis and tgt['flaky'])]
murgatroid99cf08daf2015-09-21 15:33:16 -0700117
murgatroid99fafeeb32015-09-22 09:13:03 -0700118
Jan Tattermusch77db4322016-02-20 20:19:35 -0800119def _check_compiler(compiler, supported_compilers):
120 if compiler not in supported_compilers:
Jan Tattermuschb2531e22016-03-25 16:14:41 -0700121 raise Exception('Compiler %s not supported (on this platform).' % compiler)
122
123
124def _check_arch(arch, supported_archs):
125 if arch not in supported_archs:
126 raise Exception('Architecture %s not supported.' % arch)
Jan Tattermusch77db4322016-02-20 20:19:35 -0800127
128
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800129def _is_use_docker_child():
130 """Returns True if running running as a --use_docker child."""
131 return True if os.getenv('RUN_TESTS_COMMAND') else False
132
133
Craig Tillerc7449162015-01-16 14:42:10 -0800134class CLanguage(object):
135
Craig Tillere9c959d2015-01-18 10:23:26 -0800136 def __init__(self, make_target, test_lang):
Craig Tillerc7449162015-01-16 14:42:10 -0800137 self.make_target = make_target
Craig Tillerd50993d2015-08-05 08:04:36 -0700138 self.platform = platform_string()
Craig Tiller711bbe62015-08-19 12:35:16 -0700139 self.test_lang = test_lang
Craig Tillerc7449162015-01-16 14:42:10 -0800140
Jan Tattermusch77db4322016-02-20 20:19:35 -0800141 def configure(self, config, args):
142 self.config = config
143 self.args = args
144 if self.platform == 'windows':
Jan Tattermuschc96caf82016-02-22 17:31:02 -0800145 self._make_options = [_windows_toolset_option(self.args.compiler),
146 _windows_arch_option(self.args.arch)]
Jan Tattermusch77db4322016-02-20 20:19:35 -0800147 else:
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800148 self._docker_distro, self._make_options = self._compiler_options(self.args.use_docker,
149 self.args.compiler)
Jan Tattermusch77db4322016-02-20 20:19:35 -0800150
151 def test_specs(self):
Craig Tiller547db2b2015-01-30 14:08:39 -0800152 out = []
Jan Tattermusch77db4322016-02-20 20:19:35 -0800153 binaries = get_c_tests(self.args.travis, self.test_lang)
Craig Tiller946ce7a2016-04-06 10:35:58 -0700154 for target in binaries:
Craig Tiller123f1372016-06-15 15:06:14 -0700155 polling_strategies = (_POLLING_STRATEGIES.get(self.platform, ['all'])
Craig Tiller946ce7a2016-04-06 10:35:58 -0700156 if target.get('uses_polling', True)
157 else ['all'])
158 for polling_strategy in polling_strategies:
159 env={'GRPC_DEFAULT_SSL_ROOTS_FILE_PATH':
160 _ROOT + '/src/core/lib/tsi/test_creds/ca.pem',
Craig Tillered735102016-04-06 12:59:23 -0700161 'GRPC_POLL_STRATEGY': polling_strategy}
Craig Tiller946ce7a2016-04-06 10:35:58 -0700162 shortname_ext = '' if polling_strategy=='all' else ' polling=%s' % polling_strategy
Craig Tillerb38197e2016-02-26 10:14:54 -0800163 if self.config.build_config in target['exclude_configs']:
164 continue
165 if self.platform == 'windows':
166 binary = 'vsprojects/%s%s/%s.exe' % (
167 'x64/' if self.args.arch == 'x64' else '',
168 _MSBUILD_CONFIG[self.config.build_config],
169 target['name'])
Craig Tillerca62ff02016-02-24 22:22:57 -0800170 else:
Craig Tillerb38197e2016-02-26 10:14:54 -0800171 binary = 'bins/%s/%s' % (self.config.build_config, target['name'])
172 if os.path.isfile(binary):
173 if 'gtest' in target and target['gtest']:
174 # here we parse the output of --gtest_list_tests to build up a
175 # complete list of the tests contained in a binary
176 # for each test, we then add a job to run, filtering for just that
177 # test
178 with open(os.devnull, 'w') as fnull:
179 tests = subprocess.check_output([binary, '--gtest_list_tests'],
180 stderr=fnull)
181 base = None
182 for line in tests.split('\n'):
183 i = line.find('#')
184 if i >= 0: line = line[:i]
185 if not line: continue
186 if line[0] != ' ':
187 base = line.strip()
188 else:
189 assert base is not None
190 assert line[1] == ' '
191 test = base + line.strip()
192 cmdline = [binary] + ['--gtest_filter=%s' % test]
193 out.append(self.config.job_spec(cmdline, [binary],
Craig Tiller334db352016-02-26 15:19:49 -0800194 shortname='%s:%s %s' % (binary, test, shortname_ext),
Craig Tillerb38197e2016-02-26 10:14:54 -0800195 cpu_cost=target['cpu_cost'],
196 environ=env))
197 else:
198 cmdline = [binary] + target['args']
199 out.append(self.config.job_spec(cmdline, [binary],
200 shortname=' '.join(cmdline) + shortname_ext,
201 cpu_cost=target['cpu_cost'],
Craig Tillerc2278152016-03-21 08:59:54 -0700202 flaky=target.get('flaky', False),
Craig Tillerb38197e2016-02-26 10:14:54 -0800203 environ=env))
204 elif self.args.regex == '.*' or self.platform == 'windows':
205 print '\nWARNING: binary not found, skipping', binary
Nicolas Noblee1445362015-05-11 17:40:26 -0700206 return sorted(out)
Craig Tillerc7449162015-01-16 14:42:10 -0800207
Jan Tattermusch77db4322016-02-20 20:19:35 -0800208 def make_targets(self):
209 test_regex = self.args.regex
210 if self.platform != 'windows' and self.args.regex != '.*':
Craig Tiller883064c2015-11-04 10:06:10 -0800211 # use the regex to minimize the number of things to build
Craig Tillerb0f275e2016-01-27 10:45:50 -0800212 return [os.path.basename(target['name'])
Craig Tiller883064c2015-11-04 10:06:10 -0800213 for target in get_c_tests(False, self.test_lang)
Craig Tillerb0f275e2016-01-27 10:45:50 -0800214 if re.search(test_regex, '/' + target['name'])]
Jan Tattermusch77db4322016-02-20 20:19:35 -0800215 if self.platform == 'windows':
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700216 # don't build tools on windows just yet
217 return ['buildtests_%s' % self.make_target]
Craig Tiller7552f0f2015-06-19 17:46:20 -0700218 return ['buildtests_%s' % self.make_target, 'tools_%s' % self.make_target]
Craig Tillerc7449162015-01-16 14:42:10 -0800219
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800220 def make_options(self):
Jan Tattermuschc96caf82016-02-22 17:31:02 -0800221 return self._make_options;
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800222
murgatroid99256d3df2015-09-21 16:58:02 -0700223 def pre_build_steps(self):
Jan Tattermusch874aec02015-10-07 19:26:19 -0700224 if self.platform == 'windows':
225 return [['tools\\run_tests\\pre_build_c.bat']]
226 else:
227 return []
murgatroid99256d3df2015-09-21 16:58:02 -0700228
Craig Tillerc7449162015-01-16 14:42:10 -0800229 def build_steps(self):
230 return []
231
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200232 def post_tests_steps(self):
233 if self.platform == 'windows':
234 return []
235 else:
236 return [['tools/run_tests/post_tests_c.sh']]
237
murgatroid99a3e244f2015-09-22 11:25:53 -0700238 def makefile_name(self):
239 return 'Makefile'
240
Jan Tattermusch6d258c52016-06-10 09:36:51 -0700241 def _clang_make_options(self, version_suffix=''):
242 return ['CC=clang%s' % version_suffix,
243 'CXX=clang++%s' % version_suffix,
244 'LD=clang%s' % version_suffix,
245 'LDXX=clang++%s' % version_suffix]
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800246
Jan Tattermusch6d258c52016-06-10 09:36:51 -0700247 def _gcc_make_options(self, version_suffix):
248 return ['CC=gcc%s' % version_suffix,
249 'CXX=g++%s' % version_suffix,
250 'LD=gcc%s' % version_suffix,
251 'LDXX=g++%s' % version_suffix]
Jan Tattermusch9bb70622016-03-18 10:28:54 -0700252
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800253 def _compiler_options(self, use_docker, compiler):
254 """Returns docker distro and make options to use for given compiler."""
Jan Tattermuschfd3857b2016-06-03 12:24:03 -0700255 if not use_docker and not _is_use_docker_child():
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800256 _check_compiler(compiler, ['default'])
257
258 if compiler == 'gcc4.9' or compiler == 'default':
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800259 return ('jessie', [])
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800260 elif compiler == 'gcc4.4':
Jan Tattermusch6d258c52016-06-10 09:36:51 -0700261 return ('wheezy', self._gcc_make_options(version_suffix='-4.4'))
262 elif compiler == 'gcc4.6':
263 return ('wheezy', self._gcc_make_options(version_suffix='-4.6'))
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800264 elif compiler == 'gcc5.3':
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800265 return ('ubuntu1604', [])
266 elif compiler == 'clang3.4':
Jan Tattermusch6d258c52016-06-10 09:36:51 -0700267 # on ubuntu1404, clang-3.4 alias doesn't exist, just use 'clang'
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800268 return ('ubuntu1404', self._clang_make_options())
Jan Tattermusch6d258c52016-06-10 09:36:51 -0700269 elif compiler == 'clang3.5':
270 return ('jessie', self._clang_make_options(version_suffix='-3.5'))
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800271 elif compiler == 'clang3.6':
Jan Tattermusch6d258c52016-06-10 09:36:51 -0700272 return ('ubuntu1604', self._clang_make_options(version_suffix='-3.6'))
273 elif compiler == 'clang3.7':
274 return ('ubuntu1604', self._clang_make_options(version_suffix='-3.7'))
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800275 else:
276 raise Exception('Compiler %s not supported.' % compiler)
277
Jan Tattermusch77db4322016-02-20 20:19:35 -0800278 def dockerfile_dir(self):
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800279 return 'tools/dockerfile/test/cxx_%s_%s' % (self._docker_distro,
280 _docker_arch_suffix(self.args.arch))
Jan Tattermusch788ee232016-01-26 12:19:44 -0800281
murgatroid99132ce6a2015-03-04 17:29:14 -0800282 def __str__(self):
283 return self.make_target
284
Craig Tillercc0535d2015-12-08 15:14:47 -0800285
murgatroid992c8d5162015-01-26 10:41:21 -0800286class NodeLanguage(object):
287
Jan Tattermusche477b842016-02-06 22:19:01 -0800288 def __init__(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800289 self.platform = platform_string()
Jan Tattermusche477b842016-02-06 22:19:01 -0800290
Jan Tattermusch77db4322016-02-20 20:19:35 -0800291 def configure(self, config, args):
292 self.config = config
293 self.args = args
murgatroid999fab4382016-04-29 15:05:00 -0700294 _check_compiler(self.args.compiler, ['default', 'node0.12',
295 'node4', 'node5'])
296 if self.args.compiler == 'default':
297 self.node_version = '4'
298 else:
299 # Take off the word "node"
300 self.node_version = self.args.compiler[4:]
Jan Tattermusch77db4322016-02-20 20:19:35 -0800301
302 def test_specs(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800303 if self.platform == 'windows':
Jan Tattermusch77db4322016-02-20 20:19:35 -0800304 return [self.config.job_spec(['tools\\run_tests\\run_node.bat'], None)]
Michael Lumishaaa876a2016-02-10 15:27:58 -0800305 else:
Jan Tattermusch77db4322016-02-20 20:19:35 -0800306 return [self.config.job_spec(['tools/run_tests/run_node.sh', self.node_version],
307 None,
308 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
murgatroid992c8d5162015-01-26 10:41:21 -0800309
murgatroid99256d3df2015-09-21 16:58:02 -0700310 def pre_build_steps(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800311 if self.platform == 'windows':
312 return [['tools\\run_tests\\pre_build_node.bat']]
313 else:
314 return [['tools/run_tests/pre_build_node.sh', self.node_version]]
murgatroid99256d3df2015-09-21 16:58:02 -0700315
Jan Tattermusch77db4322016-02-20 20:19:35 -0800316 def make_targets(self):
murgatroid99db5b1602015-10-01 13:20:11 -0700317 return []
murgatroid992c8d5162015-01-26 10:41:21 -0800318
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800319 def make_options(self):
320 return []
321
murgatroid992c8d5162015-01-26 10:41:21 -0800322 def build_steps(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800323 if self.platform == 'windows':
324 return [['tools\\run_tests\\build_node.bat']]
325 else:
326 return [['tools/run_tests/build_node.sh', self.node_version]]
Craig Tillerc7449162015-01-16 14:42:10 -0800327
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200328 def post_tests_steps(self):
329 return []
330
murgatroid99a3e244f2015-09-22 11:25:53 -0700331 def makefile_name(self):
332 return 'Makefile'
333
Jan Tattermusch77db4322016-02-20 20:19:35 -0800334 def dockerfile_dir(self):
335 return 'tools/dockerfile/test/node_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800336
murgatroid99132ce6a2015-03-04 17:29:14 -0800337 def __str__(self):
338 return 'node'
339
Craig Tiller99775822015-01-30 13:07:16 -0800340
Craig Tillerc7449162015-01-16 14:42:10 -0800341class PhpLanguage(object):
342
Jan Tattermusch77db4322016-02-20 20:19:35 -0800343 def configure(self, config, args):
344 self.config = config
345 self.args = args
346 _check_compiler(self.args.compiler, ['default'])
347
348 def test_specs(self):
349 return [self.config.job_spec(['src/php/bin/run_tests.sh'], None,
350 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
Craig Tillerc7449162015-01-16 14:42:10 -0800351
murgatroid99256d3df2015-09-21 16:58:02 -0700352 def pre_build_steps(self):
353 return []
354
Jan Tattermusch77db4322016-02-20 20:19:35 -0800355 def make_targets(self):
Craig Tilleraf7cf542015-05-22 10:07:34 -0700356 return ['static_c', 'shared_c']
Craig Tillerc7449162015-01-16 14:42:10 -0800357
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800358 def make_options(self):
359 return []
360
Craig Tillerc7449162015-01-16 14:42:10 -0800361 def build_steps(self):
362 return [['tools/run_tests/build_php.sh']]
363
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200364 def post_tests_steps(self):
Stanley Cheunga6b95482016-01-13 16:10:48 -0800365 return [['tools/run_tests/post_tests_php.sh']]
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200366
murgatroid99a3e244f2015-09-22 11:25:53 -0700367 def makefile_name(self):
368 return 'Makefile'
369
Jan Tattermusch77db4322016-02-20 20:19:35 -0800370 def dockerfile_dir(self):
371 return 'tools/dockerfile/test/php_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800372
murgatroid99132ce6a2015-03-04 17:29:14 -0800373 def __str__(self):
374 return 'php'
375
Craig Tillerc7449162015-01-16 14:42:10 -0800376
Masood Malekghassemi3b5b2062016-06-02 20:27:20 -0700377class PythonConfig(collections.namedtuple('PythonConfig', [
378 'python', 'venv', 'venv_relative_python', 'toolchain',])):
379
380 @property
381 def venv_python(self):
382 return os.path.abspath('{}/{}'.format(self.venv, self.venv_relative_python))
383
384
Nathaniel Manista840615e2015-01-22 20:31:47 +0000385class PythonLanguage(object):
386
Jan Tattermusch77db4322016-02-20 20:19:35 -0800387 def configure(self, config, args):
388 self.config = config
389 self.args = args
Masood Malekghassemi3b5b2062016-06-02 20:27:20 -0700390 self.pythons = self._get_pythons(self.args.compiler)
Jan Tattermusch77db4322016-02-20 20:19:35 -0800391
392 def test_specs(self):
Jan Tattermusch072ebaa2016-03-01 18:33:12 -0800393 # load list of known test suites
Masood Malekghassemi1ff429d2016-06-02 16:39:20 -0700394 with open('src/python/grpcio_tests/tests/tests.json') as tests_json_file:
Jan Tattermusch072ebaa2016-03-01 18:33:12 -0800395 tests_json = json.load(tests_json_file)
Masood Malekghassemi2b841622015-07-28 17:39:02 -0700396 environment = dict(_FORCE_ENVIRON_FOR_WRAPPERS)
Masood Malekghassemi1c062bd2016-06-13 18:41:36 -0700397 return [self.config.job_spec(
398 ['tools/run_tests/run_python.sh', config.venv_python],
399 None,
400 environ=dict(environment.items() +
401 [('GRPC_PYTHON_TESTRUNNER_FILTER', suite_name)]),
402 shortname='%s.test.%s' % (config.venv, suite_name),
403 timeout_seconds=5*60)
404 for suite_name in tests_json
405 for config in self.pythons]
Jan Tattermusch072ebaa2016-03-01 18:33:12 -0800406
Nathaniel Manista840615e2015-01-22 20:31:47 +0000407
murgatroid99256d3df2015-09-21 16:58:02 -0700408 def pre_build_steps(self):
409 return []
410
Jan Tattermusch77db4322016-02-20 20:19:35 -0800411 def make_targets(self):
Masood Malekghassemi3b5b2062016-06-02 20:27:20 -0700412 return []
Nathaniel Manista840615e2015-01-22 20:31:47 +0000413
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800414 def make_options(self):
415 return []
416
Nathaniel Manista840615e2015-01-22 20:31:47 +0000417 def build_steps(self):
Masood Malekghassemi3b5b2062016-06-02 20:27:20 -0700418 return [
419 [
420 'tools/run_tests/build_python.sh',
421 config.python, config.venv,
422 config.venv_relative_python, config.toolchain
423 ]
424 for config in self.pythons
425 ]
Nathaniel Manista840615e2015-01-22 20:31:47 +0000426
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200427 def post_tests_steps(self):
428 return []
429
murgatroid99a3e244f2015-09-22 11:25:53 -0700430 def makefile_name(self):
431 return 'Makefile'
432
Jan Tattermusch77db4322016-02-20 20:19:35 -0800433 def dockerfile_dir(self):
434 return 'tools/dockerfile/test/python_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800435
Masood Malekghassemi3b5b2062016-06-02 20:27:20 -0700436 def _get_pythons(self, compiler):
437 if os.name == 'nt':
438 venv_relative_python = 'Scripts/python.exe'
439 toolchain = 'mingw32'
440 else:
441 venv_relative_python = 'bin/python'
442 toolchain = 'unix'
443 python27_config = PythonConfig('python2.7', 'py27', venv_relative_python, toolchain)
444 python34_config = PythonConfig('python3.4', 'py34', venv_relative_python, toolchain)
Ken Payson1efb6012016-06-08 13:06:44 -0700445 if compiler == 'default':
Masood Malekghassemi3b5b2062016-06-02 20:27:20 -0700446 return (python27_config, python34_config,)
Ken Payson1efb6012016-06-08 13:06:44 -0700447 elif compiler == 'python2.7':
Masood Malekghassemi3b5b2062016-06-02 20:27:20 -0700448 return (python27_config,)
Jan Tattermusch825471c2016-04-25 16:52:25 -0700449 elif compiler == 'python3.4':
Masood Malekghassemi3b5b2062016-06-02 20:27:20 -0700450 return (python34_config,)
Jan Tattermusch825471c2016-04-25 16:52:25 -0700451 else:
452 raise Exception('Compiler %s not supported.' % compiler)
453
murgatroid99132ce6a2015-03-04 17:29:14 -0800454 def __str__(self):
455 return 'python'
456
Craig Tillerd625d812015-04-08 15:52:35 -0700457
murgatroid996a4c4fa2015-02-27 12:08:57 -0800458class RubyLanguage(object):
459
Jan Tattermusch77db4322016-02-20 20:19:35 -0800460 def configure(self, config, args):
461 self.config = config
462 self.args = args
463 _check_compiler(self.args.compiler, ['default'])
464
465 def test_specs(self):
Craig Tillereb5e4372016-06-23 16:16:10 -0700466 return [self.config.job_spec(['tools/run_tests/run_ruby.sh'],
Jan Tattermusch77db4322016-02-20 20:19:35 -0800467 timeout_seconds=10*60,
468 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
murgatroid996a4c4fa2015-02-27 12:08:57 -0800469
murgatroid99256d3df2015-09-21 16:58:02 -0700470 def pre_build_steps(self):
Nicolas "Pixel" Noblebcf988f2015-10-08 03:00:42 +0200471 return [['tools/run_tests/pre_build_ruby.sh']]
murgatroid99256d3df2015-09-21 16:58:02 -0700472
Jan Tattermusch4651bef2016-02-23 08:31:25 -0800473 def make_targets(self):
murgatroid997d243df2016-02-18 09:58:05 -0800474 return []
murgatroid996a4c4fa2015-02-27 12:08:57 -0800475
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800476 def make_options(self):
477 return []
478
murgatroid996a4c4fa2015-02-27 12:08:57 -0800479 def build_steps(self):
480 return [['tools/run_tests/build_ruby.sh']]
481
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200482 def post_tests_steps(self):
Nicolas "Pixel" Noble7ef1e532015-12-02 00:55:33 +0100483 return [['tools/run_tests/post_tests_ruby.sh']]
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200484
murgatroid99a3e244f2015-09-22 11:25:53 -0700485 def makefile_name(self):
486 return 'Makefile'
487
Jan Tattermusch77db4322016-02-20 20:19:35 -0800488 def dockerfile_dir(self):
489 return 'tools/dockerfile/test/ruby_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800490
murgatroid99132ce6a2015-03-04 17:29:14 -0800491 def __str__(self):
492 return 'ruby'
493
Craig Tillerd625d812015-04-08 15:52:35 -0700494
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800495class CSharpLanguage(object):
Jan Tattermusch77db4322016-02-20 20:19:35 -0800496
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700497 def __init__(self):
Craig Tillerd50993d2015-08-05 08:04:36 -0700498 self.platform = platform_string()
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700499
Jan Tattermusch77db4322016-02-20 20:19:35 -0800500 def configure(self, config, args):
501 self.config = config
502 self.args = args
Jan Tattermusch6d28d352016-03-25 15:07:22 -0700503 if self.platform == 'windows':
Jan Tattermuschb2531e22016-03-25 16:14:41 -0700504 # Explicitly choosing between x86 and x64 arch doesn't work yet
505 _check_arch(self.args.arch, ['default'])
Jan Tattermusch6e2f88c2016-06-21 10:52:40 -0700506 # CoreCLR use 64bit runtime by default.
507 arch_option = 'x64' if self.args.compiler == 'coreclr' else self.args.arch
Jan Tattermusch6d28d352016-03-25 15:07:22 -0700508 self._make_options = [_windows_toolset_option(self.args.compiler),
Jan Tattermusch6e2f88c2016-06-21 10:52:40 -0700509 _windows_arch_option(arch_option)]
Jan Tattermusch6d28d352016-03-25 15:07:22 -0700510 else:
Jan Tattermuschbc98af12016-06-17 18:38:27 -0700511 _check_compiler(self.args.compiler, ['default', 'coreclr'])
512 if self.platform == 'linux' and self.args.compiler == 'coreclr':
513 self._docker_distro = 'coreclr'
Jan Tattermusch743decd2016-06-21 11:40:47 -0700514 else:
515 self._docker_distro = 'jessie'
Jan Tattermusch76511a52016-06-17 14:00:57 -0700516
Jan Tattermusch6d28d352016-03-25 15:07:22 -0700517 if self.platform == 'mac':
Jan Tattermusch2a322c22016-03-30 13:55:07 -0700518 # TODO(jtattermusch): EMBED_ZLIB=true currently breaks the mac build
Jan Tattermusch6d082202016-06-21 10:03:38 -0700519 self._make_options = ['EMBED_OPENSSL=true']
520 if self.args.compiler != 'coreclr':
521 # On Mac, official distribution of mono is 32bit.
522 self._make_options += ['CFLAGS=-m32', 'LDFLAGS=-m32']
Jan Tattermusch6d28d352016-03-25 15:07:22 -0700523 else:
524 self._make_options = ['EMBED_OPENSSL=true', 'EMBED_ZLIB=true']
Jan Tattermusch77db4322016-02-20 20:19:35 -0800525
526 def test_specs(self):
Jan Tattermusch03c01062015-12-11 14:28:56 -0800527 with open('src/csharp/tests.json') as f:
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700528 tests_by_assembly = json.load(f)
Jan Tattermusch03c01062015-12-11 14:28:56 -0800529
Jan Tattermuscha2d964c2016-02-22 17:33:09 -0800530 msbuild_config = _MSBUILD_CONFIG[self.config.build_config]
Jan Tattermuschbc98af12016-06-17 18:38:27 -0700531 nunit_args = ['--labels=All']
Jan Tattermusch76511a52016-06-17 14:00:57 -0700532 assembly_subdir = 'bin/%s' % msbuild_config
533 assembly_extension = '.exe'
534
535 if self.args.compiler == 'coreclr':
Jan Tattermusch64c137c2016-06-20 17:54:19 -0700536 if self.platform == 'linux':
537 assembly_subdir += '/netstandard1.5/debian.8-x64'
538 assembly_extension = ''
Jan Tattermusch14a301d2016-06-27 17:45:29 -0700539 elif self.platform == 'mac':
Jan Tattermusch6d082202016-06-21 10:03:38 -0700540 assembly_subdir += '/netstandard1.5/osx.10.11-x64'
541 assembly_extension = ''
Jan Tattermusch64c137c2016-06-20 17:54:19 -0700542 else:
543 assembly_subdir += '/netstandard1.5/win7-x64'
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700544 runtime_cmd = []
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700545 else:
Jan Tattermuschbc98af12016-06-17 18:38:27 -0700546 nunit_args += ['--noresult', '--workers=1']
547 if self.platform == 'windows':
548 runtime_cmd = []
549 else:
550 runtime_cmd = ['mono']
Jan Tattermuschbf3b1532015-10-26 10:24:42 -0700551
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700552 specs = []
553 for assembly in tests_by_assembly.iterkeys():
Jan Tattermusch76511a52016-06-17 14:00:57 -0700554 assembly_file = 'src/csharp/%s/%s/%s%s' % (assembly,
555 assembly_subdir,
556 assembly,
557 assembly_extension)
Jan Tattermuscha5f1f122016-04-11 15:49:56 -0700558 if self.config.build_config != 'gcov' or self.platform != 'windows':
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700559 # normally, run each test as a separate process
560 for test in tests_by_assembly[assembly]:
561 cmdline = runtime_cmd + [assembly_file, '--test=%s' % test] + nunit_args
562 specs.append(self.config.job_spec(cmdline,
563 None,
564 shortname='csharp.%s' % test,
565 environ=_FORCE_ENVIRON_FOR_WRAPPERS))
566 else:
Jan Tattermuscha5f1f122016-04-11 15:49:56 -0700567 # For C# test coverage, run all tests from the same assembly at once
568 # using OpenCover.Console (only works on Windows).
569 cmdline = ['src\\csharp\\packages\\OpenCover.4.6.519\\tools\\OpenCover.Console.exe',
570 '-target:%s' % assembly_file,
571 '-targetdir:src\\csharp',
572 '-targetargs:%s' % ' '.join(nunit_args),
573 '-filter:+[Grpc.Core]*',
574 '-register:user',
575 '-output:src\\csharp\\coverage_csharp_%s.xml' % assembly]
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700576
Jan Tattermuscha5f1f122016-04-11 15:49:56 -0700577 # set really high cpu_cost to make sure instances of OpenCover.Console run exclusively
578 # to prevent problems with registering the profiler.
579 run_exclusive = 1000000
Jan Tattermusch35e608f2016-04-09 16:35:06 -0700580 specs.append(self.config.job_spec(cmdline,
581 None,
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700582 shortname='csharp.coverage.%s' % assembly,
Jan Tattermuscha5f1f122016-04-11 15:49:56 -0700583 cpu_cost=run_exclusive,
Jan Tattermusch77db4322016-02-20 20:19:35 -0800584 environ=_FORCE_ENVIRON_FOR_WRAPPERS))
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700585 return specs
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800586
murgatroid99256d3df2015-09-21 16:58:02 -0700587 def pre_build_steps(self):
Jan Tattermusch48423fc2015-10-07 18:59:16 -0700588 if self.platform == 'windows':
Jan Tattermusch874aec02015-10-07 19:26:19 -0700589 return [['tools\\run_tests\\pre_build_csharp.bat']]
Jan Tattermusch48423fc2015-10-07 18:59:16 -0700590 else:
591 return [['tools/run_tests/pre_build_csharp.sh']]
murgatroid99256d3df2015-09-21 16:58:02 -0700592
Jan Tattermusch77db4322016-02-20 20:19:35 -0800593 def make_targets(self):
Jan Tattermusch6d28d352016-03-25 15:07:22 -0700594 return ['grpc_csharp_ext']
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800595
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800596 def make_options(self):
Jan Tattermusch6d28d352016-03-25 15:07:22 -0700597 return self._make_options;
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800598
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800599 def build_steps(self):
Jan Tattermusch76511a52016-06-17 14:00:57 -0700600 if self.args.compiler == 'coreclr':
Jan Tattermuschbc98af12016-06-17 18:38:27 -0700601 if self.platform == 'windows':
602 return [['tools\\run_tests\\build_csharp_coreclr.bat']]
603 else:
604 return [['tools/run_tests/build_csharp_coreclr.sh']]
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700605 else:
Jan Tattermusch76511a52016-06-17 14:00:57 -0700606 if self.platform == 'windows':
607 return [[_windows_build_bat(self.args.compiler),
608 'src/csharp/Grpc.sln',
609 '/p:Configuration=%s' % _MSBUILD_CONFIG[self.config.build_config]]]
610 else:
611 return [['tools/run_tests/build_csharp.sh']]
Nathaniel Manista840615e2015-01-22 20:31:47 +0000612
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200613 def post_tests_steps(self):
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700614 if self.platform == 'windows':
615 return [['tools\\run_tests\\post_tests_csharp.bat']]
616 else:
617 return [['tools/run_tests/post_tests_csharp.sh']]
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200618
murgatroid99a3e244f2015-09-22 11:25:53 -0700619 def makefile_name(self):
620 return 'Makefile'
621
Jan Tattermusch77db4322016-02-20 20:19:35 -0800622 def dockerfile_dir(self):
Jan Tattermusch76511a52016-06-17 14:00:57 -0700623 return 'tools/dockerfile/test/csharp_%s_%s' % (self._docker_distro,
624 _docker_arch_suffix(self.args.arch))
Jan Tattermusch788ee232016-01-26 12:19:44 -0800625
murgatroid99132ce6a2015-03-04 17:29:14 -0800626 def __str__(self):
627 return 'csharp'
628
Craig Tillerd625d812015-04-08 15:52:35 -0700629
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700630class ObjCLanguage(object):
631
Jan Tattermusch77db4322016-02-20 20:19:35 -0800632 def configure(self, config, args):
633 self.config = config
634 self.args = args
635 _check_compiler(self.args.compiler, ['default'])
636
637 def test_specs(self):
638 return [self.config.job_spec(['src/objective-c/tests/run_tests.sh'], None,
Yuchen Zengcaca0a12016-06-21 23:07:49 -0700639 environ=_FORCE_ENVIRON_FOR_WRAPPERS),
Yuchen Zengf95a4892016-06-21 23:27:46 -0700640 self.config.job_spec(['src/objective-c/tests/build_example_test.sh'],
Yuchen Zeng82393ef2016-06-22 10:29:17 -0700641 None, timeout_seconds=15*60,
Yuchen Zengc0668c82016-06-22 01:30:47 -0700642 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700643
murgatroid99256d3df2015-09-21 16:58:02 -0700644 def pre_build_steps(self):
645 return []
646
Jan Tattermusch77db4322016-02-20 20:19:35 -0800647 def make_targets(self):
Jorge Canizalesd0b32e92015-07-30 23:08:43 -0700648 return ['grpc_objective_c_plugin', 'interop_server']
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700649
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800650 def make_options(self):
651 return []
652
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700653 def build_steps(self):
Jorge Canizalesd0b32e92015-07-30 23:08:43 -0700654 return [['src/objective-c/tests/build_tests.sh']]
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700655
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200656 def post_tests_steps(self):
657 return []
658
murgatroid99a3e244f2015-09-22 11:25:53 -0700659 def makefile_name(self):
660 return 'Makefile'
661
Jan Tattermusch77db4322016-02-20 20:19:35 -0800662 def dockerfile_dir(self):
Jan Tattermusch788ee232016-01-26 12:19:44 -0800663 return None
664
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700665 def __str__(self):
666 return 'objc'
667
668
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100669class Sanity(object):
670
Jan Tattermusch77db4322016-02-20 20:19:35 -0800671 def configure(self, config, args):
672 self.config = config
673 self.args = args
674 _check_compiler(self.args.compiler, ['default'])
675
676 def test_specs(self):
Craig Tiller94d04a52016-01-20 10:58:23 -0800677 import yaml
Jan Tattermusch788ee232016-01-26 12:19:44 -0800678 with open('tools/run_tests/sanity/sanity_tests.yaml', 'r') as f:
Craig Tiller34226af2016-06-24 16:46:25 -0700679 return [self.config.job_spec(cmd['script'].split(),
Jan Tattermusch77db4322016-02-20 20:19:35 -0800680 timeout_seconds=None, environ={'TEST': 'true'},
681 cpu_cost=cmd.get('cpu_cost', 1))
Craig Tiller94d04a52016-01-20 10:58:23 -0800682 for cmd in yaml.load(f)]
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100683
murgatroid99256d3df2015-09-21 16:58:02 -0700684 def pre_build_steps(self):
685 return []
686
Jan Tattermusch77db4322016-02-20 20:19:35 -0800687 def make_targets(self):
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100688 return ['run_dep_checks']
689
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800690 def make_options(self):
691 return []
692
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100693 def build_steps(self):
694 return []
695
Nicolas "Pixel" Noble87879b32015-10-12 23:28:53 +0200696 def post_tests_steps(self):
697 return []
698
murgatroid99a3e244f2015-09-22 11:25:53 -0700699 def makefile_name(self):
700 return 'Makefile'
701
Jan Tattermusch77db4322016-02-20 20:19:35 -0800702 def dockerfile_dir(self):
Jan Tattermusche70b3c52016-02-07 20:21:02 -0800703 return 'tools/dockerfile/test/sanity'
Jan Tattermusch788ee232016-01-26 12:19:44 -0800704
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100705 def __str__(self):
706 return 'sanity'
707
Nicolas "Pixel" Noblee55cd7f2015-04-14 17:59:13 +0200708
Craig Tiller738c3342015-01-12 14:28:33 -0800709# different configurations we can run under
Craig Tillera0f85172016-01-20 15:56:06 -0800710with open('tools/run_tests/configs.json') as f:
Craig Tiller1dce9062016-01-20 17:01:56 -0800711 _CONFIGS = dict((cfg['config'], Config(**cfg)) for cfg in ast.literal_eval(f.read()))
Craig Tiller738c3342015-01-12 14:28:33 -0800712
713
Craig Tillerc7449162015-01-16 14:42:10 -0800714_LANGUAGES = {
Craig Tillere9c959d2015-01-18 10:23:26 -0800715 'c++': CLanguage('cxx', 'c++'),
716 'c': CLanguage('c', 'c'),
murgatroid992c8d5162015-01-26 10:41:21 -0800717 'node': NodeLanguage(),
Nathaniel Manista840615e2015-01-22 20:31:47 +0000718 'php': PhpLanguage(),
719 'python': PythonLanguage(),
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800720 'ruby': RubyLanguage(),
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100721 'csharp': CSharpLanguage(),
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700722 'objc' : ObjCLanguage(),
Jan Tattermusch70a57e42016-02-20 18:50:27 -0800723 'sanity': Sanity()
Craig Tillereb272bc2015-01-30 13:13:14 -0800724 }
Nicolas Nobleddef2462015-01-06 18:08:25 -0800725
Jan Tattermusch77db4322016-02-20 20:19:35 -0800726
Jan Tattermuscha2d964c2016-02-22 17:33:09 -0800727_MSBUILD_CONFIG = {
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700728 'dbg': 'Debug',
729 'opt': 'Release',
Jan Tattermusche4a69182015-12-15 09:53:01 -0800730 'gcov': 'Debug',
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700731 }
732
David Garcia Quintase90cd372015-05-31 18:15:26 -0700733
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800734def _windows_arch_option(arch):
735 """Returns msbuild cmdline option for selected architecture."""
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800736 if arch == 'default' or arch == 'x86':
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800737 return '/p:Platform=Win32'
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800738 elif arch == 'x64':
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800739 return '/p:Platform=x64'
740 else:
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800741 print 'Architecture %s not supported.' % arch
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800742 sys.exit(1)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800743
Jan Tattermuschf08018a2016-01-26 08:22:09 -0800744
745def _check_arch_option(arch):
746 """Checks that architecture option is valid."""
747 if platform_string() == 'windows':
748 _windows_arch_option(arch)
749 elif platform_string() == 'linux':
750 # On linux, we need to be running under docker with the right architecture.
Jan Tattermusch07fb0422016-01-26 10:46:56 -0800751 runtime_arch = platform.architecture()[0]
Jan Tattermuschf08018a2016-01-26 08:22:09 -0800752 if arch == 'default':
753 return
754 elif runtime_arch == '64bit' and arch == 'x64':
755 return
756 elif runtime_arch == '32bit' and arch == 'x86':
757 return
758 else:
759 print 'Architecture %s does not match current runtime architecture.' % arch
760 sys.exit(1)
761 else:
762 if args.arch != 'default':
763 print 'Architecture %s not supported on current platform.' % args.arch
764 sys.exit(1)
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800765
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800766
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800767def _windows_build_bat(compiler):
768 """Returns name of build.bat for selected compiler."""
Jan Tattermuschbc98af12016-06-17 18:38:27 -0700769 # For CoreCLR, fall back to the default compiler for C core
770 if compiler == 'default' or compiler == 'vs2013' or compiler == 'coreclr':
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800771 return 'vsprojects\\build_vs2013.bat'
772 elif compiler == 'vs2015':
773 return 'vsprojects\\build_vs2015.bat'
774 elif compiler == 'vs2010':
775 return 'vsprojects\\build_vs2010.bat'
776 else:
777 print 'Compiler %s not supported.' % compiler
778 sys.exit(1)
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800779
780
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800781def _windows_toolset_option(compiler):
782 """Returns msbuild PlatformToolset for selected compiler."""
Jan Tattermuschbc98af12016-06-17 18:38:27 -0700783 # For CoreCLR, fall back to the default compiler for C core
784 if compiler == 'default' or compiler == 'vs2013' or compiler == 'coreclr':
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800785 return '/p:PlatformToolset=v120'
786 elif compiler == 'vs2015':
787 return '/p:PlatformToolset=v140'
788 elif compiler == 'vs2010':
789 return '/p:PlatformToolset=v100'
790 else:
791 print 'Compiler %s not supported.' % compiler
792 sys.exit(1)
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800793
794
Jan Tattermusche70b3c52016-02-07 20:21:02 -0800795def _docker_arch_suffix(arch):
796 """Returns suffix to dockerfile dir to use."""
797 if arch == 'default' or arch == 'x64':
798 return 'x64'
799 elif arch == 'x86':
800 return 'x86'
801 else:
802 print 'Architecture %s not supported with current settings.' % arch
803 sys.exit(1)
804
805
David Garcia Quintase90cd372015-05-31 18:15:26 -0700806def runs_per_test_type(arg_str):
807 """Auxilary function to parse the "runs_per_test" flag.
808
809 Returns:
810 A positive integer or 0, the latter indicating an infinite number of
811 runs.
812
813 Raises:
814 argparse.ArgumentTypeError: Upon invalid input.
815 """
816 if arg_str == 'inf':
817 return 0
818 try:
819 n = int(arg_str)
820 if n <= 0: raise ValueError
Craig Tiller50e53e22015-06-01 20:18:21 -0700821 return n
David Garcia Quintase90cd372015-05-31 18:15:26 -0700822 except:
Adele Zhoue4c35612015-10-16 15:34:23 -0700823 msg = '\'{}\' is not a positive integer or \'inf\''.format(arg_str)
David Garcia Quintase90cd372015-05-31 18:15:26 -0700824 raise argparse.ArgumentTypeError(msg)
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700825
826# parse command line
827argp = argparse.ArgumentParser(description='Run grpc tests.')
828argp.add_argument('-c', '--config',
Jan Tattermusch77db4322016-02-20 20:19:35 -0800829 choices=sorted(_CONFIGS.keys()),
830 default='opt')
David Garcia Quintase90cd372015-05-31 18:15:26 -0700831argp.add_argument('-n', '--runs_per_test', default=1, type=runs_per_test_type,
832 help='A positive integer or "inf". If "inf", all tests will run in an '
833 'infinite loop. Especially useful in combination with "-f"')
Craig Tillerfe406ec2015-02-24 13:55:12 -0800834argp.add_argument('-r', '--regex', default='.*', type=str)
Vijay Pai488fd0e2016-06-13 12:37:12 -0700835argp.add_argument('--regex_exclude', default='', type=str)
Craig Tiller5f735a62016-01-20 09:31:15 -0800836argp.add_argument('-j', '--jobs', default=multiprocessing.cpu_count(), type=int)
Craig Tiller8451e872015-02-27 09:25:51 -0800837argp.add_argument('-s', '--slowdown', default=1.0, type=float)
ctiller3040cb72015-01-07 12:13:17 -0800838argp.add_argument('-f', '--forever',
839 default=False,
840 action='store_const',
841 const=True)
Nicolas "Pixel" Noblea7df3f92015-02-26 22:07:04 +0100842argp.add_argument('-t', '--travis',
843 default=False,
844 action='store_const',
845 const=True)
Nicolas Noble044db742015-01-14 16:57:24 -0800846argp.add_argument('--newline_on_success',
847 default=False,
848 action='store_const',
849 const=True)
Craig Tiller686fb262015-01-15 07:39:09 -0800850argp.add_argument('-l', '--language',
Craig Tiller60f15e62015-05-13 09:05:17 -0700851 choices=['all'] + sorted(_LANGUAGES.keys()),
Craig Tiller686fb262015-01-15 07:39:09 -0800852 nargs='+',
Craig Tiller60f15e62015-05-13 09:05:17 -0700853 default=['all'])
Craig Tillercd43da82015-05-29 08:41:29 -0700854argp.add_argument('-S', '--stop_on_failure',
855 default=False,
856 action='store_const',
857 const=True)
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700858argp.add_argument('--use_docker',
859 default=False,
860 action='store_const',
861 const=True,
Adele Zhoue4c35612015-10-16 15:34:23 -0700862 help='Run all the tests under docker. That provides ' +
863 'additional isolation and prevents the need to install ' +
864 'language specific prerequisites. Only available on Linux.')
Craig Tillerd4509a12015-09-28 09:18:40 -0700865argp.add_argument('--allow_flakes',
866 default=False,
867 action='store_const',
868 const=True,
Adele Zhoue4c35612015-10-16 15:34:23 -0700869 help='Allow flaky tests to show as passing (re-runs failed tests up to five times)')
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800870argp.add_argument('--arch',
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800871 choices=['default', 'x86', 'x64'],
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800872 default='default',
873 help='Selects architecture to target. For some platforms "default" is the only supported choice.')
874argp.add_argument('--compiler',
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800875 choices=['default',
Jan Tattermusch6d258c52016-06-10 09:36:51 -0700876 'gcc4.4', 'gcc4.6', 'gcc4.9', 'gcc5.3',
877 'clang3.4', 'clang3.5', 'clang3.6', 'clang3.7',
Jan Tattermusch825471c2016-04-25 16:52:25 -0700878 'vs2010', 'vs2013', 'vs2015',
murgatroid999fab4382016-04-29 15:05:00 -0700879 'python2.7', 'python3.4',
Jan Tattermusch76511a52016-06-17 14:00:57 -0700880 'node0.12', 'node4', 'node5',
881 'coreclr'],
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800882 default='default',
Jan Tattermusch77db4322016-02-20 20:19:35 -0800883 help='Selects compiler to use. Allowed values depend on the platform and language.')
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800884argp.add_argument('--build_only',
885 default=False,
886 action='store_const',
887 const=True,
888 help='Perform all the build steps but dont run any tests.')
Craig Tiller5f735a62016-01-20 09:31:15 -0800889argp.add_argument('--measure_cpu_costs', default=False, action='store_const', const=True,
890 help='Measure the cpu costs of tests')
Craig Tiller1676f912016-01-05 10:49:44 -0800891argp.add_argument('--update_submodules', default=[], nargs='*',
892 help='Update some submodules before building. If any are updated, also run generate_projects. ' +
893 'Submodules are specified as SUBMODULE_NAME:BRANCH; if BRANCH is omitted, master is assumed.')
Craig Tiller234b6e72015-05-23 10:12:40 -0700894argp.add_argument('-a', '--antagonists', default=0, type=int)
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +0200895argp.add_argument('-x', '--xml_report', default=None, type=str,
896 help='Generates a JUnit-compatible XML report')
Craig Tiller123f1372016-06-15 15:06:14 -0700897argp.add_argument('--force_default_poller', default=False, action='store_const', const=True,
898 help='Dont try to iterate over many polling strategies when they exist')
Nicolas Nobleddef2462015-01-06 18:08:25 -0800899args = argp.parse_args()
900
Craig Tiller123f1372016-06-15 15:06:14 -0700901if args.force_default_poller:
902 _POLLING_STRATEGIES = {}
903
Craig Tiller5f735a62016-01-20 09:31:15 -0800904jobset.measure_cpu_costs = args.measure_cpu_costs
905
Craig Tiller1676f912016-01-05 10:49:44 -0800906# update submodules if necessary
Craig Tillerb361b4e2016-01-06 11:44:17 -0800907need_to_regenerate_projects = False
908for spec in args.update_submodules:
909 spec = spec.split(':', 1)
910 if len(spec) == 1:
911 submodule = spec[0]
912 branch = 'master'
913 elif len(spec) == 2:
914 submodule = spec[0]
915 branch = spec[1]
916 cwd = 'third_party/%s' % submodule
917 def git(cmd, cwd=cwd):
918 print 'in %s: git %s' % (cwd, cmd)
919 subprocess.check_call('git %s' % cmd, cwd=cwd, shell=True)
920 git('fetch')
921 git('checkout %s' % branch)
922 git('pull origin %s' % branch)
923 if os.path.exists('src/%s/gen_build_yaml.py' % submodule):
924 need_to_regenerate_projects = True
925if need_to_regenerate_projects:
926 if jobset.platform_string() == 'linux':
927 subprocess.check_call('tools/buildgen/generate_projects.sh', shell=True)
928 else:
929 print 'WARNING: may need to regenerate projects, but since we are not on'
930 print ' Linux this step is being skipped. Compilation MAY fail.'
Craig Tiller1676f912016-01-05 10:49:44 -0800931
932
Nicolas Nobleddef2462015-01-06 18:08:25 -0800933# grab config
Jan Tattermusch77db4322016-02-20 20:19:35 -0800934run_config = _CONFIGS[args.config]
935build_config = run_config.build_config
Craig Tillerf1973b02015-01-16 12:32:13 -0800936
Craig Tiller06805272015-06-11 14:46:47 -0700937if args.travis:
murgatroid99d3b5b7f2015-10-06 17:02:03 -0700938 _FORCE_ENVIRON_FOR_WRAPPERS = {'GRPC_TRACE': 'api'}
Craig Tiller06805272015-06-11 14:46:47 -0700939
Adele Zhou6b9527c2015-11-20 15:56:35 -0800940if 'all' in args.language:
Craig Tiller1676f912016-01-05 10:49:44 -0800941 lang_list = _LANGUAGES.keys()
Adele Zhou6b9527c2015-11-20 15:56:35 -0800942else:
943 lang_list = args.language
Craig Tiller16900662016-01-07 19:30:54 -0800944# We don't support code coverage on some languages
945if 'gcov' in args.config:
Jan Tattermusch3b5121b2016-02-22 17:41:05 -0800946 for bad in ['objc', 'sanity']:
Craig Tiller16900662016-01-07 19:30:54 -0800947 if bad in lang_list:
948 lang_list.remove(bad)
Adele Zhou6b9527c2015-11-20 15:56:35 -0800949
950languages = set(_LANGUAGES[l] for l in lang_list)
Jan Tattermusch77db4322016-02-20 20:19:35 -0800951for l in languages:
952 l.configure(run_config, args)
murgatroid99132ce6a2015-03-04 17:29:14 -0800953
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800954language_make_options=[]
955if any(language.make_options() for language in languages):
Adele Zhou3b6ab812016-05-18 17:04:20 -0700956 if not 'gcov' in args.config and len(languages) != 1:
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800957 print 'languages with custom make options cannot be built simultaneously with other languages'
958 sys.exit(1)
959 else:
960 language_make_options = next(iter(languages)).make_options()
961
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800962if args.use_docker:
963 if not args.travis:
964 print 'Seen --use_docker flag, will run tests under docker.'
965 print
966 print 'IMPORTANT: The changes you are testing need to be locally committed'
967 print 'because only the committed changes in the current branch will be'
968 print 'copied to the docker environment.'
969 time.sleep(5)
970
Jan Tattermusch3b5121b2016-02-22 17:41:05 -0800971 dockerfile_dirs = set([l.dockerfile_dir() for l in languages])
972 if len(dockerfile_dirs) > 1:
Adele Zhou9506ef22016-03-02 13:53:34 -0800973 if 'gcov' in args.config:
974 dockerfile_dir = 'tools/dockerfile/test/multilang_jessie_x64'
975 print ('Using multilang_jessie_x64 docker image for code coverage for '
976 'all languages.')
977 else:
978 print ('Languages to be tested require running under different docker '
979 'images.')
980 sys.exit(1)
981 else:
982 dockerfile_dir = next(iter(dockerfile_dirs))
Craig Tillerde7edf82016-03-20 09:12:16 -0700983
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800984 child_argv = [ arg for arg in sys.argv if not arg == '--use_docker' ]
Jan Tattermusched342b12016-01-26 14:40:31 -0800985 run_tests_cmd = 'python tools/run_tests/run_tests.py %s' % ' '.join(child_argv[1:])
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800986
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800987 env = os.environ.copy()
988 env['RUN_TESTS_COMMAND'] = run_tests_cmd
Jan Tattermusch3b5121b2016-02-22 17:41:05 -0800989 env['DOCKERFILE_DIR'] = dockerfile_dir
Jan Tattermusch9835d4b2016-04-29 15:05:05 -0700990 env['DOCKER_RUN_SCRIPT'] = 'tools/run_tests/dockerize/docker_run_tests.sh'
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800991 if args.xml_report:
992 env['XML_REPORT'] = args.xml_report
993 if not args.travis:
994 env['TTY_FLAG'] = '-t' # enables Ctrl-C when not on Jenkins.
995
Jan Tattermusch9835d4b2016-04-29 15:05:05 -0700996 subprocess.check_call(['tools/run_tests/dockerize/build_docker_and_run_tests.sh'],
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800997 shell=True,
998 env=env)
999 sys.exit(0)
Jan Tattermusch788ee232016-01-26 12:19:44 -08001000
Jan Tattermuschf08018a2016-01-26 08:22:09 -08001001_check_arch_option(args.arch)
Jan Tattermusch4dc9e722016-01-25 17:00:54 -08001002
Jan Tattermuschfba65302016-01-25 18:21:14 -08001003def make_jobspec(cfg, targets, makefile='Makefile'):
1004 if platform_string() == 'windows':
Craig Tillerfc3c0c42015-09-01 16:47:54 -07001005 extra_args = []
Craig Tillerb5391e12015-09-03 14:35:18 -07001006 # better do parallel compilation
Jan Tattermusch47eeb2b2015-10-07 14:09:18 -07001007 # empirically /m:2 gives the best performance/price and should prevent
1008 # overloading the windows workers.
Adele Zhoue4c35612015-10-16 15:34:23 -07001009 extra_args.extend(['/m:2'])
Craig Tillerb5391e12015-09-03 14:35:18 -07001010 # disable PDB generation: it's broken, and we don't need it during CI
Adele Zhoue4c35612015-10-16 15:34:23 -07001011 extra_args.extend(['/p:Jenkins=true'])
Craig Tiller6fd23842015-09-01 07:36:31 -07001012 return [
Jan Tattermusch2dd156e2015-12-04 18:26:17 -08001013 jobset.JobSpec([_windows_build_bat(args.compiler),
murgatroid99cf08daf2015-09-21 15:33:16 -07001014 'vsprojects\\%s.sln' % target,
Jan Tattermuscha2d964c2016-02-22 17:33:09 -08001015 '/p:Configuration=%s' % _MSBUILD_CONFIG[cfg]] +
Jan Tattermuschc895fe02016-01-20 09:13:09 -08001016 extra_args +
1017 language_make_options,
Craig Tiller590105a2016-01-19 13:03:46 -08001018 shell=True, timeout_seconds=None)
Craig Tiller6fd23842015-09-01 07:36:31 -07001019 for target in targets]
Jan Tattermuschfba65302016-01-25 18:21:14 -08001020 else:
murgatroid998ae409f2015-10-26 16:39:00 -07001021 if targets:
1022 return [jobset.JobSpec([os.getenv('MAKE', 'make'),
1023 '-f', makefile,
Craig Tillerdd6f7ed2016-01-21 12:54:42 -08001024 '-j', '%d' % args.jobs,
Craig Tiller71a86042016-01-15 14:59:58 -08001025 'EXTRA_DEFINES=GRPC_TEST_SLOWDOWN_MACHINE_FACTOR=%f' % args.slowdown,
1026 'CONFIG=%s' % cfg] +
Jan Tattermuschc895fe02016-01-20 09:13:09 -08001027 language_make_options +
Craig Tiller71a86042016-01-15 14:59:58 -08001028 ([] if not args.travis else ['JENKINS_BUILD=1']) +
1029 targets,
Craig Tiller590105a2016-01-19 13:03:46 -08001030 timeout_seconds=None)]
murgatroid998ae409f2015-10-26 16:39:00 -07001031 else:
1032 return []
Jan Tattermuschfba65302016-01-25 18:21:14 -08001033
murgatroid99a3e244f2015-09-22 11:25:53 -07001034make_targets = {}
1035for l in languages:
1036 makefile = l.makefile_name()
1037 make_targets[makefile] = make_targets.get(makefile, set()).union(
Jan Tattermusch77db4322016-02-20 20:19:35 -08001038 set(l.make_targets()))
Craig Tiller5058c692015-04-08 09:42:04 -07001039
Jan Tattermusche4a69182015-12-15 09:53:01 -08001040def build_step_environ(cfg):
1041 environ = {'CONFIG': cfg}
Jan Tattermuscha2d964c2016-02-22 17:33:09 -08001042 msbuild_cfg = _MSBUILD_CONFIG.get(cfg)
Jan Tattermusche4a69182015-12-15 09:53:01 -08001043 if msbuild_cfg:
1044 environ['MSBUILD_CONFIG'] = msbuild_cfg
1045 return environ
1046
murgatroid99fddac962015-09-22 09:20:11 -07001047build_steps = list(set(
Jan Tattermusch77db4322016-02-20 20:19:35 -08001048 jobset.JobSpec(cmdline, environ=build_step_environ(build_config), flake_retries=5)
murgatroid99256d3df2015-09-21 16:58:02 -07001049 for l in languages
1050 for cmdline in l.pre_build_steps()))
Craig Tillerbd4e3782015-09-01 06:48:55 -07001051if make_targets:
Jan Tattermusch77db4322016-02-20 20:19:35 -08001052 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 -07001053 build_steps.extend(set(make_commands))
Craig Tiller5058c692015-04-08 09:42:04 -07001054build_steps.extend(set(
Jan Tattermusch77db4322016-02-20 20:19:35 -08001055 jobset.JobSpec(cmdline, environ=build_step_environ(build_config), timeout_seconds=None)
Craig Tiller547db2b2015-01-30 14:08:39 -08001056 for l in languages
Craig Tiller533b1a22015-05-29 08:41:29 -07001057 for cmdline in l.build_steps()))
Craig Tillerf1973b02015-01-16 12:32:13 -08001058
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +02001059post_tests_steps = list(set(
Jan Tattermusch77db4322016-02-20 20:19:35 -08001060 jobset.JobSpec(cmdline, environ=build_step_environ(build_config))
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +02001061 for l in languages
1062 for cmdline in l.post_tests_steps()))
Nicolas Nobleddef2462015-01-06 18:08:25 -08001063runs_per_test = args.runs_per_test
ctiller3040cb72015-01-07 12:13:17 -08001064forever = args.forever
Nicolas Nobleddef2462015-01-06 18:08:25 -08001065
Nicolas Nobleddef2462015-01-06 18:08:25 -08001066
Craig Tillerf53d9c82015-08-04 14:19:43 -07001067def _start_port_server(port_server_port):
1068 # check if a compatible port server is running
1069 # if incompatible (version mismatch) ==> start a new one
1070 # if not running ==> start a new one
1071 # otherwise, leave it up
1072 try:
Craig Tillerfe4939f2015-10-06 12:55:36 -07001073 version = int(urllib2.urlopen(
1074 'http://localhost:%d/version_number' % port_server_port,
Jan Tattermusch292d0102016-06-28 10:29:41 -07001075 timeout=10).read())
Craig Tillerfe4939f2015-10-06 12:55:36 -07001076 print 'detected port server running version %d' % version
Craig Tillerf53d9c82015-08-04 14:19:43 -07001077 running = True
Craig Tillerfe4939f2015-10-06 12:55:36 -07001078 except Exception as e:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001079 print 'failed to detect port server: %s' % sys.exc_info()[0]
Craig Tillerfe4939f2015-10-06 12:55:36 -07001080 print e.strerror
Craig Tillerf53d9c82015-08-04 14:19:43 -07001081 running = False
1082 if running:
Craig Tillerfe4939f2015-10-06 12:55:36 -07001083 current_version = int(subprocess.check_output(
Jan Tattermusch3bd08272015-11-04 19:24:37 -08001084 [sys.executable, os.path.abspath('tools/run_tests/port_server.py'),
1085 'dump_version']))
Craig Tillerfe4939f2015-10-06 12:55:36 -07001086 print 'my port server is version %d' % current_version
1087 running = (version >= current_version)
1088 if not running:
1089 print 'port_server version mismatch: killing the old one'
1090 urllib2.urlopen('http://localhost:%d/quitquitquit' % port_server_port).read()
1091 time.sleep(1)
Craig Tillerf53d9c82015-08-04 14:19:43 -07001092 if not running:
Craig Tillerf0a293e2015-10-12 10:05:50 -07001093 fd, logfile = tempfile.mkstemp()
1094 os.close(fd)
1095 print 'starting port_server, with log file %s' % logfile
Jan Tattermusch3bd08272015-11-04 19:24:37 -08001096 args = [sys.executable, os.path.abspath('tools/run_tests/port_server.py'),
1097 '-p', '%d' % port_server_port, '-l', logfile]
Craig Tiller367d41d2015-10-12 13:00:22 -07001098 env = dict(os.environ)
1099 env['BUILD_ID'] = 'pleaseDontKillMeJenkins'
Nicolas "Pixel" Noblef72d7b52015-12-03 03:07:43 +01001100 if platform_string() == 'windows':
Jan Tattermusch3bd08272015-11-04 19:24:37 -08001101 # Working directory of port server needs to be outside of Jenkins
1102 # workspace to prevent file lock issues.
1103 tempdir = tempfile.mkdtemp()
Craig Tillerd2c39712015-10-12 11:08:49 -07001104 port_server = subprocess.Popen(
Craig Tiller367d41d2015-10-12 13:00:22 -07001105 args,
1106 env=env,
Jan Tattermusch3bd08272015-11-04 19:24:37 -08001107 cwd=tempdir,
Craig Tiller367d41d2015-10-12 13:00:22 -07001108 creationflags = 0x00000008, # detached process
1109 close_fds=True)
Craig Tillerd2c39712015-10-12 11:08:49 -07001110 else:
1111 port_server = subprocess.Popen(
1112 args,
Craig Tiller367d41d2015-10-12 13:00:22 -07001113 env=env,
Craig Tillerd2c39712015-10-12 11:08:49 -07001114 preexec_fn=os.setsid,
1115 close_fds=True)
Craig Tillerf0a293e2015-10-12 10:05:50 -07001116 time.sleep(1)
Craig Tiller8b5f4dc2015-08-26 08:02:01 -07001117 # ensure port server is up
Craig Tillerabd37fd2015-08-26 07:54:01 -07001118 waits = 0
Craig Tillerf53d9c82015-08-04 14:19:43 -07001119 while True:
Craig Tillerabd37fd2015-08-26 07:54:01 -07001120 if waits > 10:
Craig Tillerf0a293e2015-10-12 10:05:50 -07001121 print 'killing port server due to excessive start up waits'
Craig Tillerabd37fd2015-08-26 07:54:01 -07001122 port_server.kill()
Craig Tillera2f38b02015-09-24 11:19:17 -07001123 if port_server.poll() is not None:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001124 print 'port_server failed to start'
Craig Tillerf0a293e2015-10-12 10:05:50 -07001125 # try one final time: maybe another build managed to start one
1126 time.sleep(1)
1127 try:
1128 urllib2.urlopen('http://localhost:%d/get' % port_server_port,
1129 timeout=1).read()
1130 print 'last ditch attempt to contact port server succeeded'
1131 break
1132 except:
Jan Tattermusch3b5121b2016-02-22 17:41:05 -08001133 traceback.print_exc()
Craig Tillerf0a293e2015-10-12 10:05:50 -07001134 port_log = open(logfile, 'r').read()
1135 print port_log
1136 sys.exit(1)
Craig Tillerf53d9c82015-08-04 14:19:43 -07001137 try:
Craig Tillerabd37fd2015-08-26 07:54:01 -07001138 urllib2.urlopen('http://localhost:%d/get' % port_server_port,
1139 timeout=1).read()
Craig Tillerf0a293e2015-10-12 10:05:50 -07001140 print 'port server is up and ready'
Craig Tillerf53d9c82015-08-04 14:19:43 -07001141 break
Craig Tiller31fdaa42015-09-25 13:09:59 -07001142 except socket.timeout:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001143 print 'waiting for port_server: timeout'
Craig Tillerf0a293e2015-10-12 10:05:50 -07001144 traceback.print_exc();
1145 time.sleep(1)
Craig Tiller31fdaa42015-09-25 13:09:59 -07001146 waits += 1
Craig Tillerf53d9c82015-08-04 14:19:43 -07001147 except urllib2.URLError:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001148 print 'waiting for port_server: urlerror'
Craig Tillerf0a293e2015-10-12 10:05:50 -07001149 traceback.print_exc();
1150 time.sleep(1)
Craig Tillerabd37fd2015-08-26 07:54:01 -07001151 waits += 1
Craig Tillerf53d9c82015-08-04 14:19:43 -07001152 except:
Jan Tattermusch3b5121b2016-02-22 17:41:05 -08001153 traceback.print_exc()
Craig Tillerf53d9c82015-08-04 14:19:43 -07001154 port_server.kill()
1155 raise
1156
1157
Adele Zhoud5fffa52015-10-23 15:51:42 -07001158def _calculate_num_runs_failures(list_of_results):
1159 """Caculate number of runs and failures for a particular test.
1160
1161 Args:
1162 list_of_results: (List) of JobResult object.
1163 Returns:
1164 A tuple of total number of runs and failures.
1165 """
1166 num_runs = len(list_of_results) # By default, there is 1 run per JobResult.
1167 num_failures = 0
1168 for jobresult in list_of_results:
1169 if jobresult.retries > 0:
1170 num_runs += jobresult.retries
1171 if jobresult.num_failures > 0:
1172 num_failures += jobresult.num_failures
1173 return num_runs, num_failures
1174
Adele Zhou6b9527c2015-11-20 15:56:35 -08001175
Craig Tillereb9de8b2016-01-08 08:57:41 -08001176# _build_and_run results
1177class BuildAndRunError(object):
1178
1179 BUILD = object()
1180 TEST = object()
1181 POST_TEST = object()
1182
1183
1184# returns a list of things that failed (or an empty list on success)
Craig Tillerf53d9c82015-08-04 14:19:43 -07001185def _build_and_run(
Craig Tiller74189cd2016-06-23 15:39:06 -07001186 check_cancelled, newline_on_success, xml_report=None, build_only=False):
ctiller3040cb72015-01-07 12:13:17 -08001187 """Do one pass of building & running tests."""
murgatroid99666450e2015-01-26 13:03:31 -08001188 # build latest sequentially
Jan Tattermuschaab1e512016-01-28 09:30:44 -08001189 num_failures, resultset = jobset.run(
Adele Zhoue4c35612015-10-16 15:34:23 -07001190 build_steps, maxjobs=1, stop_on_failure=True,
Craig Tiller883064c2015-11-04 10:06:10 -08001191 newline_on_success=newline_on_success, travis=args.travis)
Adele Zhoue4c35612015-10-16 15:34:23 -07001192 if num_failures:
Craig Tillereb9de8b2016-01-08 08:57:41 -08001193 return [BuildAndRunError.BUILD]
Craig Tillerb361b4e2016-01-06 11:44:17 -08001194
Jan Tattermusch2dd156e2015-12-04 18:26:17 -08001195 if build_only:
Jan Tattermuschaab1e512016-01-28 09:30:44 -08001196 if xml_report:
1197 report_utils.render_junit_xml_report(resultset, xml_report)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001198 return []
ctiller3040cb72015-01-07 12:13:17 -08001199
Craig Tiller234b6e72015-05-23 10:12:40 -07001200 # start antagonists
David Garcia Quintas79e389f2015-06-02 17:49:42 -07001201 antagonists = [subprocess.Popen(['tools/run_tests/antagonist.py'])
Craig Tiller234b6e72015-05-23 10:12:40 -07001202 for _ in range(0, args.antagonists)]
Craig Tillerfe4939f2015-10-06 12:55:36 -07001203 port_server_port = 32767
Craig Tillerf53d9c82015-08-04 14:19:43 -07001204 _start_port_server(port_server_port)
Adele Zhou7cf72112015-11-04 11:18:43 -08001205 resultset = None
Adele Zhou803af152015-11-30 15:16:16 -08001206 num_test_failures = 0
Craig Tiller234b6e72015-05-23 10:12:40 -07001207 try:
David Garcia Quintase90cd372015-05-31 18:15:26 -07001208 infinite_runs = runs_per_test == 0
yang-g6c1fdc62015-08-18 11:57:42 -07001209 one_run = set(
1210 spec
yang-g6c1fdc62015-08-18 11:57:42 -07001211 for language in languages
Jan Tattermusch77db4322016-02-20 20:19:35 -08001212 for spec in language.test_specs()
Vijay Pai488fd0e2016-06-13 12:37:12 -07001213 if (re.search(args.regex, spec.shortname) and
1214 (args.regex_exclude == '' or
1215 not re.search(args.regex_exclude, spec.shortname))))
David Garcia Quintas79e389f2015-06-02 17:49:42 -07001216 # When running on travis, we want out test runs to be as similar as possible
1217 # for reproducibility purposes.
Craig Tiller883064c2015-11-04 10:06:10 -08001218 if args.travis:
David Garcia Quintas79e389f2015-06-02 17:49:42 -07001219 massaged_one_run = sorted(one_run, key=lambda x: x.shortname)
1220 else:
1221 # whereas otherwise, we want to shuffle things up to give all tests a
1222 # chance to run.
1223 massaged_one_run = list(one_run) # random.shuffle needs an indexable seq.
1224 random.shuffle(massaged_one_run) # which it modifies in-place.
Craig Tillerf7b7c892015-06-22 14:33:25 -07001225 if infinite_runs:
1226 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 -07001227 runs_sequence = (itertools.repeat(massaged_one_run) if infinite_runs
1228 else itertools.repeat(massaged_one_run, runs_per_test))
David Garcia Quintase90cd372015-05-31 18:15:26 -07001229 all_runs = itertools.chain.from_iterable(runs_sequence)
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +02001230
Adele Zhou803af152015-11-30 15:16:16 -08001231 num_test_failures, resultset = jobset.run(
Adele Zhou2271ab52015-10-28 13:59:14 -07001232 all_runs, check_cancelled, newline_on_success=newline_on_success,
Craig Tiller883064c2015-11-04 10:06:10 -08001233 travis=args.travis, infinite_runs=infinite_runs, maxjobs=args.jobs,
murgatroid998ae409f2015-10-26 16:39:00 -07001234 stop_on_failure=args.stop_on_failure,
Adele Zhouf2ca7bc2015-10-23 15:38:00 -07001235 add_env={'GRPC_TEST_PORT_SERVER': 'localhost:%d' % port_server_port})
Adele Zhoud5fffa52015-10-23 15:51:42 -07001236 if resultset:
Craig Tiller2b59dbc2016-05-13 15:59:09 -07001237 for k, v in sorted(resultset.items()):
Adele Zhoud5fffa52015-10-23 15:51:42 -07001238 num_runs, num_failures = _calculate_num_runs_failures(v)
1239 if num_failures == num_runs: # what about infinite_runs???
1240 jobset.message('FAILED', k, do_newline=True)
1241 elif num_failures > 0:
1242 jobset.message(
1243 'FLAKE', '%s [%d/%d runs flaked]' % (k, num_failures, num_runs),
1244 do_newline=True)
1245 else:
1246 jobset.message('PASSED', k, do_newline=True)
Craig Tiller234b6e72015-05-23 10:12:40 -07001247 finally:
1248 for antagonist in antagonists:
1249 antagonist.kill()
Adele Zhou7cf72112015-11-04 11:18:43 -08001250 if xml_report and resultset:
Adele Zhou3bc7ba42015-11-05 10:21:58 -08001251 report_utils.render_junit_xml_report(resultset, xml_report)
Craig Tillerd86a3942015-01-14 12:48:54 -08001252
Adele Zhouf2ca7bc2015-10-23 15:38:00 -07001253 number_failures, _ = jobset.run(
1254 post_tests_steps, maxjobs=1, stop_on_failure=True,
Craig Tiller883064c2015-11-04 10:06:10 -08001255 newline_on_success=newline_on_success, travis=args.travis)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001256
1257 out = []
1258 if number_failures:
1259 out.append(BuildAndRunError.POST_TEST)
1260 if num_test_failures:
1261 out.append(BuildAndRunError.TEST)
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +02001262
Craig Tillereb9de8b2016-01-08 08:57:41 -08001263 return out
ctiller3040cb72015-01-07 12:13:17 -08001264
1265
1266if forever:
Nicolas Noble044db742015-01-14 16:57:24 -08001267 success = True
ctiller3040cb72015-01-07 12:13:17 -08001268 while True:
Craig Tiller42bc87c2015-02-23 08:50:19 -08001269 dw = watch_dirs.DirWatcher(['src', 'include', 'test', 'examples'])
ctiller3040cb72015-01-07 12:13:17 -08001270 initial_time = dw.most_recent_change()
1271 have_files_changed = lambda: dw.most_recent_change() != initial_time
Nicolas Noble044db742015-01-14 16:57:24 -08001272 previous_success = success
Craig Tillereb9de8b2016-01-08 08:57:41 -08001273 errors = _build_and_run(check_cancelled=have_files_changed,
1274 newline_on_success=False,
Craig Tillereb9de8b2016-01-08 08:57:41 -08001275 build_only=args.build_only) == 0
1276 if not previous_success and not errors:
Nicolas Nobleb09078f2015-01-14 18:06:05 -08001277 jobset.message('SUCCESS',
1278 'All tests are now passing properly',
1279 do_newline=True)
Nicolas Noble044db742015-01-14 16:57:24 -08001280 jobset.message('IDLE', 'No change detected')
ctiller3040cb72015-01-07 12:13:17 -08001281 while not have_files_changed():
1282 time.sleep(1)
1283else:
Craig Tillereb9de8b2016-01-08 08:57:41 -08001284 errors = _build_and_run(check_cancelled=lambda: False,
Craig Tiller71735182015-01-15 17:07:13 -08001285 newline_on_success=args.newline_on_success,
Jan Tattermusch2dd156e2015-12-04 18:26:17 -08001286 xml_report=args.xml_report,
1287 build_only=args.build_only)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001288 if not errors:
Nicolas Nobleb09078f2015-01-14 18:06:05 -08001289 jobset.message('SUCCESS', 'All tests passed', do_newline=True)
1290 else:
1291 jobset.message('FAILED', 'Some tests failed', do_newline=True)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001292 exit_code = 0
1293 if BuildAndRunError.BUILD in errors:
1294 exit_code |= 1
Craig Tiller4f2be362016-01-08 08:59:20 -08001295 if BuildAndRunError.TEST in errors and not args.travis:
Craig Tillereb9de8b2016-01-08 08:57:41 -08001296 exit_code |= 2
Craig Tiller4f2be362016-01-08 08:59:20 -08001297 if BuildAndRunError.POST_TEST in errors:
1298 exit_code |= 4
Craig Tillereb9de8b2016-01-08 08:57:41 -08001299 sys.exit(exit_code)