blob: d5036d55d8bd2d0cfd82f5fe82aaba260d100ec6 [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):
Jan Tattermusch874aec02015-10-07 19:26:19 -0700170 if self.platform == 'windows':
171 return [['tools\\run_tests\\pre_build_c.bat']]
172 else:
173 return []
murgatroid99256d3df2015-09-21 16:58:02 -0700174
Craig Tillerc7449162015-01-16 14:42:10 -0800175 def build_steps(self):
176 return []
177
murgatroid99a3e244f2015-09-22 11:25:53 -0700178 def makefile_name(self):
179 return 'Makefile'
180
murgatroid99132ce6a2015-03-04 17:29:14 -0800181 def supports_multi_config(self):
182 return True
183
184 def __str__(self):
185 return self.make_target
186
murgatroid992c8d5162015-01-26 10:41:21 -0800187class NodeLanguage(object):
188
Nicolas "Pixel" Noble9db7c3b2015-02-27 06:03:00 +0100189 def test_specs(self, config, travis):
Craig Tiller4fc90032015-05-21 10:39:52 -0700190 return [config.job_spec(['tools/run_tests/run_node.sh'], None,
Craig Tiller06805272015-06-11 14:46:47 -0700191 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
murgatroid992c8d5162015-01-26 10:41:21 -0800192
murgatroid99256d3df2015-09-21 16:58:02 -0700193 def pre_build_steps(self):
194 return []
195
murgatroid992c8d5162015-01-26 10:41:21 -0800196 def make_targets(self):
murgatroid99db5b1602015-10-01 13:20:11 -0700197 return []
murgatroid992c8d5162015-01-26 10:41:21 -0800198
199 def build_steps(self):
200 return [['tools/run_tests/build_node.sh']]
Craig Tillerc7449162015-01-16 14:42:10 -0800201
murgatroid99a3e244f2015-09-22 11:25:53 -0700202 def makefile_name(self):
203 return 'Makefile'
204
murgatroid99132ce6a2015-03-04 17:29:14 -0800205 def supports_multi_config(self):
206 return False
207
208 def __str__(self):
209 return 'node'
210
Craig Tiller99775822015-01-30 13:07:16 -0800211
Craig Tillerc7449162015-01-16 14:42:10 -0800212class PhpLanguage(object):
213
Nicolas "Pixel" Noble9db7c3b2015-02-27 06:03:00 +0100214 def test_specs(self, config, travis):
Craig Tiller4fc90032015-05-21 10:39:52 -0700215 return [config.job_spec(['src/php/bin/run_tests.sh'], None,
Craig Tiller06805272015-06-11 14:46:47 -0700216 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
Craig Tillerc7449162015-01-16 14:42:10 -0800217
murgatroid99256d3df2015-09-21 16:58:02 -0700218 def pre_build_steps(self):
219 return []
220
Craig Tillerc7449162015-01-16 14:42:10 -0800221 def make_targets(self):
Craig Tilleraf7cf542015-05-22 10:07:34 -0700222 return ['static_c', 'shared_c']
Craig Tillerc7449162015-01-16 14:42:10 -0800223
224 def build_steps(self):
225 return [['tools/run_tests/build_php.sh']]
226
murgatroid99a3e244f2015-09-22 11:25:53 -0700227 def makefile_name(self):
228 return 'Makefile'
229
murgatroid99132ce6a2015-03-04 17:29:14 -0800230 def supports_multi_config(self):
231 return False
232
233 def __str__(self):
234 return 'php'
235
Craig Tillerc7449162015-01-16 14:42:10 -0800236
Nathaniel Manista840615e2015-01-22 20:31:47 +0000237class PythonLanguage(object):
238
Craig Tiller49f61322015-03-03 13:02:11 -0800239 def __init__(self):
Masood Malekghassemi2b841622015-07-28 17:39:02 -0700240 self._build_python_versions = ['2.7']
Masood Malekghassemie5f70022015-06-29 09:20:26 -0700241 self._has_python_versions = []
Craig Tiller49f61322015-03-03 13:02:11 -0800242
Nicolas "Pixel" Noble9db7c3b2015-02-27 06:03:00 +0100243 def test_specs(self, config, travis):
Masood Malekghassemi2b841622015-07-28 17:39:02 -0700244 environment = dict(_FORCE_ENVIRON_FOR_WRAPPERS)
245 environment['PYVER'] = '2.7'
246 return [config.job_spec(
247 ['tools/run_tests/run_python.sh'],
248 None,
249 environ=environment,
250 shortname='py.test',
251 )]
Nathaniel Manista840615e2015-01-22 20:31:47 +0000252
murgatroid99256d3df2015-09-21 16:58:02 -0700253 def pre_build_steps(self):
254 return []
255
Nathaniel Manista840615e2015-01-22 20:31:47 +0000256 def make_targets(self):
Craig Tilleraf7cf542015-05-22 10:07:34 -0700257 return ['static_c', 'grpc_python_plugin', 'shared_c']
Nathaniel Manista840615e2015-01-22 20:31:47 +0000258
259 def build_steps(self):
Masood Malekghassemie5f70022015-06-29 09:20:26 -0700260 commands = []
261 for python_version in self._build_python_versions:
262 try:
263 with open(os.devnull, 'w') as output:
264 subprocess.check_call(['which', 'python' + python_version],
265 stdout=output, stderr=output)
266 commands.append(['tools/run_tests/build_python.sh', python_version])
267 self._has_python_versions.append(python_version)
268 except:
269 jobset.message('WARNING', 'Missing Python ' + python_version,
270 do_newline=True)
271 return commands
Nathaniel Manista840615e2015-01-22 20:31:47 +0000272
murgatroid99a3e244f2015-09-22 11:25:53 -0700273 def makefile_name(self):
274 return 'Makefile'
275
murgatroid99132ce6a2015-03-04 17:29:14 -0800276 def supports_multi_config(self):
277 return False
278
279 def __str__(self):
280 return 'python'
281
Craig Tillerd625d812015-04-08 15:52:35 -0700282
murgatroid996a4c4fa2015-02-27 12:08:57 -0800283class RubyLanguage(object):
284
285 def test_specs(self, config, travis):
Craig Tiller4fc90032015-05-21 10:39:52 -0700286 return [config.job_spec(['tools/run_tests/run_ruby.sh'], None,
Craig Tiller06805272015-06-11 14:46:47 -0700287 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
murgatroid996a4c4fa2015-02-27 12:08:57 -0800288
murgatroid99256d3df2015-09-21 16:58:02 -0700289 def pre_build_steps(self):
290 return []
291
murgatroid996a4c4fa2015-02-27 12:08:57 -0800292 def make_targets(self):
murgatroid99a43c14f2015-07-30 13:31:23 -0700293 return ['static_c']
murgatroid996a4c4fa2015-02-27 12:08:57 -0800294
295 def build_steps(self):
296 return [['tools/run_tests/build_ruby.sh']]
297
murgatroid99a3e244f2015-09-22 11:25:53 -0700298 def makefile_name(self):
299 return 'Makefile'
300
murgatroid99132ce6a2015-03-04 17:29:14 -0800301 def supports_multi_config(self):
302 return False
303
304 def __str__(self):
305 return 'ruby'
306
Craig Tillerd625d812015-04-08 15:52:35 -0700307
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800308class CSharpLanguage(object):
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700309 def __init__(self):
Craig Tillerd50993d2015-08-05 08:04:36 -0700310 self.platform = platform_string()
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700311
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800312 def test_specs(self, config, travis):
Jan Tattermusch9a7d30c2015-04-23 16:12:55 -0700313 assemblies = ['Grpc.Core.Tests',
314 'Grpc.Examples.Tests',
Jan Tattermusch9d67d8d2015-08-01 20:39:16 -0700315 'Grpc.HealthCheck.Tests',
Jan Tattermusch9a7d30c2015-04-23 16:12:55 -0700316 'Grpc.IntegrationTesting']
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700317 if self.platform == 'windows':
318 cmd = 'tools\\run_tests\\run_csharp.bat'
319 else:
320 cmd = 'tools/run_tests/run_csharp.sh'
321 return [config.job_spec([cmd, assembly],
Craig Tiller4fc90032015-05-21 10:39:52 -0700322 None, shortname=assembly,
Craig Tiller06805272015-06-11 14:46:47 -0700323 environ=_FORCE_ENVIRON_FOR_WRAPPERS)
Craig Tillerd50993d2015-08-05 08:04:36 -0700324 for assembly in assemblies]
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800325
murgatroid99256d3df2015-09-21 16:58:02 -0700326 def pre_build_steps(self):
Jan Tattermusch48423fc2015-10-07 18:59:16 -0700327 if self.platform == 'windows':
Jan Tattermusch874aec02015-10-07 19:26:19 -0700328 return [['tools\\run_tests\\pre_build_csharp.bat']]
Jan Tattermusch48423fc2015-10-07 18:59:16 -0700329 else:
330 return [['tools/run_tests/pre_build_csharp.sh']]
murgatroid99256d3df2015-09-21 16:58:02 -0700331
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800332 def make_targets(self):
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700333 # For Windows, this target doesn't really build anything,
334 # everything is build by buildall script later.
Craig Tillerd5904822015-08-31 21:30:58 -0700335 if self.platform == 'windows':
336 return []
337 else:
338 return ['grpc_csharp_ext']
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800339
340 def build_steps(self):
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700341 if self.platform == 'windows':
342 return [['src\\csharp\\buildall.bat']]
343 else:
344 return [['tools/run_tests/build_csharp.sh']]
Nathaniel Manista840615e2015-01-22 20:31:47 +0000345
murgatroid99a3e244f2015-09-22 11:25:53 -0700346 def makefile_name(self):
347 return 'Makefile'
348
murgatroid99132ce6a2015-03-04 17:29:14 -0800349 def supports_multi_config(self):
350 return False
351
352 def __str__(self):
353 return 'csharp'
354
Craig Tillerd625d812015-04-08 15:52:35 -0700355
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700356class ObjCLanguage(object):
357
358 def test_specs(self, config, travis):
359 return [config.job_spec(['src/objective-c/tests/run_tests.sh'], None,
360 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
361
murgatroid99256d3df2015-09-21 16:58:02 -0700362 def pre_build_steps(self):
363 return []
364
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700365 def make_targets(self):
Jorge Canizalesd0b32e92015-07-30 23:08:43 -0700366 return ['grpc_objective_c_plugin', 'interop_server']
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700367
368 def build_steps(self):
Jorge Canizalesd0b32e92015-07-30 23:08:43 -0700369 return [['src/objective-c/tests/build_tests.sh']]
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700370
murgatroid99a3e244f2015-09-22 11:25:53 -0700371 def makefile_name(self):
372 return 'Makefile'
373
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700374 def supports_multi_config(self):
375 return False
376
377 def __str__(self):
378 return 'objc'
379
380
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100381class Sanity(object):
382
383 def test_specs(self, config, travis):
Craig Tillerf75fc122015-06-25 06:58:00 -0700384 return [config.job_spec('tools/run_tests/run_sanity.sh', None),
385 config.job_spec('tools/run_tests/check_sources_and_headers.py', None)]
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100386
murgatroid99256d3df2015-09-21 16:58:02 -0700387 def pre_build_steps(self):
388 return []
389
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100390 def make_targets(self):
391 return ['run_dep_checks']
392
393 def build_steps(self):
394 return []
395
murgatroid99a3e244f2015-09-22 11:25:53 -0700396 def makefile_name(self):
397 return 'Makefile'
398
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100399 def supports_multi_config(self):
400 return False
401
402 def __str__(self):
403 return 'sanity'
404
Nicolas "Pixel" Noblee55cd7f2015-04-14 17:59:13 +0200405
Nicolas "Pixel" Noblefd2b0932015-03-26 00:26:29 +0100406class Build(object):
407
408 def test_specs(self, config, travis):
409 return []
410
murgatroid99256d3df2015-09-21 16:58:02 -0700411 def pre_build_steps(self):
412 return []
413
Nicolas "Pixel" Noblefd2b0932015-03-26 00:26:29 +0100414 def make_targets(self):
Nicolas "Pixel" Noblec23827b2015-04-23 06:17:55 +0200415 return ['static']
Nicolas "Pixel" Noblefd2b0932015-03-26 00:26:29 +0100416
417 def build_steps(self):
418 return []
419
murgatroid99a3e244f2015-09-22 11:25:53 -0700420 def makefile_name(self):
421 return 'Makefile'
422
Nicolas "Pixel" Noblefd2b0932015-03-26 00:26:29 +0100423 def supports_multi_config(self):
424 return True
425
426 def __str__(self):
427 return self.make_target
428
429
Craig Tiller738c3342015-01-12 14:28:33 -0800430# different configurations we can run under
431_CONFIGS = {
Craig Tillerb50d1662015-01-15 17:28:21 -0800432 'dbg': SimpleConfig('dbg'),
433 'opt': SimpleConfig('opt'),
Craig Tillerb2ea0b92015-08-26 13:06:53 -0700434 'tsan': SimpleConfig('tsan', timeout_seconds=10*60, environ={
Craig Tiller1ada6ad2015-07-16 16:19:14 -0700435 'TSAN_OPTIONS': 'suppressions=tools/tsan_suppressions.txt:halt_on_error=1:second_deadlock_stack=1'}),
Craig Tiller4a71ce22015-08-26 15:47:55 -0700436 'msan': SimpleConfig('msan', timeout_seconds=7*60),
Craig Tiller96bd5f62015-02-13 09:04:13 -0800437 'ubsan': SimpleConfig('ubsan'),
Craig Tillerb2ea0b92015-08-26 13:06:53 -0700438 'asan': SimpleConfig('asan', timeout_seconds=7*60, environ={
Craig Tillerd4b13622015-05-29 09:10:10 -0700439 'ASAN_OPTIONS': 'detect_leaks=1:color=always:suppressions=tools/tsan_suppressions.txt',
440 'LSAN_OPTIONS': 'report_objects=1'}),
Craig Tiller810725c2015-05-12 09:44:41 -0700441 'asan-noleaks': SimpleConfig('asan', environ={
442 'ASAN_OPTIONS': 'detect_leaks=0:color=always:suppressions=tools/tsan_suppressions.txt'}),
Craig Tillerb50d1662015-01-15 17:28:21 -0800443 'gcov': SimpleConfig('gcov'),
Craig Tiller1a305b12015-02-18 13:37:06 -0800444 'memcheck': ValgrindConfig('valgrind', 'memcheck', ['--leak-check=full']),
Craig Tillerb50d1662015-01-15 17:28:21 -0800445 'helgrind': ValgrindConfig('dbg', 'helgrind')
446 }
Craig Tiller738c3342015-01-12 14:28:33 -0800447
448
Nicolas "Pixel" Noble1fb5e822015-03-16 06:20:37 +0100449_DEFAULT = ['opt']
Craig Tillerc7449162015-01-16 14:42:10 -0800450_LANGUAGES = {
Craig Tillere9c959d2015-01-18 10:23:26 -0800451 'c++': CLanguage('cxx', 'c++'),
452 'c': CLanguage('c', 'c'),
murgatroid992c8d5162015-01-26 10:41:21 -0800453 'node': NodeLanguage(),
Nathaniel Manista840615e2015-01-22 20:31:47 +0000454 'php': PhpLanguage(),
455 'python': PythonLanguage(),
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800456 'ruby': RubyLanguage(),
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100457 'csharp': CSharpLanguage(),
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700458 'objc' : ObjCLanguage(),
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100459 'sanity': Sanity(),
Nicolas "Pixel" Noblefd2b0932015-03-26 00:26:29 +0100460 'build': Build(),
Craig Tillereb272bc2015-01-30 13:13:14 -0800461 }
Nicolas Nobleddef2462015-01-06 18:08:25 -0800462
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700463_WINDOWS_CONFIG = {
464 'dbg': 'Debug',
465 'opt': 'Release',
466 }
467
David Garcia Quintase90cd372015-05-31 18:15:26 -0700468
469def runs_per_test_type(arg_str):
470 """Auxilary function to parse the "runs_per_test" flag.
471
472 Returns:
473 A positive integer or 0, the latter indicating an infinite number of
474 runs.
475
476 Raises:
477 argparse.ArgumentTypeError: Upon invalid input.
478 """
479 if arg_str == 'inf':
480 return 0
481 try:
482 n = int(arg_str)
483 if n <= 0: raise ValueError
Craig Tiller50e53e22015-06-01 20:18:21 -0700484 return n
David Garcia Quintase90cd372015-05-31 18:15:26 -0700485 except:
486 msg = "'{}' isn't a positive integer or 'inf'".format(arg_str)
487 raise argparse.ArgumentTypeError(msg)
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700488
489# parse command line
490argp = argparse.ArgumentParser(description='Run grpc tests.')
491argp.add_argument('-c', '--config',
492 choices=['all'] + sorted(_CONFIGS.keys()),
493 nargs='+',
494 default=_DEFAULT)
David Garcia Quintase90cd372015-05-31 18:15:26 -0700495argp.add_argument('-n', '--runs_per_test', default=1, type=runs_per_test_type,
496 help='A positive integer or "inf". If "inf", all tests will run in an '
497 'infinite loop. Especially useful in combination with "-f"')
Craig Tillerfe406ec2015-02-24 13:55:12 -0800498argp.add_argument('-r', '--regex', default='.*', type=str)
Craig Tiller83762ac2015-05-22 14:04:06 -0700499argp.add_argument('-j', '--jobs', default=2 * multiprocessing.cpu_count(), type=int)
Craig Tiller8451e872015-02-27 09:25:51 -0800500argp.add_argument('-s', '--slowdown', default=1.0, type=float)
ctiller3040cb72015-01-07 12:13:17 -0800501argp.add_argument('-f', '--forever',
502 default=False,
503 action='store_const',
504 const=True)
Nicolas "Pixel" Noblea7df3f92015-02-26 22:07:04 +0100505argp.add_argument('-t', '--travis',
506 default=False,
507 action='store_const',
508 const=True)
Nicolas Noble044db742015-01-14 16:57:24 -0800509argp.add_argument('--newline_on_success',
510 default=False,
511 action='store_const',
512 const=True)
Craig Tiller686fb262015-01-15 07:39:09 -0800513argp.add_argument('-l', '--language',
Craig Tiller60f15e62015-05-13 09:05:17 -0700514 choices=['all'] + sorted(_LANGUAGES.keys()),
Craig Tiller686fb262015-01-15 07:39:09 -0800515 nargs='+',
Craig Tiller60f15e62015-05-13 09:05:17 -0700516 default=['all'])
Craig Tillercd43da82015-05-29 08:41:29 -0700517argp.add_argument('-S', '--stop_on_failure',
518 default=False,
519 action='store_const',
520 const=True)
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700521argp.add_argument('--use_docker',
522 default=False,
523 action='store_const',
524 const=True,
525 help="Run all the tests under docker. That provides " +
Jan Tattermusch8266c672015-09-17 09:18:03 -0700526 "additional isolation and prevents the need to install " +
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700527 "language specific prerequisites. Only available on Linux.")
Craig Tillerd4509a12015-09-28 09:18:40 -0700528argp.add_argument('--allow_flakes',
529 default=False,
530 action='store_const',
531 const=True,
532 help="Allow flaky tests to show as passing (re-runs failed tests up to five times)")
Craig Tiller234b6e72015-05-23 10:12:40 -0700533argp.add_argument('-a', '--antagonists', default=0, type=int)
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +0200534argp.add_argument('-x', '--xml_report', default=None, type=str,
535 help='Generates a JUnit-compatible XML report')
Nicolas Nobleddef2462015-01-06 18:08:25 -0800536args = argp.parse_args()
537
Jan Tattermuschc96b9eb2015-09-18 16:01:21 -0700538if args.use_docker:
539 if not args.travis:
540 print 'Seen --use_docker flag, will run tests under docker.'
541 print
542 print 'IMPORTANT: The changes you are testing need to be locally committed'
543 print 'because only the committed changes in the current branch will be'
544 print 'copied to the docker environment.'
545 time.sleep(5)
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700546
547 child_argv = [ arg for arg in sys.argv if not arg == '--use_docker' ]
548 run_tests_cmd = 'tools/run_tests/run_tests.py %s' % " ".join(child_argv[1:])
549
550 # TODO(jtattermusch): revisit if we need special handling for arch here
551 # set arch command prefix in case we are working with different arch.
552 arch_env = os.getenv('arch')
553 if arch_env:
554 run_test_cmd = 'arch %s %s' % (arch_env, run_test_cmd)
555
556 env = os.environ.copy()
557 env['RUN_TESTS_COMMAND'] = run_tests_cmd
558 if args.xml_report:
559 env['XML_REPORT'] = args.xml_report
Jan Tattermusch261b58c2015-09-18 17:15:48 -0700560 if not args.travis:
561 env['TTY_FLAG'] = '-t' # enables Ctrl-C when not on Jenkins.
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700562
563 subprocess.check_call(['tools/jenkins/build_docker_and_run_tests.sh'],
564 shell=True,
565 env=env)
566 sys.exit(0)
567
Nicolas Nobleddef2462015-01-06 18:08:25 -0800568# grab config
Craig Tiller738c3342015-01-12 14:28:33 -0800569run_configs = set(_CONFIGS[cfg]
570 for cfg in itertools.chain.from_iterable(
571 _CONFIGS.iterkeys() if x == 'all' else [x]
572 for x in args.config))
573build_configs = set(cfg.build_config for cfg in run_configs)
Craig Tillerf1973b02015-01-16 12:32:13 -0800574
Craig Tiller06805272015-06-11 14:46:47 -0700575if args.travis:
576 _FORCE_ENVIRON_FOR_WRAPPERS = {'GRPC_TRACE': 'surface,batch'}
577
Craig Tiller60f15e62015-05-13 09:05:17 -0700578languages = set(_LANGUAGES[l]
579 for l in itertools.chain.from_iterable(
580 _LANGUAGES.iterkeys() if x == 'all' else [x]
581 for x in args.language))
murgatroid99132ce6a2015-03-04 17:29:14 -0800582
583if len(build_configs) > 1:
584 for language in languages:
585 if not language.supports_multi_config():
586 print language, 'does not support multiple build configurations'
587 sys.exit(1)
588
Craig Tiller5058c692015-04-08 09:42:04 -0700589if platform.system() == 'Windows':
murgatroid99a3e244f2015-09-22 11:25:53 -0700590 def make_jobspec(cfg, targets, makefile='Makefile'):
Craig Tillerfc3c0c42015-09-01 16:47:54 -0700591 extra_args = []
Craig Tillerb5391e12015-09-03 14:35:18 -0700592 # better do parallel compilation
Jan Tattermusch47eeb2b2015-10-07 14:09:18 -0700593 # empirically /m:2 gives the best performance/price and should prevent
594 # overloading the windows workers.
595 extra_args.extend(["/m:2"])
Craig Tillerb5391e12015-09-03 14:35:18 -0700596 # disable PDB generation: it's broken, and we don't need it during CI
Craig Tiller3ef8c082015-09-04 15:17:12 -0700597 extra_args.extend(["/p:Jenkins=true"])
Craig Tiller6fd23842015-09-01 07:36:31 -0700598 return [
murgatroid99cf08daf2015-09-21 15:33:16 -0700599 jobset.JobSpec(['vsprojects\\build.bat',
600 'vsprojects\\%s.sln' % target,
Craig Tillerfc3c0c42015-09-01 16:47:54 -0700601 '/p:Configuration=%s' % _WINDOWS_CONFIG[cfg]] +
602 extra_args,
Craig Tillerdfc3eee2015-09-01 16:32:16 -0700603 shell=True, timeout_seconds=90*60)
Craig Tiller6fd23842015-09-01 07:36:31 -0700604 for target in targets]
Craig Tiller5058c692015-04-08 09:42:04 -0700605else:
murgatroid99a3e244f2015-09-22 11:25:53 -0700606 def make_jobspec(cfg, targets, makefile='Makefile'):
Craig Tiller6fd23842015-09-01 07:36:31 -0700607 return [jobset.JobSpec([os.getenv('MAKE', 'make'),
murgatroid99a3e244f2015-09-22 11:25:53 -0700608 '-f', makefile,
Craig Tiller6fd23842015-09-01 07:36:31 -0700609 '-j', '%d' % (multiprocessing.cpu_count() + 1),
610 'EXTRA_DEFINES=GRPC_TEST_SLOWDOWN_MACHINE_FACTOR=%f' %
611 args.slowdown,
612 'CONFIG=%s' % cfg] + targets,
613 timeout_seconds=30*60)]
murgatroid99a3e244f2015-09-22 11:25:53 -0700614make_targets = {}
615for l in languages:
616 makefile = l.makefile_name()
617 make_targets[makefile] = make_targets.get(makefile, set()).union(
618 set(l.make_targets()))
Craig Tiller5058c692015-04-08 09:42:04 -0700619
murgatroid99fddac962015-09-22 09:20:11 -0700620build_steps = list(set(
murgatroid99256d3df2015-09-21 16:58:02 -0700621 jobset.JobSpec(cmdline, environ={'CONFIG': cfg})
622 for cfg in build_configs
623 for l in languages
624 for cmdline in l.pre_build_steps()))
Craig Tillerbd4e3782015-09-01 06:48:55 -0700625if make_targets:
murgatroid99a3e244f2015-09-22 11:25:53 -0700626 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 -0700627 build_steps.extend(set(make_commands))
Craig Tiller5058c692015-04-08 09:42:04 -0700628build_steps.extend(set(
Jan Tattermusch21897192015-10-07 15:42:21 -0700629 jobset.JobSpec(cmdline, environ={'CONFIG': cfg}, timeout_seconds=10*60)
murgatroid99132ce6a2015-03-04 17:29:14 -0800630 for cfg in build_configs
Craig Tiller547db2b2015-01-30 14:08:39 -0800631 for l in languages
Craig Tiller533b1a22015-05-29 08:41:29 -0700632 for cmdline in l.build_steps()))
Craig Tillerf1973b02015-01-16 12:32:13 -0800633
Nicolas Nobleddef2462015-01-06 18:08:25 -0800634runs_per_test = args.runs_per_test
ctiller3040cb72015-01-07 12:13:17 -0800635forever = args.forever
Nicolas Nobleddef2462015-01-06 18:08:25 -0800636
Nicolas Nobleddef2462015-01-06 18:08:25 -0800637
Craig Tiller71735182015-01-15 17:07:13 -0800638class TestCache(object):
Craig Tillerb50d1662015-01-15 17:28:21 -0800639 """Cache for running tests."""
640
David Klempner25739582015-02-11 15:57:32 -0800641 def __init__(self, use_cache_results):
Craig Tiller71735182015-01-15 17:07:13 -0800642 self._last_successful_run = {}
David Klempner25739582015-02-11 15:57:32 -0800643 self._use_cache_results = use_cache_results
Craig Tiller69cd2372015-06-11 09:38:09 -0700644 self._last_save = time.time()
Craig Tiller71735182015-01-15 17:07:13 -0800645
646 def should_run(self, cmdline, bin_hash):
Craig Tiller71735182015-01-15 17:07:13 -0800647 if cmdline not in self._last_successful_run:
648 return True
649 if self._last_successful_run[cmdline] != bin_hash:
650 return True
David Klempner25739582015-02-11 15:57:32 -0800651 if not self._use_cache_results:
652 return True
Craig Tiller71735182015-01-15 17:07:13 -0800653 return False
654
655 def finished(self, cmdline, bin_hash):
Craig Tiller547db2b2015-01-30 14:08:39 -0800656 self._last_successful_run[cmdline] = bin_hash
Craig Tiller69cd2372015-06-11 09:38:09 -0700657 if time.time() - self._last_save > 1:
658 self.save()
Craig Tiller71735182015-01-15 17:07:13 -0800659
660 def dump(self):
Craig Tillerb50d1662015-01-15 17:28:21 -0800661 return [{'cmdline': k, 'hash': v}
662 for k, v in self._last_successful_run.iteritems()]
Craig Tiller71735182015-01-15 17:07:13 -0800663
664 def parse(self, exdump):
665 self._last_successful_run = dict((o['cmdline'], o['hash']) for o in exdump)
666
667 def save(self):
668 with open('.run_tests_cache', 'w') as f:
Craig Tiller261dd982015-01-16 16:41:45 -0800669 f.write(json.dumps(self.dump()))
Craig Tiller69cd2372015-06-11 09:38:09 -0700670 self._last_save = time.time()
Craig Tiller71735182015-01-15 17:07:13 -0800671
Craig Tiller1cc11db2015-01-15 22:50:50 -0800672 def maybe_load(self):
673 if os.path.exists('.run_tests_cache'):
674 with open('.run_tests_cache') as f:
Craig Tiller261dd982015-01-16 16:41:45 -0800675 self.parse(json.loads(f.read()))
Craig Tiller71735182015-01-15 17:07:13 -0800676
677
Craig Tillerf53d9c82015-08-04 14:19:43 -0700678def _start_port_server(port_server_port):
679 # check if a compatible port server is running
680 # if incompatible (version mismatch) ==> start a new one
681 # if not running ==> start a new one
682 # otherwise, leave it up
683 try:
Craig Tillerfe4939f2015-10-06 12:55:36 -0700684 version = int(urllib2.urlopen(
685 'http://localhost:%d/version_number' % port_server_port,
686 timeout=1).read())
687 print 'detected port server running version %d' % version
Craig Tillerf53d9c82015-08-04 14:19:43 -0700688 running = True
Craig Tillerfe4939f2015-10-06 12:55:36 -0700689 except Exception as e:
Craig Tiller0d6499e2015-10-05 14:00:47 -0700690 print 'failed to detect port server: %s' % sys.exc_info()[0]
Craig Tillerfe4939f2015-10-06 12:55:36 -0700691 print e.strerror
Craig Tillerf53d9c82015-08-04 14:19:43 -0700692 running = False
693 if running:
Craig Tillerfe4939f2015-10-06 12:55:36 -0700694 current_version = int(subprocess.check_output(
695 [sys.executable, 'tools/run_tests/port_server.py', 'dump_version']))
696 print 'my port server is version %d' % current_version
697 running = (version >= current_version)
698 if not running:
699 print 'port_server version mismatch: killing the old one'
700 urllib2.urlopen('http://localhost:%d/quitquitquit' % port_server_port).read()
701 time.sleep(1)
Craig Tillerf53d9c82015-08-04 14:19:43 -0700702 if not running:
Craig Tiller0d6499e2015-10-05 14:00:47 -0700703 print 'starting port_server'
Craig Tillerf53d9c82015-08-04 14:19:43 -0700704 port_log = open('portlog.txt', 'w')
705 port_server = subprocess.Popen(
Craig Tiller1447ece2015-10-05 14:44:32 -0700706 [sys.executable, 'tools/run_tests/port_server.py', '-p', '%d' % port_server_port],
Craig Tillerf53d9c82015-08-04 14:19:43 -0700707 stderr=subprocess.STDOUT,
708 stdout=port_log)
Craig Tiller8b5f4dc2015-08-26 08:02:01 -0700709 # ensure port server is up
Craig Tillerabd37fd2015-08-26 07:54:01 -0700710 waits = 0
Craig Tillerf53d9c82015-08-04 14:19:43 -0700711 while True:
Craig Tillerabd37fd2015-08-26 07:54:01 -0700712 if waits > 10:
713 port_server.kill()
Craig Tillera2f38b02015-09-24 11:19:17 -0700714 if port_server.poll() is not None:
Craig Tiller0d6499e2015-10-05 14:00:47 -0700715 print 'port_server failed to start'
Craig Tillera2f38b02015-09-24 11:19:17 -0700716 port_log = open('portlog.txt', 'r').read()
717 print port_log
Craig Tillerabd37fd2015-08-26 07:54:01 -0700718 sys.exit(1)
Craig Tillerf53d9c82015-08-04 14:19:43 -0700719 try:
Craig Tillerabd37fd2015-08-26 07:54:01 -0700720 urllib2.urlopen('http://localhost:%d/get' % port_server_port,
721 timeout=1).read()
Craig Tillerf53d9c82015-08-04 14:19:43 -0700722 break
Craig Tiller31fdaa42015-09-25 13:09:59 -0700723 except socket.timeout:
Craig Tiller0d6499e2015-10-05 14:00:47 -0700724 print 'waiting for port_server: timeout'
Craig Tiller31fdaa42015-09-25 13:09:59 -0700725 time.sleep(0.5)
726 waits += 1
Craig Tillerf53d9c82015-08-04 14:19:43 -0700727 except urllib2.URLError:
Craig Tiller0d6499e2015-10-05 14:00:47 -0700728 print 'waiting for port_server: urlerror'
Craig Tillerf53d9c82015-08-04 14:19:43 -0700729 time.sleep(0.5)
Craig Tillerabd37fd2015-08-26 07:54:01 -0700730 waits += 1
Craig Tillerf53d9c82015-08-04 14:19:43 -0700731 except:
732 port_server.kill()
733 raise
734
735
736def _build_and_run(
737 check_cancelled, newline_on_success, travis, cache, xml_report=None):
ctiller3040cb72015-01-07 12:13:17 -0800738 """Do one pass of building & running tests."""
murgatroid99666450e2015-01-26 13:03:31 -0800739 # build latest sequentially
Nicolas "Pixel" Noblea7df3f92015-02-26 22:07:04 +0100740 if not jobset.run(build_steps, maxjobs=1,
741 newline_on_success=newline_on_success, travis=travis):
Craig Tillerd86a3942015-01-14 12:48:54 -0800742 return 1
ctiller3040cb72015-01-07 12:13:17 -0800743
Craig Tiller234b6e72015-05-23 10:12:40 -0700744 # start antagonists
David Garcia Quintas79e389f2015-06-02 17:49:42 -0700745 antagonists = [subprocess.Popen(['tools/run_tests/antagonist.py'])
Craig Tiller234b6e72015-05-23 10:12:40 -0700746 for _ in range(0, args.antagonists)]
Craig Tillerfe4939f2015-10-06 12:55:36 -0700747 port_server_port = 32767
Craig Tillerf53d9c82015-08-04 14:19:43 -0700748 _start_port_server(port_server_port)
Craig Tiller234b6e72015-05-23 10:12:40 -0700749 try:
David Garcia Quintase90cd372015-05-31 18:15:26 -0700750 infinite_runs = runs_per_test == 0
yang-g6c1fdc62015-08-18 11:57:42 -0700751 one_run = set(
752 spec
753 for config in run_configs
754 for language in languages
755 for spec in language.test_specs(config, args.travis)
756 if re.search(args.regex, spec.shortname))
David Garcia Quintas79e389f2015-06-02 17:49:42 -0700757 # When running on travis, we want out test runs to be as similar as possible
758 # for reproducibility purposes.
759 if travis:
760 massaged_one_run = sorted(one_run, key=lambda x: x.shortname)
761 else:
762 # whereas otherwise, we want to shuffle things up to give all tests a
763 # chance to run.
764 massaged_one_run = list(one_run) # random.shuffle needs an indexable seq.
765 random.shuffle(massaged_one_run) # which it modifies in-place.
Craig Tillerf7b7c892015-06-22 14:33:25 -0700766 if infinite_runs:
767 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 -0700768 runs_sequence = (itertools.repeat(massaged_one_run) if infinite_runs
769 else itertools.repeat(massaged_one_run, runs_per_test))
David Garcia Quintase90cd372015-05-31 18:15:26 -0700770 all_runs = itertools.chain.from_iterable(runs_sequence)
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +0200771
772 root = ET.Element('testsuites') if xml_report else None
773 testsuite = ET.SubElement(root, 'testsuite', id='1', package='grpc', name='tests') if xml_report else None
774
Craig Tiller234b6e72015-05-23 10:12:40 -0700775 if not jobset.run(all_runs, check_cancelled,
776 newline_on_success=newline_on_success, travis=travis,
David Garcia Quintase90cd372015-05-31 18:15:26 -0700777 infinite_runs=infinite_runs,
Craig Tillerda2220a2015-05-27 07:50:53 -0700778 maxjobs=args.jobs,
Craig Tillercd43da82015-05-29 08:41:29 -0700779 stop_on_failure=args.stop_on_failure,
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +0200780 cache=cache if not xml_report else None,
Craig Tillerf53d9c82015-08-04 14:19:43 -0700781 xml_report=testsuite,
782 add_env={'GRPC_TEST_PORT_SERVER': 'localhost:%d' % port_server_port}):
Craig Tiller234b6e72015-05-23 10:12:40 -0700783 return 2
784 finally:
785 for antagonist in antagonists:
786 antagonist.kill()
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +0200787 if xml_report:
788 tree = ET.ElementTree(root)
789 tree.write(xml_report, encoding='UTF-8')
Craig Tillerd86a3942015-01-14 12:48:54 -0800790
Craig Tiller69cd2372015-06-11 09:38:09 -0700791 if cache: cache.save()
792
Craig Tillerd86a3942015-01-14 12:48:54 -0800793 return 0
ctiller3040cb72015-01-07 12:13:17 -0800794
795
David Klempner25739582015-02-11 15:57:32 -0800796test_cache = TestCache(runs_per_test == 1)
Craig Tiller547db2b2015-01-30 14:08:39 -0800797test_cache.maybe_load()
Craig Tiller71735182015-01-15 17:07:13 -0800798
ctiller3040cb72015-01-07 12:13:17 -0800799if forever:
Nicolas Noble044db742015-01-14 16:57:24 -0800800 success = True
ctiller3040cb72015-01-07 12:13:17 -0800801 while True:
Craig Tiller42bc87c2015-02-23 08:50:19 -0800802 dw = watch_dirs.DirWatcher(['src', 'include', 'test', 'examples'])
ctiller3040cb72015-01-07 12:13:17 -0800803 initial_time = dw.most_recent_change()
804 have_files_changed = lambda: dw.most_recent_change() != initial_time
Nicolas Noble044db742015-01-14 16:57:24 -0800805 previous_success = success
Craig Tiller71735182015-01-15 17:07:13 -0800806 success = _build_and_run(check_cancelled=have_files_changed,
Nicolas Nobleb09078f2015-01-14 18:06:05 -0800807 newline_on_success=False,
Craig Tiller9a5a9402015-04-16 10:39:50 -0700808 travis=args.travis,
Craig Tiller71735182015-01-15 17:07:13 -0800809 cache=test_cache) == 0
Nicolas Noble044db742015-01-14 16:57:24 -0800810 if not previous_success and success:
Nicolas Nobleb09078f2015-01-14 18:06:05 -0800811 jobset.message('SUCCESS',
812 'All tests are now passing properly',
813 do_newline=True)
Nicolas Noble044db742015-01-14 16:57:24 -0800814 jobset.message('IDLE', 'No change detected')
ctiller3040cb72015-01-07 12:13:17 -0800815 while not have_files_changed():
816 time.sleep(1)
817else:
Craig Tiller71735182015-01-15 17:07:13 -0800818 result = _build_and_run(check_cancelled=lambda: False,
819 newline_on_success=args.newline_on_success,
Nicolas "Pixel" Noblea7df3f92015-02-26 22:07:04 +0100820 travis=args.travis,
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +0200821 cache=test_cache,
822 xml_report=args.xml_report)
Nicolas Nobleb09078f2015-01-14 18:06:05 -0800823 if result == 0:
824 jobset.message('SUCCESS', 'All tests passed', do_newline=True)
825 else:
826 jobset.message('FAILED', 'Some tests failed', do_newline=True)
827 sys.exit(result)