blob: dea481ef90ddcbafce4f2ae476201c669f03dd8b [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 Tattermuschabd7df82016-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 Tiller711bbe62015-08-19 12:35:16 -0700156 for target in binaries:
Jan Tattermusch77db4322016-02-20 20:19:35 -0800157 if self.config.build_config in target['exclude_configs']:
murgatroid99fafeeb32015-09-22 09:13:03 -0700158 continue
Nicolas Noblee1445362015-05-11 17:40:26 -0700159 if self.platform == 'windows':
Jan Tattermusch3de6b762016-01-28 11:38:11 -0800160 binary = 'vsprojects/%s%s/%s.exe' % (
Jan Tattermusch77db4322016-02-20 20:19:35 -0800161 'x64/' if self.args.arch == 'x64' else '',
Jan Tattermuscha2d964c2016-02-22 17:33:09 -0800162 _MSBUILD_CONFIG[self.config.build_config],
Jan Tattermusch3de6b762016-01-28 11:38:11 -0800163 target['name'])
Nicolas Noblee1445362015-05-11 17:40:26 -0700164 else:
Jan Tattermusch77db4322016-02-20 20:19:35 -0800165 binary = 'bins/%s/%s' % (self.config.build_config, target['name'])
yang-g6c1fdc62015-08-18 11:57:42 -0700166 if os.path.isfile(binary):
Craig Tillerca62ff02016-02-24 22:22:57 -0800167 if 'gtest' in target and target['gtest']:
Craig Tiller0488d142016-02-24 22:34:48 -0800168 # here we parse the output of --gtest_list_tests to build up a
169 # complete list of the tests contained in a binary
170 # for each test, we then add a job to run, filtering for just that
171 # test
Craig Tillerca62ff02016-02-24 22:22:57 -0800172 with open(os.devnull, 'w') as fnull:
173 tests = subprocess.check_output([binary, '--gtest_list_tests'],
174 stderr=fnull)
175 base = None
176 for line in tests.split('\n'):
177 i = line.find('#')
178 if i >= 0: line = line[:i]
179 if not line: continue
180 if line[0] != ' ':
Craig Tiller184e4232016-02-24 22:48:56 -0800181 base = line.strip()
Craig Tillerca62ff02016-02-24 22:22:57 -0800182 else:
183 assert base is not None
184 assert line[1] == ' '
Craig Tiller184e4232016-02-24 22:48:56 -0800185 test = base + line.strip()
Craig Tillerca62ff02016-02-24 22:22:57 -0800186 cmdline = [binary] + ['--gtest_filter=%s' % test]
187 out.append(self.config.job_spec(cmdline, [binary],
188 shortname='%s:%s' % (binary, test),
189 cpu_cost=target['cpu_cost'],
190 environ={'GRPC_DEFAULT_SSL_ROOTS_FILE_PATH':
Craig Tiller1796f872016-03-25 19:42:49 -0700191 _ROOT + '/src/core/lib/tsi/test_creds/ca.pem'}))
Craig Tillerca62ff02016-02-24 22:22:57 -0800192 else:
193 cmdline = [binary] + target['args']
194 out.append(self.config.job_spec(cmdline, [binary],
Craig Tiller0bda0b32016-03-03 12:51:53 -0800195 shortname=target.get('shortname', ' '.join(cmdline)),
Craig Tillerca62ff02016-02-24 22:22:57 -0800196 cpu_cost=target['cpu_cost'],
Craig Tiller33599972016-03-20 09:15:26 -0700197 flaky=target.get('flaky', False),
Craig Tillerca62ff02016-02-24 22:22:57 -0800198 environ={'GRPC_DEFAULT_SSL_ROOTS_FILE_PATH':
Craig Tiller1796f872016-03-25 19:42:49 -0700199 _ROOT + '/src/core/lib/tsi/test_creds/ca.pem'}))
Jan Tattermusch77db4322016-02-20 20:19:35 -0800200 elif self.args.regex == '.*' or self.platform == 'windows':
Adele Zhoue4c35612015-10-16 15:34:23 -0700201 print '\nWARNING: binary not found, skipping', binary
Nicolas Noblee1445362015-05-11 17:40:26 -0700202 return sorted(out)
Craig Tillerc7449162015-01-16 14:42:10 -0800203
Jan Tattermusch77db4322016-02-20 20:19:35 -0800204 def make_targets(self):
205 test_regex = self.args.regex
206 if self.platform != 'windows' and self.args.regex != '.*':
Craig Tiller883064c2015-11-04 10:06:10 -0800207 # use the regex to minimize the number of things to build
Craig Tillerb0f275e2016-01-27 10:45:50 -0800208 return [os.path.basename(target['name'])
Craig Tiller883064c2015-11-04 10:06:10 -0800209 for target in get_c_tests(False, self.test_lang)
Craig Tillerb0f275e2016-01-27 10:45:50 -0800210 if re.search(test_regex, '/' + target['name'])]
Jan Tattermusch77db4322016-02-20 20:19:35 -0800211 if self.platform == 'windows':
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700212 # don't build tools on windows just yet
213 return ['buildtests_%s' % self.make_target]
Craig Tiller7552f0f2015-06-19 17:46:20 -0700214 return ['buildtests_%s' % self.make_target, 'tools_%s' % self.make_target]
Craig Tillerc7449162015-01-16 14:42:10 -0800215
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800216 def make_options(self):
Jan Tattermuschc96caf82016-02-22 17:31:02 -0800217 return self._make_options;
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800218
murgatroid99256d3df2015-09-21 16:58:02 -0700219 def pre_build_steps(self):
Jan Tattermusch874aec02015-10-07 19:26:19 -0700220 if self.platform == 'windows':
221 return [['tools\\run_tests\\pre_build_c.bat']]
222 else:
223 return []
murgatroid99256d3df2015-09-21 16:58:02 -0700224
Craig Tillerc7449162015-01-16 14:42:10 -0800225 def build_steps(self):
226 return []
227
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200228 def post_tests_steps(self):
229 if self.platform == 'windows':
230 return []
231 else:
232 return [['tools/run_tests/post_tests_c.sh']]
233
murgatroid99a3e244f2015-09-22 11:25:53 -0700234 def makefile_name(self):
235 return 'Makefile'
236
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800237 def _clang_make_options(self):
238 return ['CC=clang', 'CXX=clang++', 'LD=clang', 'LDXX=clang++']
239
Jan Tattermusch9bb70622016-03-18 10:28:54 -0700240 def _gcc44_make_options(self):
241 return ['CC=gcc-4.4', 'CXX=g++-4.4', 'LD=gcc-4.4', 'LDXX=g++-4.4']
242
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800243 def _compiler_options(self, use_docker, compiler):
244 """Returns docker distro and make options to use for given compiler."""
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800245 if _is_use_docker_child():
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800246 return ("already_under_docker", [])
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800247 if not use_docker:
248 _check_compiler(compiler, ['default'])
249
250 if compiler == 'gcc4.9' or compiler == 'default':
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800251 return ('jessie', [])
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800252 elif compiler == 'gcc4.4':
Jan Tattermusch9bb70622016-03-18 10:28:54 -0700253 return ('wheezy', self._gcc44_make_options())
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800254 elif compiler == 'gcc5.3':
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800255 return ('ubuntu1604', [])
256 elif compiler == 'clang3.4':
257 return ('ubuntu1404', self._clang_make_options())
258 elif compiler == 'clang3.6':
259 return ('ubuntu1604', self._clang_make_options())
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800260 else:
261 raise Exception('Compiler %s not supported.' % compiler)
262
Jan Tattermusch77db4322016-02-20 20:19:35 -0800263 def dockerfile_dir(self):
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800264 return 'tools/dockerfile/test/cxx_%s_%s' % (self._docker_distro,
265 _docker_arch_suffix(self.args.arch))
Jan Tattermusch788ee232016-01-26 12:19:44 -0800266
murgatroid99132ce6a2015-03-04 17:29:14 -0800267 def __str__(self):
268 return self.make_target
269
Craig Tillercc0535d2015-12-08 15:14:47 -0800270
murgatroid992c8d5162015-01-26 10:41:21 -0800271class NodeLanguage(object):
272
Jan Tattermusche477b842016-02-06 22:19:01 -0800273 def __init__(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800274 self.platform = platform_string()
Jan Tattermusche477b842016-02-06 22:19:01 -0800275 self.node_version = '0.12'
276
Jan Tattermusch77db4322016-02-20 20:19:35 -0800277 def configure(self, config, args):
278 self.config = config
279 self.args = args
280 _check_compiler(self.args.compiler, ['default'])
281
282 def test_specs(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800283 if self.platform == 'windows':
Jan Tattermusch77db4322016-02-20 20:19:35 -0800284 return [self.config.job_spec(['tools\\run_tests\\run_node.bat'], None)]
Michael Lumishaaa876a2016-02-10 15:27:58 -0800285 else:
Jan Tattermusch77db4322016-02-20 20:19:35 -0800286 return [self.config.job_spec(['tools/run_tests/run_node.sh', self.node_version],
287 None,
288 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
murgatroid992c8d5162015-01-26 10:41:21 -0800289
murgatroid99256d3df2015-09-21 16:58:02 -0700290 def pre_build_steps(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800291 if self.platform == 'windows':
292 return [['tools\\run_tests\\pre_build_node.bat']]
293 else:
294 return [['tools/run_tests/pre_build_node.sh', self.node_version]]
murgatroid99256d3df2015-09-21 16:58:02 -0700295
Jan Tattermusch77db4322016-02-20 20:19:35 -0800296 def make_targets(self):
murgatroid99db5b1602015-10-01 13:20:11 -0700297 return []
murgatroid992c8d5162015-01-26 10:41:21 -0800298
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800299 def make_options(self):
300 return []
301
murgatroid992c8d5162015-01-26 10:41:21 -0800302 def build_steps(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800303 if self.platform == 'windows':
304 return [['tools\\run_tests\\build_node.bat']]
305 else:
306 return [['tools/run_tests/build_node.sh', self.node_version]]
Craig Tillerc7449162015-01-16 14:42:10 -0800307
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200308 def post_tests_steps(self):
Michael Lumish60d38cb2016-03-04 13:05:04 -0800309 return []
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200310
murgatroid99a3e244f2015-09-22 11:25:53 -0700311 def makefile_name(self):
312 return 'Makefile'
313
Jan Tattermusch77db4322016-02-20 20:19:35 -0800314 def dockerfile_dir(self):
315 return 'tools/dockerfile/test/node_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800316
murgatroid99132ce6a2015-03-04 17:29:14 -0800317 def __str__(self):
318 return 'node'
319
Craig Tiller99775822015-01-30 13:07:16 -0800320
Craig Tillerc7449162015-01-16 14:42:10 -0800321class PhpLanguage(object):
322
Jan Tattermusch77db4322016-02-20 20:19:35 -0800323 def configure(self, config, args):
324 self.config = config
325 self.args = args
326 _check_compiler(self.args.compiler, ['default'])
327
328 def test_specs(self):
329 return [self.config.job_spec(['src/php/bin/run_tests.sh'], None,
330 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
Craig Tillerc7449162015-01-16 14:42:10 -0800331
murgatroid99256d3df2015-09-21 16:58:02 -0700332 def pre_build_steps(self):
333 return []
334
Jan Tattermusch77db4322016-02-20 20:19:35 -0800335 def make_targets(self):
Craig Tilleraf7cf542015-05-22 10:07:34 -0700336 return ['static_c', 'shared_c']
Craig Tillerc7449162015-01-16 14:42:10 -0800337
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800338 def make_options(self):
339 return []
340
Craig Tillerc7449162015-01-16 14:42:10 -0800341 def build_steps(self):
342 return [['tools/run_tests/build_php.sh']]
343
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200344 def post_tests_steps(self):
Stanley Cheunga6b95482016-01-13 16:10:48 -0800345 return [['tools/run_tests/post_tests_php.sh']]
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200346
murgatroid99a3e244f2015-09-22 11:25:53 -0700347 def makefile_name(self):
348 return 'Makefile'
349
Jan Tattermusch77db4322016-02-20 20:19:35 -0800350 def dockerfile_dir(self):
351 return 'tools/dockerfile/test/php_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800352
murgatroid99132ce6a2015-03-04 17:29:14 -0800353 def __str__(self):
354 return 'php'
355
Craig Tillerc7449162015-01-16 14:42:10 -0800356
Nathaniel Manista840615e2015-01-22 20:31:47 +0000357class PythonLanguage(object):
358
Jan Tattermusch77db4322016-02-20 20:19:35 -0800359 def configure(self, config, args):
360 self.config = config
361 self.args = args
Jan Tattermusch825471c2016-04-25 16:52:25 -0700362 self._tox_env = self._get_tox_env(self.args.compiler)
Jan Tattermusch77db4322016-02-20 20:19:35 -0800363
364 def test_specs(self):
Jan Tattermusch072ebaa2016-03-01 18:33:12 -0800365 # load list of known test suites
366 with open('src/python/grpcio/tests/tests.json') as tests_json_file:
367 tests_json = json.load(tests_json_file)
Masood Malekghassemi2b841622015-07-28 17:39:02 -0700368 environment = dict(_FORCE_ENVIRON_FOR_WRAPPERS)
Ken Payson707c9e22016-04-20 09:42:19 -0700369 environment['PYTHONPATH'] = os.path.abspath('src/python/gens')
Jan Tattermusch072ebaa2016-03-01 18:33:12 -0800370 if self.config.build_config != 'gcov':
371 return [self.config.job_spec(
Jan Tattermusch825471c2016-04-25 16:52:25 -0700372 ['tools/run_tests/run_python.sh', self._tox_env],
Jan Tattermusch072ebaa2016-03-01 18:33:12 -0800373 None,
374 environ=dict(environment.items() +
Masood Malekghassemif7ff8be2016-03-09 15:27:28 -0800375 [('GRPC_PYTHON_TESTRUNNER_FILTER', suite_name)]),
Jan Tattermusch072ebaa2016-03-01 18:33:12 -0800376 shortname='py.test.%s' % suite_name,
377 timeout_seconds=5*60)
378 for suite_name in tests_json]
379 else:
380 return [self.config.job_spec(['tools/run_tests/run_python.sh'],
381 None,
382 environ=environment,
383 shortname='py.test.coverage',
384 timeout_seconds=15*60)]
385
Nathaniel Manista840615e2015-01-22 20:31:47 +0000386
murgatroid99256d3df2015-09-21 16:58:02 -0700387 def pre_build_steps(self):
388 return []
389
Jan Tattermusch77db4322016-02-20 20:19:35 -0800390 def make_targets(self):
Craig Tilleraf7cf542015-05-22 10:07:34 -0700391 return ['static_c', 'grpc_python_plugin', 'shared_c']
Nathaniel Manista840615e2015-01-22 20:31:47 +0000392
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800393 def make_options(self):
394 return []
395
Nathaniel Manista840615e2015-01-22 20:31:47 +0000396 def build_steps(self):
Jan Tattermusch825471c2016-04-25 16:52:25 -0700397 return [['tools/run_tests/build_python.sh', self._tox_env]]
Nathaniel Manista840615e2015-01-22 20:31:47 +0000398
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200399 def post_tests_steps(self):
400 return []
401
murgatroid99a3e244f2015-09-22 11:25:53 -0700402 def makefile_name(self):
403 return 'Makefile'
404
Jan Tattermusch77db4322016-02-20 20:19:35 -0800405 def dockerfile_dir(self):
406 return 'tools/dockerfile/test/python_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800407
Jan Tattermusch825471c2016-04-25 16:52:25 -0700408 def _get_tox_env(self, compiler):
409 """Returns name of tox environment based on selected compiler."""
410 if compiler == 'python2.7' or compiler == 'default':
411 return 'py27'
412 elif compiler == 'python3.4':
413 return 'py34'
414 else:
415 raise Exception('Compiler %s not supported.' % compiler)
416
murgatroid99132ce6a2015-03-04 17:29:14 -0800417 def __str__(self):
418 return 'python'
419
Craig Tillerd625d812015-04-08 15:52:35 -0700420
murgatroid996a4c4fa2015-02-27 12:08:57 -0800421class RubyLanguage(object):
422
Jan Tattermusch77db4322016-02-20 20:19:35 -0800423 def configure(self, config, args):
424 self.config = config
425 self.args = args
426 _check_compiler(self.args.compiler, ['default'])
427
428 def test_specs(self):
429 return [self.config.job_spec(['tools/run_tests/run_ruby.sh'], None,
430 timeout_seconds=10*60,
431 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
murgatroid996a4c4fa2015-02-27 12:08:57 -0800432
murgatroid99256d3df2015-09-21 16:58:02 -0700433 def pre_build_steps(self):
Nicolas "Pixel" Noblebcf988f2015-10-08 03:00:42 +0200434 return [['tools/run_tests/pre_build_ruby.sh']]
murgatroid99256d3df2015-09-21 16:58:02 -0700435
Jan Tattermusch4651bef2016-02-23 08:31:25 -0800436 def make_targets(self):
murgatroid997d243df2016-02-18 09:58:05 -0800437 return []
murgatroid996a4c4fa2015-02-27 12:08:57 -0800438
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800439 def make_options(self):
440 return []
441
murgatroid996a4c4fa2015-02-27 12:08:57 -0800442 def build_steps(self):
443 return [['tools/run_tests/build_ruby.sh']]
444
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200445 def post_tests_steps(self):
Nicolas "Pixel" Noble7ef1e532015-12-02 00:55:33 +0100446 return [['tools/run_tests/post_tests_ruby.sh']]
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200447
murgatroid99a3e244f2015-09-22 11:25:53 -0700448 def makefile_name(self):
449 return 'Makefile'
450
Jan Tattermusch77db4322016-02-20 20:19:35 -0800451 def dockerfile_dir(self):
452 return 'tools/dockerfile/test/ruby_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800453
murgatroid99132ce6a2015-03-04 17:29:14 -0800454 def __str__(self):
455 return 'ruby'
456
Craig Tillerd625d812015-04-08 15:52:35 -0700457
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800458class CSharpLanguage(object):
Jan Tattermusch77db4322016-02-20 20:19:35 -0800459
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700460 def __init__(self):
Craig Tillerd50993d2015-08-05 08:04:36 -0700461 self.platform = platform_string()
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700462
Jan Tattermusch77db4322016-02-20 20:19:35 -0800463 def configure(self, config, args):
464 self.config = config
465 self.args = args
Jan Tattermusch690914f2016-03-25 15:07:22 -0700466 if self.platform == 'windows':
Jan Tattermuschabd7df82016-03-25 16:14:41 -0700467 # Explicitly choosing between x86 and x64 arch doesn't work yet
468 _check_arch(self.args.arch, ['default'])
Jan Tattermusch690914f2016-03-25 15:07:22 -0700469 self._make_options = [_windows_toolset_option(self.args.compiler),
470 _windows_arch_option(self.args.arch)]
471 else:
472 _check_compiler(self.args.compiler, ['default'])
473 if self.platform == 'mac':
474 # On Mac, official distribution of mono is 32bit.
Jan Tattermusch2a322c22016-03-30 13:55:07 -0700475 # TODO(jtattermusch): EMBED_ZLIB=true currently breaks the mac build
476 self._make_options = ['EMBED_OPENSSL=true',
Jan Tattermuschd9ff4562016-03-30 13:40:48 -0700477 'CFLAGS=-m32', 'LDFLAGS=-m32']
Jan Tattermusch690914f2016-03-25 15:07:22 -0700478 else:
479 self._make_options = ['EMBED_OPENSSL=true', 'EMBED_ZLIB=true']
Jan Tattermusch77db4322016-02-20 20:19:35 -0800480
481 def test_specs(self):
Jan Tattermusch03c01062015-12-11 14:28:56 -0800482 with open('src/csharp/tests.json') as f:
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700483 tests_by_assembly = json.load(f)
Jan Tattermusch03c01062015-12-11 14:28:56 -0800484
Jan Tattermuscha2d964c2016-02-22 17:33:09 -0800485 msbuild_config = _MSBUILD_CONFIG[self.config.build_config]
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700486 nunit_args = ['--labels=All',
Jan Tattermuschf6824c22016-04-08 17:18:44 -0700487 '--noresult',
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700488 '--workers=1']
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700489 if self.platform == 'windows':
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700490 runtime_cmd = []
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700491 else:
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700492 runtime_cmd = ['mono']
Jan Tattermuschbf3b1532015-10-26 10:24:42 -0700493
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700494 specs = []
495 for assembly in tests_by_assembly.iterkeys():
496 assembly_file = 'src/csharp/%s/bin/%s/%s.exe' % (assembly, msbuild_config, assembly)
Jan Tattermuscha5f1f122016-04-11 15:49:56 -0700497 if self.config.build_config != 'gcov' or self.platform != 'windows':
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700498 # normally, run each test as a separate process
499 for test in tests_by_assembly[assembly]:
500 cmdline = runtime_cmd + [assembly_file, '--test=%s' % test] + nunit_args
501 specs.append(self.config.job_spec(cmdline,
502 None,
503 shortname='csharp.%s' % test,
504 environ=_FORCE_ENVIRON_FOR_WRAPPERS))
505 else:
Jan Tattermuscha5f1f122016-04-11 15:49:56 -0700506 # For C# test coverage, run all tests from the same assembly at once
507 # using OpenCover.Console (only works on Windows).
508 cmdline = ['src\\csharp\\packages\\OpenCover.4.6.519\\tools\\OpenCover.Console.exe',
509 '-target:%s' % assembly_file,
510 '-targetdir:src\\csharp',
511 '-targetargs:%s' % ' '.join(nunit_args),
512 '-filter:+[Grpc.Core]*',
513 '-register:user',
514 '-output:src\\csharp\\coverage_csharp_%s.xml' % assembly]
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700515
Jan Tattermuscha5f1f122016-04-11 15:49:56 -0700516 # set really high cpu_cost to make sure instances of OpenCover.Console run exclusively
517 # to prevent problems with registering the profiler.
518 run_exclusive = 1000000
Jan Tattermusch35e608f2016-04-09 16:35:06 -0700519 specs.append(self.config.job_spec(cmdline,
520 None,
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700521 shortname='csharp.coverage.%s' % assembly,
Jan Tattermuscha5f1f122016-04-11 15:49:56 -0700522 cpu_cost=run_exclusive,
Jan Tattermusch77db4322016-02-20 20:19:35 -0800523 environ=_FORCE_ENVIRON_FOR_WRAPPERS))
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700524 return specs
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800525
murgatroid99256d3df2015-09-21 16:58:02 -0700526 def pre_build_steps(self):
Jan Tattermusch48423fc2015-10-07 18:59:16 -0700527 if self.platform == 'windows':
Jan Tattermusch874aec02015-10-07 19:26:19 -0700528 return [['tools\\run_tests\\pre_build_csharp.bat']]
Jan Tattermusch48423fc2015-10-07 18:59:16 -0700529 else:
530 return [['tools/run_tests/pre_build_csharp.sh']]
murgatroid99256d3df2015-09-21 16:58:02 -0700531
Jan Tattermusch77db4322016-02-20 20:19:35 -0800532 def make_targets(self):
Jan Tattermusch690914f2016-03-25 15:07:22 -0700533 return ['grpc_csharp_ext']
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800534
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800535 def make_options(self):
Jan Tattermusch690914f2016-03-25 15:07:22 -0700536 return self._make_options;
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800537
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800538 def build_steps(self):
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700539 if self.platform == 'windows':
Jan Tattermusch690914f2016-03-25 15:07:22 -0700540 return [[_windows_build_bat(self.args.compiler),
541 'src/csharp/Grpc.sln',
542 '/p:Configuration=%s' % _MSBUILD_CONFIG[self.config.build_config]]]
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700543 else:
544 return [['tools/run_tests/build_csharp.sh']]
Nathaniel Manista840615e2015-01-22 20:31:47 +0000545
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200546 def post_tests_steps(self):
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700547 if self.platform == 'windows':
548 return [['tools\\run_tests\\post_tests_csharp.bat']]
549 else:
550 return [['tools/run_tests/post_tests_csharp.sh']]
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200551
murgatroid99a3e244f2015-09-22 11:25:53 -0700552 def makefile_name(self):
553 return 'Makefile'
554
Jan Tattermusch77db4322016-02-20 20:19:35 -0800555 def dockerfile_dir(self):
556 return 'tools/dockerfile/test/csharp_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800557
murgatroid99132ce6a2015-03-04 17:29:14 -0800558 def __str__(self):
559 return 'csharp'
560
Craig Tillerd625d812015-04-08 15:52:35 -0700561
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700562class ObjCLanguage(object):
563
Jan Tattermusch77db4322016-02-20 20:19:35 -0800564 def configure(self, config, args):
565 self.config = config
566 self.args = args
567 _check_compiler(self.args.compiler, ['default'])
568
569 def test_specs(self):
570 return [self.config.job_spec(['src/objective-c/tests/run_tests.sh'], None,
571 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700572
murgatroid99256d3df2015-09-21 16:58:02 -0700573 def pre_build_steps(self):
574 return []
575
Jan Tattermusch77db4322016-02-20 20:19:35 -0800576 def make_targets(self):
Jorge Canizalesd0b32e92015-07-30 23:08:43 -0700577 return ['grpc_objective_c_plugin', 'interop_server']
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700578
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800579 def make_options(self):
580 return []
581
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700582 def build_steps(self):
Jorge Canizalesd0b32e92015-07-30 23:08:43 -0700583 return [['src/objective-c/tests/build_tests.sh']]
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700584
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200585 def post_tests_steps(self):
586 return []
587
murgatroid99a3e244f2015-09-22 11:25:53 -0700588 def makefile_name(self):
589 return 'Makefile'
590
Jan Tattermusch77db4322016-02-20 20:19:35 -0800591 def dockerfile_dir(self):
Jan Tattermusch788ee232016-01-26 12:19:44 -0800592 return None
593
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700594 def __str__(self):
595 return 'objc'
596
597
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100598class Sanity(object):
599
Jan Tattermusch77db4322016-02-20 20:19:35 -0800600 def configure(self, config, args):
601 self.config = config
602 self.args = args
603 _check_compiler(self.args.compiler, ['default'])
604
605 def test_specs(self):
Craig Tiller94d04a52016-01-20 10:58:23 -0800606 import yaml
Jan Tattermusch788ee232016-01-26 12:19:44 -0800607 with open('tools/run_tests/sanity/sanity_tests.yaml', 'r') as f:
Jan Tattermusch77db4322016-02-20 20:19:35 -0800608 return [self.config.job_spec(cmd['script'].split(), None,
609 timeout_seconds=None, environ={'TEST': 'true'},
610 cpu_cost=cmd.get('cpu_cost', 1))
Craig Tiller94d04a52016-01-20 10:58:23 -0800611 for cmd in yaml.load(f)]
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100612
murgatroid99256d3df2015-09-21 16:58:02 -0700613 def pre_build_steps(self):
614 return []
615
Jan Tattermusch77db4322016-02-20 20:19:35 -0800616 def make_targets(self):
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100617 return ['run_dep_checks']
618
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800619 def make_options(self):
620 return []
621
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100622 def build_steps(self):
623 return []
624
Nicolas "Pixel" Noble87879b32015-10-12 23:28:53 +0200625 def post_tests_steps(self):
626 return []
627
murgatroid99a3e244f2015-09-22 11:25:53 -0700628 def makefile_name(self):
629 return 'Makefile'
630
Jan Tattermusch77db4322016-02-20 20:19:35 -0800631 def dockerfile_dir(self):
Jan Tattermusche70b3c52016-02-07 20:21:02 -0800632 return 'tools/dockerfile/test/sanity'
Jan Tattermusch788ee232016-01-26 12:19:44 -0800633
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100634 def __str__(self):
635 return 'sanity'
636
Nicolas "Pixel" Noblee55cd7f2015-04-14 17:59:13 +0200637
Craig Tiller738c3342015-01-12 14:28:33 -0800638# different configurations we can run under
Craig Tillera0f85172016-01-20 15:56:06 -0800639with open('tools/run_tests/configs.json') as f:
Craig Tiller1dce9062016-01-20 17:01:56 -0800640 _CONFIGS = dict((cfg['config'], Config(**cfg)) for cfg in ast.literal_eval(f.read()))
Craig Tiller738c3342015-01-12 14:28:33 -0800641
642
Craig Tillerc7449162015-01-16 14:42:10 -0800643_LANGUAGES = {
Craig Tillere9c959d2015-01-18 10:23:26 -0800644 'c++': CLanguage('cxx', 'c++'),
645 'c': CLanguage('c', 'c'),
murgatroid992c8d5162015-01-26 10:41:21 -0800646 'node': NodeLanguage(),
Nathaniel Manista840615e2015-01-22 20:31:47 +0000647 'php': PhpLanguage(),
648 'python': PythonLanguage(),
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800649 'ruby': RubyLanguage(),
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100650 'csharp': CSharpLanguage(),
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700651 'objc' : ObjCLanguage(),
Jan Tattermusch70a57e42016-02-20 18:50:27 -0800652 'sanity': Sanity()
Craig Tillereb272bc2015-01-30 13:13:14 -0800653 }
Nicolas Nobleddef2462015-01-06 18:08:25 -0800654
Jan Tattermusch77db4322016-02-20 20:19:35 -0800655
Jan Tattermuscha2d964c2016-02-22 17:33:09 -0800656_MSBUILD_CONFIG = {
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700657 'dbg': 'Debug',
658 'opt': 'Release',
Jan Tattermusche4a69182015-12-15 09:53:01 -0800659 'gcov': 'Debug',
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700660 }
661
David Garcia Quintase90cd372015-05-31 18:15:26 -0700662
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800663def _windows_arch_option(arch):
664 """Returns msbuild cmdline option for selected architecture."""
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800665 if arch == 'default' or arch == 'x86':
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800666 return '/p:Platform=Win32'
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800667 elif arch == 'x64':
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800668 return '/p:Platform=x64'
669 else:
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800670 print 'Architecture %s not supported.' % arch
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800671 sys.exit(1)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800672
Jan Tattermuschf08018a2016-01-26 08:22:09 -0800673
674def _check_arch_option(arch):
675 """Checks that architecture option is valid."""
676 if platform_string() == 'windows':
677 _windows_arch_option(arch)
678 elif platform_string() == 'linux':
679 # On linux, we need to be running under docker with the right architecture.
Jan Tattermusch07fb0422016-01-26 10:46:56 -0800680 runtime_arch = platform.architecture()[0]
Jan Tattermuschf08018a2016-01-26 08:22:09 -0800681 if arch == 'default':
682 return
683 elif runtime_arch == '64bit' and arch == 'x64':
684 return
685 elif runtime_arch == '32bit' and arch == 'x86':
686 return
687 else:
688 print 'Architecture %s does not match current runtime architecture.' % arch
689 sys.exit(1)
690 else:
691 if args.arch != 'default':
692 print 'Architecture %s not supported on current platform.' % args.arch
693 sys.exit(1)
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800694
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800695
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800696def _windows_build_bat(compiler):
697 """Returns name of build.bat for selected compiler."""
698 if compiler == 'default' or compiler == 'vs2013':
699 return 'vsprojects\\build_vs2013.bat'
700 elif compiler == 'vs2015':
701 return 'vsprojects\\build_vs2015.bat'
702 elif compiler == 'vs2010':
703 return 'vsprojects\\build_vs2010.bat'
704 else:
705 print 'Compiler %s not supported.' % compiler
706 sys.exit(1)
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800707
708
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800709def _windows_toolset_option(compiler):
710 """Returns msbuild PlatformToolset for selected compiler."""
711 if compiler == 'default' or compiler == 'vs2013':
712 return '/p:PlatformToolset=v120'
713 elif compiler == 'vs2015':
714 return '/p:PlatformToolset=v140'
715 elif compiler == 'vs2010':
716 return '/p:PlatformToolset=v100'
717 else:
718 print 'Compiler %s not supported.' % compiler
719 sys.exit(1)
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800720
721
Jan Tattermusche70b3c52016-02-07 20:21:02 -0800722def _docker_arch_suffix(arch):
723 """Returns suffix to dockerfile dir to use."""
724 if arch == 'default' or arch == 'x64':
725 return 'x64'
726 elif arch == 'x86':
727 return 'x86'
728 else:
729 print 'Architecture %s not supported with current settings.' % arch
730 sys.exit(1)
731
732
David Garcia Quintase90cd372015-05-31 18:15:26 -0700733def runs_per_test_type(arg_str):
734 """Auxilary function to parse the "runs_per_test" flag.
735
736 Returns:
737 A positive integer or 0, the latter indicating an infinite number of
738 runs.
739
740 Raises:
741 argparse.ArgumentTypeError: Upon invalid input.
742 """
743 if arg_str == 'inf':
744 return 0
745 try:
746 n = int(arg_str)
747 if n <= 0: raise ValueError
Craig Tiller50e53e22015-06-01 20:18:21 -0700748 return n
David Garcia Quintase90cd372015-05-31 18:15:26 -0700749 except:
Adele Zhoue4c35612015-10-16 15:34:23 -0700750 msg = '\'{}\' is not a positive integer or \'inf\''.format(arg_str)
David Garcia Quintase90cd372015-05-31 18:15:26 -0700751 raise argparse.ArgumentTypeError(msg)
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700752
753# parse command line
754argp = argparse.ArgumentParser(description='Run grpc tests.')
755argp.add_argument('-c', '--config',
Jan Tattermusch77db4322016-02-20 20:19:35 -0800756 choices=sorted(_CONFIGS.keys()),
757 default='opt')
David Garcia Quintase90cd372015-05-31 18:15:26 -0700758argp.add_argument('-n', '--runs_per_test', default=1, type=runs_per_test_type,
759 help='A positive integer or "inf". If "inf", all tests will run in an '
760 'infinite loop. Especially useful in combination with "-f"')
Craig Tillerfe406ec2015-02-24 13:55:12 -0800761argp.add_argument('-r', '--regex', default='.*', type=str)
Craig Tiller5f735a62016-01-20 09:31:15 -0800762argp.add_argument('-j', '--jobs', default=multiprocessing.cpu_count(), type=int)
Craig Tiller8451e872015-02-27 09:25:51 -0800763argp.add_argument('-s', '--slowdown', default=1.0, type=float)
ctiller3040cb72015-01-07 12:13:17 -0800764argp.add_argument('-f', '--forever',
765 default=False,
766 action='store_const',
767 const=True)
Nicolas "Pixel" Noblea7df3f92015-02-26 22:07:04 +0100768argp.add_argument('-t', '--travis',
769 default=False,
770 action='store_const',
771 const=True)
Nicolas Noble044db742015-01-14 16:57:24 -0800772argp.add_argument('--newline_on_success',
773 default=False,
774 action='store_const',
775 const=True)
Craig Tiller686fb262015-01-15 07:39:09 -0800776argp.add_argument('-l', '--language',
Craig Tiller60f15e62015-05-13 09:05:17 -0700777 choices=['all'] + sorted(_LANGUAGES.keys()),
Craig Tiller686fb262015-01-15 07:39:09 -0800778 nargs='+',
Craig Tiller60f15e62015-05-13 09:05:17 -0700779 default=['all'])
Craig Tillercd43da82015-05-29 08:41:29 -0700780argp.add_argument('-S', '--stop_on_failure',
781 default=False,
782 action='store_const',
783 const=True)
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700784argp.add_argument('--use_docker',
785 default=False,
786 action='store_const',
787 const=True,
Adele Zhoue4c35612015-10-16 15:34:23 -0700788 help='Run all the tests under docker. That provides ' +
789 'additional isolation and prevents the need to install ' +
790 'language specific prerequisites. Only available on Linux.')
Craig Tillerd4509a12015-09-28 09:18:40 -0700791argp.add_argument('--allow_flakes',
792 default=False,
793 action='store_const',
794 const=True,
Adele Zhoue4c35612015-10-16 15:34:23 -0700795 help='Allow flaky tests to show as passing (re-runs failed tests up to five times)')
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800796argp.add_argument('--arch',
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800797 choices=['default', 'x86', 'x64'],
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800798 default='default',
799 help='Selects architecture to target. For some platforms "default" is the only supported choice.')
800argp.add_argument('--compiler',
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800801 choices=['default',
802 'gcc4.4', 'gcc4.9', 'gcc5.3',
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800803 'clang3.4', 'clang3.6',
Jan Tattermusch825471c2016-04-25 16:52:25 -0700804 'vs2010', 'vs2013', 'vs2015',
805 'python2.7', 'python3.4'],
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800806 default='default',
Jan Tattermusch77db4322016-02-20 20:19:35 -0800807 help='Selects compiler to use. Allowed values depend on the platform and language.')
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800808argp.add_argument('--build_only',
809 default=False,
810 action='store_const',
811 const=True,
812 help='Perform all the build steps but dont run any tests.')
Craig Tiller5f735a62016-01-20 09:31:15 -0800813argp.add_argument('--measure_cpu_costs', default=False, action='store_const', const=True,
814 help='Measure the cpu costs of tests')
Craig Tiller1676f912016-01-05 10:49:44 -0800815argp.add_argument('--update_submodules', default=[], nargs='*',
816 help='Update some submodules before building. If any are updated, also run generate_projects. ' +
817 'Submodules are specified as SUBMODULE_NAME:BRANCH; if BRANCH is omitted, master is assumed.')
Craig Tiller234b6e72015-05-23 10:12:40 -0700818argp.add_argument('-a', '--antagonists', default=0, type=int)
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +0200819argp.add_argument('-x', '--xml_report', default=None, type=str,
820 help='Generates a JUnit-compatible XML report')
Nicolas Nobleddef2462015-01-06 18:08:25 -0800821args = argp.parse_args()
822
Craig Tiller5f735a62016-01-20 09:31:15 -0800823jobset.measure_cpu_costs = args.measure_cpu_costs
824
Craig Tiller1676f912016-01-05 10:49:44 -0800825# update submodules if necessary
Craig Tillerb361b4e2016-01-06 11:44:17 -0800826need_to_regenerate_projects = False
827for spec in args.update_submodules:
828 spec = spec.split(':', 1)
829 if len(spec) == 1:
830 submodule = spec[0]
831 branch = 'master'
832 elif len(spec) == 2:
833 submodule = spec[0]
834 branch = spec[1]
835 cwd = 'third_party/%s' % submodule
836 def git(cmd, cwd=cwd):
837 print 'in %s: git %s' % (cwd, cmd)
838 subprocess.check_call('git %s' % cmd, cwd=cwd, shell=True)
839 git('fetch')
840 git('checkout %s' % branch)
841 git('pull origin %s' % branch)
842 if os.path.exists('src/%s/gen_build_yaml.py' % submodule):
843 need_to_regenerate_projects = True
844if need_to_regenerate_projects:
845 if jobset.platform_string() == 'linux':
846 subprocess.check_call('tools/buildgen/generate_projects.sh', shell=True)
847 else:
848 print 'WARNING: may need to regenerate projects, but since we are not on'
849 print ' Linux this step is being skipped. Compilation MAY fail.'
Craig Tiller1676f912016-01-05 10:49:44 -0800850
851
Nicolas Nobleddef2462015-01-06 18:08:25 -0800852# grab config
Jan Tattermusch77db4322016-02-20 20:19:35 -0800853run_config = _CONFIGS[args.config]
854build_config = run_config.build_config
Craig Tillerf1973b02015-01-16 12:32:13 -0800855
Craig Tiller06805272015-06-11 14:46:47 -0700856if args.travis:
murgatroid99d3b5b7f2015-10-06 17:02:03 -0700857 _FORCE_ENVIRON_FOR_WRAPPERS = {'GRPC_TRACE': 'api'}
Craig Tiller06805272015-06-11 14:46:47 -0700858
Adele Zhou6b9527c2015-11-20 15:56:35 -0800859if 'all' in args.language:
Craig Tiller1676f912016-01-05 10:49:44 -0800860 lang_list = _LANGUAGES.keys()
Adele Zhou6b9527c2015-11-20 15:56:35 -0800861else:
862 lang_list = args.language
Craig Tiller16900662016-01-07 19:30:54 -0800863# We don't support code coverage on some languages
864if 'gcov' in args.config:
Jan Tattermusch3b5121b2016-02-22 17:41:05 -0800865 for bad in ['objc', 'sanity']:
Craig Tiller16900662016-01-07 19:30:54 -0800866 if bad in lang_list:
867 lang_list.remove(bad)
Adele Zhou6b9527c2015-11-20 15:56:35 -0800868
869languages = set(_LANGUAGES[l] for l in lang_list)
Jan Tattermusch77db4322016-02-20 20:19:35 -0800870for l in languages:
871 l.configure(run_config, args)
murgatroid99132ce6a2015-03-04 17:29:14 -0800872
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800873language_make_options=[]
874if any(language.make_options() for language in languages):
875 if len(languages) != 1:
876 print 'languages with custom make options cannot be built simultaneously with other languages'
877 sys.exit(1)
878 else:
879 language_make_options = next(iter(languages)).make_options()
880
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800881if args.use_docker:
882 if not args.travis:
883 print 'Seen --use_docker flag, will run tests under docker.'
884 print
885 print 'IMPORTANT: The changes you are testing need to be locally committed'
886 print 'because only the committed changes in the current branch will be'
887 print 'copied to the docker environment.'
888 time.sleep(5)
889
Jan Tattermusch3b5121b2016-02-22 17:41:05 -0800890 dockerfile_dirs = set([l.dockerfile_dir() for l in languages])
891 if len(dockerfile_dirs) > 1:
Adele Zhou9506ef22016-03-02 13:53:34 -0800892 if 'gcov' in args.config:
893 dockerfile_dir = 'tools/dockerfile/test/multilang_jessie_x64'
894 print ('Using multilang_jessie_x64 docker image for code coverage for '
895 'all languages.')
896 else:
897 print ('Languages to be tested require running under different docker '
898 'images.')
899 sys.exit(1)
900 else:
901 dockerfile_dir = next(iter(dockerfile_dirs))
Craig Tillerde7edf82016-03-20 09:12:16 -0700902
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800903 child_argv = [ arg for arg in sys.argv if not arg == '--use_docker' ]
Jan Tattermusched342b12016-01-26 14:40:31 -0800904 run_tests_cmd = 'python tools/run_tests/run_tests.py %s' % ' '.join(child_argv[1:])
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800905
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800906 env = os.environ.copy()
907 env['RUN_TESTS_COMMAND'] = run_tests_cmd
Jan Tattermusch3b5121b2016-02-22 17:41:05 -0800908 env['DOCKERFILE_DIR'] = dockerfile_dir
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800909 env['DOCKER_RUN_SCRIPT'] = 'tools/jenkins/docker_run_tests.sh'
910 if args.xml_report:
911 env['XML_REPORT'] = args.xml_report
912 if not args.travis:
913 env['TTY_FLAG'] = '-t' # enables Ctrl-C when not on Jenkins.
914
915 subprocess.check_call(['tools/jenkins/build_docker_and_run_tests.sh'],
916 shell=True,
917 env=env)
918 sys.exit(0)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800919
Jan Tattermuschf08018a2016-01-26 08:22:09 -0800920_check_arch_option(args.arch)
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800921
Jan Tattermuschfba65302016-01-25 18:21:14 -0800922def make_jobspec(cfg, targets, makefile='Makefile'):
923 if platform_string() == 'windows':
Craig Tillerfc3c0c42015-09-01 16:47:54 -0700924 extra_args = []
Craig Tillerb5391e12015-09-03 14:35:18 -0700925 # better do parallel compilation
Jan Tattermusch47eeb2b2015-10-07 14:09:18 -0700926 # empirically /m:2 gives the best performance/price and should prevent
927 # overloading the windows workers.
Adele Zhoue4c35612015-10-16 15:34:23 -0700928 extra_args.extend(['/m:2'])
Craig Tillerb5391e12015-09-03 14:35:18 -0700929 # disable PDB generation: it's broken, and we don't need it during CI
Adele Zhoue4c35612015-10-16 15:34:23 -0700930 extra_args.extend(['/p:Jenkins=true'])
Craig Tiller6fd23842015-09-01 07:36:31 -0700931 return [
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800932 jobset.JobSpec([_windows_build_bat(args.compiler),
murgatroid99cf08daf2015-09-21 15:33:16 -0700933 'vsprojects\\%s.sln' % target,
Jan Tattermuscha2d964c2016-02-22 17:33:09 -0800934 '/p:Configuration=%s' % _MSBUILD_CONFIG[cfg]] +
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800935 extra_args +
936 language_make_options,
Craig Tiller590105a2016-01-19 13:03:46 -0800937 shell=True, timeout_seconds=None)
Craig Tiller6fd23842015-09-01 07:36:31 -0700938 for target in targets]
Jan Tattermuschfba65302016-01-25 18:21:14 -0800939 else:
murgatroid998ae409f2015-10-26 16:39:00 -0700940 if targets:
941 return [jobset.JobSpec([os.getenv('MAKE', 'make'),
942 '-f', makefile,
Craig Tillerdd6f7ed2016-01-21 12:54:42 -0800943 '-j', '%d' % args.jobs,
Craig Tiller71a86042016-01-15 14:59:58 -0800944 'EXTRA_DEFINES=GRPC_TEST_SLOWDOWN_MACHINE_FACTOR=%f' % args.slowdown,
945 'CONFIG=%s' % cfg] +
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800946 language_make_options +
Craig Tiller71a86042016-01-15 14:59:58 -0800947 ([] if not args.travis else ['JENKINS_BUILD=1']) +
948 targets,
Craig Tiller590105a2016-01-19 13:03:46 -0800949 timeout_seconds=None)]
murgatroid998ae409f2015-10-26 16:39:00 -0700950 else:
951 return []
Jan Tattermuschfba65302016-01-25 18:21:14 -0800952
murgatroid99a3e244f2015-09-22 11:25:53 -0700953make_targets = {}
954for l in languages:
955 makefile = l.makefile_name()
956 make_targets[makefile] = make_targets.get(makefile, set()).union(
Jan Tattermusch77db4322016-02-20 20:19:35 -0800957 set(l.make_targets()))
Craig Tiller5058c692015-04-08 09:42:04 -0700958
Jan Tattermusche4a69182015-12-15 09:53:01 -0800959def build_step_environ(cfg):
960 environ = {'CONFIG': cfg}
Jan Tattermuscha2d964c2016-02-22 17:33:09 -0800961 msbuild_cfg = _MSBUILD_CONFIG.get(cfg)
Jan Tattermusche4a69182015-12-15 09:53:01 -0800962 if msbuild_cfg:
963 environ['MSBUILD_CONFIG'] = msbuild_cfg
964 return environ
965
murgatroid99fddac962015-09-22 09:20:11 -0700966build_steps = list(set(
Jan Tattermusch77db4322016-02-20 20:19:35 -0800967 jobset.JobSpec(cmdline, environ=build_step_environ(build_config), flake_retries=5)
murgatroid99256d3df2015-09-21 16:58:02 -0700968 for l in languages
969 for cmdline in l.pre_build_steps()))
Craig Tillerbd4e3782015-09-01 06:48:55 -0700970if make_targets:
Jan Tattermusch77db4322016-02-20 20:19:35 -0800971 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 -0700972 build_steps.extend(set(make_commands))
Craig Tiller5058c692015-04-08 09:42:04 -0700973build_steps.extend(set(
Jan Tattermusch77db4322016-02-20 20:19:35 -0800974 jobset.JobSpec(cmdline, environ=build_step_environ(build_config), timeout_seconds=None)
Craig Tiller547db2b2015-01-30 14:08:39 -0800975 for l in languages
Craig Tiller533b1a22015-05-29 08:41:29 -0700976 for cmdline in l.build_steps()))
Craig Tillerf1973b02015-01-16 12:32:13 -0800977
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200978post_tests_steps = list(set(
Jan Tattermusch77db4322016-02-20 20:19:35 -0800979 jobset.JobSpec(cmdline, environ=build_step_environ(build_config))
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200980 for l in languages
981 for cmdline in l.post_tests_steps()))
Nicolas Nobleddef2462015-01-06 18:08:25 -0800982runs_per_test = args.runs_per_test
ctiller3040cb72015-01-07 12:13:17 -0800983forever = args.forever
Nicolas Nobleddef2462015-01-06 18:08:25 -0800984
Nicolas Nobleddef2462015-01-06 18:08:25 -0800985
Craig Tiller71735182015-01-15 17:07:13 -0800986class TestCache(object):
Craig Tillerb50d1662015-01-15 17:28:21 -0800987 """Cache for running tests."""
988
David Klempner25739582015-02-11 15:57:32 -0800989 def __init__(self, use_cache_results):
Craig Tiller71735182015-01-15 17:07:13 -0800990 self._last_successful_run = {}
David Klempner25739582015-02-11 15:57:32 -0800991 self._use_cache_results = use_cache_results
Craig Tiller69cd2372015-06-11 09:38:09 -0700992 self._last_save = time.time()
Craig Tiller71735182015-01-15 17:07:13 -0800993
994 def should_run(self, cmdline, bin_hash):
Craig Tiller71735182015-01-15 17:07:13 -0800995 if cmdline not in self._last_successful_run:
996 return True
997 if self._last_successful_run[cmdline] != bin_hash:
998 return True
David Klempner25739582015-02-11 15:57:32 -0800999 if not self._use_cache_results:
1000 return True
Craig Tiller71735182015-01-15 17:07:13 -08001001 return False
1002
1003 def finished(self, cmdline, bin_hash):
Craig Tiller547db2b2015-01-30 14:08:39 -08001004 self._last_successful_run[cmdline] = bin_hash
Craig Tiller69cd2372015-06-11 09:38:09 -07001005 if time.time() - self._last_save > 1:
1006 self.save()
Craig Tiller71735182015-01-15 17:07:13 -08001007
1008 def dump(self):
Craig Tillerb50d1662015-01-15 17:28:21 -08001009 return [{'cmdline': k, 'hash': v}
1010 for k, v in self._last_successful_run.iteritems()]
Craig Tiller71735182015-01-15 17:07:13 -08001011
1012 def parse(self, exdump):
1013 self._last_successful_run = dict((o['cmdline'], o['hash']) for o in exdump)
1014
1015 def save(self):
1016 with open('.run_tests_cache', 'w') as f:
Craig Tiller261dd982015-01-16 16:41:45 -08001017 f.write(json.dumps(self.dump()))
Craig Tiller69cd2372015-06-11 09:38:09 -07001018 self._last_save = time.time()
Craig Tiller71735182015-01-15 17:07:13 -08001019
Craig Tiller1cc11db2015-01-15 22:50:50 -08001020 def maybe_load(self):
1021 if os.path.exists('.run_tests_cache'):
1022 with open('.run_tests_cache') as f:
Craig Tiller261dd982015-01-16 16:41:45 -08001023 self.parse(json.loads(f.read()))
Craig Tiller71735182015-01-15 17:07:13 -08001024
1025
Craig Tillerf53d9c82015-08-04 14:19:43 -07001026def _start_port_server(port_server_port):
1027 # check if a compatible port server is running
1028 # if incompatible (version mismatch) ==> start a new one
1029 # if not running ==> start a new one
1030 # otherwise, leave it up
1031 try:
Craig Tillerfe4939f2015-10-06 12:55:36 -07001032 version = int(urllib2.urlopen(
1033 'http://localhost:%d/version_number' % port_server_port,
1034 timeout=1).read())
1035 print 'detected port server running version %d' % version
Craig Tillerf53d9c82015-08-04 14:19:43 -07001036 running = True
Craig Tillerfe4939f2015-10-06 12:55:36 -07001037 except Exception as e:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001038 print 'failed to detect port server: %s' % sys.exc_info()[0]
Craig Tillerfe4939f2015-10-06 12:55:36 -07001039 print e.strerror
Craig Tillerf53d9c82015-08-04 14:19:43 -07001040 running = False
1041 if running:
Craig Tillerfe4939f2015-10-06 12:55:36 -07001042 current_version = int(subprocess.check_output(
Jan Tattermusch3bd08272015-11-04 19:24:37 -08001043 [sys.executable, os.path.abspath('tools/run_tests/port_server.py'),
1044 'dump_version']))
Craig Tillerfe4939f2015-10-06 12:55:36 -07001045 print 'my port server is version %d' % current_version
1046 running = (version >= current_version)
1047 if not running:
1048 print 'port_server version mismatch: killing the old one'
1049 urllib2.urlopen('http://localhost:%d/quitquitquit' % port_server_port).read()
1050 time.sleep(1)
Craig Tillerf53d9c82015-08-04 14:19:43 -07001051 if not running:
Craig Tillerf0a293e2015-10-12 10:05:50 -07001052 fd, logfile = tempfile.mkstemp()
1053 os.close(fd)
1054 print 'starting port_server, with log file %s' % logfile
Jan Tattermusch3bd08272015-11-04 19:24:37 -08001055 args = [sys.executable, os.path.abspath('tools/run_tests/port_server.py'),
1056 '-p', '%d' % port_server_port, '-l', logfile]
Craig Tiller367d41d2015-10-12 13:00:22 -07001057 env = dict(os.environ)
1058 env['BUILD_ID'] = 'pleaseDontKillMeJenkins'
Nicolas "Pixel" Noblef72d7b52015-12-03 03:07:43 +01001059 if platform_string() == 'windows':
Jan Tattermusch3bd08272015-11-04 19:24:37 -08001060 # Working directory of port server needs to be outside of Jenkins
1061 # workspace to prevent file lock issues.
1062 tempdir = tempfile.mkdtemp()
Craig Tillerd2c39712015-10-12 11:08:49 -07001063 port_server = subprocess.Popen(
Craig Tiller367d41d2015-10-12 13:00:22 -07001064 args,
1065 env=env,
Jan Tattermusch3bd08272015-11-04 19:24:37 -08001066 cwd=tempdir,
Craig Tiller367d41d2015-10-12 13:00:22 -07001067 creationflags = 0x00000008, # detached process
1068 close_fds=True)
Craig Tillerd2c39712015-10-12 11:08:49 -07001069 else:
1070 port_server = subprocess.Popen(
1071 args,
Craig Tiller367d41d2015-10-12 13:00:22 -07001072 env=env,
Craig Tillerd2c39712015-10-12 11:08:49 -07001073 preexec_fn=os.setsid,
1074 close_fds=True)
Craig Tillerf0a293e2015-10-12 10:05:50 -07001075 time.sleep(1)
Craig Tiller8b5f4dc2015-08-26 08:02:01 -07001076 # ensure port server is up
Craig Tillerabd37fd2015-08-26 07:54:01 -07001077 waits = 0
Craig Tillerf53d9c82015-08-04 14:19:43 -07001078 while True:
Craig Tillerabd37fd2015-08-26 07:54:01 -07001079 if waits > 10:
Craig Tillerf0a293e2015-10-12 10:05:50 -07001080 print 'killing port server due to excessive start up waits'
Craig Tillerabd37fd2015-08-26 07:54:01 -07001081 port_server.kill()
Craig Tillera2f38b02015-09-24 11:19:17 -07001082 if port_server.poll() is not None:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001083 print 'port_server failed to start'
Craig Tillerf0a293e2015-10-12 10:05:50 -07001084 # try one final time: maybe another build managed to start one
1085 time.sleep(1)
1086 try:
1087 urllib2.urlopen('http://localhost:%d/get' % port_server_port,
1088 timeout=1).read()
1089 print 'last ditch attempt to contact port server succeeded'
1090 break
1091 except:
Jan Tattermusch3b5121b2016-02-22 17:41:05 -08001092 traceback.print_exc()
Craig Tillerf0a293e2015-10-12 10:05:50 -07001093 port_log = open(logfile, 'r').read()
1094 print port_log
1095 sys.exit(1)
Craig Tillerf53d9c82015-08-04 14:19:43 -07001096 try:
Craig Tillerabd37fd2015-08-26 07:54:01 -07001097 urllib2.urlopen('http://localhost:%d/get' % port_server_port,
1098 timeout=1).read()
Craig Tillerf0a293e2015-10-12 10:05:50 -07001099 print 'port server is up and ready'
Craig Tillerf53d9c82015-08-04 14:19:43 -07001100 break
Craig Tiller31fdaa42015-09-25 13:09:59 -07001101 except socket.timeout:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001102 print 'waiting for port_server: timeout'
Craig Tillerf0a293e2015-10-12 10:05:50 -07001103 traceback.print_exc();
1104 time.sleep(1)
Craig Tiller31fdaa42015-09-25 13:09:59 -07001105 waits += 1
Craig Tillerf53d9c82015-08-04 14:19:43 -07001106 except urllib2.URLError:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001107 print 'waiting for port_server: urlerror'
Craig Tillerf0a293e2015-10-12 10:05:50 -07001108 traceback.print_exc();
1109 time.sleep(1)
Craig Tillerabd37fd2015-08-26 07:54:01 -07001110 waits += 1
Craig Tillerf53d9c82015-08-04 14:19:43 -07001111 except:
Jan Tattermusch3b5121b2016-02-22 17:41:05 -08001112 traceback.print_exc()
Craig Tillerf53d9c82015-08-04 14:19:43 -07001113 port_server.kill()
1114 raise
1115
1116
Adele Zhoud5fffa52015-10-23 15:51:42 -07001117def _calculate_num_runs_failures(list_of_results):
1118 """Caculate number of runs and failures for a particular test.
1119
1120 Args:
1121 list_of_results: (List) of JobResult object.
1122 Returns:
1123 A tuple of total number of runs and failures.
1124 """
1125 num_runs = len(list_of_results) # By default, there is 1 run per JobResult.
1126 num_failures = 0
1127 for jobresult in list_of_results:
1128 if jobresult.retries > 0:
1129 num_runs += jobresult.retries
1130 if jobresult.num_failures > 0:
1131 num_failures += jobresult.num_failures
1132 return num_runs, num_failures
1133
Adele Zhou6b9527c2015-11-20 15:56:35 -08001134
Craig Tillereb9de8b2016-01-08 08:57:41 -08001135# _build_and_run results
1136class BuildAndRunError(object):
1137
1138 BUILD = object()
1139 TEST = object()
1140 POST_TEST = object()
1141
1142
1143# returns a list of things that failed (or an empty list on success)
Craig Tillerf53d9c82015-08-04 14:19:43 -07001144def _build_and_run(
Jan Tattermusch2dd156e2015-12-04 18:26:17 -08001145 check_cancelled, newline_on_success, cache, xml_report=None, build_only=False):
ctiller3040cb72015-01-07 12:13:17 -08001146 """Do one pass of building & running tests."""
murgatroid99666450e2015-01-26 13:03:31 -08001147 # build latest sequentially
Jan Tattermuschaab1e512016-01-28 09:30:44 -08001148 num_failures, resultset = jobset.run(
Adele Zhoue4c35612015-10-16 15:34:23 -07001149 build_steps, maxjobs=1, stop_on_failure=True,
Craig Tiller883064c2015-11-04 10:06:10 -08001150 newline_on_success=newline_on_success, travis=args.travis)
Adele Zhoue4c35612015-10-16 15:34:23 -07001151 if num_failures:
Craig Tillereb9de8b2016-01-08 08:57:41 -08001152 return [BuildAndRunError.BUILD]
Craig Tillerb361b4e2016-01-06 11:44:17 -08001153
Jan Tattermusch2dd156e2015-12-04 18:26:17 -08001154 if build_only:
Jan Tattermuschaab1e512016-01-28 09:30:44 -08001155 if xml_report:
1156 report_utils.render_junit_xml_report(resultset, xml_report)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001157 return []
ctiller3040cb72015-01-07 12:13:17 -08001158
Craig Tiller234b6e72015-05-23 10:12:40 -07001159 # start antagonists
David Garcia Quintas79e389f2015-06-02 17:49:42 -07001160 antagonists = [subprocess.Popen(['tools/run_tests/antagonist.py'])
Craig Tiller234b6e72015-05-23 10:12:40 -07001161 for _ in range(0, args.antagonists)]
Craig Tillerfe4939f2015-10-06 12:55:36 -07001162 port_server_port = 32767
Craig Tillerf53d9c82015-08-04 14:19:43 -07001163 _start_port_server(port_server_port)
Adele Zhou7cf72112015-11-04 11:18:43 -08001164 resultset = None
Adele Zhou803af152015-11-30 15:16:16 -08001165 num_test_failures = 0
Craig Tiller234b6e72015-05-23 10:12:40 -07001166 try:
David Garcia Quintase90cd372015-05-31 18:15:26 -07001167 infinite_runs = runs_per_test == 0
yang-g6c1fdc62015-08-18 11:57:42 -07001168 one_run = set(
1169 spec
yang-g6c1fdc62015-08-18 11:57:42 -07001170 for language in languages
Jan Tattermusch77db4322016-02-20 20:19:35 -08001171 for spec in language.test_specs()
yang-g6c1fdc62015-08-18 11:57:42 -07001172 if re.search(args.regex, spec.shortname))
David Garcia Quintas79e389f2015-06-02 17:49:42 -07001173 # When running on travis, we want out test runs to be as similar as possible
1174 # for reproducibility purposes.
Craig Tiller883064c2015-11-04 10:06:10 -08001175 if args.travis:
David Garcia Quintas79e389f2015-06-02 17:49:42 -07001176 massaged_one_run = sorted(one_run, key=lambda x: x.shortname)
1177 else:
1178 # whereas otherwise, we want to shuffle things up to give all tests a
1179 # chance to run.
1180 massaged_one_run = list(one_run) # random.shuffle needs an indexable seq.
1181 random.shuffle(massaged_one_run) # which it modifies in-place.
Craig Tillerf7b7c892015-06-22 14:33:25 -07001182 if infinite_runs:
1183 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 -07001184 runs_sequence = (itertools.repeat(massaged_one_run) if infinite_runs
1185 else itertools.repeat(massaged_one_run, runs_per_test))
David Garcia Quintase90cd372015-05-31 18:15:26 -07001186 all_runs = itertools.chain.from_iterable(runs_sequence)
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +02001187
Adele Zhou803af152015-11-30 15:16:16 -08001188 num_test_failures, resultset = jobset.run(
Adele Zhou2271ab52015-10-28 13:59:14 -07001189 all_runs, check_cancelled, newline_on_success=newline_on_success,
Craig Tiller883064c2015-11-04 10:06:10 -08001190 travis=args.travis, infinite_runs=infinite_runs, maxjobs=args.jobs,
murgatroid998ae409f2015-10-26 16:39:00 -07001191 stop_on_failure=args.stop_on_failure,
Adele Zhouf2ca7bc2015-10-23 15:38:00 -07001192 cache=cache if not xml_report else None,
Adele Zhouf2ca7bc2015-10-23 15:38:00 -07001193 add_env={'GRPC_TEST_PORT_SERVER': 'localhost:%d' % port_server_port})
Adele Zhoud5fffa52015-10-23 15:51:42 -07001194 if resultset:
1195 for k, v in resultset.iteritems():
1196 num_runs, num_failures = _calculate_num_runs_failures(v)
1197 if num_failures == num_runs: # what about infinite_runs???
1198 jobset.message('FAILED', k, do_newline=True)
1199 elif num_failures > 0:
1200 jobset.message(
1201 'FLAKE', '%s [%d/%d runs flaked]' % (k, num_failures, num_runs),
1202 do_newline=True)
1203 else:
1204 jobset.message('PASSED', k, do_newline=True)
Craig Tiller234b6e72015-05-23 10:12:40 -07001205 finally:
1206 for antagonist in antagonists:
1207 antagonist.kill()
Adele Zhou7cf72112015-11-04 11:18:43 -08001208 if xml_report and resultset:
Adele Zhou3bc7ba42015-11-05 10:21:58 -08001209 report_utils.render_junit_xml_report(resultset, xml_report)
Craig Tillerd86a3942015-01-14 12:48:54 -08001210
Adele Zhouf2ca7bc2015-10-23 15:38:00 -07001211 number_failures, _ = jobset.run(
1212 post_tests_steps, maxjobs=1, stop_on_failure=True,
Craig Tiller883064c2015-11-04 10:06:10 -08001213 newline_on_success=newline_on_success, travis=args.travis)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001214
1215 out = []
1216 if number_failures:
1217 out.append(BuildAndRunError.POST_TEST)
1218 if num_test_failures:
1219 out.append(BuildAndRunError.TEST)
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +02001220
Craig Tiller69cd2372015-06-11 09:38:09 -07001221 if cache: cache.save()
1222
Craig Tillereb9de8b2016-01-08 08:57:41 -08001223 return out
ctiller3040cb72015-01-07 12:13:17 -08001224
1225
David Klempner25739582015-02-11 15:57:32 -08001226test_cache = TestCache(runs_per_test == 1)
Craig Tiller547db2b2015-01-30 14:08:39 -08001227test_cache.maybe_load()
Craig Tiller71735182015-01-15 17:07:13 -08001228
ctiller3040cb72015-01-07 12:13:17 -08001229if forever:
Nicolas Noble044db742015-01-14 16:57:24 -08001230 success = True
ctiller3040cb72015-01-07 12:13:17 -08001231 while True:
Craig Tiller42bc87c2015-02-23 08:50:19 -08001232 dw = watch_dirs.DirWatcher(['src', 'include', 'test', 'examples'])
ctiller3040cb72015-01-07 12:13:17 -08001233 initial_time = dw.most_recent_change()
1234 have_files_changed = lambda: dw.most_recent_change() != initial_time
Nicolas Noble044db742015-01-14 16:57:24 -08001235 previous_success = success
Craig Tillereb9de8b2016-01-08 08:57:41 -08001236 errors = _build_and_run(check_cancelled=have_files_changed,
1237 newline_on_success=False,
1238 cache=test_cache,
1239 build_only=args.build_only) == 0
1240 if not previous_success and not errors:
Nicolas Nobleb09078f2015-01-14 18:06:05 -08001241 jobset.message('SUCCESS',
1242 'All tests are now passing properly',
1243 do_newline=True)
Nicolas Noble044db742015-01-14 16:57:24 -08001244 jobset.message('IDLE', 'No change detected')
ctiller3040cb72015-01-07 12:13:17 -08001245 while not have_files_changed():
1246 time.sleep(1)
1247else:
Craig Tillereb9de8b2016-01-08 08:57:41 -08001248 errors = _build_and_run(check_cancelled=lambda: False,
Craig Tiller71735182015-01-15 17:07:13 -08001249 newline_on_success=args.newline_on_success,
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +02001250 cache=test_cache,
Jan Tattermusch2dd156e2015-12-04 18:26:17 -08001251 xml_report=args.xml_report,
1252 build_only=args.build_only)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001253 if not errors:
Nicolas Nobleb09078f2015-01-14 18:06:05 -08001254 jobset.message('SUCCESS', 'All tests passed', do_newline=True)
1255 else:
1256 jobset.message('FAILED', 'Some tests failed', do_newline=True)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001257 exit_code = 0
1258 if BuildAndRunError.BUILD in errors:
1259 exit_code |= 1
Craig Tiller4f2be362016-01-08 08:59:20 -08001260 if BuildAndRunError.TEST in errors and not args.travis:
Craig Tillereb9de8b2016-01-08 08:57:41 -08001261 exit_code |= 2
Craig Tiller4f2be362016-01-08 08:59:20 -08001262 if BuildAndRunError.POST_TEST in errors:
1263 exit_code |= 4
Craig Tillereb9de8b2016-01-08 08:57:41 -08001264 sys.exit(exit_code)