blob: 7ce3ed02a395b6ed8bbd0f5c15d988d70cf9267e [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
Craig Tiller2cc2b842015-02-27 11:38:31 -080058ROOT = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), '../..'))
59os.chdir(ROOT)
60
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
Craig Tillerc7449162015-01-16 14:42:10 -0800126class CLanguage(object):
127
Craig Tillere9c959d2015-01-18 10:23:26 -0800128 def __init__(self, make_target, test_lang):
Craig Tillerc7449162015-01-16 14:42:10 -0800129 self.make_target = make_target
Craig Tillerd50993d2015-08-05 08:04:36 -0700130 self.platform = platform_string()
Craig Tiller711bbe62015-08-19 12:35:16 -0700131 self.test_lang = test_lang
Craig Tillerc7449162015-01-16 14:42:10 -0800132
Jan Tattermusch77db4322016-02-20 20:19:35 -0800133 def configure(self, config, args):
134 self.config = config
135 self.args = args
136 if self.platform == 'windows':
Jan Tattermuschc96caf82016-02-22 17:31:02 -0800137 self._make_options = [_windows_toolset_option(self.args.compiler),
138 _windows_arch_option(self.args.arch)]
Jan Tattermusch77db4322016-02-20 20:19:35 -0800139 else:
140 _check_compiler(self.args.compiler, ['default'])
Jan Tattermuschc96caf82016-02-22 17:31:02 -0800141 self._make_options = []
Jan Tattermusch77db4322016-02-20 20:19:35 -0800142
143 def test_specs(self):
Craig Tiller547db2b2015-01-30 14:08:39 -0800144 out = []
Jan Tattermusch77db4322016-02-20 20:19:35 -0800145 binaries = get_c_tests(self.args.travis, self.test_lang)
Craig Tiller711bbe62015-08-19 12:35:16 -0700146 for target in binaries:
Jan Tattermusch77db4322016-02-20 20:19:35 -0800147 if self.config.build_config in target['exclude_configs']:
murgatroid99fafeeb32015-09-22 09:13:03 -0700148 continue
Nicolas Noblee1445362015-05-11 17:40:26 -0700149 if self.platform == 'windows':
Jan Tattermusch3de6b762016-01-28 11:38:11 -0800150 binary = 'vsprojects/%s%s/%s.exe' % (
Jan Tattermusch77db4322016-02-20 20:19:35 -0800151 'x64/' if self.args.arch == 'x64' else '',
Jan Tattermuscha2d964c2016-02-22 17:33:09 -0800152 _MSBUILD_CONFIG[self.config.build_config],
Jan Tattermusch3de6b762016-01-28 11:38:11 -0800153 target['name'])
Nicolas Noblee1445362015-05-11 17:40:26 -0700154 else:
Jan Tattermusch77db4322016-02-20 20:19:35 -0800155 binary = 'bins/%s/%s' % (self.config.build_config, target['name'])
yang-g6c1fdc62015-08-18 11:57:42 -0700156 if os.path.isfile(binary):
Craig Tiller0fe5ee72015-12-22 12:50:36 -0800157 cmdline = [binary] + target['args']
Jan Tattermusch77db4322016-02-20 20:19:35 -0800158 out.append(self.config.job_spec(cmdline, [binary],
159 shortname=' '.join(cmdline),
160 cpu_cost=target['cpu_cost'],
161 environ={'GRPC_DEFAULT_SSL_ROOTS_FILE_PATH':
162 os.path.abspath(os.path.dirname(
163 sys.argv[0]) + '/../../src/core/tsi/test_creds/ca.pem')}))
164 elif self.args.regex == '.*' or self.platform == 'windows':
Adele Zhoue4c35612015-10-16 15:34:23 -0700165 print '\nWARNING: binary not found, skipping', binary
Nicolas Noblee1445362015-05-11 17:40:26 -0700166 return sorted(out)
Craig Tillerc7449162015-01-16 14:42:10 -0800167
Jan Tattermusch77db4322016-02-20 20:19:35 -0800168 def make_targets(self):
169 test_regex = self.args.regex
170 if self.platform != 'windows' and self.args.regex != '.*':
Craig Tiller883064c2015-11-04 10:06:10 -0800171 # use the regex to minimize the number of things to build
Craig Tillerb0f275e2016-01-27 10:45:50 -0800172 return [os.path.basename(target['name'])
Craig Tiller883064c2015-11-04 10:06:10 -0800173 for target in get_c_tests(False, self.test_lang)
Craig Tillerb0f275e2016-01-27 10:45:50 -0800174 if re.search(test_regex, '/' + target['name'])]
Jan Tattermusch77db4322016-02-20 20:19:35 -0800175 if self.platform == 'windows':
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700176 # don't build tools on windows just yet
177 return ['buildtests_%s' % self.make_target]
Craig Tiller7552f0f2015-06-19 17:46:20 -0700178 return ['buildtests_%s' % self.make_target, 'tools_%s' % self.make_target]
Craig Tillerc7449162015-01-16 14:42:10 -0800179
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800180 def make_options(self):
Jan Tattermuschc96caf82016-02-22 17:31:02 -0800181 return self._make_options;
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800182
murgatroid99256d3df2015-09-21 16:58:02 -0700183 def pre_build_steps(self):
Jan Tattermusch874aec02015-10-07 19:26:19 -0700184 if self.platform == 'windows':
185 return [['tools\\run_tests\\pre_build_c.bat']]
186 else:
187 return []
murgatroid99256d3df2015-09-21 16:58:02 -0700188
Craig Tillerc7449162015-01-16 14:42:10 -0800189 def build_steps(self):
190 return []
191
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200192 def post_tests_steps(self):
193 if self.platform == 'windows':
194 return []
195 else:
196 return [['tools/run_tests/post_tests_c.sh']]
197
murgatroid99a3e244f2015-09-22 11:25:53 -0700198 def makefile_name(self):
199 return 'Makefile'
200
Jan Tattermusch77db4322016-02-20 20:19:35 -0800201 def dockerfile_dir(self):
202 return 'tools/dockerfile/test/cxx_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800203
murgatroid99132ce6a2015-03-04 17:29:14 -0800204 def __str__(self):
205 return self.make_target
206
Craig Tillercc0535d2015-12-08 15:14:47 -0800207
murgatroid992c8d5162015-01-26 10:41:21 -0800208class NodeLanguage(object):
209
Jan Tattermusche477b842016-02-06 22:19:01 -0800210 def __init__(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800211 self.platform = platform_string()
Jan Tattermusche477b842016-02-06 22:19:01 -0800212 self.node_version = '0.12'
213
Jan Tattermusch77db4322016-02-20 20:19:35 -0800214 def configure(self, config, args):
215 self.config = config
216 self.args = args
217 _check_compiler(self.args.compiler, ['default'])
218
219 def test_specs(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800220 if self.platform == 'windows':
Jan Tattermusch77db4322016-02-20 20:19:35 -0800221 return [self.config.job_spec(['tools\\run_tests\\run_node.bat'], None)]
Michael Lumishaaa876a2016-02-10 15:27:58 -0800222 else:
Jan Tattermusch77db4322016-02-20 20:19:35 -0800223 return [self.config.job_spec(['tools/run_tests/run_node.sh', self.node_version],
224 None,
225 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
murgatroid992c8d5162015-01-26 10:41:21 -0800226
murgatroid99256d3df2015-09-21 16:58:02 -0700227 def pre_build_steps(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800228 if self.platform == 'windows':
229 return [['tools\\run_tests\\pre_build_node.bat']]
230 else:
231 return [['tools/run_tests/pre_build_node.sh', self.node_version]]
murgatroid99256d3df2015-09-21 16:58:02 -0700232
Jan Tattermusch77db4322016-02-20 20:19:35 -0800233 def make_targets(self):
murgatroid99db5b1602015-10-01 13:20:11 -0700234 return []
murgatroid992c8d5162015-01-26 10:41:21 -0800235
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800236 def make_options(self):
237 return []
238
murgatroid992c8d5162015-01-26 10:41:21 -0800239 def build_steps(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800240 if self.platform == 'windows':
241 return [['tools\\run_tests\\build_node.bat']]
242 else:
243 return [['tools/run_tests/build_node.sh', self.node_version]]
Craig Tillerc7449162015-01-16 14:42:10 -0800244
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200245 def post_tests_steps(self):
246 return []
247
murgatroid99a3e244f2015-09-22 11:25:53 -0700248 def makefile_name(self):
249 return 'Makefile'
250
Jan Tattermusch77db4322016-02-20 20:19:35 -0800251 def dockerfile_dir(self):
252 return 'tools/dockerfile/test/node_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800253
murgatroid99132ce6a2015-03-04 17:29:14 -0800254 def __str__(self):
255 return 'node'
256
Craig Tiller99775822015-01-30 13:07:16 -0800257
Craig Tillerc7449162015-01-16 14:42:10 -0800258class PhpLanguage(object):
259
Jan Tattermusch77db4322016-02-20 20:19:35 -0800260 def configure(self, config, args):
261 self.config = config
262 self.args = args
263 _check_compiler(self.args.compiler, ['default'])
264
265 def test_specs(self):
266 return [self.config.job_spec(['src/php/bin/run_tests.sh'], None,
267 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
Craig Tillerc7449162015-01-16 14:42:10 -0800268
murgatroid99256d3df2015-09-21 16:58:02 -0700269 def pre_build_steps(self):
270 return []
271
Jan Tattermusch77db4322016-02-20 20:19:35 -0800272 def make_targets(self):
Craig Tilleraf7cf542015-05-22 10:07:34 -0700273 return ['static_c', 'shared_c']
Craig Tillerc7449162015-01-16 14:42:10 -0800274
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800275 def make_options(self):
276 return []
277
Craig Tillerc7449162015-01-16 14:42:10 -0800278 def build_steps(self):
279 return [['tools/run_tests/build_php.sh']]
280
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200281 def post_tests_steps(self):
Stanley Cheunga6b95482016-01-13 16:10:48 -0800282 return [['tools/run_tests/post_tests_php.sh']]
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200283
murgatroid99a3e244f2015-09-22 11:25:53 -0700284 def makefile_name(self):
285 return 'Makefile'
286
Jan Tattermusch77db4322016-02-20 20:19:35 -0800287 def dockerfile_dir(self):
288 return 'tools/dockerfile/test/php_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800289
murgatroid99132ce6a2015-03-04 17:29:14 -0800290 def __str__(self):
291 return 'php'
292
Craig Tillerc7449162015-01-16 14:42:10 -0800293
Nathaniel Manista840615e2015-01-22 20:31:47 +0000294class PythonLanguage(object):
295
Craig Tiller49f61322015-03-03 13:02:11 -0800296 def __init__(self):
Masood Malekghassemi2b841622015-07-28 17:39:02 -0700297 self._build_python_versions = ['2.7']
Masood Malekghassemie5f70022015-06-29 09:20:26 -0700298 self._has_python_versions = []
Craig Tiller49f61322015-03-03 13:02:11 -0800299
Jan Tattermusch77db4322016-02-20 20:19:35 -0800300 def configure(self, config, args):
301 self.config = config
302 self.args = args
303 _check_compiler(self.args.compiler, ['default'])
304
305 def test_specs(self):
Masood Malekghassemi2b841622015-07-28 17:39:02 -0700306 environment = dict(_FORCE_ENVIRON_FOR_WRAPPERS)
307 environment['PYVER'] = '2.7'
Jan Tattermusch77db4322016-02-20 20:19:35 -0800308 return [self.config.job_spec(
Masood Malekghassemi2b841622015-07-28 17:39:02 -0700309 ['tools/run_tests/run_python.sh'],
310 None,
311 environ=environment,
312 shortname='py.test',
Masood Malekghassemi26ea9e22015-10-09 15:19:17 -0700313 timeout_seconds=15*60
Masood Malekghassemi2b841622015-07-28 17:39:02 -0700314 )]
Nathaniel Manista840615e2015-01-22 20:31:47 +0000315
murgatroid99256d3df2015-09-21 16:58:02 -0700316 def pre_build_steps(self):
317 return []
318
Jan Tattermusch77db4322016-02-20 20:19:35 -0800319 def make_targets(self):
Craig Tilleraf7cf542015-05-22 10:07:34 -0700320 return ['static_c', 'grpc_python_plugin', 'shared_c']
Nathaniel Manista840615e2015-01-22 20:31:47 +0000321
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800322 def make_options(self):
323 return []
324
Nathaniel Manista840615e2015-01-22 20:31:47 +0000325 def build_steps(self):
Masood Malekghassemie5f70022015-06-29 09:20:26 -0700326 commands = []
327 for python_version in self._build_python_versions:
328 try:
329 with open(os.devnull, 'w') as output:
330 subprocess.check_call(['which', 'python' + python_version],
331 stdout=output, stderr=output)
332 commands.append(['tools/run_tests/build_python.sh', python_version])
333 self._has_python_versions.append(python_version)
334 except:
335 jobset.message('WARNING', 'Missing Python ' + python_version,
336 do_newline=True)
337 return commands
Nathaniel Manista840615e2015-01-22 20:31:47 +0000338
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200339 def post_tests_steps(self):
340 return []
341
murgatroid99a3e244f2015-09-22 11:25:53 -0700342 def makefile_name(self):
343 return 'Makefile'
344
Jan Tattermusch77db4322016-02-20 20:19:35 -0800345 def dockerfile_dir(self):
346 return 'tools/dockerfile/test/python_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800347
murgatroid99132ce6a2015-03-04 17:29:14 -0800348 def __str__(self):
349 return 'python'
350
Craig Tillerd625d812015-04-08 15:52:35 -0700351
murgatroid996a4c4fa2015-02-27 12:08:57 -0800352class RubyLanguage(object):
353
Jan Tattermusch77db4322016-02-20 20:19:35 -0800354 def configure(self, config, args):
355 self.config = config
356 self.args = args
357 _check_compiler(self.args.compiler, ['default'])
358
359 def test_specs(self):
360 return [self.config.job_spec(['tools/run_tests/run_ruby.sh'], None,
361 timeout_seconds=10*60,
362 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
murgatroid996a4c4fa2015-02-27 12:08:57 -0800363
murgatroid99256d3df2015-09-21 16:58:02 -0700364 def pre_build_steps(self):
Nicolas "Pixel" Noblebcf988f2015-10-08 03:00:42 +0200365 return [['tools/run_tests/pre_build_ruby.sh']]
murgatroid99256d3df2015-09-21 16:58:02 -0700366
Craig Tiller883064c2015-11-04 10:06:10 -0800367 def make_targets(self, test_regex):
murgatroid997d243df2016-02-18 09:58:05 -0800368 return []
murgatroid996a4c4fa2015-02-27 12:08:57 -0800369
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800370 def make_options(self):
371 return []
372
murgatroid996a4c4fa2015-02-27 12:08:57 -0800373 def build_steps(self):
374 return [['tools/run_tests/build_ruby.sh']]
375
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200376 def post_tests_steps(self):
Nicolas "Pixel" Noble7ef1e532015-12-02 00:55:33 +0100377 return [['tools/run_tests/post_tests_ruby.sh']]
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200378
murgatroid99a3e244f2015-09-22 11:25:53 -0700379 def makefile_name(self):
380 return 'Makefile'
381
Jan Tattermusch77db4322016-02-20 20:19:35 -0800382 def dockerfile_dir(self):
383 return 'tools/dockerfile/test/ruby_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800384
murgatroid99132ce6a2015-03-04 17:29:14 -0800385 def __str__(self):
386 return 'ruby'
387
Craig Tillerd625d812015-04-08 15:52:35 -0700388
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800389class CSharpLanguage(object):
Jan Tattermusch77db4322016-02-20 20:19:35 -0800390
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700391 def __init__(self):
Craig Tillerd50993d2015-08-05 08:04:36 -0700392 self.platform = platform_string()
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700393
Jan Tattermusch77db4322016-02-20 20:19:35 -0800394 def configure(self, config, args):
395 self.config = config
396 self.args = args
397 _check_compiler(self.args.compiler, ['default'])
398
399 def test_specs(self):
Jan Tattermusch03c01062015-12-11 14:28:56 -0800400 with open('src/csharp/tests.json') as f:
401 tests_json = json.load(f)
402 assemblies = tests_json['assemblies']
403 tests = tests_json['tests']
404
Jan Tattermuscha2d964c2016-02-22 17:33:09 -0800405 msbuild_config = _MSBUILD_CONFIG[self.config.build_config]
Jan Tattermusch03c01062015-12-11 14:28:56 -0800406 assembly_files = ['%s/bin/%s/%s.dll' % (a, msbuild_config, a)
407 for a in assemblies]
408
409 extra_args = ['-labels'] + assembly_files
410
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700411 if self.platform == 'windows':
Jan Tattermusch03c01062015-12-11 14:28:56 -0800412 script_name = 'tools\\run_tests\\run_csharp.bat'
413 extra_args += ['-domain=None']
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700414 else:
Jan Tattermusch03c01062015-12-11 14:28:56 -0800415 script_name = 'tools/run_tests/run_csharp.sh'
Jan Tattermuschbf3b1532015-10-26 10:24:42 -0700416
Jan Tattermusch77db4322016-02-20 20:19:35 -0800417 if self.config.build_config == 'gcov':
Jan Tattermuschbdf4b2e2015-10-28 08:22:34 -0700418 # On Windows, we only collect C# code coverage.
419 # On Linux, we only collect coverage for native extension.
420 # For code coverage all tests need to run as one suite.
Jan Tattermusch77db4322016-02-20 20:19:35 -0800421 return [self.config.job_spec([script_name] + extra_args, None,
422 shortname='csharp.coverage',
423 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
Jan Tattermusch61c3a832015-10-27 17:54:50 -0700424 else:
Jan Tattermusch03c01062015-12-11 14:28:56 -0800425 specs = []
426 for test in tests:
427 cmdline = [script_name, '-run=%s' % test] + extra_args
428 if self.platform == 'windows':
429 # use different output directory for each test to prevent
430 # TestResult.xml clash between parallel test runs.
431 cmdline += ['-work=test-result/%s' % uuid.uuid4()]
Jan Tattermusch77db4322016-02-20 20:19:35 -0800432 specs.append(self.config.job_spec(cmdline, None,
433 shortname='csharp.%s' % test,
434 environ=_FORCE_ENVIRON_FOR_WRAPPERS))
Jan Tattermusch03c01062015-12-11 14:28:56 -0800435 return specs
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800436
murgatroid99256d3df2015-09-21 16:58:02 -0700437 def pre_build_steps(self):
Jan Tattermusch48423fc2015-10-07 18:59:16 -0700438 if self.platform == 'windows':
Jan Tattermusch874aec02015-10-07 19:26:19 -0700439 return [['tools\\run_tests\\pre_build_csharp.bat']]
Jan Tattermusch48423fc2015-10-07 18:59:16 -0700440 else:
441 return [['tools/run_tests/pre_build_csharp.sh']]
murgatroid99256d3df2015-09-21 16:58:02 -0700442
Jan Tattermusch77db4322016-02-20 20:19:35 -0800443 def make_targets(self):
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700444 # For Windows, this target doesn't really build anything,
445 # everything is build by buildall script later.
Craig Tillerd5904822015-08-31 21:30:58 -0700446 if self.platform == 'windows':
447 return []
448 else:
449 return ['grpc_csharp_ext']
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800450
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800451 def make_options(self):
452 if self.platform == 'mac':
453 # On Mac, official distribution of mono is 32bit.
454 return ['CFLAGS=-arch i386', 'LDFLAGS=-arch i386']
455 else:
456 return []
457
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800458 def build_steps(self):
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700459 if self.platform == 'windows':
460 return [['src\\csharp\\buildall.bat']]
461 else:
462 return [['tools/run_tests/build_csharp.sh']]
Nathaniel Manista840615e2015-01-22 20:31:47 +0000463
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200464 def post_tests_steps(self):
465 return []
466
murgatroid99a3e244f2015-09-22 11:25:53 -0700467 def makefile_name(self):
468 return 'Makefile'
469
Jan Tattermusch77db4322016-02-20 20:19:35 -0800470 def dockerfile_dir(self):
471 return 'tools/dockerfile/test/csharp_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800472
murgatroid99132ce6a2015-03-04 17:29:14 -0800473 def __str__(self):
474 return 'csharp'
475
Craig Tillerd625d812015-04-08 15:52:35 -0700476
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700477class ObjCLanguage(object):
478
Jan Tattermusch77db4322016-02-20 20:19:35 -0800479 def configure(self, config, args):
480 self.config = config
481 self.args = args
482 _check_compiler(self.args.compiler, ['default'])
483
484 def test_specs(self):
485 return [self.config.job_spec(['src/objective-c/tests/run_tests.sh'], None,
486 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700487
murgatroid99256d3df2015-09-21 16:58:02 -0700488 def pre_build_steps(self):
489 return []
490
Jan Tattermusch77db4322016-02-20 20:19:35 -0800491 def make_targets(self):
Jorge Canizalesd0b32e92015-07-30 23:08:43 -0700492 return ['grpc_objective_c_plugin', 'interop_server']
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700493
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800494 def make_options(self):
495 return []
496
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700497 def build_steps(self):
Jorge Canizalesd0b32e92015-07-30 23:08:43 -0700498 return [['src/objective-c/tests/build_tests.sh']]
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700499
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200500 def post_tests_steps(self):
501 return []
502
murgatroid99a3e244f2015-09-22 11:25:53 -0700503 def makefile_name(self):
504 return 'Makefile'
505
Jan Tattermusch77db4322016-02-20 20:19:35 -0800506 def dockerfile_dir(self):
Jan Tattermusch788ee232016-01-26 12:19:44 -0800507 return None
508
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700509 def __str__(self):
510 return 'objc'
511
512
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100513class Sanity(object):
514
Jan Tattermusch77db4322016-02-20 20:19:35 -0800515 def configure(self, config, args):
516 self.config = config
517 self.args = args
518 _check_compiler(self.args.compiler, ['default'])
519
520 def test_specs(self):
Craig Tiller94d04a52016-01-20 10:58:23 -0800521 import yaml
Jan Tattermusch788ee232016-01-26 12:19:44 -0800522 with open('tools/run_tests/sanity/sanity_tests.yaml', 'r') as f:
Jan Tattermusch77db4322016-02-20 20:19:35 -0800523 return [self.config.job_spec(cmd['script'].split(), None,
524 timeout_seconds=None, environ={'TEST': 'true'},
525 cpu_cost=cmd.get('cpu_cost', 1))
Craig Tiller94d04a52016-01-20 10:58:23 -0800526 for cmd in yaml.load(f)]
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100527
murgatroid99256d3df2015-09-21 16:58:02 -0700528 def pre_build_steps(self):
529 return []
530
Jan Tattermusch77db4322016-02-20 20:19:35 -0800531 def make_targets(self):
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100532 return ['run_dep_checks']
533
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800534 def make_options(self):
535 return []
536
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100537 def build_steps(self):
538 return []
539
Nicolas "Pixel" Noble87879b32015-10-12 23:28:53 +0200540 def post_tests_steps(self):
541 return []
542
murgatroid99a3e244f2015-09-22 11:25:53 -0700543 def makefile_name(self):
544 return 'Makefile'
545
Jan Tattermusch77db4322016-02-20 20:19:35 -0800546 def dockerfile_dir(self):
Jan Tattermusche70b3c52016-02-07 20:21:02 -0800547 return 'tools/dockerfile/test/sanity'
Jan Tattermusch788ee232016-01-26 12:19:44 -0800548
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100549 def __str__(self):
550 return 'sanity'
551
Nicolas "Pixel" Noblee55cd7f2015-04-14 17:59:13 +0200552
Craig Tiller738c3342015-01-12 14:28:33 -0800553# different configurations we can run under
Craig Tillera0f85172016-01-20 15:56:06 -0800554with open('tools/run_tests/configs.json') as f:
Craig Tiller1dce9062016-01-20 17:01:56 -0800555 _CONFIGS = dict((cfg['config'], Config(**cfg)) for cfg in ast.literal_eval(f.read()))
Craig Tiller738c3342015-01-12 14:28:33 -0800556
557
Craig Tillerc7449162015-01-16 14:42:10 -0800558_LANGUAGES = {
Craig Tillere9c959d2015-01-18 10:23:26 -0800559 'c++': CLanguage('cxx', 'c++'),
560 'c': CLanguage('c', 'c'),
murgatroid992c8d5162015-01-26 10:41:21 -0800561 'node': NodeLanguage(),
Nathaniel Manista840615e2015-01-22 20:31:47 +0000562 'php': PhpLanguage(),
563 'python': PythonLanguage(),
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800564 'ruby': RubyLanguage(),
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100565 'csharp': CSharpLanguage(),
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700566 'objc' : ObjCLanguage(),
Jan Tattermusch70a57e42016-02-20 18:50:27 -0800567 'sanity': Sanity()
Craig Tillereb272bc2015-01-30 13:13:14 -0800568 }
Nicolas Nobleddef2462015-01-06 18:08:25 -0800569
Jan Tattermusch77db4322016-02-20 20:19:35 -0800570
Jan Tattermuscha2d964c2016-02-22 17:33:09 -0800571_MSBUILD_CONFIG = {
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700572 'dbg': 'Debug',
573 'opt': 'Release',
Jan Tattermusche4a69182015-12-15 09:53:01 -0800574 'gcov': 'Debug',
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700575 }
576
David Garcia Quintase90cd372015-05-31 18:15:26 -0700577
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800578def _windows_arch_option(arch):
579 """Returns msbuild cmdline option for selected architecture."""
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800580 if arch == 'default' or arch == 'x86':
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800581 return '/p:Platform=Win32'
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800582 elif arch == 'x64':
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800583 return '/p:Platform=x64'
584 else:
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800585 print 'Architecture %s not supported.' % arch
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800586 sys.exit(1)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800587
Jan Tattermuschf08018a2016-01-26 08:22:09 -0800588
589def _check_arch_option(arch):
590 """Checks that architecture option is valid."""
591 if platform_string() == 'windows':
592 _windows_arch_option(arch)
593 elif platform_string() == 'linux':
594 # On linux, we need to be running under docker with the right architecture.
Jan Tattermusch07fb0422016-01-26 10:46:56 -0800595 runtime_arch = platform.architecture()[0]
Jan Tattermuschf08018a2016-01-26 08:22:09 -0800596 if arch == 'default':
597 return
598 elif runtime_arch == '64bit' and arch == 'x64':
599 return
600 elif runtime_arch == '32bit' and arch == 'x86':
601 return
602 else:
603 print 'Architecture %s does not match current runtime architecture.' % arch
604 sys.exit(1)
605 else:
606 if args.arch != 'default':
607 print 'Architecture %s not supported on current platform.' % args.arch
608 sys.exit(1)
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800609
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800610
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800611def _windows_build_bat(compiler):
612 """Returns name of build.bat for selected compiler."""
613 if compiler == 'default' or compiler == 'vs2013':
614 return 'vsprojects\\build_vs2013.bat'
615 elif compiler == 'vs2015':
616 return 'vsprojects\\build_vs2015.bat'
617 elif compiler == 'vs2010':
618 return 'vsprojects\\build_vs2010.bat'
619 else:
620 print 'Compiler %s not supported.' % compiler
621 sys.exit(1)
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800622
623
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800624def _windows_toolset_option(compiler):
625 """Returns msbuild PlatformToolset for selected compiler."""
626 if compiler == 'default' or compiler == 'vs2013':
627 return '/p:PlatformToolset=v120'
628 elif compiler == 'vs2015':
629 return '/p:PlatformToolset=v140'
630 elif compiler == 'vs2010':
631 return '/p:PlatformToolset=v100'
632 else:
633 print 'Compiler %s not supported.' % compiler
634 sys.exit(1)
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800635
636
Jan Tattermusche70b3c52016-02-07 20:21:02 -0800637def _docker_arch_suffix(arch):
638 """Returns suffix to dockerfile dir to use."""
639 if arch == 'default' or arch == 'x64':
640 return 'x64'
641 elif arch == 'x86':
642 return 'x86'
643 else:
644 print 'Architecture %s not supported with current settings.' % arch
645 sys.exit(1)
646
647
Jan Tattermusch788ee232016-01-26 12:19:44 -0800648def _get_dockerfile_dir(language, cfg, arch):
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800649 """Returns dockerfile to use"""
Jan Tattermusch788ee232016-01-26 12:19:44 -0800650 custom = language.dockerfile_dir(cfg, arch)
651 if custom:
652 return custom
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800653 else:
Jan Tattermusche70b3c52016-02-07 20:21:02 -0800654 return 'tools/dockerfile/grpc_tests_multilang_%s' % _docker_arch_suffix(arch)
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800655
David Garcia Quintase90cd372015-05-31 18:15:26 -0700656def runs_per_test_type(arg_str):
657 """Auxilary function to parse the "runs_per_test" flag.
658
659 Returns:
660 A positive integer or 0, the latter indicating an infinite number of
661 runs.
662
663 Raises:
664 argparse.ArgumentTypeError: Upon invalid input.
665 """
666 if arg_str == 'inf':
667 return 0
668 try:
669 n = int(arg_str)
670 if n <= 0: raise ValueError
Craig Tiller50e53e22015-06-01 20:18:21 -0700671 return n
David Garcia Quintase90cd372015-05-31 18:15:26 -0700672 except:
Adele Zhoue4c35612015-10-16 15:34:23 -0700673 msg = '\'{}\' is not a positive integer or \'inf\''.format(arg_str)
David Garcia Quintase90cd372015-05-31 18:15:26 -0700674 raise argparse.ArgumentTypeError(msg)
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700675
676# parse command line
677argp = argparse.ArgumentParser(description='Run grpc tests.')
678argp.add_argument('-c', '--config',
Jan Tattermusch77db4322016-02-20 20:19:35 -0800679 choices=sorted(_CONFIGS.keys()),
680 default='opt')
David Garcia Quintase90cd372015-05-31 18:15:26 -0700681argp.add_argument('-n', '--runs_per_test', default=1, type=runs_per_test_type,
682 help='A positive integer or "inf". If "inf", all tests will run in an '
683 'infinite loop. Especially useful in combination with "-f"')
Craig Tillerfe406ec2015-02-24 13:55:12 -0800684argp.add_argument('-r', '--regex', default='.*', type=str)
Craig Tiller5f735a62016-01-20 09:31:15 -0800685argp.add_argument('-j', '--jobs', default=multiprocessing.cpu_count(), type=int)
Craig Tiller8451e872015-02-27 09:25:51 -0800686argp.add_argument('-s', '--slowdown', default=1.0, type=float)
ctiller3040cb72015-01-07 12:13:17 -0800687argp.add_argument('-f', '--forever',
688 default=False,
689 action='store_const',
690 const=True)
Nicolas "Pixel" Noblea7df3f92015-02-26 22:07:04 +0100691argp.add_argument('-t', '--travis',
692 default=False,
693 action='store_const',
694 const=True)
Nicolas Noble044db742015-01-14 16:57:24 -0800695argp.add_argument('--newline_on_success',
696 default=False,
697 action='store_const',
698 const=True)
Craig Tiller686fb262015-01-15 07:39:09 -0800699argp.add_argument('-l', '--language',
Craig Tiller60f15e62015-05-13 09:05:17 -0700700 choices=['all'] + sorted(_LANGUAGES.keys()),
Craig Tiller686fb262015-01-15 07:39:09 -0800701 nargs='+',
Craig Tiller60f15e62015-05-13 09:05:17 -0700702 default=['all'])
Craig Tillercd43da82015-05-29 08:41:29 -0700703argp.add_argument('-S', '--stop_on_failure',
704 default=False,
705 action='store_const',
706 const=True)
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700707argp.add_argument('--use_docker',
708 default=False,
709 action='store_const',
710 const=True,
Adele Zhoue4c35612015-10-16 15:34:23 -0700711 help='Run all the tests under docker. That provides ' +
712 'additional isolation and prevents the need to install ' +
713 'language specific prerequisites. Only available on Linux.')
Craig Tillerd4509a12015-09-28 09:18:40 -0700714argp.add_argument('--allow_flakes',
715 default=False,
716 action='store_const',
717 const=True,
Adele Zhoue4c35612015-10-16 15:34:23 -0700718 help='Allow flaky tests to show as passing (re-runs failed tests up to five times)')
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800719argp.add_argument('--arch',
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800720 choices=['default', 'x86', 'x64'],
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800721 default='default',
722 help='Selects architecture to target. For some platforms "default" is the only supported choice.')
723argp.add_argument('--compiler',
724 choices=['default', 'vs2010', 'vs2013', 'vs2015'],
725 default='default',
Jan Tattermusch77db4322016-02-20 20:19:35 -0800726 help='Selects compiler to use. Allowed values depend on the platform and language.')
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800727argp.add_argument('--build_only',
728 default=False,
729 action='store_const',
730 const=True,
731 help='Perform all the build steps but dont run any tests.')
Craig Tiller5f735a62016-01-20 09:31:15 -0800732argp.add_argument('--measure_cpu_costs', default=False, action='store_const', const=True,
733 help='Measure the cpu costs of tests')
Craig Tiller1676f912016-01-05 10:49:44 -0800734argp.add_argument('--update_submodules', default=[], nargs='*',
735 help='Update some submodules before building. If any are updated, also run generate_projects. ' +
736 'Submodules are specified as SUBMODULE_NAME:BRANCH; if BRANCH is omitted, master is assumed.')
Craig Tiller234b6e72015-05-23 10:12:40 -0700737argp.add_argument('-a', '--antagonists', default=0, type=int)
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +0200738argp.add_argument('-x', '--xml_report', default=None, type=str,
739 help='Generates a JUnit-compatible XML report')
Nicolas Nobleddef2462015-01-06 18:08:25 -0800740args = argp.parse_args()
741
Craig Tiller5f735a62016-01-20 09:31:15 -0800742jobset.measure_cpu_costs = args.measure_cpu_costs
743
Craig Tiller1676f912016-01-05 10:49:44 -0800744# update submodules if necessary
Craig Tillerb361b4e2016-01-06 11:44:17 -0800745need_to_regenerate_projects = False
746for spec in args.update_submodules:
747 spec = spec.split(':', 1)
748 if len(spec) == 1:
749 submodule = spec[0]
750 branch = 'master'
751 elif len(spec) == 2:
752 submodule = spec[0]
753 branch = spec[1]
754 cwd = 'third_party/%s' % submodule
755 def git(cmd, cwd=cwd):
756 print 'in %s: git %s' % (cwd, cmd)
757 subprocess.check_call('git %s' % cmd, cwd=cwd, shell=True)
758 git('fetch')
759 git('checkout %s' % branch)
760 git('pull origin %s' % branch)
761 if os.path.exists('src/%s/gen_build_yaml.py' % submodule):
762 need_to_regenerate_projects = True
763if need_to_regenerate_projects:
764 if jobset.platform_string() == 'linux':
765 subprocess.check_call('tools/buildgen/generate_projects.sh', shell=True)
766 else:
767 print 'WARNING: may need to regenerate projects, but since we are not on'
768 print ' Linux this step is being skipped. Compilation MAY fail.'
Craig Tiller1676f912016-01-05 10:49:44 -0800769
770
Nicolas Nobleddef2462015-01-06 18:08:25 -0800771# grab config
Jan Tattermusch77db4322016-02-20 20:19:35 -0800772run_config = _CONFIGS[args.config]
773build_config = run_config.build_config
Craig Tillerf1973b02015-01-16 12:32:13 -0800774
Craig Tiller06805272015-06-11 14:46:47 -0700775if args.travis:
murgatroid99d3b5b7f2015-10-06 17:02:03 -0700776 _FORCE_ENVIRON_FOR_WRAPPERS = {'GRPC_TRACE': 'api'}
Craig Tiller06805272015-06-11 14:46:47 -0700777
Adele Zhou6b9527c2015-11-20 15:56:35 -0800778if 'all' in args.language:
Craig Tiller1676f912016-01-05 10:49:44 -0800779 lang_list = _LANGUAGES.keys()
Adele Zhou6b9527c2015-11-20 15:56:35 -0800780else:
781 lang_list = args.language
Craig Tiller16900662016-01-07 19:30:54 -0800782# We don't support code coverage on some languages
783if 'gcov' in args.config:
784 for bad in ['objc', 'sanity', 'build']:
785 if bad in lang_list:
786 lang_list.remove(bad)
Adele Zhou6b9527c2015-11-20 15:56:35 -0800787
788languages = set(_LANGUAGES[l] for l in lang_list)
Jan Tattermusch77db4322016-02-20 20:19:35 -0800789for l in languages:
790 l.configure(run_config, args)
murgatroid99132ce6a2015-03-04 17:29:14 -0800791
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800792language_make_options=[]
793if any(language.make_options() for language in languages):
794 if len(languages) != 1:
795 print 'languages with custom make options cannot be built simultaneously with other languages'
796 sys.exit(1)
797 else:
798 language_make_options = next(iter(languages)).make_options()
799
Jan Tattermusch77db4322016-02-20 20:19:35 -0800800if len(languages) != 1:
801 print 'Multi-language testing is not supported.'
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800802 sys.exit(1)
803
804if args.use_docker:
805 if not args.travis:
806 print 'Seen --use_docker flag, will run tests under docker.'
807 print
808 print 'IMPORTANT: The changes you are testing need to be locally committed'
809 print 'because only the committed changes in the current branch will be'
810 print 'copied to the docker environment.'
811 time.sleep(5)
812
813 child_argv = [ arg for arg in sys.argv if not arg == '--use_docker' ]
Jan Tattermusched342b12016-01-26 14:40:31 -0800814 run_tests_cmd = 'python tools/run_tests/run_tests.py %s' % ' '.join(child_argv[1:])
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800815
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800816 env = os.environ.copy()
817 env['RUN_TESTS_COMMAND'] = run_tests_cmd
Jan Tattermusch788ee232016-01-26 12:19:44 -0800818 env['DOCKERFILE_DIR'] = _get_dockerfile_dir(next(iter(languages)),
819 next(iter(build_configs)),
820 args.arch)
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800821 env['DOCKER_RUN_SCRIPT'] = 'tools/jenkins/docker_run_tests.sh'
822 if args.xml_report:
823 env['XML_REPORT'] = args.xml_report
824 if not args.travis:
825 env['TTY_FLAG'] = '-t' # enables Ctrl-C when not on Jenkins.
826
827 subprocess.check_call(['tools/jenkins/build_docker_and_run_tests.sh'],
828 shell=True,
829 env=env)
830 sys.exit(0)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800831
Jan Tattermuschf08018a2016-01-26 08:22:09 -0800832_check_arch_option(args.arch)
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800833
Jan Tattermuschfba65302016-01-25 18:21:14 -0800834def make_jobspec(cfg, targets, makefile='Makefile'):
835 if platform_string() == 'windows':
Craig Tillerfc3c0c42015-09-01 16:47:54 -0700836 extra_args = []
Craig Tillerb5391e12015-09-03 14:35:18 -0700837 # better do parallel compilation
Jan Tattermusch47eeb2b2015-10-07 14:09:18 -0700838 # empirically /m:2 gives the best performance/price and should prevent
839 # overloading the windows workers.
Adele Zhoue4c35612015-10-16 15:34:23 -0700840 extra_args.extend(['/m:2'])
Craig Tillerb5391e12015-09-03 14:35:18 -0700841 # disable PDB generation: it's broken, and we don't need it during CI
Adele Zhoue4c35612015-10-16 15:34:23 -0700842 extra_args.extend(['/p:Jenkins=true'])
Craig Tiller6fd23842015-09-01 07:36:31 -0700843 return [
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800844 jobset.JobSpec([_windows_build_bat(args.compiler),
murgatroid99cf08daf2015-09-21 15:33:16 -0700845 'vsprojects\\%s.sln' % target,
Jan Tattermuscha2d964c2016-02-22 17:33:09 -0800846 '/p:Configuration=%s' % _MSBUILD_CONFIG[cfg]] +
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800847 extra_args +
848 language_make_options,
Craig Tiller590105a2016-01-19 13:03:46 -0800849 shell=True, timeout_seconds=None)
Craig Tiller6fd23842015-09-01 07:36:31 -0700850 for target in targets]
Jan Tattermuschfba65302016-01-25 18:21:14 -0800851 else:
murgatroid998ae409f2015-10-26 16:39:00 -0700852 if targets:
853 return [jobset.JobSpec([os.getenv('MAKE', 'make'),
854 '-f', makefile,
Craig Tillerdd6f7ed2016-01-21 12:54:42 -0800855 '-j', '%d' % args.jobs,
Craig Tiller71a86042016-01-15 14:59:58 -0800856 'EXTRA_DEFINES=GRPC_TEST_SLOWDOWN_MACHINE_FACTOR=%f' % args.slowdown,
857 'CONFIG=%s' % cfg] +
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800858 language_make_options +
Craig Tiller71a86042016-01-15 14:59:58 -0800859 ([] if not args.travis else ['JENKINS_BUILD=1']) +
860 targets,
Craig Tiller590105a2016-01-19 13:03:46 -0800861 timeout_seconds=None)]
murgatroid998ae409f2015-10-26 16:39:00 -0700862 else:
863 return []
Jan Tattermuschfba65302016-01-25 18:21:14 -0800864
murgatroid99a3e244f2015-09-22 11:25:53 -0700865make_targets = {}
866for l in languages:
867 makefile = l.makefile_name()
868 make_targets[makefile] = make_targets.get(makefile, set()).union(
Jan Tattermusch77db4322016-02-20 20:19:35 -0800869 set(l.make_targets()))
Craig Tiller5058c692015-04-08 09:42:04 -0700870
Jan Tattermusche4a69182015-12-15 09:53:01 -0800871def build_step_environ(cfg):
872 environ = {'CONFIG': cfg}
Jan Tattermuscha2d964c2016-02-22 17:33:09 -0800873 msbuild_cfg = _MSBUILD_CONFIG.get(cfg)
Jan Tattermusche4a69182015-12-15 09:53:01 -0800874 if msbuild_cfg:
875 environ['MSBUILD_CONFIG'] = msbuild_cfg
876 return environ
877
murgatroid99fddac962015-09-22 09:20:11 -0700878build_steps = list(set(
Jan Tattermusch77db4322016-02-20 20:19:35 -0800879 jobset.JobSpec(cmdline, environ=build_step_environ(build_config), flake_retries=5)
murgatroid99256d3df2015-09-21 16:58:02 -0700880 for l in languages
881 for cmdline in l.pre_build_steps()))
Craig Tillerbd4e3782015-09-01 06:48:55 -0700882if make_targets:
Jan Tattermusch77db4322016-02-20 20:19:35 -0800883 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 -0700884 build_steps.extend(set(make_commands))
Craig Tiller5058c692015-04-08 09:42:04 -0700885build_steps.extend(set(
Jan Tattermusch77db4322016-02-20 20:19:35 -0800886 jobset.JobSpec(cmdline, environ=build_step_environ(build_config), timeout_seconds=None)
Craig Tiller547db2b2015-01-30 14:08:39 -0800887 for l in languages
Craig Tiller533b1a22015-05-29 08:41:29 -0700888 for cmdline in l.build_steps()))
Craig Tillerf1973b02015-01-16 12:32:13 -0800889
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200890post_tests_steps = list(set(
Jan Tattermusch77db4322016-02-20 20:19:35 -0800891 jobset.JobSpec(cmdline, environ=build_step_environ(build_config))
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200892 for l in languages
893 for cmdline in l.post_tests_steps()))
Nicolas Nobleddef2462015-01-06 18:08:25 -0800894runs_per_test = args.runs_per_test
ctiller3040cb72015-01-07 12:13:17 -0800895forever = args.forever
Nicolas Nobleddef2462015-01-06 18:08:25 -0800896
Nicolas Nobleddef2462015-01-06 18:08:25 -0800897
Craig Tiller71735182015-01-15 17:07:13 -0800898class TestCache(object):
Craig Tillerb50d1662015-01-15 17:28:21 -0800899 """Cache for running tests."""
900
David Klempner25739582015-02-11 15:57:32 -0800901 def __init__(self, use_cache_results):
Craig Tiller71735182015-01-15 17:07:13 -0800902 self._last_successful_run = {}
David Klempner25739582015-02-11 15:57:32 -0800903 self._use_cache_results = use_cache_results
Craig Tiller69cd2372015-06-11 09:38:09 -0700904 self._last_save = time.time()
Craig Tiller71735182015-01-15 17:07:13 -0800905
906 def should_run(self, cmdline, bin_hash):
Craig Tiller71735182015-01-15 17:07:13 -0800907 if cmdline not in self._last_successful_run:
908 return True
909 if self._last_successful_run[cmdline] != bin_hash:
910 return True
David Klempner25739582015-02-11 15:57:32 -0800911 if not self._use_cache_results:
912 return True
Craig Tiller71735182015-01-15 17:07:13 -0800913 return False
914
915 def finished(self, cmdline, bin_hash):
Craig Tiller547db2b2015-01-30 14:08:39 -0800916 self._last_successful_run[cmdline] = bin_hash
Craig Tiller69cd2372015-06-11 09:38:09 -0700917 if time.time() - self._last_save > 1:
918 self.save()
Craig Tiller71735182015-01-15 17:07:13 -0800919
920 def dump(self):
Craig Tillerb50d1662015-01-15 17:28:21 -0800921 return [{'cmdline': k, 'hash': v}
922 for k, v in self._last_successful_run.iteritems()]
Craig Tiller71735182015-01-15 17:07:13 -0800923
924 def parse(self, exdump):
925 self._last_successful_run = dict((o['cmdline'], o['hash']) for o in exdump)
926
927 def save(self):
928 with open('.run_tests_cache', 'w') as f:
Craig Tiller261dd982015-01-16 16:41:45 -0800929 f.write(json.dumps(self.dump()))
Craig Tiller69cd2372015-06-11 09:38:09 -0700930 self._last_save = time.time()
Craig Tiller71735182015-01-15 17:07:13 -0800931
Craig Tiller1cc11db2015-01-15 22:50:50 -0800932 def maybe_load(self):
933 if os.path.exists('.run_tests_cache'):
934 with open('.run_tests_cache') as f:
Craig Tiller261dd982015-01-16 16:41:45 -0800935 self.parse(json.loads(f.read()))
Craig Tiller71735182015-01-15 17:07:13 -0800936
937
Craig Tillerf53d9c82015-08-04 14:19:43 -0700938def _start_port_server(port_server_port):
939 # check if a compatible port server is running
940 # if incompatible (version mismatch) ==> start a new one
941 # if not running ==> start a new one
942 # otherwise, leave it up
943 try:
Craig Tillerfe4939f2015-10-06 12:55:36 -0700944 version = int(urllib2.urlopen(
945 'http://localhost:%d/version_number' % port_server_port,
946 timeout=1).read())
947 print 'detected port server running version %d' % version
Craig Tillerf53d9c82015-08-04 14:19:43 -0700948 running = True
Craig Tillerfe4939f2015-10-06 12:55:36 -0700949 except Exception as e:
Craig Tiller0d6499e2015-10-05 14:00:47 -0700950 print 'failed to detect port server: %s' % sys.exc_info()[0]
Craig Tillerfe4939f2015-10-06 12:55:36 -0700951 print e.strerror
Craig Tillerf53d9c82015-08-04 14:19:43 -0700952 running = False
953 if running:
Craig Tillerfe4939f2015-10-06 12:55:36 -0700954 current_version = int(subprocess.check_output(
Jan Tattermusch3bd08272015-11-04 19:24:37 -0800955 [sys.executable, os.path.abspath('tools/run_tests/port_server.py'),
956 'dump_version']))
Craig Tillerfe4939f2015-10-06 12:55:36 -0700957 print 'my port server is version %d' % current_version
958 running = (version >= current_version)
959 if not running:
960 print 'port_server version mismatch: killing the old one'
961 urllib2.urlopen('http://localhost:%d/quitquitquit' % port_server_port).read()
962 time.sleep(1)
Craig Tillerf53d9c82015-08-04 14:19:43 -0700963 if not running:
Craig Tillerf0a293e2015-10-12 10:05:50 -0700964 fd, logfile = tempfile.mkstemp()
965 os.close(fd)
966 print 'starting port_server, with log file %s' % logfile
Jan Tattermusch3bd08272015-11-04 19:24:37 -0800967 args = [sys.executable, os.path.abspath('tools/run_tests/port_server.py'),
968 '-p', '%d' % port_server_port, '-l', logfile]
Craig Tiller367d41d2015-10-12 13:00:22 -0700969 env = dict(os.environ)
970 env['BUILD_ID'] = 'pleaseDontKillMeJenkins'
Nicolas "Pixel" Noblef72d7b52015-12-03 03:07:43 +0100971 if platform_string() == 'windows':
Jan Tattermusch3bd08272015-11-04 19:24:37 -0800972 # Working directory of port server needs to be outside of Jenkins
973 # workspace to prevent file lock issues.
974 tempdir = tempfile.mkdtemp()
Craig Tillerd2c39712015-10-12 11:08:49 -0700975 port_server = subprocess.Popen(
Craig Tiller367d41d2015-10-12 13:00:22 -0700976 args,
977 env=env,
Jan Tattermusch3bd08272015-11-04 19:24:37 -0800978 cwd=tempdir,
Craig Tiller367d41d2015-10-12 13:00:22 -0700979 creationflags = 0x00000008, # detached process
980 close_fds=True)
Craig Tillerd2c39712015-10-12 11:08:49 -0700981 else:
982 port_server = subprocess.Popen(
983 args,
Craig Tiller367d41d2015-10-12 13:00:22 -0700984 env=env,
Craig Tillerd2c39712015-10-12 11:08:49 -0700985 preexec_fn=os.setsid,
986 close_fds=True)
Craig Tillerf0a293e2015-10-12 10:05:50 -0700987 time.sleep(1)
Craig Tiller8b5f4dc2015-08-26 08:02:01 -0700988 # ensure port server is up
Craig Tillerabd37fd2015-08-26 07:54:01 -0700989 waits = 0
Craig Tillerf53d9c82015-08-04 14:19:43 -0700990 while True:
Craig Tillerabd37fd2015-08-26 07:54:01 -0700991 if waits > 10:
Craig Tillerf0a293e2015-10-12 10:05:50 -0700992 print 'killing port server due to excessive start up waits'
Craig Tillerabd37fd2015-08-26 07:54:01 -0700993 port_server.kill()
Craig Tillera2f38b02015-09-24 11:19:17 -0700994 if port_server.poll() is not None:
Craig Tiller0d6499e2015-10-05 14:00:47 -0700995 print 'port_server failed to start'
Craig Tillerf0a293e2015-10-12 10:05:50 -0700996 # try one final time: maybe another build managed to start one
997 time.sleep(1)
998 try:
999 urllib2.urlopen('http://localhost:%d/get' % port_server_port,
1000 timeout=1).read()
1001 print 'last ditch attempt to contact port server succeeded'
1002 break
1003 except:
1004 traceback.print_exc();
1005 port_log = open(logfile, 'r').read()
1006 print port_log
1007 sys.exit(1)
Craig Tillerf53d9c82015-08-04 14:19:43 -07001008 try:
Craig Tillerabd37fd2015-08-26 07:54:01 -07001009 urllib2.urlopen('http://localhost:%d/get' % port_server_port,
1010 timeout=1).read()
Craig Tillerf0a293e2015-10-12 10:05:50 -07001011 print 'port server is up and ready'
Craig Tillerf53d9c82015-08-04 14:19:43 -07001012 break
Craig Tiller31fdaa42015-09-25 13:09:59 -07001013 except socket.timeout:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001014 print 'waiting for port_server: timeout'
Craig Tillerf0a293e2015-10-12 10:05:50 -07001015 traceback.print_exc();
1016 time.sleep(1)
Craig Tiller31fdaa42015-09-25 13:09:59 -07001017 waits += 1
Craig Tillerf53d9c82015-08-04 14:19:43 -07001018 except urllib2.URLError:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001019 print 'waiting for port_server: urlerror'
Craig Tillerf0a293e2015-10-12 10:05:50 -07001020 traceback.print_exc();
1021 time.sleep(1)
Craig Tillerabd37fd2015-08-26 07:54:01 -07001022 waits += 1
Craig Tillerf53d9c82015-08-04 14:19:43 -07001023 except:
Craig Tillerf0a293e2015-10-12 10:05:50 -07001024 traceback.print_exc();
Craig Tillerf53d9c82015-08-04 14:19:43 -07001025 port_server.kill()
1026 raise
1027
1028
Adele Zhoud5fffa52015-10-23 15:51:42 -07001029def _calculate_num_runs_failures(list_of_results):
1030 """Caculate number of runs and failures for a particular test.
1031
1032 Args:
1033 list_of_results: (List) of JobResult object.
1034 Returns:
1035 A tuple of total number of runs and failures.
1036 """
1037 num_runs = len(list_of_results) # By default, there is 1 run per JobResult.
1038 num_failures = 0
1039 for jobresult in list_of_results:
1040 if jobresult.retries > 0:
1041 num_runs += jobresult.retries
1042 if jobresult.num_failures > 0:
1043 num_failures += jobresult.num_failures
1044 return num_runs, num_failures
1045
Adele Zhou6b9527c2015-11-20 15:56:35 -08001046
Craig Tillereb9de8b2016-01-08 08:57:41 -08001047# _build_and_run results
1048class BuildAndRunError(object):
1049
1050 BUILD = object()
1051 TEST = object()
1052 POST_TEST = object()
1053
1054
1055# returns a list of things that failed (or an empty list on success)
Craig Tillerf53d9c82015-08-04 14:19:43 -07001056def _build_and_run(
Jan Tattermusch2dd156e2015-12-04 18:26:17 -08001057 check_cancelled, newline_on_success, cache, xml_report=None, build_only=False):
ctiller3040cb72015-01-07 12:13:17 -08001058 """Do one pass of building & running tests."""
murgatroid99666450e2015-01-26 13:03:31 -08001059 # build latest sequentially
Jan Tattermuschaab1e512016-01-28 09:30:44 -08001060 num_failures, resultset = jobset.run(
Adele Zhoue4c35612015-10-16 15:34:23 -07001061 build_steps, maxjobs=1, stop_on_failure=True,
Craig Tiller883064c2015-11-04 10:06:10 -08001062 newline_on_success=newline_on_success, travis=args.travis)
Adele Zhoue4c35612015-10-16 15:34:23 -07001063 if num_failures:
Craig Tillereb9de8b2016-01-08 08:57:41 -08001064 return [BuildAndRunError.BUILD]
Craig Tillerb361b4e2016-01-06 11:44:17 -08001065
Jan Tattermusch2dd156e2015-12-04 18:26:17 -08001066 if build_only:
Jan Tattermuschaab1e512016-01-28 09:30:44 -08001067 if xml_report:
1068 report_utils.render_junit_xml_report(resultset, xml_report)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001069 return []
ctiller3040cb72015-01-07 12:13:17 -08001070
Craig Tiller234b6e72015-05-23 10:12:40 -07001071 # start antagonists
David Garcia Quintas79e389f2015-06-02 17:49:42 -07001072 antagonists = [subprocess.Popen(['tools/run_tests/antagonist.py'])
Craig Tiller234b6e72015-05-23 10:12:40 -07001073 for _ in range(0, args.antagonists)]
Craig Tillerfe4939f2015-10-06 12:55:36 -07001074 port_server_port = 32767
Craig Tillerf53d9c82015-08-04 14:19:43 -07001075 _start_port_server(port_server_port)
Adele Zhou7cf72112015-11-04 11:18:43 -08001076 resultset = None
Adele Zhou803af152015-11-30 15:16:16 -08001077 num_test_failures = 0
Craig Tiller234b6e72015-05-23 10:12:40 -07001078 try:
David Garcia Quintase90cd372015-05-31 18:15:26 -07001079 infinite_runs = runs_per_test == 0
yang-g6c1fdc62015-08-18 11:57:42 -07001080 one_run = set(
1081 spec
yang-g6c1fdc62015-08-18 11:57:42 -07001082 for language in languages
Jan Tattermusch77db4322016-02-20 20:19:35 -08001083 for spec in language.test_specs()
yang-g6c1fdc62015-08-18 11:57:42 -07001084 if re.search(args.regex, spec.shortname))
David Garcia Quintas79e389f2015-06-02 17:49:42 -07001085 # When running on travis, we want out test runs to be as similar as possible
1086 # for reproducibility purposes.
Craig Tiller883064c2015-11-04 10:06:10 -08001087 if args.travis:
David Garcia Quintas79e389f2015-06-02 17:49:42 -07001088 massaged_one_run = sorted(one_run, key=lambda x: x.shortname)
1089 else:
1090 # whereas otherwise, we want to shuffle things up to give all tests a
1091 # chance to run.
1092 massaged_one_run = list(one_run) # random.shuffle needs an indexable seq.
1093 random.shuffle(massaged_one_run) # which it modifies in-place.
Craig Tillerf7b7c892015-06-22 14:33:25 -07001094 if infinite_runs:
1095 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 -07001096 runs_sequence = (itertools.repeat(massaged_one_run) if infinite_runs
1097 else itertools.repeat(massaged_one_run, runs_per_test))
David Garcia Quintase90cd372015-05-31 18:15:26 -07001098 all_runs = itertools.chain.from_iterable(runs_sequence)
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +02001099
Adele Zhou803af152015-11-30 15:16:16 -08001100 num_test_failures, resultset = jobset.run(
Adele Zhou2271ab52015-10-28 13:59:14 -07001101 all_runs, check_cancelled, newline_on_success=newline_on_success,
Craig Tiller883064c2015-11-04 10:06:10 -08001102 travis=args.travis, infinite_runs=infinite_runs, maxjobs=args.jobs,
murgatroid998ae409f2015-10-26 16:39:00 -07001103 stop_on_failure=args.stop_on_failure,
Adele Zhouf2ca7bc2015-10-23 15:38:00 -07001104 cache=cache if not xml_report else None,
Adele Zhouf2ca7bc2015-10-23 15:38:00 -07001105 add_env={'GRPC_TEST_PORT_SERVER': 'localhost:%d' % port_server_port})
Adele Zhoud5fffa52015-10-23 15:51:42 -07001106 if resultset:
1107 for k, v in resultset.iteritems():
1108 num_runs, num_failures = _calculate_num_runs_failures(v)
1109 if num_failures == num_runs: # what about infinite_runs???
1110 jobset.message('FAILED', k, do_newline=True)
1111 elif num_failures > 0:
1112 jobset.message(
1113 'FLAKE', '%s [%d/%d runs flaked]' % (k, num_failures, num_runs),
1114 do_newline=True)
1115 else:
1116 jobset.message('PASSED', k, do_newline=True)
Craig Tiller234b6e72015-05-23 10:12:40 -07001117 finally:
1118 for antagonist in antagonists:
1119 antagonist.kill()
Adele Zhou7cf72112015-11-04 11:18:43 -08001120 if xml_report and resultset:
Adele Zhou3bc7ba42015-11-05 10:21:58 -08001121 report_utils.render_junit_xml_report(resultset, xml_report)
Craig Tillerd86a3942015-01-14 12:48:54 -08001122
Adele Zhouf2ca7bc2015-10-23 15:38:00 -07001123 number_failures, _ = jobset.run(
1124 post_tests_steps, maxjobs=1, stop_on_failure=True,
Craig Tiller883064c2015-11-04 10:06:10 -08001125 newline_on_success=newline_on_success, travis=args.travis)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001126
1127 out = []
1128 if number_failures:
1129 out.append(BuildAndRunError.POST_TEST)
1130 if num_test_failures:
1131 out.append(BuildAndRunError.TEST)
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +02001132
Craig Tiller69cd2372015-06-11 09:38:09 -07001133 if cache: cache.save()
1134
Craig Tillereb9de8b2016-01-08 08:57:41 -08001135 return out
ctiller3040cb72015-01-07 12:13:17 -08001136
1137
David Klempner25739582015-02-11 15:57:32 -08001138test_cache = TestCache(runs_per_test == 1)
Craig Tiller547db2b2015-01-30 14:08:39 -08001139test_cache.maybe_load()
Craig Tiller71735182015-01-15 17:07:13 -08001140
ctiller3040cb72015-01-07 12:13:17 -08001141if forever:
Nicolas Noble044db742015-01-14 16:57:24 -08001142 success = True
ctiller3040cb72015-01-07 12:13:17 -08001143 while True:
Craig Tiller42bc87c2015-02-23 08:50:19 -08001144 dw = watch_dirs.DirWatcher(['src', 'include', 'test', 'examples'])
ctiller3040cb72015-01-07 12:13:17 -08001145 initial_time = dw.most_recent_change()
1146 have_files_changed = lambda: dw.most_recent_change() != initial_time
Nicolas Noble044db742015-01-14 16:57:24 -08001147 previous_success = success
Craig Tillereb9de8b2016-01-08 08:57:41 -08001148 errors = _build_and_run(check_cancelled=have_files_changed,
1149 newline_on_success=False,
1150 cache=test_cache,
1151 build_only=args.build_only) == 0
1152 if not previous_success and not errors:
Nicolas Nobleb09078f2015-01-14 18:06:05 -08001153 jobset.message('SUCCESS',
1154 'All tests are now passing properly',
1155 do_newline=True)
Nicolas Noble044db742015-01-14 16:57:24 -08001156 jobset.message('IDLE', 'No change detected')
ctiller3040cb72015-01-07 12:13:17 -08001157 while not have_files_changed():
1158 time.sleep(1)
1159else:
Craig Tillereb9de8b2016-01-08 08:57:41 -08001160 errors = _build_and_run(check_cancelled=lambda: False,
Craig Tiller71735182015-01-15 17:07:13 -08001161 newline_on_success=args.newline_on_success,
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +02001162 cache=test_cache,
Jan Tattermusch2dd156e2015-12-04 18:26:17 -08001163 xml_report=args.xml_report,
1164 build_only=args.build_only)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001165 if not errors:
Nicolas Nobleb09078f2015-01-14 18:06:05 -08001166 jobset.message('SUCCESS', 'All tests passed', do_newline=True)
1167 else:
1168 jobset.message('FAILED', 'Some tests failed', do_newline=True)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001169 exit_code = 0
1170 if BuildAndRunError.BUILD in errors:
1171 exit_code |= 1
Craig Tiller4f2be362016-01-08 08:59:20 -08001172 if BuildAndRunError.TEST in errors and not args.travis:
Craig Tillereb9de8b2016-01-08 08:57:41 -08001173 exit_code |= 2
Craig Tiller4f2be362016-01-08 08:59:20 -08001174 if BuildAndRunError.POST_TEST in errors:
1175 exit_code |= 4
Craig Tillereb9de8b2016-01-08 08:57:41 -08001176 sys.exit(exit_code)