blob: 3266cfd19fcf10784bd2e7b1d49143c59b360b71 [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 Tiller8f18ee62016-07-18 08:00:33 -070063_FORCE_ENVIRON_FOR_WRAPPERS = {
64 'GRPC_VERBOSITY': 'DEBUG',
65}
Craig Tiller06805272015-06-11 14:46:47 -070066
67
Craig Tiller123f1372016-06-15 15:06:14 -070068_POLLING_STRATEGIES = {
Sree Kuchibhotlac3a9fae2016-06-21 16:31:08 -070069 'linux': ['epoll', 'poll', 'legacy']
Craig Tiller123f1372016-06-15 15:06:14 -070070}
71
72
Craig Tillerd50993d2015-08-05 08:04:36 -070073def platform_string():
Nicolas "Pixel" Noblef72d7b52015-12-03 03:07:43 +010074 return jobset.platform_string()
Craig Tillerd50993d2015-08-05 08:04:36 -070075
76
Craig Tiller738c3342015-01-12 14:28:33 -080077# SimpleConfig: just compile with CONFIG=config, and run the binary to test
Craig Tillera0f85172016-01-20 15:56:06 -080078class Config(object):
Craig Tillerb50d1662015-01-15 17:28:21 -080079
Craig Tillera0f85172016-01-20 15:56:06 -080080 def __init__(self, config, environ=None, timeout_multiplier=1, tool_prefix=[]):
murgatroid99132ce6a2015-03-04 17:29:14 -080081 if environ is None:
82 environ = {}
Craig Tiller738c3342015-01-12 14:28:33 -080083 self.build_config = config
Craig Tiller547db2b2015-01-30 14:08:39 -080084 self.environ = environ
murgatroid99132ce6a2015-03-04 17:29:14 -080085 self.environ['CONFIG'] = config
Craig Tillera0f85172016-01-20 15:56:06 -080086 self.tool_prefix = tool_prefix
Masood Malekghassemi26ea9e22015-10-09 15:19:17 -070087 self.timeout_multiplier = timeout_multiplier
Craig Tiller738c3342015-01-12 14:28:33 -080088
Craig Tiller74189cd2016-06-23 15:39:06 -070089 def job_spec(self, cmdline, timeout_seconds=5*60,
Craig Tillerde7edf82016-03-20 09:12:16 -070090 shortname=None, environ={}, cpu_cost=1.0, flaky=False):
Craig Tiller49f61322015-03-03 13:02:11 -080091 """Construct a jobset.JobSpec for a test under this config
92
93 Args:
94 cmdline: a list of strings specifying the command line the test
95 would like to run
Craig Tiller49f61322015-03-03 13:02:11 -080096 """
Craig Tiller4fc90032015-05-21 10:39:52 -070097 actual_environ = self.environ.copy()
98 for k, v in environ.iteritems():
99 actual_environ[k] = v
Craig Tillera0f85172016-01-20 15:56:06 -0800100 return jobset.JobSpec(cmdline=self.tool_prefix + cmdline,
Jan Tattermusch9a7d30c2015-04-23 16:12:55 -0700101 shortname=shortname,
Craig Tiller4fc90032015-05-21 10:39:52 -0700102 environ=actual_environ,
Craig Tiller56c6b6a2016-01-20 08:27:37 -0800103 cpu_cost=cpu_cost,
Craig Tiller94d04a52016-01-20 10:58:23 -0800104 timeout_seconds=(self.timeout_multiplier * timeout_seconds if timeout_seconds else None),
Craig Tillerde7edf82016-03-20 09:12:16 -0700105 flake_retries=5 if flaky or args.allow_flakes else 0,
Craig Tiller35505de2015-10-08 13:31:33 -0700106 timeout_retries=3 if args.allow_flakes else 0)
Craig Tiller738c3342015-01-12 14:28:33 -0800107
108
murgatroid99cf08daf2015-09-21 15:33:16 -0700109def get_c_tests(travis, test_lang) :
110 out = []
111 platforms_str = 'ci_platforms' if travis else 'platforms'
112 with open('tools/run_tests/tests.json') as f:
murgatroid9989899b12015-09-22 09:14:48 -0700113 js = json.load(f)
murgatroid99a3e244f2015-09-22 11:25:53 -0700114 return [tgt
115 for tgt in js
116 if tgt['language'] == test_lang and
117 platform_string() in tgt[platforms_str] and
118 not (travis and tgt['flaky'])]
murgatroid99cf08daf2015-09-21 15:33:16 -0700119
murgatroid99fafeeb32015-09-22 09:13:03 -0700120
Jan Tattermusch77db4322016-02-20 20:19:35 -0800121def _check_compiler(compiler, supported_compilers):
122 if compiler not in supported_compilers:
Jan Tattermuschb2531e22016-03-25 16:14:41 -0700123 raise Exception('Compiler %s not supported (on this platform).' % compiler)
124
125
126def _check_arch(arch, supported_archs):
127 if arch not in supported_archs:
128 raise Exception('Architecture %s not supported.' % arch)
Jan Tattermusch77db4322016-02-20 20:19:35 -0800129
130
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800131def _is_use_docker_child():
132 """Returns True if running running as a --use_docker child."""
133 return True if os.getenv('RUN_TESTS_COMMAND') else False
134
135
Craig Tillerc7449162015-01-16 14:42:10 -0800136class CLanguage(object):
137
Craig Tillere9c959d2015-01-18 10:23:26 -0800138 def __init__(self, make_target, test_lang):
Craig Tillerc7449162015-01-16 14:42:10 -0800139 self.make_target = make_target
Craig Tillerd50993d2015-08-05 08:04:36 -0700140 self.platform = platform_string()
Craig Tiller711bbe62015-08-19 12:35:16 -0700141 self.test_lang = test_lang
Craig Tillerc7449162015-01-16 14:42:10 -0800142
Jan Tattermusch77db4322016-02-20 20:19:35 -0800143 def configure(self, config, args):
144 self.config = config
145 self.args = args
146 if self.platform == 'windows':
Jan Tattermuschc96caf82016-02-22 17:31:02 -0800147 self._make_options = [_windows_toolset_option(self.args.compiler),
148 _windows_arch_option(self.args.arch)]
Jan Tattermusch77db4322016-02-20 20:19:35 -0800149 else:
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800150 self._docker_distro, self._make_options = self._compiler_options(self.args.use_docker,
151 self.args.compiler)
Jan Tattermusch77db4322016-02-20 20:19:35 -0800152
153 def test_specs(self):
Craig Tiller547db2b2015-01-30 14:08:39 -0800154 out = []
Jan Tattermusch77db4322016-02-20 20:19:35 -0800155 binaries = get_c_tests(self.args.travis, self.test_lang)
Craig Tiller946ce7a2016-04-06 10:35:58 -0700156 for target in binaries:
Craig Tiller123f1372016-06-15 15:06:14 -0700157 polling_strategies = (_POLLING_STRATEGIES.get(self.platform, ['all'])
Craig Tiller946ce7a2016-04-06 10:35:58 -0700158 if target.get('uses_polling', True)
159 else ['all'])
160 for polling_strategy in polling_strategies:
161 env={'GRPC_DEFAULT_SSL_ROOTS_FILE_PATH':
162 _ROOT + '/src/core/lib/tsi/test_creds/ca.pem',
Craig Tiller8f18ee62016-07-18 08:00:33 -0700163 'GRPC_POLL_STRATEGY': polling_strategy,
164 'GRPC_VERBOSITY': 'DEBUG'}
Craig Tiller946ce7a2016-04-06 10:35:58 -0700165 shortname_ext = '' if polling_strategy=='all' else ' polling=%s' % polling_strategy
Craig Tillerb38197e2016-02-26 10:14:54 -0800166 if self.config.build_config in target['exclude_configs']:
167 continue
168 if self.platform == 'windows':
169 binary = 'vsprojects/%s%s/%s.exe' % (
170 'x64/' if self.args.arch == 'x64' else '',
171 _MSBUILD_CONFIG[self.config.build_config],
172 target['name'])
Craig Tillerca62ff02016-02-24 22:22:57 -0800173 else:
Craig Tillerb38197e2016-02-26 10:14:54 -0800174 binary = 'bins/%s/%s' % (self.config.build_config, target['name'])
175 if os.path.isfile(binary):
176 if 'gtest' in target and target['gtest']:
177 # here we parse the output of --gtest_list_tests to build up a
178 # complete list of the tests contained in a binary
179 # for each test, we then add a job to run, filtering for just that
180 # test
181 with open(os.devnull, 'w') as fnull:
182 tests = subprocess.check_output([binary, '--gtest_list_tests'],
183 stderr=fnull)
184 base = None
185 for line in tests.split('\n'):
186 i = line.find('#')
187 if i >= 0: line = line[:i]
188 if not line: continue
189 if line[0] != ' ':
190 base = line.strip()
191 else:
192 assert base is not None
193 assert line[1] == ' '
194 test = base + line.strip()
195 cmdline = [binary] + ['--gtest_filter=%s' % test]
196 out.append(self.config.job_spec(cmdline, [binary],
Craig Tiller334db352016-02-26 15:19:49 -0800197 shortname='%s:%s %s' % (binary, test, shortname_ext),
Craig Tillerb38197e2016-02-26 10:14:54 -0800198 cpu_cost=target['cpu_cost'],
199 environ=env))
200 else:
201 cmdline = [binary] + target['args']
202 out.append(self.config.job_spec(cmdline, [binary],
203 shortname=' '.join(cmdline) + shortname_ext,
204 cpu_cost=target['cpu_cost'],
Craig Tillerc2278152016-03-21 08:59:54 -0700205 flaky=target.get('flaky', False),
Craig Tillerb38197e2016-02-26 10:14:54 -0800206 environ=env))
207 elif self.args.regex == '.*' or self.platform == 'windows':
208 print '\nWARNING: binary not found, skipping', binary
Nicolas Noblee1445362015-05-11 17:40:26 -0700209 return sorted(out)
Craig Tillerc7449162015-01-16 14:42:10 -0800210
Jan Tattermusch77db4322016-02-20 20:19:35 -0800211 def make_targets(self):
212 test_regex = self.args.regex
213 if self.platform != 'windows' and self.args.regex != '.*':
Craig Tiller883064c2015-11-04 10:06:10 -0800214 # use the regex to minimize the number of things to build
Craig Tillerb0f275e2016-01-27 10:45:50 -0800215 return [os.path.basename(target['name'])
Craig Tiller883064c2015-11-04 10:06:10 -0800216 for target in get_c_tests(False, self.test_lang)
Craig Tillerb0f275e2016-01-27 10:45:50 -0800217 if re.search(test_regex, '/' + target['name'])]
Jan Tattermusch77db4322016-02-20 20:19:35 -0800218 if self.platform == 'windows':
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700219 # don't build tools on windows just yet
220 return ['buildtests_%s' % self.make_target]
Craig Tiller7552f0f2015-06-19 17:46:20 -0700221 return ['buildtests_%s' % self.make_target, 'tools_%s' % self.make_target]
Craig Tillerc7449162015-01-16 14:42:10 -0800222
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800223 def make_options(self):
Jan Tattermuschc96caf82016-02-22 17:31:02 -0800224 return self._make_options;
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800225
murgatroid99256d3df2015-09-21 16:58:02 -0700226 def pre_build_steps(self):
Jan Tattermusch874aec02015-10-07 19:26:19 -0700227 if self.platform == 'windows':
228 return [['tools\\run_tests\\pre_build_c.bat']]
229 else:
230 return []
murgatroid99256d3df2015-09-21 16:58:02 -0700231
Craig Tillerc7449162015-01-16 14:42:10 -0800232 def build_steps(self):
233 return []
234
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200235 def post_tests_steps(self):
236 if self.platform == 'windows':
237 return []
238 else:
239 return [['tools/run_tests/post_tests_c.sh']]
240
murgatroid99a3e244f2015-09-22 11:25:53 -0700241 def makefile_name(self):
242 return 'Makefile'
243
Jan Tattermusch6d258c52016-06-10 09:36:51 -0700244 def _clang_make_options(self, version_suffix=''):
245 return ['CC=clang%s' % version_suffix,
246 'CXX=clang++%s' % version_suffix,
247 'LD=clang%s' % version_suffix,
248 'LDXX=clang++%s' % version_suffix]
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800249
Jan Tattermusch6d258c52016-06-10 09:36:51 -0700250 def _gcc_make_options(self, version_suffix):
251 return ['CC=gcc%s' % version_suffix,
252 'CXX=g++%s' % version_suffix,
253 'LD=gcc%s' % version_suffix,
254 'LDXX=g++%s' % version_suffix]
Jan Tattermusch9bb70622016-03-18 10:28:54 -0700255
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800256 def _compiler_options(self, use_docker, compiler):
257 """Returns docker distro and make options to use for given compiler."""
Jan Tattermuschfd3857b2016-06-03 12:24:03 -0700258 if not use_docker and not _is_use_docker_child():
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800259 _check_compiler(compiler, ['default'])
260
261 if compiler == 'gcc4.9' or compiler == 'default':
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800262 return ('jessie', [])
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800263 elif compiler == 'gcc4.4':
Jan Tattermusch6d258c52016-06-10 09:36:51 -0700264 return ('wheezy', self._gcc_make_options(version_suffix='-4.4'))
265 elif compiler == 'gcc4.6':
266 return ('wheezy', self._gcc_make_options(version_suffix='-4.6'))
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800267 elif compiler == 'gcc5.3':
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800268 return ('ubuntu1604', [])
269 elif compiler == 'clang3.4':
Jan Tattermusch6d258c52016-06-10 09:36:51 -0700270 # on ubuntu1404, clang-3.4 alias doesn't exist, just use 'clang'
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800271 return ('ubuntu1404', self._clang_make_options())
Jan Tattermusch6d258c52016-06-10 09:36:51 -0700272 elif compiler == 'clang3.5':
273 return ('jessie', self._clang_make_options(version_suffix='-3.5'))
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800274 elif compiler == 'clang3.6':
Jan Tattermusch6d258c52016-06-10 09:36:51 -0700275 return ('ubuntu1604', self._clang_make_options(version_suffix='-3.6'))
276 elif compiler == 'clang3.7':
277 return ('ubuntu1604', self._clang_make_options(version_suffix='-3.7'))
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800278 else:
279 raise Exception('Compiler %s not supported.' % compiler)
280
Jan Tattermusch77db4322016-02-20 20:19:35 -0800281 def dockerfile_dir(self):
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800282 return 'tools/dockerfile/test/cxx_%s_%s' % (self._docker_distro,
283 _docker_arch_suffix(self.args.arch))
Jan Tattermusch788ee232016-01-26 12:19:44 -0800284
murgatroid99132ce6a2015-03-04 17:29:14 -0800285 def __str__(self):
286 return self.make_target
287
Craig Tillercc0535d2015-12-08 15:14:47 -0800288
murgatroid992c8d5162015-01-26 10:41:21 -0800289class NodeLanguage(object):
290
Jan Tattermusche477b842016-02-06 22:19:01 -0800291 def __init__(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800292 self.platform = platform_string()
Jan Tattermusche477b842016-02-06 22:19:01 -0800293
Jan Tattermusch77db4322016-02-20 20:19:35 -0800294 def configure(self, config, args):
295 self.config = config
296 self.args = args
murgatroid999fab4382016-04-29 15:05:00 -0700297 _check_compiler(self.args.compiler, ['default', 'node0.12',
298 'node4', 'node5'])
299 if self.args.compiler == 'default':
300 self.node_version = '4'
301 else:
302 # Take off the word "node"
303 self.node_version = self.args.compiler[4:]
Jan Tattermusch77db4322016-02-20 20:19:35 -0800304
305 def test_specs(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800306 if self.platform == 'windows':
Jan Tattermusch77db4322016-02-20 20:19:35 -0800307 return [self.config.job_spec(['tools\\run_tests\\run_node.bat'], None)]
Michael Lumishaaa876a2016-02-10 15:27:58 -0800308 else:
Jan Tattermusch77db4322016-02-20 20:19:35 -0800309 return [self.config.job_spec(['tools/run_tests/run_node.sh', self.node_version],
310 None,
311 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
murgatroid992c8d5162015-01-26 10:41:21 -0800312
murgatroid99256d3df2015-09-21 16:58:02 -0700313 def pre_build_steps(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800314 if self.platform == 'windows':
315 return [['tools\\run_tests\\pre_build_node.bat']]
316 else:
317 return [['tools/run_tests/pre_build_node.sh', self.node_version]]
murgatroid99256d3df2015-09-21 16:58:02 -0700318
Jan Tattermusch77db4322016-02-20 20:19:35 -0800319 def make_targets(self):
murgatroid99db5b1602015-10-01 13:20:11 -0700320 return []
murgatroid992c8d5162015-01-26 10:41:21 -0800321
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800322 def make_options(self):
323 return []
324
murgatroid992c8d5162015-01-26 10:41:21 -0800325 def build_steps(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800326 if self.platform == 'windows':
327 return [['tools\\run_tests\\build_node.bat']]
328 else:
329 return [['tools/run_tests/build_node.sh', self.node_version]]
Craig Tillerc7449162015-01-16 14:42:10 -0800330
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200331 def post_tests_steps(self):
332 return []
333
murgatroid99a3e244f2015-09-22 11:25:53 -0700334 def makefile_name(self):
335 return 'Makefile'
336
Jan Tattermusch77db4322016-02-20 20:19:35 -0800337 def dockerfile_dir(self):
338 return 'tools/dockerfile/test/node_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800339
murgatroid99132ce6a2015-03-04 17:29:14 -0800340 def __str__(self):
341 return 'node'
342
Craig Tiller99775822015-01-30 13:07:16 -0800343
Craig Tillerc7449162015-01-16 14:42:10 -0800344class PhpLanguage(object):
345
Jan Tattermusch77db4322016-02-20 20:19:35 -0800346 def configure(self, config, args):
347 self.config = config
348 self.args = args
349 _check_compiler(self.args.compiler, ['default'])
350
351 def test_specs(self):
352 return [self.config.job_spec(['src/php/bin/run_tests.sh'], None,
353 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
Craig Tillerc7449162015-01-16 14:42:10 -0800354
murgatroid99256d3df2015-09-21 16:58:02 -0700355 def pre_build_steps(self):
356 return []
357
Jan Tattermusch77db4322016-02-20 20:19:35 -0800358 def make_targets(self):
Craig Tilleraf7cf542015-05-22 10:07:34 -0700359 return ['static_c', 'shared_c']
Craig Tillerc7449162015-01-16 14:42:10 -0800360
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800361 def make_options(self):
362 return []
363
Craig Tillerc7449162015-01-16 14:42:10 -0800364 def build_steps(self):
365 return [['tools/run_tests/build_php.sh']]
366
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200367 def post_tests_steps(self):
Stanley Cheunga6b95482016-01-13 16:10:48 -0800368 return [['tools/run_tests/post_tests_php.sh']]
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200369
murgatroid99a3e244f2015-09-22 11:25:53 -0700370 def makefile_name(self):
371 return 'Makefile'
372
Jan Tattermusch77db4322016-02-20 20:19:35 -0800373 def dockerfile_dir(self):
374 return 'tools/dockerfile/test/php_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800375
murgatroid99132ce6a2015-03-04 17:29:14 -0800376 def __str__(self):
377 return 'php'
378
Craig Tillerc7449162015-01-16 14:42:10 -0800379
Masood Malekghassemi3b5b2062016-06-02 20:27:20 -0700380class PythonConfig(collections.namedtuple('PythonConfig', [
Masood Malekghassemicab9d4f2016-06-28 09:09:31 -0700381 'name', 'build', 'run'])):
382 """Tuple of commands (named s.t. 'what it says on the tin' applies)"""
Masood Malekghassemi3b5b2062016-06-02 20:27:20 -0700383
Nathaniel Manista840615e2015-01-22 20:31:47 +0000384class PythonLanguage(object):
385
Jan Tattermusch77db4322016-02-20 20:19:35 -0800386 def configure(self, config, args):
387 self.config = config
388 self.args = args
Masood Malekghassemicab9d4f2016-06-28 09:09:31 -0700389 self.pythons = self._get_pythons(self.args)
Jan Tattermusch77db4322016-02-20 20:19:35 -0800390
391 def test_specs(self):
Jan Tattermusch072ebaa2016-03-01 18:33:12 -0800392 # load list of known test suites
Masood Malekghassemi1ff429d2016-06-02 16:39:20 -0700393 with open('src/python/grpcio_tests/tests/tests.json') as tests_json_file:
Jan Tattermusch072ebaa2016-03-01 18:33:12 -0800394 tests_json = json.load(tests_json_file)
Masood Malekghassemi2b841622015-07-28 17:39:02 -0700395 environment = dict(_FORCE_ENVIRON_FOR_WRAPPERS)
Masood Malekghassemi1c062bd2016-06-13 18:41:36 -0700396 return [self.config.job_spec(
Masood Malekghassemicab9d4f2016-06-28 09:09:31 -0700397 config.run,
Masood Malekghassemie6a23e22016-06-28 13:58:42 -0700398 timeout_seconds=5*60,
Masood Malekghassemi1c062bd2016-06-13 18:41:36 -0700399 environ=dict(environment.items() +
400 [('GRPC_PYTHON_TESTRUNNER_FILTER', suite_name)]),
Masood Malekghassemicab9d4f2016-06-28 09:09:31 -0700401 shortname='%s.test.%s' % (config.name, suite_name),)
Masood Malekghassemi1c062bd2016-06-13 18:41:36 -0700402 for suite_name in tests_json
403 for config in self.pythons]
Nathaniel Manista840615e2015-01-22 20:31:47 +0000404
murgatroid99256d3df2015-09-21 16:58:02 -0700405 def pre_build_steps(self):
406 return []
407
Jan Tattermusch77db4322016-02-20 20:19:35 -0800408 def make_targets(self):
Masood Malekghassemi3b5b2062016-06-02 20:27:20 -0700409 return []
Nathaniel Manista840615e2015-01-22 20:31:47 +0000410
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800411 def make_options(self):
412 return []
413
Nathaniel Manista840615e2015-01-22 20:31:47 +0000414 def build_steps(self):
Masood Malekghassemicab9d4f2016-06-28 09:09:31 -0700415 return [config.build for config in self.pythons]
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
Masood Malekghassemicab9d4f2016-06-28 09:09:31 -0700426 def _get_pythons(self, args):
427 if args.arch == 'x86':
428 bits = '32'
Masood Malekghassemi3b5b2062016-06-02 20:27:20 -0700429 else:
Masood Malekghassemicab9d4f2016-06-28 09:09:31 -0700430 bits = '64'
431 if os.name == 'nt':
432 shell = ['bash']
433 builder = [os.path.abspath('tools/run_tests/build_python_msys2.sh')]
434 builder_prefix_arguments = ['MINGW{}'.format(bits)]
435 venv_relative_python = ['Scripts/python.exe']
436 toolchain = ['mingw32']
437 python_pattern_function = lambda major, minor, bits: (
438 '/c/Python{major}{minor}/python.exe'.format(major=major, minor=minor, bits=bits)
439 if bits == '64' else
440 '/c/Python{major}{minor}_{bits}bits/python.exe'.format(
441 major=major, minor=minor, bits=bits))
442 else:
443 shell = []
444 builder = [os.path.abspath('tools/run_tests/build_python.sh')]
445 builder_prefix_arguments = []
446 venv_relative_python = ['bin/python']
447 toolchain = ['unix']
448 # Bit-ness is handled by the test machine's environment
449 python_pattern_function = lambda major, minor, bits: 'python{major}.{minor}'.format(major=major, minor=minor)
450 runner = [os.path.abspath('tools/run_tests/run_python.sh')]
451 python_config_generator = lambda name, major, minor, bits: PythonConfig(
452 name,
453 shell + builder + builder_prefix_arguments
454 + [python_pattern_function(major=major, minor=minor, bits=bits)]
455 + [name] + venv_relative_python + toolchain,
456 shell + runner + [os.path.join(name, venv_relative_python[0])])
457 python27_config = python_config_generator(name='py27', major='2', minor='7', bits=bits)
458 python34_config = python_config_generator(name='py34', major='3', minor='4', bits=bits)
459 if args.compiler == 'default':
460 if os.name == 'nt':
461 return (python27_config,)
462 else:
463 return (python27_config, python34_config,)
464 elif args.compiler == 'python2.7':
Masood Malekghassemi3b5b2062016-06-02 20:27:20 -0700465 return (python27_config,)
Masood Malekghassemicab9d4f2016-06-28 09:09:31 -0700466 elif args.compiler == 'python3.4':
Masood Malekghassemi3b5b2062016-06-02 20:27:20 -0700467 return (python34_config,)
Jan Tattermusch825471c2016-04-25 16:52:25 -0700468 else:
Masood Malekghassemicab9d4f2016-06-28 09:09:31 -0700469 raise Exception('Compiler %s not supported.' % args.compiler)
Jan Tattermusch825471c2016-04-25 16:52:25 -0700470
murgatroid99132ce6a2015-03-04 17:29:14 -0800471 def __str__(self):
472 return 'python'
473
Craig Tillerd625d812015-04-08 15:52:35 -0700474
murgatroid996a4c4fa2015-02-27 12:08:57 -0800475class RubyLanguage(object):
476
Jan Tattermusch77db4322016-02-20 20:19:35 -0800477 def configure(self, config, args):
478 self.config = config
479 self.args = args
480 _check_compiler(self.args.compiler, ['default'])
481
482 def test_specs(self):
Craig Tillereb5e4372016-06-23 16:16:10 -0700483 return [self.config.job_spec(['tools/run_tests/run_ruby.sh'],
Jan Tattermusch77db4322016-02-20 20:19:35 -0800484 timeout_seconds=10*60,
485 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
murgatroid996a4c4fa2015-02-27 12:08:57 -0800486
murgatroid99256d3df2015-09-21 16:58:02 -0700487 def pre_build_steps(self):
Nicolas "Pixel" Noblebcf988f2015-10-08 03:00:42 +0200488 return [['tools/run_tests/pre_build_ruby.sh']]
murgatroid99256d3df2015-09-21 16:58:02 -0700489
Jan Tattermusch4651bef2016-02-23 08:31:25 -0800490 def make_targets(self):
murgatroid997d243df2016-02-18 09:58:05 -0800491 return []
murgatroid996a4c4fa2015-02-27 12:08:57 -0800492
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800493 def make_options(self):
494 return []
495
murgatroid996a4c4fa2015-02-27 12:08:57 -0800496 def build_steps(self):
497 return [['tools/run_tests/build_ruby.sh']]
498
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200499 def post_tests_steps(self):
Nicolas "Pixel" Noble7ef1e532015-12-02 00:55:33 +0100500 return [['tools/run_tests/post_tests_ruby.sh']]
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200501
murgatroid99a3e244f2015-09-22 11:25:53 -0700502 def makefile_name(self):
503 return 'Makefile'
504
Jan Tattermusch77db4322016-02-20 20:19:35 -0800505 def dockerfile_dir(self):
506 return 'tools/dockerfile/test/ruby_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800507
murgatroid99132ce6a2015-03-04 17:29:14 -0800508 def __str__(self):
509 return 'ruby'
510
Craig Tillerd625d812015-04-08 15:52:35 -0700511
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800512class CSharpLanguage(object):
Jan Tattermusch77db4322016-02-20 20:19:35 -0800513
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700514 def __init__(self):
Craig Tillerd50993d2015-08-05 08:04:36 -0700515 self.platform = platform_string()
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700516
Jan Tattermusch77db4322016-02-20 20:19:35 -0800517 def configure(self, config, args):
518 self.config = config
519 self.args = args
Jan Tattermusch6d28d352016-03-25 15:07:22 -0700520 if self.platform == 'windows':
Jan Tattermuschb2531e22016-03-25 16:14:41 -0700521 # Explicitly choosing between x86 and x64 arch doesn't work yet
522 _check_arch(self.args.arch, ['default'])
Jan Tattermusch6e2f88c2016-06-21 10:52:40 -0700523 # CoreCLR use 64bit runtime by default.
524 arch_option = 'x64' if self.args.compiler == 'coreclr' else self.args.arch
Jan Tattermusch6d28d352016-03-25 15:07:22 -0700525 self._make_options = [_windows_toolset_option(self.args.compiler),
Jan Tattermusch6e2f88c2016-06-21 10:52:40 -0700526 _windows_arch_option(arch_option)]
Jan Tattermusch6d28d352016-03-25 15:07:22 -0700527 else:
Jan Tattermuschbc98af12016-06-17 18:38:27 -0700528 _check_compiler(self.args.compiler, ['default', 'coreclr'])
529 if self.platform == 'linux' and self.args.compiler == 'coreclr':
530 self._docker_distro = 'coreclr'
Jan Tattermusch743decd2016-06-21 11:40:47 -0700531 else:
532 self._docker_distro = 'jessie'
Jan Tattermusch76511a52016-06-17 14:00:57 -0700533
Jan Tattermusch6d28d352016-03-25 15:07:22 -0700534 if self.platform == 'mac':
Jan Tattermusch2a322c22016-03-30 13:55:07 -0700535 # TODO(jtattermusch): EMBED_ZLIB=true currently breaks the mac build
Jan Tattermusch6d082202016-06-21 10:03:38 -0700536 self._make_options = ['EMBED_OPENSSL=true']
537 if self.args.compiler != 'coreclr':
538 # On Mac, official distribution of mono is 32bit.
539 self._make_options += ['CFLAGS=-m32', 'LDFLAGS=-m32']
Jan Tattermusch6d28d352016-03-25 15:07:22 -0700540 else:
541 self._make_options = ['EMBED_OPENSSL=true', 'EMBED_ZLIB=true']
Jan Tattermusch77db4322016-02-20 20:19:35 -0800542
543 def test_specs(self):
Jan Tattermusch03c01062015-12-11 14:28:56 -0800544 with open('src/csharp/tests.json') as f:
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700545 tests_by_assembly = json.load(f)
Jan Tattermusch03c01062015-12-11 14:28:56 -0800546
Jan Tattermuscha2d964c2016-02-22 17:33:09 -0800547 msbuild_config = _MSBUILD_CONFIG[self.config.build_config]
Jan Tattermuschbc98af12016-06-17 18:38:27 -0700548 nunit_args = ['--labels=All']
Jan Tattermusch76511a52016-06-17 14:00:57 -0700549 assembly_subdir = 'bin/%s' % msbuild_config
550 assembly_extension = '.exe'
551
552 if self.args.compiler == 'coreclr':
Jan Tattermusch64c137c2016-06-20 17:54:19 -0700553 if self.platform == 'linux':
554 assembly_subdir += '/netstandard1.5/debian.8-x64'
555 assembly_extension = ''
Jan Tattermusch14a301d2016-06-27 17:45:29 -0700556 elif self.platform == 'mac':
Jan Tattermusch6d082202016-06-21 10:03:38 -0700557 assembly_subdir += '/netstandard1.5/osx.10.11-x64'
558 assembly_extension = ''
Jan Tattermusch64c137c2016-06-20 17:54:19 -0700559 else:
560 assembly_subdir += '/netstandard1.5/win7-x64'
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700561 runtime_cmd = []
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700562 else:
Jan Tattermuschbc98af12016-06-17 18:38:27 -0700563 nunit_args += ['--noresult', '--workers=1']
564 if self.platform == 'windows':
565 runtime_cmd = []
566 else:
567 runtime_cmd = ['mono']
Jan Tattermuschbf3b1532015-10-26 10:24:42 -0700568
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700569 specs = []
570 for assembly in tests_by_assembly.iterkeys():
Jan Tattermusch76511a52016-06-17 14:00:57 -0700571 assembly_file = 'src/csharp/%s/%s/%s%s' % (assembly,
572 assembly_subdir,
573 assembly,
574 assembly_extension)
Jan Tattermuscha5f1f122016-04-11 15:49:56 -0700575 if self.config.build_config != 'gcov' or self.platform != 'windows':
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700576 # normally, run each test as a separate process
577 for test in tests_by_assembly[assembly]:
578 cmdline = runtime_cmd + [assembly_file, '--test=%s' % test] + nunit_args
579 specs.append(self.config.job_spec(cmdline,
580 None,
581 shortname='csharp.%s' % test,
582 environ=_FORCE_ENVIRON_FOR_WRAPPERS))
583 else:
Jan Tattermuscha5f1f122016-04-11 15:49:56 -0700584 # For C# test coverage, run all tests from the same assembly at once
585 # using OpenCover.Console (only works on Windows).
586 cmdline = ['src\\csharp\\packages\\OpenCover.4.6.519\\tools\\OpenCover.Console.exe',
587 '-target:%s' % assembly_file,
588 '-targetdir:src\\csharp',
589 '-targetargs:%s' % ' '.join(nunit_args),
590 '-filter:+[Grpc.Core]*',
591 '-register:user',
592 '-output:src\\csharp\\coverage_csharp_%s.xml' % assembly]
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700593
Jan Tattermuscha5f1f122016-04-11 15:49:56 -0700594 # set really high cpu_cost to make sure instances of OpenCover.Console run exclusively
595 # to prevent problems with registering the profiler.
596 run_exclusive = 1000000
Jan Tattermusch35e608f2016-04-09 16:35:06 -0700597 specs.append(self.config.job_spec(cmdline,
598 None,
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700599 shortname='csharp.coverage.%s' % assembly,
Jan Tattermuscha5f1f122016-04-11 15:49:56 -0700600 cpu_cost=run_exclusive,
Jan Tattermusch77db4322016-02-20 20:19:35 -0800601 environ=_FORCE_ENVIRON_FOR_WRAPPERS))
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700602 return specs
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800603
murgatroid99256d3df2015-09-21 16:58:02 -0700604 def pre_build_steps(self):
Jan Tattermusch48423fc2015-10-07 18:59:16 -0700605 if self.platform == 'windows':
Jan Tattermusch874aec02015-10-07 19:26:19 -0700606 return [['tools\\run_tests\\pre_build_csharp.bat']]
Jan Tattermusch48423fc2015-10-07 18:59:16 -0700607 else:
608 return [['tools/run_tests/pre_build_csharp.sh']]
murgatroid99256d3df2015-09-21 16:58:02 -0700609
Jan Tattermusch77db4322016-02-20 20:19:35 -0800610 def make_targets(self):
Jan Tattermusch6d28d352016-03-25 15:07:22 -0700611 return ['grpc_csharp_ext']
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800612
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800613 def make_options(self):
Jan Tattermusch6d28d352016-03-25 15:07:22 -0700614 return self._make_options;
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800615
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800616 def build_steps(self):
Jan Tattermusch76511a52016-06-17 14:00:57 -0700617 if self.args.compiler == 'coreclr':
Jan Tattermuschbc98af12016-06-17 18:38:27 -0700618 if self.platform == 'windows':
619 return [['tools\\run_tests\\build_csharp_coreclr.bat']]
620 else:
621 return [['tools/run_tests/build_csharp_coreclr.sh']]
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700622 else:
Jan Tattermusch76511a52016-06-17 14:00:57 -0700623 if self.platform == 'windows':
624 return [[_windows_build_bat(self.args.compiler),
625 'src/csharp/Grpc.sln',
626 '/p:Configuration=%s' % _MSBUILD_CONFIG[self.config.build_config]]]
627 else:
628 return [['tools/run_tests/build_csharp.sh']]
Nathaniel Manista840615e2015-01-22 20:31:47 +0000629
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200630 def post_tests_steps(self):
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700631 if self.platform == 'windows':
632 return [['tools\\run_tests\\post_tests_csharp.bat']]
633 else:
634 return [['tools/run_tests/post_tests_csharp.sh']]
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200635
murgatroid99a3e244f2015-09-22 11:25:53 -0700636 def makefile_name(self):
637 return 'Makefile'
638
Jan Tattermusch77db4322016-02-20 20:19:35 -0800639 def dockerfile_dir(self):
Jan Tattermusch76511a52016-06-17 14:00:57 -0700640 return 'tools/dockerfile/test/csharp_%s_%s' % (self._docker_distro,
641 _docker_arch_suffix(self.args.arch))
Jan Tattermusch788ee232016-01-26 12:19:44 -0800642
murgatroid99132ce6a2015-03-04 17:29:14 -0800643 def __str__(self):
644 return 'csharp'
645
Craig Tillerd625d812015-04-08 15:52:35 -0700646
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700647class ObjCLanguage(object):
648
Jan Tattermusch77db4322016-02-20 20:19:35 -0800649 def configure(self, config, args):
650 self.config = config
651 self.args = args
652 _check_compiler(self.args.compiler, ['default'])
653
654 def test_specs(self):
Jorge Canizales6ec3b532016-07-01 11:34:32 -0700655 return [self.config.job_spec(['src/objective-c/tests/run_tests.sh'],
656 timeout_seconds=None,
657 shortname='objc-tests',
658 environ=_FORCE_ENVIRON_FOR_WRAPPERS),
Yuchen Zengf95a4892016-06-21 23:27:46 -0700659 self.config.job_spec(['src/objective-c/tests/build_example_test.sh'],
Jorge Canizales6ec3b532016-07-01 11:34:32 -0700660 timeout_seconds=15*60,
661 shortname='objc-examples-build',
Yuchen Zengc0668c82016-06-22 01:30:47 -0700662 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700663
murgatroid99256d3df2015-09-21 16:58:02 -0700664 def pre_build_steps(self):
665 return []
666
Jan Tattermusch77db4322016-02-20 20:19:35 -0800667 def make_targets(self):
Jorge Canizales6eade6d2016-07-11 00:34:14 -0700668 return ['interop_server']
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700669
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800670 def make_options(self):
671 return []
672
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700673 def build_steps(self):
Jorge Canizalesd0b32e92015-07-30 23:08:43 -0700674 return [['src/objective-c/tests/build_tests.sh']]
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700675
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200676 def post_tests_steps(self):
677 return []
678
murgatroid99a3e244f2015-09-22 11:25:53 -0700679 def makefile_name(self):
680 return 'Makefile'
681
Jan Tattermusch77db4322016-02-20 20:19:35 -0800682 def dockerfile_dir(self):
Jan Tattermusch788ee232016-01-26 12:19:44 -0800683 return None
684
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700685 def __str__(self):
686 return 'objc'
687
688
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100689class Sanity(object):
690
Jan Tattermusch77db4322016-02-20 20:19:35 -0800691 def configure(self, config, args):
692 self.config = config
693 self.args = args
694 _check_compiler(self.args.compiler, ['default'])
695
696 def test_specs(self):
Craig Tiller94d04a52016-01-20 10:58:23 -0800697 import yaml
Jan Tattermusch788ee232016-01-26 12:19:44 -0800698 with open('tools/run_tests/sanity/sanity_tests.yaml', 'r') as f:
Craig Tiller34226af2016-06-24 16:46:25 -0700699 return [self.config.job_spec(cmd['script'].split(),
Jan Tattermusch77db4322016-02-20 20:19:35 -0800700 timeout_seconds=None, environ={'TEST': 'true'},
701 cpu_cost=cmd.get('cpu_cost', 1))
Craig Tiller94d04a52016-01-20 10:58:23 -0800702 for cmd in yaml.load(f)]
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100703
murgatroid99256d3df2015-09-21 16:58:02 -0700704 def pre_build_steps(self):
705 return []
706
Jan Tattermusch77db4322016-02-20 20:19:35 -0800707 def make_targets(self):
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100708 return ['run_dep_checks']
709
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800710 def make_options(self):
711 return []
712
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100713 def build_steps(self):
714 return []
715
Nicolas "Pixel" Noble87879b32015-10-12 23:28:53 +0200716 def post_tests_steps(self):
717 return []
718
murgatroid99a3e244f2015-09-22 11:25:53 -0700719 def makefile_name(self):
720 return 'Makefile'
721
Jan Tattermusch77db4322016-02-20 20:19:35 -0800722 def dockerfile_dir(self):
Jan Tattermusche70b3c52016-02-07 20:21:02 -0800723 return 'tools/dockerfile/test/sanity'
Jan Tattermusch788ee232016-01-26 12:19:44 -0800724
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100725 def __str__(self):
726 return 'sanity'
727
Nicolas "Pixel" Noblee55cd7f2015-04-14 17:59:13 +0200728
Craig Tiller738c3342015-01-12 14:28:33 -0800729# different configurations we can run under
Craig Tillera0f85172016-01-20 15:56:06 -0800730with open('tools/run_tests/configs.json') as f:
Craig Tiller1dce9062016-01-20 17:01:56 -0800731 _CONFIGS = dict((cfg['config'], Config(**cfg)) for cfg in ast.literal_eval(f.read()))
Craig Tiller738c3342015-01-12 14:28:33 -0800732
733
Craig Tillerc7449162015-01-16 14:42:10 -0800734_LANGUAGES = {
Craig Tillere9c959d2015-01-18 10:23:26 -0800735 'c++': CLanguage('cxx', 'c++'),
736 'c': CLanguage('c', 'c'),
murgatroid992c8d5162015-01-26 10:41:21 -0800737 'node': NodeLanguage(),
Nathaniel Manista840615e2015-01-22 20:31:47 +0000738 'php': PhpLanguage(),
739 'python': PythonLanguage(),
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800740 'ruby': RubyLanguage(),
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100741 'csharp': CSharpLanguage(),
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700742 'objc' : ObjCLanguage(),
Jan Tattermusch70a57e42016-02-20 18:50:27 -0800743 'sanity': Sanity()
Craig Tillereb272bc2015-01-30 13:13:14 -0800744 }
Nicolas Nobleddef2462015-01-06 18:08:25 -0800745
Jan Tattermusch77db4322016-02-20 20:19:35 -0800746
Jan Tattermuscha2d964c2016-02-22 17:33:09 -0800747_MSBUILD_CONFIG = {
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700748 'dbg': 'Debug',
749 'opt': 'Release',
Jan Tattermusche4a69182015-12-15 09:53:01 -0800750 'gcov': 'Debug',
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700751 }
752
David Garcia Quintase90cd372015-05-31 18:15:26 -0700753
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800754def _windows_arch_option(arch):
755 """Returns msbuild cmdline option for selected architecture."""
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800756 if arch == 'default' or arch == 'x86':
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800757 return '/p:Platform=Win32'
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800758 elif arch == 'x64':
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800759 return '/p:Platform=x64'
760 else:
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800761 print 'Architecture %s not supported.' % arch
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800762 sys.exit(1)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800763
Jan Tattermuschf08018a2016-01-26 08:22:09 -0800764
765def _check_arch_option(arch):
766 """Checks that architecture option is valid."""
767 if platform_string() == 'windows':
768 _windows_arch_option(arch)
769 elif platform_string() == 'linux':
770 # On linux, we need to be running under docker with the right architecture.
Jan Tattermusch07fb0422016-01-26 10:46:56 -0800771 runtime_arch = platform.architecture()[0]
Jan Tattermuschf08018a2016-01-26 08:22:09 -0800772 if arch == 'default':
773 return
774 elif runtime_arch == '64bit' and arch == 'x64':
775 return
776 elif runtime_arch == '32bit' and arch == 'x86':
777 return
778 else:
779 print 'Architecture %s does not match current runtime architecture.' % arch
780 sys.exit(1)
781 else:
782 if args.arch != 'default':
783 print 'Architecture %s not supported on current platform.' % args.arch
784 sys.exit(1)
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800785
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800786
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800787def _windows_build_bat(compiler):
788 """Returns name of build.bat for selected compiler."""
Jan Tattermuschbc98af12016-06-17 18:38:27 -0700789 # For CoreCLR, fall back to the default compiler for C core
790 if compiler == 'default' or compiler == 'vs2013' or compiler == 'coreclr':
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800791 return 'vsprojects\\build_vs2013.bat'
792 elif compiler == 'vs2015':
793 return 'vsprojects\\build_vs2015.bat'
794 elif compiler == 'vs2010':
795 return 'vsprojects\\build_vs2010.bat'
796 else:
797 print 'Compiler %s not supported.' % compiler
798 sys.exit(1)
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800799
800
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800801def _windows_toolset_option(compiler):
802 """Returns msbuild PlatformToolset for selected compiler."""
Jan Tattermuschbc98af12016-06-17 18:38:27 -0700803 # For CoreCLR, fall back to the default compiler for C core
804 if compiler == 'default' or compiler == 'vs2013' or compiler == 'coreclr':
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800805 return '/p:PlatformToolset=v120'
806 elif compiler == 'vs2015':
807 return '/p:PlatformToolset=v140'
808 elif compiler == 'vs2010':
809 return '/p:PlatformToolset=v100'
810 else:
811 print 'Compiler %s not supported.' % compiler
812 sys.exit(1)
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800813
814
Jan Tattermusche70b3c52016-02-07 20:21:02 -0800815def _docker_arch_suffix(arch):
816 """Returns suffix to dockerfile dir to use."""
817 if arch == 'default' or arch == 'x64':
818 return 'x64'
819 elif arch == 'x86':
820 return 'x86'
821 else:
822 print 'Architecture %s not supported with current settings.' % arch
823 sys.exit(1)
824
825
David Garcia Quintase90cd372015-05-31 18:15:26 -0700826def runs_per_test_type(arg_str):
827 """Auxilary function to parse the "runs_per_test" flag.
828
829 Returns:
830 A positive integer or 0, the latter indicating an infinite number of
831 runs.
832
833 Raises:
834 argparse.ArgumentTypeError: Upon invalid input.
835 """
836 if arg_str == 'inf':
837 return 0
838 try:
839 n = int(arg_str)
840 if n <= 0: raise ValueError
Craig Tiller50e53e22015-06-01 20:18:21 -0700841 return n
David Garcia Quintase90cd372015-05-31 18:15:26 -0700842 except:
Adele Zhoue4c35612015-10-16 15:34:23 -0700843 msg = '\'{}\' is not a positive integer or \'inf\''.format(arg_str)
David Garcia Quintase90cd372015-05-31 18:15:26 -0700844 raise argparse.ArgumentTypeError(msg)
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700845
846# parse command line
847argp = argparse.ArgumentParser(description='Run grpc tests.')
848argp.add_argument('-c', '--config',
Jan Tattermusch77db4322016-02-20 20:19:35 -0800849 choices=sorted(_CONFIGS.keys()),
850 default='opt')
David Garcia Quintase90cd372015-05-31 18:15:26 -0700851argp.add_argument('-n', '--runs_per_test', default=1, type=runs_per_test_type,
852 help='A positive integer or "inf". If "inf", all tests will run in an '
853 'infinite loop. Especially useful in combination with "-f"')
Craig Tillerfe406ec2015-02-24 13:55:12 -0800854argp.add_argument('-r', '--regex', default='.*', type=str)
Vijay Pai488fd0e2016-06-13 12:37:12 -0700855argp.add_argument('--regex_exclude', default='', type=str)
Craig Tiller5f735a62016-01-20 09:31:15 -0800856argp.add_argument('-j', '--jobs', default=multiprocessing.cpu_count(), type=int)
Craig Tiller8451e872015-02-27 09:25:51 -0800857argp.add_argument('-s', '--slowdown', default=1.0, type=float)
ctiller3040cb72015-01-07 12:13:17 -0800858argp.add_argument('-f', '--forever',
859 default=False,
860 action='store_const',
861 const=True)
Nicolas "Pixel" Noblea7df3f92015-02-26 22:07:04 +0100862argp.add_argument('-t', '--travis',
863 default=False,
864 action='store_const',
865 const=True)
Nicolas Noble044db742015-01-14 16:57:24 -0800866argp.add_argument('--newline_on_success',
867 default=False,
868 action='store_const',
869 const=True)
Craig Tiller686fb262015-01-15 07:39:09 -0800870argp.add_argument('-l', '--language',
Craig Tiller60f15e62015-05-13 09:05:17 -0700871 choices=['all'] + sorted(_LANGUAGES.keys()),
Craig Tiller686fb262015-01-15 07:39:09 -0800872 nargs='+',
Craig Tiller60f15e62015-05-13 09:05:17 -0700873 default=['all'])
Craig Tillercd43da82015-05-29 08:41:29 -0700874argp.add_argument('-S', '--stop_on_failure',
875 default=False,
876 action='store_const',
877 const=True)
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700878argp.add_argument('--use_docker',
879 default=False,
880 action='store_const',
881 const=True,
Adele Zhoue4c35612015-10-16 15:34:23 -0700882 help='Run all the tests under docker. That provides ' +
883 'additional isolation and prevents the need to install ' +
884 'language specific prerequisites. Only available on Linux.')
Craig Tillerd4509a12015-09-28 09:18:40 -0700885argp.add_argument('--allow_flakes',
886 default=False,
887 action='store_const',
888 const=True,
Adele Zhoue4c35612015-10-16 15:34:23 -0700889 help='Allow flaky tests to show as passing (re-runs failed tests up to five times)')
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800890argp.add_argument('--arch',
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800891 choices=['default', 'x86', 'x64'],
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800892 default='default',
893 help='Selects architecture to target. For some platforms "default" is the only supported choice.')
894argp.add_argument('--compiler',
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800895 choices=['default',
Jan Tattermusch6d258c52016-06-10 09:36:51 -0700896 'gcc4.4', 'gcc4.6', 'gcc4.9', 'gcc5.3',
897 'clang3.4', 'clang3.5', 'clang3.6', 'clang3.7',
Jan Tattermusch825471c2016-04-25 16:52:25 -0700898 'vs2010', 'vs2013', 'vs2015',
murgatroid999fab4382016-04-29 15:05:00 -0700899 'python2.7', 'python3.4',
Jan Tattermusch76511a52016-06-17 14:00:57 -0700900 'node0.12', 'node4', 'node5',
901 'coreclr'],
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800902 default='default',
Jan Tattermusch77db4322016-02-20 20:19:35 -0800903 help='Selects compiler to use. Allowed values depend on the platform and language.')
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800904argp.add_argument('--build_only',
905 default=False,
906 action='store_const',
907 const=True,
908 help='Perform all the build steps but dont run any tests.')
Craig Tiller5f735a62016-01-20 09:31:15 -0800909argp.add_argument('--measure_cpu_costs', default=False, action='store_const', const=True,
910 help='Measure the cpu costs of tests')
Craig Tiller1676f912016-01-05 10:49:44 -0800911argp.add_argument('--update_submodules', default=[], nargs='*',
912 help='Update some submodules before building. If any are updated, also run generate_projects. ' +
913 'Submodules are specified as SUBMODULE_NAME:BRANCH; if BRANCH is omitted, master is assumed.')
Craig Tiller234b6e72015-05-23 10:12:40 -0700914argp.add_argument('-a', '--antagonists', default=0, type=int)
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +0200915argp.add_argument('-x', '--xml_report', default=None, type=str,
916 help='Generates a JUnit-compatible XML report')
Craig Tiller123f1372016-06-15 15:06:14 -0700917argp.add_argument('--force_default_poller', default=False, action='store_const', const=True,
918 help='Dont try to iterate over many polling strategies when they exist')
Nicolas Nobleddef2462015-01-06 18:08:25 -0800919args = argp.parse_args()
920
Craig Tiller123f1372016-06-15 15:06:14 -0700921if args.force_default_poller:
922 _POLLING_STRATEGIES = {}
923
Craig Tiller5f735a62016-01-20 09:31:15 -0800924jobset.measure_cpu_costs = args.measure_cpu_costs
925
Craig Tiller1676f912016-01-05 10:49:44 -0800926# update submodules if necessary
Craig Tillerb361b4e2016-01-06 11:44:17 -0800927need_to_regenerate_projects = False
928for spec in args.update_submodules:
929 spec = spec.split(':', 1)
930 if len(spec) == 1:
931 submodule = spec[0]
932 branch = 'master'
933 elif len(spec) == 2:
934 submodule = spec[0]
935 branch = spec[1]
936 cwd = 'third_party/%s' % submodule
937 def git(cmd, cwd=cwd):
938 print 'in %s: git %s' % (cwd, cmd)
939 subprocess.check_call('git %s' % cmd, cwd=cwd, shell=True)
940 git('fetch')
941 git('checkout %s' % branch)
942 git('pull origin %s' % branch)
943 if os.path.exists('src/%s/gen_build_yaml.py' % submodule):
944 need_to_regenerate_projects = True
945if need_to_regenerate_projects:
946 if jobset.platform_string() == 'linux':
947 subprocess.check_call('tools/buildgen/generate_projects.sh', shell=True)
948 else:
949 print 'WARNING: may need to regenerate projects, but since we are not on'
950 print ' Linux this step is being skipped. Compilation MAY fail.'
Craig Tiller1676f912016-01-05 10:49:44 -0800951
952
Nicolas Nobleddef2462015-01-06 18:08:25 -0800953# grab config
Jan Tattermusch77db4322016-02-20 20:19:35 -0800954run_config = _CONFIGS[args.config]
955build_config = run_config.build_config
Craig Tillerf1973b02015-01-16 12:32:13 -0800956
Craig Tiller06805272015-06-11 14:46:47 -0700957if args.travis:
murgatroid99d3b5b7f2015-10-06 17:02:03 -0700958 _FORCE_ENVIRON_FOR_WRAPPERS = {'GRPC_TRACE': 'api'}
Craig Tiller06805272015-06-11 14:46:47 -0700959
Adele Zhou6b9527c2015-11-20 15:56:35 -0800960if 'all' in args.language:
Craig Tiller1676f912016-01-05 10:49:44 -0800961 lang_list = _LANGUAGES.keys()
Adele Zhou6b9527c2015-11-20 15:56:35 -0800962else:
963 lang_list = args.language
Craig Tiller16900662016-01-07 19:30:54 -0800964# We don't support code coverage on some languages
965if 'gcov' in args.config:
Jan Tattermusch3b5121b2016-02-22 17:41:05 -0800966 for bad in ['objc', 'sanity']:
Craig Tiller16900662016-01-07 19:30:54 -0800967 if bad in lang_list:
968 lang_list.remove(bad)
Adele Zhou6b9527c2015-11-20 15:56:35 -0800969
970languages = set(_LANGUAGES[l] for l in lang_list)
Jan Tattermusch77db4322016-02-20 20:19:35 -0800971for l in languages:
972 l.configure(run_config, args)
murgatroid99132ce6a2015-03-04 17:29:14 -0800973
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800974language_make_options=[]
975if any(language.make_options() for language in languages):
Adele Zhou3b6ab812016-05-18 17:04:20 -0700976 if not 'gcov' in args.config and len(languages) != 1:
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800977 print 'languages with custom make options cannot be built simultaneously with other languages'
978 sys.exit(1)
979 else:
980 language_make_options = next(iter(languages)).make_options()
981
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800982if args.use_docker:
983 if not args.travis:
984 print 'Seen --use_docker flag, will run tests under docker.'
985 print
986 print 'IMPORTANT: The changes you are testing need to be locally committed'
987 print 'because only the committed changes in the current branch will be'
988 print 'copied to the docker environment.'
989 time.sleep(5)
990
Jan Tattermusch3b5121b2016-02-22 17:41:05 -0800991 dockerfile_dirs = set([l.dockerfile_dir() for l in languages])
992 if len(dockerfile_dirs) > 1:
Adele Zhou9506ef22016-03-02 13:53:34 -0800993 if 'gcov' in args.config:
994 dockerfile_dir = 'tools/dockerfile/test/multilang_jessie_x64'
995 print ('Using multilang_jessie_x64 docker image for code coverage for '
996 'all languages.')
997 else:
998 print ('Languages to be tested require running under different docker '
999 'images.')
1000 sys.exit(1)
1001 else:
1002 dockerfile_dir = next(iter(dockerfile_dirs))
Craig Tillerde7edf82016-03-20 09:12:16 -07001003
Jan Tattermusch4dc9e722016-01-25 17:00:54 -08001004 child_argv = [ arg for arg in sys.argv if not arg == '--use_docker' ]
Jan Tattermusched342b12016-01-26 14:40:31 -08001005 run_tests_cmd = 'python tools/run_tests/run_tests.py %s' % ' '.join(child_argv[1:])
Jan Tattermusch4dc9e722016-01-25 17:00:54 -08001006
Jan Tattermusch4dc9e722016-01-25 17:00:54 -08001007 env = os.environ.copy()
1008 env['RUN_TESTS_COMMAND'] = run_tests_cmd
Jan Tattermusch3b5121b2016-02-22 17:41:05 -08001009 env['DOCKERFILE_DIR'] = dockerfile_dir
Jan Tattermusch9835d4b2016-04-29 15:05:05 -07001010 env['DOCKER_RUN_SCRIPT'] = 'tools/run_tests/dockerize/docker_run_tests.sh'
Jan Tattermusch4dc9e722016-01-25 17:00:54 -08001011 if args.xml_report:
1012 env['XML_REPORT'] = args.xml_report
1013 if not args.travis:
1014 env['TTY_FLAG'] = '-t' # enables Ctrl-C when not on Jenkins.
1015
Jan Tattermusch9835d4b2016-04-29 15:05:05 -07001016 subprocess.check_call(['tools/run_tests/dockerize/build_docker_and_run_tests.sh'],
Jan Tattermusch4dc9e722016-01-25 17:00:54 -08001017 shell=True,
1018 env=env)
1019 sys.exit(0)
Jan Tattermusch788ee232016-01-26 12:19:44 -08001020
Jan Tattermuschf08018a2016-01-26 08:22:09 -08001021_check_arch_option(args.arch)
Jan Tattermusch4dc9e722016-01-25 17:00:54 -08001022
Jan Tattermuschfba65302016-01-25 18:21:14 -08001023def make_jobspec(cfg, targets, makefile='Makefile'):
1024 if platform_string() == 'windows':
Craig Tillerfc3c0c42015-09-01 16:47:54 -07001025 extra_args = []
Craig Tillerb5391e12015-09-03 14:35:18 -07001026 # better do parallel compilation
Jan Tattermusch47eeb2b2015-10-07 14:09:18 -07001027 # empirically /m:2 gives the best performance/price and should prevent
1028 # overloading the windows workers.
Adele Zhoue4c35612015-10-16 15:34:23 -07001029 extra_args.extend(['/m:2'])
Craig Tillerb5391e12015-09-03 14:35:18 -07001030 # disable PDB generation: it's broken, and we don't need it during CI
Adele Zhoue4c35612015-10-16 15:34:23 -07001031 extra_args.extend(['/p:Jenkins=true'])
Craig Tiller6fd23842015-09-01 07:36:31 -07001032 return [
Jan Tattermusch2dd156e2015-12-04 18:26:17 -08001033 jobset.JobSpec([_windows_build_bat(args.compiler),
murgatroid99cf08daf2015-09-21 15:33:16 -07001034 'vsprojects\\%s.sln' % target,
Jan Tattermuscha2d964c2016-02-22 17:33:09 -08001035 '/p:Configuration=%s' % _MSBUILD_CONFIG[cfg]] +
Jan Tattermuschc895fe02016-01-20 09:13:09 -08001036 extra_args +
1037 language_make_options,
Craig Tiller590105a2016-01-19 13:03:46 -08001038 shell=True, timeout_seconds=None)
Craig Tiller6fd23842015-09-01 07:36:31 -07001039 for target in targets]
Jan Tattermuschfba65302016-01-25 18:21:14 -08001040 else:
murgatroid998ae409f2015-10-26 16:39:00 -07001041 if targets:
1042 return [jobset.JobSpec([os.getenv('MAKE', 'make'),
1043 '-f', makefile,
Craig Tillerdd6f7ed2016-01-21 12:54:42 -08001044 '-j', '%d' % args.jobs,
Craig Tiller71a86042016-01-15 14:59:58 -08001045 'EXTRA_DEFINES=GRPC_TEST_SLOWDOWN_MACHINE_FACTOR=%f' % args.slowdown,
1046 'CONFIG=%s' % cfg] +
Jan Tattermuschc895fe02016-01-20 09:13:09 -08001047 language_make_options +
Craig Tiller71a86042016-01-15 14:59:58 -08001048 ([] if not args.travis else ['JENKINS_BUILD=1']) +
1049 targets,
Craig Tiller590105a2016-01-19 13:03:46 -08001050 timeout_seconds=None)]
murgatroid998ae409f2015-10-26 16:39:00 -07001051 else:
1052 return []
Jan Tattermuschfba65302016-01-25 18:21:14 -08001053
murgatroid99a3e244f2015-09-22 11:25:53 -07001054make_targets = {}
1055for l in languages:
1056 makefile = l.makefile_name()
1057 make_targets[makefile] = make_targets.get(makefile, set()).union(
Jan Tattermusch77db4322016-02-20 20:19:35 -08001058 set(l.make_targets()))
Craig Tiller5058c692015-04-08 09:42:04 -07001059
Jan Tattermusche4a69182015-12-15 09:53:01 -08001060def build_step_environ(cfg):
1061 environ = {'CONFIG': cfg}
Jan Tattermuscha2d964c2016-02-22 17:33:09 -08001062 msbuild_cfg = _MSBUILD_CONFIG.get(cfg)
Jan Tattermusche4a69182015-12-15 09:53:01 -08001063 if msbuild_cfg:
1064 environ['MSBUILD_CONFIG'] = msbuild_cfg
1065 return environ
1066
murgatroid99fddac962015-09-22 09:20:11 -07001067build_steps = list(set(
Jan Tattermusch77db4322016-02-20 20:19:35 -08001068 jobset.JobSpec(cmdline, environ=build_step_environ(build_config), flake_retries=5)
murgatroid99256d3df2015-09-21 16:58:02 -07001069 for l in languages
1070 for cmdline in l.pre_build_steps()))
Craig Tillerbd4e3782015-09-01 06:48:55 -07001071if make_targets:
Jan Tattermusch77db4322016-02-20 20:19:35 -08001072 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 -07001073 build_steps.extend(set(make_commands))
Craig Tiller5058c692015-04-08 09:42:04 -07001074build_steps.extend(set(
Jan Tattermusch77db4322016-02-20 20:19:35 -08001075 jobset.JobSpec(cmdline, environ=build_step_environ(build_config), timeout_seconds=None)
Craig Tiller547db2b2015-01-30 14:08:39 -08001076 for l in languages
Craig Tiller533b1a22015-05-29 08:41:29 -07001077 for cmdline in l.build_steps()))
Craig Tillerf1973b02015-01-16 12:32:13 -08001078
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +02001079post_tests_steps = list(set(
Jan Tattermusch77db4322016-02-20 20:19:35 -08001080 jobset.JobSpec(cmdline, environ=build_step_environ(build_config))
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +02001081 for l in languages
1082 for cmdline in l.post_tests_steps()))
Nicolas Nobleddef2462015-01-06 18:08:25 -08001083runs_per_test = args.runs_per_test
ctiller3040cb72015-01-07 12:13:17 -08001084forever = args.forever
Nicolas Nobleddef2462015-01-06 18:08:25 -08001085
Nicolas Nobleddef2462015-01-06 18:08:25 -08001086
Ken Paysonfa51de52016-06-30 23:50:48 -07001087def _shut_down_legacy_server(legacy_server_port):
1088 try:
1089 version = int(urllib2.urlopen(
1090 'http://localhost:%d/version_number' % legacy_server_port,
1091 timeout=10).read())
1092 except:
1093 pass
1094 else:
1095 urllib2.urlopen(
1096 'http://localhost:%d/quitquitquit' % legacy_server_port).read()
1097
1098
Ken Paysond9dfc672016-06-30 23:50:48 -07001099def _shut_down_legacy_server(legacy_server_port):
1100 try:
1101 version = int(urllib2.urlopen(
1102 'http://localhost:%d/version_number' % legacy_server_port,
1103 timeout=10).read())
1104 except:
1105 pass
1106 else:
1107 urllib2.urlopen(
1108 'http://localhost:%d/quitquitquit' % legacy_server_port).read()
1109
1110
Craig Tillerf53d9c82015-08-04 14:19:43 -07001111def _start_port_server(port_server_port):
1112 # check if a compatible port server is running
1113 # if incompatible (version mismatch) ==> start a new one
1114 # if not running ==> start a new one
1115 # otherwise, leave it up
1116 try:
Craig Tillerfe4939f2015-10-06 12:55:36 -07001117 version = int(urllib2.urlopen(
1118 'http://localhost:%d/version_number' % port_server_port,
Jan Tattermusch292d0102016-06-28 10:29:41 -07001119 timeout=10).read())
Craig Tillerfe4939f2015-10-06 12:55:36 -07001120 print 'detected port server running version %d' % version
Craig Tillerf53d9c82015-08-04 14:19:43 -07001121 running = True
Craig Tillerfe4939f2015-10-06 12:55:36 -07001122 except Exception as e:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001123 print 'failed to detect port server: %s' % sys.exc_info()[0]
Craig Tillerfe4939f2015-10-06 12:55:36 -07001124 print e.strerror
Craig Tillerf53d9c82015-08-04 14:19:43 -07001125 running = False
1126 if running:
Craig Tillerfe4939f2015-10-06 12:55:36 -07001127 current_version = int(subprocess.check_output(
Jan Tattermusch3bd08272015-11-04 19:24:37 -08001128 [sys.executable, os.path.abspath('tools/run_tests/port_server.py'),
1129 'dump_version']))
Craig Tillerfe4939f2015-10-06 12:55:36 -07001130 print 'my port server is version %d' % current_version
1131 running = (version >= current_version)
1132 if not running:
1133 print 'port_server version mismatch: killing the old one'
1134 urllib2.urlopen('http://localhost:%d/quitquitquit' % port_server_port).read()
1135 time.sleep(1)
Craig Tillerf53d9c82015-08-04 14:19:43 -07001136 if not running:
Craig Tillerf0a293e2015-10-12 10:05:50 -07001137 fd, logfile = tempfile.mkstemp()
1138 os.close(fd)
1139 print 'starting port_server, with log file %s' % logfile
Jan Tattermusch3bd08272015-11-04 19:24:37 -08001140 args = [sys.executable, os.path.abspath('tools/run_tests/port_server.py'),
1141 '-p', '%d' % port_server_port, '-l', logfile]
Craig Tiller367d41d2015-10-12 13:00:22 -07001142 env = dict(os.environ)
1143 env['BUILD_ID'] = 'pleaseDontKillMeJenkins'
Nicolas "Pixel" Noblef72d7b52015-12-03 03:07:43 +01001144 if platform_string() == 'windows':
Jan Tattermusch3bd08272015-11-04 19:24:37 -08001145 # Working directory of port server needs to be outside of Jenkins
1146 # workspace to prevent file lock issues.
1147 tempdir = tempfile.mkdtemp()
Craig Tillerd2c39712015-10-12 11:08:49 -07001148 port_server = subprocess.Popen(
Craig Tiller367d41d2015-10-12 13:00:22 -07001149 args,
1150 env=env,
Jan Tattermusch3bd08272015-11-04 19:24:37 -08001151 cwd=tempdir,
Craig Tiller367d41d2015-10-12 13:00:22 -07001152 creationflags = 0x00000008, # detached process
1153 close_fds=True)
Craig Tillerd2c39712015-10-12 11:08:49 -07001154 else:
1155 port_server = subprocess.Popen(
1156 args,
Craig Tiller367d41d2015-10-12 13:00:22 -07001157 env=env,
Craig Tillerd2c39712015-10-12 11:08:49 -07001158 preexec_fn=os.setsid,
1159 close_fds=True)
Craig Tillerf0a293e2015-10-12 10:05:50 -07001160 time.sleep(1)
Craig Tiller8b5f4dc2015-08-26 08:02:01 -07001161 # ensure port server is up
Craig Tillerabd37fd2015-08-26 07:54:01 -07001162 waits = 0
Craig Tillerf53d9c82015-08-04 14:19:43 -07001163 while True:
Craig Tillerabd37fd2015-08-26 07:54:01 -07001164 if waits > 10:
Craig Tillerf0a293e2015-10-12 10:05:50 -07001165 print 'killing port server due to excessive start up waits'
Craig Tillerabd37fd2015-08-26 07:54:01 -07001166 port_server.kill()
Craig Tillera2f38b02015-09-24 11:19:17 -07001167 if port_server.poll() is not None:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001168 print 'port_server failed to start'
Craig Tillerf0a293e2015-10-12 10:05:50 -07001169 # try one final time: maybe another build managed to start one
1170 time.sleep(1)
1171 try:
1172 urllib2.urlopen('http://localhost:%d/get' % port_server_port,
1173 timeout=1).read()
1174 print 'last ditch attempt to contact port server succeeded'
1175 break
1176 except:
Jan Tattermusch3b5121b2016-02-22 17:41:05 -08001177 traceback.print_exc()
Craig Tillerf0a293e2015-10-12 10:05:50 -07001178 port_log = open(logfile, 'r').read()
1179 print port_log
1180 sys.exit(1)
Craig Tillerf53d9c82015-08-04 14:19:43 -07001181 try:
Craig Tillerabd37fd2015-08-26 07:54:01 -07001182 urllib2.urlopen('http://localhost:%d/get' % port_server_port,
1183 timeout=1).read()
Craig Tillerf0a293e2015-10-12 10:05:50 -07001184 print 'port server is up and ready'
Craig Tillerf53d9c82015-08-04 14:19:43 -07001185 break
Craig Tiller31fdaa42015-09-25 13:09:59 -07001186 except socket.timeout:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001187 print 'waiting for port_server: timeout'
Craig Tillerf0a293e2015-10-12 10:05:50 -07001188 traceback.print_exc();
1189 time.sleep(1)
Craig Tiller31fdaa42015-09-25 13:09:59 -07001190 waits += 1
Craig Tillerf53d9c82015-08-04 14:19:43 -07001191 except urllib2.URLError:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001192 print 'waiting for port_server: urlerror'
Craig Tillerf0a293e2015-10-12 10:05:50 -07001193 traceback.print_exc();
1194 time.sleep(1)
Craig Tillerabd37fd2015-08-26 07:54:01 -07001195 waits += 1
Craig Tillerf53d9c82015-08-04 14:19:43 -07001196 except:
Jan Tattermusch3b5121b2016-02-22 17:41:05 -08001197 traceback.print_exc()
Craig Tillerf53d9c82015-08-04 14:19:43 -07001198 port_server.kill()
1199 raise
1200
1201
Adele Zhoud5fffa52015-10-23 15:51:42 -07001202def _calculate_num_runs_failures(list_of_results):
1203 """Caculate number of runs and failures for a particular test.
1204
1205 Args:
1206 list_of_results: (List) of JobResult object.
1207 Returns:
1208 A tuple of total number of runs and failures.
1209 """
1210 num_runs = len(list_of_results) # By default, there is 1 run per JobResult.
1211 num_failures = 0
1212 for jobresult in list_of_results:
1213 if jobresult.retries > 0:
1214 num_runs += jobresult.retries
1215 if jobresult.num_failures > 0:
1216 num_failures += jobresult.num_failures
1217 return num_runs, num_failures
1218
Adele Zhou6b9527c2015-11-20 15:56:35 -08001219
Craig Tillereb9de8b2016-01-08 08:57:41 -08001220# _build_and_run results
1221class BuildAndRunError(object):
1222
1223 BUILD = object()
1224 TEST = object()
1225 POST_TEST = object()
1226
1227
1228# returns a list of things that failed (or an empty list on success)
Craig Tillerf53d9c82015-08-04 14:19:43 -07001229def _build_and_run(
Craig Tiller74189cd2016-06-23 15:39:06 -07001230 check_cancelled, newline_on_success, xml_report=None, build_only=False):
ctiller3040cb72015-01-07 12:13:17 -08001231 """Do one pass of building & running tests."""
murgatroid99666450e2015-01-26 13:03:31 -08001232 # build latest sequentially
Jan Tattermuschaab1e512016-01-28 09:30:44 -08001233 num_failures, resultset = jobset.run(
Adele Zhoue4c35612015-10-16 15:34:23 -07001234 build_steps, maxjobs=1, stop_on_failure=True,
Craig Tiller883064c2015-11-04 10:06:10 -08001235 newline_on_success=newline_on_success, travis=args.travis)
Adele Zhoue4c35612015-10-16 15:34:23 -07001236 if num_failures:
Craig Tillereb9de8b2016-01-08 08:57:41 -08001237 return [BuildAndRunError.BUILD]
Craig Tillerb361b4e2016-01-06 11:44:17 -08001238
Jan Tattermusch2dd156e2015-12-04 18:26:17 -08001239 if build_only:
Jan Tattermuschaab1e512016-01-28 09:30:44 -08001240 if xml_report:
1241 report_utils.render_junit_xml_report(resultset, xml_report)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001242 return []
ctiller3040cb72015-01-07 12:13:17 -08001243
Craig Tiller234b6e72015-05-23 10:12:40 -07001244 # start antagonists
David Garcia Quintas79e389f2015-06-02 17:49:42 -07001245 antagonists = [subprocess.Popen(['tools/run_tests/antagonist.py'])
Craig Tiller234b6e72015-05-23 10:12:40 -07001246 for _ in range(0, args.antagonists)]
Ken Paysonfa51de52016-06-30 23:50:48 -07001247 port_server_port = 32766
Craig Tillerf53d9c82015-08-04 14:19:43 -07001248 _start_port_server(port_server_port)
Adele Zhou7cf72112015-11-04 11:18:43 -08001249 resultset = None
Adele Zhou803af152015-11-30 15:16:16 -08001250 num_test_failures = 0
Craig Tiller234b6e72015-05-23 10:12:40 -07001251 try:
David Garcia Quintase90cd372015-05-31 18:15:26 -07001252 infinite_runs = runs_per_test == 0
yang-g6c1fdc62015-08-18 11:57:42 -07001253 one_run = set(
1254 spec
yang-g6c1fdc62015-08-18 11:57:42 -07001255 for language in languages
Jan Tattermusch77db4322016-02-20 20:19:35 -08001256 for spec in language.test_specs()
Vijay Pai488fd0e2016-06-13 12:37:12 -07001257 if (re.search(args.regex, spec.shortname) and
1258 (args.regex_exclude == '' or
1259 not re.search(args.regex_exclude, spec.shortname))))
David Garcia Quintas79e389f2015-06-02 17:49:42 -07001260 # When running on travis, we want out test runs to be as similar as possible
1261 # for reproducibility purposes.
Craig Tiller883064c2015-11-04 10:06:10 -08001262 if args.travis:
David Garcia Quintas79e389f2015-06-02 17:49:42 -07001263 massaged_one_run = sorted(one_run, key=lambda x: x.shortname)
1264 else:
1265 # whereas otherwise, we want to shuffle things up to give all tests a
1266 # chance to run.
1267 massaged_one_run = list(one_run) # random.shuffle needs an indexable seq.
1268 random.shuffle(massaged_one_run) # which it modifies in-place.
Craig Tillerf7b7c892015-06-22 14:33:25 -07001269 if infinite_runs:
1270 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 -07001271 runs_sequence = (itertools.repeat(massaged_one_run) if infinite_runs
1272 else itertools.repeat(massaged_one_run, runs_per_test))
David Garcia Quintase90cd372015-05-31 18:15:26 -07001273 all_runs = itertools.chain.from_iterable(runs_sequence)
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +02001274
Adele Zhou803af152015-11-30 15:16:16 -08001275 num_test_failures, resultset = jobset.run(
Adele Zhou2271ab52015-10-28 13:59:14 -07001276 all_runs, check_cancelled, newline_on_success=newline_on_success,
Craig Tiller883064c2015-11-04 10:06:10 -08001277 travis=args.travis, infinite_runs=infinite_runs, maxjobs=args.jobs,
murgatroid998ae409f2015-10-26 16:39:00 -07001278 stop_on_failure=args.stop_on_failure,
Adele Zhouf2ca7bc2015-10-23 15:38:00 -07001279 add_env={'GRPC_TEST_PORT_SERVER': 'localhost:%d' % port_server_port})
Adele Zhoud5fffa52015-10-23 15:51:42 -07001280 if resultset:
Craig Tiller2b59dbc2016-05-13 15:59:09 -07001281 for k, v in sorted(resultset.items()):
Adele Zhoud5fffa52015-10-23 15:51:42 -07001282 num_runs, num_failures = _calculate_num_runs_failures(v)
1283 if num_failures == num_runs: # what about infinite_runs???
1284 jobset.message('FAILED', k, do_newline=True)
1285 elif num_failures > 0:
1286 jobset.message(
1287 'FLAKE', '%s [%d/%d runs flaked]' % (k, num_failures, num_runs),
1288 do_newline=True)
1289 else:
1290 jobset.message('PASSED', k, do_newline=True)
Craig Tiller234b6e72015-05-23 10:12:40 -07001291 finally:
1292 for antagonist in antagonists:
1293 antagonist.kill()
Adele Zhou7cf72112015-11-04 11:18:43 -08001294 if xml_report and resultset:
Adele Zhou3bc7ba42015-11-05 10:21:58 -08001295 report_utils.render_junit_xml_report(resultset, xml_report)
Craig Tillerd86a3942015-01-14 12:48:54 -08001296
Adele Zhouf2ca7bc2015-10-23 15:38:00 -07001297 number_failures, _ = jobset.run(
1298 post_tests_steps, maxjobs=1, stop_on_failure=True,
Craig Tiller883064c2015-11-04 10:06:10 -08001299 newline_on_success=newline_on_success, travis=args.travis)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001300
1301 out = []
1302 if number_failures:
1303 out.append(BuildAndRunError.POST_TEST)
1304 if num_test_failures:
1305 out.append(BuildAndRunError.TEST)
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +02001306
Craig Tillereb9de8b2016-01-08 08:57:41 -08001307 return out
ctiller3040cb72015-01-07 12:13:17 -08001308
1309
1310if forever:
Nicolas Noble044db742015-01-14 16:57:24 -08001311 success = True
ctiller3040cb72015-01-07 12:13:17 -08001312 while True:
Craig Tiller42bc87c2015-02-23 08:50:19 -08001313 dw = watch_dirs.DirWatcher(['src', 'include', 'test', 'examples'])
ctiller3040cb72015-01-07 12:13:17 -08001314 initial_time = dw.most_recent_change()
1315 have_files_changed = lambda: dw.most_recent_change() != initial_time
Nicolas Noble044db742015-01-14 16:57:24 -08001316 previous_success = success
Craig Tillereb9de8b2016-01-08 08:57:41 -08001317 errors = _build_and_run(check_cancelled=have_files_changed,
1318 newline_on_success=False,
Craig Tillereb9de8b2016-01-08 08:57:41 -08001319 build_only=args.build_only) == 0
1320 if not previous_success and not errors:
Nicolas Nobleb09078f2015-01-14 18:06:05 -08001321 jobset.message('SUCCESS',
1322 'All tests are now passing properly',
1323 do_newline=True)
Nicolas Noble044db742015-01-14 16:57:24 -08001324 jobset.message('IDLE', 'No change detected')
ctiller3040cb72015-01-07 12:13:17 -08001325 while not have_files_changed():
1326 time.sleep(1)
1327else:
Craig Tillereb9de8b2016-01-08 08:57:41 -08001328 errors = _build_and_run(check_cancelled=lambda: False,
Craig Tiller71735182015-01-15 17:07:13 -08001329 newline_on_success=args.newline_on_success,
Jan Tattermusch2dd156e2015-12-04 18:26:17 -08001330 xml_report=args.xml_report,
1331 build_only=args.build_only)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001332 if not errors:
Nicolas Nobleb09078f2015-01-14 18:06:05 -08001333 jobset.message('SUCCESS', 'All tests passed', do_newline=True)
1334 else:
1335 jobset.message('FAILED', 'Some tests failed', do_newline=True)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001336 exit_code = 0
1337 if BuildAndRunError.BUILD in errors:
1338 exit_code |= 1
Craig Tiller4f2be362016-01-08 08:59:20 -08001339 if BuildAndRunError.TEST in errors and not args.travis:
Craig Tillereb9de8b2016-01-08 08:57:41 -08001340 exit_code |= 2
Craig Tiller4f2be362016-01-08 08:59:20 -08001341 if BuildAndRunError.POST_TEST in errors:
1342 exit_code |= 4
Craig Tillereb9de8b2016-01-08 08:57:41 -08001343 sys.exit(exit_code)