blob: 2f0f1f74739fe13142b30e5085fbdb9f35f009f0 [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
Jan Tattermusch77db4322016-02-20 20:19:35 -0800276 def configure(self, config, args):
277 self.config = config
278 self.args = args
murgatroid999fab4382016-04-29 15:05:00 -0700279 _check_compiler(self.args.compiler, ['default', 'node0.12',
280 'node4', 'node5'])
281 if self.args.compiler == 'default':
282 self.node_version = '4'
283 else:
284 # Take off the word "node"
285 self.node_version = self.args.compiler[4:]
Jan Tattermusch77db4322016-02-20 20:19:35 -0800286
287 def test_specs(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800288 if self.platform == 'windows':
Jan Tattermusch77db4322016-02-20 20:19:35 -0800289 return [self.config.job_spec(['tools\\run_tests\\run_node.bat'], None)]
Michael Lumishaaa876a2016-02-10 15:27:58 -0800290 else:
Jan Tattermusch77db4322016-02-20 20:19:35 -0800291 return [self.config.job_spec(['tools/run_tests/run_node.sh', self.node_version],
292 None,
293 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
murgatroid992c8d5162015-01-26 10:41:21 -0800294
murgatroid99256d3df2015-09-21 16:58:02 -0700295 def pre_build_steps(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800296 if self.platform == 'windows':
297 return [['tools\\run_tests\\pre_build_node.bat']]
298 else:
299 return [['tools/run_tests/pre_build_node.sh', self.node_version]]
murgatroid99256d3df2015-09-21 16:58:02 -0700300
Jan Tattermusch77db4322016-02-20 20:19:35 -0800301 def make_targets(self):
murgatroid99db5b1602015-10-01 13:20:11 -0700302 return []
murgatroid992c8d5162015-01-26 10:41:21 -0800303
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800304 def make_options(self):
305 return []
306
murgatroid992c8d5162015-01-26 10:41:21 -0800307 def build_steps(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800308 if self.platform == 'windows':
309 return [['tools\\run_tests\\build_node.bat']]
310 else:
311 return [['tools/run_tests/build_node.sh', self.node_version]]
Craig Tillerc7449162015-01-16 14:42:10 -0800312
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200313 def post_tests_steps(self):
Michael Lumish60d38cb2016-03-04 13:05:04 -0800314 return []
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200315
murgatroid99a3e244f2015-09-22 11:25:53 -0700316 def makefile_name(self):
317 return 'Makefile'
318
Jan Tattermusch77db4322016-02-20 20:19:35 -0800319 def dockerfile_dir(self):
320 return 'tools/dockerfile/test/node_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800321
murgatroid99132ce6a2015-03-04 17:29:14 -0800322 def __str__(self):
323 return 'node'
324
Craig Tiller99775822015-01-30 13:07:16 -0800325
Craig Tillerc7449162015-01-16 14:42:10 -0800326class PhpLanguage(object):
327
Jan Tattermusch77db4322016-02-20 20:19:35 -0800328 def configure(self, config, args):
329 self.config = config
330 self.args = args
331 _check_compiler(self.args.compiler, ['default'])
332
333 def test_specs(self):
334 return [self.config.job_spec(['src/php/bin/run_tests.sh'], None,
335 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
Craig Tillerc7449162015-01-16 14:42:10 -0800336
murgatroid99256d3df2015-09-21 16:58:02 -0700337 def pre_build_steps(self):
338 return []
339
Jan Tattermusch77db4322016-02-20 20:19:35 -0800340 def make_targets(self):
Craig Tilleraf7cf542015-05-22 10:07:34 -0700341 return ['static_c', 'shared_c']
Craig Tillerc7449162015-01-16 14:42:10 -0800342
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800343 def make_options(self):
344 return []
345
Craig Tillerc7449162015-01-16 14:42:10 -0800346 def build_steps(self):
347 return [['tools/run_tests/build_php.sh']]
348
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200349 def post_tests_steps(self):
Stanley Cheunga6b95482016-01-13 16:10:48 -0800350 return [['tools/run_tests/post_tests_php.sh']]
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200351
murgatroid99a3e244f2015-09-22 11:25:53 -0700352 def makefile_name(self):
353 return 'Makefile'
354
Jan Tattermusch77db4322016-02-20 20:19:35 -0800355 def dockerfile_dir(self):
356 return 'tools/dockerfile/test/php_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800357
murgatroid99132ce6a2015-03-04 17:29:14 -0800358 def __str__(self):
359 return 'php'
360
Craig Tillerc7449162015-01-16 14:42:10 -0800361
Nathaniel Manista840615e2015-01-22 20:31:47 +0000362class PythonLanguage(object):
363
Jan Tattermusch77db4322016-02-20 20:19:35 -0800364 def configure(self, config, args):
365 self.config = config
366 self.args = args
Jan Tattermusch825471c2016-04-25 16:52:25 -0700367 self._tox_env = self._get_tox_env(self.args.compiler)
Jan Tattermusch77db4322016-02-20 20:19:35 -0800368
369 def test_specs(self):
Jan Tattermusch072ebaa2016-03-01 18:33:12 -0800370 # load list of known test suites
371 with open('src/python/grpcio/tests/tests.json') as tests_json_file:
372 tests_json = json.load(tests_json_file)
Masood Malekghassemi2b841622015-07-28 17:39:02 -0700373 environment = dict(_FORCE_ENVIRON_FOR_WRAPPERS)
Ken Payson707c9e22016-04-20 09:42:19 -0700374 environment['PYTHONPATH'] = os.path.abspath('src/python/gens')
Jan Tattermusch072ebaa2016-03-01 18:33:12 -0800375 if self.config.build_config != 'gcov':
376 return [self.config.job_spec(
Jan Tattermusch825471c2016-04-25 16:52:25 -0700377 ['tools/run_tests/run_python.sh', self._tox_env],
Jan Tattermusch072ebaa2016-03-01 18:33:12 -0800378 None,
379 environ=dict(environment.items() +
Masood Malekghassemif7ff8be2016-03-09 15:27:28 -0800380 [('GRPC_PYTHON_TESTRUNNER_FILTER', suite_name)]),
Jan Tattermusch072ebaa2016-03-01 18:33:12 -0800381 shortname='py.test.%s' % suite_name,
382 timeout_seconds=5*60)
383 for suite_name in tests_json]
384 else:
385 return [self.config.job_spec(['tools/run_tests/run_python.sh'],
386 None,
387 environ=environment,
388 shortname='py.test.coverage',
389 timeout_seconds=15*60)]
390
Nathaniel Manista840615e2015-01-22 20:31:47 +0000391
murgatroid99256d3df2015-09-21 16:58:02 -0700392 def pre_build_steps(self):
393 return []
394
Jan Tattermusch77db4322016-02-20 20:19:35 -0800395 def make_targets(self):
Craig Tilleraf7cf542015-05-22 10:07:34 -0700396 return ['static_c', 'grpc_python_plugin', 'shared_c']
Nathaniel Manista840615e2015-01-22 20:31:47 +0000397
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800398 def make_options(self):
399 return []
400
Nathaniel Manista840615e2015-01-22 20:31:47 +0000401 def build_steps(self):
Jan Tattermusch825471c2016-04-25 16:52:25 -0700402 return [['tools/run_tests/build_python.sh', self._tox_env]]
Nathaniel Manista840615e2015-01-22 20:31:47 +0000403
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200404 def post_tests_steps(self):
405 return []
406
murgatroid99a3e244f2015-09-22 11:25:53 -0700407 def makefile_name(self):
408 return 'Makefile'
409
Jan Tattermusch77db4322016-02-20 20:19:35 -0800410 def dockerfile_dir(self):
411 return 'tools/dockerfile/test/python_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800412
Jan Tattermusch825471c2016-04-25 16:52:25 -0700413 def _get_tox_env(self, compiler):
414 """Returns name of tox environment based on selected compiler."""
415 if compiler == 'python2.7' or compiler == 'default':
416 return 'py27'
417 elif compiler == 'python3.4':
418 return 'py34'
419 else:
420 raise Exception('Compiler %s not supported.' % compiler)
421
murgatroid99132ce6a2015-03-04 17:29:14 -0800422 def __str__(self):
423 return 'python'
424
Craig Tillerd625d812015-04-08 15:52:35 -0700425
murgatroid996a4c4fa2015-02-27 12:08:57 -0800426class RubyLanguage(object):
427
Jan Tattermusch77db4322016-02-20 20:19:35 -0800428 def configure(self, config, args):
429 self.config = config
430 self.args = args
431 _check_compiler(self.args.compiler, ['default'])
432
433 def test_specs(self):
434 return [self.config.job_spec(['tools/run_tests/run_ruby.sh'], None,
435 timeout_seconds=10*60,
436 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
murgatroid996a4c4fa2015-02-27 12:08:57 -0800437
murgatroid99256d3df2015-09-21 16:58:02 -0700438 def pre_build_steps(self):
Nicolas "Pixel" Noblebcf988f2015-10-08 03:00:42 +0200439 return [['tools/run_tests/pre_build_ruby.sh']]
murgatroid99256d3df2015-09-21 16:58:02 -0700440
Jan Tattermusch4651bef2016-02-23 08:31:25 -0800441 def make_targets(self):
murgatroid997d243df2016-02-18 09:58:05 -0800442 return []
murgatroid996a4c4fa2015-02-27 12:08:57 -0800443
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800444 def make_options(self):
445 return []
446
murgatroid996a4c4fa2015-02-27 12:08:57 -0800447 def build_steps(self):
448 return [['tools/run_tests/build_ruby.sh']]
449
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200450 def post_tests_steps(self):
Nicolas "Pixel" Noble7ef1e532015-12-02 00:55:33 +0100451 return [['tools/run_tests/post_tests_ruby.sh']]
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200452
murgatroid99a3e244f2015-09-22 11:25:53 -0700453 def makefile_name(self):
454 return 'Makefile'
455
Jan Tattermusch77db4322016-02-20 20:19:35 -0800456 def dockerfile_dir(self):
457 return 'tools/dockerfile/test/ruby_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800458
murgatroid99132ce6a2015-03-04 17:29:14 -0800459 def __str__(self):
460 return 'ruby'
461
Craig Tillerd625d812015-04-08 15:52:35 -0700462
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800463class CSharpLanguage(object):
Jan Tattermusch77db4322016-02-20 20:19:35 -0800464
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700465 def __init__(self):
Craig Tillerd50993d2015-08-05 08:04:36 -0700466 self.platform = platform_string()
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700467
Jan Tattermusch77db4322016-02-20 20:19:35 -0800468 def configure(self, config, args):
469 self.config = config
470 self.args = args
Jan Tattermusch690914f2016-03-25 15:07:22 -0700471 if self.platform == 'windows':
Jan Tattermuschabd7df82016-03-25 16:14:41 -0700472 # Explicitly choosing between x86 and x64 arch doesn't work yet
473 _check_arch(self.args.arch, ['default'])
Jan Tattermusch690914f2016-03-25 15:07:22 -0700474 self._make_options = [_windows_toolset_option(self.args.compiler),
475 _windows_arch_option(self.args.arch)]
476 else:
477 _check_compiler(self.args.compiler, ['default'])
478 if self.platform == 'mac':
479 # On Mac, official distribution of mono is 32bit.
Jan Tattermusch2a322c22016-03-30 13:55:07 -0700480 # TODO(jtattermusch): EMBED_ZLIB=true currently breaks the mac build
481 self._make_options = ['EMBED_OPENSSL=true',
Jan Tattermuschd9ff4562016-03-30 13:40:48 -0700482 'CFLAGS=-m32', 'LDFLAGS=-m32']
Jan Tattermusch690914f2016-03-25 15:07:22 -0700483 else:
484 self._make_options = ['EMBED_OPENSSL=true', 'EMBED_ZLIB=true']
Jan Tattermusch77db4322016-02-20 20:19:35 -0800485
486 def test_specs(self):
Jan Tattermusch03c01062015-12-11 14:28:56 -0800487 with open('src/csharp/tests.json') as f:
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700488 tests_by_assembly = json.load(f)
Jan Tattermusch03c01062015-12-11 14:28:56 -0800489
Jan Tattermuscha2d964c2016-02-22 17:33:09 -0800490 msbuild_config = _MSBUILD_CONFIG[self.config.build_config]
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700491 nunit_args = ['--labels=All',
Jan Tattermuschf6824c22016-04-08 17:18:44 -0700492 '--noresult',
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700493 '--workers=1']
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700494 if self.platform == 'windows':
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700495 runtime_cmd = []
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700496 else:
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700497 runtime_cmd = ['mono']
Jan Tattermuschbf3b1532015-10-26 10:24:42 -0700498
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700499 specs = []
500 for assembly in tests_by_assembly.iterkeys():
501 assembly_file = 'src/csharp/%s/bin/%s/%s.exe' % (assembly, msbuild_config, assembly)
Jan Tattermuscha5f1f122016-04-11 15:49:56 -0700502 if self.config.build_config != 'gcov' or self.platform != 'windows':
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700503 # normally, run each test as a separate process
504 for test in tests_by_assembly[assembly]:
505 cmdline = runtime_cmd + [assembly_file, '--test=%s' % test] + nunit_args
506 specs.append(self.config.job_spec(cmdline,
507 None,
508 shortname='csharp.%s' % test,
509 environ=_FORCE_ENVIRON_FOR_WRAPPERS))
510 else:
Jan Tattermuscha5f1f122016-04-11 15:49:56 -0700511 # For C# test coverage, run all tests from the same assembly at once
512 # using OpenCover.Console (only works on Windows).
513 cmdline = ['src\\csharp\\packages\\OpenCover.4.6.519\\tools\\OpenCover.Console.exe',
514 '-target:%s' % assembly_file,
515 '-targetdir:src\\csharp',
516 '-targetargs:%s' % ' '.join(nunit_args),
517 '-filter:+[Grpc.Core]*',
518 '-register:user',
519 '-output:src\\csharp\\coverage_csharp_%s.xml' % assembly]
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700520
Jan Tattermuscha5f1f122016-04-11 15:49:56 -0700521 # set really high cpu_cost to make sure instances of OpenCover.Console run exclusively
522 # to prevent problems with registering the profiler.
523 run_exclusive = 1000000
Jan Tattermusch35e608f2016-04-09 16:35:06 -0700524 specs.append(self.config.job_spec(cmdline,
525 None,
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700526 shortname='csharp.coverage.%s' % assembly,
Jan Tattermuscha5f1f122016-04-11 15:49:56 -0700527 cpu_cost=run_exclusive,
Jan Tattermusch77db4322016-02-20 20:19:35 -0800528 environ=_FORCE_ENVIRON_FOR_WRAPPERS))
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700529 return specs
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800530
murgatroid99256d3df2015-09-21 16:58:02 -0700531 def pre_build_steps(self):
Jan Tattermusch48423fc2015-10-07 18:59:16 -0700532 if self.platform == 'windows':
Jan Tattermusch874aec02015-10-07 19:26:19 -0700533 return [['tools\\run_tests\\pre_build_csharp.bat']]
Jan Tattermusch48423fc2015-10-07 18:59:16 -0700534 else:
535 return [['tools/run_tests/pre_build_csharp.sh']]
murgatroid99256d3df2015-09-21 16:58:02 -0700536
Jan Tattermusch77db4322016-02-20 20:19:35 -0800537 def make_targets(self):
Jan Tattermusch690914f2016-03-25 15:07:22 -0700538 return ['grpc_csharp_ext']
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800539
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800540 def make_options(self):
Jan Tattermusch690914f2016-03-25 15:07:22 -0700541 return self._make_options;
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800542
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800543 def build_steps(self):
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700544 if self.platform == 'windows':
Jan Tattermusch690914f2016-03-25 15:07:22 -0700545 return [[_windows_build_bat(self.args.compiler),
546 'src/csharp/Grpc.sln',
547 '/p:Configuration=%s' % _MSBUILD_CONFIG[self.config.build_config]]]
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700548 else:
549 return [['tools/run_tests/build_csharp.sh']]
Nathaniel Manista840615e2015-01-22 20:31:47 +0000550
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200551 def post_tests_steps(self):
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700552 if self.platform == 'windows':
553 return [['tools\\run_tests\\post_tests_csharp.bat']]
554 else:
555 return [['tools/run_tests/post_tests_csharp.sh']]
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200556
murgatroid99a3e244f2015-09-22 11:25:53 -0700557 def makefile_name(self):
558 return 'Makefile'
559
Jan Tattermusch77db4322016-02-20 20:19:35 -0800560 def dockerfile_dir(self):
561 return 'tools/dockerfile/test/csharp_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800562
murgatroid99132ce6a2015-03-04 17:29:14 -0800563 def __str__(self):
564 return 'csharp'
565
Craig Tillerd625d812015-04-08 15:52:35 -0700566
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700567class ObjCLanguage(object):
568
Jan Tattermusch77db4322016-02-20 20:19:35 -0800569 def configure(self, config, args):
570 self.config = config
571 self.args = args
572 _check_compiler(self.args.compiler, ['default'])
573
574 def test_specs(self):
575 return [self.config.job_spec(['src/objective-c/tests/run_tests.sh'], None,
576 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700577
murgatroid99256d3df2015-09-21 16:58:02 -0700578 def pre_build_steps(self):
579 return []
580
Jan Tattermusch77db4322016-02-20 20:19:35 -0800581 def make_targets(self):
Jorge Canizalesd0b32e92015-07-30 23:08:43 -0700582 return ['grpc_objective_c_plugin', 'interop_server']
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700583
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800584 def make_options(self):
585 return []
586
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700587 def build_steps(self):
Jorge Canizalesd0b32e92015-07-30 23:08:43 -0700588 return [['src/objective-c/tests/build_tests.sh']]
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700589
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200590 def post_tests_steps(self):
591 return []
592
murgatroid99a3e244f2015-09-22 11:25:53 -0700593 def makefile_name(self):
594 return 'Makefile'
595
Jan Tattermusch77db4322016-02-20 20:19:35 -0800596 def dockerfile_dir(self):
Jan Tattermusch788ee232016-01-26 12:19:44 -0800597 return None
598
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700599 def __str__(self):
600 return 'objc'
601
602
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100603class Sanity(object):
604
Jan Tattermusch77db4322016-02-20 20:19:35 -0800605 def configure(self, config, args):
606 self.config = config
607 self.args = args
608 _check_compiler(self.args.compiler, ['default'])
609
610 def test_specs(self):
Craig Tiller94d04a52016-01-20 10:58:23 -0800611 import yaml
Jan Tattermusch788ee232016-01-26 12:19:44 -0800612 with open('tools/run_tests/sanity/sanity_tests.yaml', 'r') as f:
Jan Tattermusch77db4322016-02-20 20:19:35 -0800613 return [self.config.job_spec(cmd['script'].split(), None,
614 timeout_seconds=None, environ={'TEST': 'true'},
615 cpu_cost=cmd.get('cpu_cost', 1))
Craig Tiller94d04a52016-01-20 10:58:23 -0800616 for cmd in yaml.load(f)]
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100617
murgatroid99256d3df2015-09-21 16:58:02 -0700618 def pre_build_steps(self):
619 return []
620
Jan Tattermusch77db4322016-02-20 20:19:35 -0800621 def make_targets(self):
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100622 return ['run_dep_checks']
623
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800624 def make_options(self):
625 return []
626
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100627 def build_steps(self):
628 return []
629
Nicolas "Pixel" Noble87879b32015-10-12 23:28:53 +0200630 def post_tests_steps(self):
631 return []
632
murgatroid99a3e244f2015-09-22 11:25:53 -0700633 def makefile_name(self):
634 return 'Makefile'
635
Jan Tattermusch77db4322016-02-20 20:19:35 -0800636 def dockerfile_dir(self):
Jan Tattermusche70b3c52016-02-07 20:21:02 -0800637 return 'tools/dockerfile/test/sanity'
Jan Tattermusch788ee232016-01-26 12:19:44 -0800638
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100639 def __str__(self):
640 return 'sanity'
641
Nicolas "Pixel" Noblee55cd7f2015-04-14 17:59:13 +0200642
Craig Tiller738c3342015-01-12 14:28:33 -0800643# different configurations we can run under
Craig Tillera0f85172016-01-20 15:56:06 -0800644with open('tools/run_tests/configs.json') as f:
Craig Tiller1dce9062016-01-20 17:01:56 -0800645 _CONFIGS = dict((cfg['config'], Config(**cfg)) for cfg in ast.literal_eval(f.read()))
Craig Tiller738c3342015-01-12 14:28:33 -0800646
647
Craig Tillerc7449162015-01-16 14:42:10 -0800648_LANGUAGES = {
Craig Tillere9c959d2015-01-18 10:23:26 -0800649 'c++': CLanguage('cxx', 'c++'),
650 'c': CLanguage('c', 'c'),
murgatroid992c8d5162015-01-26 10:41:21 -0800651 'node': NodeLanguage(),
Nathaniel Manista840615e2015-01-22 20:31:47 +0000652 'php': PhpLanguage(),
653 'python': PythonLanguage(),
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800654 'ruby': RubyLanguage(),
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100655 'csharp': CSharpLanguage(),
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700656 'objc' : ObjCLanguage(),
Jan Tattermusch70a57e42016-02-20 18:50:27 -0800657 'sanity': Sanity()
Craig Tillereb272bc2015-01-30 13:13:14 -0800658 }
Nicolas Nobleddef2462015-01-06 18:08:25 -0800659
Jan Tattermusch77db4322016-02-20 20:19:35 -0800660
Jan Tattermuscha2d964c2016-02-22 17:33:09 -0800661_MSBUILD_CONFIG = {
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700662 'dbg': 'Debug',
663 'opt': 'Release',
Jan Tattermusche4a69182015-12-15 09:53:01 -0800664 'gcov': 'Debug',
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700665 }
666
David Garcia Quintase90cd372015-05-31 18:15:26 -0700667
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800668def _windows_arch_option(arch):
669 """Returns msbuild cmdline option for selected architecture."""
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800670 if arch == 'default' or arch == 'x86':
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800671 return '/p:Platform=Win32'
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800672 elif arch == 'x64':
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800673 return '/p:Platform=x64'
674 else:
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800675 print 'Architecture %s not supported.' % arch
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800676 sys.exit(1)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800677
Jan Tattermuschf08018a2016-01-26 08:22:09 -0800678
679def _check_arch_option(arch):
680 """Checks that architecture option is valid."""
681 if platform_string() == 'windows':
682 _windows_arch_option(arch)
683 elif platform_string() == 'linux':
684 # On linux, we need to be running under docker with the right architecture.
Jan Tattermusch07fb0422016-01-26 10:46:56 -0800685 runtime_arch = platform.architecture()[0]
Jan Tattermuschf08018a2016-01-26 08:22:09 -0800686 if arch == 'default':
687 return
688 elif runtime_arch == '64bit' and arch == 'x64':
689 return
690 elif runtime_arch == '32bit' and arch == 'x86':
691 return
692 else:
693 print 'Architecture %s does not match current runtime architecture.' % arch
694 sys.exit(1)
695 else:
696 if args.arch != 'default':
697 print 'Architecture %s not supported on current platform.' % args.arch
698 sys.exit(1)
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800699
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800700
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800701def _windows_build_bat(compiler):
702 """Returns name of build.bat for selected compiler."""
703 if compiler == 'default' or compiler == 'vs2013':
704 return 'vsprojects\\build_vs2013.bat'
705 elif compiler == 'vs2015':
706 return 'vsprojects\\build_vs2015.bat'
707 elif compiler == 'vs2010':
708 return 'vsprojects\\build_vs2010.bat'
709 else:
710 print 'Compiler %s not supported.' % compiler
711 sys.exit(1)
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800712
713
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800714def _windows_toolset_option(compiler):
715 """Returns msbuild PlatformToolset for selected compiler."""
716 if compiler == 'default' or compiler == 'vs2013':
717 return '/p:PlatformToolset=v120'
718 elif compiler == 'vs2015':
719 return '/p:PlatformToolset=v140'
720 elif compiler == 'vs2010':
721 return '/p:PlatformToolset=v100'
722 else:
723 print 'Compiler %s not supported.' % compiler
724 sys.exit(1)
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800725
726
Jan Tattermusche70b3c52016-02-07 20:21:02 -0800727def _docker_arch_suffix(arch):
728 """Returns suffix to dockerfile dir to use."""
729 if arch == 'default' or arch == 'x64':
730 return 'x64'
731 elif arch == 'x86':
732 return 'x86'
733 else:
734 print 'Architecture %s not supported with current settings.' % arch
735 sys.exit(1)
736
737
David Garcia Quintase90cd372015-05-31 18:15:26 -0700738def runs_per_test_type(arg_str):
739 """Auxilary function to parse the "runs_per_test" flag.
740
741 Returns:
742 A positive integer or 0, the latter indicating an infinite number of
743 runs.
744
745 Raises:
746 argparse.ArgumentTypeError: Upon invalid input.
747 """
748 if arg_str == 'inf':
749 return 0
750 try:
751 n = int(arg_str)
752 if n <= 0: raise ValueError
Craig Tiller50e53e22015-06-01 20:18:21 -0700753 return n
David Garcia Quintase90cd372015-05-31 18:15:26 -0700754 except:
Adele Zhoue4c35612015-10-16 15:34:23 -0700755 msg = '\'{}\' is not a positive integer or \'inf\''.format(arg_str)
David Garcia Quintase90cd372015-05-31 18:15:26 -0700756 raise argparse.ArgumentTypeError(msg)
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700757
758# parse command line
759argp = argparse.ArgumentParser(description='Run grpc tests.')
760argp.add_argument('-c', '--config',
Jan Tattermusch77db4322016-02-20 20:19:35 -0800761 choices=sorted(_CONFIGS.keys()),
762 default='opt')
David Garcia Quintase90cd372015-05-31 18:15:26 -0700763argp.add_argument('-n', '--runs_per_test', default=1, type=runs_per_test_type,
764 help='A positive integer or "inf". If "inf", all tests will run in an '
765 'infinite loop. Especially useful in combination with "-f"')
Craig Tillerfe406ec2015-02-24 13:55:12 -0800766argp.add_argument('-r', '--regex', default='.*', type=str)
Craig Tiller5f735a62016-01-20 09:31:15 -0800767argp.add_argument('-j', '--jobs', default=multiprocessing.cpu_count(), type=int)
Craig Tiller8451e872015-02-27 09:25:51 -0800768argp.add_argument('-s', '--slowdown', default=1.0, type=float)
ctiller3040cb72015-01-07 12:13:17 -0800769argp.add_argument('-f', '--forever',
770 default=False,
771 action='store_const',
772 const=True)
Nicolas "Pixel" Noblea7df3f92015-02-26 22:07:04 +0100773argp.add_argument('-t', '--travis',
774 default=False,
775 action='store_const',
776 const=True)
Nicolas Noble044db742015-01-14 16:57:24 -0800777argp.add_argument('--newline_on_success',
778 default=False,
779 action='store_const',
780 const=True)
Craig Tiller686fb262015-01-15 07:39:09 -0800781argp.add_argument('-l', '--language',
Craig Tiller60f15e62015-05-13 09:05:17 -0700782 choices=['all'] + sorted(_LANGUAGES.keys()),
Craig Tiller686fb262015-01-15 07:39:09 -0800783 nargs='+',
Craig Tiller60f15e62015-05-13 09:05:17 -0700784 default=['all'])
Craig Tillercd43da82015-05-29 08:41:29 -0700785argp.add_argument('-S', '--stop_on_failure',
786 default=False,
787 action='store_const',
788 const=True)
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700789argp.add_argument('--use_docker',
790 default=False,
791 action='store_const',
792 const=True,
Adele Zhoue4c35612015-10-16 15:34:23 -0700793 help='Run all the tests under docker. That provides ' +
794 'additional isolation and prevents the need to install ' +
795 'language specific prerequisites. Only available on Linux.')
Craig Tillerd4509a12015-09-28 09:18:40 -0700796argp.add_argument('--allow_flakes',
797 default=False,
798 action='store_const',
799 const=True,
Adele Zhoue4c35612015-10-16 15:34:23 -0700800 help='Allow flaky tests to show as passing (re-runs failed tests up to five times)')
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800801argp.add_argument('--arch',
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800802 choices=['default', 'x86', 'x64'],
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800803 default='default',
804 help='Selects architecture to target. For some platforms "default" is the only supported choice.')
805argp.add_argument('--compiler',
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800806 choices=['default',
807 'gcc4.4', 'gcc4.9', 'gcc5.3',
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800808 'clang3.4', 'clang3.6',
Jan Tattermusch825471c2016-04-25 16:52:25 -0700809 'vs2010', 'vs2013', 'vs2015',
murgatroid999fab4382016-04-29 15:05:00 -0700810 'python2.7', 'python3.4',
811 'node0.12', 'node4', 'node5'],
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800812 default='default',
Jan Tattermusch77db4322016-02-20 20:19:35 -0800813 help='Selects compiler to use. Allowed values depend on the platform and language.')
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800814argp.add_argument('--build_only',
815 default=False,
816 action='store_const',
817 const=True,
818 help='Perform all the build steps but dont run any tests.')
Craig Tiller5f735a62016-01-20 09:31:15 -0800819argp.add_argument('--measure_cpu_costs', default=False, action='store_const', const=True,
820 help='Measure the cpu costs of tests')
Craig Tiller1676f912016-01-05 10:49:44 -0800821argp.add_argument('--update_submodules', default=[], nargs='*',
822 help='Update some submodules before building. If any are updated, also run generate_projects. ' +
823 'Submodules are specified as SUBMODULE_NAME:BRANCH; if BRANCH is omitted, master is assumed.')
Craig Tiller234b6e72015-05-23 10:12:40 -0700824argp.add_argument('-a', '--antagonists', default=0, type=int)
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +0200825argp.add_argument('-x', '--xml_report', default=None, type=str,
826 help='Generates a JUnit-compatible XML report')
Nicolas Nobleddef2462015-01-06 18:08:25 -0800827args = argp.parse_args()
828
Craig Tiller5f735a62016-01-20 09:31:15 -0800829jobset.measure_cpu_costs = args.measure_cpu_costs
830
Craig Tiller1676f912016-01-05 10:49:44 -0800831# update submodules if necessary
Craig Tillerb361b4e2016-01-06 11:44:17 -0800832need_to_regenerate_projects = False
833for spec in args.update_submodules:
834 spec = spec.split(':', 1)
835 if len(spec) == 1:
836 submodule = spec[0]
837 branch = 'master'
838 elif len(spec) == 2:
839 submodule = spec[0]
840 branch = spec[1]
841 cwd = 'third_party/%s' % submodule
842 def git(cmd, cwd=cwd):
843 print 'in %s: git %s' % (cwd, cmd)
844 subprocess.check_call('git %s' % cmd, cwd=cwd, shell=True)
845 git('fetch')
846 git('checkout %s' % branch)
847 git('pull origin %s' % branch)
848 if os.path.exists('src/%s/gen_build_yaml.py' % submodule):
849 need_to_regenerate_projects = True
850if need_to_regenerate_projects:
851 if jobset.platform_string() == 'linux':
852 subprocess.check_call('tools/buildgen/generate_projects.sh', shell=True)
853 else:
854 print 'WARNING: may need to regenerate projects, but since we are not on'
855 print ' Linux this step is being skipped. Compilation MAY fail.'
Craig Tiller1676f912016-01-05 10:49:44 -0800856
857
Nicolas Nobleddef2462015-01-06 18:08:25 -0800858# grab config
Jan Tattermusch77db4322016-02-20 20:19:35 -0800859run_config = _CONFIGS[args.config]
860build_config = run_config.build_config
Craig Tillerf1973b02015-01-16 12:32:13 -0800861
Craig Tiller06805272015-06-11 14:46:47 -0700862if args.travis:
murgatroid99d3b5b7f2015-10-06 17:02:03 -0700863 _FORCE_ENVIRON_FOR_WRAPPERS = {'GRPC_TRACE': 'api'}
Craig Tiller06805272015-06-11 14:46:47 -0700864
Adele Zhou6b9527c2015-11-20 15:56:35 -0800865if 'all' in args.language:
Craig Tiller1676f912016-01-05 10:49:44 -0800866 lang_list = _LANGUAGES.keys()
Adele Zhou6b9527c2015-11-20 15:56:35 -0800867else:
868 lang_list = args.language
Craig Tiller16900662016-01-07 19:30:54 -0800869# We don't support code coverage on some languages
870if 'gcov' in args.config:
Jan Tattermusch3b5121b2016-02-22 17:41:05 -0800871 for bad in ['objc', 'sanity']:
Craig Tiller16900662016-01-07 19:30:54 -0800872 if bad in lang_list:
873 lang_list.remove(bad)
Adele Zhou6b9527c2015-11-20 15:56:35 -0800874
875languages = set(_LANGUAGES[l] for l in lang_list)
Jan Tattermusch77db4322016-02-20 20:19:35 -0800876for l in languages:
877 l.configure(run_config, args)
murgatroid99132ce6a2015-03-04 17:29:14 -0800878
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800879language_make_options=[]
880if any(language.make_options() for language in languages):
881 if len(languages) != 1:
882 print 'languages with custom make options cannot be built simultaneously with other languages'
883 sys.exit(1)
884 else:
885 language_make_options = next(iter(languages)).make_options()
886
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800887if args.use_docker:
888 if not args.travis:
889 print 'Seen --use_docker flag, will run tests under docker.'
890 print
891 print 'IMPORTANT: The changes you are testing need to be locally committed'
892 print 'because only the committed changes in the current branch will be'
893 print 'copied to the docker environment.'
894 time.sleep(5)
895
Jan Tattermusch3b5121b2016-02-22 17:41:05 -0800896 dockerfile_dirs = set([l.dockerfile_dir() for l in languages])
897 if len(dockerfile_dirs) > 1:
Adele Zhou9506ef22016-03-02 13:53:34 -0800898 if 'gcov' in args.config:
899 dockerfile_dir = 'tools/dockerfile/test/multilang_jessie_x64'
900 print ('Using multilang_jessie_x64 docker image for code coverage for '
901 'all languages.')
902 else:
903 print ('Languages to be tested require running under different docker '
904 'images.')
905 sys.exit(1)
906 else:
907 dockerfile_dir = next(iter(dockerfile_dirs))
Craig Tillerde7edf82016-03-20 09:12:16 -0700908
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800909 child_argv = [ arg for arg in sys.argv if not arg == '--use_docker' ]
Jan Tattermusched342b12016-01-26 14:40:31 -0800910 run_tests_cmd = 'python tools/run_tests/run_tests.py %s' % ' '.join(child_argv[1:])
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800911
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800912 env = os.environ.copy()
913 env['RUN_TESTS_COMMAND'] = run_tests_cmd
Jan Tattermusch3b5121b2016-02-22 17:41:05 -0800914 env['DOCKERFILE_DIR'] = dockerfile_dir
Jan Tattermusch9835d4b2016-04-29 15:05:05 -0700915 env['DOCKER_RUN_SCRIPT'] = 'tools/run_tests/dockerize/docker_run_tests.sh'
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800916 if args.xml_report:
917 env['XML_REPORT'] = args.xml_report
918 if not args.travis:
919 env['TTY_FLAG'] = '-t' # enables Ctrl-C when not on Jenkins.
920
Jan Tattermusch9835d4b2016-04-29 15:05:05 -0700921 subprocess.check_call(['tools/run_tests/dockerize/build_docker_and_run_tests.sh'],
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800922 shell=True,
923 env=env)
924 sys.exit(0)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800925
Jan Tattermuschf08018a2016-01-26 08:22:09 -0800926_check_arch_option(args.arch)
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800927
Jan Tattermuschfba65302016-01-25 18:21:14 -0800928def make_jobspec(cfg, targets, makefile='Makefile'):
929 if platform_string() == 'windows':
Craig Tillerfc3c0c42015-09-01 16:47:54 -0700930 extra_args = []
Craig Tillerb5391e12015-09-03 14:35:18 -0700931 # better do parallel compilation
Jan Tattermusch47eeb2b2015-10-07 14:09:18 -0700932 # empirically /m:2 gives the best performance/price and should prevent
933 # overloading the windows workers.
Adele Zhoue4c35612015-10-16 15:34:23 -0700934 extra_args.extend(['/m:2'])
Craig Tillerb5391e12015-09-03 14:35:18 -0700935 # disable PDB generation: it's broken, and we don't need it during CI
Adele Zhoue4c35612015-10-16 15:34:23 -0700936 extra_args.extend(['/p:Jenkins=true'])
Craig Tiller6fd23842015-09-01 07:36:31 -0700937 return [
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800938 jobset.JobSpec([_windows_build_bat(args.compiler),
murgatroid99cf08daf2015-09-21 15:33:16 -0700939 'vsprojects\\%s.sln' % target,
Jan Tattermuscha2d964c2016-02-22 17:33:09 -0800940 '/p:Configuration=%s' % _MSBUILD_CONFIG[cfg]] +
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800941 extra_args +
942 language_make_options,
Craig Tiller590105a2016-01-19 13:03:46 -0800943 shell=True, timeout_seconds=None)
Craig Tiller6fd23842015-09-01 07:36:31 -0700944 for target in targets]
Jan Tattermuschfba65302016-01-25 18:21:14 -0800945 else:
murgatroid998ae409f2015-10-26 16:39:00 -0700946 if targets:
947 return [jobset.JobSpec([os.getenv('MAKE', 'make'),
948 '-f', makefile,
Craig Tillerdd6f7ed2016-01-21 12:54:42 -0800949 '-j', '%d' % args.jobs,
Craig Tiller71a86042016-01-15 14:59:58 -0800950 'EXTRA_DEFINES=GRPC_TEST_SLOWDOWN_MACHINE_FACTOR=%f' % args.slowdown,
951 'CONFIG=%s' % cfg] +
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800952 language_make_options +
Craig Tiller71a86042016-01-15 14:59:58 -0800953 ([] if not args.travis else ['JENKINS_BUILD=1']) +
954 targets,
Craig Tiller590105a2016-01-19 13:03:46 -0800955 timeout_seconds=None)]
murgatroid998ae409f2015-10-26 16:39:00 -0700956 else:
957 return []
Jan Tattermuschfba65302016-01-25 18:21:14 -0800958
murgatroid99a3e244f2015-09-22 11:25:53 -0700959make_targets = {}
960for l in languages:
961 makefile = l.makefile_name()
962 make_targets[makefile] = make_targets.get(makefile, set()).union(
Jan Tattermusch77db4322016-02-20 20:19:35 -0800963 set(l.make_targets()))
Craig Tiller5058c692015-04-08 09:42:04 -0700964
Jan Tattermusche4a69182015-12-15 09:53:01 -0800965def build_step_environ(cfg):
966 environ = {'CONFIG': cfg}
Jan Tattermuscha2d964c2016-02-22 17:33:09 -0800967 msbuild_cfg = _MSBUILD_CONFIG.get(cfg)
Jan Tattermusche4a69182015-12-15 09:53:01 -0800968 if msbuild_cfg:
969 environ['MSBUILD_CONFIG'] = msbuild_cfg
970 return environ
971
murgatroid99fddac962015-09-22 09:20:11 -0700972build_steps = list(set(
Jan Tattermusch77db4322016-02-20 20:19:35 -0800973 jobset.JobSpec(cmdline, environ=build_step_environ(build_config), flake_retries=5)
murgatroid99256d3df2015-09-21 16:58:02 -0700974 for l in languages
975 for cmdline in l.pre_build_steps()))
Craig Tillerbd4e3782015-09-01 06:48:55 -0700976if make_targets:
Jan Tattermusch77db4322016-02-20 20:19:35 -0800977 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 -0700978 build_steps.extend(set(make_commands))
Craig Tiller5058c692015-04-08 09:42:04 -0700979build_steps.extend(set(
Jan Tattermusch77db4322016-02-20 20:19:35 -0800980 jobset.JobSpec(cmdline, environ=build_step_environ(build_config), timeout_seconds=None)
Craig Tiller547db2b2015-01-30 14:08:39 -0800981 for l in languages
Craig Tiller533b1a22015-05-29 08:41:29 -0700982 for cmdline in l.build_steps()))
Craig Tillerf1973b02015-01-16 12:32:13 -0800983
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200984post_tests_steps = list(set(
Jan Tattermusch77db4322016-02-20 20:19:35 -0800985 jobset.JobSpec(cmdline, environ=build_step_environ(build_config))
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200986 for l in languages
987 for cmdline in l.post_tests_steps()))
Nicolas Nobleddef2462015-01-06 18:08:25 -0800988runs_per_test = args.runs_per_test
ctiller3040cb72015-01-07 12:13:17 -0800989forever = args.forever
Nicolas Nobleddef2462015-01-06 18:08:25 -0800990
Nicolas Nobleddef2462015-01-06 18:08:25 -0800991
Craig Tiller71735182015-01-15 17:07:13 -0800992class TestCache(object):
Craig Tillerb50d1662015-01-15 17:28:21 -0800993 """Cache for running tests."""
994
David Klempner25739582015-02-11 15:57:32 -0800995 def __init__(self, use_cache_results):
Craig Tiller71735182015-01-15 17:07:13 -0800996 self._last_successful_run = {}
David Klempner25739582015-02-11 15:57:32 -0800997 self._use_cache_results = use_cache_results
Craig Tiller69cd2372015-06-11 09:38:09 -0700998 self._last_save = time.time()
Craig Tiller71735182015-01-15 17:07:13 -0800999
1000 def should_run(self, cmdline, bin_hash):
Craig Tiller71735182015-01-15 17:07:13 -08001001 if cmdline not in self._last_successful_run:
1002 return True
1003 if self._last_successful_run[cmdline] != bin_hash:
1004 return True
David Klempner25739582015-02-11 15:57:32 -08001005 if not self._use_cache_results:
1006 return True
Craig Tiller71735182015-01-15 17:07:13 -08001007 return False
1008
1009 def finished(self, cmdline, bin_hash):
Craig Tiller547db2b2015-01-30 14:08:39 -08001010 self._last_successful_run[cmdline] = bin_hash
Craig Tiller69cd2372015-06-11 09:38:09 -07001011 if time.time() - self._last_save > 1:
1012 self.save()
Craig Tiller71735182015-01-15 17:07:13 -08001013
1014 def dump(self):
Craig Tillerb50d1662015-01-15 17:28:21 -08001015 return [{'cmdline': k, 'hash': v}
1016 for k, v in self._last_successful_run.iteritems()]
Craig Tiller71735182015-01-15 17:07:13 -08001017
1018 def parse(self, exdump):
1019 self._last_successful_run = dict((o['cmdline'], o['hash']) for o in exdump)
1020
1021 def save(self):
1022 with open('.run_tests_cache', 'w') as f:
Craig Tiller261dd982015-01-16 16:41:45 -08001023 f.write(json.dumps(self.dump()))
Craig Tiller69cd2372015-06-11 09:38:09 -07001024 self._last_save = time.time()
Craig Tiller71735182015-01-15 17:07:13 -08001025
Craig Tiller1cc11db2015-01-15 22:50:50 -08001026 def maybe_load(self):
1027 if os.path.exists('.run_tests_cache'):
1028 with open('.run_tests_cache') as f:
Craig Tiller261dd982015-01-16 16:41:45 -08001029 self.parse(json.loads(f.read()))
Craig Tiller71735182015-01-15 17:07:13 -08001030
1031
Craig Tillerf53d9c82015-08-04 14:19:43 -07001032def _start_port_server(port_server_port):
1033 # check if a compatible port server is running
1034 # if incompatible (version mismatch) ==> start a new one
1035 # if not running ==> start a new one
1036 # otherwise, leave it up
1037 try:
Craig Tillerfe4939f2015-10-06 12:55:36 -07001038 version = int(urllib2.urlopen(
1039 'http://localhost:%d/version_number' % port_server_port,
1040 timeout=1).read())
1041 print 'detected port server running version %d' % version
Craig Tillerf53d9c82015-08-04 14:19:43 -07001042 running = True
Craig Tillerfe4939f2015-10-06 12:55:36 -07001043 except Exception as e:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001044 print 'failed to detect port server: %s' % sys.exc_info()[0]
Craig Tillerfe4939f2015-10-06 12:55:36 -07001045 print e.strerror
Craig Tillerf53d9c82015-08-04 14:19:43 -07001046 running = False
1047 if running:
Craig Tillerfe4939f2015-10-06 12:55:36 -07001048 current_version = int(subprocess.check_output(
Jan Tattermusch3bd08272015-11-04 19:24:37 -08001049 [sys.executable, os.path.abspath('tools/run_tests/port_server.py'),
1050 'dump_version']))
Craig Tillerfe4939f2015-10-06 12:55:36 -07001051 print 'my port server is version %d' % current_version
1052 running = (version >= current_version)
1053 if not running:
1054 print 'port_server version mismatch: killing the old one'
1055 urllib2.urlopen('http://localhost:%d/quitquitquit' % port_server_port).read()
1056 time.sleep(1)
Craig Tillerf53d9c82015-08-04 14:19:43 -07001057 if not running:
Craig Tillerf0a293e2015-10-12 10:05:50 -07001058 fd, logfile = tempfile.mkstemp()
1059 os.close(fd)
1060 print 'starting port_server, with log file %s' % logfile
Jan Tattermusch3bd08272015-11-04 19:24:37 -08001061 args = [sys.executable, os.path.abspath('tools/run_tests/port_server.py'),
1062 '-p', '%d' % port_server_port, '-l', logfile]
Craig Tiller367d41d2015-10-12 13:00:22 -07001063 env = dict(os.environ)
1064 env['BUILD_ID'] = 'pleaseDontKillMeJenkins'
Nicolas "Pixel" Noblef72d7b52015-12-03 03:07:43 +01001065 if platform_string() == 'windows':
Jan Tattermusch3bd08272015-11-04 19:24:37 -08001066 # Working directory of port server needs to be outside of Jenkins
1067 # workspace to prevent file lock issues.
1068 tempdir = tempfile.mkdtemp()
Craig Tillerd2c39712015-10-12 11:08:49 -07001069 port_server = subprocess.Popen(
Craig Tiller367d41d2015-10-12 13:00:22 -07001070 args,
1071 env=env,
Jan Tattermusch3bd08272015-11-04 19:24:37 -08001072 cwd=tempdir,
Craig Tiller367d41d2015-10-12 13:00:22 -07001073 creationflags = 0x00000008, # detached process
1074 close_fds=True)
Craig Tillerd2c39712015-10-12 11:08:49 -07001075 else:
1076 port_server = subprocess.Popen(
1077 args,
Craig Tiller367d41d2015-10-12 13:00:22 -07001078 env=env,
Craig Tillerd2c39712015-10-12 11:08:49 -07001079 preexec_fn=os.setsid,
1080 close_fds=True)
Craig Tillerf0a293e2015-10-12 10:05:50 -07001081 time.sleep(1)
Craig Tiller8b5f4dc2015-08-26 08:02:01 -07001082 # ensure port server is up
Craig Tillerabd37fd2015-08-26 07:54:01 -07001083 waits = 0
Craig Tillerf53d9c82015-08-04 14:19:43 -07001084 while True:
Craig Tillerabd37fd2015-08-26 07:54:01 -07001085 if waits > 10:
Craig Tillerf0a293e2015-10-12 10:05:50 -07001086 print 'killing port server due to excessive start up waits'
Craig Tillerabd37fd2015-08-26 07:54:01 -07001087 port_server.kill()
Craig Tillera2f38b02015-09-24 11:19:17 -07001088 if port_server.poll() is not None:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001089 print 'port_server failed to start'
Craig Tillerf0a293e2015-10-12 10:05:50 -07001090 # try one final time: maybe another build managed to start one
1091 time.sleep(1)
1092 try:
1093 urllib2.urlopen('http://localhost:%d/get' % port_server_port,
1094 timeout=1).read()
1095 print 'last ditch attempt to contact port server succeeded'
1096 break
1097 except:
Jan Tattermusch3b5121b2016-02-22 17:41:05 -08001098 traceback.print_exc()
Craig Tillerf0a293e2015-10-12 10:05:50 -07001099 port_log = open(logfile, 'r').read()
1100 print port_log
1101 sys.exit(1)
Craig Tillerf53d9c82015-08-04 14:19:43 -07001102 try:
Craig Tillerabd37fd2015-08-26 07:54:01 -07001103 urllib2.urlopen('http://localhost:%d/get' % port_server_port,
1104 timeout=1).read()
Craig Tillerf0a293e2015-10-12 10:05:50 -07001105 print 'port server is up and ready'
Craig Tillerf53d9c82015-08-04 14:19:43 -07001106 break
Craig Tiller31fdaa42015-09-25 13:09:59 -07001107 except socket.timeout:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001108 print 'waiting for port_server: timeout'
Craig Tillerf0a293e2015-10-12 10:05:50 -07001109 traceback.print_exc();
1110 time.sleep(1)
Craig Tiller31fdaa42015-09-25 13:09:59 -07001111 waits += 1
Craig Tillerf53d9c82015-08-04 14:19:43 -07001112 except urllib2.URLError:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001113 print 'waiting for port_server: urlerror'
Craig Tillerf0a293e2015-10-12 10:05:50 -07001114 traceback.print_exc();
1115 time.sleep(1)
Craig Tillerabd37fd2015-08-26 07:54:01 -07001116 waits += 1
Craig Tillerf53d9c82015-08-04 14:19:43 -07001117 except:
Jan Tattermusch3b5121b2016-02-22 17:41:05 -08001118 traceback.print_exc()
Craig Tillerf53d9c82015-08-04 14:19:43 -07001119 port_server.kill()
1120 raise
1121
1122
Adele Zhoud5fffa52015-10-23 15:51:42 -07001123def _calculate_num_runs_failures(list_of_results):
1124 """Caculate number of runs and failures for a particular test.
1125
1126 Args:
1127 list_of_results: (List) of JobResult object.
1128 Returns:
1129 A tuple of total number of runs and failures.
1130 """
1131 num_runs = len(list_of_results) # By default, there is 1 run per JobResult.
1132 num_failures = 0
1133 for jobresult in list_of_results:
1134 if jobresult.retries > 0:
1135 num_runs += jobresult.retries
1136 if jobresult.num_failures > 0:
1137 num_failures += jobresult.num_failures
1138 return num_runs, num_failures
1139
Adele Zhou6b9527c2015-11-20 15:56:35 -08001140
Craig Tillereb9de8b2016-01-08 08:57:41 -08001141# _build_and_run results
1142class BuildAndRunError(object):
1143
1144 BUILD = object()
1145 TEST = object()
1146 POST_TEST = object()
1147
1148
1149# returns a list of things that failed (or an empty list on success)
Craig Tillerf53d9c82015-08-04 14:19:43 -07001150def _build_and_run(
Jan Tattermusch2dd156e2015-12-04 18:26:17 -08001151 check_cancelled, newline_on_success, cache, xml_report=None, build_only=False):
ctiller3040cb72015-01-07 12:13:17 -08001152 """Do one pass of building & running tests."""
murgatroid99666450e2015-01-26 13:03:31 -08001153 # build latest sequentially
Jan Tattermuschaab1e512016-01-28 09:30:44 -08001154 num_failures, resultset = jobset.run(
Adele Zhoue4c35612015-10-16 15:34:23 -07001155 build_steps, maxjobs=1, stop_on_failure=True,
Craig Tiller883064c2015-11-04 10:06:10 -08001156 newline_on_success=newline_on_success, travis=args.travis)
Adele Zhoue4c35612015-10-16 15:34:23 -07001157 if num_failures:
Craig Tillereb9de8b2016-01-08 08:57:41 -08001158 return [BuildAndRunError.BUILD]
Craig Tillerb361b4e2016-01-06 11:44:17 -08001159
Jan Tattermusch2dd156e2015-12-04 18:26:17 -08001160 if build_only:
Jan Tattermuschaab1e512016-01-28 09:30:44 -08001161 if xml_report:
1162 report_utils.render_junit_xml_report(resultset, xml_report)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001163 return []
ctiller3040cb72015-01-07 12:13:17 -08001164
Craig Tiller234b6e72015-05-23 10:12:40 -07001165 # start antagonists
David Garcia Quintas79e389f2015-06-02 17:49:42 -07001166 antagonists = [subprocess.Popen(['tools/run_tests/antagonist.py'])
Craig Tiller234b6e72015-05-23 10:12:40 -07001167 for _ in range(0, args.antagonists)]
Craig Tillerfe4939f2015-10-06 12:55:36 -07001168 port_server_port = 32767
Craig Tillerf53d9c82015-08-04 14:19:43 -07001169 _start_port_server(port_server_port)
Adele Zhou7cf72112015-11-04 11:18:43 -08001170 resultset = None
Adele Zhou803af152015-11-30 15:16:16 -08001171 num_test_failures = 0
Craig Tiller234b6e72015-05-23 10:12:40 -07001172 try:
David Garcia Quintase90cd372015-05-31 18:15:26 -07001173 infinite_runs = runs_per_test == 0
yang-g6c1fdc62015-08-18 11:57:42 -07001174 one_run = set(
1175 spec
yang-g6c1fdc62015-08-18 11:57:42 -07001176 for language in languages
Jan Tattermusch77db4322016-02-20 20:19:35 -08001177 for spec in language.test_specs()
yang-g6c1fdc62015-08-18 11:57:42 -07001178 if re.search(args.regex, spec.shortname))
David Garcia Quintas79e389f2015-06-02 17:49:42 -07001179 # When running on travis, we want out test runs to be as similar as possible
1180 # for reproducibility purposes.
Craig Tiller883064c2015-11-04 10:06:10 -08001181 if args.travis:
David Garcia Quintas79e389f2015-06-02 17:49:42 -07001182 massaged_one_run = sorted(one_run, key=lambda x: x.shortname)
1183 else:
1184 # whereas otherwise, we want to shuffle things up to give all tests a
1185 # chance to run.
1186 massaged_one_run = list(one_run) # random.shuffle needs an indexable seq.
1187 random.shuffle(massaged_one_run) # which it modifies in-place.
Craig Tillerf7b7c892015-06-22 14:33:25 -07001188 if infinite_runs:
1189 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 -07001190 runs_sequence = (itertools.repeat(massaged_one_run) if infinite_runs
1191 else itertools.repeat(massaged_one_run, runs_per_test))
David Garcia Quintase90cd372015-05-31 18:15:26 -07001192 all_runs = itertools.chain.from_iterable(runs_sequence)
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +02001193
Adele Zhou803af152015-11-30 15:16:16 -08001194 num_test_failures, resultset = jobset.run(
Adele Zhou2271ab52015-10-28 13:59:14 -07001195 all_runs, check_cancelled, newline_on_success=newline_on_success,
Craig Tiller883064c2015-11-04 10:06:10 -08001196 travis=args.travis, infinite_runs=infinite_runs, maxjobs=args.jobs,
murgatroid998ae409f2015-10-26 16:39:00 -07001197 stop_on_failure=args.stop_on_failure,
Adele Zhouf2ca7bc2015-10-23 15:38:00 -07001198 cache=cache if not xml_report else None,
Adele Zhouf2ca7bc2015-10-23 15:38:00 -07001199 add_env={'GRPC_TEST_PORT_SERVER': 'localhost:%d' % port_server_port})
Adele Zhoud5fffa52015-10-23 15:51:42 -07001200 if resultset:
Craig Tiller2b59dbc2016-05-13 15:59:09 -07001201 for k, v in sorted(resultset.items()):
Adele Zhoud5fffa52015-10-23 15:51:42 -07001202 num_runs, num_failures = _calculate_num_runs_failures(v)
1203 if num_failures == num_runs: # what about infinite_runs???
1204 jobset.message('FAILED', k, do_newline=True)
1205 elif num_failures > 0:
1206 jobset.message(
1207 'FLAKE', '%s [%d/%d runs flaked]' % (k, num_failures, num_runs),
1208 do_newline=True)
1209 else:
1210 jobset.message('PASSED', k, do_newline=True)
Craig Tiller234b6e72015-05-23 10:12:40 -07001211 finally:
1212 for antagonist in antagonists:
1213 antagonist.kill()
Adele Zhou7cf72112015-11-04 11:18:43 -08001214 if xml_report and resultset:
Adele Zhou3bc7ba42015-11-05 10:21:58 -08001215 report_utils.render_junit_xml_report(resultset, xml_report)
Craig Tillerd86a3942015-01-14 12:48:54 -08001216
Adele Zhouf2ca7bc2015-10-23 15:38:00 -07001217 number_failures, _ = jobset.run(
1218 post_tests_steps, maxjobs=1, stop_on_failure=True,
Craig Tiller883064c2015-11-04 10:06:10 -08001219 newline_on_success=newline_on_success, travis=args.travis)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001220
1221 out = []
1222 if number_failures:
1223 out.append(BuildAndRunError.POST_TEST)
1224 if num_test_failures:
1225 out.append(BuildAndRunError.TEST)
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +02001226
Craig Tiller69cd2372015-06-11 09:38:09 -07001227 if cache: cache.save()
1228
Craig Tillereb9de8b2016-01-08 08:57:41 -08001229 return out
ctiller3040cb72015-01-07 12:13:17 -08001230
1231
David Klempner25739582015-02-11 15:57:32 -08001232test_cache = TestCache(runs_per_test == 1)
Craig Tiller547db2b2015-01-30 14:08:39 -08001233test_cache.maybe_load()
Craig Tiller71735182015-01-15 17:07:13 -08001234
ctiller3040cb72015-01-07 12:13:17 -08001235if forever:
Nicolas Noble044db742015-01-14 16:57:24 -08001236 success = True
ctiller3040cb72015-01-07 12:13:17 -08001237 while True:
Craig Tiller42bc87c2015-02-23 08:50:19 -08001238 dw = watch_dirs.DirWatcher(['src', 'include', 'test', 'examples'])
ctiller3040cb72015-01-07 12:13:17 -08001239 initial_time = dw.most_recent_change()
1240 have_files_changed = lambda: dw.most_recent_change() != initial_time
Nicolas Noble044db742015-01-14 16:57:24 -08001241 previous_success = success
Craig Tillereb9de8b2016-01-08 08:57:41 -08001242 errors = _build_and_run(check_cancelled=have_files_changed,
1243 newline_on_success=False,
1244 cache=test_cache,
1245 build_only=args.build_only) == 0
1246 if not previous_success and not errors:
Nicolas Nobleb09078f2015-01-14 18:06:05 -08001247 jobset.message('SUCCESS',
1248 'All tests are now passing properly',
1249 do_newline=True)
Nicolas Noble044db742015-01-14 16:57:24 -08001250 jobset.message('IDLE', 'No change detected')
ctiller3040cb72015-01-07 12:13:17 -08001251 while not have_files_changed():
1252 time.sleep(1)
1253else:
Craig Tillereb9de8b2016-01-08 08:57:41 -08001254 errors = _build_and_run(check_cancelled=lambda: False,
Craig Tiller71735182015-01-15 17:07:13 -08001255 newline_on_success=args.newline_on_success,
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +02001256 cache=test_cache,
Jan Tattermusch2dd156e2015-12-04 18:26:17 -08001257 xml_report=args.xml_report,
1258 build_only=args.build_only)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001259 if not errors:
Nicolas Nobleb09078f2015-01-14 18:06:05 -08001260 jobset.message('SUCCESS', 'All tests passed', do_newline=True)
1261 else:
1262 jobset.message('FAILED', 'Some tests failed', do_newline=True)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001263 exit_code = 0
1264 if BuildAndRunError.BUILD in errors:
1265 exit_code |= 1
Craig Tiller4f2be362016-01-08 08:59:20 -08001266 if BuildAndRunError.TEST in errors and not args.travis:
Craig Tillereb9de8b2016-01-08 08:57:41 -08001267 exit_code |= 2
Craig Tiller4f2be362016-01-08 08:59:20 -08001268 if BuildAndRunError.POST_TEST in errors:
1269 exit_code |= 4
Craig Tillereb9de8b2016-01-08 08:57:41 -08001270 sys.exit(exit_code)