blob: d3819c08840f761a1cb1c94e18cf9f34d255b59a [file] [log] [blame]
Nathaniel Manistaae4fbcd2015-09-23 16:29:44 +00001#!/usr/bin/env python2.7
Craig Tiller6169d5f2016-03-31 07:46:18 -07002# Copyright 2015, Google Inc.
Craig Tillerc2c79212015-02-16 12:00:01 -08003# All rights reserved.
4#
5# Redistribution and use in source and binary forms, with or without
6# modification, are permitted provided that the following conditions are
7# met:
8#
9# * Redistributions of source code must retain the above copyright
10# notice, this list of conditions and the following disclaimer.
11# * Redistributions in binary form must reproduce the above
12# copyright notice, this list of conditions and the following disclaimer
13# in the documentation and/or other materials provided with the
14# distribution.
15# * Neither the name of Google Inc. nor the names of its
16# contributors may be used to endorse or promote products derived from
17# this software without specific prior written permission.
18#
19# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
Nicolas Nobleddef2462015-01-06 18:08:25 -080031"""Run tests in parallel."""
32
33import argparse
Craig Tiller9279ac22016-01-20 17:05:23 -080034import ast
Nicolas Nobleddef2462015-01-06 18:08:25 -080035import glob
Craig Tillerf53d9c82015-08-04 14:19:43 -070036import hashlib
Nicolas Nobleddef2462015-01-06 18:08:25 -080037import itertools
Craig Tiller261dd982015-01-16 16:41:45 -080038import json
Nicolas Nobleddef2462015-01-06 18:08:25 -080039import multiprocessing
Craig Tiller1cc11db2015-01-15 22:50:50 -080040import os
David Garcia Quintas79e389f2015-06-02 17:49:42 -070041import platform
42import random
Craig Tillerfe406ec2015-02-24 13:55:12 -080043import re
Craig Tiller82875232015-09-25 13:57:34 -070044import socket
David Garcia Quintas79e389f2015-06-02 17:49:42 -070045import subprocess
Nicolas Nobleddef2462015-01-06 18:08:25 -080046import sys
Craig Tillerf0a293e2015-10-12 10:05:50 -070047import tempfile
48import traceback
ctiller3040cb72015-01-07 12:13:17 -080049import time
Craig Tillerf53d9c82015-08-04 14:19:43 -070050import urllib2
Jan Tattermusch03c01062015-12-11 14:28:56 -080051import uuid
Nicolas Nobleddef2462015-01-06 18:08:25 -080052
53import jobset
Adele Zhoua30f8292015-11-02 13:15:46 -080054import report_utils
ctiller3040cb72015-01-07 12:13:17 -080055import watch_dirs
Nicolas Nobleddef2462015-01-06 18:08:25 -080056
Craig Tillerb361b4e2016-01-06 11:44:17 -080057
Jan Tattermusch3b5121b2016-02-22 17:41:05 -080058_ROOT = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), '../..'))
59os.chdir(_ROOT)
Craig Tiller2cc2b842015-02-27 11:38:31 -080060
61
Craig Tiller06805272015-06-11 14:46:47 -070062_FORCE_ENVIRON_FOR_WRAPPERS = {}
63
64
Craig Tillerd50993d2015-08-05 08:04:36 -070065def platform_string():
Nicolas "Pixel" Noblef72d7b52015-12-03 03:07:43 +010066 return jobset.platform_string()
Craig Tillerd50993d2015-08-05 08:04:36 -070067
68
Craig Tiller738c3342015-01-12 14:28:33 -080069# SimpleConfig: just compile with CONFIG=config, and run the binary to test
Craig Tillera0f85172016-01-20 15:56:06 -080070class Config(object):
Craig Tillerb50d1662015-01-15 17:28:21 -080071
Craig Tillera0f85172016-01-20 15:56:06 -080072 def __init__(self, config, environ=None, timeout_multiplier=1, tool_prefix=[]):
murgatroid99132ce6a2015-03-04 17:29:14 -080073 if environ is None:
74 environ = {}
Craig Tiller738c3342015-01-12 14:28:33 -080075 self.build_config = config
Craig Tillerc7449162015-01-16 14:42:10 -080076 self.allow_hashing = (config != 'gcov')
Craig Tiller547db2b2015-01-30 14:08:39 -080077 self.environ = environ
murgatroid99132ce6a2015-03-04 17:29:14 -080078 self.environ['CONFIG'] = config
Craig Tillera0f85172016-01-20 15:56:06 -080079 self.tool_prefix = tool_prefix
Masood Malekghassemi26ea9e22015-10-09 15:19:17 -070080 self.timeout_multiplier = timeout_multiplier
Craig Tiller738c3342015-01-12 14:28:33 -080081
Masood Malekghassemi26ea9e22015-10-09 15:19:17 -070082 def job_spec(self, cmdline, hash_targets, timeout_seconds=5*60,
Craig Tillerde7edf82016-03-20 09:12:16 -070083 shortname=None, environ={}, cpu_cost=1.0, flaky=False):
Craig Tiller49f61322015-03-03 13:02:11 -080084 """Construct a jobset.JobSpec for a test under this config
85
86 Args:
87 cmdline: a list of strings specifying the command line the test
88 would like to run
89 hash_targets: either None (don't do caching of test results), or
90 a list of strings specifying files to include in a
91 binary hash to check if a test has changed
92 -- if used, all artifacts needed to run the test must
93 be listed
94 """
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 Tiller547db2b2015-01-30 14:08:39 -0800103 hash_targets=hash_targets
Craig Tillerd4509a12015-09-28 09:18:40 -0700104 if self.allow_hashing 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 Tillerb38197e2016-02-26 10:14:54 -0800156 POLLING_STRATEGIES = {
157 'windows': ['all'],
158 'mac': ['all'],
159 'posix': ['all'],
Craig Tillerc29298d2016-05-31 13:45:38 -0700160 'linux': ['poll', 'legacy']
Craig Tillerb38197e2016-02-26 10:14:54 -0800161 }
Craig Tiller946ce7a2016-04-06 10:35:58 -0700162 for target in binaries:
163 polling_strategies = (POLLING_STRATEGIES[self.platform]
164 if target.get('uses_polling', True)
165 else ['all'])
166 for polling_strategy in polling_strategies:
167 env={'GRPC_DEFAULT_SSL_ROOTS_FILE_PATH':
168 _ROOT + '/src/core/lib/tsi/test_creds/ca.pem',
Craig Tillered735102016-04-06 12:59:23 -0700169 'GRPC_POLL_STRATEGY': polling_strategy}
Craig Tiller946ce7a2016-04-06 10:35:58 -0700170 shortname_ext = '' if polling_strategy=='all' else ' polling=%s' % polling_strategy
Craig Tillerb38197e2016-02-26 10:14:54 -0800171 if self.config.build_config in target['exclude_configs']:
172 continue
173 if self.platform == 'windows':
174 binary = 'vsprojects/%s%s/%s.exe' % (
175 'x64/' if self.args.arch == 'x64' else '',
176 _MSBUILD_CONFIG[self.config.build_config],
177 target['name'])
Craig Tillerca62ff02016-02-24 22:22:57 -0800178 else:
Craig Tillerb38197e2016-02-26 10:14:54 -0800179 binary = 'bins/%s/%s' % (self.config.build_config, target['name'])
180 if os.path.isfile(binary):
181 if 'gtest' in target and target['gtest']:
182 # here we parse the output of --gtest_list_tests to build up a
183 # complete list of the tests contained in a binary
184 # for each test, we then add a job to run, filtering for just that
185 # test
186 with open(os.devnull, 'w') as fnull:
187 tests = subprocess.check_output([binary, '--gtest_list_tests'],
188 stderr=fnull)
189 base = None
190 for line in tests.split('\n'):
191 i = line.find('#')
192 if i >= 0: line = line[:i]
193 if not line: continue
194 if line[0] != ' ':
195 base = line.strip()
196 else:
197 assert base is not None
198 assert line[1] == ' '
199 test = base + line.strip()
200 cmdline = [binary] + ['--gtest_filter=%s' % test]
201 out.append(self.config.job_spec(cmdline, [binary],
Craig Tiller334db352016-02-26 15:19:49 -0800202 shortname='%s:%s %s' % (binary, test, shortname_ext),
Craig Tillerb38197e2016-02-26 10:14:54 -0800203 cpu_cost=target['cpu_cost'],
204 environ=env))
205 else:
206 cmdline = [binary] + target['args']
207 out.append(self.config.job_spec(cmdline, [binary],
208 shortname=' '.join(cmdline) + shortname_ext,
209 cpu_cost=target['cpu_cost'],
Craig Tillerc2278152016-03-21 08:59:54 -0700210 flaky=target.get('flaky', False),
Craig Tillerb38197e2016-02-26 10:14:54 -0800211 environ=env))
212 elif self.args.regex == '.*' or self.platform == 'windows':
213 print '\nWARNING: binary not found, skipping', binary
Nicolas Noblee1445362015-05-11 17:40:26 -0700214 return sorted(out)
Craig Tillerc7449162015-01-16 14:42:10 -0800215
Jan Tattermusch77db4322016-02-20 20:19:35 -0800216 def make_targets(self):
217 test_regex = self.args.regex
218 if self.platform != 'windows' and self.args.regex != '.*':
Craig Tiller883064c2015-11-04 10:06:10 -0800219 # use the regex to minimize the number of things to build
Craig Tillerb0f275e2016-01-27 10:45:50 -0800220 return [os.path.basename(target['name'])
Craig Tiller883064c2015-11-04 10:06:10 -0800221 for target in get_c_tests(False, self.test_lang)
Craig Tillerb0f275e2016-01-27 10:45:50 -0800222 if re.search(test_regex, '/' + target['name'])]
Jan Tattermusch77db4322016-02-20 20:19:35 -0800223 if self.platform == 'windows':
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700224 # don't build tools on windows just yet
225 return ['buildtests_%s' % self.make_target]
Craig Tiller7552f0f2015-06-19 17:46:20 -0700226 return ['buildtests_%s' % self.make_target, 'tools_%s' % self.make_target]
Craig Tillerc7449162015-01-16 14:42:10 -0800227
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800228 def make_options(self):
Jan Tattermuschc96caf82016-02-22 17:31:02 -0800229 return self._make_options;
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800230
murgatroid99256d3df2015-09-21 16:58:02 -0700231 def pre_build_steps(self):
Jan Tattermusch874aec02015-10-07 19:26:19 -0700232 if self.platform == 'windows':
233 return [['tools\\run_tests\\pre_build_c.bat']]
234 else:
235 return []
murgatroid99256d3df2015-09-21 16:58:02 -0700236
Craig Tillerc7449162015-01-16 14:42:10 -0800237 def build_steps(self):
238 return []
239
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200240 def post_tests_steps(self):
241 if self.platform == 'windows':
242 return []
243 else:
244 return [['tools/run_tests/post_tests_c.sh']]
245
murgatroid99a3e244f2015-09-22 11:25:53 -0700246 def makefile_name(self):
247 return 'Makefile'
248
Jan Tattermusch6d258c52016-06-10 09:36:51 -0700249 def _clang_make_options(self, version_suffix=''):
250 return ['CC=clang%s' % version_suffix,
251 'CXX=clang++%s' % version_suffix,
252 'LD=clang%s' % version_suffix,
253 'LDXX=clang++%s' % version_suffix]
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800254
Jan Tattermusch6d258c52016-06-10 09:36:51 -0700255 def _gcc_make_options(self, version_suffix):
256 return ['CC=gcc%s' % version_suffix,
257 'CXX=g++%s' % version_suffix,
258 'LD=gcc%s' % version_suffix,
259 'LDXX=g++%s' % version_suffix]
Jan Tattermusch9bb70622016-03-18 10:28:54 -0700260
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800261 def _compiler_options(self, use_docker, compiler):
262 """Returns docker distro and make options to use for given compiler."""
Jan Tattermuschfd3857b2016-06-03 12:24:03 -0700263 if not use_docker and not _is_use_docker_child():
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800264 _check_compiler(compiler, ['default'])
265
266 if compiler == 'gcc4.9' or compiler == 'default':
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800267 return ('jessie', [])
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800268 elif compiler == 'gcc4.4':
Jan Tattermusch6d258c52016-06-10 09:36:51 -0700269 return ('wheezy', self._gcc_make_options(version_suffix='-4.4'))
270 elif compiler == 'gcc4.6':
271 return ('wheezy', self._gcc_make_options(version_suffix='-4.6'))
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800272 elif compiler == 'gcc5.3':
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800273 return ('ubuntu1604', [])
274 elif compiler == 'clang3.4':
Jan Tattermusch6d258c52016-06-10 09:36:51 -0700275 # on ubuntu1404, clang-3.4 alias doesn't exist, just use 'clang'
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800276 return ('ubuntu1404', self._clang_make_options())
Jan Tattermusch6d258c52016-06-10 09:36:51 -0700277 elif compiler == 'clang3.5':
278 return ('jessie', self._clang_make_options(version_suffix='-3.5'))
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800279 elif compiler == 'clang3.6':
Jan Tattermusch6d258c52016-06-10 09:36:51 -0700280 return ('ubuntu1604', self._clang_make_options(version_suffix='-3.6'))
281 elif compiler == 'clang3.7':
282 return ('ubuntu1604', self._clang_make_options(version_suffix='-3.7'))
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800283 else:
284 raise Exception('Compiler %s not supported.' % compiler)
285
Jan Tattermusch77db4322016-02-20 20:19:35 -0800286 def dockerfile_dir(self):
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800287 return 'tools/dockerfile/test/cxx_%s_%s' % (self._docker_distro,
288 _docker_arch_suffix(self.args.arch))
Jan Tattermusch788ee232016-01-26 12:19:44 -0800289
murgatroid99132ce6a2015-03-04 17:29:14 -0800290 def __str__(self):
291 return self.make_target
292
Craig Tillercc0535d2015-12-08 15:14:47 -0800293
murgatroid992c8d5162015-01-26 10:41:21 -0800294class NodeLanguage(object):
295
Jan Tattermusche477b842016-02-06 22:19:01 -0800296 def __init__(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800297 self.platform = platform_string()
Jan Tattermusche477b842016-02-06 22:19:01 -0800298
Jan Tattermusch77db4322016-02-20 20:19:35 -0800299 def configure(self, config, args):
300 self.config = config
301 self.args = args
murgatroid999fab4382016-04-29 15:05:00 -0700302 _check_compiler(self.args.compiler, ['default', 'node0.12',
303 'node4', 'node5'])
304 if self.args.compiler == 'default':
305 self.node_version = '4'
306 else:
307 # Take off the word "node"
308 self.node_version = self.args.compiler[4:]
Jan Tattermusch77db4322016-02-20 20:19:35 -0800309
310 def test_specs(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800311 if self.platform == 'windows':
Jan Tattermusch77db4322016-02-20 20:19:35 -0800312 return [self.config.job_spec(['tools\\run_tests\\run_node.bat'], None)]
Michael Lumishaaa876a2016-02-10 15:27:58 -0800313 else:
Jan Tattermusch77db4322016-02-20 20:19:35 -0800314 return [self.config.job_spec(['tools/run_tests/run_node.sh', self.node_version],
315 None,
316 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
murgatroid992c8d5162015-01-26 10:41:21 -0800317
murgatroid99256d3df2015-09-21 16:58:02 -0700318 def pre_build_steps(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800319 if self.platform == 'windows':
320 return [['tools\\run_tests\\pre_build_node.bat']]
321 else:
322 return [['tools/run_tests/pre_build_node.sh', self.node_version]]
murgatroid99256d3df2015-09-21 16:58:02 -0700323
Jan Tattermusch77db4322016-02-20 20:19:35 -0800324 def make_targets(self):
murgatroid99db5b1602015-10-01 13:20:11 -0700325 return []
murgatroid992c8d5162015-01-26 10:41:21 -0800326
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800327 def make_options(self):
328 return []
329
murgatroid992c8d5162015-01-26 10:41:21 -0800330 def build_steps(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800331 if self.platform == 'windows':
332 return [['tools\\run_tests\\build_node.bat']]
333 else:
334 return [['tools/run_tests/build_node.sh', self.node_version]]
Craig Tillerc7449162015-01-16 14:42:10 -0800335
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200336 def post_tests_steps(self):
337 return []
338
murgatroid99a3e244f2015-09-22 11:25:53 -0700339 def makefile_name(self):
340 return 'Makefile'
341
Jan Tattermusch77db4322016-02-20 20:19:35 -0800342 def dockerfile_dir(self):
343 return 'tools/dockerfile/test/node_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800344
murgatroid99132ce6a2015-03-04 17:29:14 -0800345 def __str__(self):
346 return 'node'
347
Craig Tiller99775822015-01-30 13:07:16 -0800348
Craig Tillerc7449162015-01-16 14:42:10 -0800349class PhpLanguage(object):
350
Jan Tattermusch77db4322016-02-20 20:19:35 -0800351 def configure(self, config, args):
352 self.config = config
353 self.args = args
354 _check_compiler(self.args.compiler, ['default'])
355
356 def test_specs(self):
357 return [self.config.job_spec(['src/php/bin/run_tests.sh'], None,
358 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
Craig Tillerc7449162015-01-16 14:42:10 -0800359
murgatroid99256d3df2015-09-21 16:58:02 -0700360 def pre_build_steps(self):
361 return []
362
Jan Tattermusch77db4322016-02-20 20:19:35 -0800363 def make_targets(self):
Craig Tilleraf7cf542015-05-22 10:07:34 -0700364 return ['static_c', 'shared_c']
Craig Tillerc7449162015-01-16 14:42:10 -0800365
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800366 def make_options(self):
367 return []
368
Craig Tillerc7449162015-01-16 14:42:10 -0800369 def build_steps(self):
370 return [['tools/run_tests/build_php.sh']]
371
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200372 def post_tests_steps(self):
Stanley Cheunga6b95482016-01-13 16:10:48 -0800373 return [['tools/run_tests/post_tests_php.sh']]
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200374
murgatroid99a3e244f2015-09-22 11:25:53 -0700375 def makefile_name(self):
376 return 'Makefile'
377
Jan Tattermusch77db4322016-02-20 20:19:35 -0800378 def dockerfile_dir(self):
379 return 'tools/dockerfile/test/php_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800380
murgatroid99132ce6a2015-03-04 17:29:14 -0800381 def __str__(self):
382 return 'php'
383
Craig Tillerc7449162015-01-16 14:42:10 -0800384
Nathaniel Manista840615e2015-01-22 20:31:47 +0000385class PythonLanguage(object):
386
Jan Tattermusch77db4322016-02-20 20:19:35 -0800387 def configure(self, config, args):
388 self.config = config
389 self.args = args
Ken Payson1efb6012016-06-08 13:06:44 -0700390 self._tox_envs = self._get_tox_envs(self.args.compiler)
Jan Tattermusch77db4322016-02-20 20:19:35 -0800391
392 def test_specs(self):
Jan Tattermusch072ebaa2016-03-01 18:33:12 -0800393 # load list of known test suites
394 with open('src/python/grpcio/tests/tests.json') as tests_json_file:
395 tests_json = json.load(tests_json_file)
Masood Malekghassemi2b841622015-07-28 17:39:02 -0700396 environment = dict(_FORCE_ENVIRON_FOR_WRAPPERS)
Ken Paysonc47e43d2016-05-04 18:46:16 -0700397 environment['PYTHONPATH'] = '{}:{}'.format(
398 os.path.abspath('src/python/gens'),
399 os.path.abspath('src/python/grpcio_health_checking'))
Jan Tattermusch072ebaa2016-03-01 18:33:12 -0800400 if self.config.build_config != 'gcov':
401 return [self.config.job_spec(
Ken Payson1efb6012016-06-08 13:06:44 -0700402 ['tools/run_tests/run_python.sh', tox_env],
Jan Tattermusch072ebaa2016-03-01 18:33:12 -0800403 None,
404 environ=dict(environment.items() +
Masood Malekghassemif7ff8be2016-03-09 15:27:28 -0800405 [('GRPC_PYTHON_TESTRUNNER_FILTER', suite_name)]),
Ken Payson1efb6012016-06-08 13:06:44 -0700406 shortname='%s.test.%s' % (tox_env, suite_name),
Jan Tattermusch072ebaa2016-03-01 18:33:12 -0800407 timeout_seconds=5*60)
Ken Payson1efb6012016-06-08 13:06:44 -0700408 for suite_name in tests_json
409 for tox_env in self._tox_envs]
Jan Tattermusch072ebaa2016-03-01 18:33:12 -0800410 else:
Ken Payson1efb6012016-06-08 13:06:44 -0700411 return [self.config.job_spec(['tools/run_tests/run_python.sh', tox_env],
Jan Tattermusch072ebaa2016-03-01 18:33:12 -0800412 None,
413 environ=environment,
Ken Payson1efb6012016-06-08 13:06:44 -0700414 shortname='%s.test.coverage' % tox_env,
415 timeout_seconds=15*60)
416 for tox_env in self._tox_envs]
Jan Tattermusch072ebaa2016-03-01 18:33:12 -0800417
Nathaniel Manista840615e2015-01-22 20:31:47 +0000418
murgatroid99256d3df2015-09-21 16:58:02 -0700419 def pre_build_steps(self):
420 return []
421
Jan Tattermusch77db4322016-02-20 20:19:35 -0800422 def make_targets(self):
Craig Tilleraf7cf542015-05-22 10:07:34 -0700423 return ['static_c', 'grpc_python_plugin', 'shared_c']
Nathaniel Manista840615e2015-01-22 20:31:47 +0000424
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800425 def make_options(self):
426 return []
427
Nathaniel Manista840615e2015-01-22 20:31:47 +0000428 def build_steps(self):
Ken Payson1efb6012016-06-08 13:06:44 -0700429 return [['tools/run_tests/build_python.sh', tox_env]
430 for tox_env in self._tox_envs]
Nathaniel Manista840615e2015-01-22 20:31:47 +0000431
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200432 def post_tests_steps(self):
433 return []
434
murgatroid99a3e244f2015-09-22 11:25:53 -0700435 def makefile_name(self):
436 return 'Makefile'
437
Jan Tattermusch77db4322016-02-20 20:19:35 -0800438 def dockerfile_dir(self):
439 return 'tools/dockerfile/test/python_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800440
Ken Payson1efb6012016-06-08 13:06:44 -0700441 def _get_tox_envs(self, compiler):
Jan Tattermusch825471c2016-04-25 16:52:25 -0700442 """Returns name of tox environment based on selected compiler."""
Ken Payson1efb6012016-06-08 13:06:44 -0700443 if compiler == 'default':
444 return ('py27', 'py34')
445 elif compiler == 'python2.7':
446 return ('py27',)
Jan Tattermusch825471c2016-04-25 16:52:25 -0700447 elif compiler == 'python3.4':
Ken Payson1efb6012016-06-08 13:06:44 -0700448 return ('py34',)
Jan Tattermusch825471c2016-04-25 16:52:25 -0700449 else:
450 raise Exception('Compiler %s not supported.' % compiler)
451
murgatroid99132ce6a2015-03-04 17:29:14 -0800452 def __str__(self):
453 return 'python'
454
Craig Tillerd625d812015-04-08 15:52:35 -0700455
murgatroid996a4c4fa2015-02-27 12:08:57 -0800456class RubyLanguage(object):
457
Jan Tattermusch77db4322016-02-20 20:19:35 -0800458 def configure(self, config, args):
459 self.config = config
460 self.args = args
461 _check_compiler(self.args.compiler, ['default'])
462
463 def test_specs(self):
464 return [self.config.job_spec(['tools/run_tests/run_ruby.sh'], None,
465 timeout_seconds=10*60,
466 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
murgatroid996a4c4fa2015-02-27 12:08:57 -0800467
murgatroid99256d3df2015-09-21 16:58:02 -0700468 def pre_build_steps(self):
Nicolas "Pixel" Noblebcf988f2015-10-08 03:00:42 +0200469 return [['tools/run_tests/pre_build_ruby.sh']]
murgatroid99256d3df2015-09-21 16:58:02 -0700470
Jan Tattermusch4651bef2016-02-23 08:31:25 -0800471 def make_targets(self):
murgatroid997d243df2016-02-18 09:58:05 -0800472 return []
murgatroid996a4c4fa2015-02-27 12:08:57 -0800473
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800474 def make_options(self):
475 return []
476
murgatroid996a4c4fa2015-02-27 12:08:57 -0800477 def build_steps(self):
478 return [['tools/run_tests/build_ruby.sh']]
479
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200480 def post_tests_steps(self):
Nicolas "Pixel" Noble7ef1e532015-12-02 00:55:33 +0100481 return [['tools/run_tests/post_tests_ruby.sh']]
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200482
murgatroid99a3e244f2015-09-22 11:25:53 -0700483 def makefile_name(self):
484 return 'Makefile'
485
Jan Tattermusch77db4322016-02-20 20:19:35 -0800486 def dockerfile_dir(self):
487 return 'tools/dockerfile/test/ruby_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800488
murgatroid99132ce6a2015-03-04 17:29:14 -0800489 def __str__(self):
490 return 'ruby'
491
Craig Tillerd625d812015-04-08 15:52:35 -0700492
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800493class CSharpLanguage(object):
Jan Tattermusch77db4322016-02-20 20:19:35 -0800494
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700495 def __init__(self):
Craig Tillerd50993d2015-08-05 08:04:36 -0700496 self.platform = platform_string()
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700497
Jan Tattermusch77db4322016-02-20 20:19:35 -0800498 def configure(self, config, args):
499 self.config = config
500 self.args = args
Jan Tattermusch6d28d352016-03-25 15:07:22 -0700501 if self.platform == 'windows':
Jan Tattermuschb2531e22016-03-25 16:14:41 -0700502 # Explicitly choosing between x86 and x64 arch doesn't work yet
503 _check_arch(self.args.arch, ['default'])
Jan Tattermusch6e2f88c2016-06-21 10:52:40 -0700504 # CoreCLR use 64bit runtime by default.
505 arch_option = 'x64' if self.args.compiler == 'coreclr' else self.args.arch
Jan Tattermusch6d28d352016-03-25 15:07:22 -0700506 self._make_options = [_windows_toolset_option(self.args.compiler),
Jan Tattermusch6e2f88c2016-06-21 10:52:40 -0700507 _windows_arch_option(arch_option)]
Jan Tattermusch6d28d352016-03-25 15:07:22 -0700508 else:
Jan Tattermuschbc98af12016-06-17 18:38:27 -0700509 _check_compiler(self.args.compiler, ['default', 'coreclr'])
510 if self.platform == 'linux' and self.args.compiler == 'coreclr':
511 self._docker_distro = 'coreclr'
Jan Tattermusch76511a52016-06-17 14:00:57 -0700512
Jan Tattermusch6d28d352016-03-25 15:07:22 -0700513 if self.platform == 'mac':
Jan Tattermusch2a322c22016-03-30 13:55:07 -0700514 # TODO(jtattermusch): EMBED_ZLIB=true currently breaks the mac build
Jan Tattermusch6d082202016-06-21 10:03:38 -0700515 self._make_options = ['EMBED_OPENSSL=true']
516 if self.args.compiler != 'coreclr':
517 # On Mac, official distribution of mono is 32bit.
518 self._make_options += ['CFLAGS=-m32', 'LDFLAGS=-m32']
Jan Tattermusch6d28d352016-03-25 15:07:22 -0700519 else:
520 self._make_options = ['EMBED_OPENSSL=true', 'EMBED_ZLIB=true']
Jan Tattermusch77db4322016-02-20 20:19:35 -0800521
522 def test_specs(self):
Jan Tattermusch03c01062015-12-11 14:28:56 -0800523 with open('src/csharp/tests.json') as f:
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700524 tests_by_assembly = json.load(f)
Jan Tattermusch03c01062015-12-11 14:28:56 -0800525
Jan Tattermuscha2d964c2016-02-22 17:33:09 -0800526 msbuild_config = _MSBUILD_CONFIG[self.config.build_config]
Jan Tattermuschbc98af12016-06-17 18:38:27 -0700527 nunit_args = ['--labels=All']
Jan Tattermusch76511a52016-06-17 14:00:57 -0700528 assembly_subdir = 'bin/%s' % msbuild_config
529 assembly_extension = '.exe'
530
531 if self.args.compiler == 'coreclr':
Jan Tattermusch64c137c2016-06-20 17:54:19 -0700532 if self.platform == 'linux':
533 assembly_subdir += '/netstandard1.5/debian.8-x64'
534 assembly_extension = ''
Jan Tattermusch6d082202016-06-21 10:03:38 -0700535 if self.platform == 'mac':
536 assembly_subdir += '/netstandard1.5/osx.10.11-x64'
537 assembly_extension = ''
Jan Tattermusch64c137c2016-06-20 17:54:19 -0700538 else:
539 assembly_subdir += '/netstandard1.5/win7-x64'
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700540 runtime_cmd = []
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700541 else:
Jan Tattermuschbc98af12016-06-17 18:38:27 -0700542 nunit_args += ['--noresult', '--workers=1']
543 if self.platform == 'windows':
544 runtime_cmd = []
545 else:
546 runtime_cmd = ['mono']
Jan Tattermuschbf3b1532015-10-26 10:24:42 -0700547
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700548 specs = []
549 for assembly in tests_by_assembly.iterkeys():
Jan Tattermusch76511a52016-06-17 14:00:57 -0700550 assembly_file = 'src/csharp/%s/%s/%s%s' % (assembly,
551 assembly_subdir,
552 assembly,
553 assembly_extension)
Jan Tattermuscha5f1f122016-04-11 15:49:56 -0700554 if self.config.build_config != 'gcov' or self.platform != 'windows':
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700555 # normally, run each test as a separate process
556 for test in tests_by_assembly[assembly]:
557 cmdline = runtime_cmd + [assembly_file, '--test=%s' % test] + nunit_args
558 specs.append(self.config.job_spec(cmdline,
559 None,
560 shortname='csharp.%s' % test,
561 environ=_FORCE_ENVIRON_FOR_WRAPPERS))
562 else:
Jan Tattermuscha5f1f122016-04-11 15:49:56 -0700563 # For C# test coverage, run all tests from the same assembly at once
564 # using OpenCover.Console (only works on Windows).
565 cmdline = ['src\\csharp\\packages\\OpenCover.4.6.519\\tools\\OpenCover.Console.exe',
566 '-target:%s' % assembly_file,
567 '-targetdir:src\\csharp',
568 '-targetargs:%s' % ' '.join(nunit_args),
569 '-filter:+[Grpc.Core]*',
570 '-register:user',
571 '-output:src\\csharp\\coverage_csharp_%s.xml' % assembly]
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700572
Jan Tattermuscha5f1f122016-04-11 15:49:56 -0700573 # set really high cpu_cost to make sure instances of OpenCover.Console run exclusively
574 # to prevent problems with registering the profiler.
575 run_exclusive = 1000000
Jan Tattermusch35e608f2016-04-09 16:35:06 -0700576 specs.append(self.config.job_spec(cmdline,
577 None,
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700578 shortname='csharp.coverage.%s' % assembly,
Jan Tattermuscha5f1f122016-04-11 15:49:56 -0700579 cpu_cost=run_exclusive,
Jan Tattermusch77db4322016-02-20 20:19:35 -0800580 environ=_FORCE_ENVIRON_FOR_WRAPPERS))
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700581 return specs
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800582
murgatroid99256d3df2015-09-21 16:58:02 -0700583 def pre_build_steps(self):
Jan Tattermusch48423fc2015-10-07 18:59:16 -0700584 if self.platform == 'windows':
Jan Tattermusch874aec02015-10-07 19:26:19 -0700585 return [['tools\\run_tests\\pre_build_csharp.bat']]
Jan Tattermusch48423fc2015-10-07 18:59:16 -0700586 else:
587 return [['tools/run_tests/pre_build_csharp.sh']]
murgatroid99256d3df2015-09-21 16:58:02 -0700588
Jan Tattermusch77db4322016-02-20 20:19:35 -0800589 def make_targets(self):
Jan Tattermusch6d28d352016-03-25 15:07:22 -0700590 return ['grpc_csharp_ext']
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800591
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800592 def make_options(self):
Jan Tattermusch6d28d352016-03-25 15:07:22 -0700593 return self._make_options;
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800594
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800595 def build_steps(self):
Jan Tattermusch76511a52016-06-17 14:00:57 -0700596 if self.args.compiler == 'coreclr':
Jan Tattermuschbc98af12016-06-17 18:38:27 -0700597 if self.platform == 'windows':
598 return [['tools\\run_tests\\build_csharp_coreclr.bat']]
599 else:
600 return [['tools/run_tests/build_csharp_coreclr.sh']]
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700601 else:
Jan Tattermusch76511a52016-06-17 14:00:57 -0700602 if self.platform == 'windows':
603 return [[_windows_build_bat(self.args.compiler),
604 'src/csharp/Grpc.sln',
605 '/p:Configuration=%s' % _MSBUILD_CONFIG[self.config.build_config]]]
606 else:
607 return [['tools/run_tests/build_csharp.sh']]
Nathaniel Manista840615e2015-01-22 20:31:47 +0000608
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200609 def post_tests_steps(self):
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700610 if self.platform == 'windows':
611 return [['tools\\run_tests\\post_tests_csharp.bat']]
612 else:
613 return [['tools/run_tests/post_tests_csharp.sh']]
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200614
murgatroid99a3e244f2015-09-22 11:25:53 -0700615 def makefile_name(self):
616 return 'Makefile'
617
Jan Tattermusch77db4322016-02-20 20:19:35 -0800618 def dockerfile_dir(self):
Jan Tattermusch76511a52016-06-17 14:00:57 -0700619 return 'tools/dockerfile/test/csharp_%s_%s' % (self._docker_distro,
620 _docker_arch_suffix(self.args.arch))
Jan Tattermusch788ee232016-01-26 12:19:44 -0800621
murgatroid99132ce6a2015-03-04 17:29:14 -0800622 def __str__(self):
623 return 'csharp'
624
Craig Tillerd625d812015-04-08 15:52:35 -0700625
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700626class ObjCLanguage(object):
627
Jan Tattermusch77db4322016-02-20 20:19:35 -0800628 def configure(self, config, args):
629 self.config = config
630 self.args = args
631 _check_compiler(self.args.compiler, ['default'])
632
633 def test_specs(self):
634 return [self.config.job_spec(['src/objective-c/tests/run_tests.sh'], None,
635 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700636
murgatroid99256d3df2015-09-21 16:58:02 -0700637 def pre_build_steps(self):
638 return []
639
Jan Tattermusch77db4322016-02-20 20:19:35 -0800640 def make_targets(self):
Jorge Canizalesd0b32e92015-07-30 23:08:43 -0700641 return ['grpc_objective_c_plugin', 'interop_server']
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700642
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800643 def make_options(self):
644 return []
645
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700646 def build_steps(self):
Jorge Canizalesd0b32e92015-07-30 23:08:43 -0700647 return [['src/objective-c/tests/build_tests.sh']]
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700648
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200649 def post_tests_steps(self):
650 return []
651
murgatroid99a3e244f2015-09-22 11:25:53 -0700652 def makefile_name(self):
653 return 'Makefile'
654
Jan Tattermusch77db4322016-02-20 20:19:35 -0800655 def dockerfile_dir(self):
Jan Tattermusch788ee232016-01-26 12:19:44 -0800656 return None
657
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700658 def __str__(self):
659 return 'objc'
660
661
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100662class Sanity(object):
663
Jan Tattermusch77db4322016-02-20 20:19:35 -0800664 def configure(self, config, args):
665 self.config = config
666 self.args = args
667 _check_compiler(self.args.compiler, ['default'])
668
669 def test_specs(self):
Craig Tiller94d04a52016-01-20 10:58:23 -0800670 import yaml
Jan Tattermusch788ee232016-01-26 12:19:44 -0800671 with open('tools/run_tests/sanity/sanity_tests.yaml', 'r') as f:
Jan Tattermusch77db4322016-02-20 20:19:35 -0800672 return [self.config.job_spec(cmd['script'].split(), None,
673 timeout_seconds=None, environ={'TEST': 'true'},
674 cpu_cost=cmd.get('cpu_cost', 1))
Craig Tiller94d04a52016-01-20 10:58:23 -0800675 for cmd in yaml.load(f)]
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100676
murgatroid99256d3df2015-09-21 16:58:02 -0700677 def pre_build_steps(self):
678 return []
679
Jan Tattermusch77db4322016-02-20 20:19:35 -0800680 def make_targets(self):
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100681 return ['run_dep_checks']
682
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800683 def make_options(self):
684 return []
685
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100686 def build_steps(self):
687 return []
688
Nicolas "Pixel" Noble87879b32015-10-12 23:28:53 +0200689 def post_tests_steps(self):
690 return []
691
murgatroid99a3e244f2015-09-22 11:25:53 -0700692 def makefile_name(self):
693 return 'Makefile'
694
Jan Tattermusch77db4322016-02-20 20:19:35 -0800695 def dockerfile_dir(self):
Jan Tattermusche70b3c52016-02-07 20:21:02 -0800696 return 'tools/dockerfile/test/sanity'
Jan Tattermusch788ee232016-01-26 12:19:44 -0800697
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100698 def __str__(self):
699 return 'sanity'
700
Nicolas "Pixel" Noblee55cd7f2015-04-14 17:59:13 +0200701
Craig Tiller738c3342015-01-12 14:28:33 -0800702# different configurations we can run under
Craig Tillera0f85172016-01-20 15:56:06 -0800703with open('tools/run_tests/configs.json') as f:
Craig Tiller1dce9062016-01-20 17:01:56 -0800704 _CONFIGS = dict((cfg['config'], Config(**cfg)) for cfg in ast.literal_eval(f.read()))
Craig Tiller738c3342015-01-12 14:28:33 -0800705
706
Craig Tillerc7449162015-01-16 14:42:10 -0800707_LANGUAGES = {
Craig Tillere9c959d2015-01-18 10:23:26 -0800708 'c++': CLanguage('cxx', 'c++'),
709 'c': CLanguage('c', 'c'),
murgatroid992c8d5162015-01-26 10:41:21 -0800710 'node': NodeLanguage(),
Nathaniel Manista840615e2015-01-22 20:31:47 +0000711 'php': PhpLanguage(),
712 'python': PythonLanguage(),
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800713 'ruby': RubyLanguage(),
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100714 'csharp': CSharpLanguage(),
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700715 'objc' : ObjCLanguage(),
Jan Tattermusch70a57e42016-02-20 18:50:27 -0800716 'sanity': Sanity()
Craig Tillereb272bc2015-01-30 13:13:14 -0800717 }
Nicolas Nobleddef2462015-01-06 18:08:25 -0800718
Jan Tattermusch77db4322016-02-20 20:19:35 -0800719
Jan Tattermuscha2d964c2016-02-22 17:33:09 -0800720_MSBUILD_CONFIG = {
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700721 'dbg': 'Debug',
722 'opt': 'Release',
Jan Tattermusche4a69182015-12-15 09:53:01 -0800723 'gcov': 'Debug',
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700724 }
725
David Garcia Quintase90cd372015-05-31 18:15:26 -0700726
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800727def _windows_arch_option(arch):
728 """Returns msbuild cmdline option for selected architecture."""
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800729 if arch == 'default' or arch == 'x86':
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800730 return '/p:Platform=Win32'
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800731 elif arch == 'x64':
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800732 return '/p:Platform=x64'
733 else:
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800734 print 'Architecture %s not supported.' % arch
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800735 sys.exit(1)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800736
Jan Tattermuschf08018a2016-01-26 08:22:09 -0800737
738def _check_arch_option(arch):
739 """Checks that architecture option is valid."""
740 if platform_string() == 'windows':
741 _windows_arch_option(arch)
742 elif platform_string() == 'linux':
743 # On linux, we need to be running under docker with the right architecture.
Jan Tattermusch07fb0422016-01-26 10:46:56 -0800744 runtime_arch = platform.architecture()[0]
Jan Tattermuschf08018a2016-01-26 08:22:09 -0800745 if arch == 'default':
746 return
747 elif runtime_arch == '64bit' and arch == 'x64':
748 return
749 elif runtime_arch == '32bit' and arch == 'x86':
750 return
751 else:
752 print 'Architecture %s does not match current runtime architecture.' % arch
753 sys.exit(1)
754 else:
755 if args.arch != 'default':
756 print 'Architecture %s not supported on current platform.' % args.arch
757 sys.exit(1)
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800758
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800759
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800760def _windows_build_bat(compiler):
761 """Returns name of build.bat for selected compiler."""
Jan Tattermuschbc98af12016-06-17 18:38:27 -0700762 # For CoreCLR, fall back to the default compiler for C core
763 if compiler == 'default' or compiler == 'vs2013' or compiler == 'coreclr':
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800764 return 'vsprojects\\build_vs2013.bat'
765 elif compiler == 'vs2015':
766 return 'vsprojects\\build_vs2015.bat'
767 elif compiler == 'vs2010':
768 return 'vsprojects\\build_vs2010.bat'
769 else:
770 print 'Compiler %s not supported.' % compiler
771 sys.exit(1)
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800772
773
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800774def _windows_toolset_option(compiler):
775 """Returns msbuild PlatformToolset for selected compiler."""
Jan Tattermuschbc98af12016-06-17 18:38:27 -0700776 # For CoreCLR, fall back to the default compiler for C core
777 if compiler == 'default' or compiler == 'vs2013' or compiler == 'coreclr':
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800778 return '/p:PlatformToolset=v120'
779 elif compiler == 'vs2015':
780 return '/p:PlatformToolset=v140'
781 elif compiler == 'vs2010':
782 return '/p:PlatformToolset=v100'
783 else:
784 print 'Compiler %s not supported.' % compiler
785 sys.exit(1)
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800786
787
Jan Tattermusche70b3c52016-02-07 20:21:02 -0800788def _docker_arch_suffix(arch):
789 """Returns suffix to dockerfile dir to use."""
790 if arch == 'default' or arch == 'x64':
791 return 'x64'
792 elif arch == 'x86':
793 return 'x86'
794 else:
795 print 'Architecture %s not supported with current settings.' % arch
796 sys.exit(1)
797
798
David Garcia Quintase90cd372015-05-31 18:15:26 -0700799def runs_per_test_type(arg_str):
800 """Auxilary function to parse the "runs_per_test" flag.
801
802 Returns:
803 A positive integer or 0, the latter indicating an infinite number of
804 runs.
805
806 Raises:
807 argparse.ArgumentTypeError: Upon invalid input.
808 """
809 if arg_str == 'inf':
810 return 0
811 try:
812 n = int(arg_str)
813 if n <= 0: raise ValueError
Craig Tiller50e53e22015-06-01 20:18:21 -0700814 return n
David Garcia Quintase90cd372015-05-31 18:15:26 -0700815 except:
Adele Zhoue4c35612015-10-16 15:34:23 -0700816 msg = '\'{}\' is not a positive integer or \'inf\''.format(arg_str)
David Garcia Quintase90cd372015-05-31 18:15:26 -0700817 raise argparse.ArgumentTypeError(msg)
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700818
819# parse command line
820argp = argparse.ArgumentParser(description='Run grpc tests.')
821argp.add_argument('-c', '--config',
Jan Tattermusch77db4322016-02-20 20:19:35 -0800822 choices=sorted(_CONFIGS.keys()),
823 default='opt')
David Garcia Quintase90cd372015-05-31 18:15:26 -0700824argp.add_argument('-n', '--runs_per_test', default=1, type=runs_per_test_type,
825 help='A positive integer or "inf". If "inf", all tests will run in an '
826 'infinite loop. Especially useful in combination with "-f"')
Craig Tillerfe406ec2015-02-24 13:55:12 -0800827argp.add_argument('-r', '--regex', default='.*', type=str)
Craig Tiller5f735a62016-01-20 09:31:15 -0800828argp.add_argument('-j', '--jobs', default=multiprocessing.cpu_count(), type=int)
Craig Tiller8451e872015-02-27 09:25:51 -0800829argp.add_argument('-s', '--slowdown', default=1.0, type=float)
ctiller3040cb72015-01-07 12:13:17 -0800830argp.add_argument('-f', '--forever',
831 default=False,
832 action='store_const',
833 const=True)
Nicolas "Pixel" Noblea7df3f92015-02-26 22:07:04 +0100834argp.add_argument('-t', '--travis',
835 default=False,
836 action='store_const',
837 const=True)
Nicolas Noble044db742015-01-14 16:57:24 -0800838argp.add_argument('--newline_on_success',
839 default=False,
840 action='store_const',
841 const=True)
Craig Tiller686fb262015-01-15 07:39:09 -0800842argp.add_argument('-l', '--language',
Craig Tiller60f15e62015-05-13 09:05:17 -0700843 choices=['all'] + sorted(_LANGUAGES.keys()),
Craig Tiller686fb262015-01-15 07:39:09 -0800844 nargs='+',
Craig Tiller60f15e62015-05-13 09:05:17 -0700845 default=['all'])
Craig Tillercd43da82015-05-29 08:41:29 -0700846argp.add_argument('-S', '--stop_on_failure',
847 default=False,
848 action='store_const',
849 const=True)
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700850argp.add_argument('--use_docker',
851 default=False,
852 action='store_const',
853 const=True,
Adele Zhoue4c35612015-10-16 15:34:23 -0700854 help='Run all the tests under docker. That provides ' +
855 'additional isolation and prevents the need to install ' +
856 'language specific prerequisites. Only available on Linux.')
Craig Tillerd4509a12015-09-28 09:18:40 -0700857argp.add_argument('--allow_flakes',
858 default=False,
859 action='store_const',
860 const=True,
Adele Zhoue4c35612015-10-16 15:34:23 -0700861 help='Allow flaky tests to show as passing (re-runs failed tests up to five times)')
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800862argp.add_argument('--arch',
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800863 choices=['default', 'x86', 'x64'],
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800864 default='default',
865 help='Selects architecture to target. For some platforms "default" is the only supported choice.')
866argp.add_argument('--compiler',
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800867 choices=['default',
Jan Tattermusch6d258c52016-06-10 09:36:51 -0700868 'gcc4.4', 'gcc4.6', 'gcc4.9', 'gcc5.3',
869 'clang3.4', 'clang3.5', 'clang3.6', 'clang3.7',
Jan Tattermusch825471c2016-04-25 16:52:25 -0700870 'vs2010', 'vs2013', 'vs2015',
murgatroid999fab4382016-04-29 15:05:00 -0700871 'python2.7', 'python3.4',
Jan Tattermusch76511a52016-06-17 14:00:57 -0700872 'node0.12', 'node4', 'node5',
873 'coreclr'],
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800874 default='default',
Jan Tattermusch77db4322016-02-20 20:19:35 -0800875 help='Selects compiler to use. Allowed values depend on the platform and language.')
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800876argp.add_argument('--build_only',
877 default=False,
878 action='store_const',
879 const=True,
880 help='Perform all the build steps but dont run any tests.')
Craig Tiller5f735a62016-01-20 09:31:15 -0800881argp.add_argument('--measure_cpu_costs', default=False, action='store_const', const=True,
882 help='Measure the cpu costs of tests')
Craig Tiller1676f912016-01-05 10:49:44 -0800883argp.add_argument('--update_submodules', default=[], nargs='*',
884 help='Update some submodules before building. If any are updated, also run generate_projects. ' +
885 'Submodules are specified as SUBMODULE_NAME:BRANCH; if BRANCH is omitted, master is assumed.')
Craig Tiller234b6e72015-05-23 10:12:40 -0700886argp.add_argument('-a', '--antagonists', default=0, type=int)
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +0200887argp.add_argument('-x', '--xml_report', default=None, type=str,
888 help='Generates a JUnit-compatible XML report')
Nicolas Nobleddef2462015-01-06 18:08:25 -0800889args = argp.parse_args()
890
Craig Tiller5f735a62016-01-20 09:31:15 -0800891jobset.measure_cpu_costs = args.measure_cpu_costs
892
Craig Tiller1676f912016-01-05 10:49:44 -0800893# update submodules if necessary
Craig Tillerb361b4e2016-01-06 11:44:17 -0800894need_to_regenerate_projects = False
895for spec in args.update_submodules:
896 spec = spec.split(':', 1)
897 if len(spec) == 1:
898 submodule = spec[0]
899 branch = 'master'
900 elif len(spec) == 2:
901 submodule = spec[0]
902 branch = spec[1]
903 cwd = 'third_party/%s' % submodule
904 def git(cmd, cwd=cwd):
905 print 'in %s: git %s' % (cwd, cmd)
906 subprocess.check_call('git %s' % cmd, cwd=cwd, shell=True)
907 git('fetch')
908 git('checkout %s' % branch)
909 git('pull origin %s' % branch)
910 if os.path.exists('src/%s/gen_build_yaml.py' % submodule):
911 need_to_regenerate_projects = True
912if need_to_regenerate_projects:
913 if jobset.platform_string() == 'linux':
914 subprocess.check_call('tools/buildgen/generate_projects.sh', shell=True)
915 else:
916 print 'WARNING: may need to regenerate projects, but since we are not on'
917 print ' Linux this step is being skipped. Compilation MAY fail.'
Craig Tiller1676f912016-01-05 10:49:44 -0800918
919
Nicolas Nobleddef2462015-01-06 18:08:25 -0800920# grab config
Jan Tattermusch77db4322016-02-20 20:19:35 -0800921run_config = _CONFIGS[args.config]
922build_config = run_config.build_config
Craig Tillerf1973b02015-01-16 12:32:13 -0800923
Craig Tiller06805272015-06-11 14:46:47 -0700924if args.travis:
murgatroid99d3b5b7f2015-10-06 17:02:03 -0700925 _FORCE_ENVIRON_FOR_WRAPPERS = {'GRPC_TRACE': 'api'}
Craig Tiller06805272015-06-11 14:46:47 -0700926
Adele Zhou6b9527c2015-11-20 15:56:35 -0800927if 'all' in args.language:
Craig Tiller1676f912016-01-05 10:49:44 -0800928 lang_list = _LANGUAGES.keys()
Adele Zhou6b9527c2015-11-20 15:56:35 -0800929else:
930 lang_list = args.language
Craig Tiller16900662016-01-07 19:30:54 -0800931# We don't support code coverage on some languages
932if 'gcov' in args.config:
Jan Tattermusch3b5121b2016-02-22 17:41:05 -0800933 for bad in ['objc', 'sanity']:
Craig Tiller16900662016-01-07 19:30:54 -0800934 if bad in lang_list:
935 lang_list.remove(bad)
Adele Zhou6b9527c2015-11-20 15:56:35 -0800936
937languages = set(_LANGUAGES[l] for l in lang_list)
Jan Tattermusch77db4322016-02-20 20:19:35 -0800938for l in languages:
939 l.configure(run_config, args)
murgatroid99132ce6a2015-03-04 17:29:14 -0800940
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800941language_make_options=[]
942if any(language.make_options() for language in languages):
Adele Zhou3b6ab812016-05-18 17:04:20 -0700943 if not 'gcov' in args.config and len(languages) != 1:
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800944 print 'languages with custom make options cannot be built simultaneously with other languages'
945 sys.exit(1)
946 else:
947 language_make_options = next(iter(languages)).make_options()
948
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800949if args.use_docker:
950 if not args.travis:
951 print 'Seen --use_docker flag, will run tests under docker.'
952 print
953 print 'IMPORTANT: The changes you are testing need to be locally committed'
954 print 'because only the committed changes in the current branch will be'
955 print 'copied to the docker environment.'
956 time.sleep(5)
957
Jan Tattermusch3b5121b2016-02-22 17:41:05 -0800958 dockerfile_dirs = set([l.dockerfile_dir() for l in languages])
959 if len(dockerfile_dirs) > 1:
Adele Zhou9506ef22016-03-02 13:53:34 -0800960 if 'gcov' in args.config:
961 dockerfile_dir = 'tools/dockerfile/test/multilang_jessie_x64'
962 print ('Using multilang_jessie_x64 docker image for code coverage for '
963 'all languages.')
964 else:
965 print ('Languages to be tested require running under different docker '
966 'images.')
967 sys.exit(1)
968 else:
969 dockerfile_dir = next(iter(dockerfile_dirs))
Craig Tillerde7edf82016-03-20 09:12:16 -0700970
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800971 child_argv = [ arg for arg in sys.argv if not arg == '--use_docker' ]
Jan Tattermusched342b12016-01-26 14:40:31 -0800972 run_tests_cmd = 'python tools/run_tests/run_tests.py %s' % ' '.join(child_argv[1:])
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800973
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800974 env = os.environ.copy()
975 env['RUN_TESTS_COMMAND'] = run_tests_cmd
Jan Tattermusch3b5121b2016-02-22 17:41:05 -0800976 env['DOCKERFILE_DIR'] = dockerfile_dir
Jan Tattermusch9835d4b2016-04-29 15:05:05 -0700977 env['DOCKER_RUN_SCRIPT'] = 'tools/run_tests/dockerize/docker_run_tests.sh'
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800978 if args.xml_report:
979 env['XML_REPORT'] = args.xml_report
980 if not args.travis:
981 env['TTY_FLAG'] = '-t' # enables Ctrl-C when not on Jenkins.
982
Jan Tattermusch9835d4b2016-04-29 15:05:05 -0700983 subprocess.check_call(['tools/run_tests/dockerize/build_docker_and_run_tests.sh'],
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800984 shell=True,
985 env=env)
986 sys.exit(0)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800987
Jan Tattermuschf08018a2016-01-26 08:22:09 -0800988_check_arch_option(args.arch)
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800989
Jan Tattermuschfba65302016-01-25 18:21:14 -0800990def make_jobspec(cfg, targets, makefile='Makefile'):
991 if platform_string() == 'windows':
Craig Tillerfc3c0c42015-09-01 16:47:54 -0700992 extra_args = []
Craig Tillerb5391e12015-09-03 14:35:18 -0700993 # better do parallel compilation
Jan Tattermusch47eeb2b2015-10-07 14:09:18 -0700994 # empirically /m:2 gives the best performance/price and should prevent
995 # overloading the windows workers.
Adele Zhoue4c35612015-10-16 15:34:23 -0700996 extra_args.extend(['/m:2'])
Craig Tillerb5391e12015-09-03 14:35:18 -0700997 # disable PDB generation: it's broken, and we don't need it during CI
Adele Zhoue4c35612015-10-16 15:34:23 -0700998 extra_args.extend(['/p:Jenkins=true'])
Craig Tiller6fd23842015-09-01 07:36:31 -0700999 return [
Jan Tattermusch2dd156e2015-12-04 18:26:17 -08001000 jobset.JobSpec([_windows_build_bat(args.compiler),
murgatroid99cf08daf2015-09-21 15:33:16 -07001001 'vsprojects\\%s.sln' % target,
Jan Tattermuscha2d964c2016-02-22 17:33:09 -08001002 '/p:Configuration=%s' % _MSBUILD_CONFIG[cfg]] +
Jan Tattermuschc895fe02016-01-20 09:13:09 -08001003 extra_args +
1004 language_make_options,
Craig Tiller590105a2016-01-19 13:03:46 -08001005 shell=True, timeout_seconds=None)
Craig Tiller6fd23842015-09-01 07:36:31 -07001006 for target in targets]
Jan Tattermuschfba65302016-01-25 18:21:14 -08001007 else:
murgatroid998ae409f2015-10-26 16:39:00 -07001008 if targets:
1009 return [jobset.JobSpec([os.getenv('MAKE', 'make'),
1010 '-f', makefile,
Craig Tillerdd6f7ed2016-01-21 12:54:42 -08001011 '-j', '%d' % args.jobs,
Craig Tiller71a86042016-01-15 14:59:58 -08001012 'EXTRA_DEFINES=GRPC_TEST_SLOWDOWN_MACHINE_FACTOR=%f' % args.slowdown,
1013 'CONFIG=%s' % cfg] +
Jan Tattermuschc895fe02016-01-20 09:13:09 -08001014 language_make_options +
Craig Tiller71a86042016-01-15 14:59:58 -08001015 ([] if not args.travis else ['JENKINS_BUILD=1']) +
1016 targets,
Craig Tiller590105a2016-01-19 13:03:46 -08001017 timeout_seconds=None)]
murgatroid998ae409f2015-10-26 16:39:00 -07001018 else:
1019 return []
Jan Tattermuschfba65302016-01-25 18:21:14 -08001020
murgatroid99a3e244f2015-09-22 11:25:53 -07001021make_targets = {}
1022for l in languages:
1023 makefile = l.makefile_name()
1024 make_targets[makefile] = make_targets.get(makefile, set()).union(
Jan Tattermusch77db4322016-02-20 20:19:35 -08001025 set(l.make_targets()))
Craig Tiller5058c692015-04-08 09:42:04 -07001026
Jan Tattermusche4a69182015-12-15 09:53:01 -08001027def build_step_environ(cfg):
1028 environ = {'CONFIG': cfg}
Jan Tattermuscha2d964c2016-02-22 17:33:09 -08001029 msbuild_cfg = _MSBUILD_CONFIG.get(cfg)
Jan Tattermusche4a69182015-12-15 09:53:01 -08001030 if msbuild_cfg:
1031 environ['MSBUILD_CONFIG'] = msbuild_cfg
1032 return environ
1033
murgatroid99fddac962015-09-22 09:20:11 -07001034build_steps = list(set(
Jan Tattermusch77db4322016-02-20 20:19:35 -08001035 jobset.JobSpec(cmdline, environ=build_step_environ(build_config), flake_retries=5)
murgatroid99256d3df2015-09-21 16:58:02 -07001036 for l in languages
1037 for cmdline in l.pre_build_steps()))
Craig Tillerbd4e3782015-09-01 06:48:55 -07001038if make_targets:
Jan Tattermusch77db4322016-02-20 20:19:35 -08001039 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 -07001040 build_steps.extend(set(make_commands))
Craig Tiller5058c692015-04-08 09:42:04 -07001041build_steps.extend(set(
Jan Tattermusch77db4322016-02-20 20:19:35 -08001042 jobset.JobSpec(cmdline, environ=build_step_environ(build_config), timeout_seconds=None)
Craig Tiller547db2b2015-01-30 14:08:39 -08001043 for l in languages
Craig Tiller533b1a22015-05-29 08:41:29 -07001044 for cmdline in l.build_steps()))
Craig Tillerf1973b02015-01-16 12:32:13 -08001045
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +02001046post_tests_steps = list(set(
Jan Tattermusch77db4322016-02-20 20:19:35 -08001047 jobset.JobSpec(cmdline, environ=build_step_environ(build_config))
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +02001048 for l in languages
1049 for cmdline in l.post_tests_steps()))
Nicolas Nobleddef2462015-01-06 18:08:25 -08001050runs_per_test = args.runs_per_test
ctiller3040cb72015-01-07 12:13:17 -08001051forever = args.forever
Nicolas Nobleddef2462015-01-06 18:08:25 -08001052
Nicolas Nobleddef2462015-01-06 18:08:25 -08001053
Craig Tiller71735182015-01-15 17:07:13 -08001054class TestCache(object):
Craig Tillerb50d1662015-01-15 17:28:21 -08001055 """Cache for running tests."""
1056
David Klempner25739582015-02-11 15:57:32 -08001057 def __init__(self, use_cache_results):
Craig Tiller71735182015-01-15 17:07:13 -08001058 self._last_successful_run = {}
David Klempner25739582015-02-11 15:57:32 -08001059 self._use_cache_results = use_cache_results
Craig Tiller69cd2372015-06-11 09:38:09 -07001060 self._last_save = time.time()
Craig Tiller71735182015-01-15 17:07:13 -08001061
1062 def should_run(self, cmdline, bin_hash):
Craig Tiller71735182015-01-15 17:07:13 -08001063 if cmdline not in self._last_successful_run:
1064 return True
1065 if self._last_successful_run[cmdline] != bin_hash:
1066 return True
David Klempner25739582015-02-11 15:57:32 -08001067 if not self._use_cache_results:
1068 return True
Craig Tiller71735182015-01-15 17:07:13 -08001069 return False
1070
1071 def finished(self, cmdline, bin_hash):
Craig Tiller547db2b2015-01-30 14:08:39 -08001072 self._last_successful_run[cmdline] = bin_hash
Craig Tiller69cd2372015-06-11 09:38:09 -07001073 if time.time() - self._last_save > 1:
1074 self.save()
Craig Tiller71735182015-01-15 17:07:13 -08001075
1076 def dump(self):
Craig Tillerb50d1662015-01-15 17:28:21 -08001077 return [{'cmdline': k, 'hash': v}
1078 for k, v in self._last_successful_run.iteritems()]
Craig Tiller71735182015-01-15 17:07:13 -08001079
1080 def parse(self, exdump):
1081 self._last_successful_run = dict((o['cmdline'], o['hash']) for o in exdump)
1082
1083 def save(self):
1084 with open('.run_tests_cache', 'w') as f:
Craig Tiller261dd982015-01-16 16:41:45 -08001085 f.write(json.dumps(self.dump()))
Craig Tiller69cd2372015-06-11 09:38:09 -07001086 self._last_save = time.time()
Craig Tiller71735182015-01-15 17:07:13 -08001087
Craig Tiller1cc11db2015-01-15 22:50:50 -08001088 def maybe_load(self):
1089 if os.path.exists('.run_tests_cache'):
1090 with open('.run_tests_cache') as f:
Craig Tiller261dd982015-01-16 16:41:45 -08001091 self.parse(json.loads(f.read()))
Craig Tiller71735182015-01-15 17:07:13 -08001092
1093
Craig Tillerf53d9c82015-08-04 14:19:43 -07001094def _start_port_server(port_server_port):
1095 # check if a compatible port server is running
1096 # if incompatible (version mismatch) ==> start a new one
1097 # if not running ==> start a new one
1098 # otherwise, leave it up
1099 try:
Craig Tillerfe4939f2015-10-06 12:55:36 -07001100 version = int(urllib2.urlopen(
1101 'http://localhost:%d/version_number' % port_server_port,
1102 timeout=1).read())
1103 print 'detected port server running version %d' % version
Craig Tillerf53d9c82015-08-04 14:19:43 -07001104 running = True
Craig Tillerfe4939f2015-10-06 12:55:36 -07001105 except Exception as e:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001106 print 'failed to detect port server: %s' % sys.exc_info()[0]
Craig Tillerfe4939f2015-10-06 12:55:36 -07001107 print e.strerror
Craig Tillerf53d9c82015-08-04 14:19:43 -07001108 running = False
1109 if running:
Craig Tillerfe4939f2015-10-06 12:55:36 -07001110 current_version = int(subprocess.check_output(
Jan Tattermusch3bd08272015-11-04 19:24:37 -08001111 [sys.executable, os.path.abspath('tools/run_tests/port_server.py'),
1112 'dump_version']))
Craig Tillerfe4939f2015-10-06 12:55:36 -07001113 print 'my port server is version %d' % current_version
1114 running = (version >= current_version)
1115 if not running:
1116 print 'port_server version mismatch: killing the old one'
1117 urllib2.urlopen('http://localhost:%d/quitquitquit' % port_server_port).read()
1118 time.sleep(1)
Craig Tillerf53d9c82015-08-04 14:19:43 -07001119 if not running:
Craig Tillerf0a293e2015-10-12 10:05:50 -07001120 fd, logfile = tempfile.mkstemp()
1121 os.close(fd)
1122 print 'starting port_server, with log file %s' % logfile
Jan Tattermusch3bd08272015-11-04 19:24:37 -08001123 args = [sys.executable, os.path.abspath('tools/run_tests/port_server.py'),
1124 '-p', '%d' % port_server_port, '-l', logfile]
Craig Tiller367d41d2015-10-12 13:00:22 -07001125 env = dict(os.environ)
1126 env['BUILD_ID'] = 'pleaseDontKillMeJenkins'
Nicolas "Pixel" Noblef72d7b52015-12-03 03:07:43 +01001127 if platform_string() == 'windows':
Jan Tattermusch3bd08272015-11-04 19:24:37 -08001128 # Working directory of port server needs to be outside of Jenkins
1129 # workspace to prevent file lock issues.
1130 tempdir = tempfile.mkdtemp()
Craig Tillerd2c39712015-10-12 11:08:49 -07001131 port_server = subprocess.Popen(
Craig Tiller367d41d2015-10-12 13:00:22 -07001132 args,
1133 env=env,
Jan Tattermusch3bd08272015-11-04 19:24:37 -08001134 cwd=tempdir,
Craig Tiller367d41d2015-10-12 13:00:22 -07001135 creationflags = 0x00000008, # detached process
1136 close_fds=True)
Craig Tillerd2c39712015-10-12 11:08:49 -07001137 else:
1138 port_server = subprocess.Popen(
1139 args,
Craig Tiller367d41d2015-10-12 13:00:22 -07001140 env=env,
Craig Tillerd2c39712015-10-12 11:08:49 -07001141 preexec_fn=os.setsid,
1142 close_fds=True)
Craig Tillerf0a293e2015-10-12 10:05:50 -07001143 time.sleep(1)
Craig Tiller8b5f4dc2015-08-26 08:02:01 -07001144 # ensure port server is up
Craig Tillerabd37fd2015-08-26 07:54:01 -07001145 waits = 0
Craig Tillerf53d9c82015-08-04 14:19:43 -07001146 while True:
Craig Tillerabd37fd2015-08-26 07:54:01 -07001147 if waits > 10:
Craig Tillerf0a293e2015-10-12 10:05:50 -07001148 print 'killing port server due to excessive start up waits'
Craig Tillerabd37fd2015-08-26 07:54:01 -07001149 port_server.kill()
Craig Tillera2f38b02015-09-24 11:19:17 -07001150 if port_server.poll() is not None:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001151 print 'port_server failed to start'
Craig Tillerf0a293e2015-10-12 10:05:50 -07001152 # try one final time: maybe another build managed to start one
1153 time.sleep(1)
1154 try:
1155 urllib2.urlopen('http://localhost:%d/get' % port_server_port,
1156 timeout=1).read()
1157 print 'last ditch attempt to contact port server succeeded'
1158 break
1159 except:
Jan Tattermusch3b5121b2016-02-22 17:41:05 -08001160 traceback.print_exc()
Craig Tillerf0a293e2015-10-12 10:05:50 -07001161 port_log = open(logfile, 'r').read()
1162 print port_log
1163 sys.exit(1)
Craig Tillerf53d9c82015-08-04 14:19:43 -07001164 try:
Craig Tillerabd37fd2015-08-26 07:54:01 -07001165 urllib2.urlopen('http://localhost:%d/get' % port_server_port,
1166 timeout=1).read()
Craig Tillerf0a293e2015-10-12 10:05:50 -07001167 print 'port server is up and ready'
Craig Tillerf53d9c82015-08-04 14:19:43 -07001168 break
Craig Tiller31fdaa42015-09-25 13:09:59 -07001169 except socket.timeout:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001170 print 'waiting for port_server: timeout'
Craig Tillerf0a293e2015-10-12 10:05:50 -07001171 traceback.print_exc();
1172 time.sleep(1)
Craig Tiller31fdaa42015-09-25 13:09:59 -07001173 waits += 1
Craig Tillerf53d9c82015-08-04 14:19:43 -07001174 except urllib2.URLError:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001175 print 'waiting for port_server: urlerror'
Craig Tillerf0a293e2015-10-12 10:05:50 -07001176 traceback.print_exc();
1177 time.sleep(1)
Craig Tillerabd37fd2015-08-26 07:54:01 -07001178 waits += 1
Craig Tillerf53d9c82015-08-04 14:19:43 -07001179 except:
Jan Tattermusch3b5121b2016-02-22 17:41:05 -08001180 traceback.print_exc()
Craig Tillerf53d9c82015-08-04 14:19:43 -07001181 port_server.kill()
1182 raise
1183
1184
Adele Zhoud5fffa52015-10-23 15:51:42 -07001185def _calculate_num_runs_failures(list_of_results):
1186 """Caculate number of runs and failures for a particular test.
1187
1188 Args:
1189 list_of_results: (List) of JobResult object.
1190 Returns:
1191 A tuple of total number of runs and failures.
1192 """
1193 num_runs = len(list_of_results) # By default, there is 1 run per JobResult.
1194 num_failures = 0
1195 for jobresult in list_of_results:
1196 if jobresult.retries > 0:
1197 num_runs += jobresult.retries
1198 if jobresult.num_failures > 0:
1199 num_failures += jobresult.num_failures
1200 return num_runs, num_failures
1201
Adele Zhou6b9527c2015-11-20 15:56:35 -08001202
Craig Tillereb9de8b2016-01-08 08:57:41 -08001203# _build_and_run results
1204class BuildAndRunError(object):
1205
1206 BUILD = object()
1207 TEST = object()
1208 POST_TEST = object()
1209
1210
1211# returns a list of things that failed (or an empty list on success)
Craig Tillerf53d9c82015-08-04 14:19:43 -07001212def _build_and_run(
Jan Tattermusch2dd156e2015-12-04 18:26:17 -08001213 check_cancelled, newline_on_success, cache, xml_report=None, build_only=False):
ctiller3040cb72015-01-07 12:13:17 -08001214 """Do one pass of building & running tests."""
murgatroid99666450e2015-01-26 13:03:31 -08001215 # build latest sequentially
Jan Tattermuschaab1e512016-01-28 09:30:44 -08001216 num_failures, resultset = jobset.run(
Adele Zhoue4c35612015-10-16 15:34:23 -07001217 build_steps, maxjobs=1, stop_on_failure=True,
Craig Tiller883064c2015-11-04 10:06:10 -08001218 newline_on_success=newline_on_success, travis=args.travis)
Adele Zhoue4c35612015-10-16 15:34:23 -07001219 if num_failures:
Craig Tillereb9de8b2016-01-08 08:57:41 -08001220 return [BuildAndRunError.BUILD]
Craig Tillerb361b4e2016-01-06 11:44:17 -08001221
Jan Tattermusch2dd156e2015-12-04 18:26:17 -08001222 if build_only:
Jan Tattermuschaab1e512016-01-28 09:30:44 -08001223 if xml_report:
1224 report_utils.render_junit_xml_report(resultset, xml_report)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001225 return []
ctiller3040cb72015-01-07 12:13:17 -08001226
Craig Tiller234b6e72015-05-23 10:12:40 -07001227 # start antagonists
David Garcia Quintas79e389f2015-06-02 17:49:42 -07001228 antagonists = [subprocess.Popen(['tools/run_tests/antagonist.py'])
Craig Tiller234b6e72015-05-23 10:12:40 -07001229 for _ in range(0, args.antagonists)]
Craig Tillerfe4939f2015-10-06 12:55:36 -07001230 port_server_port = 32767
Craig Tillerf53d9c82015-08-04 14:19:43 -07001231 _start_port_server(port_server_port)
Adele Zhou7cf72112015-11-04 11:18:43 -08001232 resultset = None
Adele Zhou803af152015-11-30 15:16:16 -08001233 num_test_failures = 0
Craig Tiller234b6e72015-05-23 10:12:40 -07001234 try:
David Garcia Quintase90cd372015-05-31 18:15:26 -07001235 infinite_runs = runs_per_test == 0
yang-g6c1fdc62015-08-18 11:57:42 -07001236 one_run = set(
1237 spec
yang-g6c1fdc62015-08-18 11:57:42 -07001238 for language in languages
Jan Tattermusch77db4322016-02-20 20:19:35 -08001239 for spec in language.test_specs()
yang-g6c1fdc62015-08-18 11:57:42 -07001240 if re.search(args.regex, spec.shortname))
David Garcia Quintas79e389f2015-06-02 17:49:42 -07001241 # When running on travis, we want out test runs to be as similar as possible
1242 # for reproducibility purposes.
Craig Tiller883064c2015-11-04 10:06:10 -08001243 if args.travis:
David Garcia Quintas79e389f2015-06-02 17:49:42 -07001244 massaged_one_run = sorted(one_run, key=lambda x: x.shortname)
1245 else:
1246 # whereas otherwise, we want to shuffle things up to give all tests a
1247 # chance to run.
1248 massaged_one_run = list(one_run) # random.shuffle needs an indexable seq.
1249 random.shuffle(massaged_one_run) # which it modifies in-place.
Craig Tillerf7b7c892015-06-22 14:33:25 -07001250 if infinite_runs:
1251 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 -07001252 runs_sequence = (itertools.repeat(massaged_one_run) if infinite_runs
1253 else itertools.repeat(massaged_one_run, runs_per_test))
David Garcia Quintase90cd372015-05-31 18:15:26 -07001254 all_runs = itertools.chain.from_iterable(runs_sequence)
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +02001255
Adele Zhou803af152015-11-30 15:16:16 -08001256 num_test_failures, resultset = jobset.run(
Adele Zhou2271ab52015-10-28 13:59:14 -07001257 all_runs, check_cancelled, newline_on_success=newline_on_success,
Craig Tiller883064c2015-11-04 10:06:10 -08001258 travis=args.travis, infinite_runs=infinite_runs, maxjobs=args.jobs,
murgatroid998ae409f2015-10-26 16:39:00 -07001259 stop_on_failure=args.stop_on_failure,
Adele Zhouf2ca7bc2015-10-23 15:38:00 -07001260 cache=cache if not xml_report else None,
Adele Zhouf2ca7bc2015-10-23 15:38:00 -07001261 add_env={'GRPC_TEST_PORT_SERVER': 'localhost:%d' % port_server_port})
Adele Zhoud5fffa52015-10-23 15:51:42 -07001262 if resultset:
1263 for k, v in resultset.iteritems():
1264 num_runs, num_failures = _calculate_num_runs_failures(v)
1265 if num_failures == num_runs: # what about infinite_runs???
1266 jobset.message('FAILED', k, do_newline=True)
1267 elif num_failures > 0:
1268 jobset.message(
1269 'FLAKE', '%s [%d/%d runs flaked]' % (k, num_failures, num_runs),
1270 do_newline=True)
1271 else:
1272 jobset.message('PASSED', k, do_newline=True)
Craig Tiller234b6e72015-05-23 10:12:40 -07001273 finally:
1274 for antagonist in antagonists:
1275 antagonist.kill()
Adele Zhou7cf72112015-11-04 11:18:43 -08001276 if xml_report and resultset:
Adele Zhou3bc7ba42015-11-05 10:21:58 -08001277 report_utils.render_junit_xml_report(resultset, xml_report)
Craig Tillerd86a3942015-01-14 12:48:54 -08001278
Adele Zhouf2ca7bc2015-10-23 15:38:00 -07001279 number_failures, _ = jobset.run(
1280 post_tests_steps, maxjobs=1, stop_on_failure=True,
Craig Tiller883064c2015-11-04 10:06:10 -08001281 newline_on_success=newline_on_success, travis=args.travis)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001282
1283 out = []
1284 if number_failures:
1285 out.append(BuildAndRunError.POST_TEST)
1286 if num_test_failures:
1287 out.append(BuildAndRunError.TEST)
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +02001288
Craig Tiller69cd2372015-06-11 09:38:09 -07001289 if cache: cache.save()
1290
Craig Tillereb9de8b2016-01-08 08:57:41 -08001291 return out
ctiller3040cb72015-01-07 12:13:17 -08001292
1293
David Klempner25739582015-02-11 15:57:32 -08001294test_cache = TestCache(runs_per_test == 1)
Craig Tiller547db2b2015-01-30 14:08:39 -08001295test_cache.maybe_load()
Craig Tiller71735182015-01-15 17:07:13 -08001296
ctiller3040cb72015-01-07 12:13:17 -08001297if forever:
Nicolas Noble044db742015-01-14 16:57:24 -08001298 success = True
ctiller3040cb72015-01-07 12:13:17 -08001299 while True:
Craig Tiller42bc87c2015-02-23 08:50:19 -08001300 dw = watch_dirs.DirWatcher(['src', 'include', 'test', 'examples'])
ctiller3040cb72015-01-07 12:13:17 -08001301 initial_time = dw.most_recent_change()
1302 have_files_changed = lambda: dw.most_recent_change() != initial_time
Nicolas Noble044db742015-01-14 16:57:24 -08001303 previous_success = success
Craig Tillereb9de8b2016-01-08 08:57:41 -08001304 errors = _build_and_run(check_cancelled=have_files_changed,
1305 newline_on_success=False,
1306 cache=test_cache,
1307 build_only=args.build_only) == 0
1308 if not previous_success and not errors:
Nicolas Nobleb09078f2015-01-14 18:06:05 -08001309 jobset.message('SUCCESS',
1310 'All tests are now passing properly',
1311 do_newline=True)
Nicolas Noble044db742015-01-14 16:57:24 -08001312 jobset.message('IDLE', 'No change detected')
ctiller3040cb72015-01-07 12:13:17 -08001313 while not have_files_changed():
1314 time.sleep(1)
1315else:
Craig Tillereb9de8b2016-01-08 08:57:41 -08001316 errors = _build_and_run(check_cancelled=lambda: False,
Craig Tiller71735182015-01-15 17:07:13 -08001317 newline_on_success=args.newline_on_success,
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +02001318 cache=test_cache,
Jan Tattermusch2dd156e2015-12-04 18:26:17 -08001319 xml_report=args.xml_report,
1320 build_only=args.build_only)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001321 if not errors:
Nicolas Nobleb09078f2015-01-14 18:06:05 -08001322 jobset.message('SUCCESS', 'All tests passed', do_newline=True)
1323 else:
1324 jobset.message('FAILED', 'Some tests failed', do_newline=True)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001325 exit_code = 0
1326 if BuildAndRunError.BUILD in errors:
1327 exit_code |= 1
Craig Tiller4f2be362016-01-08 08:59:20 -08001328 if BuildAndRunError.TEST in errors and not args.travis:
Craig Tillereb9de8b2016-01-08 08:57:41 -08001329 exit_code |= 2
Craig Tiller4f2be362016-01-08 08:59:20 -08001330 if BuildAndRunError.POST_TEST in errors:
1331 exit_code |= 4
Craig Tillereb9de8b2016-01-08 08:57:41 -08001332 sys.exit(exit_code)