blob: 69a480ac850e2f1827f619f14872d3876653c6b6 [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
Craig Tiller82875232015-09-25 13:57:34 -070043import socket
David Garcia Quintas79e389f2015-06-02 17:49:42 -070044import subprocess
Nicolas Nobleddef2462015-01-06 18:08:25 -080045import sys
ctiller3040cb72015-01-07 12:13:17 -080046import time
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +020047import xml.etree.cElementTree as ET
Craig Tillerf53d9c82015-08-04 14:19:43 -070048import urllib2
Nicolas Nobleddef2462015-01-06 18:08:25 -080049
50import jobset
ctiller3040cb72015-01-07 12:13:17 -080051import watch_dirs
Nicolas Nobleddef2462015-01-06 18:08:25 -080052
Craig Tiller2cc2b842015-02-27 11:38:31 -080053ROOT = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), '../..'))
54os.chdir(ROOT)
55
56
Craig Tiller06805272015-06-11 14:46:47 -070057_FORCE_ENVIRON_FOR_WRAPPERS = {}
58
59
Craig Tillerd50993d2015-08-05 08:04:36 -070060def platform_string():
61 if platform.system() == 'Windows':
62 return 'windows'
63 elif platform.system() == 'Darwin':
64 return 'mac'
65 elif platform.system() == 'Linux':
66 return 'linux'
67 else:
68 return 'posix'
69
70
Craig Tiller738c3342015-01-12 14:28:33 -080071# SimpleConfig: just compile with CONFIG=config, and run the binary to test
72class SimpleConfig(object):
Craig Tillerb50d1662015-01-15 17:28:21 -080073
Craig Tillerb2ea0b92015-08-26 13:06:53 -070074 def __init__(self, config, environ=None, timeout_seconds=5*60):
murgatroid99132ce6a2015-03-04 17:29:14 -080075 if environ is None:
76 environ = {}
Craig Tiller738c3342015-01-12 14:28:33 -080077 self.build_config = config
Craig Tillerc7449162015-01-16 14:42:10 -080078 self.allow_hashing = (config != 'gcov')
Craig Tiller547db2b2015-01-30 14:08:39 -080079 self.environ = environ
murgatroid99132ce6a2015-03-04 17:29:14 -080080 self.environ['CONFIG'] = config
Craig Tillerb2ea0b92015-08-26 13:06:53 -070081 self.timeout_seconds = timeout_seconds
Craig Tiller738c3342015-01-12 14:28:33 -080082
Craig Tiller4fc90032015-05-21 10:39:52 -070083 def job_spec(self, cmdline, hash_targets, shortname=None, environ={}):
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 Tiller49f61322015-03-03 13:02:11 -080098 return jobset.JobSpec(cmdline=cmdline,
Jan Tattermusch9a7d30c2015-04-23 16:12:55 -070099 shortname=shortname,
Craig Tiller4fc90032015-05-21 10:39:52 -0700100 environ=actual_environ,
Craig Tillerb2ea0b92015-08-26 13:06:53 -0700101 timeout_seconds=self.timeout_seconds,
Craig Tiller547db2b2015-01-30 14:08:39 -0800102 hash_targets=hash_targets
Craig Tillerd4509a12015-09-28 09:18:40 -0700103 if self.allow_hashing else None,
104 flake_retries=5 if args.allow_flakes else 0)
Craig Tiller738c3342015-01-12 14:28:33 -0800105
106
107# ValgrindConfig: compile with some CONFIG=config, but use valgrind to run
108class ValgrindConfig(object):
Craig Tillerb50d1662015-01-15 17:28:21 -0800109
murgatroid99132ce6a2015-03-04 17:29:14 -0800110 def __init__(self, config, tool, args=None):
111 if args is None:
112 args = []
Craig Tiller738c3342015-01-12 14:28:33 -0800113 self.build_config = config
Craig Tiller2aa4d642015-01-14 15:59:44 -0800114 self.tool = tool
Craig Tiller1a305b12015-02-18 13:37:06 -0800115 self.args = args
Craig Tillerc7449162015-01-16 14:42:10 -0800116 self.allow_hashing = False
Craig Tiller738c3342015-01-12 14:28:33 -0800117
Craig Tiller49f61322015-03-03 13:02:11 -0800118 def job_spec(self, cmdline, hash_targets):
Craig Tiller1a305b12015-02-18 13:37:06 -0800119 return jobset.JobSpec(cmdline=['valgrind', '--tool=%s' % self.tool] +
Craig Tiller49f61322015-03-03 13:02:11 -0800120 self.args + cmdline,
Craig Tiller71ec6cb2015-06-03 00:51:11 -0700121 shortname='valgrind %s' % cmdline[0],
Craig Tillerd4509a12015-09-28 09:18:40 -0700122 hash_targets=None,
Craig Tiller95cc07b2015-09-28 13:41:30 -0700123 flake_retries=5 if args.allow_flakes else 0,
124 timeout_retries=2 if args.allow_flakes else 0)
Craig Tiller738c3342015-01-12 14:28:33 -0800125
126
murgatroid99cf08daf2015-09-21 15:33:16 -0700127def get_c_tests(travis, test_lang) :
128 out = []
129 platforms_str = 'ci_platforms' if travis else 'platforms'
130 with open('tools/run_tests/tests.json') as f:
murgatroid9989899b12015-09-22 09:14:48 -0700131 js = json.load(f)
murgatroid99a3e244f2015-09-22 11:25:53 -0700132 return [tgt
133 for tgt in js
134 if tgt['language'] == test_lang and
135 platform_string() in tgt[platforms_str] and
136 not (travis and tgt['flaky'])]
murgatroid99cf08daf2015-09-21 15:33:16 -0700137
murgatroid99fafeeb32015-09-22 09:13:03 -0700138
Craig Tillerc7449162015-01-16 14:42:10 -0800139class CLanguage(object):
140
Craig Tillere9c959d2015-01-18 10:23:26 -0800141 def __init__(self, make_target, test_lang):
Craig Tillerc7449162015-01-16 14:42:10 -0800142 self.make_target = make_target
Craig Tillerd50993d2015-08-05 08:04:36 -0700143 self.platform = platform_string()
Craig Tiller711bbe62015-08-19 12:35:16 -0700144 self.test_lang = test_lang
Craig Tillerc7449162015-01-16 14:42:10 -0800145
Nicolas "Pixel" Noble9db7c3b2015-02-27 06:03:00 +0100146 def test_specs(self, config, travis):
Craig Tiller547db2b2015-01-30 14:08:39 -0800147 out = []
murgatroid99cf08daf2015-09-21 15:33:16 -0700148 binaries = get_c_tests(travis, self.test_lang)
Craig Tiller711bbe62015-08-19 12:35:16 -0700149 for target in binaries:
murgatroid99a3e244f2015-09-22 11:25:53 -0700150 if config.build_config in target['exclude_configs']:
murgatroid99fafeeb32015-09-22 09:13:03 -0700151 continue
Nicolas Noblee1445362015-05-11 17:40:26 -0700152 if self.platform == 'windows':
Craig Tillerf4182602015-09-01 12:23:16 -0700153 binary = 'vsprojects/%s/%s.exe' % (
154 _WINDOWS_CONFIG[config.build_config], target['name'])
Nicolas Noblee1445362015-05-11 17:40:26 -0700155 else:
156 binary = 'bins/%s/%s' % (config.build_config, target['name'])
yang-g6c1fdc62015-08-18 11:57:42 -0700157 if os.path.isfile(binary):
158 out.append(config.job_spec([binary], [binary]))
159 else:
160 print "\nWARNING: binary not found, skipping", binary
Nicolas Noblee1445362015-05-11 17:40:26 -0700161 return sorted(out)
Craig Tillerc7449162015-01-16 14:42:10 -0800162
163 def make_targets(self):
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700164 if platform_string() == 'windows':
165 # don't build tools on windows just yet
166 return ['buildtests_%s' % self.make_target]
Craig Tiller7552f0f2015-06-19 17:46:20 -0700167 return ['buildtests_%s' % self.make_target, 'tools_%s' % self.make_target]
Craig Tillerc7449162015-01-16 14:42:10 -0800168
murgatroid99256d3df2015-09-21 16:58:02 -0700169 def pre_build_steps(self):
170 return []
171
Craig Tillerc7449162015-01-16 14:42:10 -0800172 def build_steps(self):
173 return []
174
murgatroid99a3e244f2015-09-22 11:25:53 -0700175 def makefile_name(self):
176 return 'Makefile'
177
murgatroid99132ce6a2015-03-04 17:29:14 -0800178 def supports_multi_config(self):
179 return True
180
181 def __str__(self):
182 return self.make_target
183
murgatroid992c8d5162015-01-26 10:41:21 -0800184class NodeLanguage(object):
185
Nicolas "Pixel" Noble9db7c3b2015-02-27 06:03:00 +0100186 def test_specs(self, config, travis):
Craig Tiller4fc90032015-05-21 10:39:52 -0700187 return [config.job_spec(['tools/run_tests/run_node.sh'], None,
Craig Tiller06805272015-06-11 14:46:47 -0700188 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
murgatroid992c8d5162015-01-26 10:41:21 -0800189
murgatroid99256d3df2015-09-21 16:58:02 -0700190 def pre_build_steps(self):
191 return []
192
murgatroid992c8d5162015-01-26 10:41:21 -0800193 def make_targets(self):
murgatroid99db5b1602015-10-01 13:20:11 -0700194 return []
murgatroid992c8d5162015-01-26 10:41:21 -0800195
196 def build_steps(self):
197 return [['tools/run_tests/build_node.sh']]
Craig Tillerc7449162015-01-16 14:42:10 -0800198
murgatroid99a3e244f2015-09-22 11:25:53 -0700199 def makefile_name(self):
200 return 'Makefile'
201
murgatroid99132ce6a2015-03-04 17:29:14 -0800202 def supports_multi_config(self):
203 return False
204
205 def __str__(self):
206 return 'node'
207
Craig Tiller99775822015-01-30 13:07:16 -0800208
Craig Tillerc7449162015-01-16 14:42:10 -0800209class PhpLanguage(object):
210
Nicolas "Pixel" Noble9db7c3b2015-02-27 06:03:00 +0100211 def test_specs(self, config, travis):
Craig Tiller4fc90032015-05-21 10:39:52 -0700212 return [config.job_spec(['src/php/bin/run_tests.sh'], None,
Craig Tiller06805272015-06-11 14:46:47 -0700213 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
Craig Tillerc7449162015-01-16 14:42:10 -0800214
murgatroid99256d3df2015-09-21 16:58:02 -0700215 def pre_build_steps(self):
216 return []
217
Craig Tillerc7449162015-01-16 14:42:10 -0800218 def make_targets(self):
Craig Tilleraf7cf542015-05-22 10:07:34 -0700219 return ['static_c', 'shared_c']
Craig Tillerc7449162015-01-16 14:42:10 -0800220
221 def build_steps(self):
222 return [['tools/run_tests/build_php.sh']]
223
murgatroid99a3e244f2015-09-22 11:25:53 -0700224 def makefile_name(self):
225 return 'Makefile'
226
murgatroid99132ce6a2015-03-04 17:29:14 -0800227 def supports_multi_config(self):
228 return False
229
230 def __str__(self):
231 return 'php'
232
Craig Tillerc7449162015-01-16 14:42:10 -0800233
Nathaniel Manista840615e2015-01-22 20:31:47 +0000234class PythonLanguage(object):
235
Craig Tiller49f61322015-03-03 13:02:11 -0800236 def __init__(self):
Masood Malekghassemi2b841622015-07-28 17:39:02 -0700237 self._build_python_versions = ['2.7']
Masood Malekghassemie5f70022015-06-29 09:20:26 -0700238 self._has_python_versions = []
Craig Tiller49f61322015-03-03 13:02:11 -0800239
Nicolas "Pixel" Noble9db7c3b2015-02-27 06:03:00 +0100240 def test_specs(self, config, travis):
Masood Malekghassemi2b841622015-07-28 17:39:02 -0700241 environment = dict(_FORCE_ENVIRON_FOR_WRAPPERS)
242 environment['PYVER'] = '2.7'
243 return [config.job_spec(
244 ['tools/run_tests/run_python.sh'],
245 None,
246 environ=environment,
247 shortname='py.test',
248 )]
Nathaniel Manista840615e2015-01-22 20:31:47 +0000249
murgatroid99256d3df2015-09-21 16:58:02 -0700250 def pre_build_steps(self):
251 return []
252
Nathaniel Manista840615e2015-01-22 20:31:47 +0000253 def make_targets(self):
Craig Tilleraf7cf542015-05-22 10:07:34 -0700254 return ['static_c', 'grpc_python_plugin', 'shared_c']
Nathaniel Manista840615e2015-01-22 20:31:47 +0000255
256 def build_steps(self):
Masood Malekghassemie5f70022015-06-29 09:20:26 -0700257 commands = []
258 for python_version in self._build_python_versions:
259 try:
260 with open(os.devnull, 'w') as output:
261 subprocess.check_call(['which', 'python' + python_version],
262 stdout=output, stderr=output)
263 commands.append(['tools/run_tests/build_python.sh', python_version])
264 self._has_python_versions.append(python_version)
265 except:
266 jobset.message('WARNING', 'Missing Python ' + python_version,
267 do_newline=True)
268 return commands
Nathaniel Manista840615e2015-01-22 20:31:47 +0000269
murgatroid99a3e244f2015-09-22 11:25:53 -0700270 def makefile_name(self):
271 return 'Makefile'
272
murgatroid99132ce6a2015-03-04 17:29:14 -0800273 def supports_multi_config(self):
274 return False
275
276 def __str__(self):
277 return 'python'
278
Craig Tillerd625d812015-04-08 15:52:35 -0700279
murgatroid996a4c4fa2015-02-27 12:08:57 -0800280class RubyLanguage(object):
281
282 def test_specs(self, config, travis):
Craig Tiller4fc90032015-05-21 10:39:52 -0700283 return [config.job_spec(['tools/run_tests/run_ruby.sh'], None,
Craig Tiller06805272015-06-11 14:46:47 -0700284 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
murgatroid996a4c4fa2015-02-27 12:08:57 -0800285
murgatroid99256d3df2015-09-21 16:58:02 -0700286 def pre_build_steps(self):
287 return []
288
murgatroid996a4c4fa2015-02-27 12:08:57 -0800289 def make_targets(self):
murgatroid99a43c14f2015-07-30 13:31:23 -0700290 return ['static_c']
murgatroid996a4c4fa2015-02-27 12:08:57 -0800291
292 def build_steps(self):
293 return [['tools/run_tests/build_ruby.sh']]
294
murgatroid99a3e244f2015-09-22 11:25:53 -0700295 def makefile_name(self):
296 return 'Makefile'
297
murgatroid99132ce6a2015-03-04 17:29:14 -0800298 def supports_multi_config(self):
299 return False
300
301 def __str__(self):
302 return 'ruby'
303
Craig Tillerd625d812015-04-08 15:52:35 -0700304
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800305class CSharpLanguage(object):
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700306 def __init__(self):
Craig Tillerd50993d2015-08-05 08:04:36 -0700307 self.platform = platform_string()
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700308
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800309 def test_specs(self, config, travis):
Jan Tattermusch9a7d30c2015-04-23 16:12:55 -0700310 assemblies = ['Grpc.Core.Tests',
311 'Grpc.Examples.Tests',
Jan Tattermusch9d67d8d2015-08-01 20:39:16 -0700312 'Grpc.HealthCheck.Tests',
Jan Tattermusch9a7d30c2015-04-23 16:12:55 -0700313 'Grpc.IntegrationTesting']
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700314 if self.platform == 'windows':
315 cmd = 'tools\\run_tests\\run_csharp.bat'
316 else:
317 cmd = 'tools/run_tests/run_csharp.sh'
318 return [config.job_spec([cmd, assembly],
Craig Tiller4fc90032015-05-21 10:39:52 -0700319 None, shortname=assembly,
Craig Tiller06805272015-06-11 14:46:47 -0700320 environ=_FORCE_ENVIRON_FOR_WRAPPERS)
Craig Tillerd50993d2015-08-05 08:04:36 -0700321 for assembly in assemblies]
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800322
murgatroid99256d3df2015-09-21 16:58:02 -0700323 def pre_build_steps(self):
Jan Tattermusch48423fc2015-10-07 18:59:16 -0700324 if self.platform == 'windows':
325 return []
326 else:
327 return [['tools/run_tests/pre_build_csharp.sh']]
murgatroid99256d3df2015-09-21 16:58:02 -0700328
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800329 def make_targets(self):
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700330 # For Windows, this target doesn't really build anything,
331 # everything is build by buildall script later.
Craig Tillerd5904822015-08-31 21:30:58 -0700332 if self.platform == 'windows':
333 return []
334 else:
335 return ['grpc_csharp_ext']
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800336
337 def build_steps(self):
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700338 if self.platform == 'windows':
339 return [['src\\csharp\\buildall.bat']]
340 else:
341 return [['tools/run_tests/build_csharp.sh']]
Nathaniel Manista840615e2015-01-22 20:31:47 +0000342
murgatroid99a3e244f2015-09-22 11:25:53 -0700343 def makefile_name(self):
344 return 'Makefile'
345
murgatroid99132ce6a2015-03-04 17:29:14 -0800346 def supports_multi_config(self):
347 return False
348
349 def __str__(self):
350 return 'csharp'
351
Craig Tillerd625d812015-04-08 15:52:35 -0700352
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700353class ObjCLanguage(object):
354
355 def test_specs(self, config, travis):
356 return [config.job_spec(['src/objective-c/tests/run_tests.sh'], None,
357 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
358
murgatroid99256d3df2015-09-21 16:58:02 -0700359 def pre_build_steps(self):
360 return []
361
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700362 def make_targets(self):
Jorge Canizalesd0b32e92015-07-30 23:08:43 -0700363 return ['grpc_objective_c_plugin', 'interop_server']
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700364
365 def build_steps(self):
Jorge Canizalesd0b32e92015-07-30 23:08:43 -0700366 return [['src/objective-c/tests/build_tests.sh']]
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700367
murgatroid99a3e244f2015-09-22 11:25:53 -0700368 def makefile_name(self):
369 return 'Makefile'
370
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700371 def supports_multi_config(self):
372 return False
373
374 def __str__(self):
375 return 'objc'
376
377
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100378class Sanity(object):
379
380 def test_specs(self, config, travis):
Craig Tillerf75fc122015-06-25 06:58:00 -0700381 return [config.job_spec('tools/run_tests/run_sanity.sh', None),
382 config.job_spec('tools/run_tests/check_sources_and_headers.py', None)]
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100383
murgatroid99256d3df2015-09-21 16:58:02 -0700384 def pre_build_steps(self):
385 return []
386
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100387 def make_targets(self):
388 return ['run_dep_checks']
389
390 def build_steps(self):
391 return []
392
murgatroid99a3e244f2015-09-22 11:25:53 -0700393 def makefile_name(self):
394 return 'Makefile'
395
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100396 def supports_multi_config(self):
397 return False
398
399 def __str__(self):
400 return 'sanity'
401
Nicolas "Pixel" Noblee55cd7f2015-04-14 17:59:13 +0200402
Nicolas "Pixel" Noblefd2b0932015-03-26 00:26:29 +0100403class Build(object):
404
405 def test_specs(self, config, travis):
406 return []
407
murgatroid99256d3df2015-09-21 16:58:02 -0700408 def pre_build_steps(self):
409 return []
410
Nicolas "Pixel" Noblefd2b0932015-03-26 00:26:29 +0100411 def make_targets(self):
Nicolas "Pixel" Noblec23827b2015-04-23 06:17:55 +0200412 return ['static']
Nicolas "Pixel" Noblefd2b0932015-03-26 00:26:29 +0100413
414 def build_steps(self):
415 return []
416
murgatroid99a3e244f2015-09-22 11:25:53 -0700417 def makefile_name(self):
418 return 'Makefile'
419
Nicolas "Pixel" Noblefd2b0932015-03-26 00:26:29 +0100420 def supports_multi_config(self):
421 return True
422
423 def __str__(self):
424 return self.make_target
425
426
Craig Tiller738c3342015-01-12 14:28:33 -0800427# different configurations we can run under
428_CONFIGS = {
Craig Tillerb50d1662015-01-15 17:28:21 -0800429 'dbg': SimpleConfig('dbg'),
430 'opt': SimpleConfig('opt'),
Craig Tillerb2ea0b92015-08-26 13:06:53 -0700431 'tsan': SimpleConfig('tsan', timeout_seconds=10*60, environ={
Craig Tiller1ada6ad2015-07-16 16:19:14 -0700432 'TSAN_OPTIONS': 'suppressions=tools/tsan_suppressions.txt:halt_on_error=1:second_deadlock_stack=1'}),
Craig Tiller4a71ce22015-08-26 15:47:55 -0700433 'msan': SimpleConfig('msan', timeout_seconds=7*60),
Craig Tiller96bd5f62015-02-13 09:04:13 -0800434 'ubsan': SimpleConfig('ubsan'),
Craig Tillerb2ea0b92015-08-26 13:06:53 -0700435 'asan': SimpleConfig('asan', timeout_seconds=7*60, environ={
Craig Tillerd4b13622015-05-29 09:10:10 -0700436 'ASAN_OPTIONS': 'detect_leaks=1:color=always:suppressions=tools/tsan_suppressions.txt',
437 'LSAN_OPTIONS': 'report_objects=1'}),
Craig Tiller810725c2015-05-12 09:44:41 -0700438 'asan-noleaks': SimpleConfig('asan', environ={
439 'ASAN_OPTIONS': 'detect_leaks=0:color=always:suppressions=tools/tsan_suppressions.txt'}),
Craig Tillerb50d1662015-01-15 17:28:21 -0800440 'gcov': SimpleConfig('gcov'),
Craig Tiller1a305b12015-02-18 13:37:06 -0800441 'memcheck': ValgrindConfig('valgrind', 'memcheck', ['--leak-check=full']),
Craig Tillerb50d1662015-01-15 17:28:21 -0800442 'helgrind': ValgrindConfig('dbg', 'helgrind')
443 }
Craig Tiller738c3342015-01-12 14:28:33 -0800444
445
Nicolas "Pixel" Noble1fb5e822015-03-16 06:20:37 +0100446_DEFAULT = ['opt']
Craig Tillerc7449162015-01-16 14:42:10 -0800447_LANGUAGES = {
Craig Tillere9c959d2015-01-18 10:23:26 -0800448 'c++': CLanguage('cxx', 'c++'),
449 'c': CLanguage('c', 'c'),
murgatroid992c8d5162015-01-26 10:41:21 -0800450 'node': NodeLanguage(),
Nathaniel Manista840615e2015-01-22 20:31:47 +0000451 'php': PhpLanguage(),
452 'python': PythonLanguage(),
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800453 'ruby': RubyLanguage(),
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100454 'csharp': CSharpLanguage(),
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700455 'objc' : ObjCLanguage(),
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100456 'sanity': Sanity(),
Nicolas "Pixel" Noblefd2b0932015-03-26 00:26:29 +0100457 'build': Build(),
Craig Tillereb272bc2015-01-30 13:13:14 -0800458 }
Nicolas Nobleddef2462015-01-06 18:08:25 -0800459
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700460_WINDOWS_CONFIG = {
461 'dbg': 'Debug',
462 'opt': 'Release',
463 }
464
David Garcia Quintase90cd372015-05-31 18:15:26 -0700465
466def runs_per_test_type(arg_str):
467 """Auxilary function to parse the "runs_per_test" flag.
468
469 Returns:
470 A positive integer or 0, the latter indicating an infinite number of
471 runs.
472
473 Raises:
474 argparse.ArgumentTypeError: Upon invalid input.
475 """
476 if arg_str == 'inf':
477 return 0
478 try:
479 n = int(arg_str)
480 if n <= 0: raise ValueError
Craig Tiller50e53e22015-06-01 20:18:21 -0700481 return n
David Garcia Quintase90cd372015-05-31 18:15:26 -0700482 except:
483 msg = "'{}' isn't a positive integer or 'inf'".format(arg_str)
484 raise argparse.ArgumentTypeError(msg)
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700485
486# parse command line
487argp = argparse.ArgumentParser(description='Run grpc tests.')
488argp.add_argument('-c', '--config',
489 choices=['all'] + sorted(_CONFIGS.keys()),
490 nargs='+',
491 default=_DEFAULT)
David Garcia Quintase90cd372015-05-31 18:15:26 -0700492argp.add_argument('-n', '--runs_per_test', default=1, type=runs_per_test_type,
493 help='A positive integer or "inf". If "inf", all tests will run in an '
494 'infinite loop. Especially useful in combination with "-f"')
Craig Tillerfe406ec2015-02-24 13:55:12 -0800495argp.add_argument('-r', '--regex', default='.*', type=str)
Craig Tiller83762ac2015-05-22 14:04:06 -0700496argp.add_argument('-j', '--jobs', default=2 * multiprocessing.cpu_count(), type=int)
Craig Tiller8451e872015-02-27 09:25:51 -0800497argp.add_argument('-s', '--slowdown', default=1.0, type=float)
ctiller3040cb72015-01-07 12:13:17 -0800498argp.add_argument('-f', '--forever',
499 default=False,
500 action='store_const',
501 const=True)
Nicolas "Pixel" Noblea7df3f92015-02-26 22:07:04 +0100502argp.add_argument('-t', '--travis',
503 default=False,
504 action='store_const',
505 const=True)
Nicolas Noble044db742015-01-14 16:57:24 -0800506argp.add_argument('--newline_on_success',
507 default=False,
508 action='store_const',
509 const=True)
Craig Tiller686fb262015-01-15 07:39:09 -0800510argp.add_argument('-l', '--language',
Craig Tiller60f15e62015-05-13 09:05:17 -0700511 choices=['all'] + sorted(_LANGUAGES.keys()),
Craig Tiller686fb262015-01-15 07:39:09 -0800512 nargs='+',
Craig Tiller60f15e62015-05-13 09:05:17 -0700513 default=['all'])
Craig Tillercd43da82015-05-29 08:41:29 -0700514argp.add_argument('-S', '--stop_on_failure',
515 default=False,
516 action='store_const',
517 const=True)
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700518argp.add_argument('--use_docker',
519 default=False,
520 action='store_const',
521 const=True,
522 help="Run all the tests under docker. That provides " +
Jan Tattermusch8266c672015-09-17 09:18:03 -0700523 "additional isolation and prevents the need to install " +
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700524 "language specific prerequisites. Only available on Linux.")
Craig Tillerd4509a12015-09-28 09:18:40 -0700525argp.add_argument('--allow_flakes',
526 default=False,
527 action='store_const',
528 const=True,
529 help="Allow flaky tests to show as passing (re-runs failed tests up to five times)")
Craig Tiller234b6e72015-05-23 10:12:40 -0700530argp.add_argument('-a', '--antagonists', default=0, type=int)
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +0200531argp.add_argument('-x', '--xml_report', default=None, type=str,
532 help='Generates a JUnit-compatible XML report')
Nicolas Nobleddef2462015-01-06 18:08:25 -0800533args = argp.parse_args()
534
Jan Tattermuschc96b9eb2015-09-18 16:01:21 -0700535if args.use_docker:
536 if not args.travis:
537 print 'Seen --use_docker flag, will run tests under docker.'
538 print
539 print 'IMPORTANT: The changes you are testing need to be locally committed'
540 print 'because only the committed changes in the current branch will be'
541 print 'copied to the docker environment.'
542 time.sleep(5)
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700543
544 child_argv = [ arg for arg in sys.argv if not arg == '--use_docker' ]
545 run_tests_cmd = 'tools/run_tests/run_tests.py %s' % " ".join(child_argv[1:])
546
547 # TODO(jtattermusch): revisit if we need special handling for arch here
548 # set arch command prefix in case we are working with different arch.
549 arch_env = os.getenv('arch')
550 if arch_env:
551 run_test_cmd = 'arch %s %s' % (arch_env, run_test_cmd)
552
553 env = os.environ.copy()
554 env['RUN_TESTS_COMMAND'] = run_tests_cmd
555 if args.xml_report:
556 env['XML_REPORT'] = args.xml_report
Jan Tattermusch261b58c2015-09-18 17:15:48 -0700557 if not args.travis:
558 env['TTY_FLAG'] = '-t' # enables Ctrl-C when not on Jenkins.
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700559
560 subprocess.check_call(['tools/jenkins/build_docker_and_run_tests.sh'],
561 shell=True,
562 env=env)
563 sys.exit(0)
564
Nicolas Nobleddef2462015-01-06 18:08:25 -0800565# grab config
Craig Tiller738c3342015-01-12 14:28:33 -0800566run_configs = set(_CONFIGS[cfg]
567 for cfg in itertools.chain.from_iterable(
568 _CONFIGS.iterkeys() if x == 'all' else [x]
569 for x in args.config))
570build_configs = set(cfg.build_config for cfg in run_configs)
Craig Tillerf1973b02015-01-16 12:32:13 -0800571
Craig Tiller06805272015-06-11 14:46:47 -0700572if args.travis:
573 _FORCE_ENVIRON_FOR_WRAPPERS = {'GRPC_TRACE': 'surface,batch'}
574
Craig Tiller60f15e62015-05-13 09:05:17 -0700575languages = set(_LANGUAGES[l]
576 for l in itertools.chain.from_iterable(
577 _LANGUAGES.iterkeys() if x == 'all' else [x]
578 for x in args.language))
murgatroid99132ce6a2015-03-04 17:29:14 -0800579
580if len(build_configs) > 1:
581 for language in languages:
582 if not language.supports_multi_config():
583 print language, 'does not support multiple build configurations'
584 sys.exit(1)
585
Craig Tiller5058c692015-04-08 09:42:04 -0700586if platform.system() == 'Windows':
murgatroid99a3e244f2015-09-22 11:25:53 -0700587 def make_jobspec(cfg, targets, makefile='Makefile'):
Craig Tillerfc3c0c42015-09-01 16:47:54 -0700588 extra_args = []
Craig Tillerb5391e12015-09-03 14:35:18 -0700589 # better do parallel compilation
Jan Tattermusch47eeb2b2015-10-07 14:09:18 -0700590 # empirically /m:2 gives the best performance/price and should prevent
591 # overloading the windows workers.
592 extra_args.extend(["/m:2"])
Craig Tillerb5391e12015-09-03 14:35:18 -0700593 # disable PDB generation: it's broken, and we don't need it during CI
Craig Tiller3ef8c082015-09-04 15:17:12 -0700594 extra_args.extend(["/p:Jenkins=true"])
Craig Tiller6fd23842015-09-01 07:36:31 -0700595 return [
murgatroid99cf08daf2015-09-21 15:33:16 -0700596 jobset.JobSpec(['vsprojects\\build.bat',
597 'vsprojects\\%s.sln' % target,
Craig Tillerfc3c0c42015-09-01 16:47:54 -0700598 '/p:Configuration=%s' % _WINDOWS_CONFIG[cfg]] +
599 extra_args,
Craig Tillerdfc3eee2015-09-01 16:32:16 -0700600 shell=True, timeout_seconds=90*60)
Craig Tiller6fd23842015-09-01 07:36:31 -0700601 for target in targets]
Craig Tiller5058c692015-04-08 09:42:04 -0700602else:
murgatroid99a3e244f2015-09-22 11:25:53 -0700603 def make_jobspec(cfg, targets, makefile='Makefile'):
Craig Tiller6fd23842015-09-01 07:36:31 -0700604 return [jobset.JobSpec([os.getenv('MAKE', 'make'),
murgatroid99a3e244f2015-09-22 11:25:53 -0700605 '-f', makefile,
Craig Tiller6fd23842015-09-01 07:36:31 -0700606 '-j', '%d' % (multiprocessing.cpu_count() + 1),
607 'EXTRA_DEFINES=GRPC_TEST_SLOWDOWN_MACHINE_FACTOR=%f' %
608 args.slowdown,
609 'CONFIG=%s' % cfg] + targets,
610 timeout_seconds=30*60)]
murgatroid99a3e244f2015-09-22 11:25:53 -0700611make_targets = {}
612for l in languages:
613 makefile = l.makefile_name()
614 make_targets[makefile] = make_targets.get(makefile, set()).union(
615 set(l.make_targets()))
Craig Tiller5058c692015-04-08 09:42:04 -0700616
murgatroid99fddac962015-09-22 09:20:11 -0700617build_steps = list(set(
murgatroid99256d3df2015-09-21 16:58:02 -0700618 jobset.JobSpec(cmdline, environ={'CONFIG': cfg})
619 for cfg in build_configs
620 for l in languages
621 for cmdline in l.pre_build_steps()))
Craig Tillerbd4e3782015-09-01 06:48:55 -0700622if make_targets:
murgatroid99a3e244f2015-09-22 11:25:53 -0700623 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 -0700624 build_steps.extend(set(make_commands))
Craig Tiller5058c692015-04-08 09:42:04 -0700625build_steps.extend(set(
Jan Tattermusch21897192015-10-07 15:42:21 -0700626 jobset.JobSpec(cmdline, environ={'CONFIG': cfg}, timeout_seconds=10*60)
murgatroid99132ce6a2015-03-04 17:29:14 -0800627 for cfg in build_configs
Craig Tiller547db2b2015-01-30 14:08:39 -0800628 for l in languages
Craig Tiller533b1a22015-05-29 08:41:29 -0700629 for cmdline in l.build_steps()))
Craig Tillerf1973b02015-01-16 12:32:13 -0800630
Nicolas Nobleddef2462015-01-06 18:08:25 -0800631runs_per_test = args.runs_per_test
ctiller3040cb72015-01-07 12:13:17 -0800632forever = args.forever
Nicolas Nobleddef2462015-01-06 18:08:25 -0800633
Nicolas Nobleddef2462015-01-06 18:08:25 -0800634
Craig Tiller71735182015-01-15 17:07:13 -0800635class TestCache(object):
Craig Tillerb50d1662015-01-15 17:28:21 -0800636 """Cache for running tests."""
637
David Klempner25739582015-02-11 15:57:32 -0800638 def __init__(self, use_cache_results):
Craig Tiller71735182015-01-15 17:07:13 -0800639 self._last_successful_run = {}
David Klempner25739582015-02-11 15:57:32 -0800640 self._use_cache_results = use_cache_results
Craig Tiller69cd2372015-06-11 09:38:09 -0700641 self._last_save = time.time()
Craig Tiller71735182015-01-15 17:07:13 -0800642
643 def should_run(self, cmdline, bin_hash):
Craig Tiller71735182015-01-15 17:07:13 -0800644 if cmdline not in self._last_successful_run:
645 return True
646 if self._last_successful_run[cmdline] != bin_hash:
647 return True
David Klempner25739582015-02-11 15:57:32 -0800648 if not self._use_cache_results:
649 return True
Craig Tiller71735182015-01-15 17:07:13 -0800650 return False
651
652 def finished(self, cmdline, bin_hash):
Craig Tiller547db2b2015-01-30 14:08:39 -0800653 self._last_successful_run[cmdline] = bin_hash
Craig Tiller69cd2372015-06-11 09:38:09 -0700654 if time.time() - self._last_save > 1:
655 self.save()
Craig Tiller71735182015-01-15 17:07:13 -0800656
657 def dump(self):
Craig Tillerb50d1662015-01-15 17:28:21 -0800658 return [{'cmdline': k, 'hash': v}
659 for k, v in self._last_successful_run.iteritems()]
Craig Tiller71735182015-01-15 17:07:13 -0800660
661 def parse(self, exdump):
662 self._last_successful_run = dict((o['cmdline'], o['hash']) for o in exdump)
663
664 def save(self):
665 with open('.run_tests_cache', 'w') as f:
Craig Tiller261dd982015-01-16 16:41:45 -0800666 f.write(json.dumps(self.dump()))
Craig Tiller69cd2372015-06-11 09:38:09 -0700667 self._last_save = time.time()
Craig Tiller71735182015-01-15 17:07:13 -0800668
Craig Tiller1cc11db2015-01-15 22:50:50 -0800669 def maybe_load(self):
670 if os.path.exists('.run_tests_cache'):
671 with open('.run_tests_cache') as f:
Craig Tiller261dd982015-01-16 16:41:45 -0800672 self.parse(json.loads(f.read()))
Craig Tiller71735182015-01-15 17:07:13 -0800673
674
Craig Tillerf53d9c82015-08-04 14:19:43 -0700675def _start_port_server(port_server_port):
676 # check if a compatible port server is running
677 # if incompatible (version mismatch) ==> start a new one
678 # if not running ==> start a new one
679 # otherwise, leave it up
680 try:
Craig Tillerfe4939f2015-10-06 12:55:36 -0700681 version = int(urllib2.urlopen(
682 'http://localhost:%d/version_number' % port_server_port,
683 timeout=1).read())
684 print 'detected port server running version %d' % version
Craig Tillerf53d9c82015-08-04 14:19:43 -0700685 running = True
Craig Tillerfe4939f2015-10-06 12:55:36 -0700686 except Exception as e:
Craig Tiller0d6499e2015-10-05 14:00:47 -0700687 print 'failed to detect port server: %s' % sys.exc_info()[0]
Craig Tillerfe4939f2015-10-06 12:55:36 -0700688 print e.strerror
Craig Tillerf53d9c82015-08-04 14:19:43 -0700689 running = False
690 if running:
Craig Tillerfe4939f2015-10-06 12:55:36 -0700691 current_version = int(subprocess.check_output(
692 [sys.executable, 'tools/run_tests/port_server.py', 'dump_version']))
693 print 'my port server is version %d' % current_version
694 running = (version >= current_version)
695 if not running:
696 print 'port_server version mismatch: killing the old one'
697 urllib2.urlopen('http://localhost:%d/quitquitquit' % port_server_port).read()
698 time.sleep(1)
Craig Tillerf53d9c82015-08-04 14:19:43 -0700699 if not running:
Craig Tiller0d6499e2015-10-05 14:00:47 -0700700 print 'starting port_server'
Craig Tillerf53d9c82015-08-04 14:19:43 -0700701 port_log = open('portlog.txt', 'w')
702 port_server = subprocess.Popen(
Craig Tiller1447ece2015-10-05 14:44:32 -0700703 [sys.executable, 'tools/run_tests/port_server.py', '-p', '%d' % port_server_port],
Craig Tillerf53d9c82015-08-04 14:19:43 -0700704 stderr=subprocess.STDOUT,
705 stdout=port_log)
Craig Tiller8b5f4dc2015-08-26 08:02:01 -0700706 # ensure port server is up
Craig Tillerabd37fd2015-08-26 07:54:01 -0700707 waits = 0
Craig Tillerf53d9c82015-08-04 14:19:43 -0700708 while True:
Craig Tillerabd37fd2015-08-26 07:54:01 -0700709 if waits > 10:
710 port_server.kill()
Craig Tillera2f38b02015-09-24 11:19:17 -0700711 if port_server.poll() is not None:
Craig Tiller0d6499e2015-10-05 14:00:47 -0700712 print 'port_server failed to start'
Craig Tillera2f38b02015-09-24 11:19:17 -0700713 port_log = open('portlog.txt', 'r').read()
714 print port_log
Craig Tillerabd37fd2015-08-26 07:54:01 -0700715 sys.exit(1)
Craig Tillerf53d9c82015-08-04 14:19:43 -0700716 try:
Craig Tillerabd37fd2015-08-26 07:54:01 -0700717 urllib2.urlopen('http://localhost:%d/get' % port_server_port,
718 timeout=1).read()
Craig Tillerf53d9c82015-08-04 14:19:43 -0700719 break
Craig Tiller31fdaa42015-09-25 13:09:59 -0700720 except socket.timeout:
Craig Tiller0d6499e2015-10-05 14:00:47 -0700721 print 'waiting for port_server: timeout'
Craig Tiller31fdaa42015-09-25 13:09:59 -0700722 time.sleep(0.5)
723 waits += 1
Craig Tillerf53d9c82015-08-04 14:19:43 -0700724 except urllib2.URLError:
Craig Tiller0d6499e2015-10-05 14:00:47 -0700725 print 'waiting for port_server: urlerror'
Craig Tillerf53d9c82015-08-04 14:19:43 -0700726 time.sleep(0.5)
Craig Tillerabd37fd2015-08-26 07:54:01 -0700727 waits += 1
Craig Tillerf53d9c82015-08-04 14:19:43 -0700728 except:
729 port_server.kill()
730 raise
731
732
733def _build_and_run(
734 check_cancelled, newline_on_success, travis, cache, xml_report=None):
ctiller3040cb72015-01-07 12:13:17 -0800735 """Do one pass of building & running tests."""
murgatroid99666450e2015-01-26 13:03:31 -0800736 # build latest sequentially
Nicolas "Pixel" Noblea7df3f92015-02-26 22:07:04 +0100737 if not jobset.run(build_steps, maxjobs=1,
738 newline_on_success=newline_on_success, travis=travis):
Craig Tillerd86a3942015-01-14 12:48:54 -0800739 return 1
ctiller3040cb72015-01-07 12:13:17 -0800740
Craig Tiller234b6e72015-05-23 10:12:40 -0700741 # start antagonists
David Garcia Quintas79e389f2015-06-02 17:49:42 -0700742 antagonists = [subprocess.Popen(['tools/run_tests/antagonist.py'])
Craig Tiller234b6e72015-05-23 10:12:40 -0700743 for _ in range(0, args.antagonists)]
Craig Tillerfe4939f2015-10-06 12:55:36 -0700744 port_server_port = 32767
Craig Tillerf53d9c82015-08-04 14:19:43 -0700745 _start_port_server(port_server_port)
Craig Tiller234b6e72015-05-23 10:12:40 -0700746 try:
David Garcia Quintase90cd372015-05-31 18:15:26 -0700747 infinite_runs = runs_per_test == 0
yang-g6c1fdc62015-08-18 11:57:42 -0700748 one_run = set(
749 spec
750 for config in run_configs
751 for language in languages
752 for spec in language.test_specs(config, args.travis)
753 if re.search(args.regex, spec.shortname))
David Garcia Quintas79e389f2015-06-02 17:49:42 -0700754 # When running on travis, we want out test runs to be as similar as possible
755 # for reproducibility purposes.
756 if travis:
757 massaged_one_run = sorted(one_run, key=lambda x: x.shortname)
758 else:
759 # whereas otherwise, we want to shuffle things up to give all tests a
760 # chance to run.
761 massaged_one_run = list(one_run) # random.shuffle needs an indexable seq.
762 random.shuffle(massaged_one_run) # which it modifies in-place.
Craig Tillerf7b7c892015-06-22 14:33:25 -0700763 if infinite_runs:
764 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 -0700765 runs_sequence = (itertools.repeat(massaged_one_run) if infinite_runs
766 else itertools.repeat(massaged_one_run, runs_per_test))
David Garcia Quintase90cd372015-05-31 18:15:26 -0700767 all_runs = itertools.chain.from_iterable(runs_sequence)
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +0200768
769 root = ET.Element('testsuites') if xml_report else None
770 testsuite = ET.SubElement(root, 'testsuite', id='1', package='grpc', name='tests') if xml_report else None
771
Craig Tiller234b6e72015-05-23 10:12:40 -0700772 if not jobset.run(all_runs, check_cancelled,
773 newline_on_success=newline_on_success, travis=travis,
David Garcia Quintase90cd372015-05-31 18:15:26 -0700774 infinite_runs=infinite_runs,
Craig Tillerda2220a2015-05-27 07:50:53 -0700775 maxjobs=args.jobs,
Craig Tillercd43da82015-05-29 08:41:29 -0700776 stop_on_failure=args.stop_on_failure,
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +0200777 cache=cache if not xml_report else None,
Craig Tillerf53d9c82015-08-04 14:19:43 -0700778 xml_report=testsuite,
779 add_env={'GRPC_TEST_PORT_SERVER': 'localhost:%d' % port_server_port}):
Craig Tiller234b6e72015-05-23 10:12:40 -0700780 return 2
781 finally:
782 for antagonist in antagonists:
783 antagonist.kill()
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +0200784 if xml_report:
785 tree = ET.ElementTree(root)
786 tree.write(xml_report, encoding='UTF-8')
Craig Tillerd86a3942015-01-14 12:48:54 -0800787
Craig Tiller69cd2372015-06-11 09:38:09 -0700788 if cache: cache.save()
789
Craig Tillerd86a3942015-01-14 12:48:54 -0800790 return 0
ctiller3040cb72015-01-07 12:13:17 -0800791
792
David Klempner25739582015-02-11 15:57:32 -0800793test_cache = TestCache(runs_per_test == 1)
Craig Tiller547db2b2015-01-30 14:08:39 -0800794test_cache.maybe_load()
Craig Tiller71735182015-01-15 17:07:13 -0800795
ctiller3040cb72015-01-07 12:13:17 -0800796if forever:
Nicolas Noble044db742015-01-14 16:57:24 -0800797 success = True
ctiller3040cb72015-01-07 12:13:17 -0800798 while True:
Craig Tiller42bc87c2015-02-23 08:50:19 -0800799 dw = watch_dirs.DirWatcher(['src', 'include', 'test', 'examples'])
ctiller3040cb72015-01-07 12:13:17 -0800800 initial_time = dw.most_recent_change()
801 have_files_changed = lambda: dw.most_recent_change() != initial_time
Nicolas Noble044db742015-01-14 16:57:24 -0800802 previous_success = success
Craig Tiller71735182015-01-15 17:07:13 -0800803 success = _build_and_run(check_cancelled=have_files_changed,
Nicolas Nobleb09078f2015-01-14 18:06:05 -0800804 newline_on_success=False,
Craig Tiller9a5a9402015-04-16 10:39:50 -0700805 travis=args.travis,
Craig Tiller71735182015-01-15 17:07:13 -0800806 cache=test_cache) == 0
Nicolas Noble044db742015-01-14 16:57:24 -0800807 if not previous_success and success:
Nicolas Nobleb09078f2015-01-14 18:06:05 -0800808 jobset.message('SUCCESS',
809 'All tests are now passing properly',
810 do_newline=True)
Nicolas Noble044db742015-01-14 16:57:24 -0800811 jobset.message('IDLE', 'No change detected')
ctiller3040cb72015-01-07 12:13:17 -0800812 while not have_files_changed():
813 time.sleep(1)
814else:
Craig Tiller71735182015-01-15 17:07:13 -0800815 result = _build_and_run(check_cancelled=lambda: False,
816 newline_on_success=args.newline_on_success,
Nicolas "Pixel" Noblea7df3f92015-02-26 22:07:04 +0100817 travis=args.travis,
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +0200818 cache=test_cache,
819 xml_report=args.xml_report)
Nicolas Nobleb09078f2015-01-14 18:06:05 -0800820 if result == 0:
821 jobset.message('SUCCESS', 'All tests passed', do_newline=True)
822 else:
823 jobset.message('FAILED', 'Some tests failed', do_newline=True)
824 sys.exit(result)