blob: d271137ca124c065a8002e71df0789c5cb359ccf [file] [log] [blame]
Nathaniel Manistaae4fbcd2015-09-23 16:29:44 +00001#!/usr/bin/env python2.7
Craig Tillerc2c79212015-02-16 12:00:01 -08002# Copyright 2015, Google Inc.
3# 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
34import glob
Craig Tillerf53d9c82015-08-04 14:19:43 -070035import hashlib
Nicolas Nobleddef2462015-01-06 18:08:25 -080036import itertools
Craig Tiller261dd982015-01-16 16:41:45 -080037import json
Nicolas Nobleddef2462015-01-06 18:08:25 -080038import multiprocessing
Craig Tiller1cc11db2015-01-15 22:50:50 -080039import os
David Garcia Quintas79e389f2015-06-02 17:49:42 -070040import platform
41import random
Craig Tillerfe406ec2015-02-24 13:55:12 -080042import re
David Garcia Quintas79e389f2015-06-02 17:49:42 -070043import subprocess
Nicolas Nobleddef2462015-01-06 18:08:25 -080044import sys
ctiller3040cb72015-01-07 12:13:17 -080045import time
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +020046import xml.etree.cElementTree as ET
Craig Tillerf53d9c82015-08-04 14:19:43 -070047import urllib2
Nicolas Nobleddef2462015-01-06 18:08:25 -080048
49import jobset
ctiller3040cb72015-01-07 12:13:17 -080050import watch_dirs
Nicolas Nobleddef2462015-01-06 18:08:25 -080051
Craig Tiller2cc2b842015-02-27 11:38:31 -080052ROOT = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), '../..'))
53os.chdir(ROOT)
54
55
Craig Tiller06805272015-06-11 14:46:47 -070056_FORCE_ENVIRON_FOR_WRAPPERS = {}
57
58
Craig Tillerd50993d2015-08-05 08:04:36 -070059def platform_string():
60 if platform.system() == 'Windows':
61 return 'windows'
62 elif platform.system() == 'Darwin':
63 return 'mac'
64 elif platform.system() == 'Linux':
65 return 'linux'
66 else:
67 return 'posix'
68
69
Craig Tiller738c3342015-01-12 14:28:33 -080070# SimpleConfig: just compile with CONFIG=config, and run the binary to test
71class SimpleConfig(object):
Craig Tillerb50d1662015-01-15 17:28:21 -080072
Craig Tillerb2ea0b92015-08-26 13:06:53 -070073 def __init__(self, config, environ=None, timeout_seconds=5*60):
murgatroid99132ce6a2015-03-04 17:29:14 -080074 if environ is None:
75 environ = {}
Craig Tiller738c3342015-01-12 14:28:33 -080076 self.build_config = config
Craig Tillerc7449162015-01-16 14:42:10 -080077 self.allow_hashing = (config != 'gcov')
Craig Tiller547db2b2015-01-30 14:08:39 -080078 self.environ = environ
murgatroid99132ce6a2015-03-04 17:29:14 -080079 self.environ['CONFIG'] = config
Craig Tillerb2ea0b92015-08-26 13:06:53 -070080 self.timeout_seconds = timeout_seconds
Craig Tiller738c3342015-01-12 14:28:33 -080081
Craig Tiller4fc90032015-05-21 10:39:52 -070082 def job_spec(self, cmdline, hash_targets, shortname=None, environ={}):
Craig Tiller49f61322015-03-03 13:02:11 -080083 """Construct a jobset.JobSpec for a test under this config
84
85 Args:
86 cmdline: a list of strings specifying the command line the test
87 would like to run
88 hash_targets: either None (don't do caching of test results), or
89 a list of strings specifying files to include in a
90 binary hash to check if a test has changed
91 -- if used, all artifacts needed to run the test must
92 be listed
93 """
Craig Tiller4fc90032015-05-21 10:39:52 -070094 actual_environ = self.environ.copy()
95 for k, v in environ.iteritems():
96 actual_environ[k] = v
Craig Tiller49f61322015-03-03 13:02:11 -080097 return jobset.JobSpec(cmdline=cmdline,
Jan Tattermusch9a7d30c2015-04-23 16:12:55 -070098 shortname=shortname,
Craig Tiller4fc90032015-05-21 10:39:52 -070099 environ=actual_environ,
Craig Tillerb2ea0b92015-08-26 13:06:53 -0700100 timeout_seconds=self.timeout_seconds,
Craig Tiller547db2b2015-01-30 14:08:39 -0800101 hash_targets=hash_targets
102 if self.allow_hashing else None)
Craig Tiller738c3342015-01-12 14:28:33 -0800103
104
105# ValgrindConfig: compile with some CONFIG=config, but use valgrind to run
106class ValgrindConfig(object):
Craig Tillerb50d1662015-01-15 17:28:21 -0800107
murgatroid99132ce6a2015-03-04 17:29:14 -0800108 def __init__(self, config, tool, args=None):
109 if args is None:
110 args = []
Craig Tiller738c3342015-01-12 14:28:33 -0800111 self.build_config = config
Craig Tiller2aa4d642015-01-14 15:59:44 -0800112 self.tool = tool
Craig Tiller1a305b12015-02-18 13:37:06 -0800113 self.args = args
Craig Tillerc7449162015-01-16 14:42:10 -0800114 self.allow_hashing = False
Craig Tiller738c3342015-01-12 14:28:33 -0800115
Craig Tiller49f61322015-03-03 13:02:11 -0800116 def job_spec(self, cmdline, hash_targets):
Craig Tiller1a305b12015-02-18 13:37:06 -0800117 return jobset.JobSpec(cmdline=['valgrind', '--tool=%s' % self.tool] +
Craig Tiller49f61322015-03-03 13:02:11 -0800118 self.args + cmdline,
Craig Tiller71ec6cb2015-06-03 00:51:11 -0700119 shortname='valgrind %s' % cmdline[0],
Craig Tiller1a305b12015-02-18 13:37:06 -0800120 hash_targets=None)
Craig Tiller738c3342015-01-12 14:28:33 -0800121
122
murgatroid99cf08daf2015-09-21 15:33:16 -0700123def get_c_tests(travis, test_lang) :
124 out = []
125 platforms_str = 'ci_platforms' if travis else 'platforms'
126 with open('tools/run_tests/tests.json') as f:
murgatroid9989899b12015-09-22 09:14:48 -0700127 js = json.load(f)
murgatroid99a3e244f2015-09-22 11:25:53 -0700128 return [tgt
129 for tgt in js
130 if tgt['language'] == test_lang and
131 platform_string() in tgt[platforms_str] and
132 not (travis and tgt['flaky'])]
murgatroid99cf08daf2015-09-21 15:33:16 -0700133
murgatroid99fafeeb32015-09-22 09:13:03 -0700134
Craig Tillerc7449162015-01-16 14:42:10 -0800135class CLanguage(object):
136
Craig Tillere9c959d2015-01-18 10:23:26 -0800137 def __init__(self, make_target, test_lang):
Craig Tillerc7449162015-01-16 14:42:10 -0800138 self.make_target = make_target
Craig Tillerd50993d2015-08-05 08:04:36 -0700139 self.platform = platform_string()
Craig Tiller711bbe62015-08-19 12:35:16 -0700140 self.test_lang = test_lang
Craig Tillerc7449162015-01-16 14:42:10 -0800141
Nicolas "Pixel" Noble9db7c3b2015-02-27 06:03:00 +0100142 def test_specs(self, config, travis):
Craig Tiller547db2b2015-01-30 14:08:39 -0800143 out = []
murgatroid99cf08daf2015-09-21 15:33:16 -0700144 binaries = get_c_tests(travis, self.test_lang)
Craig Tiller711bbe62015-08-19 12:35:16 -0700145 for target in binaries:
murgatroid99a3e244f2015-09-22 11:25:53 -0700146 if config.build_config in target['exclude_configs']:
murgatroid99fafeeb32015-09-22 09:13:03 -0700147 continue
Nicolas Noblee1445362015-05-11 17:40:26 -0700148 if self.platform == 'windows':
Craig Tillerf4182602015-09-01 12:23:16 -0700149 binary = 'vsprojects/%s/%s.exe' % (
150 _WINDOWS_CONFIG[config.build_config], target['name'])
Nicolas Noblee1445362015-05-11 17:40:26 -0700151 else:
152 binary = 'bins/%s/%s' % (config.build_config, target['name'])
yang-g6c1fdc62015-08-18 11:57:42 -0700153 if os.path.isfile(binary):
154 out.append(config.job_spec([binary], [binary]))
155 else:
156 print "\nWARNING: binary not found, skipping", binary
Nicolas Noblee1445362015-05-11 17:40:26 -0700157 return sorted(out)
Craig Tillerc7449162015-01-16 14:42:10 -0800158
159 def make_targets(self):
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700160 if platform_string() == 'windows':
161 # don't build tools on windows just yet
162 return ['buildtests_%s' % self.make_target]
Craig Tiller7552f0f2015-06-19 17:46:20 -0700163 return ['buildtests_%s' % self.make_target, 'tools_%s' % self.make_target]
Craig Tillerc7449162015-01-16 14:42:10 -0800164
murgatroid99256d3df2015-09-21 16:58:02 -0700165 def pre_build_steps(self):
166 return []
167
Craig Tillerc7449162015-01-16 14:42:10 -0800168 def build_steps(self):
169 return []
170
murgatroid99a3e244f2015-09-22 11:25:53 -0700171 def makefile_name(self):
172 return 'Makefile'
173
murgatroid99132ce6a2015-03-04 17:29:14 -0800174 def supports_multi_config(self):
175 return True
176
177 def __str__(self):
178 return self.make_target
179
murgatroid99fafeeb32015-09-22 09:13:03 -0700180
murgatroid99cf08daf2015-09-21 15:33:16 -0700181def gyp_test_paths(travis, config=None):
182 binaries = get_c_tests(travis, 'c')
183 out = []
184 for target in binaries:
murgatroid99fddac962015-09-22 09:20:11 -0700185 if config is not None and config.build_config in target['exclude_configs']:
murgatroid99cf08daf2015-09-21 15:33:16 -0700186 continue
187 binary = 'out/Debug/%s' % target['name']
188 out.append(binary)
189 return sorted(out)
190
murgatroid99fafeeb32015-09-22 09:13:03 -0700191
murgatroid99cf08daf2015-09-21 15:33:16 -0700192class GYPCLanguage(object):
193
194 def test_specs(self, config, travis):
195 return [config.job_spec([binary], [binary])
196 for binary in gyp_test_paths(travis, config)]
197
murgatroid99256d3df2015-09-21 16:58:02 -0700198 def pre_build_steps(self):
murgatroid99a3e244f2015-09-22 11:25:53 -0700199 return [['gyp', '--depth=.', '--suffix=-gyp', 'grpc.gyp']]
murgatroid99256d3df2015-09-21 16:58:02 -0700200
murgatroid99cf08daf2015-09-21 15:33:16 -0700201 def make_targets(self):
Craig Tillerc1385d62015-09-24 08:52:00 -0700202 # HACK(ctiller): force fling_client and fling_server to be built, as fling_test
203 # needs these
204 return gyp_test_paths(False) + ['fling_client', 'fling_server']
murgatroid99cf08daf2015-09-21 15:33:16 -0700205
206 def build_steps(self):
207 return []
208
murgatroid99a3e244f2015-09-22 11:25:53 -0700209 def makefile_name(self):
210 return 'Makefile-gyp'
211
murgatroid99cf08daf2015-09-21 15:33:16 -0700212 def supports_multi_config(self):
213 return False
214
215 def __str__(self):
216 return 'gyp'
Craig Tiller99775822015-01-30 13:07:16 -0800217
murgatroid99fafeeb32015-09-22 09:13:03 -0700218
murgatroid992c8d5162015-01-26 10:41:21 -0800219class NodeLanguage(object):
220
Nicolas "Pixel" Noble9db7c3b2015-02-27 06:03:00 +0100221 def test_specs(self, config, travis):
Craig Tiller4fc90032015-05-21 10:39:52 -0700222 return [config.job_spec(['tools/run_tests/run_node.sh'], None,
Craig Tiller06805272015-06-11 14:46:47 -0700223 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
murgatroid992c8d5162015-01-26 10:41:21 -0800224
murgatroid99256d3df2015-09-21 16:58:02 -0700225 def pre_build_steps(self):
226 return []
227
murgatroid992c8d5162015-01-26 10:41:21 -0800228 def make_targets(self):
Craig Tilleraf7cf542015-05-22 10:07:34 -0700229 return ['static_c', 'shared_c']
murgatroid992c8d5162015-01-26 10:41:21 -0800230
231 def build_steps(self):
232 return [['tools/run_tests/build_node.sh']]
Craig Tillerc7449162015-01-16 14:42:10 -0800233
murgatroid99a3e244f2015-09-22 11:25:53 -0700234 def makefile_name(self):
235 return 'Makefile'
236
murgatroid99132ce6a2015-03-04 17:29:14 -0800237 def supports_multi_config(self):
238 return False
239
240 def __str__(self):
241 return 'node'
242
Craig Tiller99775822015-01-30 13:07:16 -0800243
Craig Tillerc7449162015-01-16 14:42:10 -0800244class PhpLanguage(object):
245
Nicolas "Pixel" Noble9db7c3b2015-02-27 06:03:00 +0100246 def test_specs(self, config, travis):
Craig Tiller4fc90032015-05-21 10:39:52 -0700247 return [config.job_spec(['src/php/bin/run_tests.sh'], None,
Craig Tiller06805272015-06-11 14:46:47 -0700248 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
Craig Tillerc7449162015-01-16 14:42:10 -0800249
murgatroid99256d3df2015-09-21 16:58:02 -0700250 def pre_build_steps(self):
251 return []
252
Craig Tillerc7449162015-01-16 14:42:10 -0800253 def make_targets(self):
Craig Tilleraf7cf542015-05-22 10:07:34 -0700254 return ['static_c', 'shared_c']
Craig Tillerc7449162015-01-16 14:42:10 -0800255
256 def build_steps(self):
257 return [['tools/run_tests/build_php.sh']]
258
murgatroid99a3e244f2015-09-22 11:25:53 -0700259 def makefile_name(self):
260 return 'Makefile'
261
murgatroid99132ce6a2015-03-04 17:29:14 -0800262 def supports_multi_config(self):
263 return False
264
265 def __str__(self):
266 return 'php'
267
Craig Tillerc7449162015-01-16 14:42:10 -0800268
Nathaniel Manista840615e2015-01-22 20:31:47 +0000269class PythonLanguage(object):
270
Craig Tiller49f61322015-03-03 13:02:11 -0800271 def __init__(self):
Masood Malekghassemi2b841622015-07-28 17:39:02 -0700272 self._build_python_versions = ['2.7']
Masood Malekghassemie5f70022015-06-29 09:20:26 -0700273 self._has_python_versions = []
Craig Tiller49f61322015-03-03 13:02:11 -0800274
Nicolas "Pixel" Noble9db7c3b2015-02-27 06:03:00 +0100275 def test_specs(self, config, travis):
Masood Malekghassemi2b841622015-07-28 17:39:02 -0700276 environment = dict(_FORCE_ENVIRON_FOR_WRAPPERS)
277 environment['PYVER'] = '2.7'
278 return [config.job_spec(
279 ['tools/run_tests/run_python.sh'],
280 None,
281 environ=environment,
282 shortname='py.test',
283 )]
Nathaniel Manista840615e2015-01-22 20:31:47 +0000284
murgatroid99256d3df2015-09-21 16:58:02 -0700285 def pre_build_steps(self):
286 return []
287
Nathaniel Manista840615e2015-01-22 20:31:47 +0000288 def make_targets(self):
Craig Tilleraf7cf542015-05-22 10:07:34 -0700289 return ['static_c', 'grpc_python_plugin', 'shared_c']
Nathaniel Manista840615e2015-01-22 20:31:47 +0000290
291 def build_steps(self):
Masood Malekghassemie5f70022015-06-29 09:20:26 -0700292 commands = []
293 for python_version in self._build_python_versions:
294 try:
295 with open(os.devnull, 'w') as output:
296 subprocess.check_call(['which', 'python' + python_version],
297 stdout=output, stderr=output)
298 commands.append(['tools/run_tests/build_python.sh', python_version])
299 self._has_python_versions.append(python_version)
300 except:
301 jobset.message('WARNING', 'Missing Python ' + python_version,
302 do_newline=True)
303 return commands
Nathaniel Manista840615e2015-01-22 20:31:47 +0000304
murgatroid99a3e244f2015-09-22 11:25:53 -0700305 def makefile_name(self):
306 return 'Makefile'
307
murgatroid99132ce6a2015-03-04 17:29:14 -0800308 def supports_multi_config(self):
309 return False
310
311 def __str__(self):
312 return 'python'
313
Craig Tillerd625d812015-04-08 15:52:35 -0700314
murgatroid996a4c4fa2015-02-27 12:08:57 -0800315class RubyLanguage(object):
316
317 def test_specs(self, config, travis):
Craig Tiller4fc90032015-05-21 10:39:52 -0700318 return [config.job_spec(['tools/run_tests/run_ruby.sh'], None,
Craig Tiller06805272015-06-11 14:46:47 -0700319 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
murgatroid996a4c4fa2015-02-27 12:08:57 -0800320
murgatroid99256d3df2015-09-21 16:58:02 -0700321 def pre_build_steps(self):
322 return []
323
murgatroid996a4c4fa2015-02-27 12:08:57 -0800324 def make_targets(self):
murgatroid99a43c14f2015-07-30 13:31:23 -0700325 return ['static_c']
murgatroid996a4c4fa2015-02-27 12:08:57 -0800326
327 def build_steps(self):
328 return [['tools/run_tests/build_ruby.sh']]
329
murgatroid99a3e244f2015-09-22 11:25:53 -0700330 def makefile_name(self):
331 return 'Makefile'
332
murgatroid99132ce6a2015-03-04 17:29:14 -0800333 def supports_multi_config(self):
334 return False
335
336 def __str__(self):
337 return 'ruby'
338
Craig Tillerd625d812015-04-08 15:52:35 -0700339
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800340class CSharpLanguage(object):
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700341 def __init__(self):
Craig Tillerd50993d2015-08-05 08:04:36 -0700342 self.platform = platform_string()
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700343
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800344 def test_specs(self, config, travis):
Jan Tattermusch9a7d30c2015-04-23 16:12:55 -0700345 assemblies = ['Grpc.Core.Tests',
346 'Grpc.Examples.Tests',
Jan Tattermusch9d67d8d2015-08-01 20:39:16 -0700347 'Grpc.HealthCheck.Tests',
Jan Tattermusch9a7d30c2015-04-23 16:12:55 -0700348 'Grpc.IntegrationTesting']
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700349 if self.platform == 'windows':
350 cmd = 'tools\\run_tests\\run_csharp.bat'
351 else:
352 cmd = 'tools/run_tests/run_csharp.sh'
353 return [config.job_spec([cmd, assembly],
Craig Tiller4fc90032015-05-21 10:39:52 -0700354 None, shortname=assembly,
Craig Tiller06805272015-06-11 14:46:47 -0700355 environ=_FORCE_ENVIRON_FOR_WRAPPERS)
Craig Tillerd50993d2015-08-05 08:04:36 -0700356 for assembly in assemblies]
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800357
murgatroid99256d3df2015-09-21 16:58:02 -0700358 def pre_build_steps(self):
359 return []
360
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800361 def make_targets(self):
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700362 # For Windows, this target doesn't really build anything,
363 # everything is build by buildall script later.
Craig Tillerd5904822015-08-31 21:30:58 -0700364 if self.platform == 'windows':
365 return []
366 else:
367 return ['grpc_csharp_ext']
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800368
369 def build_steps(self):
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700370 if self.platform == 'windows':
371 return [['src\\csharp\\buildall.bat']]
372 else:
373 return [['tools/run_tests/build_csharp.sh']]
Nathaniel Manista840615e2015-01-22 20:31:47 +0000374
murgatroid99a3e244f2015-09-22 11:25:53 -0700375 def makefile_name(self):
376 return 'Makefile'
377
murgatroid99132ce6a2015-03-04 17:29:14 -0800378 def supports_multi_config(self):
379 return False
380
381 def __str__(self):
382 return 'csharp'
383
Craig Tillerd625d812015-04-08 15:52:35 -0700384
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700385class ObjCLanguage(object):
386
387 def test_specs(self, config, travis):
388 return [config.job_spec(['src/objective-c/tests/run_tests.sh'], None,
389 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
390
murgatroid99256d3df2015-09-21 16:58:02 -0700391 def pre_build_steps(self):
392 return []
393
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700394 def make_targets(self):
Jorge Canizalesd0b32e92015-07-30 23:08:43 -0700395 return ['grpc_objective_c_plugin', 'interop_server']
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700396
397 def build_steps(self):
Jorge Canizalesd0b32e92015-07-30 23:08:43 -0700398 return [['src/objective-c/tests/build_tests.sh']]
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700399
murgatroid99a3e244f2015-09-22 11:25:53 -0700400 def makefile_name(self):
401 return 'Makefile'
402
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700403 def supports_multi_config(self):
404 return False
405
406 def __str__(self):
407 return 'objc'
408
409
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100410class Sanity(object):
411
412 def test_specs(self, config, travis):
Craig Tillerf75fc122015-06-25 06:58:00 -0700413 return [config.job_spec('tools/run_tests/run_sanity.sh', None),
414 config.job_spec('tools/run_tests/check_sources_and_headers.py', None)]
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100415
murgatroid99256d3df2015-09-21 16:58:02 -0700416 def pre_build_steps(self):
417 return []
418
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100419 def make_targets(self):
420 return ['run_dep_checks']
421
422 def build_steps(self):
423 return []
424
murgatroid99a3e244f2015-09-22 11:25:53 -0700425 def makefile_name(self):
426 return 'Makefile'
427
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100428 def supports_multi_config(self):
429 return False
430
431 def __str__(self):
432 return 'sanity'
433
Nicolas "Pixel" Noblee55cd7f2015-04-14 17:59:13 +0200434
Nicolas "Pixel" Noblefd2b0932015-03-26 00:26:29 +0100435class Build(object):
436
437 def test_specs(self, config, travis):
438 return []
439
murgatroid99256d3df2015-09-21 16:58:02 -0700440 def pre_build_steps(self):
441 return []
442
Nicolas "Pixel" Noblefd2b0932015-03-26 00:26:29 +0100443 def make_targets(self):
Nicolas "Pixel" Noblec23827b2015-04-23 06:17:55 +0200444 return ['static']
Nicolas "Pixel" Noblefd2b0932015-03-26 00:26:29 +0100445
446 def build_steps(self):
447 return []
448
murgatroid99a3e244f2015-09-22 11:25:53 -0700449 def makefile_name(self):
450 return 'Makefile'
451
Nicolas "Pixel" Noblefd2b0932015-03-26 00:26:29 +0100452 def supports_multi_config(self):
453 return True
454
455 def __str__(self):
456 return self.make_target
457
458
Craig Tiller738c3342015-01-12 14:28:33 -0800459# different configurations we can run under
460_CONFIGS = {
Craig Tillerb50d1662015-01-15 17:28:21 -0800461 'dbg': SimpleConfig('dbg'),
462 'opt': SimpleConfig('opt'),
Craig Tillerb2ea0b92015-08-26 13:06:53 -0700463 'tsan': SimpleConfig('tsan', timeout_seconds=10*60, environ={
Craig Tiller1ada6ad2015-07-16 16:19:14 -0700464 'TSAN_OPTIONS': 'suppressions=tools/tsan_suppressions.txt:halt_on_error=1:second_deadlock_stack=1'}),
Craig Tiller4a71ce22015-08-26 15:47:55 -0700465 'msan': SimpleConfig('msan', timeout_seconds=7*60),
Craig Tiller96bd5f62015-02-13 09:04:13 -0800466 'ubsan': SimpleConfig('ubsan'),
Craig Tillerb2ea0b92015-08-26 13:06:53 -0700467 'asan': SimpleConfig('asan', timeout_seconds=7*60, environ={
Craig Tillerd4b13622015-05-29 09:10:10 -0700468 'ASAN_OPTIONS': 'detect_leaks=1:color=always:suppressions=tools/tsan_suppressions.txt',
469 'LSAN_OPTIONS': 'report_objects=1'}),
Craig Tiller810725c2015-05-12 09:44:41 -0700470 'asan-noleaks': SimpleConfig('asan', environ={
471 'ASAN_OPTIONS': 'detect_leaks=0:color=always:suppressions=tools/tsan_suppressions.txt'}),
Craig Tillerb50d1662015-01-15 17:28:21 -0800472 'gcov': SimpleConfig('gcov'),
Craig Tiller1a305b12015-02-18 13:37:06 -0800473 'memcheck': ValgrindConfig('valgrind', 'memcheck', ['--leak-check=full']),
Craig Tillerb50d1662015-01-15 17:28:21 -0800474 'helgrind': ValgrindConfig('dbg', 'helgrind')
475 }
Craig Tiller738c3342015-01-12 14:28:33 -0800476
477
Nicolas "Pixel" Noble1fb5e822015-03-16 06:20:37 +0100478_DEFAULT = ['opt']
Craig Tillerc7449162015-01-16 14:42:10 -0800479_LANGUAGES = {
Craig Tillere9c959d2015-01-18 10:23:26 -0800480 'c++': CLanguage('cxx', 'c++'),
481 'c': CLanguage('c', 'c'),
murgatroid99cf08daf2015-09-21 15:33:16 -0700482 'gyp': GYPCLanguage(),
murgatroid992c8d5162015-01-26 10:41:21 -0800483 'node': NodeLanguage(),
Nathaniel Manista840615e2015-01-22 20:31:47 +0000484 'php': PhpLanguage(),
485 'python': PythonLanguage(),
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800486 'ruby': RubyLanguage(),
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100487 'csharp': CSharpLanguage(),
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700488 'objc' : ObjCLanguage(),
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100489 'sanity': Sanity(),
Nicolas "Pixel" Noblefd2b0932015-03-26 00:26:29 +0100490 'build': Build(),
Craig Tillereb272bc2015-01-30 13:13:14 -0800491 }
Nicolas Nobleddef2462015-01-06 18:08:25 -0800492
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700493_WINDOWS_CONFIG = {
494 'dbg': 'Debug',
495 'opt': 'Release',
496 }
497
David Garcia Quintase90cd372015-05-31 18:15:26 -0700498
499def runs_per_test_type(arg_str):
500 """Auxilary function to parse the "runs_per_test" flag.
501
502 Returns:
503 A positive integer or 0, the latter indicating an infinite number of
504 runs.
505
506 Raises:
507 argparse.ArgumentTypeError: Upon invalid input.
508 """
509 if arg_str == 'inf':
510 return 0
511 try:
512 n = int(arg_str)
513 if n <= 0: raise ValueError
Craig Tiller50e53e22015-06-01 20:18:21 -0700514 return n
David Garcia Quintase90cd372015-05-31 18:15:26 -0700515 except:
516 msg = "'{}' isn't a positive integer or 'inf'".format(arg_str)
517 raise argparse.ArgumentTypeError(msg)
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700518
519# parse command line
520argp = argparse.ArgumentParser(description='Run grpc tests.')
521argp.add_argument('-c', '--config',
522 choices=['all'] + sorted(_CONFIGS.keys()),
523 nargs='+',
524 default=_DEFAULT)
David Garcia Quintase90cd372015-05-31 18:15:26 -0700525argp.add_argument('-n', '--runs_per_test', default=1, type=runs_per_test_type,
526 help='A positive integer or "inf". If "inf", all tests will run in an '
527 'infinite loop. Especially useful in combination with "-f"')
Craig Tillerfe406ec2015-02-24 13:55:12 -0800528argp.add_argument('-r', '--regex', default='.*', type=str)
Craig Tiller83762ac2015-05-22 14:04:06 -0700529argp.add_argument('-j', '--jobs', default=2 * multiprocessing.cpu_count(), type=int)
Craig Tiller8451e872015-02-27 09:25:51 -0800530argp.add_argument('-s', '--slowdown', default=1.0, type=float)
ctiller3040cb72015-01-07 12:13:17 -0800531argp.add_argument('-f', '--forever',
532 default=False,
533 action='store_const',
534 const=True)
Nicolas "Pixel" Noblea7df3f92015-02-26 22:07:04 +0100535argp.add_argument('-t', '--travis',
536 default=False,
537 action='store_const',
538 const=True)
Nicolas Noble044db742015-01-14 16:57:24 -0800539argp.add_argument('--newline_on_success',
540 default=False,
541 action='store_const',
542 const=True)
Craig Tiller686fb262015-01-15 07:39:09 -0800543argp.add_argument('-l', '--language',
Craig Tiller60f15e62015-05-13 09:05:17 -0700544 choices=['all'] + sorted(_LANGUAGES.keys()),
Craig Tiller686fb262015-01-15 07:39:09 -0800545 nargs='+',
Craig Tiller60f15e62015-05-13 09:05:17 -0700546 default=['all'])
Craig Tillercd43da82015-05-29 08:41:29 -0700547argp.add_argument('-S', '--stop_on_failure',
548 default=False,
549 action='store_const',
550 const=True)
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700551argp.add_argument('--use_docker',
552 default=False,
553 action='store_const',
554 const=True,
555 help="Run all the tests under docker. That provides " +
556 "additional isolation and prevents the need to installs " +
557 "language specific prerequisites. Only available on Linux.")
Craig Tiller234b6e72015-05-23 10:12:40 -0700558argp.add_argument('-a', '--antagonists', default=0, type=int)
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +0200559argp.add_argument('-x', '--xml_report', default=None, type=str,
560 help='Generates a JUnit-compatible XML report')
Nicolas Nobleddef2462015-01-06 18:08:25 -0800561args = argp.parse_args()
562
Jan Tattermuschc96b9eb2015-09-18 16:01:21 -0700563if args.use_docker:
564 if not args.travis:
565 print 'Seen --use_docker flag, will run tests under docker.'
566 print
567 print 'IMPORTANT: The changes you are testing need to be locally committed'
568 print 'because only the committed changes in the current branch will be'
569 print 'copied to the docker environment.'
570 time.sleep(5)
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700571
572 child_argv = [ arg for arg in sys.argv if not arg == '--use_docker' ]
573 run_tests_cmd = 'tools/run_tests/run_tests.py %s' % " ".join(child_argv[1:])
574
575 # TODO(jtattermusch): revisit if we need special handling for arch here
576 # set arch command prefix in case we are working with different arch.
577 arch_env = os.getenv('arch')
578 if arch_env:
579 run_test_cmd = 'arch %s %s' % (arch_env, run_test_cmd)
580
581 env = os.environ.copy()
582 env['RUN_TESTS_COMMAND'] = run_tests_cmd
583 if args.xml_report:
584 env['XML_REPORT'] = args.xml_report
Jan Tattermusch261b58c2015-09-18 17:15:48 -0700585 if not args.travis:
586 env['TTY_FLAG'] = '-t' # enables Ctrl-C when not on Jenkins.
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700587
588 subprocess.check_call(['tools/jenkins/build_docker_and_run_tests.sh'],
589 shell=True,
590 env=env)
591 sys.exit(0)
592
Nicolas Nobleddef2462015-01-06 18:08:25 -0800593# grab config
Craig Tiller738c3342015-01-12 14:28:33 -0800594run_configs = set(_CONFIGS[cfg]
595 for cfg in itertools.chain.from_iterable(
596 _CONFIGS.iterkeys() if x == 'all' else [x]
597 for x in args.config))
598build_configs = set(cfg.build_config for cfg in run_configs)
Craig Tillerf1973b02015-01-16 12:32:13 -0800599
Craig Tiller06805272015-06-11 14:46:47 -0700600if args.travis:
601 _FORCE_ENVIRON_FOR_WRAPPERS = {'GRPC_TRACE': 'surface,batch'}
602
Craig Tiller60f15e62015-05-13 09:05:17 -0700603languages = set(_LANGUAGES[l]
604 for l in itertools.chain.from_iterable(
605 _LANGUAGES.iterkeys() if x == 'all' else [x]
606 for x in args.language))
murgatroid99132ce6a2015-03-04 17:29:14 -0800607
608if len(build_configs) > 1:
609 for language in languages:
610 if not language.supports_multi_config():
611 print language, 'does not support multiple build configurations'
612 sys.exit(1)
613
Craig Tiller5058c692015-04-08 09:42:04 -0700614if platform.system() == 'Windows':
murgatroid99a3e244f2015-09-22 11:25:53 -0700615 def make_jobspec(cfg, targets, makefile='Makefile'):
Craig Tillerfc3c0c42015-09-01 16:47:54 -0700616 extra_args = []
Craig Tillerb5391e12015-09-03 14:35:18 -0700617 # better do parallel compilation
618 extra_args.extend(["/m"])
619 # disable PDB generation: it's broken, and we don't need it during CI
620 extra_args.extend(["/p:GenerateDebugInformation=false", "/p:DebugInformationFormat=None"])
Craig Tiller6fd23842015-09-01 07:36:31 -0700621 return [
murgatroid99cf08daf2015-09-21 15:33:16 -0700622 jobset.JobSpec(['vsprojects\\build.bat',
623 'vsprojects\\%s.sln' % target,
Craig Tillerfc3c0c42015-09-01 16:47:54 -0700624 '/p:Configuration=%s' % _WINDOWS_CONFIG[cfg]] +
625 extra_args,
Craig Tillerdfc3eee2015-09-01 16:32:16 -0700626 shell=True, timeout_seconds=90*60)
Craig Tiller6fd23842015-09-01 07:36:31 -0700627 for target in targets]
Craig Tiller5058c692015-04-08 09:42:04 -0700628else:
murgatroid99a3e244f2015-09-22 11:25:53 -0700629 def make_jobspec(cfg, targets, makefile='Makefile'):
Craig Tiller6fd23842015-09-01 07:36:31 -0700630 return [jobset.JobSpec([os.getenv('MAKE', 'make'),
murgatroid99a3e244f2015-09-22 11:25:53 -0700631 '-f', makefile,
Craig Tiller6fd23842015-09-01 07:36:31 -0700632 '-j', '%d' % (multiprocessing.cpu_count() + 1),
633 'EXTRA_DEFINES=GRPC_TEST_SLOWDOWN_MACHINE_FACTOR=%f' %
634 args.slowdown,
635 'CONFIG=%s' % cfg] + targets,
636 timeout_seconds=30*60)]
murgatroid99a3e244f2015-09-22 11:25:53 -0700637make_targets = {}
638for l in languages:
639 makefile = l.makefile_name()
640 make_targets[makefile] = make_targets.get(makefile, set()).union(
641 set(l.make_targets()))
Craig Tiller5058c692015-04-08 09:42:04 -0700642
murgatroid99fddac962015-09-22 09:20:11 -0700643build_steps = list(set(
murgatroid99256d3df2015-09-21 16:58:02 -0700644 jobset.JobSpec(cmdline, environ={'CONFIG': cfg})
645 for cfg in build_configs
646 for l in languages
647 for cmdline in l.pre_build_steps()))
Craig Tillerbd4e3782015-09-01 06:48:55 -0700648if make_targets:
murgatroid99a3e244f2015-09-22 11:25:53 -0700649 make_commands = itertools.chain.from_iterable(make_jobspec(cfg, list(targets), makefile) for cfg in build_configs for (makefile, targets) in make_targets.iteritems())
Craig Tiller6fd23842015-09-01 07:36:31 -0700650 build_steps.extend(set(make_commands))
Craig Tiller5058c692015-04-08 09:42:04 -0700651build_steps.extend(set(
murgatroid99132ce6a2015-03-04 17:29:14 -0800652 jobset.JobSpec(cmdline, environ={'CONFIG': cfg})
653 for cfg in build_configs
Craig Tiller547db2b2015-01-30 14:08:39 -0800654 for l in languages
Craig Tiller533b1a22015-05-29 08:41:29 -0700655 for cmdline in l.build_steps()))
Craig Tillerf1973b02015-01-16 12:32:13 -0800656
Nicolas Nobleddef2462015-01-06 18:08:25 -0800657runs_per_test = args.runs_per_test
ctiller3040cb72015-01-07 12:13:17 -0800658forever = args.forever
Nicolas Nobleddef2462015-01-06 18:08:25 -0800659
Nicolas Nobleddef2462015-01-06 18:08:25 -0800660
Craig Tiller71735182015-01-15 17:07:13 -0800661class TestCache(object):
Craig Tillerb50d1662015-01-15 17:28:21 -0800662 """Cache for running tests."""
663
David Klempner25739582015-02-11 15:57:32 -0800664 def __init__(self, use_cache_results):
Craig Tiller71735182015-01-15 17:07:13 -0800665 self._last_successful_run = {}
David Klempner25739582015-02-11 15:57:32 -0800666 self._use_cache_results = use_cache_results
Craig Tiller69cd2372015-06-11 09:38:09 -0700667 self._last_save = time.time()
Craig Tiller71735182015-01-15 17:07:13 -0800668
669 def should_run(self, cmdline, bin_hash):
Craig Tiller71735182015-01-15 17:07:13 -0800670 if cmdline not in self._last_successful_run:
671 return True
672 if self._last_successful_run[cmdline] != bin_hash:
673 return True
David Klempner25739582015-02-11 15:57:32 -0800674 if not self._use_cache_results:
675 return True
Craig Tiller71735182015-01-15 17:07:13 -0800676 return False
677
678 def finished(self, cmdline, bin_hash):
Craig Tiller547db2b2015-01-30 14:08:39 -0800679 self._last_successful_run[cmdline] = bin_hash
Craig Tiller69cd2372015-06-11 09:38:09 -0700680 if time.time() - self._last_save > 1:
681 self.save()
Craig Tiller71735182015-01-15 17:07:13 -0800682
683 def dump(self):
Craig Tillerb50d1662015-01-15 17:28:21 -0800684 return [{'cmdline': k, 'hash': v}
685 for k, v in self._last_successful_run.iteritems()]
Craig Tiller71735182015-01-15 17:07:13 -0800686
687 def parse(self, exdump):
688 self._last_successful_run = dict((o['cmdline'], o['hash']) for o in exdump)
689
690 def save(self):
691 with open('.run_tests_cache', 'w') as f:
Craig Tiller261dd982015-01-16 16:41:45 -0800692 f.write(json.dumps(self.dump()))
Craig Tiller69cd2372015-06-11 09:38:09 -0700693 self._last_save = time.time()
Craig Tiller71735182015-01-15 17:07:13 -0800694
Craig Tiller1cc11db2015-01-15 22:50:50 -0800695 def maybe_load(self):
696 if os.path.exists('.run_tests_cache'):
697 with open('.run_tests_cache') as f:
Craig Tiller261dd982015-01-16 16:41:45 -0800698 self.parse(json.loads(f.read()))
Craig Tiller71735182015-01-15 17:07:13 -0800699
700
Craig Tillerf53d9c82015-08-04 14:19:43 -0700701def _start_port_server(port_server_port):
702 # check if a compatible port server is running
703 # if incompatible (version mismatch) ==> start a new one
704 # if not running ==> start a new one
705 # otherwise, leave it up
706 try:
Craig Tillerabd37fd2015-08-26 07:54:01 -0700707 version = urllib2.urlopen('http://localhost:%d/version' % port_server_port,
708 timeout=1).read()
Craig Tillerf53d9c82015-08-04 14:19:43 -0700709 running = True
710 except Exception:
711 running = False
712 if running:
713 with open('tools/run_tests/port_server.py') as f:
714 current_version = hashlib.sha1(f.read()).hexdigest()
715 running = (version == current_version)
716 if not running:
Craig Tilleref125592015-08-05 07:41:35 -0700717 urllib2.urlopen('http://localhost:%d/quit' % port_server_port).read()
718 time.sleep(1)
Craig Tillerf53d9c82015-08-04 14:19:43 -0700719 if not running:
720 port_log = open('portlog.txt', 'w')
721 port_server = subprocess.Popen(
Craig Tiller9a0c10e2015-08-06 15:47:32 -0700722 ['python', 'tools/run_tests/port_server.py', '-p', '%d' % port_server_port],
Craig Tillerf53d9c82015-08-04 14:19:43 -0700723 stderr=subprocess.STDOUT,
724 stdout=port_log)
Craig Tiller8b5f4dc2015-08-26 08:02:01 -0700725 # ensure port server is up
Craig Tillerabd37fd2015-08-26 07:54:01 -0700726 waits = 0
Craig Tillerf53d9c82015-08-04 14:19:43 -0700727 while True:
Craig Tillerabd37fd2015-08-26 07:54:01 -0700728 if waits > 10:
729 port_server.kill()
Craig Tillera2f38b02015-09-24 11:19:17 -0700730 if port_server.poll() is not None:
Craig Tillerabd37fd2015-08-26 07:54:01 -0700731 print "port_server failed to start"
Craig Tillera2f38b02015-09-24 11:19:17 -0700732 port_log = open('portlog.txt', 'r').read()
733 print port_log
Craig Tillerabd37fd2015-08-26 07:54:01 -0700734 sys.exit(1)
Craig Tillerf53d9c82015-08-04 14:19:43 -0700735 try:
Craig Tillerabd37fd2015-08-26 07:54:01 -0700736 urllib2.urlopen('http://localhost:%d/get' % port_server_port,
737 timeout=1).read()
Craig Tillerf53d9c82015-08-04 14:19:43 -0700738 break
739 except urllib2.URLError:
Craig Tillerabd37fd2015-08-26 07:54:01 -0700740 print "waiting for port_server"
Craig Tillerf53d9c82015-08-04 14:19:43 -0700741 time.sleep(0.5)
Craig Tillerabd37fd2015-08-26 07:54:01 -0700742 waits += 1
Craig Tillerf53d9c82015-08-04 14:19:43 -0700743 except:
744 port_server.kill()
745 raise
746
747
748def _build_and_run(
749 check_cancelled, newline_on_success, travis, cache, xml_report=None):
ctiller3040cb72015-01-07 12:13:17 -0800750 """Do one pass of building & running tests."""
murgatroid99666450e2015-01-26 13:03:31 -0800751 # build latest sequentially
Nicolas "Pixel" Noblea7df3f92015-02-26 22:07:04 +0100752 if not jobset.run(build_steps, maxjobs=1,
753 newline_on_success=newline_on_success, travis=travis):
Craig Tillerd86a3942015-01-14 12:48:54 -0800754 return 1
ctiller3040cb72015-01-07 12:13:17 -0800755
Craig Tiller234b6e72015-05-23 10:12:40 -0700756 # start antagonists
David Garcia Quintas79e389f2015-06-02 17:49:42 -0700757 antagonists = [subprocess.Popen(['tools/run_tests/antagonist.py'])
Craig Tiller234b6e72015-05-23 10:12:40 -0700758 for _ in range(0, args.antagonists)]
Craig Tillerf53d9c82015-08-04 14:19:43 -0700759 port_server_port = 9999
760 _start_port_server(port_server_port)
Craig Tiller234b6e72015-05-23 10:12:40 -0700761 try:
David Garcia Quintase90cd372015-05-31 18:15:26 -0700762 infinite_runs = runs_per_test == 0
yang-g6c1fdc62015-08-18 11:57:42 -0700763 one_run = set(
764 spec
765 for config in run_configs
766 for language in languages
767 for spec in language.test_specs(config, args.travis)
768 if re.search(args.regex, spec.shortname))
David Garcia Quintas79e389f2015-06-02 17:49:42 -0700769 # When running on travis, we want out test runs to be as similar as possible
770 # for reproducibility purposes.
771 if travis:
772 massaged_one_run = sorted(one_run, key=lambda x: x.shortname)
773 else:
774 # whereas otherwise, we want to shuffle things up to give all tests a
775 # chance to run.
776 massaged_one_run = list(one_run) # random.shuffle needs an indexable seq.
777 random.shuffle(massaged_one_run) # which it modifies in-place.
Craig Tillerf7b7c892015-06-22 14:33:25 -0700778 if infinite_runs:
779 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 -0700780 runs_sequence = (itertools.repeat(massaged_one_run) if infinite_runs
781 else itertools.repeat(massaged_one_run, runs_per_test))
David Garcia Quintase90cd372015-05-31 18:15:26 -0700782 all_runs = itertools.chain.from_iterable(runs_sequence)
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +0200783
784 root = ET.Element('testsuites') if xml_report else None
785 testsuite = ET.SubElement(root, 'testsuite', id='1', package='grpc', name='tests') if xml_report else None
786
Craig Tiller234b6e72015-05-23 10:12:40 -0700787 if not jobset.run(all_runs, check_cancelled,
788 newline_on_success=newline_on_success, travis=travis,
David Garcia Quintase90cd372015-05-31 18:15:26 -0700789 infinite_runs=infinite_runs,
Craig Tillerda2220a2015-05-27 07:50:53 -0700790 maxjobs=args.jobs,
Craig Tillercd43da82015-05-29 08:41:29 -0700791 stop_on_failure=args.stop_on_failure,
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +0200792 cache=cache if not xml_report else None,
Craig Tillerf53d9c82015-08-04 14:19:43 -0700793 xml_report=testsuite,
794 add_env={'GRPC_TEST_PORT_SERVER': 'localhost:%d' % port_server_port}):
Craig Tiller234b6e72015-05-23 10:12:40 -0700795 return 2
796 finally:
797 for antagonist in antagonists:
798 antagonist.kill()
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +0200799 if xml_report:
800 tree = ET.ElementTree(root)
801 tree.write(xml_report, encoding='UTF-8')
Craig Tillerd86a3942015-01-14 12:48:54 -0800802
Craig Tiller69cd2372015-06-11 09:38:09 -0700803 if cache: cache.save()
804
Craig Tillerd86a3942015-01-14 12:48:54 -0800805 return 0
ctiller3040cb72015-01-07 12:13:17 -0800806
807
David Klempner25739582015-02-11 15:57:32 -0800808test_cache = TestCache(runs_per_test == 1)
Craig Tiller547db2b2015-01-30 14:08:39 -0800809test_cache.maybe_load()
Craig Tiller71735182015-01-15 17:07:13 -0800810
ctiller3040cb72015-01-07 12:13:17 -0800811if forever:
Nicolas Noble044db742015-01-14 16:57:24 -0800812 success = True
ctiller3040cb72015-01-07 12:13:17 -0800813 while True:
Craig Tiller42bc87c2015-02-23 08:50:19 -0800814 dw = watch_dirs.DirWatcher(['src', 'include', 'test', 'examples'])
ctiller3040cb72015-01-07 12:13:17 -0800815 initial_time = dw.most_recent_change()
816 have_files_changed = lambda: dw.most_recent_change() != initial_time
Nicolas Noble044db742015-01-14 16:57:24 -0800817 previous_success = success
Craig Tiller71735182015-01-15 17:07:13 -0800818 success = _build_and_run(check_cancelled=have_files_changed,
Nicolas Nobleb09078f2015-01-14 18:06:05 -0800819 newline_on_success=False,
Craig Tiller9a5a9402015-04-16 10:39:50 -0700820 travis=args.travis,
Craig Tiller71735182015-01-15 17:07:13 -0800821 cache=test_cache) == 0
Nicolas Noble044db742015-01-14 16:57:24 -0800822 if not previous_success and success:
Nicolas Nobleb09078f2015-01-14 18:06:05 -0800823 jobset.message('SUCCESS',
824 'All tests are now passing properly',
825 do_newline=True)
Nicolas Noble044db742015-01-14 16:57:24 -0800826 jobset.message('IDLE', 'No change detected')
ctiller3040cb72015-01-07 12:13:17 -0800827 while not have_files_changed():
828 time.sleep(1)
829else:
Craig Tiller71735182015-01-15 17:07:13 -0800830 result = _build_and_run(check_cancelled=lambda: False,
831 newline_on_success=args.newline_on_success,
Nicolas "Pixel" Noblea7df3f92015-02-26 22:07:04 +0100832 travis=args.travis,
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +0200833 cache=test_cache,
834 xml_report=args.xml_report)
Nicolas Nobleb09078f2015-01-14 18:06:05 -0800835 if result == 0:
836 jobset.message('SUCCESS', 'All tests passed', do_newline=True)
837 else:
838 jobset.message('FAILED', 'Some tests failed', do_newline=True)
839 sys.exit(result)