blob: a05fbe806a8b0452a261b1419c11971b29b9bab8 [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
murgatroid99fafeeb32015-09-22 09:13:03 -0700184
murgatroid99cf08daf2015-09-21 15:33:16 -0700185def gyp_test_paths(travis, config=None):
186 binaries = get_c_tests(travis, 'c')
187 out = []
188 for target in binaries:
murgatroid99fddac962015-09-22 09:20:11 -0700189 if config is not None and config.build_config in target['exclude_configs']:
murgatroid99cf08daf2015-09-21 15:33:16 -0700190 continue
191 binary = 'out/Debug/%s' % target['name']
192 out.append(binary)
193 return sorted(out)
194
murgatroid99fafeeb32015-09-22 09:13:03 -0700195
murgatroid99cf08daf2015-09-21 15:33:16 -0700196class GYPCLanguage(object):
197
198 def test_specs(self, config, travis):
199 return [config.job_spec([binary], [binary])
200 for binary in gyp_test_paths(travis, config)]
201
murgatroid99256d3df2015-09-21 16:58:02 -0700202 def pre_build_steps(self):
murgatroid99a3e244f2015-09-22 11:25:53 -0700203 return [['gyp', '--depth=.', '--suffix=-gyp', 'grpc.gyp']]
murgatroid99256d3df2015-09-21 16:58:02 -0700204
murgatroid99cf08daf2015-09-21 15:33:16 -0700205 def make_targets(self):
Craig Tillerc1385d62015-09-24 08:52:00 -0700206 # HACK(ctiller): force fling_client and fling_server to be built, as fling_test
207 # needs these
208 return gyp_test_paths(False) + ['fling_client', 'fling_server']
murgatroid99cf08daf2015-09-21 15:33:16 -0700209
210 def build_steps(self):
211 return []
212
murgatroid99a3e244f2015-09-22 11:25:53 -0700213 def makefile_name(self):
214 return 'Makefile-gyp'
215
murgatroid99cf08daf2015-09-21 15:33:16 -0700216 def supports_multi_config(self):
217 return False
218
219 def __str__(self):
220 return 'gyp'
Craig Tiller99775822015-01-30 13:07:16 -0800221
murgatroid99fafeeb32015-09-22 09:13:03 -0700222
murgatroid992c8d5162015-01-26 10:41:21 -0800223class NodeLanguage(object):
224
Nicolas "Pixel" Noble9db7c3b2015-02-27 06:03:00 +0100225 def test_specs(self, config, travis):
Craig Tiller4fc90032015-05-21 10:39:52 -0700226 return [config.job_spec(['tools/run_tests/run_node.sh'], None,
Craig Tiller06805272015-06-11 14:46:47 -0700227 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
murgatroid992c8d5162015-01-26 10:41:21 -0800228
murgatroid99256d3df2015-09-21 16:58:02 -0700229 def pre_build_steps(self):
230 return []
231
murgatroid992c8d5162015-01-26 10:41:21 -0800232 def make_targets(self):
Craig Tilleraf7cf542015-05-22 10:07:34 -0700233 return ['static_c', 'shared_c']
murgatroid992c8d5162015-01-26 10:41:21 -0800234
235 def build_steps(self):
236 return [['tools/run_tests/build_node.sh']]
Craig Tillerc7449162015-01-16 14:42:10 -0800237
murgatroid99a3e244f2015-09-22 11:25:53 -0700238 def makefile_name(self):
239 return 'Makefile'
240
murgatroid99132ce6a2015-03-04 17:29:14 -0800241 def supports_multi_config(self):
242 return False
243
244 def __str__(self):
245 return 'node'
246
Craig Tiller99775822015-01-30 13:07:16 -0800247
Craig Tillerc7449162015-01-16 14:42:10 -0800248class PhpLanguage(object):
249
Nicolas "Pixel" Noble9db7c3b2015-02-27 06:03:00 +0100250 def test_specs(self, config, travis):
Craig Tiller4fc90032015-05-21 10:39:52 -0700251 return [config.job_spec(['src/php/bin/run_tests.sh'], None,
Craig Tiller06805272015-06-11 14:46:47 -0700252 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
Craig Tillerc7449162015-01-16 14:42:10 -0800253
murgatroid99256d3df2015-09-21 16:58:02 -0700254 def pre_build_steps(self):
255 return []
256
Craig Tillerc7449162015-01-16 14:42:10 -0800257 def make_targets(self):
Craig Tilleraf7cf542015-05-22 10:07:34 -0700258 return ['static_c', 'shared_c']
Craig Tillerc7449162015-01-16 14:42:10 -0800259
260 def build_steps(self):
261 return [['tools/run_tests/build_php.sh']]
262
murgatroid99a3e244f2015-09-22 11:25:53 -0700263 def makefile_name(self):
264 return 'Makefile'
265
murgatroid99132ce6a2015-03-04 17:29:14 -0800266 def supports_multi_config(self):
267 return False
268
269 def __str__(self):
270 return 'php'
271
Craig Tillerc7449162015-01-16 14:42:10 -0800272
Nathaniel Manista840615e2015-01-22 20:31:47 +0000273class PythonLanguage(object):
274
Craig Tiller49f61322015-03-03 13:02:11 -0800275 def __init__(self):
Masood Malekghassemi2b841622015-07-28 17:39:02 -0700276 self._build_python_versions = ['2.7']
Masood Malekghassemie5f70022015-06-29 09:20:26 -0700277 self._has_python_versions = []
Craig Tiller49f61322015-03-03 13:02:11 -0800278
Nicolas "Pixel" Noble9db7c3b2015-02-27 06:03:00 +0100279 def test_specs(self, config, travis):
Masood Malekghassemi2b841622015-07-28 17:39:02 -0700280 environment = dict(_FORCE_ENVIRON_FOR_WRAPPERS)
281 environment['PYVER'] = '2.7'
282 return [config.job_spec(
283 ['tools/run_tests/run_python.sh'],
284 None,
285 environ=environment,
286 shortname='py.test',
287 )]
Nathaniel Manista840615e2015-01-22 20:31:47 +0000288
murgatroid99256d3df2015-09-21 16:58:02 -0700289 def pre_build_steps(self):
290 return []
291
Nathaniel Manista840615e2015-01-22 20:31:47 +0000292 def make_targets(self):
Craig Tilleraf7cf542015-05-22 10:07:34 -0700293 return ['static_c', 'grpc_python_plugin', 'shared_c']
Nathaniel Manista840615e2015-01-22 20:31:47 +0000294
295 def build_steps(self):
Masood Malekghassemie5f70022015-06-29 09:20:26 -0700296 commands = []
297 for python_version in self._build_python_versions:
298 try:
299 with open(os.devnull, 'w') as output:
300 subprocess.check_call(['which', 'python' + python_version],
301 stdout=output, stderr=output)
302 commands.append(['tools/run_tests/build_python.sh', python_version])
303 self._has_python_versions.append(python_version)
304 except:
305 jobset.message('WARNING', 'Missing Python ' + python_version,
306 do_newline=True)
307 return commands
Nathaniel Manista840615e2015-01-22 20:31:47 +0000308
murgatroid99a3e244f2015-09-22 11:25:53 -0700309 def makefile_name(self):
310 return 'Makefile'
311
murgatroid99132ce6a2015-03-04 17:29:14 -0800312 def supports_multi_config(self):
313 return False
314
315 def __str__(self):
316 return 'python'
317
Craig Tillerd625d812015-04-08 15:52:35 -0700318
murgatroid996a4c4fa2015-02-27 12:08:57 -0800319class RubyLanguage(object):
320
321 def test_specs(self, config, travis):
Craig Tiller4fc90032015-05-21 10:39:52 -0700322 return [config.job_spec(['tools/run_tests/run_ruby.sh'], None,
Craig Tiller06805272015-06-11 14:46:47 -0700323 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
murgatroid996a4c4fa2015-02-27 12:08:57 -0800324
murgatroid99256d3df2015-09-21 16:58:02 -0700325 def pre_build_steps(self):
326 return []
327
murgatroid996a4c4fa2015-02-27 12:08:57 -0800328 def make_targets(self):
murgatroid99a43c14f2015-07-30 13:31:23 -0700329 return ['static_c']
murgatroid996a4c4fa2015-02-27 12:08:57 -0800330
331 def build_steps(self):
332 return [['tools/run_tests/build_ruby.sh']]
333
murgatroid99a3e244f2015-09-22 11:25:53 -0700334 def makefile_name(self):
335 return 'Makefile'
336
murgatroid99132ce6a2015-03-04 17:29:14 -0800337 def supports_multi_config(self):
338 return False
339
340 def __str__(self):
341 return 'ruby'
342
Craig Tillerd625d812015-04-08 15:52:35 -0700343
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800344class CSharpLanguage(object):
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700345 def __init__(self):
Craig Tillerd50993d2015-08-05 08:04:36 -0700346 self.platform = platform_string()
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700347
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800348 def test_specs(self, config, travis):
Jan Tattermusch9a7d30c2015-04-23 16:12:55 -0700349 assemblies = ['Grpc.Core.Tests',
350 'Grpc.Examples.Tests',
Jan Tattermusch9d67d8d2015-08-01 20:39:16 -0700351 'Grpc.HealthCheck.Tests',
Jan Tattermusch9a7d30c2015-04-23 16:12:55 -0700352 'Grpc.IntegrationTesting']
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700353 if self.platform == 'windows':
354 cmd = 'tools\\run_tests\\run_csharp.bat'
355 else:
356 cmd = 'tools/run_tests/run_csharp.sh'
357 return [config.job_spec([cmd, assembly],
Craig Tiller4fc90032015-05-21 10:39:52 -0700358 None, shortname=assembly,
Craig Tiller06805272015-06-11 14:46:47 -0700359 environ=_FORCE_ENVIRON_FOR_WRAPPERS)
Craig Tillerd50993d2015-08-05 08:04:36 -0700360 for assembly in assemblies]
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800361
murgatroid99256d3df2015-09-21 16:58:02 -0700362 def pre_build_steps(self):
363 return []
364
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800365 def make_targets(self):
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700366 # For Windows, this target doesn't really build anything,
367 # everything is build by buildall script later.
Craig Tillerd5904822015-08-31 21:30:58 -0700368 if self.platform == 'windows':
369 return []
370 else:
371 return ['grpc_csharp_ext']
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800372
373 def build_steps(self):
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700374 if self.platform == 'windows':
375 return [['src\\csharp\\buildall.bat']]
376 else:
377 return [['tools/run_tests/build_csharp.sh']]
Nathaniel Manista840615e2015-01-22 20:31:47 +0000378
murgatroid99a3e244f2015-09-22 11:25:53 -0700379 def makefile_name(self):
380 return 'Makefile'
381
murgatroid99132ce6a2015-03-04 17:29:14 -0800382 def supports_multi_config(self):
383 return False
384
385 def __str__(self):
386 return 'csharp'
387
Craig Tillerd625d812015-04-08 15:52:35 -0700388
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700389class ObjCLanguage(object):
390
391 def test_specs(self, config, travis):
392 return [config.job_spec(['src/objective-c/tests/run_tests.sh'], None,
393 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
394
murgatroid99256d3df2015-09-21 16:58:02 -0700395 def pre_build_steps(self):
396 return []
397
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700398 def make_targets(self):
Jorge Canizalesd0b32e92015-07-30 23:08:43 -0700399 return ['grpc_objective_c_plugin', 'interop_server']
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700400
401 def build_steps(self):
Jorge Canizalesd0b32e92015-07-30 23:08:43 -0700402 return [['src/objective-c/tests/build_tests.sh']]
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700403
murgatroid99a3e244f2015-09-22 11:25:53 -0700404 def makefile_name(self):
405 return 'Makefile'
406
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700407 def supports_multi_config(self):
408 return False
409
410 def __str__(self):
411 return 'objc'
412
413
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100414class Sanity(object):
415
416 def test_specs(self, config, travis):
Craig Tillerf75fc122015-06-25 06:58:00 -0700417 return [config.job_spec('tools/run_tests/run_sanity.sh', None),
418 config.job_spec('tools/run_tests/check_sources_and_headers.py', None)]
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100419
murgatroid99256d3df2015-09-21 16:58:02 -0700420 def pre_build_steps(self):
421 return []
422
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100423 def make_targets(self):
424 return ['run_dep_checks']
425
426 def build_steps(self):
427 return []
428
murgatroid99a3e244f2015-09-22 11:25:53 -0700429 def makefile_name(self):
430 return 'Makefile'
431
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100432 def supports_multi_config(self):
433 return False
434
435 def __str__(self):
436 return 'sanity'
437
Nicolas "Pixel" Noblee55cd7f2015-04-14 17:59:13 +0200438
Nicolas "Pixel" Noblefd2b0932015-03-26 00:26:29 +0100439class Build(object):
440
441 def test_specs(self, config, travis):
442 return []
443
murgatroid99256d3df2015-09-21 16:58:02 -0700444 def pre_build_steps(self):
445 return []
446
Nicolas "Pixel" Noblefd2b0932015-03-26 00:26:29 +0100447 def make_targets(self):
Nicolas "Pixel" Noblec23827b2015-04-23 06:17:55 +0200448 return ['static']
Nicolas "Pixel" Noblefd2b0932015-03-26 00:26:29 +0100449
450 def build_steps(self):
451 return []
452
murgatroid99a3e244f2015-09-22 11:25:53 -0700453 def makefile_name(self):
454 return 'Makefile'
455
Nicolas "Pixel" Noblefd2b0932015-03-26 00:26:29 +0100456 def supports_multi_config(self):
457 return True
458
459 def __str__(self):
460 return self.make_target
461
462
Craig Tiller738c3342015-01-12 14:28:33 -0800463# different configurations we can run under
464_CONFIGS = {
Craig Tillerb50d1662015-01-15 17:28:21 -0800465 'dbg': SimpleConfig('dbg'),
466 'opt': SimpleConfig('opt'),
Craig Tillerb2ea0b92015-08-26 13:06:53 -0700467 'tsan': SimpleConfig('tsan', timeout_seconds=10*60, environ={
Craig Tiller1ada6ad2015-07-16 16:19:14 -0700468 'TSAN_OPTIONS': 'suppressions=tools/tsan_suppressions.txt:halt_on_error=1:second_deadlock_stack=1'}),
Craig Tiller4a71ce22015-08-26 15:47:55 -0700469 'msan': SimpleConfig('msan', timeout_seconds=7*60),
Craig Tiller96bd5f62015-02-13 09:04:13 -0800470 'ubsan': SimpleConfig('ubsan'),
Craig Tillerb2ea0b92015-08-26 13:06:53 -0700471 'asan': SimpleConfig('asan', timeout_seconds=7*60, environ={
Craig Tillerd4b13622015-05-29 09:10:10 -0700472 'ASAN_OPTIONS': 'detect_leaks=1:color=always:suppressions=tools/tsan_suppressions.txt',
473 'LSAN_OPTIONS': 'report_objects=1'}),
Craig Tiller810725c2015-05-12 09:44:41 -0700474 'asan-noleaks': SimpleConfig('asan', environ={
475 'ASAN_OPTIONS': 'detect_leaks=0:color=always:suppressions=tools/tsan_suppressions.txt'}),
Craig Tillerb50d1662015-01-15 17:28:21 -0800476 'gcov': SimpleConfig('gcov'),
Craig Tiller1a305b12015-02-18 13:37:06 -0800477 'memcheck': ValgrindConfig('valgrind', 'memcheck', ['--leak-check=full']),
Craig Tillerb50d1662015-01-15 17:28:21 -0800478 'helgrind': ValgrindConfig('dbg', 'helgrind')
479 }
Craig Tiller738c3342015-01-12 14:28:33 -0800480
481
Nicolas "Pixel" Noble1fb5e822015-03-16 06:20:37 +0100482_DEFAULT = ['opt']
Craig Tillerc7449162015-01-16 14:42:10 -0800483_LANGUAGES = {
Craig Tillere9c959d2015-01-18 10:23:26 -0800484 'c++': CLanguage('cxx', 'c++'),
485 'c': CLanguage('c', 'c'),
murgatroid99cf08daf2015-09-21 15:33:16 -0700486 'gyp': GYPCLanguage(),
murgatroid992c8d5162015-01-26 10:41:21 -0800487 'node': NodeLanguage(),
Nathaniel Manista840615e2015-01-22 20:31:47 +0000488 'php': PhpLanguage(),
489 'python': PythonLanguage(),
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800490 'ruby': RubyLanguage(),
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100491 'csharp': CSharpLanguage(),
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700492 'objc' : ObjCLanguage(),
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100493 'sanity': Sanity(),
Nicolas "Pixel" Noblefd2b0932015-03-26 00:26:29 +0100494 'build': Build(),
Craig Tillereb272bc2015-01-30 13:13:14 -0800495 }
Nicolas Nobleddef2462015-01-06 18:08:25 -0800496
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700497_WINDOWS_CONFIG = {
498 'dbg': 'Debug',
499 'opt': 'Release',
500 }
501
David Garcia Quintase90cd372015-05-31 18:15:26 -0700502
503def runs_per_test_type(arg_str):
504 """Auxilary function to parse the "runs_per_test" flag.
505
506 Returns:
507 A positive integer or 0, the latter indicating an infinite number of
508 runs.
509
510 Raises:
511 argparse.ArgumentTypeError: Upon invalid input.
512 """
513 if arg_str == 'inf':
514 return 0
515 try:
516 n = int(arg_str)
517 if n <= 0: raise ValueError
Craig Tiller50e53e22015-06-01 20:18:21 -0700518 return n
David Garcia Quintase90cd372015-05-31 18:15:26 -0700519 except:
520 msg = "'{}' isn't a positive integer or 'inf'".format(arg_str)
521 raise argparse.ArgumentTypeError(msg)
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700522
523# parse command line
524argp = argparse.ArgumentParser(description='Run grpc tests.')
525argp.add_argument('-c', '--config',
526 choices=['all'] + sorted(_CONFIGS.keys()),
527 nargs='+',
528 default=_DEFAULT)
David Garcia Quintase90cd372015-05-31 18:15:26 -0700529argp.add_argument('-n', '--runs_per_test', default=1, type=runs_per_test_type,
530 help='A positive integer or "inf". If "inf", all tests will run in an '
531 'infinite loop. Especially useful in combination with "-f"')
Craig Tillerfe406ec2015-02-24 13:55:12 -0800532argp.add_argument('-r', '--regex', default='.*', type=str)
Craig Tiller83762ac2015-05-22 14:04:06 -0700533argp.add_argument('-j', '--jobs', default=2 * multiprocessing.cpu_count(), type=int)
Craig Tiller8451e872015-02-27 09:25:51 -0800534argp.add_argument('-s', '--slowdown', default=1.0, type=float)
ctiller3040cb72015-01-07 12:13:17 -0800535argp.add_argument('-f', '--forever',
536 default=False,
537 action='store_const',
538 const=True)
Nicolas "Pixel" Noblea7df3f92015-02-26 22:07:04 +0100539argp.add_argument('-t', '--travis',
540 default=False,
541 action='store_const',
542 const=True)
Nicolas Noble044db742015-01-14 16:57:24 -0800543argp.add_argument('--newline_on_success',
544 default=False,
545 action='store_const',
546 const=True)
Craig Tiller686fb262015-01-15 07:39:09 -0800547argp.add_argument('-l', '--language',
Craig Tiller60f15e62015-05-13 09:05:17 -0700548 choices=['all'] + sorted(_LANGUAGES.keys()),
Craig Tiller686fb262015-01-15 07:39:09 -0800549 nargs='+',
Craig Tiller60f15e62015-05-13 09:05:17 -0700550 default=['all'])
Craig Tillercd43da82015-05-29 08:41:29 -0700551argp.add_argument('-S', '--stop_on_failure',
552 default=False,
553 action='store_const',
554 const=True)
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700555argp.add_argument('--use_docker',
556 default=False,
557 action='store_const',
558 const=True,
559 help="Run all the tests under docker. That provides " +
Jan Tattermusch8266c672015-09-17 09:18:03 -0700560 "additional isolation and prevents the need to install " +
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700561 "language specific prerequisites. Only available on Linux.")
Craig Tillerd4509a12015-09-28 09:18:40 -0700562argp.add_argument('--allow_flakes',
563 default=False,
564 action='store_const',
565 const=True,
566 help="Allow flaky tests to show as passing (re-runs failed tests up to five times)")
Craig Tiller234b6e72015-05-23 10:12:40 -0700567argp.add_argument('-a', '--antagonists', default=0, type=int)
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +0200568argp.add_argument('-x', '--xml_report', default=None, type=str,
569 help='Generates a JUnit-compatible XML report')
Nicolas Nobleddef2462015-01-06 18:08:25 -0800570args = argp.parse_args()
571
Jan Tattermuschc96b9eb2015-09-18 16:01:21 -0700572if args.use_docker:
573 if not args.travis:
574 print 'Seen --use_docker flag, will run tests under docker.'
575 print
576 print 'IMPORTANT: The changes you are testing need to be locally committed'
577 print 'because only the committed changes in the current branch will be'
578 print 'copied to the docker environment.'
579 time.sleep(5)
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700580
581 child_argv = [ arg for arg in sys.argv if not arg == '--use_docker' ]
582 run_tests_cmd = 'tools/run_tests/run_tests.py %s' % " ".join(child_argv[1:])
583
584 # TODO(jtattermusch): revisit if we need special handling for arch here
585 # set arch command prefix in case we are working with different arch.
586 arch_env = os.getenv('arch')
587 if arch_env:
588 run_test_cmd = 'arch %s %s' % (arch_env, run_test_cmd)
589
590 env = os.environ.copy()
591 env['RUN_TESTS_COMMAND'] = run_tests_cmd
592 if args.xml_report:
593 env['XML_REPORT'] = args.xml_report
Jan Tattermusch261b58c2015-09-18 17:15:48 -0700594 if not args.travis:
595 env['TTY_FLAG'] = '-t' # enables Ctrl-C when not on Jenkins.
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700596
597 subprocess.check_call(['tools/jenkins/build_docker_and_run_tests.sh'],
598 shell=True,
599 env=env)
600 sys.exit(0)
601
Nicolas Nobleddef2462015-01-06 18:08:25 -0800602# grab config
Craig Tiller738c3342015-01-12 14:28:33 -0800603run_configs = set(_CONFIGS[cfg]
604 for cfg in itertools.chain.from_iterable(
605 _CONFIGS.iterkeys() if x == 'all' else [x]
606 for x in args.config))
607build_configs = set(cfg.build_config for cfg in run_configs)
Craig Tillerf1973b02015-01-16 12:32:13 -0800608
Craig Tiller06805272015-06-11 14:46:47 -0700609if args.travis:
610 _FORCE_ENVIRON_FOR_WRAPPERS = {'GRPC_TRACE': 'surface,batch'}
611
Craig Tiller60f15e62015-05-13 09:05:17 -0700612languages = set(_LANGUAGES[l]
613 for l in itertools.chain.from_iterable(
614 _LANGUAGES.iterkeys() if x == 'all' else [x]
615 for x in args.language))
murgatroid99132ce6a2015-03-04 17:29:14 -0800616
617if len(build_configs) > 1:
618 for language in languages:
619 if not language.supports_multi_config():
620 print language, 'does not support multiple build configurations'
621 sys.exit(1)
622
Craig Tiller5058c692015-04-08 09:42:04 -0700623if platform.system() == 'Windows':
murgatroid99a3e244f2015-09-22 11:25:53 -0700624 def make_jobspec(cfg, targets, makefile='Makefile'):
Craig Tillerfc3c0c42015-09-01 16:47:54 -0700625 extra_args = []
Craig Tillerb5391e12015-09-03 14:35:18 -0700626 # better do parallel compilation
Jan Tattermusch47eeb2b2015-10-07 14:09:18 -0700627 # empirically /m:2 gives the best performance/price and should prevent
628 # overloading the windows workers.
629 extra_args.extend(["/m:2"])
Craig Tillerb5391e12015-09-03 14:35:18 -0700630 # disable PDB generation: it's broken, and we don't need it during CI
Craig Tiller3ef8c082015-09-04 15:17:12 -0700631 extra_args.extend(["/p:Jenkins=true"])
Craig Tiller6fd23842015-09-01 07:36:31 -0700632 return [
murgatroid99cf08daf2015-09-21 15:33:16 -0700633 jobset.JobSpec(['vsprojects\\build.bat',
634 'vsprojects\\%s.sln' % target,
Craig Tillerfc3c0c42015-09-01 16:47:54 -0700635 '/p:Configuration=%s' % _WINDOWS_CONFIG[cfg]] +
636 extra_args,
Craig Tillerdfc3eee2015-09-01 16:32:16 -0700637 shell=True, timeout_seconds=90*60)
Craig Tiller6fd23842015-09-01 07:36:31 -0700638 for target in targets]
Craig Tiller5058c692015-04-08 09:42:04 -0700639else:
murgatroid99a3e244f2015-09-22 11:25:53 -0700640 def make_jobspec(cfg, targets, makefile='Makefile'):
Craig Tiller6fd23842015-09-01 07:36:31 -0700641 return [jobset.JobSpec([os.getenv('MAKE', 'make'),
murgatroid99a3e244f2015-09-22 11:25:53 -0700642 '-f', makefile,
Craig Tiller6fd23842015-09-01 07:36:31 -0700643 '-j', '%d' % (multiprocessing.cpu_count() + 1),
644 'EXTRA_DEFINES=GRPC_TEST_SLOWDOWN_MACHINE_FACTOR=%f' %
645 args.slowdown,
646 'CONFIG=%s' % cfg] + targets,
647 timeout_seconds=30*60)]
murgatroid99a3e244f2015-09-22 11:25:53 -0700648make_targets = {}
649for l in languages:
650 makefile = l.makefile_name()
651 make_targets[makefile] = make_targets.get(makefile, set()).union(
652 set(l.make_targets()))
Craig Tiller5058c692015-04-08 09:42:04 -0700653
murgatroid99fddac962015-09-22 09:20:11 -0700654build_steps = list(set(
murgatroid99256d3df2015-09-21 16:58:02 -0700655 jobset.JobSpec(cmdline, environ={'CONFIG': cfg})
656 for cfg in build_configs
657 for l in languages
658 for cmdline in l.pre_build_steps()))
Craig Tillerbd4e3782015-09-01 06:48:55 -0700659if make_targets:
murgatroid99a3e244f2015-09-22 11:25:53 -0700660 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 -0700661 build_steps.extend(set(make_commands))
Craig Tiller5058c692015-04-08 09:42:04 -0700662build_steps.extend(set(
murgatroid99132ce6a2015-03-04 17:29:14 -0800663 jobset.JobSpec(cmdline, environ={'CONFIG': cfg})
664 for cfg in build_configs
Craig Tiller547db2b2015-01-30 14:08:39 -0800665 for l in languages
Craig Tiller533b1a22015-05-29 08:41:29 -0700666 for cmdline in l.build_steps()))
Craig Tillerf1973b02015-01-16 12:32:13 -0800667
Nicolas Nobleddef2462015-01-06 18:08:25 -0800668runs_per_test = args.runs_per_test
ctiller3040cb72015-01-07 12:13:17 -0800669forever = args.forever
Nicolas Nobleddef2462015-01-06 18:08:25 -0800670
Nicolas Nobleddef2462015-01-06 18:08:25 -0800671
Craig Tiller71735182015-01-15 17:07:13 -0800672class TestCache(object):
Craig Tillerb50d1662015-01-15 17:28:21 -0800673 """Cache for running tests."""
674
David Klempner25739582015-02-11 15:57:32 -0800675 def __init__(self, use_cache_results):
Craig Tiller71735182015-01-15 17:07:13 -0800676 self._last_successful_run = {}
David Klempner25739582015-02-11 15:57:32 -0800677 self._use_cache_results = use_cache_results
Craig Tiller69cd2372015-06-11 09:38:09 -0700678 self._last_save = time.time()
Craig Tiller71735182015-01-15 17:07:13 -0800679
680 def should_run(self, cmdline, bin_hash):
Craig Tiller71735182015-01-15 17:07:13 -0800681 if cmdline not in self._last_successful_run:
682 return True
683 if self._last_successful_run[cmdline] != bin_hash:
684 return True
David Klempner25739582015-02-11 15:57:32 -0800685 if not self._use_cache_results:
686 return True
Craig Tiller71735182015-01-15 17:07:13 -0800687 return False
688
689 def finished(self, cmdline, bin_hash):
Craig Tiller547db2b2015-01-30 14:08:39 -0800690 self._last_successful_run[cmdline] = bin_hash
Craig Tiller69cd2372015-06-11 09:38:09 -0700691 if time.time() - self._last_save > 1:
692 self.save()
Craig Tiller71735182015-01-15 17:07:13 -0800693
694 def dump(self):
Craig Tillerb50d1662015-01-15 17:28:21 -0800695 return [{'cmdline': k, 'hash': v}
696 for k, v in self._last_successful_run.iteritems()]
Craig Tiller71735182015-01-15 17:07:13 -0800697
698 def parse(self, exdump):
699 self._last_successful_run = dict((o['cmdline'], o['hash']) for o in exdump)
700
701 def save(self):
702 with open('.run_tests_cache', 'w') as f:
Craig Tiller261dd982015-01-16 16:41:45 -0800703 f.write(json.dumps(self.dump()))
Craig Tiller69cd2372015-06-11 09:38:09 -0700704 self._last_save = time.time()
Craig Tiller71735182015-01-15 17:07:13 -0800705
Craig Tiller1cc11db2015-01-15 22:50:50 -0800706 def maybe_load(self):
707 if os.path.exists('.run_tests_cache'):
708 with open('.run_tests_cache') as f:
Craig Tiller261dd982015-01-16 16:41:45 -0800709 self.parse(json.loads(f.read()))
Craig Tiller71735182015-01-15 17:07:13 -0800710
711
Craig Tillerf53d9c82015-08-04 14:19:43 -0700712def _start_port_server(port_server_port):
713 # check if a compatible port server is running
714 # if incompatible (version mismatch) ==> start a new one
715 # if not running ==> start a new one
716 # otherwise, leave it up
717 try:
Craig Tillerfe4939f2015-10-06 12:55:36 -0700718 version = int(urllib2.urlopen(
719 'http://localhost:%d/version_number' % port_server_port,
720 timeout=1).read())
721 print 'detected port server running version %d' % version
Craig Tillerf53d9c82015-08-04 14:19:43 -0700722 running = True
Craig Tillerfe4939f2015-10-06 12:55:36 -0700723 except Exception as e:
Craig Tiller0d6499e2015-10-05 14:00:47 -0700724 print 'failed to detect port server: %s' % sys.exc_info()[0]
Craig Tillerfe4939f2015-10-06 12:55:36 -0700725 print e.strerror
Craig Tillerf53d9c82015-08-04 14:19:43 -0700726 running = False
727 if running:
Craig Tillerfe4939f2015-10-06 12:55:36 -0700728 current_version = int(subprocess.check_output(
729 [sys.executable, 'tools/run_tests/port_server.py', 'dump_version']))
730 print 'my port server is version %d' % current_version
731 running = (version >= current_version)
732 if not running:
733 print 'port_server version mismatch: killing the old one'
734 urllib2.urlopen('http://localhost:%d/quitquitquit' % port_server_port).read()
735 time.sleep(1)
Craig Tillerf53d9c82015-08-04 14:19:43 -0700736 if not running:
Craig Tiller0d6499e2015-10-05 14:00:47 -0700737 print 'starting port_server'
Craig Tillerf53d9c82015-08-04 14:19:43 -0700738 port_log = open('portlog.txt', 'w')
739 port_server = subprocess.Popen(
Craig Tiller1447ece2015-10-05 14:44:32 -0700740 [sys.executable, 'tools/run_tests/port_server.py', '-p', '%d' % port_server_port],
Craig Tillerf53d9c82015-08-04 14:19:43 -0700741 stderr=subprocess.STDOUT,
742 stdout=port_log)
Craig Tiller8b5f4dc2015-08-26 08:02:01 -0700743 # ensure port server is up
Craig Tillerabd37fd2015-08-26 07:54:01 -0700744 waits = 0
Craig Tillerf53d9c82015-08-04 14:19:43 -0700745 while True:
Craig Tillerabd37fd2015-08-26 07:54:01 -0700746 if waits > 10:
747 port_server.kill()
Craig Tillera2f38b02015-09-24 11:19:17 -0700748 if port_server.poll() is not None:
Craig Tiller0d6499e2015-10-05 14:00:47 -0700749 print 'port_server failed to start'
Craig Tillera2f38b02015-09-24 11:19:17 -0700750 port_log = open('portlog.txt', 'r').read()
751 print port_log
Craig Tillerabd37fd2015-08-26 07:54:01 -0700752 sys.exit(1)
Craig Tillerf53d9c82015-08-04 14:19:43 -0700753 try:
Craig Tillerabd37fd2015-08-26 07:54:01 -0700754 urllib2.urlopen('http://localhost:%d/get' % port_server_port,
755 timeout=1).read()
Craig Tillerf53d9c82015-08-04 14:19:43 -0700756 break
Craig Tiller31fdaa42015-09-25 13:09:59 -0700757 except socket.timeout:
Craig Tiller0d6499e2015-10-05 14:00:47 -0700758 print 'waiting for port_server: timeout'
Craig Tiller31fdaa42015-09-25 13:09:59 -0700759 time.sleep(0.5)
760 waits += 1
Craig Tillerf53d9c82015-08-04 14:19:43 -0700761 except urllib2.URLError:
Craig Tiller0d6499e2015-10-05 14:00:47 -0700762 print 'waiting for port_server: urlerror'
Craig Tillerf53d9c82015-08-04 14:19:43 -0700763 time.sleep(0.5)
Craig Tillerabd37fd2015-08-26 07:54:01 -0700764 waits += 1
Craig Tillerf53d9c82015-08-04 14:19:43 -0700765 except:
766 port_server.kill()
767 raise
768
769
770def _build_and_run(
771 check_cancelled, newline_on_success, travis, cache, xml_report=None):
ctiller3040cb72015-01-07 12:13:17 -0800772 """Do one pass of building & running tests."""
murgatroid99666450e2015-01-26 13:03:31 -0800773 # build latest sequentially
Nicolas "Pixel" Noblea7df3f92015-02-26 22:07:04 +0100774 if not jobset.run(build_steps, maxjobs=1,
775 newline_on_success=newline_on_success, travis=travis):
Craig Tillerd86a3942015-01-14 12:48:54 -0800776 return 1
ctiller3040cb72015-01-07 12:13:17 -0800777
Craig Tiller234b6e72015-05-23 10:12:40 -0700778 # start antagonists
David Garcia Quintas79e389f2015-06-02 17:49:42 -0700779 antagonists = [subprocess.Popen(['tools/run_tests/antagonist.py'])
Craig Tiller234b6e72015-05-23 10:12:40 -0700780 for _ in range(0, args.antagonists)]
Craig Tillerfe4939f2015-10-06 12:55:36 -0700781 port_server_port = 32767
Craig Tillerf53d9c82015-08-04 14:19:43 -0700782 _start_port_server(port_server_port)
Craig Tiller234b6e72015-05-23 10:12:40 -0700783 try:
David Garcia Quintase90cd372015-05-31 18:15:26 -0700784 infinite_runs = runs_per_test == 0
yang-g6c1fdc62015-08-18 11:57:42 -0700785 one_run = set(
786 spec
787 for config in run_configs
788 for language in languages
789 for spec in language.test_specs(config, args.travis)
790 if re.search(args.regex, spec.shortname))
David Garcia Quintas79e389f2015-06-02 17:49:42 -0700791 # When running on travis, we want out test runs to be as similar as possible
792 # for reproducibility purposes.
793 if travis:
794 massaged_one_run = sorted(one_run, key=lambda x: x.shortname)
795 else:
796 # whereas otherwise, we want to shuffle things up to give all tests a
797 # chance to run.
798 massaged_one_run = list(one_run) # random.shuffle needs an indexable seq.
799 random.shuffle(massaged_one_run) # which it modifies in-place.
Craig Tillerf7b7c892015-06-22 14:33:25 -0700800 if infinite_runs:
801 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 -0700802 runs_sequence = (itertools.repeat(massaged_one_run) if infinite_runs
803 else itertools.repeat(massaged_one_run, runs_per_test))
David Garcia Quintase90cd372015-05-31 18:15:26 -0700804 all_runs = itertools.chain.from_iterable(runs_sequence)
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +0200805
806 root = ET.Element('testsuites') if xml_report else None
807 testsuite = ET.SubElement(root, 'testsuite', id='1', package='grpc', name='tests') if xml_report else None
808
Craig Tiller234b6e72015-05-23 10:12:40 -0700809 if not jobset.run(all_runs, check_cancelled,
810 newline_on_success=newline_on_success, travis=travis,
David Garcia Quintase90cd372015-05-31 18:15:26 -0700811 infinite_runs=infinite_runs,
Craig Tillerda2220a2015-05-27 07:50:53 -0700812 maxjobs=args.jobs,
Craig Tillercd43da82015-05-29 08:41:29 -0700813 stop_on_failure=args.stop_on_failure,
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +0200814 cache=cache if not xml_report else None,
Craig Tillerf53d9c82015-08-04 14:19:43 -0700815 xml_report=testsuite,
816 add_env={'GRPC_TEST_PORT_SERVER': 'localhost:%d' % port_server_port}):
Craig Tiller234b6e72015-05-23 10:12:40 -0700817 return 2
818 finally:
819 for antagonist in antagonists:
820 antagonist.kill()
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +0200821 if xml_report:
822 tree = ET.ElementTree(root)
823 tree.write(xml_report, encoding='UTF-8')
Craig Tillerd86a3942015-01-14 12:48:54 -0800824
Craig Tiller69cd2372015-06-11 09:38:09 -0700825 if cache: cache.save()
826
Craig Tillerd86a3942015-01-14 12:48:54 -0800827 return 0
ctiller3040cb72015-01-07 12:13:17 -0800828
829
David Klempner25739582015-02-11 15:57:32 -0800830test_cache = TestCache(runs_per_test == 1)
Craig Tiller547db2b2015-01-30 14:08:39 -0800831test_cache.maybe_load()
Craig Tiller71735182015-01-15 17:07:13 -0800832
ctiller3040cb72015-01-07 12:13:17 -0800833if forever:
Nicolas Noble044db742015-01-14 16:57:24 -0800834 success = True
ctiller3040cb72015-01-07 12:13:17 -0800835 while True:
Craig Tiller42bc87c2015-02-23 08:50:19 -0800836 dw = watch_dirs.DirWatcher(['src', 'include', 'test', 'examples'])
ctiller3040cb72015-01-07 12:13:17 -0800837 initial_time = dw.most_recent_change()
838 have_files_changed = lambda: dw.most_recent_change() != initial_time
Nicolas Noble044db742015-01-14 16:57:24 -0800839 previous_success = success
Craig Tiller71735182015-01-15 17:07:13 -0800840 success = _build_and_run(check_cancelled=have_files_changed,
Nicolas Nobleb09078f2015-01-14 18:06:05 -0800841 newline_on_success=False,
Craig Tiller9a5a9402015-04-16 10:39:50 -0700842 travis=args.travis,
Craig Tiller71735182015-01-15 17:07:13 -0800843 cache=test_cache) == 0
Nicolas Noble044db742015-01-14 16:57:24 -0800844 if not previous_success and success:
Nicolas Nobleb09078f2015-01-14 18:06:05 -0800845 jobset.message('SUCCESS',
846 'All tests are now passing properly',
847 do_newline=True)
Nicolas Noble044db742015-01-14 16:57:24 -0800848 jobset.message('IDLE', 'No change detected')
ctiller3040cb72015-01-07 12:13:17 -0800849 while not have_files_changed():
850 time.sleep(1)
851else:
Craig Tiller71735182015-01-15 17:07:13 -0800852 result = _build_and_run(check_cancelled=lambda: False,
853 newline_on_success=args.newline_on_success,
Nicolas "Pixel" Noblea7df3f92015-02-26 22:07:04 +0100854 travis=args.travis,
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +0200855 cache=test_cache,
856 xml_report=args.xml_report)
Nicolas Nobleb09078f2015-01-14 18:06:05 -0800857 if result == 0:
858 jobset.message('SUCCESS', 'All tests passed', do_newline=True)
859 else:
860 jobset.message('FAILED', 'Some tests failed', do_newline=True)
861 sys.exit(result)