blob: 87b91bdc1115602c5684e4b7dd20bb975b825c2e [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
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':
Jan Tattermusch3b5121b2016-02-22 17:41:05 -0800162 _ROOT + '/src/core/tsi/test_creds/ca.pem'}))
Jan Tattermusch77db4322016-02-20 20:19:35 -0800163 elif self.args.regex == '.*' or self.platform == 'windows':
Adele Zhoue4c35612015-10-16 15:34:23 -0700164 print '\nWARNING: binary not found, skipping', binary
Nicolas Noblee1445362015-05-11 17:40:26 -0700165 return sorted(out)
Craig Tillerc7449162015-01-16 14:42:10 -0800166
Jan Tattermusch77db4322016-02-20 20:19:35 -0800167 def make_targets(self):
168 test_regex = self.args.regex
169 if self.platform != 'windows' and self.args.regex != '.*':
Craig Tiller883064c2015-11-04 10:06:10 -0800170 # use the regex to minimize the number of things to build
Craig Tillerb0f275e2016-01-27 10:45:50 -0800171 return [os.path.basename(target['name'])
Craig Tiller883064c2015-11-04 10:06:10 -0800172 for target in get_c_tests(False, self.test_lang)
Craig Tillerb0f275e2016-01-27 10:45:50 -0800173 if re.search(test_regex, '/' + target['name'])]
Jan Tattermusch77db4322016-02-20 20:19:35 -0800174 if self.platform == 'windows':
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700175 # don't build tools on windows just yet
176 return ['buildtests_%s' % self.make_target]
Craig Tiller7552f0f2015-06-19 17:46:20 -0700177 return ['buildtests_%s' % self.make_target, 'tools_%s' % self.make_target]
Craig Tillerc7449162015-01-16 14:42:10 -0800178
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800179 def make_options(self):
Jan Tattermuschc96caf82016-02-22 17:31:02 -0800180 return self._make_options;
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800181
murgatroid99256d3df2015-09-21 16:58:02 -0700182 def pre_build_steps(self):
Jan Tattermusch874aec02015-10-07 19:26:19 -0700183 if self.platform == 'windows':
184 return [['tools\\run_tests\\pre_build_c.bat']]
185 else:
186 return []
murgatroid99256d3df2015-09-21 16:58:02 -0700187
Craig Tillerc7449162015-01-16 14:42:10 -0800188 def build_steps(self):
189 return []
190
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200191 def post_tests_steps(self):
192 if self.platform == 'windows':
193 return []
194 else:
195 return [['tools/run_tests/post_tests_c.sh']]
196
murgatroid99a3e244f2015-09-22 11:25:53 -0700197 def makefile_name(self):
198 return 'Makefile'
199
Jan Tattermusch77db4322016-02-20 20:19:35 -0800200 def dockerfile_dir(self):
201 return 'tools/dockerfile/test/cxx_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800202
murgatroid99132ce6a2015-03-04 17:29:14 -0800203 def __str__(self):
204 return self.make_target
205
Craig Tillercc0535d2015-12-08 15:14:47 -0800206
murgatroid992c8d5162015-01-26 10:41:21 -0800207class NodeLanguage(object):
208
Jan Tattermusche477b842016-02-06 22:19:01 -0800209 def __init__(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800210 self.platform = platform_string()
Jan Tattermusche477b842016-02-06 22:19:01 -0800211 self.node_version = '0.12'
212
Jan Tattermusch77db4322016-02-20 20:19:35 -0800213 def configure(self, config, args):
214 self.config = config
215 self.args = args
216 _check_compiler(self.args.compiler, ['default'])
217
218 def test_specs(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800219 if self.platform == 'windows':
Jan Tattermusch77db4322016-02-20 20:19:35 -0800220 return [self.config.job_spec(['tools\\run_tests\\run_node.bat'], None)]
Michael Lumishaaa876a2016-02-10 15:27:58 -0800221 else:
Jan Tattermusch77db4322016-02-20 20:19:35 -0800222 return [self.config.job_spec(['tools/run_tests/run_node.sh', self.node_version],
223 None,
224 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
murgatroid992c8d5162015-01-26 10:41:21 -0800225
murgatroid99256d3df2015-09-21 16:58:02 -0700226 def pre_build_steps(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800227 if self.platform == 'windows':
228 return [['tools\\run_tests\\pre_build_node.bat']]
229 else:
230 return [['tools/run_tests/pre_build_node.sh', self.node_version]]
murgatroid99256d3df2015-09-21 16:58:02 -0700231
Jan Tattermusch77db4322016-02-20 20:19:35 -0800232 def make_targets(self):
murgatroid99db5b1602015-10-01 13:20:11 -0700233 return []
murgatroid992c8d5162015-01-26 10:41:21 -0800234
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800235 def make_options(self):
236 return []
237
murgatroid992c8d5162015-01-26 10:41:21 -0800238 def build_steps(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800239 if self.platform == 'windows':
240 return [['tools\\run_tests\\build_node.bat']]
241 else:
242 return [['tools/run_tests/build_node.sh', self.node_version]]
Craig Tillerc7449162015-01-16 14:42:10 -0800243
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200244 def post_tests_steps(self):
245 return []
246
murgatroid99a3e244f2015-09-22 11:25:53 -0700247 def makefile_name(self):
248 return 'Makefile'
249
Jan Tattermusch77db4322016-02-20 20:19:35 -0800250 def dockerfile_dir(self):
251 return 'tools/dockerfile/test/node_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800252
murgatroid99132ce6a2015-03-04 17:29:14 -0800253 def __str__(self):
254 return 'node'
255
Craig Tiller99775822015-01-30 13:07:16 -0800256
Craig Tillerc7449162015-01-16 14:42:10 -0800257class PhpLanguage(object):
258
Jan Tattermusch77db4322016-02-20 20:19:35 -0800259 def configure(self, config, args):
260 self.config = config
261 self.args = args
262 _check_compiler(self.args.compiler, ['default'])
263
264 def test_specs(self):
265 return [self.config.job_spec(['src/php/bin/run_tests.sh'], None,
266 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
Craig Tillerc7449162015-01-16 14:42:10 -0800267
murgatroid99256d3df2015-09-21 16:58:02 -0700268 def pre_build_steps(self):
269 return []
270
Jan Tattermusch77db4322016-02-20 20:19:35 -0800271 def make_targets(self):
Craig Tilleraf7cf542015-05-22 10:07:34 -0700272 return ['static_c', 'shared_c']
Craig Tillerc7449162015-01-16 14:42:10 -0800273
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800274 def make_options(self):
275 return []
276
Craig Tillerc7449162015-01-16 14:42:10 -0800277 def build_steps(self):
278 return [['tools/run_tests/build_php.sh']]
279
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200280 def post_tests_steps(self):
Stanley Cheunga6b95482016-01-13 16:10:48 -0800281 return [['tools/run_tests/post_tests_php.sh']]
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200282
murgatroid99a3e244f2015-09-22 11:25:53 -0700283 def makefile_name(self):
284 return 'Makefile'
285
Jan Tattermusch77db4322016-02-20 20:19:35 -0800286 def dockerfile_dir(self):
287 return 'tools/dockerfile/test/php_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800288
murgatroid99132ce6a2015-03-04 17:29:14 -0800289 def __str__(self):
290 return 'php'
291
Craig Tillerc7449162015-01-16 14:42:10 -0800292
Nathaniel Manista840615e2015-01-22 20:31:47 +0000293class PythonLanguage(object):
294
Craig Tiller49f61322015-03-03 13:02:11 -0800295 def __init__(self):
Masood Malekghassemi2b841622015-07-28 17:39:02 -0700296 self._build_python_versions = ['2.7']
Masood Malekghassemie5f70022015-06-29 09:20:26 -0700297 self._has_python_versions = []
Craig Tiller49f61322015-03-03 13:02:11 -0800298
Jan Tattermusch77db4322016-02-20 20:19:35 -0800299 def configure(self, config, args):
300 self.config = config
301 self.args = args
302 _check_compiler(self.args.compiler, ['default'])
303
304 def test_specs(self):
Masood Malekghassemi2b841622015-07-28 17:39:02 -0700305 environment = dict(_FORCE_ENVIRON_FOR_WRAPPERS)
306 environment['PYVER'] = '2.7'
Jan Tattermusch77db4322016-02-20 20:19:35 -0800307 return [self.config.job_spec(
Masood Malekghassemi2b841622015-07-28 17:39:02 -0700308 ['tools/run_tests/run_python.sh'],
309 None,
310 environ=environment,
311 shortname='py.test',
Masood Malekghassemi26ea9e22015-10-09 15:19:17 -0700312 timeout_seconds=15*60
Masood Malekghassemi2b841622015-07-28 17:39:02 -0700313 )]
Nathaniel Manista840615e2015-01-22 20:31:47 +0000314
murgatroid99256d3df2015-09-21 16:58:02 -0700315 def pre_build_steps(self):
316 return []
317
Jan Tattermusch77db4322016-02-20 20:19:35 -0800318 def make_targets(self):
Craig Tilleraf7cf542015-05-22 10:07:34 -0700319 return ['static_c', 'grpc_python_plugin', 'shared_c']
Nathaniel Manista840615e2015-01-22 20:31:47 +0000320
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800321 def make_options(self):
322 return []
323
Nathaniel Manista840615e2015-01-22 20:31:47 +0000324 def build_steps(self):
Masood Malekghassemie5f70022015-06-29 09:20:26 -0700325 commands = []
326 for python_version in self._build_python_versions:
327 try:
328 with open(os.devnull, 'w') as output:
329 subprocess.check_call(['which', 'python' + python_version],
330 stdout=output, stderr=output)
331 commands.append(['tools/run_tests/build_python.sh', python_version])
332 self._has_python_versions.append(python_version)
333 except:
334 jobset.message('WARNING', 'Missing Python ' + python_version,
335 do_newline=True)
336 return commands
Nathaniel Manista840615e2015-01-22 20:31:47 +0000337
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200338 def post_tests_steps(self):
339 return []
340
murgatroid99a3e244f2015-09-22 11:25:53 -0700341 def makefile_name(self):
342 return 'Makefile'
343
Jan Tattermusch77db4322016-02-20 20:19:35 -0800344 def dockerfile_dir(self):
345 return 'tools/dockerfile/test/python_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800346
murgatroid99132ce6a2015-03-04 17:29:14 -0800347 def __str__(self):
348 return 'python'
349
Craig Tillerd625d812015-04-08 15:52:35 -0700350
murgatroid996a4c4fa2015-02-27 12:08:57 -0800351class RubyLanguage(object):
352
Jan Tattermusch77db4322016-02-20 20:19:35 -0800353 def configure(self, config, args):
354 self.config = config
355 self.args = args
356 _check_compiler(self.args.compiler, ['default'])
357
358 def test_specs(self):
359 return [self.config.job_spec(['tools/run_tests/run_ruby.sh'], None,
360 timeout_seconds=10*60,
361 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
murgatroid996a4c4fa2015-02-27 12:08:57 -0800362
murgatroid99256d3df2015-09-21 16:58:02 -0700363 def pre_build_steps(self):
Nicolas "Pixel" Noblebcf988f2015-10-08 03:00:42 +0200364 return [['tools/run_tests/pre_build_ruby.sh']]
murgatroid99256d3df2015-09-21 16:58:02 -0700365
Craig Tiller883064c2015-11-04 10:06:10 -0800366 def make_targets(self, test_regex):
murgatroid997d243df2016-02-18 09:58:05 -0800367 return []
murgatroid996a4c4fa2015-02-27 12:08:57 -0800368
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800369 def make_options(self):
370 return []
371
murgatroid996a4c4fa2015-02-27 12:08:57 -0800372 def build_steps(self):
373 return [['tools/run_tests/build_ruby.sh']]
374
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200375 def post_tests_steps(self):
Nicolas "Pixel" Noble7ef1e532015-12-02 00:55:33 +0100376 return [['tools/run_tests/post_tests_ruby.sh']]
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200377
murgatroid99a3e244f2015-09-22 11:25:53 -0700378 def makefile_name(self):
379 return 'Makefile'
380
Jan Tattermusch77db4322016-02-20 20:19:35 -0800381 def dockerfile_dir(self):
382 return 'tools/dockerfile/test/ruby_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800383
murgatroid99132ce6a2015-03-04 17:29:14 -0800384 def __str__(self):
385 return 'ruby'
386
Craig Tillerd625d812015-04-08 15:52:35 -0700387
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800388class CSharpLanguage(object):
Jan Tattermusch77db4322016-02-20 20:19:35 -0800389
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700390 def __init__(self):
Craig Tillerd50993d2015-08-05 08:04:36 -0700391 self.platform = platform_string()
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700392
Jan Tattermusch77db4322016-02-20 20:19:35 -0800393 def configure(self, config, args):
394 self.config = config
395 self.args = args
396 _check_compiler(self.args.compiler, ['default'])
397
398 def test_specs(self):
Jan Tattermusch03c01062015-12-11 14:28:56 -0800399 with open('src/csharp/tests.json') as f:
400 tests_json = json.load(f)
401 assemblies = tests_json['assemblies']
402 tests = tests_json['tests']
403
Jan Tattermuscha2d964c2016-02-22 17:33:09 -0800404 msbuild_config = _MSBUILD_CONFIG[self.config.build_config]
Jan Tattermusch03c01062015-12-11 14:28:56 -0800405 assembly_files = ['%s/bin/%s/%s.dll' % (a, msbuild_config, a)
406 for a in assemblies]
407
408 extra_args = ['-labels'] + assembly_files
409
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700410 if self.platform == 'windows':
Jan Tattermusch03c01062015-12-11 14:28:56 -0800411 script_name = 'tools\\run_tests\\run_csharp.bat'
412 extra_args += ['-domain=None']
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700413 else:
Jan Tattermusch03c01062015-12-11 14:28:56 -0800414 script_name = 'tools/run_tests/run_csharp.sh'
Jan Tattermuschbf3b1532015-10-26 10:24:42 -0700415
Jan Tattermusch77db4322016-02-20 20:19:35 -0800416 if self.config.build_config == 'gcov':
Jan Tattermuschbdf4b2e2015-10-28 08:22:34 -0700417 # On Windows, we only collect C# code coverage.
418 # On Linux, we only collect coverage for native extension.
419 # For code coverage all tests need to run as one suite.
Jan Tattermusch77db4322016-02-20 20:19:35 -0800420 return [self.config.job_spec([script_name] + extra_args, None,
421 shortname='csharp.coverage',
422 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
Jan Tattermusch61c3a832015-10-27 17:54:50 -0700423 else:
Jan Tattermusch03c01062015-12-11 14:28:56 -0800424 specs = []
425 for test in tests:
426 cmdline = [script_name, '-run=%s' % test] + extra_args
427 if self.platform == 'windows':
428 # use different output directory for each test to prevent
429 # TestResult.xml clash between parallel test runs.
430 cmdline += ['-work=test-result/%s' % uuid.uuid4()]
Jan Tattermusch77db4322016-02-20 20:19:35 -0800431 specs.append(self.config.job_spec(cmdline, None,
432 shortname='csharp.%s' % test,
433 environ=_FORCE_ENVIRON_FOR_WRAPPERS))
Jan Tattermusch03c01062015-12-11 14:28:56 -0800434 return specs
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800435
murgatroid99256d3df2015-09-21 16:58:02 -0700436 def pre_build_steps(self):
Jan Tattermusch48423fc2015-10-07 18:59:16 -0700437 if self.platform == 'windows':
Jan Tattermusch874aec02015-10-07 19:26:19 -0700438 return [['tools\\run_tests\\pre_build_csharp.bat']]
Jan Tattermusch48423fc2015-10-07 18:59:16 -0700439 else:
440 return [['tools/run_tests/pre_build_csharp.sh']]
murgatroid99256d3df2015-09-21 16:58:02 -0700441
Jan Tattermusch77db4322016-02-20 20:19:35 -0800442 def make_targets(self):
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700443 # For Windows, this target doesn't really build anything,
444 # everything is build by buildall script later.
Craig Tillerd5904822015-08-31 21:30:58 -0700445 if self.platform == 'windows':
446 return []
447 else:
448 return ['grpc_csharp_ext']
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800449
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800450 def make_options(self):
451 if self.platform == 'mac':
452 # On Mac, official distribution of mono is 32bit.
453 return ['CFLAGS=-arch i386', 'LDFLAGS=-arch i386']
454 else:
455 return []
456
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800457 def build_steps(self):
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700458 if self.platform == 'windows':
459 return [['src\\csharp\\buildall.bat']]
460 else:
461 return [['tools/run_tests/build_csharp.sh']]
Nathaniel Manista840615e2015-01-22 20:31:47 +0000462
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200463 def post_tests_steps(self):
464 return []
465
murgatroid99a3e244f2015-09-22 11:25:53 -0700466 def makefile_name(self):
467 return 'Makefile'
468
Jan Tattermusch77db4322016-02-20 20:19:35 -0800469 def dockerfile_dir(self):
470 return 'tools/dockerfile/test/csharp_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800471
murgatroid99132ce6a2015-03-04 17:29:14 -0800472 def __str__(self):
473 return 'csharp'
474
Craig Tillerd625d812015-04-08 15:52:35 -0700475
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700476class ObjCLanguage(object):
477
Jan Tattermusch77db4322016-02-20 20:19:35 -0800478 def configure(self, config, args):
479 self.config = config
480 self.args = args
481 _check_compiler(self.args.compiler, ['default'])
482
483 def test_specs(self):
484 return [self.config.job_spec(['src/objective-c/tests/run_tests.sh'], None,
485 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700486
murgatroid99256d3df2015-09-21 16:58:02 -0700487 def pre_build_steps(self):
488 return []
489
Jan Tattermusch77db4322016-02-20 20:19:35 -0800490 def make_targets(self):
Jorge Canizalesd0b32e92015-07-30 23:08:43 -0700491 return ['grpc_objective_c_plugin', 'interop_server']
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700492
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800493 def make_options(self):
494 return []
495
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700496 def build_steps(self):
Jorge Canizalesd0b32e92015-07-30 23:08:43 -0700497 return [['src/objective-c/tests/build_tests.sh']]
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700498
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200499 def post_tests_steps(self):
500 return []
501
murgatroid99a3e244f2015-09-22 11:25:53 -0700502 def makefile_name(self):
503 return 'Makefile'
504
Jan Tattermusch77db4322016-02-20 20:19:35 -0800505 def dockerfile_dir(self):
Jan Tattermusch788ee232016-01-26 12:19:44 -0800506 return None
507
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700508 def __str__(self):
509 return 'objc'
510
511
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100512class Sanity(object):
513
Jan Tattermusch77db4322016-02-20 20:19:35 -0800514 def configure(self, config, args):
515 self.config = config
516 self.args = args
517 _check_compiler(self.args.compiler, ['default'])
518
519 def test_specs(self):
Craig Tiller94d04a52016-01-20 10:58:23 -0800520 import yaml
Jan Tattermusch788ee232016-01-26 12:19:44 -0800521 with open('tools/run_tests/sanity/sanity_tests.yaml', 'r') as f:
Jan Tattermusch77db4322016-02-20 20:19:35 -0800522 return [self.config.job_spec(cmd['script'].split(), None,
523 timeout_seconds=None, environ={'TEST': 'true'},
524 cpu_cost=cmd.get('cpu_cost', 1))
Craig Tiller94d04a52016-01-20 10:58:23 -0800525 for cmd in yaml.load(f)]
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100526
murgatroid99256d3df2015-09-21 16:58:02 -0700527 def pre_build_steps(self):
528 return []
529
Jan Tattermusch77db4322016-02-20 20:19:35 -0800530 def make_targets(self):
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100531 return ['run_dep_checks']
532
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800533 def make_options(self):
534 return []
535
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100536 def build_steps(self):
537 return []
538
Nicolas "Pixel" Noble87879b32015-10-12 23:28:53 +0200539 def post_tests_steps(self):
540 return []
541
murgatroid99a3e244f2015-09-22 11:25:53 -0700542 def makefile_name(self):
543 return 'Makefile'
544
Jan Tattermusch77db4322016-02-20 20:19:35 -0800545 def dockerfile_dir(self):
Jan Tattermusche70b3c52016-02-07 20:21:02 -0800546 return 'tools/dockerfile/test/sanity'
Jan Tattermusch788ee232016-01-26 12:19:44 -0800547
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100548 def __str__(self):
549 return 'sanity'
550
Nicolas "Pixel" Noblee55cd7f2015-04-14 17:59:13 +0200551
Craig Tiller738c3342015-01-12 14:28:33 -0800552# different configurations we can run under
Craig Tillera0f85172016-01-20 15:56:06 -0800553with open('tools/run_tests/configs.json') as f:
Craig Tiller1dce9062016-01-20 17:01:56 -0800554 _CONFIGS = dict((cfg['config'], Config(**cfg)) for cfg in ast.literal_eval(f.read()))
Craig Tiller738c3342015-01-12 14:28:33 -0800555
556
Craig Tillerc7449162015-01-16 14:42:10 -0800557_LANGUAGES = {
Craig Tillere9c959d2015-01-18 10:23:26 -0800558 'c++': CLanguage('cxx', 'c++'),
559 'c': CLanguage('c', 'c'),
murgatroid992c8d5162015-01-26 10:41:21 -0800560 'node': NodeLanguage(),
Nathaniel Manista840615e2015-01-22 20:31:47 +0000561 'php': PhpLanguage(),
562 'python': PythonLanguage(),
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800563 'ruby': RubyLanguage(),
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100564 'csharp': CSharpLanguage(),
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700565 'objc' : ObjCLanguage(),
Jan Tattermusch70a57e42016-02-20 18:50:27 -0800566 'sanity': Sanity()
Craig Tillereb272bc2015-01-30 13:13:14 -0800567 }
Nicolas Nobleddef2462015-01-06 18:08:25 -0800568
Jan Tattermusch77db4322016-02-20 20:19:35 -0800569
Jan Tattermuscha2d964c2016-02-22 17:33:09 -0800570_MSBUILD_CONFIG = {
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700571 'dbg': 'Debug',
572 'opt': 'Release',
Jan Tattermusche4a69182015-12-15 09:53:01 -0800573 'gcov': 'Debug',
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700574 }
575
David Garcia Quintase90cd372015-05-31 18:15:26 -0700576
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800577def _windows_arch_option(arch):
578 """Returns msbuild cmdline option for selected architecture."""
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800579 if arch == 'default' or arch == 'x86':
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800580 return '/p:Platform=Win32'
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800581 elif arch == 'x64':
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800582 return '/p:Platform=x64'
583 else:
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800584 print 'Architecture %s not supported.' % arch
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800585 sys.exit(1)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800586
Jan Tattermuschf08018a2016-01-26 08:22:09 -0800587
588def _check_arch_option(arch):
589 """Checks that architecture option is valid."""
590 if platform_string() == 'windows':
591 _windows_arch_option(arch)
592 elif platform_string() == 'linux':
593 # On linux, we need to be running under docker with the right architecture.
Jan Tattermusch07fb0422016-01-26 10:46:56 -0800594 runtime_arch = platform.architecture()[0]
Jan Tattermuschf08018a2016-01-26 08:22:09 -0800595 if arch == 'default':
596 return
597 elif runtime_arch == '64bit' and arch == 'x64':
598 return
599 elif runtime_arch == '32bit' and arch == 'x86':
600 return
601 else:
602 print 'Architecture %s does not match current runtime architecture.' % arch
603 sys.exit(1)
604 else:
605 if args.arch != 'default':
606 print 'Architecture %s not supported on current platform.' % args.arch
607 sys.exit(1)
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800608
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800609
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800610def _windows_build_bat(compiler):
611 """Returns name of build.bat for selected compiler."""
612 if compiler == 'default' or compiler == 'vs2013':
613 return 'vsprojects\\build_vs2013.bat'
614 elif compiler == 'vs2015':
615 return 'vsprojects\\build_vs2015.bat'
616 elif compiler == 'vs2010':
617 return 'vsprojects\\build_vs2010.bat'
618 else:
619 print 'Compiler %s not supported.' % compiler
620 sys.exit(1)
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800621
622
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800623def _windows_toolset_option(compiler):
624 """Returns msbuild PlatformToolset for selected compiler."""
625 if compiler == 'default' or compiler == 'vs2013':
626 return '/p:PlatformToolset=v120'
627 elif compiler == 'vs2015':
628 return '/p:PlatformToolset=v140'
629 elif compiler == 'vs2010':
630 return '/p:PlatformToolset=v100'
631 else:
632 print 'Compiler %s not supported.' % compiler
633 sys.exit(1)
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800634
635
Jan Tattermusche70b3c52016-02-07 20:21:02 -0800636def _docker_arch_suffix(arch):
637 """Returns suffix to dockerfile dir to use."""
638 if arch == 'default' or arch == 'x64':
639 return 'x64'
640 elif arch == 'x86':
641 return 'x86'
642 else:
643 print 'Architecture %s not supported with current settings.' % arch
644 sys.exit(1)
645
646
David Garcia Quintase90cd372015-05-31 18:15:26 -0700647def runs_per_test_type(arg_str):
648 """Auxilary function to parse the "runs_per_test" flag.
649
650 Returns:
651 A positive integer or 0, the latter indicating an infinite number of
652 runs.
653
654 Raises:
655 argparse.ArgumentTypeError: Upon invalid input.
656 """
657 if arg_str == 'inf':
658 return 0
659 try:
660 n = int(arg_str)
661 if n <= 0: raise ValueError
Craig Tiller50e53e22015-06-01 20:18:21 -0700662 return n
David Garcia Quintase90cd372015-05-31 18:15:26 -0700663 except:
Adele Zhoue4c35612015-10-16 15:34:23 -0700664 msg = '\'{}\' is not a positive integer or \'inf\''.format(arg_str)
David Garcia Quintase90cd372015-05-31 18:15:26 -0700665 raise argparse.ArgumentTypeError(msg)
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700666
667# parse command line
668argp = argparse.ArgumentParser(description='Run grpc tests.')
669argp.add_argument('-c', '--config',
Jan Tattermusch77db4322016-02-20 20:19:35 -0800670 choices=sorted(_CONFIGS.keys()),
671 default='opt')
David Garcia Quintase90cd372015-05-31 18:15:26 -0700672argp.add_argument('-n', '--runs_per_test', default=1, type=runs_per_test_type,
673 help='A positive integer or "inf". If "inf", all tests will run in an '
674 'infinite loop. Especially useful in combination with "-f"')
Craig Tillerfe406ec2015-02-24 13:55:12 -0800675argp.add_argument('-r', '--regex', default='.*', type=str)
Craig Tiller5f735a62016-01-20 09:31:15 -0800676argp.add_argument('-j', '--jobs', default=multiprocessing.cpu_count(), type=int)
Craig Tiller8451e872015-02-27 09:25:51 -0800677argp.add_argument('-s', '--slowdown', default=1.0, type=float)
ctiller3040cb72015-01-07 12:13:17 -0800678argp.add_argument('-f', '--forever',
679 default=False,
680 action='store_const',
681 const=True)
Nicolas "Pixel" Noblea7df3f92015-02-26 22:07:04 +0100682argp.add_argument('-t', '--travis',
683 default=False,
684 action='store_const',
685 const=True)
Nicolas Noble044db742015-01-14 16:57:24 -0800686argp.add_argument('--newline_on_success',
687 default=False,
688 action='store_const',
689 const=True)
Craig Tiller686fb262015-01-15 07:39:09 -0800690argp.add_argument('-l', '--language',
Craig Tiller60f15e62015-05-13 09:05:17 -0700691 choices=['all'] + sorted(_LANGUAGES.keys()),
Craig Tiller686fb262015-01-15 07:39:09 -0800692 nargs='+',
Craig Tiller60f15e62015-05-13 09:05:17 -0700693 default=['all'])
Craig Tillercd43da82015-05-29 08:41:29 -0700694argp.add_argument('-S', '--stop_on_failure',
695 default=False,
696 action='store_const',
697 const=True)
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700698argp.add_argument('--use_docker',
699 default=False,
700 action='store_const',
701 const=True,
Adele Zhoue4c35612015-10-16 15:34:23 -0700702 help='Run all the tests under docker. That provides ' +
703 'additional isolation and prevents the need to install ' +
704 'language specific prerequisites. Only available on Linux.')
Craig Tillerd4509a12015-09-28 09:18:40 -0700705argp.add_argument('--allow_flakes',
706 default=False,
707 action='store_const',
708 const=True,
Adele Zhoue4c35612015-10-16 15:34:23 -0700709 help='Allow flaky tests to show as passing (re-runs failed tests up to five times)')
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800710argp.add_argument('--arch',
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800711 choices=['default', 'x86', 'x64'],
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800712 default='default',
713 help='Selects architecture to target. For some platforms "default" is the only supported choice.')
714argp.add_argument('--compiler',
715 choices=['default', 'vs2010', 'vs2013', 'vs2015'],
716 default='default',
Jan Tattermusch77db4322016-02-20 20:19:35 -0800717 help='Selects compiler to use. Allowed values depend on the platform and language.')
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800718argp.add_argument('--build_only',
719 default=False,
720 action='store_const',
721 const=True,
722 help='Perform all the build steps but dont run any tests.')
Craig Tiller5f735a62016-01-20 09:31:15 -0800723argp.add_argument('--measure_cpu_costs', default=False, action='store_const', const=True,
724 help='Measure the cpu costs of tests')
Craig Tiller1676f912016-01-05 10:49:44 -0800725argp.add_argument('--update_submodules', default=[], nargs='*',
726 help='Update some submodules before building. If any are updated, also run generate_projects. ' +
727 'Submodules are specified as SUBMODULE_NAME:BRANCH; if BRANCH is omitted, master is assumed.')
Craig Tiller234b6e72015-05-23 10:12:40 -0700728argp.add_argument('-a', '--antagonists', default=0, type=int)
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +0200729argp.add_argument('-x', '--xml_report', default=None, type=str,
730 help='Generates a JUnit-compatible XML report')
Nicolas Nobleddef2462015-01-06 18:08:25 -0800731args = argp.parse_args()
732
Craig Tiller5f735a62016-01-20 09:31:15 -0800733jobset.measure_cpu_costs = args.measure_cpu_costs
734
Craig Tiller1676f912016-01-05 10:49:44 -0800735# update submodules if necessary
Craig Tillerb361b4e2016-01-06 11:44:17 -0800736need_to_regenerate_projects = False
737for spec in args.update_submodules:
738 spec = spec.split(':', 1)
739 if len(spec) == 1:
740 submodule = spec[0]
741 branch = 'master'
742 elif len(spec) == 2:
743 submodule = spec[0]
744 branch = spec[1]
745 cwd = 'third_party/%s' % submodule
746 def git(cmd, cwd=cwd):
747 print 'in %s: git %s' % (cwd, cmd)
748 subprocess.check_call('git %s' % cmd, cwd=cwd, shell=True)
749 git('fetch')
750 git('checkout %s' % branch)
751 git('pull origin %s' % branch)
752 if os.path.exists('src/%s/gen_build_yaml.py' % submodule):
753 need_to_regenerate_projects = True
754if need_to_regenerate_projects:
755 if jobset.platform_string() == 'linux':
756 subprocess.check_call('tools/buildgen/generate_projects.sh', shell=True)
757 else:
758 print 'WARNING: may need to regenerate projects, but since we are not on'
759 print ' Linux this step is being skipped. Compilation MAY fail.'
Craig Tiller1676f912016-01-05 10:49:44 -0800760
761
Nicolas Nobleddef2462015-01-06 18:08:25 -0800762# grab config
Jan Tattermusch77db4322016-02-20 20:19:35 -0800763run_config = _CONFIGS[args.config]
764build_config = run_config.build_config
Craig Tillerf1973b02015-01-16 12:32:13 -0800765
Craig Tiller06805272015-06-11 14:46:47 -0700766if args.travis:
murgatroid99d3b5b7f2015-10-06 17:02:03 -0700767 _FORCE_ENVIRON_FOR_WRAPPERS = {'GRPC_TRACE': 'api'}
Craig Tiller06805272015-06-11 14:46:47 -0700768
Adele Zhou6b9527c2015-11-20 15:56:35 -0800769if 'all' in args.language:
Craig Tiller1676f912016-01-05 10:49:44 -0800770 lang_list = _LANGUAGES.keys()
Adele Zhou6b9527c2015-11-20 15:56:35 -0800771else:
772 lang_list = args.language
Craig Tiller16900662016-01-07 19:30:54 -0800773# We don't support code coverage on some languages
774if 'gcov' in args.config:
Jan Tattermusch3b5121b2016-02-22 17:41:05 -0800775 for bad in ['objc', 'sanity']:
Craig Tiller16900662016-01-07 19:30:54 -0800776 if bad in lang_list:
777 lang_list.remove(bad)
Adele Zhou6b9527c2015-11-20 15:56:35 -0800778
779languages = set(_LANGUAGES[l] for l in lang_list)
Jan Tattermusch77db4322016-02-20 20:19:35 -0800780for l in languages:
781 l.configure(run_config, args)
murgatroid99132ce6a2015-03-04 17:29:14 -0800782
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800783language_make_options=[]
784if any(language.make_options() for language in languages):
785 if len(languages) != 1:
786 print 'languages with custom make options cannot be built simultaneously with other languages'
787 sys.exit(1)
788 else:
789 language_make_options = next(iter(languages)).make_options()
790
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800791if args.use_docker:
792 if not args.travis:
793 print 'Seen --use_docker flag, will run tests under docker.'
794 print
795 print 'IMPORTANT: The changes you are testing need to be locally committed'
796 print 'because only the committed changes in the current branch will be'
797 print 'copied to the docker environment.'
798 time.sleep(5)
799
Jan Tattermusch3b5121b2016-02-22 17:41:05 -0800800 dockerfile_dirs = set([l.dockerfile_dir() for l in languages])
801 if len(dockerfile_dirs) > 1:
802 print 'Languages to be tested require running under different docker images.'
803 sys.exit(1)
804 dockerfile_dir = next(iter(dockerfile_dirs))
805
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800806 child_argv = [ arg for arg in sys.argv if not arg == '--use_docker' ]
Jan Tattermusched342b12016-01-26 14:40:31 -0800807 run_tests_cmd = 'python tools/run_tests/run_tests.py %s' % ' '.join(child_argv[1:])
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800808
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800809 env = os.environ.copy()
810 env['RUN_TESTS_COMMAND'] = run_tests_cmd
Jan Tattermusch3b5121b2016-02-22 17:41:05 -0800811 env['DOCKERFILE_DIR'] = dockerfile_dir
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800812 env['DOCKER_RUN_SCRIPT'] = 'tools/jenkins/docker_run_tests.sh'
813 if args.xml_report:
814 env['XML_REPORT'] = args.xml_report
815 if not args.travis:
816 env['TTY_FLAG'] = '-t' # enables Ctrl-C when not on Jenkins.
817
818 subprocess.check_call(['tools/jenkins/build_docker_and_run_tests.sh'],
819 shell=True,
820 env=env)
821 sys.exit(0)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800822
Jan Tattermuschf08018a2016-01-26 08:22:09 -0800823_check_arch_option(args.arch)
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800824
Jan Tattermuschfba65302016-01-25 18:21:14 -0800825def make_jobspec(cfg, targets, makefile='Makefile'):
826 if platform_string() == 'windows':
Craig Tillerfc3c0c42015-09-01 16:47:54 -0700827 extra_args = []
Craig Tillerb5391e12015-09-03 14:35:18 -0700828 # better do parallel compilation
Jan Tattermusch47eeb2b2015-10-07 14:09:18 -0700829 # empirically /m:2 gives the best performance/price and should prevent
830 # overloading the windows workers.
Adele Zhoue4c35612015-10-16 15:34:23 -0700831 extra_args.extend(['/m:2'])
Craig Tillerb5391e12015-09-03 14:35:18 -0700832 # disable PDB generation: it's broken, and we don't need it during CI
Adele Zhoue4c35612015-10-16 15:34:23 -0700833 extra_args.extend(['/p:Jenkins=true'])
Craig Tiller6fd23842015-09-01 07:36:31 -0700834 return [
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800835 jobset.JobSpec([_windows_build_bat(args.compiler),
murgatroid99cf08daf2015-09-21 15:33:16 -0700836 'vsprojects\\%s.sln' % target,
Jan Tattermuscha2d964c2016-02-22 17:33:09 -0800837 '/p:Configuration=%s' % _MSBUILD_CONFIG[cfg]] +
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800838 extra_args +
839 language_make_options,
Craig Tiller590105a2016-01-19 13:03:46 -0800840 shell=True, timeout_seconds=None)
Craig Tiller6fd23842015-09-01 07:36:31 -0700841 for target in targets]
Jan Tattermuschfba65302016-01-25 18:21:14 -0800842 else:
murgatroid998ae409f2015-10-26 16:39:00 -0700843 if targets:
844 return [jobset.JobSpec([os.getenv('MAKE', 'make'),
845 '-f', makefile,
Craig Tillerdd6f7ed2016-01-21 12:54:42 -0800846 '-j', '%d' % args.jobs,
Craig Tiller71a86042016-01-15 14:59:58 -0800847 'EXTRA_DEFINES=GRPC_TEST_SLOWDOWN_MACHINE_FACTOR=%f' % args.slowdown,
848 'CONFIG=%s' % cfg] +
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800849 language_make_options +
Craig Tiller71a86042016-01-15 14:59:58 -0800850 ([] if not args.travis else ['JENKINS_BUILD=1']) +
851 targets,
Craig Tiller590105a2016-01-19 13:03:46 -0800852 timeout_seconds=None)]
murgatroid998ae409f2015-10-26 16:39:00 -0700853 else:
854 return []
Jan Tattermuschfba65302016-01-25 18:21:14 -0800855
murgatroid99a3e244f2015-09-22 11:25:53 -0700856make_targets = {}
857for l in languages:
858 makefile = l.makefile_name()
859 make_targets[makefile] = make_targets.get(makefile, set()).union(
Jan Tattermusch77db4322016-02-20 20:19:35 -0800860 set(l.make_targets()))
Craig Tiller5058c692015-04-08 09:42:04 -0700861
Jan Tattermusche4a69182015-12-15 09:53:01 -0800862def build_step_environ(cfg):
863 environ = {'CONFIG': cfg}
Jan Tattermuscha2d964c2016-02-22 17:33:09 -0800864 msbuild_cfg = _MSBUILD_CONFIG.get(cfg)
Jan Tattermusche4a69182015-12-15 09:53:01 -0800865 if msbuild_cfg:
866 environ['MSBUILD_CONFIG'] = msbuild_cfg
867 return environ
868
murgatroid99fddac962015-09-22 09:20:11 -0700869build_steps = list(set(
Jan Tattermusch77db4322016-02-20 20:19:35 -0800870 jobset.JobSpec(cmdline, environ=build_step_environ(build_config), flake_retries=5)
murgatroid99256d3df2015-09-21 16:58:02 -0700871 for l in languages
872 for cmdline in l.pre_build_steps()))
Craig Tillerbd4e3782015-09-01 06:48:55 -0700873if make_targets:
Jan Tattermusch77db4322016-02-20 20:19:35 -0800874 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 -0700875 build_steps.extend(set(make_commands))
Craig Tiller5058c692015-04-08 09:42:04 -0700876build_steps.extend(set(
Jan Tattermusch77db4322016-02-20 20:19:35 -0800877 jobset.JobSpec(cmdline, environ=build_step_environ(build_config), timeout_seconds=None)
Craig Tiller547db2b2015-01-30 14:08:39 -0800878 for l in languages
Craig Tiller533b1a22015-05-29 08:41:29 -0700879 for cmdline in l.build_steps()))
Craig Tillerf1973b02015-01-16 12:32:13 -0800880
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200881post_tests_steps = list(set(
Jan Tattermusch77db4322016-02-20 20:19:35 -0800882 jobset.JobSpec(cmdline, environ=build_step_environ(build_config))
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200883 for l in languages
884 for cmdline in l.post_tests_steps()))
Nicolas Nobleddef2462015-01-06 18:08:25 -0800885runs_per_test = args.runs_per_test
ctiller3040cb72015-01-07 12:13:17 -0800886forever = args.forever
Nicolas Nobleddef2462015-01-06 18:08:25 -0800887
Nicolas Nobleddef2462015-01-06 18:08:25 -0800888
Craig Tiller71735182015-01-15 17:07:13 -0800889class TestCache(object):
Craig Tillerb50d1662015-01-15 17:28:21 -0800890 """Cache for running tests."""
891
David Klempner25739582015-02-11 15:57:32 -0800892 def __init__(self, use_cache_results):
Craig Tiller71735182015-01-15 17:07:13 -0800893 self._last_successful_run = {}
David Klempner25739582015-02-11 15:57:32 -0800894 self._use_cache_results = use_cache_results
Craig Tiller69cd2372015-06-11 09:38:09 -0700895 self._last_save = time.time()
Craig Tiller71735182015-01-15 17:07:13 -0800896
897 def should_run(self, cmdline, bin_hash):
Craig Tiller71735182015-01-15 17:07:13 -0800898 if cmdline not in self._last_successful_run:
899 return True
900 if self._last_successful_run[cmdline] != bin_hash:
901 return True
David Klempner25739582015-02-11 15:57:32 -0800902 if not self._use_cache_results:
903 return True
Craig Tiller71735182015-01-15 17:07:13 -0800904 return False
905
906 def finished(self, cmdline, bin_hash):
Craig Tiller547db2b2015-01-30 14:08:39 -0800907 self._last_successful_run[cmdline] = bin_hash
Craig Tiller69cd2372015-06-11 09:38:09 -0700908 if time.time() - self._last_save > 1:
909 self.save()
Craig Tiller71735182015-01-15 17:07:13 -0800910
911 def dump(self):
Craig Tillerb50d1662015-01-15 17:28:21 -0800912 return [{'cmdline': k, 'hash': v}
913 for k, v in self._last_successful_run.iteritems()]
Craig Tiller71735182015-01-15 17:07:13 -0800914
915 def parse(self, exdump):
916 self._last_successful_run = dict((o['cmdline'], o['hash']) for o in exdump)
917
918 def save(self):
919 with open('.run_tests_cache', 'w') as f:
Craig Tiller261dd982015-01-16 16:41:45 -0800920 f.write(json.dumps(self.dump()))
Craig Tiller69cd2372015-06-11 09:38:09 -0700921 self._last_save = time.time()
Craig Tiller71735182015-01-15 17:07:13 -0800922
Craig Tiller1cc11db2015-01-15 22:50:50 -0800923 def maybe_load(self):
924 if os.path.exists('.run_tests_cache'):
925 with open('.run_tests_cache') as f:
Craig Tiller261dd982015-01-16 16:41:45 -0800926 self.parse(json.loads(f.read()))
Craig Tiller71735182015-01-15 17:07:13 -0800927
928
Craig Tillerf53d9c82015-08-04 14:19:43 -0700929def _start_port_server(port_server_port):
930 # check if a compatible port server is running
931 # if incompatible (version mismatch) ==> start a new one
932 # if not running ==> start a new one
933 # otherwise, leave it up
934 try:
Craig Tillerfe4939f2015-10-06 12:55:36 -0700935 version = int(urllib2.urlopen(
936 'http://localhost:%d/version_number' % port_server_port,
937 timeout=1).read())
938 print 'detected port server running version %d' % version
Craig Tillerf53d9c82015-08-04 14:19:43 -0700939 running = True
Craig Tillerfe4939f2015-10-06 12:55:36 -0700940 except Exception as e:
Craig Tiller0d6499e2015-10-05 14:00:47 -0700941 print 'failed to detect port server: %s' % sys.exc_info()[0]
Craig Tillerfe4939f2015-10-06 12:55:36 -0700942 print e.strerror
Craig Tillerf53d9c82015-08-04 14:19:43 -0700943 running = False
944 if running:
Craig Tillerfe4939f2015-10-06 12:55:36 -0700945 current_version = int(subprocess.check_output(
Jan Tattermusch3bd08272015-11-04 19:24:37 -0800946 [sys.executable, os.path.abspath('tools/run_tests/port_server.py'),
947 'dump_version']))
Craig Tillerfe4939f2015-10-06 12:55:36 -0700948 print 'my port server is version %d' % current_version
949 running = (version >= current_version)
950 if not running:
951 print 'port_server version mismatch: killing the old one'
952 urllib2.urlopen('http://localhost:%d/quitquitquit' % port_server_port).read()
953 time.sleep(1)
Craig Tillerf53d9c82015-08-04 14:19:43 -0700954 if not running:
Craig Tillerf0a293e2015-10-12 10:05:50 -0700955 fd, logfile = tempfile.mkstemp()
956 os.close(fd)
957 print 'starting port_server, with log file %s' % logfile
Jan Tattermusch3bd08272015-11-04 19:24:37 -0800958 args = [sys.executable, os.path.abspath('tools/run_tests/port_server.py'),
959 '-p', '%d' % port_server_port, '-l', logfile]
Craig Tiller367d41d2015-10-12 13:00:22 -0700960 env = dict(os.environ)
961 env['BUILD_ID'] = 'pleaseDontKillMeJenkins'
Nicolas "Pixel" Noblef72d7b52015-12-03 03:07:43 +0100962 if platform_string() == 'windows':
Jan Tattermusch3bd08272015-11-04 19:24:37 -0800963 # Working directory of port server needs to be outside of Jenkins
964 # workspace to prevent file lock issues.
965 tempdir = tempfile.mkdtemp()
Craig Tillerd2c39712015-10-12 11:08:49 -0700966 port_server = subprocess.Popen(
Craig Tiller367d41d2015-10-12 13:00:22 -0700967 args,
968 env=env,
Jan Tattermusch3bd08272015-11-04 19:24:37 -0800969 cwd=tempdir,
Craig Tiller367d41d2015-10-12 13:00:22 -0700970 creationflags = 0x00000008, # detached process
971 close_fds=True)
Craig Tillerd2c39712015-10-12 11:08:49 -0700972 else:
973 port_server = subprocess.Popen(
974 args,
Craig Tiller367d41d2015-10-12 13:00:22 -0700975 env=env,
Craig Tillerd2c39712015-10-12 11:08:49 -0700976 preexec_fn=os.setsid,
977 close_fds=True)
Craig Tillerf0a293e2015-10-12 10:05:50 -0700978 time.sleep(1)
Craig Tiller8b5f4dc2015-08-26 08:02:01 -0700979 # ensure port server is up
Craig Tillerabd37fd2015-08-26 07:54:01 -0700980 waits = 0
Craig Tillerf53d9c82015-08-04 14:19:43 -0700981 while True:
Craig Tillerabd37fd2015-08-26 07:54:01 -0700982 if waits > 10:
Craig Tillerf0a293e2015-10-12 10:05:50 -0700983 print 'killing port server due to excessive start up waits'
Craig Tillerabd37fd2015-08-26 07:54:01 -0700984 port_server.kill()
Craig Tillera2f38b02015-09-24 11:19:17 -0700985 if port_server.poll() is not None:
Craig Tiller0d6499e2015-10-05 14:00:47 -0700986 print 'port_server failed to start'
Craig Tillerf0a293e2015-10-12 10:05:50 -0700987 # try one final time: maybe another build managed to start one
988 time.sleep(1)
989 try:
990 urllib2.urlopen('http://localhost:%d/get' % port_server_port,
991 timeout=1).read()
992 print 'last ditch attempt to contact port server succeeded'
993 break
994 except:
Jan Tattermusch3b5121b2016-02-22 17:41:05 -0800995 traceback.print_exc()
Craig Tillerf0a293e2015-10-12 10:05:50 -0700996 port_log = open(logfile, 'r').read()
997 print port_log
998 sys.exit(1)
Craig Tillerf53d9c82015-08-04 14:19:43 -0700999 try:
Craig Tillerabd37fd2015-08-26 07:54:01 -07001000 urllib2.urlopen('http://localhost:%d/get' % port_server_port,
1001 timeout=1).read()
Craig Tillerf0a293e2015-10-12 10:05:50 -07001002 print 'port server is up and ready'
Craig Tillerf53d9c82015-08-04 14:19:43 -07001003 break
Craig Tiller31fdaa42015-09-25 13:09:59 -07001004 except socket.timeout:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001005 print 'waiting for port_server: timeout'
Craig Tillerf0a293e2015-10-12 10:05:50 -07001006 traceback.print_exc();
1007 time.sleep(1)
Craig Tiller31fdaa42015-09-25 13:09:59 -07001008 waits += 1
Craig Tillerf53d9c82015-08-04 14:19:43 -07001009 except urllib2.URLError:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001010 print 'waiting for port_server: urlerror'
Craig Tillerf0a293e2015-10-12 10:05:50 -07001011 traceback.print_exc();
1012 time.sleep(1)
Craig Tillerabd37fd2015-08-26 07:54:01 -07001013 waits += 1
Craig Tillerf53d9c82015-08-04 14:19:43 -07001014 except:
Jan Tattermusch3b5121b2016-02-22 17:41:05 -08001015 traceback.print_exc()
Craig Tillerf53d9c82015-08-04 14:19:43 -07001016 port_server.kill()
1017 raise
1018
1019
Adele Zhoud5fffa52015-10-23 15:51:42 -07001020def _calculate_num_runs_failures(list_of_results):
1021 """Caculate number of runs and failures for a particular test.
1022
1023 Args:
1024 list_of_results: (List) of JobResult object.
1025 Returns:
1026 A tuple of total number of runs and failures.
1027 """
1028 num_runs = len(list_of_results) # By default, there is 1 run per JobResult.
1029 num_failures = 0
1030 for jobresult in list_of_results:
1031 if jobresult.retries > 0:
1032 num_runs += jobresult.retries
1033 if jobresult.num_failures > 0:
1034 num_failures += jobresult.num_failures
1035 return num_runs, num_failures
1036
Adele Zhou6b9527c2015-11-20 15:56:35 -08001037
Craig Tillereb9de8b2016-01-08 08:57:41 -08001038# _build_and_run results
1039class BuildAndRunError(object):
1040
1041 BUILD = object()
1042 TEST = object()
1043 POST_TEST = object()
1044
1045
1046# returns a list of things that failed (or an empty list on success)
Craig Tillerf53d9c82015-08-04 14:19:43 -07001047def _build_and_run(
Jan Tattermusch2dd156e2015-12-04 18:26:17 -08001048 check_cancelled, newline_on_success, cache, xml_report=None, build_only=False):
ctiller3040cb72015-01-07 12:13:17 -08001049 """Do one pass of building & running tests."""
murgatroid99666450e2015-01-26 13:03:31 -08001050 # build latest sequentially
Jan Tattermuschaab1e512016-01-28 09:30:44 -08001051 num_failures, resultset = jobset.run(
Adele Zhoue4c35612015-10-16 15:34:23 -07001052 build_steps, maxjobs=1, stop_on_failure=True,
Craig Tiller883064c2015-11-04 10:06:10 -08001053 newline_on_success=newline_on_success, travis=args.travis)
Adele Zhoue4c35612015-10-16 15:34:23 -07001054 if num_failures:
Craig Tillereb9de8b2016-01-08 08:57:41 -08001055 return [BuildAndRunError.BUILD]
Craig Tillerb361b4e2016-01-06 11:44:17 -08001056
Jan Tattermusch2dd156e2015-12-04 18:26:17 -08001057 if build_only:
Jan Tattermuschaab1e512016-01-28 09:30:44 -08001058 if xml_report:
1059 report_utils.render_junit_xml_report(resultset, xml_report)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001060 return []
ctiller3040cb72015-01-07 12:13:17 -08001061
Craig Tiller234b6e72015-05-23 10:12:40 -07001062 # start antagonists
David Garcia Quintas79e389f2015-06-02 17:49:42 -07001063 antagonists = [subprocess.Popen(['tools/run_tests/antagonist.py'])
Craig Tiller234b6e72015-05-23 10:12:40 -07001064 for _ in range(0, args.antagonists)]
Craig Tillerfe4939f2015-10-06 12:55:36 -07001065 port_server_port = 32767
Craig Tillerf53d9c82015-08-04 14:19:43 -07001066 _start_port_server(port_server_port)
Adele Zhou7cf72112015-11-04 11:18:43 -08001067 resultset = None
Adele Zhou803af152015-11-30 15:16:16 -08001068 num_test_failures = 0
Craig Tiller234b6e72015-05-23 10:12:40 -07001069 try:
David Garcia Quintase90cd372015-05-31 18:15:26 -07001070 infinite_runs = runs_per_test == 0
yang-g6c1fdc62015-08-18 11:57:42 -07001071 one_run = set(
1072 spec
yang-g6c1fdc62015-08-18 11:57:42 -07001073 for language in languages
Jan Tattermusch77db4322016-02-20 20:19:35 -08001074 for spec in language.test_specs()
yang-g6c1fdc62015-08-18 11:57:42 -07001075 if re.search(args.regex, spec.shortname))
David Garcia Quintas79e389f2015-06-02 17:49:42 -07001076 # When running on travis, we want out test runs to be as similar as possible
1077 # for reproducibility purposes.
Craig Tiller883064c2015-11-04 10:06:10 -08001078 if args.travis:
David Garcia Quintas79e389f2015-06-02 17:49:42 -07001079 massaged_one_run = sorted(one_run, key=lambda x: x.shortname)
1080 else:
1081 # whereas otherwise, we want to shuffle things up to give all tests a
1082 # chance to run.
1083 massaged_one_run = list(one_run) # random.shuffle needs an indexable seq.
1084 random.shuffle(massaged_one_run) # which it modifies in-place.
Craig Tillerf7b7c892015-06-22 14:33:25 -07001085 if infinite_runs:
1086 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 -07001087 runs_sequence = (itertools.repeat(massaged_one_run) if infinite_runs
1088 else itertools.repeat(massaged_one_run, runs_per_test))
David Garcia Quintase90cd372015-05-31 18:15:26 -07001089 all_runs = itertools.chain.from_iterable(runs_sequence)
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +02001090
Adele Zhou803af152015-11-30 15:16:16 -08001091 num_test_failures, resultset = jobset.run(
Adele Zhou2271ab52015-10-28 13:59:14 -07001092 all_runs, check_cancelled, newline_on_success=newline_on_success,
Craig Tiller883064c2015-11-04 10:06:10 -08001093 travis=args.travis, infinite_runs=infinite_runs, maxjobs=args.jobs,
murgatroid998ae409f2015-10-26 16:39:00 -07001094 stop_on_failure=args.stop_on_failure,
Adele Zhouf2ca7bc2015-10-23 15:38:00 -07001095 cache=cache if not xml_report else None,
Adele Zhouf2ca7bc2015-10-23 15:38:00 -07001096 add_env={'GRPC_TEST_PORT_SERVER': 'localhost:%d' % port_server_port})
Adele Zhoud5fffa52015-10-23 15:51:42 -07001097 if resultset:
1098 for k, v in resultset.iteritems():
1099 num_runs, num_failures = _calculate_num_runs_failures(v)
1100 if num_failures == num_runs: # what about infinite_runs???
1101 jobset.message('FAILED', k, do_newline=True)
1102 elif num_failures > 0:
1103 jobset.message(
1104 'FLAKE', '%s [%d/%d runs flaked]' % (k, num_failures, num_runs),
1105 do_newline=True)
1106 else:
1107 jobset.message('PASSED', k, do_newline=True)
Craig Tiller234b6e72015-05-23 10:12:40 -07001108 finally:
1109 for antagonist in antagonists:
1110 antagonist.kill()
Adele Zhou7cf72112015-11-04 11:18:43 -08001111 if xml_report and resultset:
Adele Zhou3bc7ba42015-11-05 10:21:58 -08001112 report_utils.render_junit_xml_report(resultset, xml_report)
Craig Tillerd86a3942015-01-14 12:48:54 -08001113
Adele Zhouf2ca7bc2015-10-23 15:38:00 -07001114 number_failures, _ = jobset.run(
1115 post_tests_steps, maxjobs=1, stop_on_failure=True,
Craig Tiller883064c2015-11-04 10:06:10 -08001116 newline_on_success=newline_on_success, travis=args.travis)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001117
1118 out = []
1119 if number_failures:
1120 out.append(BuildAndRunError.POST_TEST)
1121 if num_test_failures:
1122 out.append(BuildAndRunError.TEST)
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +02001123
Craig Tiller69cd2372015-06-11 09:38:09 -07001124 if cache: cache.save()
1125
Craig Tillereb9de8b2016-01-08 08:57:41 -08001126 return out
ctiller3040cb72015-01-07 12:13:17 -08001127
1128
David Klempner25739582015-02-11 15:57:32 -08001129test_cache = TestCache(runs_per_test == 1)
Craig Tiller547db2b2015-01-30 14:08:39 -08001130test_cache.maybe_load()
Craig Tiller71735182015-01-15 17:07:13 -08001131
ctiller3040cb72015-01-07 12:13:17 -08001132if forever:
Nicolas Noble044db742015-01-14 16:57:24 -08001133 success = True
ctiller3040cb72015-01-07 12:13:17 -08001134 while True:
Craig Tiller42bc87c2015-02-23 08:50:19 -08001135 dw = watch_dirs.DirWatcher(['src', 'include', 'test', 'examples'])
ctiller3040cb72015-01-07 12:13:17 -08001136 initial_time = dw.most_recent_change()
1137 have_files_changed = lambda: dw.most_recent_change() != initial_time
Nicolas Noble044db742015-01-14 16:57:24 -08001138 previous_success = success
Craig Tillereb9de8b2016-01-08 08:57:41 -08001139 errors = _build_and_run(check_cancelled=have_files_changed,
1140 newline_on_success=False,
1141 cache=test_cache,
1142 build_only=args.build_only) == 0
1143 if not previous_success and not errors:
Nicolas Nobleb09078f2015-01-14 18:06:05 -08001144 jobset.message('SUCCESS',
1145 'All tests are now passing properly',
1146 do_newline=True)
Nicolas Noble044db742015-01-14 16:57:24 -08001147 jobset.message('IDLE', 'No change detected')
ctiller3040cb72015-01-07 12:13:17 -08001148 while not have_files_changed():
1149 time.sleep(1)
1150else:
Craig Tillereb9de8b2016-01-08 08:57:41 -08001151 errors = _build_and_run(check_cancelled=lambda: False,
Craig Tiller71735182015-01-15 17:07:13 -08001152 newline_on_success=args.newline_on_success,
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +02001153 cache=test_cache,
Jan Tattermusch2dd156e2015-12-04 18:26:17 -08001154 xml_report=args.xml_report,
1155 build_only=args.build_only)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001156 if not errors:
Nicolas Nobleb09078f2015-01-14 18:06:05 -08001157 jobset.message('SUCCESS', 'All tests passed', do_newline=True)
1158 else:
1159 jobset.message('FAILED', 'Some tests failed', do_newline=True)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001160 exit_code = 0
1161 if BuildAndRunError.BUILD in errors:
1162 exit_code |= 1
Craig Tiller4f2be362016-01-08 08:59:20 -08001163 if BuildAndRunError.TEST in errors and not args.travis:
Craig Tillereb9de8b2016-01-08 08:57:41 -08001164 exit_code |= 2
Craig Tiller4f2be362016-01-08 08:59:20 -08001165 if BuildAndRunError.POST_TEST in errors:
1166 exit_code |= 4
Craig Tillereb9de8b2016-01-08 08:57:41 -08001167 sys.exit(exit_code)