blob: bdda368674388c3549d510a4359aadc33248626c [file] [log] [blame]
Nathaniel Manistaae4fbcd2015-09-23 16:29:44 +00001#!/usr/bin/env python2.7
Craig Tiller40839772016-01-05 12:34:49 -08002# Copyright 2015-2016, 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 Tiller56c6b6a2016-01-20 08:27:37 -080083 shortname=None, environ={}, cpu_cost=1.0):
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 Tiller35505de2015-10-08 13:31:33 -0700105 flake_retries=5 if args.allow_flakes else 0,
106 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:
123 raise Exception('Compiler %s not supported.' % compiler)
124
125
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800126def _is_use_docker_child():
127 """Returns True if running running as a --use_docker child."""
128 return True if os.getenv('RUN_TESTS_COMMAND') else False
129
130
Craig Tillerc7449162015-01-16 14:42:10 -0800131class CLanguage(object):
132
Craig Tillere9c959d2015-01-18 10:23:26 -0800133 def __init__(self, make_target, test_lang):
Craig Tillerc7449162015-01-16 14:42:10 -0800134 self.make_target = make_target
Craig Tillerd50993d2015-08-05 08:04:36 -0700135 self.platform = platform_string()
Craig Tiller711bbe62015-08-19 12:35:16 -0700136 self.test_lang = test_lang
Craig Tillerc7449162015-01-16 14:42:10 -0800137
Jan Tattermusch77db4322016-02-20 20:19:35 -0800138 def configure(self, config, args):
139 self.config = config
140 self.args = args
141 if self.platform == 'windows':
Jan Tattermuschc96caf82016-02-22 17:31:02 -0800142 self._make_options = [_windows_toolset_option(self.args.compiler),
143 _windows_arch_option(self.args.arch)]
Jan Tattermusch77db4322016-02-20 20:19:35 -0800144 else:
Jan Tattermuschc96caf82016-02-22 17:31:02 -0800145 self._make_options = []
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800146 self._docker_distro = self._get_docker_distro(self.args.use_docker,
147 self.args.compiler)
Jan Tattermusch77db4322016-02-20 20:19:35 -0800148
149 def test_specs(self):
Craig Tiller547db2b2015-01-30 14:08:39 -0800150 out = []
Jan Tattermusch77db4322016-02-20 20:19:35 -0800151 binaries = get_c_tests(self.args.travis, self.test_lang)
Craig Tiller711bbe62015-08-19 12:35:16 -0700152 for target in binaries:
Jan Tattermusch77db4322016-02-20 20:19:35 -0800153 if self.config.build_config in target['exclude_configs']:
murgatroid99fafeeb32015-09-22 09:13:03 -0700154 continue
Nicolas Noblee1445362015-05-11 17:40:26 -0700155 if self.platform == 'windows':
Jan Tattermusch3de6b762016-01-28 11:38:11 -0800156 binary = 'vsprojects/%s%s/%s.exe' % (
Jan Tattermusch77db4322016-02-20 20:19:35 -0800157 'x64/' if self.args.arch == 'x64' else '',
Jan Tattermuscha2d964c2016-02-22 17:33:09 -0800158 _MSBUILD_CONFIG[self.config.build_config],
Jan Tattermusch3de6b762016-01-28 11:38:11 -0800159 target['name'])
Nicolas Noblee1445362015-05-11 17:40:26 -0700160 else:
Jan Tattermusch77db4322016-02-20 20:19:35 -0800161 binary = 'bins/%s/%s' % (self.config.build_config, target['name'])
yang-g6c1fdc62015-08-18 11:57:42 -0700162 if os.path.isfile(binary):
Craig Tillerca62ff02016-02-24 22:22:57 -0800163 if 'gtest' in target and target['gtest']:
164 with open(os.devnull, 'w') as fnull:
165 tests = subprocess.check_output([binary, '--gtest_list_tests'],
166 stderr=fnull)
167 base = None
168 for line in tests.split('\n'):
169 i = line.find('#')
170 if i >= 0: line = line[:i]
171 if not line: continue
172 if line[0] != ' ':
173 base = line
174 else:
175 assert base is not None
176 assert line[1] == ' '
177 test = base + line[2:]
178 cmdline = [binary] + ['--gtest_filter=%s' % test]
179 out.append(self.config.job_spec(cmdline, [binary],
180 shortname='%s:%s' % (binary, test),
181 cpu_cost=target['cpu_cost'],
182 environ={'GRPC_DEFAULT_SSL_ROOTS_FILE_PATH':
183 _ROOT + '/src/core/tsi/test_creds/ca.pem'}))
184 else:
185 cmdline = [binary] + target['args']
186 out.append(self.config.job_spec(cmdline, [binary],
187 shortname=' '.join(cmdline),
188 cpu_cost=target['cpu_cost'],
189 environ={'GRPC_DEFAULT_SSL_ROOTS_FILE_PATH':
190 _ROOT + '/src/core/tsi/test_creds/ca.pem'}))
Jan Tattermusch77db4322016-02-20 20:19:35 -0800191 elif self.args.regex == '.*' or self.platform == 'windows':
Adele Zhoue4c35612015-10-16 15:34:23 -0700192 print '\nWARNING: binary not found, skipping', binary
Nicolas Noblee1445362015-05-11 17:40:26 -0700193 return sorted(out)
Craig Tillerc7449162015-01-16 14:42:10 -0800194
Jan Tattermusch77db4322016-02-20 20:19:35 -0800195 def make_targets(self):
196 test_regex = self.args.regex
197 if self.platform != 'windows' and self.args.regex != '.*':
Craig Tiller883064c2015-11-04 10:06:10 -0800198 # use the regex to minimize the number of things to build
Craig Tillerb0f275e2016-01-27 10:45:50 -0800199 return [os.path.basename(target['name'])
Craig Tiller883064c2015-11-04 10:06:10 -0800200 for target in get_c_tests(False, self.test_lang)
Craig Tillerb0f275e2016-01-27 10:45:50 -0800201 if re.search(test_regex, '/' + target['name'])]
Jan Tattermusch77db4322016-02-20 20:19:35 -0800202 if self.platform == 'windows':
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700203 # don't build tools on windows just yet
204 return ['buildtests_%s' % self.make_target]
Craig Tiller7552f0f2015-06-19 17:46:20 -0700205 return ['buildtests_%s' % self.make_target, 'tools_%s' % self.make_target]
Craig Tillerc7449162015-01-16 14:42:10 -0800206
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800207 def make_options(self):
Jan Tattermuschc96caf82016-02-22 17:31:02 -0800208 return self._make_options;
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800209
murgatroid99256d3df2015-09-21 16:58:02 -0700210 def pre_build_steps(self):
Jan Tattermusch874aec02015-10-07 19:26:19 -0700211 if self.platform == 'windows':
212 return [['tools\\run_tests\\pre_build_c.bat']]
213 else:
214 return []
murgatroid99256d3df2015-09-21 16:58:02 -0700215
Craig Tillerc7449162015-01-16 14:42:10 -0800216 def build_steps(self):
217 return []
218
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200219 def post_tests_steps(self):
220 if self.platform == 'windows':
221 return []
222 else:
223 return [['tools/run_tests/post_tests_c.sh']]
224
murgatroid99a3e244f2015-09-22 11:25:53 -0700225 def makefile_name(self):
226 return 'Makefile'
227
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800228 def _get_docker_distro(self, use_docker, compiler):
229 if _is_use_docker_child():
230 return "already_under_docker"
231 if not use_docker:
232 _check_compiler(compiler, ['default'])
233
234 if compiler == 'gcc4.9' or compiler == 'default':
235 return 'jessie'
236 elif compiler == 'gcc4.4':
237 return 'squeeze'
238 elif compiler == 'gcc5.3':
239 return 'ubuntu1604'
240 else:
241 raise Exception('Compiler %s not supported.' % compiler)
242
Jan Tattermusch77db4322016-02-20 20:19:35 -0800243 def dockerfile_dir(self):
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800244 return 'tools/dockerfile/test/cxx_%s_%s' % (self._docker_distro,
245 _docker_arch_suffix(self.args.arch))
Jan Tattermusch788ee232016-01-26 12:19:44 -0800246
murgatroid99132ce6a2015-03-04 17:29:14 -0800247 def __str__(self):
248 return self.make_target
249
Craig Tillercc0535d2015-12-08 15:14:47 -0800250
murgatroid992c8d5162015-01-26 10:41:21 -0800251class NodeLanguage(object):
252
Jan Tattermusche477b842016-02-06 22:19:01 -0800253 def __init__(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800254 self.platform = platform_string()
Jan Tattermusche477b842016-02-06 22:19:01 -0800255 self.node_version = '0.12'
256
Jan Tattermusch77db4322016-02-20 20:19:35 -0800257 def configure(self, config, args):
258 self.config = config
259 self.args = args
260 _check_compiler(self.args.compiler, ['default'])
261
262 def test_specs(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800263 if self.platform == 'windows':
Jan Tattermusch77db4322016-02-20 20:19:35 -0800264 return [self.config.job_spec(['tools\\run_tests\\run_node.bat'], None)]
Michael Lumishaaa876a2016-02-10 15:27:58 -0800265 else:
Jan Tattermusch77db4322016-02-20 20:19:35 -0800266 return [self.config.job_spec(['tools/run_tests/run_node.sh', self.node_version],
267 None,
268 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
murgatroid992c8d5162015-01-26 10:41:21 -0800269
murgatroid99256d3df2015-09-21 16:58:02 -0700270 def pre_build_steps(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800271 if self.platform == 'windows':
272 return [['tools\\run_tests\\pre_build_node.bat']]
273 else:
274 return [['tools/run_tests/pre_build_node.sh', self.node_version]]
murgatroid99256d3df2015-09-21 16:58:02 -0700275
Jan Tattermusch77db4322016-02-20 20:19:35 -0800276 def make_targets(self):
murgatroid99db5b1602015-10-01 13:20:11 -0700277 return []
murgatroid992c8d5162015-01-26 10:41:21 -0800278
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800279 def make_options(self):
280 return []
281
murgatroid992c8d5162015-01-26 10:41:21 -0800282 def build_steps(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800283 if self.platform == 'windows':
284 return [['tools\\run_tests\\build_node.bat']]
285 else:
286 return [['tools/run_tests/build_node.sh', self.node_version]]
Craig Tillerc7449162015-01-16 14:42:10 -0800287
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200288 def post_tests_steps(self):
289 return []
290
murgatroid99a3e244f2015-09-22 11:25:53 -0700291 def makefile_name(self):
292 return 'Makefile'
293
Jan Tattermusch77db4322016-02-20 20:19:35 -0800294 def dockerfile_dir(self):
295 return 'tools/dockerfile/test/node_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800296
murgatroid99132ce6a2015-03-04 17:29:14 -0800297 def __str__(self):
298 return 'node'
299
Craig Tiller99775822015-01-30 13:07:16 -0800300
Craig Tillerc7449162015-01-16 14:42:10 -0800301class PhpLanguage(object):
302
Jan Tattermusch77db4322016-02-20 20:19:35 -0800303 def configure(self, config, args):
304 self.config = config
305 self.args = args
306 _check_compiler(self.args.compiler, ['default'])
307
308 def test_specs(self):
309 return [self.config.job_spec(['src/php/bin/run_tests.sh'], None,
310 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
Craig Tillerc7449162015-01-16 14:42:10 -0800311
murgatroid99256d3df2015-09-21 16:58:02 -0700312 def pre_build_steps(self):
313 return []
314
Jan Tattermusch77db4322016-02-20 20:19:35 -0800315 def make_targets(self):
Craig Tilleraf7cf542015-05-22 10:07:34 -0700316 return ['static_c', 'shared_c']
Craig Tillerc7449162015-01-16 14:42:10 -0800317
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800318 def make_options(self):
319 return []
320
Craig Tillerc7449162015-01-16 14:42:10 -0800321 def build_steps(self):
322 return [['tools/run_tests/build_php.sh']]
323
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200324 def post_tests_steps(self):
Stanley Cheunga6b95482016-01-13 16:10:48 -0800325 return [['tools/run_tests/post_tests_php.sh']]
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200326
murgatroid99a3e244f2015-09-22 11:25:53 -0700327 def makefile_name(self):
328 return 'Makefile'
329
Jan Tattermusch77db4322016-02-20 20:19:35 -0800330 def dockerfile_dir(self):
331 return 'tools/dockerfile/test/php_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800332
murgatroid99132ce6a2015-03-04 17:29:14 -0800333 def __str__(self):
334 return 'php'
335
Craig Tillerc7449162015-01-16 14:42:10 -0800336
Nathaniel Manista840615e2015-01-22 20:31:47 +0000337class PythonLanguage(object):
338
Craig Tiller49f61322015-03-03 13:02:11 -0800339 def __init__(self):
Masood Malekghassemi2b841622015-07-28 17:39:02 -0700340 self._build_python_versions = ['2.7']
Masood Malekghassemie5f70022015-06-29 09:20:26 -0700341 self._has_python_versions = []
Craig Tiller49f61322015-03-03 13:02:11 -0800342
Jan Tattermusch77db4322016-02-20 20:19:35 -0800343 def configure(self, config, args):
344 self.config = config
345 self.args = args
346 _check_compiler(self.args.compiler, ['default'])
347
348 def test_specs(self):
Masood Malekghassemi2b841622015-07-28 17:39:02 -0700349 environment = dict(_FORCE_ENVIRON_FOR_WRAPPERS)
350 environment['PYVER'] = '2.7'
Jan Tattermusch77db4322016-02-20 20:19:35 -0800351 return [self.config.job_spec(
Masood Malekghassemi2b841622015-07-28 17:39:02 -0700352 ['tools/run_tests/run_python.sh'],
353 None,
354 environ=environment,
355 shortname='py.test',
Masood Malekghassemi26ea9e22015-10-09 15:19:17 -0700356 timeout_seconds=15*60
Masood Malekghassemi2b841622015-07-28 17:39:02 -0700357 )]
Nathaniel Manista840615e2015-01-22 20:31:47 +0000358
murgatroid99256d3df2015-09-21 16:58:02 -0700359 def pre_build_steps(self):
360 return []
361
Jan Tattermusch77db4322016-02-20 20:19:35 -0800362 def make_targets(self):
Craig Tilleraf7cf542015-05-22 10:07:34 -0700363 return ['static_c', 'grpc_python_plugin', 'shared_c']
Nathaniel Manista840615e2015-01-22 20:31:47 +0000364
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800365 def make_options(self):
366 return []
367
Nathaniel Manista840615e2015-01-22 20:31:47 +0000368 def build_steps(self):
Masood Malekghassemie5f70022015-06-29 09:20:26 -0700369 commands = []
370 for python_version in self._build_python_versions:
371 try:
372 with open(os.devnull, 'w') as output:
373 subprocess.check_call(['which', 'python' + python_version],
374 stdout=output, stderr=output)
375 commands.append(['tools/run_tests/build_python.sh', python_version])
376 self._has_python_versions.append(python_version)
377 except:
378 jobset.message('WARNING', 'Missing Python ' + python_version,
379 do_newline=True)
380 return commands
Nathaniel Manista840615e2015-01-22 20:31:47 +0000381
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200382 def post_tests_steps(self):
383 return []
384
murgatroid99a3e244f2015-09-22 11:25:53 -0700385 def makefile_name(self):
386 return 'Makefile'
387
Jan Tattermusch77db4322016-02-20 20:19:35 -0800388 def dockerfile_dir(self):
389 return 'tools/dockerfile/test/python_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800390
murgatroid99132ce6a2015-03-04 17:29:14 -0800391 def __str__(self):
392 return 'python'
393
Craig Tillerd625d812015-04-08 15:52:35 -0700394
murgatroid996a4c4fa2015-02-27 12:08:57 -0800395class RubyLanguage(object):
396
Jan Tattermusch77db4322016-02-20 20:19:35 -0800397 def configure(self, config, args):
398 self.config = config
399 self.args = args
400 _check_compiler(self.args.compiler, ['default'])
401
402 def test_specs(self):
403 return [self.config.job_spec(['tools/run_tests/run_ruby.sh'], None,
404 timeout_seconds=10*60,
405 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
murgatroid996a4c4fa2015-02-27 12:08:57 -0800406
murgatroid99256d3df2015-09-21 16:58:02 -0700407 def pre_build_steps(self):
Nicolas "Pixel" Noblebcf988f2015-10-08 03:00:42 +0200408 return [['tools/run_tests/pre_build_ruby.sh']]
murgatroid99256d3df2015-09-21 16:58:02 -0700409
Jan Tattermusch4651bef2016-02-23 08:31:25 -0800410 def make_targets(self):
murgatroid997d243df2016-02-18 09:58:05 -0800411 return []
murgatroid996a4c4fa2015-02-27 12:08:57 -0800412
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800413 def make_options(self):
414 return []
415
murgatroid996a4c4fa2015-02-27 12:08:57 -0800416 def build_steps(self):
417 return [['tools/run_tests/build_ruby.sh']]
418
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200419 def post_tests_steps(self):
Nicolas "Pixel" Noble7ef1e532015-12-02 00:55:33 +0100420 return [['tools/run_tests/post_tests_ruby.sh']]
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200421
murgatroid99a3e244f2015-09-22 11:25:53 -0700422 def makefile_name(self):
423 return 'Makefile'
424
Jan Tattermusch77db4322016-02-20 20:19:35 -0800425 def dockerfile_dir(self):
426 return 'tools/dockerfile/test/ruby_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800427
murgatroid99132ce6a2015-03-04 17:29:14 -0800428 def __str__(self):
429 return 'ruby'
430
Craig Tillerd625d812015-04-08 15:52:35 -0700431
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800432class CSharpLanguage(object):
Jan Tattermusch77db4322016-02-20 20:19:35 -0800433
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700434 def __init__(self):
Craig Tillerd50993d2015-08-05 08:04:36 -0700435 self.platform = platform_string()
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700436
Jan Tattermusch77db4322016-02-20 20:19:35 -0800437 def configure(self, config, args):
438 self.config = config
439 self.args = args
440 _check_compiler(self.args.compiler, ['default'])
441
442 def test_specs(self):
Jan Tattermusch03c01062015-12-11 14:28:56 -0800443 with open('src/csharp/tests.json') as f:
444 tests_json = json.load(f)
445 assemblies = tests_json['assemblies']
446 tests = tests_json['tests']
447
Jan Tattermuscha2d964c2016-02-22 17:33:09 -0800448 msbuild_config = _MSBUILD_CONFIG[self.config.build_config]
Jan Tattermusch03c01062015-12-11 14:28:56 -0800449 assembly_files = ['%s/bin/%s/%s.dll' % (a, msbuild_config, a)
450 for a in assemblies]
451
452 extra_args = ['-labels'] + assembly_files
453
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700454 if self.platform == 'windows':
Jan Tattermusch03c01062015-12-11 14:28:56 -0800455 script_name = 'tools\\run_tests\\run_csharp.bat'
456 extra_args += ['-domain=None']
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700457 else:
Jan Tattermusch03c01062015-12-11 14:28:56 -0800458 script_name = 'tools/run_tests/run_csharp.sh'
Jan Tattermuschbf3b1532015-10-26 10:24:42 -0700459
Jan Tattermusch77db4322016-02-20 20:19:35 -0800460 if self.config.build_config == 'gcov':
Jan Tattermuschbdf4b2e2015-10-28 08:22:34 -0700461 # On Windows, we only collect C# code coverage.
462 # On Linux, we only collect coverage for native extension.
463 # For code coverage all tests need to run as one suite.
Jan Tattermusch77db4322016-02-20 20:19:35 -0800464 return [self.config.job_spec([script_name] + extra_args, None,
465 shortname='csharp.coverage',
466 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
Jan Tattermusch61c3a832015-10-27 17:54:50 -0700467 else:
Jan Tattermusch03c01062015-12-11 14:28:56 -0800468 specs = []
469 for test in tests:
470 cmdline = [script_name, '-run=%s' % test] + extra_args
471 if self.platform == 'windows':
472 # use different output directory for each test to prevent
473 # TestResult.xml clash between parallel test runs.
474 cmdline += ['-work=test-result/%s' % uuid.uuid4()]
Jan Tattermusch77db4322016-02-20 20:19:35 -0800475 specs.append(self.config.job_spec(cmdline, None,
476 shortname='csharp.%s' % test,
477 environ=_FORCE_ENVIRON_FOR_WRAPPERS))
Jan Tattermusch03c01062015-12-11 14:28:56 -0800478 return specs
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800479
murgatroid99256d3df2015-09-21 16:58:02 -0700480 def pre_build_steps(self):
Jan Tattermusch48423fc2015-10-07 18:59:16 -0700481 if self.platform == 'windows':
Jan Tattermusch874aec02015-10-07 19:26:19 -0700482 return [['tools\\run_tests\\pre_build_csharp.bat']]
Jan Tattermusch48423fc2015-10-07 18:59:16 -0700483 else:
484 return [['tools/run_tests/pre_build_csharp.sh']]
murgatroid99256d3df2015-09-21 16:58:02 -0700485
Jan Tattermusch77db4322016-02-20 20:19:35 -0800486 def make_targets(self):
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700487 # For Windows, this target doesn't really build anything,
488 # everything is build by buildall script later.
Craig Tillerd5904822015-08-31 21:30:58 -0700489 if self.platform == 'windows':
490 return []
491 else:
492 return ['grpc_csharp_ext']
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800493
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800494 def make_options(self):
495 if self.platform == 'mac':
496 # On Mac, official distribution of mono is 32bit.
497 return ['CFLAGS=-arch i386', 'LDFLAGS=-arch i386']
498 else:
499 return []
500
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800501 def build_steps(self):
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700502 if self.platform == 'windows':
503 return [['src\\csharp\\buildall.bat']]
504 else:
505 return [['tools/run_tests/build_csharp.sh']]
Nathaniel Manista840615e2015-01-22 20:31:47 +0000506
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200507 def post_tests_steps(self):
508 return []
509
murgatroid99a3e244f2015-09-22 11:25:53 -0700510 def makefile_name(self):
511 return 'Makefile'
512
Jan Tattermusch77db4322016-02-20 20:19:35 -0800513 def dockerfile_dir(self):
514 return 'tools/dockerfile/test/csharp_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800515
murgatroid99132ce6a2015-03-04 17:29:14 -0800516 def __str__(self):
517 return 'csharp'
518
Craig Tillerd625d812015-04-08 15:52:35 -0700519
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700520class ObjCLanguage(object):
521
Jan Tattermusch77db4322016-02-20 20:19:35 -0800522 def configure(self, config, args):
523 self.config = config
524 self.args = args
525 _check_compiler(self.args.compiler, ['default'])
526
527 def test_specs(self):
528 return [self.config.job_spec(['src/objective-c/tests/run_tests.sh'], None,
529 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700530
murgatroid99256d3df2015-09-21 16:58:02 -0700531 def pre_build_steps(self):
532 return []
533
Jan Tattermusch77db4322016-02-20 20:19:35 -0800534 def make_targets(self):
Jorge Canizalesd0b32e92015-07-30 23:08:43 -0700535 return ['grpc_objective_c_plugin', 'interop_server']
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700536
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800537 def make_options(self):
538 return []
539
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700540 def build_steps(self):
Jorge Canizalesd0b32e92015-07-30 23:08:43 -0700541 return [['src/objective-c/tests/build_tests.sh']]
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700542
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200543 def post_tests_steps(self):
544 return []
545
murgatroid99a3e244f2015-09-22 11:25:53 -0700546 def makefile_name(self):
547 return 'Makefile'
548
Jan Tattermusch77db4322016-02-20 20:19:35 -0800549 def dockerfile_dir(self):
Jan Tattermusch788ee232016-01-26 12:19:44 -0800550 return None
551
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700552 def __str__(self):
553 return 'objc'
554
555
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100556class Sanity(object):
557
Jan Tattermusch77db4322016-02-20 20:19:35 -0800558 def configure(self, config, args):
559 self.config = config
560 self.args = args
561 _check_compiler(self.args.compiler, ['default'])
562
563 def test_specs(self):
Craig Tiller94d04a52016-01-20 10:58:23 -0800564 import yaml
Jan Tattermusch788ee232016-01-26 12:19:44 -0800565 with open('tools/run_tests/sanity/sanity_tests.yaml', 'r') as f:
Jan Tattermusch77db4322016-02-20 20:19:35 -0800566 return [self.config.job_spec(cmd['script'].split(), None,
567 timeout_seconds=None, environ={'TEST': 'true'},
568 cpu_cost=cmd.get('cpu_cost', 1))
Craig Tiller94d04a52016-01-20 10:58:23 -0800569 for cmd in yaml.load(f)]
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100570
murgatroid99256d3df2015-09-21 16:58:02 -0700571 def pre_build_steps(self):
572 return []
573
Jan Tattermusch77db4322016-02-20 20:19:35 -0800574 def make_targets(self):
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100575 return ['run_dep_checks']
576
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800577 def make_options(self):
578 return []
579
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100580 def build_steps(self):
581 return []
582
Nicolas "Pixel" Noble87879b32015-10-12 23:28:53 +0200583 def post_tests_steps(self):
584 return []
585
murgatroid99a3e244f2015-09-22 11:25:53 -0700586 def makefile_name(self):
587 return 'Makefile'
588
Jan Tattermusch77db4322016-02-20 20:19:35 -0800589 def dockerfile_dir(self):
Jan Tattermusche70b3c52016-02-07 20:21:02 -0800590 return 'tools/dockerfile/test/sanity'
Jan Tattermusch788ee232016-01-26 12:19:44 -0800591
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100592 def __str__(self):
593 return 'sanity'
594
Nicolas "Pixel" Noblee55cd7f2015-04-14 17:59:13 +0200595
Craig Tiller738c3342015-01-12 14:28:33 -0800596# different configurations we can run under
Craig Tillera0f85172016-01-20 15:56:06 -0800597with open('tools/run_tests/configs.json') as f:
Craig Tiller1dce9062016-01-20 17:01:56 -0800598 _CONFIGS = dict((cfg['config'], Config(**cfg)) for cfg in ast.literal_eval(f.read()))
Craig Tiller738c3342015-01-12 14:28:33 -0800599
600
Craig Tillerc7449162015-01-16 14:42:10 -0800601_LANGUAGES = {
Craig Tillere9c959d2015-01-18 10:23:26 -0800602 'c++': CLanguage('cxx', 'c++'),
603 'c': CLanguage('c', 'c'),
murgatroid992c8d5162015-01-26 10:41:21 -0800604 'node': NodeLanguage(),
Nathaniel Manista840615e2015-01-22 20:31:47 +0000605 'php': PhpLanguage(),
606 'python': PythonLanguage(),
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800607 'ruby': RubyLanguage(),
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100608 'csharp': CSharpLanguage(),
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700609 'objc' : ObjCLanguage(),
Jan Tattermusch70a57e42016-02-20 18:50:27 -0800610 'sanity': Sanity()
Craig Tillereb272bc2015-01-30 13:13:14 -0800611 }
Nicolas Nobleddef2462015-01-06 18:08:25 -0800612
Jan Tattermusch77db4322016-02-20 20:19:35 -0800613
Jan Tattermuscha2d964c2016-02-22 17:33:09 -0800614_MSBUILD_CONFIG = {
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700615 'dbg': 'Debug',
616 'opt': 'Release',
Jan Tattermusche4a69182015-12-15 09:53:01 -0800617 'gcov': 'Debug',
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700618 }
619
David Garcia Quintase90cd372015-05-31 18:15:26 -0700620
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800621def _windows_arch_option(arch):
622 """Returns msbuild cmdline option for selected architecture."""
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800623 if arch == 'default' or arch == 'x86':
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800624 return '/p:Platform=Win32'
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800625 elif arch == 'x64':
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800626 return '/p:Platform=x64'
627 else:
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800628 print 'Architecture %s not supported.' % arch
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800629 sys.exit(1)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800630
Jan Tattermuschf08018a2016-01-26 08:22:09 -0800631
632def _check_arch_option(arch):
633 """Checks that architecture option is valid."""
634 if platform_string() == 'windows':
635 _windows_arch_option(arch)
636 elif platform_string() == 'linux':
637 # On linux, we need to be running under docker with the right architecture.
Jan Tattermusch07fb0422016-01-26 10:46:56 -0800638 runtime_arch = platform.architecture()[0]
Jan Tattermuschf08018a2016-01-26 08:22:09 -0800639 if arch == 'default':
640 return
641 elif runtime_arch == '64bit' and arch == 'x64':
642 return
643 elif runtime_arch == '32bit' and arch == 'x86':
644 return
645 else:
646 print 'Architecture %s does not match current runtime architecture.' % arch
647 sys.exit(1)
648 else:
649 if args.arch != 'default':
650 print 'Architecture %s not supported on current platform.' % args.arch
651 sys.exit(1)
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800652
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800653
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800654def _windows_build_bat(compiler):
655 """Returns name of build.bat for selected compiler."""
656 if compiler == 'default' or compiler == 'vs2013':
657 return 'vsprojects\\build_vs2013.bat'
658 elif compiler == 'vs2015':
659 return 'vsprojects\\build_vs2015.bat'
660 elif compiler == 'vs2010':
661 return 'vsprojects\\build_vs2010.bat'
662 else:
663 print 'Compiler %s not supported.' % compiler
664 sys.exit(1)
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800665
666
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800667def _windows_toolset_option(compiler):
668 """Returns msbuild PlatformToolset for selected compiler."""
669 if compiler == 'default' or compiler == 'vs2013':
670 return '/p:PlatformToolset=v120'
671 elif compiler == 'vs2015':
672 return '/p:PlatformToolset=v140'
673 elif compiler == 'vs2010':
674 return '/p:PlatformToolset=v100'
675 else:
676 print 'Compiler %s not supported.' % compiler
677 sys.exit(1)
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800678
679
Jan Tattermusche70b3c52016-02-07 20:21:02 -0800680def _docker_arch_suffix(arch):
681 """Returns suffix to dockerfile dir to use."""
682 if arch == 'default' or arch == 'x64':
683 return 'x64'
684 elif arch == 'x86':
685 return 'x86'
686 else:
687 print 'Architecture %s not supported with current settings.' % arch
688 sys.exit(1)
689
690
David Garcia Quintase90cd372015-05-31 18:15:26 -0700691def runs_per_test_type(arg_str):
692 """Auxilary function to parse the "runs_per_test" flag.
693
694 Returns:
695 A positive integer or 0, the latter indicating an infinite number of
696 runs.
697
698 Raises:
699 argparse.ArgumentTypeError: Upon invalid input.
700 """
701 if arg_str == 'inf':
702 return 0
703 try:
704 n = int(arg_str)
705 if n <= 0: raise ValueError
Craig Tiller50e53e22015-06-01 20:18:21 -0700706 return n
David Garcia Quintase90cd372015-05-31 18:15:26 -0700707 except:
Adele Zhoue4c35612015-10-16 15:34:23 -0700708 msg = '\'{}\' is not a positive integer or \'inf\''.format(arg_str)
David Garcia Quintase90cd372015-05-31 18:15:26 -0700709 raise argparse.ArgumentTypeError(msg)
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700710
711# parse command line
712argp = argparse.ArgumentParser(description='Run grpc tests.')
713argp.add_argument('-c', '--config',
Jan Tattermusch77db4322016-02-20 20:19:35 -0800714 choices=sorted(_CONFIGS.keys()),
715 default='opt')
David Garcia Quintase90cd372015-05-31 18:15:26 -0700716argp.add_argument('-n', '--runs_per_test', default=1, type=runs_per_test_type,
717 help='A positive integer or "inf". If "inf", all tests will run in an '
718 'infinite loop. Especially useful in combination with "-f"')
Craig Tillerfe406ec2015-02-24 13:55:12 -0800719argp.add_argument('-r', '--regex', default='.*', type=str)
Craig Tiller5f735a62016-01-20 09:31:15 -0800720argp.add_argument('-j', '--jobs', default=multiprocessing.cpu_count(), type=int)
Craig Tiller8451e872015-02-27 09:25:51 -0800721argp.add_argument('-s', '--slowdown', default=1.0, type=float)
ctiller3040cb72015-01-07 12:13:17 -0800722argp.add_argument('-f', '--forever',
723 default=False,
724 action='store_const',
725 const=True)
Nicolas "Pixel" Noblea7df3f92015-02-26 22:07:04 +0100726argp.add_argument('-t', '--travis',
727 default=False,
728 action='store_const',
729 const=True)
Nicolas Noble044db742015-01-14 16:57:24 -0800730argp.add_argument('--newline_on_success',
731 default=False,
732 action='store_const',
733 const=True)
Craig Tiller686fb262015-01-15 07:39:09 -0800734argp.add_argument('-l', '--language',
Craig Tiller60f15e62015-05-13 09:05:17 -0700735 choices=['all'] + sorted(_LANGUAGES.keys()),
Craig Tiller686fb262015-01-15 07:39:09 -0800736 nargs='+',
Craig Tiller60f15e62015-05-13 09:05:17 -0700737 default=['all'])
Craig Tillercd43da82015-05-29 08:41:29 -0700738argp.add_argument('-S', '--stop_on_failure',
739 default=False,
740 action='store_const',
741 const=True)
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700742argp.add_argument('--use_docker',
743 default=False,
744 action='store_const',
745 const=True,
Adele Zhoue4c35612015-10-16 15:34:23 -0700746 help='Run all the tests under docker. That provides ' +
747 'additional isolation and prevents the need to install ' +
748 'language specific prerequisites. Only available on Linux.')
Craig Tillerd4509a12015-09-28 09:18:40 -0700749argp.add_argument('--allow_flakes',
750 default=False,
751 action='store_const',
752 const=True,
Adele Zhoue4c35612015-10-16 15:34:23 -0700753 help='Allow flaky tests to show as passing (re-runs failed tests up to five times)')
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800754argp.add_argument('--arch',
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800755 choices=['default', 'x86', 'x64'],
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800756 default='default',
757 help='Selects architecture to target. For some platforms "default" is the only supported choice.')
758argp.add_argument('--compiler',
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800759 choices=['default',
760 'gcc4.4', 'gcc4.9', 'gcc5.3',
761 'vs2010', 'vs2013', 'vs2015'],
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800762 default='default',
Jan Tattermusch77db4322016-02-20 20:19:35 -0800763 help='Selects compiler to use. Allowed values depend on the platform and language.')
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800764argp.add_argument('--build_only',
765 default=False,
766 action='store_const',
767 const=True,
768 help='Perform all the build steps but dont run any tests.')
Craig Tiller5f735a62016-01-20 09:31:15 -0800769argp.add_argument('--measure_cpu_costs', default=False, action='store_const', const=True,
770 help='Measure the cpu costs of tests')
Craig Tiller1676f912016-01-05 10:49:44 -0800771argp.add_argument('--update_submodules', default=[], nargs='*',
772 help='Update some submodules before building. If any are updated, also run generate_projects. ' +
773 'Submodules are specified as SUBMODULE_NAME:BRANCH; if BRANCH is omitted, master is assumed.')
Craig Tiller234b6e72015-05-23 10:12:40 -0700774argp.add_argument('-a', '--antagonists', default=0, type=int)
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +0200775argp.add_argument('-x', '--xml_report', default=None, type=str,
776 help='Generates a JUnit-compatible XML report')
Nicolas Nobleddef2462015-01-06 18:08:25 -0800777args = argp.parse_args()
778
Craig Tiller5f735a62016-01-20 09:31:15 -0800779jobset.measure_cpu_costs = args.measure_cpu_costs
780
Craig Tiller1676f912016-01-05 10:49:44 -0800781# update submodules if necessary
Craig Tillerb361b4e2016-01-06 11:44:17 -0800782need_to_regenerate_projects = False
783for spec in args.update_submodules:
784 spec = spec.split(':', 1)
785 if len(spec) == 1:
786 submodule = spec[0]
787 branch = 'master'
788 elif len(spec) == 2:
789 submodule = spec[0]
790 branch = spec[1]
791 cwd = 'third_party/%s' % submodule
792 def git(cmd, cwd=cwd):
793 print 'in %s: git %s' % (cwd, cmd)
794 subprocess.check_call('git %s' % cmd, cwd=cwd, shell=True)
795 git('fetch')
796 git('checkout %s' % branch)
797 git('pull origin %s' % branch)
798 if os.path.exists('src/%s/gen_build_yaml.py' % submodule):
799 need_to_regenerate_projects = True
800if need_to_regenerate_projects:
801 if jobset.platform_string() == 'linux':
802 subprocess.check_call('tools/buildgen/generate_projects.sh', shell=True)
803 else:
804 print 'WARNING: may need to regenerate projects, but since we are not on'
805 print ' Linux this step is being skipped. Compilation MAY fail.'
Craig Tiller1676f912016-01-05 10:49:44 -0800806
807
Nicolas Nobleddef2462015-01-06 18:08:25 -0800808# grab config
Jan Tattermusch77db4322016-02-20 20:19:35 -0800809run_config = _CONFIGS[args.config]
810build_config = run_config.build_config
Craig Tillerf1973b02015-01-16 12:32:13 -0800811
Craig Tiller06805272015-06-11 14:46:47 -0700812if args.travis:
murgatroid99d3b5b7f2015-10-06 17:02:03 -0700813 _FORCE_ENVIRON_FOR_WRAPPERS = {'GRPC_TRACE': 'api'}
Craig Tiller06805272015-06-11 14:46:47 -0700814
Adele Zhou6b9527c2015-11-20 15:56:35 -0800815if 'all' in args.language:
Craig Tiller1676f912016-01-05 10:49:44 -0800816 lang_list = _LANGUAGES.keys()
Adele Zhou6b9527c2015-11-20 15:56:35 -0800817else:
818 lang_list = args.language
Craig Tiller16900662016-01-07 19:30:54 -0800819# We don't support code coverage on some languages
820if 'gcov' in args.config:
Jan Tattermusch3b5121b2016-02-22 17:41:05 -0800821 for bad in ['objc', 'sanity']:
Craig Tiller16900662016-01-07 19:30:54 -0800822 if bad in lang_list:
823 lang_list.remove(bad)
Adele Zhou6b9527c2015-11-20 15:56:35 -0800824
825languages = set(_LANGUAGES[l] for l in lang_list)
Jan Tattermusch77db4322016-02-20 20:19:35 -0800826for l in languages:
827 l.configure(run_config, args)
murgatroid99132ce6a2015-03-04 17:29:14 -0800828
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800829language_make_options=[]
830if any(language.make_options() for language in languages):
831 if len(languages) != 1:
832 print 'languages with custom make options cannot be built simultaneously with other languages'
833 sys.exit(1)
834 else:
835 language_make_options = next(iter(languages)).make_options()
836
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800837if args.use_docker:
838 if not args.travis:
839 print 'Seen --use_docker flag, will run tests under docker.'
840 print
841 print 'IMPORTANT: The changes you are testing need to be locally committed'
842 print 'because only the committed changes in the current branch will be'
843 print 'copied to the docker environment.'
844 time.sleep(5)
845
Jan Tattermusch3b5121b2016-02-22 17:41:05 -0800846 dockerfile_dirs = set([l.dockerfile_dir() for l in languages])
847 if len(dockerfile_dirs) > 1:
848 print 'Languages to be tested require running under different docker images.'
849 sys.exit(1)
850 dockerfile_dir = next(iter(dockerfile_dirs))
851
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800852 child_argv = [ arg for arg in sys.argv if not arg == '--use_docker' ]
Jan Tattermusched342b12016-01-26 14:40:31 -0800853 run_tests_cmd = 'python tools/run_tests/run_tests.py %s' % ' '.join(child_argv[1:])
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800854
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800855 env = os.environ.copy()
856 env['RUN_TESTS_COMMAND'] = run_tests_cmd
Jan Tattermusch3b5121b2016-02-22 17:41:05 -0800857 env['DOCKERFILE_DIR'] = dockerfile_dir
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800858 env['DOCKER_RUN_SCRIPT'] = 'tools/jenkins/docker_run_tests.sh'
859 if args.xml_report:
860 env['XML_REPORT'] = args.xml_report
861 if not args.travis:
862 env['TTY_FLAG'] = '-t' # enables Ctrl-C when not on Jenkins.
863
864 subprocess.check_call(['tools/jenkins/build_docker_and_run_tests.sh'],
865 shell=True,
866 env=env)
867 sys.exit(0)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800868
Jan Tattermuschf08018a2016-01-26 08:22:09 -0800869_check_arch_option(args.arch)
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800870
Jan Tattermuschfba65302016-01-25 18:21:14 -0800871def make_jobspec(cfg, targets, makefile='Makefile'):
872 if platform_string() == 'windows':
Craig Tillerfc3c0c42015-09-01 16:47:54 -0700873 extra_args = []
Craig Tillerb5391e12015-09-03 14:35:18 -0700874 # better do parallel compilation
Jan Tattermusch47eeb2b2015-10-07 14:09:18 -0700875 # empirically /m:2 gives the best performance/price and should prevent
876 # overloading the windows workers.
Adele Zhoue4c35612015-10-16 15:34:23 -0700877 extra_args.extend(['/m:2'])
Craig Tillerb5391e12015-09-03 14:35:18 -0700878 # disable PDB generation: it's broken, and we don't need it during CI
Adele Zhoue4c35612015-10-16 15:34:23 -0700879 extra_args.extend(['/p:Jenkins=true'])
Craig Tiller6fd23842015-09-01 07:36:31 -0700880 return [
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800881 jobset.JobSpec([_windows_build_bat(args.compiler),
murgatroid99cf08daf2015-09-21 15:33:16 -0700882 'vsprojects\\%s.sln' % target,
Jan Tattermuscha2d964c2016-02-22 17:33:09 -0800883 '/p:Configuration=%s' % _MSBUILD_CONFIG[cfg]] +
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800884 extra_args +
885 language_make_options,
Craig Tiller590105a2016-01-19 13:03:46 -0800886 shell=True, timeout_seconds=None)
Craig Tiller6fd23842015-09-01 07:36:31 -0700887 for target in targets]
Jan Tattermuschfba65302016-01-25 18:21:14 -0800888 else:
murgatroid998ae409f2015-10-26 16:39:00 -0700889 if targets:
890 return [jobset.JobSpec([os.getenv('MAKE', 'make'),
891 '-f', makefile,
Craig Tillerdd6f7ed2016-01-21 12:54:42 -0800892 '-j', '%d' % args.jobs,
Craig Tiller71a86042016-01-15 14:59:58 -0800893 'EXTRA_DEFINES=GRPC_TEST_SLOWDOWN_MACHINE_FACTOR=%f' % args.slowdown,
894 'CONFIG=%s' % cfg] +
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800895 language_make_options +
Craig Tiller71a86042016-01-15 14:59:58 -0800896 ([] if not args.travis else ['JENKINS_BUILD=1']) +
897 targets,
Craig Tiller590105a2016-01-19 13:03:46 -0800898 timeout_seconds=None)]
murgatroid998ae409f2015-10-26 16:39:00 -0700899 else:
900 return []
Jan Tattermuschfba65302016-01-25 18:21:14 -0800901
murgatroid99a3e244f2015-09-22 11:25:53 -0700902make_targets = {}
903for l in languages:
904 makefile = l.makefile_name()
905 make_targets[makefile] = make_targets.get(makefile, set()).union(
Jan Tattermusch77db4322016-02-20 20:19:35 -0800906 set(l.make_targets()))
Craig Tiller5058c692015-04-08 09:42:04 -0700907
Jan Tattermusche4a69182015-12-15 09:53:01 -0800908def build_step_environ(cfg):
909 environ = {'CONFIG': cfg}
Jan Tattermuscha2d964c2016-02-22 17:33:09 -0800910 msbuild_cfg = _MSBUILD_CONFIG.get(cfg)
Jan Tattermusche4a69182015-12-15 09:53:01 -0800911 if msbuild_cfg:
912 environ['MSBUILD_CONFIG'] = msbuild_cfg
913 return environ
914
murgatroid99fddac962015-09-22 09:20:11 -0700915build_steps = list(set(
Jan Tattermusch77db4322016-02-20 20:19:35 -0800916 jobset.JobSpec(cmdline, environ=build_step_environ(build_config), flake_retries=5)
murgatroid99256d3df2015-09-21 16:58:02 -0700917 for l in languages
918 for cmdline in l.pre_build_steps()))
Craig Tillerbd4e3782015-09-01 06:48:55 -0700919if make_targets:
Jan Tattermusch77db4322016-02-20 20:19:35 -0800920 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 -0700921 build_steps.extend(set(make_commands))
Craig Tiller5058c692015-04-08 09:42:04 -0700922build_steps.extend(set(
Jan Tattermusch77db4322016-02-20 20:19:35 -0800923 jobset.JobSpec(cmdline, environ=build_step_environ(build_config), timeout_seconds=None)
Craig Tiller547db2b2015-01-30 14:08:39 -0800924 for l in languages
Craig Tiller533b1a22015-05-29 08:41:29 -0700925 for cmdline in l.build_steps()))
Craig Tillerf1973b02015-01-16 12:32:13 -0800926
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200927post_tests_steps = list(set(
Jan Tattermusch77db4322016-02-20 20:19:35 -0800928 jobset.JobSpec(cmdline, environ=build_step_environ(build_config))
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200929 for l in languages
930 for cmdline in l.post_tests_steps()))
Nicolas Nobleddef2462015-01-06 18:08:25 -0800931runs_per_test = args.runs_per_test
ctiller3040cb72015-01-07 12:13:17 -0800932forever = args.forever
Nicolas Nobleddef2462015-01-06 18:08:25 -0800933
Nicolas Nobleddef2462015-01-06 18:08:25 -0800934
Craig Tiller71735182015-01-15 17:07:13 -0800935class TestCache(object):
Craig Tillerb50d1662015-01-15 17:28:21 -0800936 """Cache for running tests."""
937
David Klempner25739582015-02-11 15:57:32 -0800938 def __init__(self, use_cache_results):
Craig Tiller71735182015-01-15 17:07:13 -0800939 self._last_successful_run = {}
David Klempner25739582015-02-11 15:57:32 -0800940 self._use_cache_results = use_cache_results
Craig Tiller69cd2372015-06-11 09:38:09 -0700941 self._last_save = time.time()
Craig Tiller71735182015-01-15 17:07:13 -0800942
943 def should_run(self, cmdline, bin_hash):
Craig Tiller71735182015-01-15 17:07:13 -0800944 if cmdline not in self._last_successful_run:
945 return True
946 if self._last_successful_run[cmdline] != bin_hash:
947 return True
David Klempner25739582015-02-11 15:57:32 -0800948 if not self._use_cache_results:
949 return True
Craig Tiller71735182015-01-15 17:07:13 -0800950 return False
951
952 def finished(self, cmdline, bin_hash):
Craig Tiller547db2b2015-01-30 14:08:39 -0800953 self._last_successful_run[cmdline] = bin_hash
Craig Tiller69cd2372015-06-11 09:38:09 -0700954 if time.time() - self._last_save > 1:
955 self.save()
Craig Tiller71735182015-01-15 17:07:13 -0800956
957 def dump(self):
Craig Tillerb50d1662015-01-15 17:28:21 -0800958 return [{'cmdline': k, 'hash': v}
959 for k, v in self._last_successful_run.iteritems()]
Craig Tiller71735182015-01-15 17:07:13 -0800960
961 def parse(self, exdump):
962 self._last_successful_run = dict((o['cmdline'], o['hash']) for o in exdump)
963
964 def save(self):
965 with open('.run_tests_cache', 'w') as f:
Craig Tiller261dd982015-01-16 16:41:45 -0800966 f.write(json.dumps(self.dump()))
Craig Tiller69cd2372015-06-11 09:38:09 -0700967 self._last_save = time.time()
Craig Tiller71735182015-01-15 17:07:13 -0800968
Craig Tiller1cc11db2015-01-15 22:50:50 -0800969 def maybe_load(self):
970 if os.path.exists('.run_tests_cache'):
971 with open('.run_tests_cache') as f:
Craig Tiller261dd982015-01-16 16:41:45 -0800972 self.parse(json.loads(f.read()))
Craig Tiller71735182015-01-15 17:07:13 -0800973
974
Craig Tillerf53d9c82015-08-04 14:19:43 -0700975def _start_port_server(port_server_port):
976 # check if a compatible port server is running
977 # if incompatible (version mismatch) ==> start a new one
978 # if not running ==> start a new one
979 # otherwise, leave it up
980 try:
Craig Tillerfe4939f2015-10-06 12:55:36 -0700981 version = int(urllib2.urlopen(
982 'http://localhost:%d/version_number' % port_server_port,
983 timeout=1).read())
984 print 'detected port server running version %d' % version
Craig Tillerf53d9c82015-08-04 14:19:43 -0700985 running = True
Craig Tillerfe4939f2015-10-06 12:55:36 -0700986 except Exception as e:
Craig Tiller0d6499e2015-10-05 14:00:47 -0700987 print 'failed to detect port server: %s' % sys.exc_info()[0]
Craig Tillerfe4939f2015-10-06 12:55:36 -0700988 print e.strerror
Craig Tillerf53d9c82015-08-04 14:19:43 -0700989 running = False
990 if running:
Craig Tillerfe4939f2015-10-06 12:55:36 -0700991 current_version = int(subprocess.check_output(
Jan Tattermusch3bd08272015-11-04 19:24:37 -0800992 [sys.executable, os.path.abspath('tools/run_tests/port_server.py'),
993 'dump_version']))
Craig Tillerfe4939f2015-10-06 12:55:36 -0700994 print 'my port server is version %d' % current_version
995 running = (version >= current_version)
996 if not running:
997 print 'port_server version mismatch: killing the old one'
998 urllib2.urlopen('http://localhost:%d/quitquitquit' % port_server_port).read()
999 time.sleep(1)
Craig Tillerf53d9c82015-08-04 14:19:43 -07001000 if not running:
Craig Tillerf0a293e2015-10-12 10:05:50 -07001001 fd, logfile = tempfile.mkstemp()
1002 os.close(fd)
1003 print 'starting port_server, with log file %s' % logfile
Jan Tattermusch3bd08272015-11-04 19:24:37 -08001004 args = [sys.executable, os.path.abspath('tools/run_tests/port_server.py'),
1005 '-p', '%d' % port_server_port, '-l', logfile]
Craig Tiller367d41d2015-10-12 13:00:22 -07001006 env = dict(os.environ)
1007 env['BUILD_ID'] = 'pleaseDontKillMeJenkins'
Nicolas "Pixel" Noblef72d7b52015-12-03 03:07:43 +01001008 if platform_string() == 'windows':
Jan Tattermusch3bd08272015-11-04 19:24:37 -08001009 # Working directory of port server needs to be outside of Jenkins
1010 # workspace to prevent file lock issues.
1011 tempdir = tempfile.mkdtemp()
Craig Tillerd2c39712015-10-12 11:08:49 -07001012 port_server = subprocess.Popen(
Craig Tiller367d41d2015-10-12 13:00:22 -07001013 args,
1014 env=env,
Jan Tattermusch3bd08272015-11-04 19:24:37 -08001015 cwd=tempdir,
Craig Tiller367d41d2015-10-12 13:00:22 -07001016 creationflags = 0x00000008, # detached process
1017 close_fds=True)
Craig Tillerd2c39712015-10-12 11:08:49 -07001018 else:
1019 port_server = subprocess.Popen(
1020 args,
Craig Tiller367d41d2015-10-12 13:00:22 -07001021 env=env,
Craig Tillerd2c39712015-10-12 11:08:49 -07001022 preexec_fn=os.setsid,
1023 close_fds=True)
Craig Tillerf0a293e2015-10-12 10:05:50 -07001024 time.sleep(1)
Craig Tiller8b5f4dc2015-08-26 08:02:01 -07001025 # ensure port server is up
Craig Tillerabd37fd2015-08-26 07:54:01 -07001026 waits = 0
Craig Tillerf53d9c82015-08-04 14:19:43 -07001027 while True:
Craig Tillerabd37fd2015-08-26 07:54:01 -07001028 if waits > 10:
Craig Tillerf0a293e2015-10-12 10:05:50 -07001029 print 'killing port server due to excessive start up waits'
Craig Tillerabd37fd2015-08-26 07:54:01 -07001030 port_server.kill()
Craig Tillera2f38b02015-09-24 11:19:17 -07001031 if port_server.poll() is not None:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001032 print 'port_server failed to start'
Craig Tillerf0a293e2015-10-12 10:05:50 -07001033 # try one final time: maybe another build managed to start one
1034 time.sleep(1)
1035 try:
1036 urllib2.urlopen('http://localhost:%d/get' % port_server_port,
1037 timeout=1).read()
1038 print 'last ditch attempt to contact port server succeeded'
1039 break
1040 except:
Jan Tattermusch3b5121b2016-02-22 17:41:05 -08001041 traceback.print_exc()
Craig Tillerf0a293e2015-10-12 10:05:50 -07001042 port_log = open(logfile, 'r').read()
1043 print port_log
1044 sys.exit(1)
Craig Tillerf53d9c82015-08-04 14:19:43 -07001045 try:
Craig Tillerabd37fd2015-08-26 07:54:01 -07001046 urllib2.urlopen('http://localhost:%d/get' % port_server_port,
1047 timeout=1).read()
Craig Tillerf0a293e2015-10-12 10:05:50 -07001048 print 'port server is up and ready'
Craig Tillerf53d9c82015-08-04 14:19:43 -07001049 break
Craig Tiller31fdaa42015-09-25 13:09:59 -07001050 except socket.timeout:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001051 print 'waiting for port_server: timeout'
Craig Tillerf0a293e2015-10-12 10:05:50 -07001052 traceback.print_exc();
1053 time.sleep(1)
Craig Tiller31fdaa42015-09-25 13:09:59 -07001054 waits += 1
Craig Tillerf53d9c82015-08-04 14:19:43 -07001055 except urllib2.URLError:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001056 print 'waiting for port_server: urlerror'
Craig Tillerf0a293e2015-10-12 10:05:50 -07001057 traceback.print_exc();
1058 time.sleep(1)
Craig Tillerabd37fd2015-08-26 07:54:01 -07001059 waits += 1
Craig Tillerf53d9c82015-08-04 14:19:43 -07001060 except:
Jan Tattermusch3b5121b2016-02-22 17:41:05 -08001061 traceback.print_exc()
Craig Tillerf53d9c82015-08-04 14:19:43 -07001062 port_server.kill()
1063 raise
1064
1065
Adele Zhoud5fffa52015-10-23 15:51:42 -07001066def _calculate_num_runs_failures(list_of_results):
1067 """Caculate number of runs and failures for a particular test.
1068
1069 Args:
1070 list_of_results: (List) of JobResult object.
1071 Returns:
1072 A tuple of total number of runs and failures.
1073 """
1074 num_runs = len(list_of_results) # By default, there is 1 run per JobResult.
1075 num_failures = 0
1076 for jobresult in list_of_results:
1077 if jobresult.retries > 0:
1078 num_runs += jobresult.retries
1079 if jobresult.num_failures > 0:
1080 num_failures += jobresult.num_failures
1081 return num_runs, num_failures
1082
Adele Zhou6b9527c2015-11-20 15:56:35 -08001083
Craig Tillereb9de8b2016-01-08 08:57:41 -08001084# _build_and_run results
1085class BuildAndRunError(object):
1086
1087 BUILD = object()
1088 TEST = object()
1089 POST_TEST = object()
1090
1091
1092# returns a list of things that failed (or an empty list on success)
Craig Tillerf53d9c82015-08-04 14:19:43 -07001093def _build_and_run(
Jan Tattermusch2dd156e2015-12-04 18:26:17 -08001094 check_cancelled, newline_on_success, cache, xml_report=None, build_only=False):
ctiller3040cb72015-01-07 12:13:17 -08001095 """Do one pass of building & running tests."""
murgatroid99666450e2015-01-26 13:03:31 -08001096 # build latest sequentially
Jan Tattermuschaab1e512016-01-28 09:30:44 -08001097 num_failures, resultset = jobset.run(
Adele Zhoue4c35612015-10-16 15:34:23 -07001098 build_steps, maxjobs=1, stop_on_failure=True,
Craig Tiller883064c2015-11-04 10:06:10 -08001099 newline_on_success=newline_on_success, travis=args.travis)
Adele Zhoue4c35612015-10-16 15:34:23 -07001100 if num_failures:
Craig Tillereb9de8b2016-01-08 08:57:41 -08001101 return [BuildAndRunError.BUILD]
Craig Tillerb361b4e2016-01-06 11:44:17 -08001102
Jan Tattermusch2dd156e2015-12-04 18:26:17 -08001103 if build_only:
Jan Tattermuschaab1e512016-01-28 09:30:44 -08001104 if xml_report:
1105 report_utils.render_junit_xml_report(resultset, xml_report)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001106 return []
ctiller3040cb72015-01-07 12:13:17 -08001107
Craig Tiller234b6e72015-05-23 10:12:40 -07001108 # start antagonists
David Garcia Quintas79e389f2015-06-02 17:49:42 -07001109 antagonists = [subprocess.Popen(['tools/run_tests/antagonist.py'])
Craig Tiller234b6e72015-05-23 10:12:40 -07001110 for _ in range(0, args.antagonists)]
Craig Tillerfe4939f2015-10-06 12:55:36 -07001111 port_server_port = 32767
Craig Tillerf53d9c82015-08-04 14:19:43 -07001112 _start_port_server(port_server_port)
Adele Zhou7cf72112015-11-04 11:18:43 -08001113 resultset = None
Adele Zhou803af152015-11-30 15:16:16 -08001114 num_test_failures = 0
Craig Tiller234b6e72015-05-23 10:12:40 -07001115 try:
David Garcia Quintase90cd372015-05-31 18:15:26 -07001116 infinite_runs = runs_per_test == 0
yang-g6c1fdc62015-08-18 11:57:42 -07001117 one_run = set(
1118 spec
yang-g6c1fdc62015-08-18 11:57:42 -07001119 for language in languages
Jan Tattermusch77db4322016-02-20 20:19:35 -08001120 for spec in language.test_specs()
yang-g6c1fdc62015-08-18 11:57:42 -07001121 if re.search(args.regex, spec.shortname))
David Garcia Quintas79e389f2015-06-02 17:49:42 -07001122 # When running on travis, we want out test runs to be as similar as possible
1123 # for reproducibility purposes.
Craig Tiller883064c2015-11-04 10:06:10 -08001124 if args.travis:
David Garcia Quintas79e389f2015-06-02 17:49:42 -07001125 massaged_one_run = sorted(one_run, key=lambda x: x.shortname)
1126 else:
1127 # whereas otherwise, we want to shuffle things up to give all tests a
1128 # chance to run.
1129 massaged_one_run = list(one_run) # random.shuffle needs an indexable seq.
1130 random.shuffle(massaged_one_run) # which it modifies in-place.
Craig Tillerf7b7c892015-06-22 14:33:25 -07001131 if infinite_runs:
1132 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 -07001133 runs_sequence = (itertools.repeat(massaged_one_run) if infinite_runs
1134 else itertools.repeat(massaged_one_run, runs_per_test))
David Garcia Quintase90cd372015-05-31 18:15:26 -07001135 all_runs = itertools.chain.from_iterable(runs_sequence)
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +02001136
Adele Zhou803af152015-11-30 15:16:16 -08001137 num_test_failures, resultset = jobset.run(
Adele Zhou2271ab52015-10-28 13:59:14 -07001138 all_runs, check_cancelled, newline_on_success=newline_on_success,
Craig Tiller883064c2015-11-04 10:06:10 -08001139 travis=args.travis, infinite_runs=infinite_runs, maxjobs=args.jobs,
murgatroid998ae409f2015-10-26 16:39:00 -07001140 stop_on_failure=args.stop_on_failure,
Adele Zhouf2ca7bc2015-10-23 15:38:00 -07001141 cache=cache if not xml_report else None,
Adele Zhouf2ca7bc2015-10-23 15:38:00 -07001142 add_env={'GRPC_TEST_PORT_SERVER': 'localhost:%d' % port_server_port})
Adele Zhoud5fffa52015-10-23 15:51:42 -07001143 if resultset:
1144 for k, v in resultset.iteritems():
1145 num_runs, num_failures = _calculate_num_runs_failures(v)
1146 if num_failures == num_runs: # what about infinite_runs???
1147 jobset.message('FAILED', k, do_newline=True)
1148 elif num_failures > 0:
1149 jobset.message(
1150 'FLAKE', '%s [%d/%d runs flaked]' % (k, num_failures, num_runs),
1151 do_newline=True)
1152 else:
1153 jobset.message('PASSED', k, do_newline=True)
Craig Tiller234b6e72015-05-23 10:12:40 -07001154 finally:
1155 for antagonist in antagonists:
1156 antagonist.kill()
Adele Zhou7cf72112015-11-04 11:18:43 -08001157 if xml_report and resultset:
Adele Zhou3bc7ba42015-11-05 10:21:58 -08001158 report_utils.render_junit_xml_report(resultset, xml_report)
Craig Tillerd86a3942015-01-14 12:48:54 -08001159
Adele Zhouf2ca7bc2015-10-23 15:38:00 -07001160 number_failures, _ = jobset.run(
1161 post_tests_steps, maxjobs=1, stop_on_failure=True,
Craig Tiller883064c2015-11-04 10:06:10 -08001162 newline_on_success=newline_on_success, travis=args.travis)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001163
1164 out = []
1165 if number_failures:
1166 out.append(BuildAndRunError.POST_TEST)
1167 if num_test_failures:
1168 out.append(BuildAndRunError.TEST)
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +02001169
Craig Tiller69cd2372015-06-11 09:38:09 -07001170 if cache: cache.save()
1171
Craig Tillereb9de8b2016-01-08 08:57:41 -08001172 return out
ctiller3040cb72015-01-07 12:13:17 -08001173
1174
David Klempner25739582015-02-11 15:57:32 -08001175test_cache = TestCache(runs_per_test == 1)
Craig Tiller547db2b2015-01-30 14:08:39 -08001176test_cache.maybe_load()
Craig Tiller71735182015-01-15 17:07:13 -08001177
ctiller3040cb72015-01-07 12:13:17 -08001178if forever:
Nicolas Noble044db742015-01-14 16:57:24 -08001179 success = True
ctiller3040cb72015-01-07 12:13:17 -08001180 while True:
Craig Tiller42bc87c2015-02-23 08:50:19 -08001181 dw = watch_dirs.DirWatcher(['src', 'include', 'test', 'examples'])
ctiller3040cb72015-01-07 12:13:17 -08001182 initial_time = dw.most_recent_change()
1183 have_files_changed = lambda: dw.most_recent_change() != initial_time
Nicolas Noble044db742015-01-14 16:57:24 -08001184 previous_success = success
Craig Tillereb9de8b2016-01-08 08:57:41 -08001185 errors = _build_and_run(check_cancelled=have_files_changed,
1186 newline_on_success=False,
1187 cache=test_cache,
1188 build_only=args.build_only) == 0
1189 if not previous_success and not errors:
Nicolas Nobleb09078f2015-01-14 18:06:05 -08001190 jobset.message('SUCCESS',
1191 'All tests are now passing properly',
1192 do_newline=True)
Nicolas Noble044db742015-01-14 16:57:24 -08001193 jobset.message('IDLE', 'No change detected')
ctiller3040cb72015-01-07 12:13:17 -08001194 while not have_files_changed():
1195 time.sleep(1)
1196else:
Craig Tillereb9de8b2016-01-08 08:57:41 -08001197 errors = _build_and_run(check_cancelled=lambda: False,
Craig Tiller71735182015-01-15 17:07:13 -08001198 newline_on_success=args.newline_on_success,
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +02001199 cache=test_cache,
Jan Tattermusch2dd156e2015-12-04 18:26:17 -08001200 xml_report=args.xml_report,
1201 build_only=args.build_only)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001202 if not errors:
Nicolas Nobleb09078f2015-01-14 18:06:05 -08001203 jobset.message('SUCCESS', 'All tests passed', do_newline=True)
1204 else:
1205 jobset.message('FAILED', 'Some tests failed', do_newline=True)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001206 exit_code = 0
1207 if BuildAndRunError.BUILD in errors:
1208 exit_code |= 1
Craig Tiller4f2be362016-01-08 08:59:20 -08001209 if BuildAndRunError.TEST in errors and not args.travis:
Craig Tillereb9de8b2016-01-08 08:57:41 -08001210 exit_code |= 2
Craig Tiller4f2be362016-01-08 08:59:20 -08001211 if BuildAndRunError.POST_TEST in errors:
1212 exit_code |= 4
Craig Tillereb9de8b2016-01-08 08:57:41 -08001213 sys.exit(exit_code)