blob: 52d753729f4788a820465ec44d33599683801120 [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
103 if self.allow_hashing else None)
Craig Tiller738c3342015-01-12 14:28:33 -0800104
105
106# ValgrindConfig: compile with some CONFIG=config, but use valgrind to run
107class ValgrindConfig(object):
Craig Tillerb50d1662015-01-15 17:28:21 -0800108
murgatroid99132ce6a2015-03-04 17:29:14 -0800109 def __init__(self, config, tool, args=None):
110 if args is None:
111 args = []
Craig Tiller738c3342015-01-12 14:28:33 -0800112 self.build_config = config
Craig Tiller2aa4d642015-01-14 15:59:44 -0800113 self.tool = tool
Craig Tiller1a305b12015-02-18 13:37:06 -0800114 self.args = args
Craig Tillerc7449162015-01-16 14:42:10 -0800115 self.allow_hashing = False
Craig Tiller738c3342015-01-12 14:28:33 -0800116
Craig Tiller49f61322015-03-03 13:02:11 -0800117 def job_spec(self, cmdline, hash_targets):
Craig Tiller1a305b12015-02-18 13:37:06 -0800118 return jobset.JobSpec(cmdline=['valgrind', '--tool=%s' % self.tool] +
Craig Tiller49f61322015-03-03 13:02:11 -0800119 self.args + cmdline,
Craig Tiller71ec6cb2015-06-03 00:51:11 -0700120 shortname='valgrind %s' % cmdline[0],
Craig Tiller1a305b12015-02-18 13:37:06 -0800121 hash_targets=None)
Craig Tiller738c3342015-01-12 14:28:33 -0800122
123
murgatroid99cf08daf2015-09-21 15:33:16 -0700124def get_c_tests(travis, test_lang) :
125 out = []
126 platforms_str = 'ci_platforms' if travis else 'platforms'
127 with open('tools/run_tests/tests.json') as f:
murgatroid9989899b12015-09-22 09:14:48 -0700128 js = json.load(f)
murgatroid99a3e244f2015-09-22 11:25:53 -0700129 return [tgt
130 for tgt in js
131 if tgt['language'] == test_lang and
132 platform_string() in tgt[platforms_str] and
133 not (travis and tgt['flaky'])]
murgatroid99cf08daf2015-09-21 15:33:16 -0700134
murgatroid99fafeeb32015-09-22 09:13:03 -0700135
Craig Tillerc7449162015-01-16 14:42:10 -0800136class CLanguage(object):
137
Craig Tillere9c959d2015-01-18 10:23:26 -0800138 def __init__(self, make_target, test_lang):
Craig Tillerc7449162015-01-16 14:42:10 -0800139 self.make_target = make_target
Craig Tillerd50993d2015-08-05 08:04:36 -0700140 self.platform = platform_string()
Craig Tiller711bbe62015-08-19 12:35:16 -0700141 self.test_lang = test_lang
Craig Tillerc7449162015-01-16 14:42:10 -0800142
Nicolas "Pixel" Noble9db7c3b2015-02-27 06:03:00 +0100143 def test_specs(self, config, travis):
Craig Tiller547db2b2015-01-30 14:08:39 -0800144 out = []
murgatroid99cf08daf2015-09-21 15:33:16 -0700145 binaries = get_c_tests(travis, self.test_lang)
Craig Tiller711bbe62015-08-19 12:35:16 -0700146 for target in binaries:
murgatroid99a3e244f2015-09-22 11:25:53 -0700147 if 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':
Craig Tillerf4182602015-09-01 12:23:16 -0700150 binary = 'vsprojects/%s/%s.exe' % (
151 _WINDOWS_CONFIG[config.build_config], target['name'])
Nicolas Noblee1445362015-05-11 17:40:26 -0700152 else:
153 binary = 'bins/%s/%s' % (config.build_config, target['name'])
yang-g6c1fdc62015-08-18 11:57:42 -0700154 if os.path.isfile(binary):
155 out.append(config.job_spec([binary], [binary]))
156 else:
157 print "\nWARNING: binary not found, skipping", binary
Nicolas Noblee1445362015-05-11 17:40:26 -0700158 return sorted(out)
Craig Tillerc7449162015-01-16 14:42:10 -0800159
160 def make_targets(self):
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700161 if platform_string() == 'windows':
162 # don't build tools on windows just yet
163 return ['buildtests_%s' % self.make_target]
Craig Tiller7552f0f2015-06-19 17:46:20 -0700164 return ['buildtests_%s' % self.make_target, 'tools_%s' % self.make_target]
Craig Tillerc7449162015-01-16 14:42:10 -0800165
murgatroid99256d3df2015-09-21 16:58:02 -0700166 def pre_build_steps(self):
167 return []
168
Craig Tillerc7449162015-01-16 14:42:10 -0800169 def build_steps(self):
170 return []
171
murgatroid99a3e244f2015-09-22 11:25:53 -0700172 def makefile_name(self):
173 return 'Makefile'
174
murgatroid99132ce6a2015-03-04 17:29:14 -0800175 def supports_multi_config(self):
176 return True
177
178 def __str__(self):
179 return self.make_target
180
murgatroid99fafeeb32015-09-22 09:13:03 -0700181
murgatroid99cf08daf2015-09-21 15:33:16 -0700182def gyp_test_paths(travis, config=None):
183 binaries = get_c_tests(travis, 'c')
184 out = []
185 for target in binaries:
murgatroid99fddac962015-09-22 09:20:11 -0700186 if config is not None and config.build_config in target['exclude_configs']:
murgatroid99cf08daf2015-09-21 15:33:16 -0700187 continue
188 binary = 'out/Debug/%s' % target['name']
189 out.append(binary)
190 return sorted(out)
191
murgatroid99fafeeb32015-09-22 09:13:03 -0700192
murgatroid99cf08daf2015-09-21 15:33:16 -0700193class GYPCLanguage(object):
194
195 def test_specs(self, config, travis):
196 return [config.job_spec([binary], [binary])
197 for binary in gyp_test_paths(travis, config)]
198
murgatroid99256d3df2015-09-21 16:58:02 -0700199 def pre_build_steps(self):
murgatroid99a3e244f2015-09-22 11:25:53 -0700200 return [['gyp', '--depth=.', '--suffix=-gyp', 'grpc.gyp']]
murgatroid99256d3df2015-09-21 16:58:02 -0700201
murgatroid99cf08daf2015-09-21 15:33:16 -0700202 def make_targets(self):
Craig Tillerc1385d62015-09-24 08:52:00 -0700203 # HACK(ctiller): force fling_client and fling_server to be built, as fling_test
204 # needs these
205 return gyp_test_paths(False) + ['fling_client', 'fling_server']
murgatroid99cf08daf2015-09-21 15:33:16 -0700206
207 def build_steps(self):
208 return []
209
murgatroid99a3e244f2015-09-22 11:25:53 -0700210 def makefile_name(self):
211 return 'Makefile-gyp'
212
murgatroid99cf08daf2015-09-21 15:33:16 -0700213 def supports_multi_config(self):
214 return False
215
216 def __str__(self):
217 return 'gyp'
Craig Tiller99775822015-01-30 13:07:16 -0800218
murgatroid99fafeeb32015-09-22 09:13:03 -0700219
murgatroid992c8d5162015-01-26 10:41:21 -0800220class NodeLanguage(object):
221
Nicolas "Pixel" Noble9db7c3b2015-02-27 06:03:00 +0100222 def test_specs(self, config, travis):
Craig Tiller4fc90032015-05-21 10:39:52 -0700223 return [config.job_spec(['tools/run_tests/run_node.sh'], None,
Craig Tiller06805272015-06-11 14:46:47 -0700224 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
murgatroid992c8d5162015-01-26 10:41:21 -0800225
murgatroid99256d3df2015-09-21 16:58:02 -0700226 def pre_build_steps(self):
227 return []
228
murgatroid992c8d5162015-01-26 10:41:21 -0800229 def make_targets(self):
Craig Tilleraf7cf542015-05-22 10:07:34 -0700230 return ['static_c', 'shared_c']
murgatroid992c8d5162015-01-26 10:41:21 -0800231
232 def build_steps(self):
233 return [['tools/run_tests/build_node.sh']]
Craig Tillerc7449162015-01-16 14:42:10 -0800234
murgatroid99a3e244f2015-09-22 11:25:53 -0700235 def makefile_name(self):
236 return 'Makefile'
237
murgatroid99132ce6a2015-03-04 17:29:14 -0800238 def supports_multi_config(self):
239 return False
240
241 def __str__(self):
242 return 'node'
243
Craig Tiller99775822015-01-30 13:07:16 -0800244
Craig Tillerc7449162015-01-16 14:42:10 -0800245class PhpLanguage(object):
246
Nicolas "Pixel" Noble9db7c3b2015-02-27 06:03:00 +0100247 def test_specs(self, config, travis):
Craig Tiller4fc90032015-05-21 10:39:52 -0700248 return [config.job_spec(['src/php/bin/run_tests.sh'], None,
Craig Tiller06805272015-06-11 14:46:47 -0700249 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
Craig Tillerc7449162015-01-16 14:42:10 -0800250
murgatroid99256d3df2015-09-21 16:58:02 -0700251 def pre_build_steps(self):
252 return []
253
Craig Tillerc7449162015-01-16 14:42:10 -0800254 def make_targets(self):
Craig Tilleraf7cf542015-05-22 10:07:34 -0700255 return ['static_c', 'shared_c']
Craig Tillerc7449162015-01-16 14:42:10 -0800256
257 def build_steps(self):
258 return [['tools/run_tests/build_php.sh']]
259
murgatroid99a3e244f2015-09-22 11:25:53 -0700260 def makefile_name(self):
261 return 'Makefile'
262
murgatroid99132ce6a2015-03-04 17:29:14 -0800263 def supports_multi_config(self):
264 return False
265
266 def __str__(self):
267 return 'php'
268
Craig Tillerc7449162015-01-16 14:42:10 -0800269
Nathaniel Manista840615e2015-01-22 20:31:47 +0000270class PythonLanguage(object):
271
Craig Tiller49f61322015-03-03 13:02:11 -0800272 def __init__(self):
Masood Malekghassemi2b841622015-07-28 17:39:02 -0700273 self._build_python_versions = ['2.7']
Masood Malekghassemie5f70022015-06-29 09:20:26 -0700274 self._has_python_versions = []
Craig Tiller49f61322015-03-03 13:02:11 -0800275
Nicolas "Pixel" Noble9db7c3b2015-02-27 06:03:00 +0100276 def test_specs(self, config, travis):
Masood Malekghassemi2b841622015-07-28 17:39:02 -0700277 environment = dict(_FORCE_ENVIRON_FOR_WRAPPERS)
278 environment['PYVER'] = '2.7'
279 return [config.job_spec(
280 ['tools/run_tests/run_python.sh'],
281 None,
282 environ=environment,
283 shortname='py.test',
284 )]
Nathaniel Manista840615e2015-01-22 20:31:47 +0000285
murgatroid99256d3df2015-09-21 16:58:02 -0700286 def pre_build_steps(self):
287 return []
288
Nathaniel Manista840615e2015-01-22 20:31:47 +0000289 def make_targets(self):
Craig Tilleraf7cf542015-05-22 10:07:34 -0700290 return ['static_c', 'grpc_python_plugin', 'shared_c']
Nathaniel Manista840615e2015-01-22 20:31:47 +0000291
292 def build_steps(self):
Masood Malekghassemie5f70022015-06-29 09:20:26 -0700293 commands = []
294 for python_version in self._build_python_versions:
295 try:
296 with open(os.devnull, 'w') as output:
297 subprocess.check_call(['which', 'python' + python_version],
298 stdout=output, stderr=output)
299 commands.append(['tools/run_tests/build_python.sh', python_version])
300 self._has_python_versions.append(python_version)
301 except:
302 jobset.message('WARNING', 'Missing Python ' + python_version,
303 do_newline=True)
304 return commands
Nathaniel Manista840615e2015-01-22 20:31:47 +0000305
murgatroid99a3e244f2015-09-22 11:25:53 -0700306 def makefile_name(self):
307 return 'Makefile'
308
murgatroid99132ce6a2015-03-04 17:29:14 -0800309 def supports_multi_config(self):
310 return False
311
312 def __str__(self):
313 return 'python'
314
Craig Tillerd625d812015-04-08 15:52:35 -0700315
murgatroid996a4c4fa2015-02-27 12:08:57 -0800316class RubyLanguage(object):
317
318 def test_specs(self, config, travis):
Craig Tiller4fc90032015-05-21 10:39:52 -0700319 return [config.job_spec(['tools/run_tests/run_ruby.sh'], None,
Craig Tiller06805272015-06-11 14:46:47 -0700320 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
murgatroid996a4c4fa2015-02-27 12:08:57 -0800321
murgatroid99256d3df2015-09-21 16:58:02 -0700322 def pre_build_steps(self):
323 return []
324
murgatroid996a4c4fa2015-02-27 12:08:57 -0800325 def make_targets(self):
murgatroid99a43c14f2015-07-30 13:31:23 -0700326 return ['static_c']
murgatroid996a4c4fa2015-02-27 12:08:57 -0800327
328 def build_steps(self):
329 return [['tools/run_tests/build_ruby.sh']]
330
murgatroid99a3e244f2015-09-22 11:25:53 -0700331 def makefile_name(self):
332 return 'Makefile'
333
murgatroid99132ce6a2015-03-04 17:29:14 -0800334 def supports_multi_config(self):
335 return False
336
337 def __str__(self):
338 return 'ruby'
339
Craig Tillerd625d812015-04-08 15:52:35 -0700340
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800341class CSharpLanguage(object):
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700342 def __init__(self):
Craig Tillerd50993d2015-08-05 08:04:36 -0700343 self.platform = platform_string()
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700344
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800345 def test_specs(self, config, travis):
Jan Tattermusch9a7d30c2015-04-23 16:12:55 -0700346 assemblies = ['Grpc.Core.Tests',
347 'Grpc.Examples.Tests',
Jan Tattermusch9d67d8d2015-08-01 20:39:16 -0700348 'Grpc.HealthCheck.Tests',
Jan Tattermusch9a7d30c2015-04-23 16:12:55 -0700349 'Grpc.IntegrationTesting']
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700350 if self.platform == 'windows':
351 cmd = 'tools\\run_tests\\run_csharp.bat'
352 else:
353 cmd = 'tools/run_tests/run_csharp.sh'
354 return [config.job_spec([cmd, assembly],
Craig Tiller4fc90032015-05-21 10:39:52 -0700355 None, shortname=assembly,
Craig Tiller06805272015-06-11 14:46:47 -0700356 environ=_FORCE_ENVIRON_FOR_WRAPPERS)
Craig Tillerd50993d2015-08-05 08:04:36 -0700357 for assembly in assemblies]
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800358
murgatroid99256d3df2015-09-21 16:58:02 -0700359 def pre_build_steps(self):
360 return []
361
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800362 def make_targets(self):
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700363 # For Windows, this target doesn't really build anything,
364 # everything is build by buildall script later.
Craig Tillerd5904822015-08-31 21:30:58 -0700365 if self.platform == 'windows':
366 return []
367 else:
368 return ['grpc_csharp_ext']
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800369
370 def build_steps(self):
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700371 if self.platform == 'windows':
372 return [['src\\csharp\\buildall.bat']]
373 else:
374 return [['tools/run_tests/build_csharp.sh']]
Nathaniel Manista840615e2015-01-22 20:31:47 +0000375
murgatroid99a3e244f2015-09-22 11:25:53 -0700376 def makefile_name(self):
377 return 'Makefile'
378
murgatroid99132ce6a2015-03-04 17:29:14 -0800379 def supports_multi_config(self):
380 return False
381
382 def __str__(self):
383 return 'csharp'
384
Craig Tillerd625d812015-04-08 15:52:35 -0700385
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700386class ObjCLanguage(object):
387
388 def test_specs(self, config, travis):
389 return [config.job_spec(['src/objective-c/tests/run_tests.sh'], None,
390 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
391
murgatroid99256d3df2015-09-21 16:58:02 -0700392 def pre_build_steps(self):
393 return []
394
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700395 def make_targets(self):
Jorge Canizalesd0b32e92015-07-30 23:08:43 -0700396 return ['grpc_objective_c_plugin', 'interop_server']
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700397
398 def build_steps(self):
Jorge Canizalesd0b32e92015-07-30 23:08:43 -0700399 return [['src/objective-c/tests/build_tests.sh']]
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700400
murgatroid99a3e244f2015-09-22 11:25:53 -0700401 def makefile_name(self):
402 return 'Makefile'
403
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700404 def supports_multi_config(self):
405 return False
406
407 def __str__(self):
408 return 'objc'
409
410
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100411class Sanity(object):
412
413 def test_specs(self, config, travis):
Craig Tillerf75fc122015-06-25 06:58:00 -0700414 return [config.job_spec('tools/run_tests/run_sanity.sh', None),
415 config.job_spec('tools/run_tests/check_sources_and_headers.py', None)]
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100416
murgatroid99256d3df2015-09-21 16:58:02 -0700417 def pre_build_steps(self):
418 return []
419
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100420 def make_targets(self):
421 return ['run_dep_checks']
422
423 def build_steps(self):
424 return []
425
murgatroid99a3e244f2015-09-22 11:25:53 -0700426 def makefile_name(self):
427 return 'Makefile'
428
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100429 def supports_multi_config(self):
430 return False
431
432 def __str__(self):
433 return 'sanity'
434
Nicolas "Pixel" Noblee55cd7f2015-04-14 17:59:13 +0200435
Nicolas "Pixel" Noblefd2b0932015-03-26 00:26:29 +0100436class Build(object):
437
438 def test_specs(self, config, travis):
439 return []
440
murgatroid99256d3df2015-09-21 16:58:02 -0700441 def pre_build_steps(self):
442 return []
443
Nicolas "Pixel" Noblefd2b0932015-03-26 00:26:29 +0100444 def make_targets(self):
Nicolas "Pixel" Noblec23827b2015-04-23 06:17:55 +0200445 return ['static']
Nicolas "Pixel" Noblefd2b0932015-03-26 00:26:29 +0100446
447 def build_steps(self):
448 return []
449
murgatroid99a3e244f2015-09-22 11:25:53 -0700450 def makefile_name(self):
451 return 'Makefile'
452
Nicolas "Pixel" Noblefd2b0932015-03-26 00:26:29 +0100453 def supports_multi_config(self):
454 return True
455
456 def __str__(self):
457 return self.make_target
458
459
Craig Tiller738c3342015-01-12 14:28:33 -0800460# different configurations we can run under
461_CONFIGS = {
Craig Tillerb50d1662015-01-15 17:28:21 -0800462 'dbg': SimpleConfig('dbg'),
463 'opt': SimpleConfig('opt'),
Craig Tillerb2ea0b92015-08-26 13:06:53 -0700464 'tsan': SimpleConfig('tsan', timeout_seconds=10*60, environ={
Craig Tiller1ada6ad2015-07-16 16:19:14 -0700465 'TSAN_OPTIONS': 'suppressions=tools/tsan_suppressions.txt:halt_on_error=1:second_deadlock_stack=1'}),
Craig Tiller4a71ce22015-08-26 15:47:55 -0700466 'msan': SimpleConfig('msan', timeout_seconds=7*60),
Craig Tiller96bd5f62015-02-13 09:04:13 -0800467 'ubsan': SimpleConfig('ubsan'),
Craig Tillerb2ea0b92015-08-26 13:06:53 -0700468 'asan': SimpleConfig('asan', timeout_seconds=7*60, environ={
Craig Tillerd4b13622015-05-29 09:10:10 -0700469 'ASAN_OPTIONS': 'detect_leaks=1:color=always:suppressions=tools/tsan_suppressions.txt',
470 'LSAN_OPTIONS': 'report_objects=1'}),
Craig Tiller810725c2015-05-12 09:44:41 -0700471 'asan-noleaks': SimpleConfig('asan', environ={
472 'ASAN_OPTIONS': 'detect_leaks=0:color=always:suppressions=tools/tsan_suppressions.txt'}),
Craig Tillerb50d1662015-01-15 17:28:21 -0800473 'gcov': SimpleConfig('gcov'),
Craig Tiller1a305b12015-02-18 13:37:06 -0800474 'memcheck': ValgrindConfig('valgrind', 'memcheck', ['--leak-check=full']),
Craig Tillerb50d1662015-01-15 17:28:21 -0800475 'helgrind': ValgrindConfig('dbg', 'helgrind')
476 }
Craig Tiller738c3342015-01-12 14:28:33 -0800477
478
Nicolas "Pixel" Noble1fb5e822015-03-16 06:20:37 +0100479_DEFAULT = ['opt']
Craig Tillerc7449162015-01-16 14:42:10 -0800480_LANGUAGES = {
Craig Tillere9c959d2015-01-18 10:23:26 -0800481 'c++': CLanguage('cxx', 'c++'),
482 'c': CLanguage('c', 'c'),
murgatroid99cf08daf2015-09-21 15:33:16 -0700483 'gyp': GYPCLanguage(),
murgatroid992c8d5162015-01-26 10:41:21 -0800484 'node': NodeLanguage(),
Nathaniel Manista840615e2015-01-22 20:31:47 +0000485 'php': PhpLanguage(),
486 'python': PythonLanguage(),
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800487 'ruby': RubyLanguage(),
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100488 'csharp': CSharpLanguage(),
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700489 'objc' : ObjCLanguage(),
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100490 'sanity': Sanity(),
Nicolas "Pixel" Noblefd2b0932015-03-26 00:26:29 +0100491 'build': Build(),
Craig Tillereb272bc2015-01-30 13:13:14 -0800492 }
Nicolas Nobleddef2462015-01-06 18:08:25 -0800493
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700494_WINDOWS_CONFIG = {
495 'dbg': 'Debug',
496 'opt': 'Release',
497 }
498
David Garcia Quintase90cd372015-05-31 18:15:26 -0700499
500def runs_per_test_type(arg_str):
501 """Auxilary function to parse the "runs_per_test" flag.
502
503 Returns:
504 A positive integer or 0, the latter indicating an infinite number of
505 runs.
506
507 Raises:
508 argparse.ArgumentTypeError: Upon invalid input.
509 """
510 if arg_str == 'inf':
511 return 0
512 try:
513 n = int(arg_str)
514 if n <= 0: raise ValueError
Craig Tiller50e53e22015-06-01 20:18:21 -0700515 return n
David Garcia Quintase90cd372015-05-31 18:15:26 -0700516 except:
517 msg = "'{}' isn't a positive integer or 'inf'".format(arg_str)
518 raise argparse.ArgumentTypeError(msg)
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700519
520# parse command line
521argp = argparse.ArgumentParser(description='Run grpc tests.')
522argp.add_argument('-c', '--config',
523 choices=['all'] + sorted(_CONFIGS.keys()),
524 nargs='+',
525 default=_DEFAULT)
David Garcia Quintase90cd372015-05-31 18:15:26 -0700526argp.add_argument('-n', '--runs_per_test', default=1, type=runs_per_test_type,
527 help='A positive integer or "inf". If "inf", all tests will run in an '
528 'infinite loop. Especially useful in combination with "-f"')
Craig Tillerfe406ec2015-02-24 13:55:12 -0800529argp.add_argument('-r', '--regex', default='.*', type=str)
Craig Tiller83762ac2015-05-22 14:04:06 -0700530argp.add_argument('-j', '--jobs', default=2 * multiprocessing.cpu_count(), type=int)
Craig Tiller8451e872015-02-27 09:25:51 -0800531argp.add_argument('-s', '--slowdown', default=1.0, type=float)
ctiller3040cb72015-01-07 12:13:17 -0800532argp.add_argument('-f', '--forever',
533 default=False,
534 action='store_const',
535 const=True)
Nicolas "Pixel" Noblea7df3f92015-02-26 22:07:04 +0100536argp.add_argument('-t', '--travis',
537 default=False,
538 action='store_const',
539 const=True)
Nicolas Noble044db742015-01-14 16:57:24 -0800540argp.add_argument('--newline_on_success',
541 default=False,
542 action='store_const',
543 const=True)
Craig Tiller686fb262015-01-15 07:39:09 -0800544argp.add_argument('-l', '--language',
Craig Tiller60f15e62015-05-13 09:05:17 -0700545 choices=['all'] + sorted(_LANGUAGES.keys()),
Craig Tiller686fb262015-01-15 07:39:09 -0800546 nargs='+',
Craig Tiller60f15e62015-05-13 09:05:17 -0700547 default=['all'])
Craig Tillercd43da82015-05-29 08:41:29 -0700548argp.add_argument('-S', '--stop_on_failure',
549 default=False,
550 action='store_const',
551 const=True)
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700552argp.add_argument('--use_docker',
553 default=False,
554 action='store_const',
555 const=True,
556 help="Run all the tests under docker. That provides " +
557 "additional isolation and prevents the need to installs " +
558 "language specific prerequisites. Only available on Linux.")
Craig Tiller234b6e72015-05-23 10:12:40 -0700559argp.add_argument('-a', '--antagonists', default=0, type=int)
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +0200560argp.add_argument('-x', '--xml_report', default=None, type=str,
561 help='Generates a JUnit-compatible XML report')
Nicolas Nobleddef2462015-01-06 18:08:25 -0800562args = argp.parse_args()
563
Jan Tattermuschc96b9eb2015-09-18 16:01:21 -0700564if args.use_docker:
565 if not args.travis:
566 print 'Seen --use_docker flag, will run tests under docker.'
567 print
568 print 'IMPORTANT: The changes you are testing need to be locally committed'
569 print 'because only the committed changes in the current branch will be'
570 print 'copied to the docker environment.'
571 time.sleep(5)
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700572
573 child_argv = [ arg for arg in sys.argv if not arg == '--use_docker' ]
574 run_tests_cmd = 'tools/run_tests/run_tests.py %s' % " ".join(child_argv[1:])
575
576 # TODO(jtattermusch): revisit if we need special handling for arch here
577 # set arch command prefix in case we are working with different arch.
578 arch_env = os.getenv('arch')
579 if arch_env:
580 run_test_cmd = 'arch %s %s' % (arch_env, run_test_cmd)
581
582 env = os.environ.copy()
583 env['RUN_TESTS_COMMAND'] = run_tests_cmd
584 if args.xml_report:
585 env['XML_REPORT'] = args.xml_report
Jan Tattermusch261b58c2015-09-18 17:15:48 -0700586 if not args.travis:
587 env['TTY_FLAG'] = '-t' # enables Ctrl-C when not on Jenkins.
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700588
589 subprocess.check_call(['tools/jenkins/build_docker_and_run_tests.sh'],
590 shell=True,
591 env=env)
592 sys.exit(0)
593
Nicolas Nobleddef2462015-01-06 18:08:25 -0800594# grab config
Craig Tiller738c3342015-01-12 14:28:33 -0800595run_configs = set(_CONFIGS[cfg]
596 for cfg in itertools.chain.from_iterable(
597 _CONFIGS.iterkeys() if x == 'all' else [x]
598 for x in args.config))
599build_configs = set(cfg.build_config for cfg in run_configs)
Craig Tillerf1973b02015-01-16 12:32:13 -0800600
Craig Tiller06805272015-06-11 14:46:47 -0700601if args.travis:
602 _FORCE_ENVIRON_FOR_WRAPPERS = {'GRPC_TRACE': 'surface,batch'}
603
Craig Tiller60f15e62015-05-13 09:05:17 -0700604languages = set(_LANGUAGES[l]
605 for l in itertools.chain.from_iterable(
606 _LANGUAGES.iterkeys() if x == 'all' else [x]
607 for x in args.language))
murgatroid99132ce6a2015-03-04 17:29:14 -0800608
609if len(build_configs) > 1:
610 for language in languages:
611 if not language.supports_multi_config():
612 print language, 'does not support multiple build configurations'
613 sys.exit(1)
614
Craig Tiller5058c692015-04-08 09:42:04 -0700615if platform.system() == 'Windows':
murgatroid99a3e244f2015-09-22 11:25:53 -0700616 def make_jobspec(cfg, targets, makefile='Makefile'):
Craig Tillerfc3c0c42015-09-01 16:47:54 -0700617 extra_args = []
Craig Tillerb5391e12015-09-03 14:35:18 -0700618 # better do parallel compilation
619 extra_args.extend(["/m"])
620 # disable PDB generation: it's broken, and we don't need it during CI
621 extra_args.extend(["/p:GenerateDebugInformation=false", "/p:DebugInformationFormat=None"])
Craig Tiller6fd23842015-09-01 07:36:31 -0700622 return [
murgatroid99cf08daf2015-09-21 15:33:16 -0700623 jobset.JobSpec(['vsprojects\\build.bat',
624 'vsprojects\\%s.sln' % target,
Craig Tillerfc3c0c42015-09-01 16:47:54 -0700625 '/p:Configuration=%s' % _WINDOWS_CONFIG[cfg]] +
626 extra_args,
Craig Tillerdfc3eee2015-09-01 16:32:16 -0700627 shell=True, timeout_seconds=90*60)
Craig Tiller6fd23842015-09-01 07:36:31 -0700628 for target in targets]
Craig Tiller5058c692015-04-08 09:42:04 -0700629else:
murgatroid99a3e244f2015-09-22 11:25:53 -0700630 def make_jobspec(cfg, targets, makefile='Makefile'):
Craig Tiller6fd23842015-09-01 07:36:31 -0700631 return [jobset.JobSpec([os.getenv('MAKE', 'make'),
murgatroid99a3e244f2015-09-22 11:25:53 -0700632 '-f', makefile,
Craig Tiller6fd23842015-09-01 07:36:31 -0700633 '-j', '%d' % (multiprocessing.cpu_count() + 1),
634 'EXTRA_DEFINES=GRPC_TEST_SLOWDOWN_MACHINE_FACTOR=%f' %
635 args.slowdown,
636 'CONFIG=%s' % cfg] + targets,
637 timeout_seconds=30*60)]
murgatroid99a3e244f2015-09-22 11:25:53 -0700638make_targets = {}
639for l in languages:
640 makefile = l.makefile_name()
641 make_targets[makefile] = make_targets.get(makefile, set()).union(
642 set(l.make_targets()))
Craig Tiller5058c692015-04-08 09:42:04 -0700643
murgatroid99fddac962015-09-22 09:20:11 -0700644build_steps = list(set(
murgatroid99256d3df2015-09-21 16:58:02 -0700645 jobset.JobSpec(cmdline, environ={'CONFIG': cfg})
646 for cfg in build_configs
647 for l in languages
648 for cmdline in l.pre_build_steps()))
Craig Tillerbd4e3782015-09-01 06:48:55 -0700649if make_targets:
murgatroid99a3e244f2015-09-22 11:25:53 -0700650 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 -0700651 build_steps.extend(set(make_commands))
Craig Tiller5058c692015-04-08 09:42:04 -0700652build_steps.extend(set(
murgatroid99132ce6a2015-03-04 17:29:14 -0800653 jobset.JobSpec(cmdline, environ={'CONFIG': cfg})
654 for cfg in build_configs
Craig Tiller547db2b2015-01-30 14:08:39 -0800655 for l in languages
Craig Tiller533b1a22015-05-29 08:41:29 -0700656 for cmdline in l.build_steps()))
Craig Tillerf1973b02015-01-16 12:32:13 -0800657
Nicolas Nobleddef2462015-01-06 18:08:25 -0800658runs_per_test = args.runs_per_test
ctiller3040cb72015-01-07 12:13:17 -0800659forever = args.forever
Nicolas Nobleddef2462015-01-06 18:08:25 -0800660
Nicolas Nobleddef2462015-01-06 18:08:25 -0800661
Craig Tiller71735182015-01-15 17:07:13 -0800662class TestCache(object):
Craig Tillerb50d1662015-01-15 17:28:21 -0800663 """Cache for running tests."""
664
David Klempner25739582015-02-11 15:57:32 -0800665 def __init__(self, use_cache_results):
Craig Tiller71735182015-01-15 17:07:13 -0800666 self._last_successful_run = {}
David Klempner25739582015-02-11 15:57:32 -0800667 self._use_cache_results = use_cache_results
Craig Tiller69cd2372015-06-11 09:38:09 -0700668 self._last_save = time.time()
Craig Tiller71735182015-01-15 17:07:13 -0800669
670 def should_run(self, cmdline, bin_hash):
Craig Tiller71735182015-01-15 17:07:13 -0800671 if cmdline not in self._last_successful_run:
672 return True
673 if self._last_successful_run[cmdline] != bin_hash:
674 return True
David Klempner25739582015-02-11 15:57:32 -0800675 if not self._use_cache_results:
676 return True
Craig Tiller71735182015-01-15 17:07:13 -0800677 return False
678
679 def finished(self, cmdline, bin_hash):
Craig Tiller547db2b2015-01-30 14:08:39 -0800680 self._last_successful_run[cmdline] = bin_hash
Craig Tiller69cd2372015-06-11 09:38:09 -0700681 if time.time() - self._last_save > 1:
682 self.save()
Craig Tiller71735182015-01-15 17:07:13 -0800683
684 def dump(self):
Craig Tillerb50d1662015-01-15 17:28:21 -0800685 return [{'cmdline': k, 'hash': v}
686 for k, v in self._last_successful_run.iteritems()]
Craig Tiller71735182015-01-15 17:07:13 -0800687
688 def parse(self, exdump):
689 self._last_successful_run = dict((o['cmdline'], o['hash']) for o in exdump)
690
691 def save(self):
692 with open('.run_tests_cache', 'w') as f:
Craig Tiller261dd982015-01-16 16:41:45 -0800693 f.write(json.dumps(self.dump()))
Craig Tiller69cd2372015-06-11 09:38:09 -0700694 self._last_save = time.time()
Craig Tiller71735182015-01-15 17:07:13 -0800695
Craig Tiller1cc11db2015-01-15 22:50:50 -0800696 def maybe_load(self):
697 if os.path.exists('.run_tests_cache'):
698 with open('.run_tests_cache') as f:
Craig Tiller261dd982015-01-16 16:41:45 -0800699 self.parse(json.loads(f.read()))
Craig Tiller71735182015-01-15 17:07:13 -0800700
701
Craig Tillerf53d9c82015-08-04 14:19:43 -0700702def _start_port_server(port_server_port):
703 # check if a compatible port server is running
704 # if incompatible (version mismatch) ==> start a new one
705 # if not running ==> start a new one
706 # otherwise, leave it up
707 try:
Craig Tillerabd37fd2015-08-26 07:54:01 -0700708 version = urllib2.urlopen('http://localhost:%d/version' % port_server_port,
709 timeout=1).read()
Craig Tillerf53d9c82015-08-04 14:19:43 -0700710 running = True
711 except Exception:
712 running = False
713 if running:
714 with open('tools/run_tests/port_server.py') as f:
715 current_version = hashlib.sha1(f.read()).hexdigest()
716 running = (version == current_version)
717 if not running:
Craig Tilleref125592015-08-05 07:41:35 -0700718 urllib2.urlopen('http://localhost:%d/quit' % port_server_port).read()
719 time.sleep(1)
Craig Tillerf53d9c82015-08-04 14:19:43 -0700720 if not running:
721 port_log = open('portlog.txt', 'w')
722 port_server = subprocess.Popen(
Craig Tiller9a0c10e2015-08-06 15:47:32 -0700723 ['python', 'tools/run_tests/port_server.py', '-p', '%d' % port_server_port],
Craig Tillerf53d9c82015-08-04 14:19:43 -0700724 stderr=subprocess.STDOUT,
725 stdout=port_log)
Craig Tiller8b5f4dc2015-08-26 08:02:01 -0700726 # ensure port server is up
Craig Tillerabd37fd2015-08-26 07:54:01 -0700727 waits = 0
Craig Tillerf53d9c82015-08-04 14:19:43 -0700728 while True:
Craig Tillerabd37fd2015-08-26 07:54:01 -0700729 if waits > 10:
730 port_server.kill()
Craig Tillera2f38b02015-09-24 11:19:17 -0700731 if port_server.poll() is not None:
Craig Tillerabd37fd2015-08-26 07:54:01 -0700732 print "port_server failed to start"
Craig Tillera2f38b02015-09-24 11:19:17 -0700733 port_log = open('portlog.txt', 'r').read()
734 print port_log
Craig Tillerabd37fd2015-08-26 07:54:01 -0700735 sys.exit(1)
Craig Tillerf53d9c82015-08-04 14:19:43 -0700736 try:
Craig Tillerabd37fd2015-08-26 07:54:01 -0700737 urllib2.urlopen('http://localhost:%d/get' % port_server_port,
738 timeout=1).read()
Craig Tillerf53d9c82015-08-04 14:19:43 -0700739 break
Craig Tiller31fdaa42015-09-25 13:09:59 -0700740 except socket.timeout:
741 print "waiting for port_server"
742 time.sleep(0.5)
743 waits += 1
Craig Tillerf53d9c82015-08-04 14:19:43 -0700744 except urllib2.URLError:
Craig Tillerabd37fd2015-08-26 07:54:01 -0700745 print "waiting for port_server"
Craig Tillerf53d9c82015-08-04 14:19:43 -0700746 time.sleep(0.5)
Craig Tillerabd37fd2015-08-26 07:54:01 -0700747 waits += 1
Craig Tillerf53d9c82015-08-04 14:19:43 -0700748 except:
749 port_server.kill()
750 raise
751
752
753def _build_and_run(
754 check_cancelled, newline_on_success, travis, cache, xml_report=None):
ctiller3040cb72015-01-07 12:13:17 -0800755 """Do one pass of building & running tests."""
murgatroid99666450e2015-01-26 13:03:31 -0800756 # build latest sequentially
Nicolas "Pixel" Noblea7df3f92015-02-26 22:07:04 +0100757 if not jobset.run(build_steps, maxjobs=1,
758 newline_on_success=newline_on_success, travis=travis):
Craig Tillerd86a3942015-01-14 12:48:54 -0800759 return 1
ctiller3040cb72015-01-07 12:13:17 -0800760
Craig Tiller234b6e72015-05-23 10:12:40 -0700761 # start antagonists
David Garcia Quintas79e389f2015-06-02 17:49:42 -0700762 antagonists = [subprocess.Popen(['tools/run_tests/antagonist.py'])
Craig Tiller234b6e72015-05-23 10:12:40 -0700763 for _ in range(0, args.antagonists)]
Craig Tillerf53d9c82015-08-04 14:19:43 -0700764 port_server_port = 9999
765 _start_port_server(port_server_port)
Craig Tiller234b6e72015-05-23 10:12:40 -0700766 try:
David Garcia Quintase90cd372015-05-31 18:15:26 -0700767 infinite_runs = runs_per_test == 0
yang-g6c1fdc62015-08-18 11:57:42 -0700768 one_run = set(
769 spec
770 for config in run_configs
771 for language in languages
772 for spec in language.test_specs(config, args.travis)
773 if re.search(args.regex, spec.shortname))
David Garcia Quintas79e389f2015-06-02 17:49:42 -0700774 # When running on travis, we want out test runs to be as similar as possible
775 # for reproducibility purposes.
776 if travis:
777 massaged_one_run = sorted(one_run, key=lambda x: x.shortname)
778 else:
779 # whereas otherwise, we want to shuffle things up to give all tests a
780 # chance to run.
781 massaged_one_run = list(one_run) # random.shuffle needs an indexable seq.
782 random.shuffle(massaged_one_run) # which it modifies in-place.
Craig Tillerf7b7c892015-06-22 14:33:25 -0700783 if infinite_runs:
784 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 -0700785 runs_sequence = (itertools.repeat(massaged_one_run) if infinite_runs
786 else itertools.repeat(massaged_one_run, runs_per_test))
David Garcia Quintase90cd372015-05-31 18:15:26 -0700787 all_runs = itertools.chain.from_iterable(runs_sequence)
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +0200788
789 root = ET.Element('testsuites') if xml_report else None
790 testsuite = ET.SubElement(root, 'testsuite', id='1', package='grpc', name='tests') if xml_report else None
791
Craig Tiller234b6e72015-05-23 10:12:40 -0700792 if not jobset.run(all_runs, check_cancelled,
793 newline_on_success=newline_on_success, travis=travis,
David Garcia Quintase90cd372015-05-31 18:15:26 -0700794 infinite_runs=infinite_runs,
Craig Tillerda2220a2015-05-27 07:50:53 -0700795 maxjobs=args.jobs,
Craig Tillercd43da82015-05-29 08:41:29 -0700796 stop_on_failure=args.stop_on_failure,
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +0200797 cache=cache if not xml_report else None,
Craig Tillerf53d9c82015-08-04 14:19:43 -0700798 xml_report=testsuite,
799 add_env={'GRPC_TEST_PORT_SERVER': 'localhost:%d' % port_server_port}):
Craig Tiller234b6e72015-05-23 10:12:40 -0700800 return 2
801 finally:
802 for antagonist in antagonists:
803 antagonist.kill()
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +0200804 if xml_report:
805 tree = ET.ElementTree(root)
806 tree.write(xml_report, encoding='UTF-8')
Craig Tillerd86a3942015-01-14 12:48:54 -0800807
Craig Tiller69cd2372015-06-11 09:38:09 -0700808 if cache: cache.save()
809
Craig Tillerd86a3942015-01-14 12:48:54 -0800810 return 0
ctiller3040cb72015-01-07 12:13:17 -0800811
812
David Klempner25739582015-02-11 15:57:32 -0800813test_cache = TestCache(runs_per_test == 1)
Craig Tiller547db2b2015-01-30 14:08:39 -0800814test_cache.maybe_load()
Craig Tiller71735182015-01-15 17:07:13 -0800815
ctiller3040cb72015-01-07 12:13:17 -0800816if forever:
Nicolas Noble044db742015-01-14 16:57:24 -0800817 success = True
ctiller3040cb72015-01-07 12:13:17 -0800818 while True:
Craig Tiller42bc87c2015-02-23 08:50:19 -0800819 dw = watch_dirs.DirWatcher(['src', 'include', 'test', 'examples'])
ctiller3040cb72015-01-07 12:13:17 -0800820 initial_time = dw.most_recent_change()
821 have_files_changed = lambda: dw.most_recent_change() != initial_time
Nicolas Noble044db742015-01-14 16:57:24 -0800822 previous_success = success
Craig Tiller71735182015-01-15 17:07:13 -0800823 success = _build_and_run(check_cancelled=have_files_changed,
Nicolas Nobleb09078f2015-01-14 18:06:05 -0800824 newline_on_success=False,
Craig Tiller9a5a9402015-04-16 10:39:50 -0700825 travis=args.travis,
Craig Tiller71735182015-01-15 17:07:13 -0800826 cache=test_cache) == 0
Nicolas Noble044db742015-01-14 16:57:24 -0800827 if not previous_success and success:
Nicolas Nobleb09078f2015-01-14 18:06:05 -0800828 jobset.message('SUCCESS',
829 'All tests are now passing properly',
830 do_newline=True)
Nicolas Noble044db742015-01-14 16:57:24 -0800831 jobset.message('IDLE', 'No change detected')
ctiller3040cb72015-01-07 12:13:17 -0800832 while not have_files_changed():
833 time.sleep(1)
834else:
Craig Tiller71735182015-01-15 17:07:13 -0800835 result = _build_and_run(check_cancelled=lambda: False,
836 newline_on_success=args.newline_on_success,
Nicolas "Pixel" Noblea7df3f92015-02-26 22:07:04 +0100837 travis=args.travis,
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +0200838 cache=test_cache,
839 xml_report=args.xml_report)
Nicolas Nobleb09078f2015-01-14 18:06:05 -0800840 if result == 0:
841 jobset.message('SUCCESS', 'All tests passed', do_newline=True)
842 else:
843 jobset.message('FAILED', 'Some tests failed', do_newline=True)
844 sys.exit(result)