blob: 6cbdca3e732c300eeec9e351a0a2b6a6cb61bcbe [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', [
Masood Malekghassemicab9d4f2016-06-28 09:09:31 -0700378 'name', 'build', 'run'])):
379 """Tuple of commands (named s.t. 'what it says on the tin' applies)"""
Masood Malekghassemi3b5b2062016-06-02 20:27:20 -0700380
Nathaniel Manista840615e2015-01-22 20:31:47 +0000381class PythonLanguage(object):
382
Jan Tattermusch77db4322016-02-20 20:19:35 -0800383 def configure(self, config, args):
384 self.config = config
385 self.args = args
Masood Malekghassemicab9d4f2016-06-28 09:09:31 -0700386 self.pythons = self._get_pythons(self.args)
Jan Tattermusch77db4322016-02-20 20:19:35 -0800387
388 def test_specs(self):
Jan Tattermusch072ebaa2016-03-01 18:33:12 -0800389 # load list of known test suites
Masood Malekghassemi1ff429d2016-06-02 16:39:20 -0700390 with open('src/python/grpcio_tests/tests/tests.json') as tests_json_file:
Jan Tattermusch072ebaa2016-03-01 18:33:12 -0800391 tests_json = json.load(tests_json_file)
Masood Malekghassemi2b841622015-07-28 17:39:02 -0700392 environment = dict(_FORCE_ENVIRON_FOR_WRAPPERS)
Masood Malekghassemi1c062bd2016-06-13 18:41:36 -0700393 return [self.config.job_spec(
Masood Malekghassemicab9d4f2016-06-28 09:09:31 -0700394 config.run,
Masood Malekghassemie6a23e22016-06-28 13:58:42 -0700395 timeout_seconds=5*60,
Masood Malekghassemi1c062bd2016-06-13 18:41:36 -0700396 environ=dict(environment.items() +
397 [('GRPC_PYTHON_TESTRUNNER_FILTER', suite_name)]),
Masood Malekghassemicab9d4f2016-06-28 09:09:31 -0700398 shortname='%s.test.%s' % (config.name, suite_name),)
Masood Malekghassemi1c062bd2016-06-13 18:41:36 -0700399 for suite_name in tests_json
400 for config in self.pythons]
Nathaniel Manista840615e2015-01-22 20:31:47 +0000401
murgatroid99256d3df2015-09-21 16:58:02 -0700402 def pre_build_steps(self):
403 return []
404
Jan Tattermusch77db4322016-02-20 20:19:35 -0800405 def make_targets(self):
Masood Malekghassemi3b5b2062016-06-02 20:27:20 -0700406 return []
Nathaniel Manista840615e2015-01-22 20:31:47 +0000407
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800408 def make_options(self):
409 return []
410
Nathaniel Manista840615e2015-01-22 20:31:47 +0000411 def build_steps(self):
Masood Malekghassemicab9d4f2016-06-28 09:09:31 -0700412 return [config.build for config in self.pythons]
Nathaniel Manista840615e2015-01-22 20:31:47 +0000413
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200414 def post_tests_steps(self):
415 return []
416
murgatroid99a3e244f2015-09-22 11:25:53 -0700417 def makefile_name(self):
418 return 'Makefile'
419
Jan Tattermusch77db4322016-02-20 20:19:35 -0800420 def dockerfile_dir(self):
siddharthshuklac4782142016-06-28 18:48:47 +0200421 return 'tools/dockerfile/test/python_%s_%s' % (self.python_manager_name(), _docker_arch_suffix(self.args.arch))
422
423 def python_manager_name(self):
424 return 'pyenv' if self.args.compiler in ['python3.5', 'python3.6'] else 'jessie'
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)
siddharthshuklac4782142016-06-28 18:48:47 +0200459 python35_config = python_config_generator(name='py35', major='3', minor='5', bits=bits)
460 python36_config = python_config_generator(name='py36', major='3', minor='6', bits=bits)
Masood Malekghassemicab9d4f2016-06-28 09:09:31 -0700461 if args.compiler == 'default':
462 if os.name == 'nt':
463 return (python27_config,)
464 else:
465 return (python27_config, python34_config,)
466 elif args.compiler == 'python2.7':
Masood Malekghassemi3b5b2062016-06-02 20:27:20 -0700467 return (python27_config,)
Masood Malekghassemicab9d4f2016-06-28 09:09:31 -0700468 elif args.compiler == 'python3.4':
Masood Malekghassemi3b5b2062016-06-02 20:27:20 -0700469 return (python34_config,)
siddharthshuklac4782142016-06-28 18:48:47 +0200470 elif args.compiler == 'python3.5':
471 return (python35_config,)
472 elif args.compiler == 'python3.6':
473 return (python36_config,)
Jan Tattermusch825471c2016-04-25 16:52:25 -0700474 else:
Masood Malekghassemicab9d4f2016-06-28 09:09:31 -0700475 raise Exception('Compiler %s not supported.' % args.compiler)
Jan Tattermusch825471c2016-04-25 16:52:25 -0700476
murgatroid99132ce6a2015-03-04 17:29:14 -0800477 def __str__(self):
478 return 'python'
479
Craig Tillerd625d812015-04-08 15:52:35 -0700480
murgatroid996a4c4fa2015-02-27 12:08:57 -0800481class RubyLanguage(object):
482
Jan Tattermusch77db4322016-02-20 20:19:35 -0800483 def configure(self, config, args):
484 self.config = config
485 self.args = args
486 _check_compiler(self.args.compiler, ['default'])
487
488 def test_specs(self):
Craig Tillereb5e4372016-06-23 16:16:10 -0700489 return [self.config.job_spec(['tools/run_tests/run_ruby.sh'],
Jan Tattermusch77db4322016-02-20 20:19:35 -0800490 timeout_seconds=10*60,
491 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
murgatroid996a4c4fa2015-02-27 12:08:57 -0800492
murgatroid99256d3df2015-09-21 16:58:02 -0700493 def pre_build_steps(self):
Nicolas "Pixel" Noblebcf988f2015-10-08 03:00:42 +0200494 return [['tools/run_tests/pre_build_ruby.sh']]
murgatroid99256d3df2015-09-21 16:58:02 -0700495
Jan Tattermusch4651bef2016-02-23 08:31:25 -0800496 def make_targets(self):
murgatroid997d243df2016-02-18 09:58:05 -0800497 return []
murgatroid996a4c4fa2015-02-27 12:08:57 -0800498
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800499 def make_options(self):
500 return []
501
murgatroid996a4c4fa2015-02-27 12:08:57 -0800502 def build_steps(self):
503 return [['tools/run_tests/build_ruby.sh']]
504
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200505 def post_tests_steps(self):
Nicolas "Pixel" Noble7ef1e532015-12-02 00:55:33 +0100506 return [['tools/run_tests/post_tests_ruby.sh']]
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200507
murgatroid99a3e244f2015-09-22 11:25:53 -0700508 def makefile_name(self):
509 return 'Makefile'
510
Jan Tattermusch77db4322016-02-20 20:19:35 -0800511 def dockerfile_dir(self):
512 return 'tools/dockerfile/test/ruby_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800513
murgatroid99132ce6a2015-03-04 17:29:14 -0800514 def __str__(self):
515 return 'ruby'
516
Craig Tillerd625d812015-04-08 15:52:35 -0700517
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800518class CSharpLanguage(object):
Jan Tattermusch77db4322016-02-20 20:19:35 -0800519
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700520 def __init__(self):
Craig Tillerd50993d2015-08-05 08:04:36 -0700521 self.platform = platform_string()
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700522
Jan Tattermusch77db4322016-02-20 20:19:35 -0800523 def configure(self, config, args):
524 self.config = config
525 self.args = args
Jan Tattermusch6d28d352016-03-25 15:07:22 -0700526 if self.platform == 'windows':
Jan Tattermuschb2531e22016-03-25 16:14:41 -0700527 # Explicitly choosing between x86 and x64 arch doesn't work yet
528 _check_arch(self.args.arch, ['default'])
Jan Tattermusch6e2f88c2016-06-21 10:52:40 -0700529 # CoreCLR use 64bit runtime by default.
530 arch_option = 'x64' if self.args.compiler == 'coreclr' else self.args.arch
Jan Tattermusch6d28d352016-03-25 15:07:22 -0700531 self._make_options = [_windows_toolset_option(self.args.compiler),
Jan Tattermusch6e2f88c2016-06-21 10:52:40 -0700532 _windows_arch_option(arch_option)]
Jan Tattermusch6d28d352016-03-25 15:07:22 -0700533 else:
Jan Tattermuschbc98af12016-06-17 18:38:27 -0700534 _check_compiler(self.args.compiler, ['default', 'coreclr'])
535 if self.platform == 'linux' and self.args.compiler == 'coreclr':
536 self._docker_distro = 'coreclr'
Jan Tattermusch743decd2016-06-21 11:40:47 -0700537 else:
538 self._docker_distro = 'jessie'
Jan Tattermusch76511a52016-06-17 14:00:57 -0700539
Jan Tattermusch6d28d352016-03-25 15:07:22 -0700540 if self.platform == 'mac':
Jan Tattermusch2a322c22016-03-30 13:55:07 -0700541 # TODO(jtattermusch): EMBED_ZLIB=true currently breaks the mac build
Jan Tattermusch6d082202016-06-21 10:03:38 -0700542 self._make_options = ['EMBED_OPENSSL=true']
543 if self.args.compiler != 'coreclr':
544 # On Mac, official distribution of mono is 32bit.
545 self._make_options += ['CFLAGS=-m32', 'LDFLAGS=-m32']
Jan Tattermusch6d28d352016-03-25 15:07:22 -0700546 else:
547 self._make_options = ['EMBED_OPENSSL=true', 'EMBED_ZLIB=true']
Jan Tattermusch77db4322016-02-20 20:19:35 -0800548
549 def test_specs(self):
Jan Tattermusch03c01062015-12-11 14:28:56 -0800550 with open('src/csharp/tests.json') as f:
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700551 tests_by_assembly = json.load(f)
Jan Tattermusch03c01062015-12-11 14:28:56 -0800552
Jan Tattermuscha2d964c2016-02-22 17:33:09 -0800553 msbuild_config = _MSBUILD_CONFIG[self.config.build_config]
Jan Tattermuschbc98af12016-06-17 18:38:27 -0700554 nunit_args = ['--labels=All']
Jan Tattermusch76511a52016-06-17 14:00:57 -0700555 assembly_subdir = 'bin/%s' % msbuild_config
556 assembly_extension = '.exe'
557
558 if self.args.compiler == 'coreclr':
Jan Tattermusch64c137c2016-06-20 17:54:19 -0700559 if self.platform == 'linux':
560 assembly_subdir += '/netstandard1.5/debian.8-x64'
561 assembly_extension = ''
Jan Tattermusch14a301d2016-06-27 17:45:29 -0700562 elif self.platform == 'mac':
Jan Tattermusch6d082202016-06-21 10:03:38 -0700563 assembly_subdir += '/netstandard1.5/osx.10.11-x64'
564 assembly_extension = ''
Jan Tattermusch64c137c2016-06-20 17:54:19 -0700565 else:
566 assembly_subdir += '/netstandard1.5/win7-x64'
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700567 runtime_cmd = []
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700568 else:
Jan Tattermuschbc98af12016-06-17 18:38:27 -0700569 nunit_args += ['--noresult', '--workers=1']
570 if self.platform == 'windows':
571 runtime_cmd = []
572 else:
573 runtime_cmd = ['mono']
Jan Tattermuschbf3b1532015-10-26 10:24:42 -0700574
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700575 specs = []
576 for assembly in tests_by_assembly.iterkeys():
Jan Tattermusch76511a52016-06-17 14:00:57 -0700577 assembly_file = 'src/csharp/%s/%s/%s%s' % (assembly,
578 assembly_subdir,
579 assembly,
580 assembly_extension)
Jan Tattermuscha5f1f122016-04-11 15:49:56 -0700581 if self.config.build_config != 'gcov' or self.platform != 'windows':
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700582 # normally, run each test as a separate process
583 for test in tests_by_assembly[assembly]:
584 cmdline = runtime_cmd + [assembly_file, '--test=%s' % test] + nunit_args
585 specs.append(self.config.job_spec(cmdline,
586 None,
587 shortname='csharp.%s' % test,
588 environ=_FORCE_ENVIRON_FOR_WRAPPERS))
589 else:
Jan Tattermuscha5f1f122016-04-11 15:49:56 -0700590 # For C# test coverage, run all tests from the same assembly at once
591 # using OpenCover.Console (only works on Windows).
592 cmdline = ['src\\csharp\\packages\\OpenCover.4.6.519\\tools\\OpenCover.Console.exe',
593 '-target:%s' % assembly_file,
594 '-targetdir:src\\csharp',
595 '-targetargs:%s' % ' '.join(nunit_args),
596 '-filter:+[Grpc.Core]*',
597 '-register:user',
598 '-output:src\\csharp\\coverage_csharp_%s.xml' % assembly]
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700599
Jan Tattermuscha5f1f122016-04-11 15:49:56 -0700600 # set really high cpu_cost to make sure instances of OpenCover.Console run exclusively
601 # to prevent problems with registering the profiler.
602 run_exclusive = 1000000
Jan Tattermusch35e608f2016-04-09 16:35:06 -0700603 specs.append(self.config.job_spec(cmdline,
604 None,
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700605 shortname='csharp.coverage.%s' % assembly,
Jan Tattermuscha5f1f122016-04-11 15:49:56 -0700606 cpu_cost=run_exclusive,
Jan Tattermusch77db4322016-02-20 20:19:35 -0800607 environ=_FORCE_ENVIRON_FOR_WRAPPERS))
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700608 return specs
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800609
murgatroid99256d3df2015-09-21 16:58:02 -0700610 def pre_build_steps(self):
Jan Tattermusch48423fc2015-10-07 18:59:16 -0700611 if self.platform == 'windows':
Jan Tattermusch874aec02015-10-07 19:26:19 -0700612 return [['tools\\run_tests\\pre_build_csharp.bat']]
Jan Tattermusch48423fc2015-10-07 18:59:16 -0700613 else:
614 return [['tools/run_tests/pre_build_csharp.sh']]
murgatroid99256d3df2015-09-21 16:58:02 -0700615
Jan Tattermusch77db4322016-02-20 20:19:35 -0800616 def make_targets(self):
Jan Tattermusch6d28d352016-03-25 15:07:22 -0700617 return ['grpc_csharp_ext']
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800618
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800619 def make_options(self):
Jan Tattermusch6d28d352016-03-25 15:07:22 -0700620 return self._make_options;
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800621
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800622 def build_steps(self):
Jan Tattermusch76511a52016-06-17 14:00:57 -0700623 if self.args.compiler == 'coreclr':
Jan Tattermuschbc98af12016-06-17 18:38:27 -0700624 if self.platform == 'windows':
625 return [['tools\\run_tests\\build_csharp_coreclr.bat']]
626 else:
627 return [['tools/run_tests/build_csharp_coreclr.sh']]
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700628 else:
Jan Tattermusch76511a52016-06-17 14:00:57 -0700629 if self.platform == 'windows':
630 return [[_windows_build_bat(self.args.compiler),
631 'src/csharp/Grpc.sln',
632 '/p:Configuration=%s' % _MSBUILD_CONFIG[self.config.build_config]]]
633 else:
634 return [['tools/run_tests/build_csharp.sh']]
Nathaniel Manista840615e2015-01-22 20:31:47 +0000635
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200636 def post_tests_steps(self):
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700637 if self.platform == 'windows':
638 return [['tools\\run_tests\\post_tests_csharp.bat']]
639 else:
640 return [['tools/run_tests/post_tests_csharp.sh']]
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200641
murgatroid99a3e244f2015-09-22 11:25:53 -0700642 def makefile_name(self):
643 return 'Makefile'
644
Jan Tattermusch77db4322016-02-20 20:19:35 -0800645 def dockerfile_dir(self):
Jan Tattermusch76511a52016-06-17 14:00:57 -0700646 return 'tools/dockerfile/test/csharp_%s_%s' % (self._docker_distro,
647 _docker_arch_suffix(self.args.arch))
Jan Tattermusch788ee232016-01-26 12:19:44 -0800648
murgatroid99132ce6a2015-03-04 17:29:14 -0800649 def __str__(self):
650 return 'csharp'
651
Craig Tillerd625d812015-04-08 15:52:35 -0700652
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700653class ObjCLanguage(object):
654
Jan Tattermusch77db4322016-02-20 20:19:35 -0800655 def configure(self, config, args):
656 self.config = config
657 self.args = args
658 _check_compiler(self.args.compiler, ['default'])
659
660 def test_specs(self):
Jorge Canizales6ec3b532016-07-01 11:34:32 -0700661 return [self.config.job_spec(['src/objective-c/tests/run_tests.sh'],
662 timeout_seconds=None,
663 shortname='objc-tests',
664 environ=_FORCE_ENVIRON_FOR_WRAPPERS),
Yuchen Zengf95a4892016-06-21 23:27:46 -0700665 self.config.job_spec(['src/objective-c/tests/build_example_test.sh'],
Jorge Canizales6ec3b532016-07-01 11:34:32 -0700666 timeout_seconds=15*60,
667 shortname='objc-examples-build',
Yuchen Zengc0668c82016-06-22 01:30:47 -0700668 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700669
murgatroid99256d3df2015-09-21 16:58:02 -0700670 def pre_build_steps(self):
671 return []
672
Jan Tattermusch77db4322016-02-20 20:19:35 -0800673 def make_targets(self):
Jorge Canizalesd0b32e92015-07-30 23:08:43 -0700674 return ['grpc_objective_c_plugin', 'interop_server']
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700675
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800676 def make_options(self):
677 return []
678
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700679 def build_steps(self):
Jorge Canizalesd0b32e92015-07-30 23:08:43 -0700680 return [['src/objective-c/tests/build_tests.sh']]
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700681
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200682 def post_tests_steps(self):
683 return []
684
murgatroid99a3e244f2015-09-22 11:25:53 -0700685 def makefile_name(self):
686 return 'Makefile'
687
Jan Tattermusch77db4322016-02-20 20:19:35 -0800688 def dockerfile_dir(self):
Jan Tattermusch788ee232016-01-26 12:19:44 -0800689 return None
690
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700691 def __str__(self):
692 return 'objc'
693
694
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100695class Sanity(object):
696
Jan Tattermusch77db4322016-02-20 20:19:35 -0800697 def configure(self, config, args):
698 self.config = config
699 self.args = args
700 _check_compiler(self.args.compiler, ['default'])
701
702 def test_specs(self):
Craig Tiller94d04a52016-01-20 10:58:23 -0800703 import yaml
Jan Tattermusch788ee232016-01-26 12:19:44 -0800704 with open('tools/run_tests/sanity/sanity_tests.yaml', 'r') as f:
Craig Tiller34226af2016-06-24 16:46:25 -0700705 return [self.config.job_spec(cmd['script'].split(),
Jan Tattermusch77db4322016-02-20 20:19:35 -0800706 timeout_seconds=None, environ={'TEST': 'true'},
707 cpu_cost=cmd.get('cpu_cost', 1))
Craig Tiller94d04a52016-01-20 10:58:23 -0800708 for cmd in yaml.load(f)]
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100709
murgatroid99256d3df2015-09-21 16:58:02 -0700710 def pre_build_steps(self):
711 return []
712
Jan Tattermusch77db4322016-02-20 20:19:35 -0800713 def make_targets(self):
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100714 return ['run_dep_checks']
715
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800716 def make_options(self):
717 return []
718
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100719 def build_steps(self):
720 return []
721
Nicolas "Pixel" Noble87879b32015-10-12 23:28:53 +0200722 def post_tests_steps(self):
723 return []
724
murgatroid99a3e244f2015-09-22 11:25:53 -0700725 def makefile_name(self):
726 return 'Makefile'
727
Jan Tattermusch77db4322016-02-20 20:19:35 -0800728 def dockerfile_dir(self):
Jan Tattermusche70b3c52016-02-07 20:21:02 -0800729 return 'tools/dockerfile/test/sanity'
Jan Tattermusch788ee232016-01-26 12:19:44 -0800730
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100731 def __str__(self):
732 return 'sanity'
733
Nicolas "Pixel" Noblee55cd7f2015-04-14 17:59:13 +0200734
Craig Tiller738c3342015-01-12 14:28:33 -0800735# different configurations we can run under
Craig Tillera0f85172016-01-20 15:56:06 -0800736with open('tools/run_tests/configs.json') as f:
Craig Tiller1dce9062016-01-20 17:01:56 -0800737 _CONFIGS = dict((cfg['config'], Config(**cfg)) for cfg in ast.literal_eval(f.read()))
Craig Tiller738c3342015-01-12 14:28:33 -0800738
739
Craig Tillerc7449162015-01-16 14:42:10 -0800740_LANGUAGES = {
Craig Tillere9c959d2015-01-18 10:23:26 -0800741 'c++': CLanguage('cxx', 'c++'),
742 'c': CLanguage('c', 'c'),
murgatroid992c8d5162015-01-26 10:41:21 -0800743 'node': NodeLanguage(),
Nathaniel Manista840615e2015-01-22 20:31:47 +0000744 'php': PhpLanguage(),
745 'python': PythonLanguage(),
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800746 'ruby': RubyLanguage(),
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100747 'csharp': CSharpLanguage(),
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700748 'objc' : ObjCLanguage(),
Jan Tattermusch70a57e42016-02-20 18:50:27 -0800749 'sanity': Sanity()
Craig Tillereb272bc2015-01-30 13:13:14 -0800750 }
Nicolas Nobleddef2462015-01-06 18:08:25 -0800751
Jan Tattermusch77db4322016-02-20 20:19:35 -0800752
Jan Tattermuscha2d964c2016-02-22 17:33:09 -0800753_MSBUILD_CONFIG = {
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700754 'dbg': 'Debug',
755 'opt': 'Release',
Jan Tattermusche4a69182015-12-15 09:53:01 -0800756 'gcov': 'Debug',
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700757 }
758
David Garcia Quintase90cd372015-05-31 18:15:26 -0700759
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800760def _windows_arch_option(arch):
761 """Returns msbuild cmdline option for selected architecture."""
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800762 if arch == 'default' or arch == 'x86':
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800763 return '/p:Platform=Win32'
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800764 elif arch == 'x64':
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800765 return '/p:Platform=x64'
766 else:
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800767 print 'Architecture %s not supported.' % arch
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800768 sys.exit(1)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800769
Jan Tattermuschf08018a2016-01-26 08:22:09 -0800770
771def _check_arch_option(arch):
772 """Checks that architecture option is valid."""
773 if platform_string() == 'windows':
774 _windows_arch_option(arch)
775 elif platform_string() == 'linux':
776 # On linux, we need to be running under docker with the right architecture.
Jan Tattermusch07fb0422016-01-26 10:46:56 -0800777 runtime_arch = platform.architecture()[0]
Jan Tattermuschf08018a2016-01-26 08:22:09 -0800778 if arch == 'default':
779 return
780 elif runtime_arch == '64bit' and arch == 'x64':
781 return
782 elif runtime_arch == '32bit' and arch == 'x86':
783 return
784 else:
785 print 'Architecture %s does not match current runtime architecture.' % arch
786 sys.exit(1)
787 else:
788 if args.arch != 'default':
789 print 'Architecture %s not supported on current platform.' % args.arch
790 sys.exit(1)
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800791
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800792
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800793def _windows_build_bat(compiler):
794 """Returns name of build.bat for selected compiler."""
Jan Tattermuschbc98af12016-06-17 18:38:27 -0700795 # For CoreCLR, fall back to the default compiler for C core
796 if compiler == 'default' or compiler == 'vs2013' or compiler == 'coreclr':
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800797 return 'vsprojects\\build_vs2013.bat'
798 elif compiler == 'vs2015':
799 return 'vsprojects\\build_vs2015.bat'
800 elif compiler == 'vs2010':
801 return 'vsprojects\\build_vs2010.bat'
802 else:
803 print 'Compiler %s not supported.' % compiler
804 sys.exit(1)
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800805
806
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800807def _windows_toolset_option(compiler):
808 """Returns msbuild PlatformToolset for selected compiler."""
Jan Tattermuschbc98af12016-06-17 18:38:27 -0700809 # For CoreCLR, fall back to the default compiler for C core
810 if compiler == 'default' or compiler == 'vs2013' or compiler == 'coreclr':
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800811 return '/p:PlatformToolset=v120'
812 elif compiler == 'vs2015':
813 return '/p:PlatformToolset=v140'
814 elif compiler == 'vs2010':
815 return '/p:PlatformToolset=v100'
816 else:
817 print 'Compiler %s not supported.' % compiler
818 sys.exit(1)
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800819
820
Jan Tattermusche70b3c52016-02-07 20:21:02 -0800821def _docker_arch_suffix(arch):
822 """Returns suffix to dockerfile dir to use."""
823 if arch == 'default' or arch == 'x64':
824 return 'x64'
825 elif arch == 'x86':
826 return 'x86'
827 else:
828 print 'Architecture %s not supported with current settings.' % arch
829 sys.exit(1)
830
831
David Garcia Quintase90cd372015-05-31 18:15:26 -0700832def runs_per_test_type(arg_str):
833 """Auxilary function to parse the "runs_per_test" flag.
834
835 Returns:
836 A positive integer or 0, the latter indicating an infinite number of
837 runs.
838
839 Raises:
840 argparse.ArgumentTypeError: Upon invalid input.
841 """
842 if arg_str == 'inf':
843 return 0
844 try:
845 n = int(arg_str)
846 if n <= 0: raise ValueError
Craig Tiller50e53e22015-06-01 20:18:21 -0700847 return n
David Garcia Quintase90cd372015-05-31 18:15:26 -0700848 except:
Adele Zhoue4c35612015-10-16 15:34:23 -0700849 msg = '\'{}\' is not a positive integer or \'inf\''.format(arg_str)
David Garcia Quintase90cd372015-05-31 18:15:26 -0700850 raise argparse.ArgumentTypeError(msg)
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700851
852# parse command line
853argp = argparse.ArgumentParser(description='Run grpc tests.')
854argp.add_argument('-c', '--config',
Jan Tattermusch77db4322016-02-20 20:19:35 -0800855 choices=sorted(_CONFIGS.keys()),
856 default='opt')
David Garcia Quintase90cd372015-05-31 18:15:26 -0700857argp.add_argument('-n', '--runs_per_test', default=1, type=runs_per_test_type,
858 help='A positive integer or "inf". If "inf", all tests will run in an '
859 'infinite loop. Especially useful in combination with "-f"')
Craig Tillerfe406ec2015-02-24 13:55:12 -0800860argp.add_argument('-r', '--regex', default='.*', type=str)
Vijay Pai488fd0e2016-06-13 12:37:12 -0700861argp.add_argument('--regex_exclude', default='', type=str)
Craig Tiller5f735a62016-01-20 09:31:15 -0800862argp.add_argument('-j', '--jobs', default=multiprocessing.cpu_count(), type=int)
Craig Tiller8451e872015-02-27 09:25:51 -0800863argp.add_argument('-s', '--slowdown', default=1.0, type=float)
ctiller3040cb72015-01-07 12:13:17 -0800864argp.add_argument('-f', '--forever',
865 default=False,
866 action='store_const',
867 const=True)
Nicolas "Pixel" Noblea7df3f92015-02-26 22:07:04 +0100868argp.add_argument('-t', '--travis',
869 default=False,
870 action='store_const',
871 const=True)
Nicolas Noble044db742015-01-14 16:57:24 -0800872argp.add_argument('--newline_on_success',
873 default=False,
874 action='store_const',
875 const=True)
Craig Tiller686fb262015-01-15 07:39:09 -0800876argp.add_argument('-l', '--language',
Craig Tiller60f15e62015-05-13 09:05:17 -0700877 choices=['all'] + sorted(_LANGUAGES.keys()),
Craig Tiller686fb262015-01-15 07:39:09 -0800878 nargs='+',
Craig Tiller60f15e62015-05-13 09:05:17 -0700879 default=['all'])
Craig Tillercd43da82015-05-29 08:41:29 -0700880argp.add_argument('-S', '--stop_on_failure',
881 default=False,
882 action='store_const',
883 const=True)
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700884argp.add_argument('--use_docker',
885 default=False,
886 action='store_const',
887 const=True,
Adele Zhoue4c35612015-10-16 15:34:23 -0700888 help='Run all the tests under docker. That provides ' +
889 'additional isolation and prevents the need to install ' +
890 'language specific prerequisites. Only available on Linux.')
Craig Tillerd4509a12015-09-28 09:18:40 -0700891argp.add_argument('--allow_flakes',
892 default=False,
893 action='store_const',
894 const=True,
Adele Zhoue4c35612015-10-16 15:34:23 -0700895 help='Allow flaky tests to show as passing (re-runs failed tests up to five times)')
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800896argp.add_argument('--arch',
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800897 choices=['default', 'x86', 'x64'],
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800898 default='default',
899 help='Selects architecture to target. For some platforms "default" is the only supported choice.')
900argp.add_argument('--compiler',
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800901 choices=['default',
Jan Tattermusch6d258c52016-06-10 09:36:51 -0700902 'gcc4.4', 'gcc4.6', 'gcc4.9', 'gcc5.3',
903 'clang3.4', 'clang3.5', 'clang3.6', 'clang3.7',
Jan Tattermusch825471c2016-04-25 16:52:25 -0700904 'vs2010', 'vs2013', 'vs2015',
siddharthshuklac4782142016-06-28 18:48:47 +0200905 'python2.7', 'python3.4', 'python3.5', 'python3.6',
Jan Tattermusch76511a52016-06-17 14:00:57 -0700906 'node0.12', 'node4', 'node5',
907 'coreclr'],
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800908 default='default',
Jan Tattermusch77db4322016-02-20 20:19:35 -0800909 help='Selects compiler to use. Allowed values depend on the platform and language.')
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800910argp.add_argument('--build_only',
911 default=False,
912 action='store_const',
913 const=True,
914 help='Perform all the build steps but dont run any tests.')
Craig Tiller5f735a62016-01-20 09:31:15 -0800915argp.add_argument('--measure_cpu_costs', default=False, action='store_const', const=True,
916 help='Measure the cpu costs of tests')
Craig Tiller1676f912016-01-05 10:49:44 -0800917argp.add_argument('--update_submodules', default=[], nargs='*',
918 help='Update some submodules before building. If any are updated, also run generate_projects. ' +
919 'Submodules are specified as SUBMODULE_NAME:BRANCH; if BRANCH is omitted, master is assumed.')
Craig Tiller234b6e72015-05-23 10:12:40 -0700920argp.add_argument('-a', '--antagonists', default=0, type=int)
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +0200921argp.add_argument('-x', '--xml_report', default=None, type=str,
922 help='Generates a JUnit-compatible XML report')
Craig Tiller123f1372016-06-15 15:06:14 -0700923argp.add_argument('--force_default_poller', default=False, action='store_const', const=True,
924 help='Dont try to iterate over many polling strategies when they exist')
Nicolas Nobleddef2462015-01-06 18:08:25 -0800925args = argp.parse_args()
926
Craig Tiller123f1372016-06-15 15:06:14 -0700927if args.force_default_poller:
928 _POLLING_STRATEGIES = {}
929
Craig Tiller5f735a62016-01-20 09:31:15 -0800930jobset.measure_cpu_costs = args.measure_cpu_costs
931
Craig Tiller1676f912016-01-05 10:49:44 -0800932# update submodules if necessary
Craig Tillerb361b4e2016-01-06 11:44:17 -0800933need_to_regenerate_projects = False
934for spec in args.update_submodules:
935 spec = spec.split(':', 1)
936 if len(spec) == 1:
937 submodule = spec[0]
938 branch = 'master'
939 elif len(spec) == 2:
940 submodule = spec[0]
941 branch = spec[1]
942 cwd = 'third_party/%s' % submodule
943 def git(cmd, cwd=cwd):
944 print 'in %s: git %s' % (cwd, cmd)
945 subprocess.check_call('git %s' % cmd, cwd=cwd, shell=True)
946 git('fetch')
947 git('checkout %s' % branch)
948 git('pull origin %s' % branch)
949 if os.path.exists('src/%s/gen_build_yaml.py' % submodule):
950 need_to_regenerate_projects = True
951if need_to_regenerate_projects:
952 if jobset.platform_string() == 'linux':
953 subprocess.check_call('tools/buildgen/generate_projects.sh', shell=True)
954 else:
955 print 'WARNING: may need to regenerate projects, but since we are not on'
956 print ' Linux this step is being skipped. Compilation MAY fail.'
Craig Tiller1676f912016-01-05 10:49:44 -0800957
958
Nicolas Nobleddef2462015-01-06 18:08:25 -0800959# grab config
Jan Tattermusch77db4322016-02-20 20:19:35 -0800960run_config = _CONFIGS[args.config]
961build_config = run_config.build_config
Craig Tillerf1973b02015-01-16 12:32:13 -0800962
Craig Tiller06805272015-06-11 14:46:47 -0700963if args.travis:
murgatroid99d3b5b7f2015-10-06 17:02:03 -0700964 _FORCE_ENVIRON_FOR_WRAPPERS = {'GRPC_TRACE': 'api'}
Craig Tiller06805272015-06-11 14:46:47 -0700965
Adele Zhou6b9527c2015-11-20 15:56:35 -0800966if 'all' in args.language:
Craig Tiller1676f912016-01-05 10:49:44 -0800967 lang_list = _LANGUAGES.keys()
Adele Zhou6b9527c2015-11-20 15:56:35 -0800968else:
969 lang_list = args.language
Craig Tiller16900662016-01-07 19:30:54 -0800970# We don't support code coverage on some languages
971if 'gcov' in args.config:
Jan Tattermusch3b5121b2016-02-22 17:41:05 -0800972 for bad in ['objc', 'sanity']:
Craig Tiller16900662016-01-07 19:30:54 -0800973 if bad in lang_list:
974 lang_list.remove(bad)
Adele Zhou6b9527c2015-11-20 15:56:35 -0800975
976languages = set(_LANGUAGES[l] for l in lang_list)
Jan Tattermusch77db4322016-02-20 20:19:35 -0800977for l in languages:
978 l.configure(run_config, args)
murgatroid99132ce6a2015-03-04 17:29:14 -0800979
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800980language_make_options=[]
981if any(language.make_options() for language in languages):
Adele Zhou3b6ab812016-05-18 17:04:20 -0700982 if not 'gcov' in args.config and len(languages) != 1:
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800983 print 'languages with custom make options cannot be built simultaneously with other languages'
984 sys.exit(1)
985 else:
986 language_make_options = next(iter(languages)).make_options()
987
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800988if args.use_docker:
989 if not args.travis:
990 print 'Seen --use_docker flag, will run tests under docker.'
991 print
992 print 'IMPORTANT: The changes you are testing need to be locally committed'
993 print 'because only the committed changes in the current branch will be'
994 print 'copied to the docker environment.'
995 time.sleep(5)
996
Jan Tattermusch3b5121b2016-02-22 17:41:05 -0800997 dockerfile_dirs = set([l.dockerfile_dir() for l in languages])
998 if len(dockerfile_dirs) > 1:
Adele Zhou9506ef22016-03-02 13:53:34 -0800999 if 'gcov' in args.config:
1000 dockerfile_dir = 'tools/dockerfile/test/multilang_jessie_x64'
1001 print ('Using multilang_jessie_x64 docker image for code coverage for '
1002 'all languages.')
1003 else:
1004 print ('Languages to be tested require running under different docker '
1005 'images.')
1006 sys.exit(1)
1007 else:
1008 dockerfile_dir = next(iter(dockerfile_dirs))
Craig Tillerde7edf82016-03-20 09:12:16 -07001009
Jan Tattermusch4dc9e722016-01-25 17:00:54 -08001010 child_argv = [ arg for arg in sys.argv if not arg == '--use_docker' ]
Jan Tattermusched342b12016-01-26 14:40:31 -08001011 run_tests_cmd = 'python tools/run_tests/run_tests.py %s' % ' '.join(child_argv[1:])
Jan Tattermusch4dc9e722016-01-25 17:00:54 -08001012
Jan Tattermusch4dc9e722016-01-25 17:00:54 -08001013 env = os.environ.copy()
1014 env['RUN_TESTS_COMMAND'] = run_tests_cmd
Jan Tattermusch3b5121b2016-02-22 17:41:05 -08001015 env['DOCKERFILE_DIR'] = dockerfile_dir
Jan Tattermusch9835d4b2016-04-29 15:05:05 -07001016 env['DOCKER_RUN_SCRIPT'] = 'tools/run_tests/dockerize/docker_run_tests.sh'
Jan Tattermusch4dc9e722016-01-25 17:00:54 -08001017 if args.xml_report:
1018 env['XML_REPORT'] = args.xml_report
1019 if not args.travis:
1020 env['TTY_FLAG'] = '-t' # enables Ctrl-C when not on Jenkins.
1021
Jan Tattermusch9835d4b2016-04-29 15:05:05 -07001022 subprocess.check_call(['tools/run_tests/dockerize/build_docker_and_run_tests.sh'],
Jan Tattermusch4dc9e722016-01-25 17:00:54 -08001023 shell=True,
1024 env=env)
1025 sys.exit(0)
Jan Tattermusch788ee232016-01-26 12:19:44 -08001026
Jan Tattermuschf08018a2016-01-26 08:22:09 -08001027_check_arch_option(args.arch)
Jan Tattermusch4dc9e722016-01-25 17:00:54 -08001028
Jan Tattermuschfba65302016-01-25 18:21:14 -08001029def make_jobspec(cfg, targets, makefile='Makefile'):
1030 if platform_string() == 'windows':
Craig Tillerfc3c0c42015-09-01 16:47:54 -07001031 extra_args = []
Craig Tillerb5391e12015-09-03 14:35:18 -07001032 # better do parallel compilation
Jan Tattermusch47eeb2b2015-10-07 14:09:18 -07001033 # empirically /m:2 gives the best performance/price and should prevent
1034 # overloading the windows workers.
Adele Zhoue4c35612015-10-16 15:34:23 -07001035 extra_args.extend(['/m:2'])
Craig Tillerb5391e12015-09-03 14:35:18 -07001036 # disable PDB generation: it's broken, and we don't need it during CI
Adele Zhoue4c35612015-10-16 15:34:23 -07001037 extra_args.extend(['/p:Jenkins=true'])
Craig Tiller6fd23842015-09-01 07:36:31 -07001038 return [
Jan Tattermusch2dd156e2015-12-04 18:26:17 -08001039 jobset.JobSpec([_windows_build_bat(args.compiler),
murgatroid99cf08daf2015-09-21 15:33:16 -07001040 'vsprojects\\%s.sln' % target,
Jan Tattermuscha2d964c2016-02-22 17:33:09 -08001041 '/p:Configuration=%s' % _MSBUILD_CONFIG[cfg]] +
Jan Tattermuschc895fe02016-01-20 09:13:09 -08001042 extra_args +
1043 language_make_options,
Craig Tiller590105a2016-01-19 13:03:46 -08001044 shell=True, timeout_seconds=None)
Craig Tiller6fd23842015-09-01 07:36:31 -07001045 for target in targets]
Jan Tattermuschfba65302016-01-25 18:21:14 -08001046 else:
murgatroid998ae409f2015-10-26 16:39:00 -07001047 if targets:
1048 return [jobset.JobSpec([os.getenv('MAKE', 'make'),
1049 '-f', makefile,
Craig Tillerdd6f7ed2016-01-21 12:54:42 -08001050 '-j', '%d' % args.jobs,
Craig Tiller71a86042016-01-15 14:59:58 -08001051 'EXTRA_DEFINES=GRPC_TEST_SLOWDOWN_MACHINE_FACTOR=%f' % args.slowdown,
1052 'CONFIG=%s' % cfg] +
Jan Tattermuschc895fe02016-01-20 09:13:09 -08001053 language_make_options +
Craig Tiller71a86042016-01-15 14:59:58 -08001054 ([] if not args.travis else ['JENKINS_BUILD=1']) +
1055 targets,
Craig Tiller590105a2016-01-19 13:03:46 -08001056 timeout_seconds=None)]
murgatroid998ae409f2015-10-26 16:39:00 -07001057 else:
1058 return []
Jan Tattermuschfba65302016-01-25 18:21:14 -08001059
murgatroid99a3e244f2015-09-22 11:25:53 -07001060make_targets = {}
1061for l in languages:
1062 makefile = l.makefile_name()
1063 make_targets[makefile] = make_targets.get(makefile, set()).union(
Jan Tattermusch77db4322016-02-20 20:19:35 -08001064 set(l.make_targets()))
Craig Tiller5058c692015-04-08 09:42:04 -07001065
Jan Tattermusche4a69182015-12-15 09:53:01 -08001066def build_step_environ(cfg):
1067 environ = {'CONFIG': cfg}
Jan Tattermuscha2d964c2016-02-22 17:33:09 -08001068 msbuild_cfg = _MSBUILD_CONFIG.get(cfg)
Jan Tattermusche4a69182015-12-15 09:53:01 -08001069 if msbuild_cfg:
1070 environ['MSBUILD_CONFIG'] = msbuild_cfg
1071 return environ
1072
murgatroid99fddac962015-09-22 09:20:11 -07001073build_steps = list(set(
Jan Tattermusch77db4322016-02-20 20:19:35 -08001074 jobset.JobSpec(cmdline, environ=build_step_environ(build_config), flake_retries=5)
murgatroid99256d3df2015-09-21 16:58:02 -07001075 for l in languages
1076 for cmdline in l.pre_build_steps()))
Craig Tillerbd4e3782015-09-01 06:48:55 -07001077if make_targets:
Jan Tattermusch77db4322016-02-20 20:19:35 -08001078 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 -07001079 build_steps.extend(set(make_commands))
Craig Tiller5058c692015-04-08 09:42:04 -07001080build_steps.extend(set(
Jan Tattermusch77db4322016-02-20 20:19:35 -08001081 jobset.JobSpec(cmdline, environ=build_step_environ(build_config), timeout_seconds=None)
Craig Tiller547db2b2015-01-30 14:08:39 -08001082 for l in languages
Craig Tiller533b1a22015-05-29 08:41:29 -07001083 for cmdline in l.build_steps()))
Craig Tillerf1973b02015-01-16 12:32:13 -08001084
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +02001085post_tests_steps = list(set(
Jan Tattermusch77db4322016-02-20 20:19:35 -08001086 jobset.JobSpec(cmdline, environ=build_step_environ(build_config))
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +02001087 for l in languages
1088 for cmdline in l.post_tests_steps()))
Nicolas Nobleddef2462015-01-06 18:08:25 -08001089runs_per_test = args.runs_per_test
ctiller3040cb72015-01-07 12:13:17 -08001090forever = args.forever
Nicolas Nobleddef2462015-01-06 18:08:25 -08001091
Nicolas Nobleddef2462015-01-06 18:08:25 -08001092
Ken Paysonfa51de52016-06-30 23:50:48 -07001093def _shut_down_legacy_server(legacy_server_port):
1094 try:
1095 version = int(urllib2.urlopen(
1096 'http://localhost:%d/version_number' % legacy_server_port,
1097 timeout=10).read())
1098 except:
1099 pass
1100 else:
1101 urllib2.urlopen(
1102 'http://localhost:%d/quitquitquit' % legacy_server_port).read()
1103
1104
Craig Tillerf53d9c82015-08-04 14:19:43 -07001105def _start_port_server(port_server_port):
1106 # check if a compatible port server is running
1107 # if incompatible (version mismatch) ==> start a new one
1108 # if not running ==> start a new one
1109 # otherwise, leave it up
1110 try:
Craig Tillerfe4939f2015-10-06 12:55:36 -07001111 version = int(urllib2.urlopen(
1112 'http://localhost:%d/version_number' % port_server_port,
Jan Tattermusch292d0102016-06-28 10:29:41 -07001113 timeout=10).read())
Craig Tillerfe4939f2015-10-06 12:55:36 -07001114 print 'detected port server running version %d' % version
Craig Tillerf53d9c82015-08-04 14:19:43 -07001115 running = True
Craig Tillerfe4939f2015-10-06 12:55:36 -07001116 except Exception as e:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001117 print 'failed to detect port server: %s' % sys.exc_info()[0]
Craig Tillerfe4939f2015-10-06 12:55:36 -07001118 print e.strerror
Craig Tillerf53d9c82015-08-04 14:19:43 -07001119 running = False
1120 if running:
Craig Tillerfe4939f2015-10-06 12:55:36 -07001121 current_version = int(subprocess.check_output(
Jan Tattermusch3bd08272015-11-04 19:24:37 -08001122 [sys.executable, os.path.abspath('tools/run_tests/port_server.py'),
1123 'dump_version']))
Craig Tillerfe4939f2015-10-06 12:55:36 -07001124 print 'my port server is version %d' % current_version
1125 running = (version >= current_version)
1126 if not running:
1127 print 'port_server version mismatch: killing the old one'
1128 urllib2.urlopen('http://localhost:%d/quitquitquit' % port_server_port).read()
1129 time.sleep(1)
Craig Tillerf53d9c82015-08-04 14:19:43 -07001130 if not running:
Craig Tillerf0a293e2015-10-12 10:05:50 -07001131 fd, logfile = tempfile.mkstemp()
1132 os.close(fd)
1133 print 'starting port_server, with log file %s' % logfile
Jan Tattermusch3bd08272015-11-04 19:24:37 -08001134 args = [sys.executable, os.path.abspath('tools/run_tests/port_server.py'),
1135 '-p', '%d' % port_server_port, '-l', logfile]
Craig Tiller367d41d2015-10-12 13:00:22 -07001136 env = dict(os.environ)
1137 env['BUILD_ID'] = 'pleaseDontKillMeJenkins'
Nicolas "Pixel" Noblef72d7b52015-12-03 03:07:43 +01001138 if platform_string() == 'windows':
Jan Tattermusch3bd08272015-11-04 19:24:37 -08001139 # Working directory of port server needs to be outside of Jenkins
1140 # workspace to prevent file lock issues.
1141 tempdir = tempfile.mkdtemp()
Craig Tillerd2c39712015-10-12 11:08:49 -07001142 port_server = subprocess.Popen(
Craig Tiller367d41d2015-10-12 13:00:22 -07001143 args,
1144 env=env,
Jan Tattermusch3bd08272015-11-04 19:24:37 -08001145 cwd=tempdir,
Craig Tiller367d41d2015-10-12 13:00:22 -07001146 creationflags = 0x00000008, # detached process
1147 close_fds=True)
Craig Tillerd2c39712015-10-12 11:08:49 -07001148 else:
1149 port_server = subprocess.Popen(
1150 args,
Craig Tiller367d41d2015-10-12 13:00:22 -07001151 env=env,
Craig Tillerd2c39712015-10-12 11:08:49 -07001152 preexec_fn=os.setsid,
1153 close_fds=True)
Craig Tillerf0a293e2015-10-12 10:05:50 -07001154 time.sleep(1)
Craig Tiller8b5f4dc2015-08-26 08:02:01 -07001155 # ensure port server is up
Craig Tillerabd37fd2015-08-26 07:54:01 -07001156 waits = 0
Craig Tillerf53d9c82015-08-04 14:19:43 -07001157 while True:
Craig Tillerabd37fd2015-08-26 07:54:01 -07001158 if waits > 10:
Craig Tillerf0a293e2015-10-12 10:05:50 -07001159 print 'killing port server due to excessive start up waits'
Craig Tillerabd37fd2015-08-26 07:54:01 -07001160 port_server.kill()
Craig Tillera2f38b02015-09-24 11:19:17 -07001161 if port_server.poll() is not None:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001162 print 'port_server failed to start'
Craig Tillerf0a293e2015-10-12 10:05:50 -07001163 # try one final time: maybe another build managed to start one
1164 time.sleep(1)
1165 try:
1166 urllib2.urlopen('http://localhost:%d/get' % port_server_port,
1167 timeout=1).read()
1168 print 'last ditch attempt to contact port server succeeded'
1169 break
1170 except:
Jan Tattermusch3b5121b2016-02-22 17:41:05 -08001171 traceback.print_exc()
Craig Tillerf0a293e2015-10-12 10:05:50 -07001172 port_log = open(logfile, 'r').read()
1173 print port_log
1174 sys.exit(1)
Craig Tillerf53d9c82015-08-04 14:19:43 -07001175 try:
Craig Tillerabd37fd2015-08-26 07:54:01 -07001176 urllib2.urlopen('http://localhost:%d/get' % port_server_port,
1177 timeout=1).read()
Craig Tillerf0a293e2015-10-12 10:05:50 -07001178 print 'port server is up and ready'
Craig Tillerf53d9c82015-08-04 14:19:43 -07001179 break
Craig Tiller31fdaa42015-09-25 13:09:59 -07001180 except socket.timeout:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001181 print 'waiting for port_server: timeout'
Craig Tillerf0a293e2015-10-12 10:05:50 -07001182 traceback.print_exc();
1183 time.sleep(1)
Craig Tiller31fdaa42015-09-25 13:09:59 -07001184 waits += 1
Craig Tillerf53d9c82015-08-04 14:19:43 -07001185 except urllib2.URLError:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001186 print 'waiting for port_server: urlerror'
Craig Tillerf0a293e2015-10-12 10:05:50 -07001187 traceback.print_exc();
1188 time.sleep(1)
Craig Tillerabd37fd2015-08-26 07:54:01 -07001189 waits += 1
Craig Tillerf53d9c82015-08-04 14:19:43 -07001190 except:
Jan Tattermusch3b5121b2016-02-22 17:41:05 -08001191 traceback.print_exc()
Craig Tillerf53d9c82015-08-04 14:19:43 -07001192 port_server.kill()
1193 raise
1194
1195
Adele Zhoud5fffa52015-10-23 15:51:42 -07001196def _calculate_num_runs_failures(list_of_results):
1197 """Caculate number of runs and failures for a particular test.
1198
1199 Args:
1200 list_of_results: (List) of JobResult object.
1201 Returns:
1202 A tuple of total number of runs and failures.
1203 """
1204 num_runs = len(list_of_results) # By default, there is 1 run per JobResult.
1205 num_failures = 0
1206 for jobresult in list_of_results:
1207 if jobresult.retries > 0:
1208 num_runs += jobresult.retries
1209 if jobresult.num_failures > 0:
1210 num_failures += jobresult.num_failures
1211 return num_runs, num_failures
1212
Adele Zhou6b9527c2015-11-20 15:56:35 -08001213
Craig Tillereb9de8b2016-01-08 08:57:41 -08001214# _build_and_run results
1215class BuildAndRunError(object):
1216
1217 BUILD = object()
1218 TEST = object()
1219 POST_TEST = object()
1220
1221
1222# returns a list of things that failed (or an empty list on success)
Craig Tillerf53d9c82015-08-04 14:19:43 -07001223def _build_and_run(
Craig Tiller74189cd2016-06-23 15:39:06 -07001224 check_cancelled, newline_on_success, xml_report=None, build_only=False):
ctiller3040cb72015-01-07 12:13:17 -08001225 """Do one pass of building & running tests."""
murgatroid99666450e2015-01-26 13:03:31 -08001226 # build latest sequentially
Jan Tattermuschaab1e512016-01-28 09:30:44 -08001227 num_failures, resultset = jobset.run(
Adele Zhoue4c35612015-10-16 15:34:23 -07001228 build_steps, maxjobs=1, stop_on_failure=True,
Craig Tiller883064c2015-11-04 10:06:10 -08001229 newline_on_success=newline_on_success, travis=args.travis)
Adele Zhoue4c35612015-10-16 15:34:23 -07001230 if num_failures:
Craig Tillereb9de8b2016-01-08 08:57:41 -08001231 return [BuildAndRunError.BUILD]
Craig Tillerb361b4e2016-01-06 11:44:17 -08001232
Jan Tattermusch2dd156e2015-12-04 18:26:17 -08001233 if build_only:
Jan Tattermuschaab1e512016-01-28 09:30:44 -08001234 if xml_report:
1235 report_utils.render_junit_xml_report(resultset, xml_report)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001236 return []
ctiller3040cb72015-01-07 12:13:17 -08001237
Craig Tiller234b6e72015-05-23 10:12:40 -07001238 # start antagonists
David Garcia Quintas79e389f2015-06-02 17:49:42 -07001239 antagonists = [subprocess.Popen(['tools/run_tests/antagonist.py'])
Craig Tiller234b6e72015-05-23 10:12:40 -07001240 for _ in range(0, args.antagonists)]
Ken Paysonfa51de52016-06-30 23:50:48 -07001241 port_server_port = 32766
Craig Tillerf53d9c82015-08-04 14:19:43 -07001242 _start_port_server(port_server_port)
Adele Zhou7cf72112015-11-04 11:18:43 -08001243 resultset = None
Adele Zhou803af152015-11-30 15:16:16 -08001244 num_test_failures = 0
Craig Tiller234b6e72015-05-23 10:12:40 -07001245 try:
David Garcia Quintase90cd372015-05-31 18:15:26 -07001246 infinite_runs = runs_per_test == 0
yang-g6c1fdc62015-08-18 11:57:42 -07001247 one_run = set(
1248 spec
yang-g6c1fdc62015-08-18 11:57:42 -07001249 for language in languages
Jan Tattermusch77db4322016-02-20 20:19:35 -08001250 for spec in language.test_specs()
Vijay Pai488fd0e2016-06-13 12:37:12 -07001251 if (re.search(args.regex, spec.shortname) and
1252 (args.regex_exclude == '' or
1253 not re.search(args.regex_exclude, spec.shortname))))
David Garcia Quintas79e389f2015-06-02 17:49:42 -07001254 # When running on travis, we want out test runs to be as similar as possible
1255 # for reproducibility purposes.
Craig Tiller883064c2015-11-04 10:06:10 -08001256 if args.travis:
David Garcia Quintas79e389f2015-06-02 17:49:42 -07001257 massaged_one_run = sorted(one_run, key=lambda x: x.shortname)
1258 else:
1259 # whereas otherwise, we want to shuffle things up to give all tests a
1260 # chance to run.
1261 massaged_one_run = list(one_run) # random.shuffle needs an indexable seq.
1262 random.shuffle(massaged_one_run) # which it modifies in-place.
Craig Tillerf7b7c892015-06-22 14:33:25 -07001263 if infinite_runs:
1264 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 -07001265 runs_sequence = (itertools.repeat(massaged_one_run) if infinite_runs
1266 else itertools.repeat(massaged_one_run, runs_per_test))
David Garcia Quintase90cd372015-05-31 18:15:26 -07001267 all_runs = itertools.chain.from_iterable(runs_sequence)
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +02001268
Adele Zhou803af152015-11-30 15:16:16 -08001269 num_test_failures, resultset = jobset.run(
Adele Zhou2271ab52015-10-28 13:59:14 -07001270 all_runs, check_cancelled, newline_on_success=newline_on_success,
Craig Tiller883064c2015-11-04 10:06:10 -08001271 travis=args.travis, infinite_runs=infinite_runs, maxjobs=args.jobs,
murgatroid998ae409f2015-10-26 16:39:00 -07001272 stop_on_failure=args.stop_on_failure,
Adele Zhouf2ca7bc2015-10-23 15:38:00 -07001273 add_env={'GRPC_TEST_PORT_SERVER': 'localhost:%d' % port_server_port})
Adele Zhoud5fffa52015-10-23 15:51:42 -07001274 if resultset:
Craig Tiller2b59dbc2016-05-13 15:59:09 -07001275 for k, v in sorted(resultset.items()):
Adele Zhoud5fffa52015-10-23 15:51:42 -07001276 num_runs, num_failures = _calculate_num_runs_failures(v)
1277 if num_failures == num_runs: # what about infinite_runs???
1278 jobset.message('FAILED', k, do_newline=True)
1279 elif num_failures > 0:
1280 jobset.message(
1281 'FLAKE', '%s [%d/%d runs flaked]' % (k, num_failures, num_runs),
1282 do_newline=True)
1283 else:
1284 jobset.message('PASSED', k, do_newline=True)
Craig Tiller234b6e72015-05-23 10:12:40 -07001285 finally:
1286 for antagonist in antagonists:
1287 antagonist.kill()
Adele Zhou7cf72112015-11-04 11:18:43 -08001288 if xml_report and resultset:
Adele Zhou3bc7ba42015-11-05 10:21:58 -08001289 report_utils.render_junit_xml_report(resultset, xml_report)
Craig Tillerd86a3942015-01-14 12:48:54 -08001290
Adele Zhouf2ca7bc2015-10-23 15:38:00 -07001291 number_failures, _ = jobset.run(
1292 post_tests_steps, maxjobs=1, stop_on_failure=True,
Craig Tiller883064c2015-11-04 10:06:10 -08001293 newline_on_success=newline_on_success, travis=args.travis)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001294
1295 out = []
1296 if number_failures:
1297 out.append(BuildAndRunError.POST_TEST)
1298 if num_test_failures:
1299 out.append(BuildAndRunError.TEST)
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +02001300
Craig Tillereb9de8b2016-01-08 08:57:41 -08001301 return out
ctiller3040cb72015-01-07 12:13:17 -08001302
1303
1304if forever:
Nicolas Noble044db742015-01-14 16:57:24 -08001305 success = True
ctiller3040cb72015-01-07 12:13:17 -08001306 while True:
Craig Tiller42bc87c2015-02-23 08:50:19 -08001307 dw = watch_dirs.DirWatcher(['src', 'include', 'test', 'examples'])
ctiller3040cb72015-01-07 12:13:17 -08001308 initial_time = dw.most_recent_change()
1309 have_files_changed = lambda: dw.most_recent_change() != initial_time
Nicolas Noble044db742015-01-14 16:57:24 -08001310 previous_success = success
Craig Tillereb9de8b2016-01-08 08:57:41 -08001311 errors = _build_and_run(check_cancelled=have_files_changed,
1312 newline_on_success=False,
Craig Tillereb9de8b2016-01-08 08:57:41 -08001313 build_only=args.build_only) == 0
1314 if not previous_success and not errors:
Nicolas Nobleb09078f2015-01-14 18:06:05 -08001315 jobset.message('SUCCESS',
1316 'All tests are now passing properly',
1317 do_newline=True)
Nicolas Noble044db742015-01-14 16:57:24 -08001318 jobset.message('IDLE', 'No change detected')
ctiller3040cb72015-01-07 12:13:17 -08001319 while not have_files_changed():
1320 time.sleep(1)
1321else:
Craig Tillereb9de8b2016-01-08 08:57:41 -08001322 errors = _build_and_run(check_cancelled=lambda: False,
Craig Tiller71735182015-01-15 17:07:13 -08001323 newline_on_success=args.newline_on_success,
Jan Tattermusch2dd156e2015-12-04 18:26:17 -08001324 xml_report=args.xml_report,
1325 build_only=args.build_only)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001326 if not errors:
Nicolas Nobleb09078f2015-01-14 18:06:05 -08001327 jobset.message('SUCCESS', 'All tests passed', do_newline=True)
1328 else:
1329 jobset.message('FAILED', 'Some tests failed', do_newline=True)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001330 exit_code = 0
1331 if BuildAndRunError.BUILD in errors:
1332 exit_code |= 1
Craig Tiller4f2be362016-01-08 08:59:20 -08001333 if BuildAndRunError.TEST in errors and not args.travis:
Craig Tillereb9de8b2016-01-08 08:57:41 -08001334 exit_code |= 2
Craig Tiller4f2be362016-01-08 08:59:20 -08001335 if BuildAndRunError.POST_TEST in errors:
1336 exit_code |= 4
Craig Tillereb9de8b2016-01-08 08:57:41 -08001337 sys.exit(exit_code)