blob: 5120f6cb931b1e34d2167a59cc63e61931b45d8c [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
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200178 def post_tests_steps(self):
179 if self.platform == 'windows':
180 return []
181 else:
182 return [['tools/run_tests/post_tests_c.sh']]
183
murgatroid99a3e244f2015-09-22 11:25:53 -0700184 def makefile_name(self):
185 return 'Makefile'
186
murgatroid99132ce6a2015-03-04 17:29:14 -0800187 def supports_multi_config(self):
188 return True
189
190 def __str__(self):
191 return self.make_target
192
murgatroid992c8d5162015-01-26 10:41:21 -0800193class NodeLanguage(object):
194
Nicolas "Pixel" Noble9db7c3b2015-02-27 06:03:00 +0100195 def test_specs(self, config, travis):
Craig Tiller4fc90032015-05-21 10:39:52 -0700196 return [config.job_spec(['tools/run_tests/run_node.sh'], None,
Craig Tiller06805272015-06-11 14:46:47 -0700197 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
murgatroid992c8d5162015-01-26 10:41:21 -0800198
murgatroid99256d3df2015-09-21 16:58:02 -0700199 def pre_build_steps(self):
200 return []
201
murgatroid992c8d5162015-01-26 10:41:21 -0800202 def make_targets(self):
murgatroid99db5b1602015-10-01 13:20:11 -0700203 return []
murgatroid992c8d5162015-01-26 10:41:21 -0800204
205 def build_steps(self):
206 return [['tools/run_tests/build_node.sh']]
Craig Tillerc7449162015-01-16 14:42:10 -0800207
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200208 def post_tests_steps(self):
209 return []
210
murgatroid99a3e244f2015-09-22 11:25:53 -0700211 def makefile_name(self):
212 return 'Makefile'
213
murgatroid99132ce6a2015-03-04 17:29:14 -0800214 def supports_multi_config(self):
215 return False
216
217 def __str__(self):
218 return 'node'
219
Craig Tiller99775822015-01-30 13:07:16 -0800220
Craig Tillerc7449162015-01-16 14:42:10 -0800221class PhpLanguage(object):
222
Nicolas "Pixel" Noble9db7c3b2015-02-27 06:03:00 +0100223 def test_specs(self, config, travis):
Craig Tiller4fc90032015-05-21 10:39:52 -0700224 return [config.job_spec(['src/php/bin/run_tests.sh'], None,
Craig Tiller06805272015-06-11 14:46:47 -0700225 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
Craig Tillerc7449162015-01-16 14:42:10 -0800226
murgatroid99256d3df2015-09-21 16:58:02 -0700227 def pre_build_steps(self):
228 return []
229
Craig Tillerc7449162015-01-16 14:42:10 -0800230 def make_targets(self):
Craig Tilleraf7cf542015-05-22 10:07:34 -0700231 return ['static_c', 'shared_c']
Craig Tillerc7449162015-01-16 14:42:10 -0800232
233 def build_steps(self):
234 return [['tools/run_tests/build_php.sh']]
235
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200236 def post_tests_steps(self):
237 return []
238
murgatroid99a3e244f2015-09-22 11:25:53 -0700239 def makefile_name(self):
240 return 'Makefile'
241
murgatroid99132ce6a2015-03-04 17:29:14 -0800242 def supports_multi_config(self):
243 return False
244
245 def __str__(self):
246 return 'php'
247
Craig Tillerc7449162015-01-16 14:42:10 -0800248
Nathaniel Manista840615e2015-01-22 20:31:47 +0000249class PythonLanguage(object):
250
Craig Tiller49f61322015-03-03 13:02:11 -0800251 def __init__(self):
Masood Malekghassemi2b841622015-07-28 17:39:02 -0700252 self._build_python_versions = ['2.7']
Masood Malekghassemie5f70022015-06-29 09:20:26 -0700253 self._has_python_versions = []
Craig Tiller49f61322015-03-03 13:02:11 -0800254
Nicolas "Pixel" Noble9db7c3b2015-02-27 06:03:00 +0100255 def test_specs(self, config, travis):
Masood Malekghassemi2b841622015-07-28 17:39:02 -0700256 environment = dict(_FORCE_ENVIRON_FOR_WRAPPERS)
257 environment['PYVER'] = '2.7'
258 return [config.job_spec(
259 ['tools/run_tests/run_python.sh'],
260 None,
261 environ=environment,
262 shortname='py.test',
263 )]
Nathaniel Manista840615e2015-01-22 20:31:47 +0000264
murgatroid99256d3df2015-09-21 16:58:02 -0700265 def pre_build_steps(self):
266 return []
267
Nathaniel Manista840615e2015-01-22 20:31:47 +0000268 def make_targets(self):
Craig Tilleraf7cf542015-05-22 10:07:34 -0700269 return ['static_c', 'grpc_python_plugin', 'shared_c']
Nathaniel Manista840615e2015-01-22 20:31:47 +0000270
271 def build_steps(self):
Masood Malekghassemie5f70022015-06-29 09:20:26 -0700272 commands = []
273 for python_version in self._build_python_versions:
274 try:
275 with open(os.devnull, 'w') as output:
276 subprocess.check_call(['which', 'python' + python_version],
277 stdout=output, stderr=output)
278 commands.append(['tools/run_tests/build_python.sh', python_version])
279 self._has_python_versions.append(python_version)
280 except:
281 jobset.message('WARNING', 'Missing Python ' + python_version,
282 do_newline=True)
283 return commands
Nathaniel Manista840615e2015-01-22 20:31:47 +0000284
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200285 def post_tests_steps(self):
286 return []
287
murgatroid99a3e244f2015-09-22 11:25:53 -0700288 def makefile_name(self):
289 return 'Makefile'
290
murgatroid99132ce6a2015-03-04 17:29:14 -0800291 def supports_multi_config(self):
292 return False
293
294 def __str__(self):
295 return 'python'
296
Craig Tillerd625d812015-04-08 15:52:35 -0700297
murgatroid996a4c4fa2015-02-27 12:08:57 -0800298class RubyLanguage(object):
299
300 def test_specs(self, config, travis):
Craig Tiller4fc90032015-05-21 10:39:52 -0700301 return [config.job_spec(['tools/run_tests/run_ruby.sh'], None,
Craig Tiller06805272015-06-11 14:46:47 -0700302 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
murgatroid996a4c4fa2015-02-27 12:08:57 -0800303
murgatroid99256d3df2015-09-21 16:58:02 -0700304 def pre_build_steps(self):
Nicolas "Pixel" Noblebcf988f2015-10-08 03:00:42 +0200305 return [['tools/run_tests/pre_build_ruby.sh']]
murgatroid99256d3df2015-09-21 16:58:02 -0700306
murgatroid996a4c4fa2015-02-27 12:08:57 -0800307 def make_targets(self):
murgatroid99a43c14f2015-07-30 13:31:23 -0700308 return ['static_c']
murgatroid996a4c4fa2015-02-27 12:08:57 -0800309
310 def build_steps(self):
311 return [['tools/run_tests/build_ruby.sh']]
312
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200313 def post_tests_steps(self):
314 return []
315
murgatroid99a3e244f2015-09-22 11:25:53 -0700316 def makefile_name(self):
317 return 'Makefile'
318
murgatroid99132ce6a2015-03-04 17:29:14 -0800319 def supports_multi_config(self):
320 return False
321
322 def __str__(self):
323 return 'ruby'
324
Craig Tillerd625d812015-04-08 15:52:35 -0700325
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800326class CSharpLanguage(object):
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700327 def __init__(self):
Craig Tillerd50993d2015-08-05 08:04:36 -0700328 self.platform = platform_string()
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700329
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800330 def test_specs(self, config, travis):
Jan Tattermusch9a7d30c2015-04-23 16:12:55 -0700331 assemblies = ['Grpc.Core.Tests',
332 'Grpc.Examples.Tests',
Jan Tattermusch9d67d8d2015-08-01 20:39:16 -0700333 'Grpc.HealthCheck.Tests',
Jan Tattermusch9a7d30c2015-04-23 16:12:55 -0700334 'Grpc.IntegrationTesting']
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700335 if self.platform == 'windows':
336 cmd = 'tools\\run_tests\\run_csharp.bat'
337 else:
338 cmd = 'tools/run_tests/run_csharp.sh'
339 return [config.job_spec([cmd, assembly],
Craig Tiller4fc90032015-05-21 10:39:52 -0700340 None, shortname=assembly,
Craig Tiller06805272015-06-11 14:46:47 -0700341 environ=_FORCE_ENVIRON_FOR_WRAPPERS)
Craig Tillerd50993d2015-08-05 08:04:36 -0700342 for assembly in assemblies]
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800343
murgatroid99256d3df2015-09-21 16:58:02 -0700344 def pre_build_steps(self):
Jan Tattermusch48423fc2015-10-07 18:59:16 -0700345 if self.platform == 'windows':
Jan Tattermusch874aec02015-10-07 19:26:19 -0700346 return [['tools\\run_tests\\pre_build_csharp.bat']]
Jan Tattermusch48423fc2015-10-07 18:59:16 -0700347 else:
348 return [['tools/run_tests/pre_build_csharp.sh']]
murgatroid99256d3df2015-09-21 16:58:02 -0700349
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800350 def make_targets(self):
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700351 # For Windows, this target doesn't really build anything,
352 # everything is build by buildall script later.
Craig Tillerd5904822015-08-31 21:30:58 -0700353 if self.platform == 'windows':
354 return []
355 else:
356 return ['grpc_csharp_ext']
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800357
358 def build_steps(self):
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700359 if self.platform == 'windows':
360 return [['src\\csharp\\buildall.bat']]
361 else:
362 return [['tools/run_tests/build_csharp.sh']]
Nathaniel Manista840615e2015-01-22 20:31:47 +0000363
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200364 def post_tests_steps(self):
365 return []
366
murgatroid99a3e244f2015-09-22 11:25:53 -0700367 def makefile_name(self):
368 return 'Makefile'
369
murgatroid99132ce6a2015-03-04 17:29:14 -0800370 def supports_multi_config(self):
371 return False
372
373 def __str__(self):
374 return 'csharp'
375
Craig Tillerd625d812015-04-08 15:52:35 -0700376
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700377class ObjCLanguage(object):
378
379 def test_specs(self, config, travis):
380 return [config.job_spec(['src/objective-c/tests/run_tests.sh'], None,
381 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
382
murgatroid99256d3df2015-09-21 16:58:02 -0700383 def pre_build_steps(self):
384 return []
385
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700386 def make_targets(self):
Jorge Canizalesd0b32e92015-07-30 23:08:43 -0700387 return ['grpc_objective_c_plugin', 'interop_server']
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700388
389 def build_steps(self):
Jorge Canizalesd0b32e92015-07-30 23:08:43 -0700390 return [['src/objective-c/tests/build_tests.sh']]
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700391
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200392 def post_tests_steps(self):
393 return []
394
murgatroid99a3e244f2015-09-22 11:25:53 -0700395 def makefile_name(self):
396 return 'Makefile'
397
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700398 def supports_multi_config(self):
399 return False
400
401 def __str__(self):
402 return 'objc'
403
404
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100405class Sanity(object):
406
407 def test_specs(self, config, travis):
Craig Tillerf75fc122015-06-25 06:58:00 -0700408 return [config.job_spec('tools/run_tests/run_sanity.sh', None),
409 config.job_spec('tools/run_tests/check_sources_and_headers.py', None)]
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100410
murgatroid99256d3df2015-09-21 16:58:02 -0700411 def pre_build_steps(self):
412 return []
413
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100414 def make_targets(self):
415 return ['run_dep_checks']
416
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" Noble9f728642015-03-24 18:50:30 +0100423 def supports_multi_config(self):
424 return False
425
426 def __str__(self):
427 return 'sanity'
428
Nicolas "Pixel" Noblee55cd7f2015-04-14 17:59:13 +0200429
Nicolas "Pixel" Noblefd2b0932015-03-26 00:26:29 +0100430class Build(object):
431
432 def test_specs(self, config, travis):
433 return []
434
murgatroid99256d3df2015-09-21 16:58:02 -0700435 def pre_build_steps(self):
436 return []
437
Nicolas "Pixel" Noblefd2b0932015-03-26 00:26:29 +0100438 def make_targets(self):
Nicolas "Pixel" Noblec23827b2015-04-23 06:17:55 +0200439 return ['static']
Nicolas "Pixel" Noblefd2b0932015-03-26 00:26:29 +0100440
441 def build_steps(self):
442 return []
443
murgatroid99a3e244f2015-09-22 11:25:53 -0700444 def makefile_name(self):
445 return 'Makefile'
446
Nicolas "Pixel" Noblefd2b0932015-03-26 00:26:29 +0100447 def supports_multi_config(self):
448 return True
449
450 def __str__(self):
451 return self.make_target
452
453
Craig Tiller738c3342015-01-12 14:28:33 -0800454# different configurations we can run under
455_CONFIGS = {
Craig Tillerb50d1662015-01-15 17:28:21 -0800456 'dbg': SimpleConfig('dbg'),
457 'opt': SimpleConfig('opt'),
Craig Tillerb2ea0b92015-08-26 13:06:53 -0700458 'tsan': SimpleConfig('tsan', timeout_seconds=10*60, environ={
Craig Tiller1ada6ad2015-07-16 16:19:14 -0700459 'TSAN_OPTIONS': 'suppressions=tools/tsan_suppressions.txt:halt_on_error=1:second_deadlock_stack=1'}),
Craig Tiller4a71ce22015-08-26 15:47:55 -0700460 'msan': SimpleConfig('msan', timeout_seconds=7*60),
Craig Tiller96bd5f62015-02-13 09:04:13 -0800461 'ubsan': SimpleConfig('ubsan'),
Craig Tillerb2ea0b92015-08-26 13:06:53 -0700462 'asan': SimpleConfig('asan', timeout_seconds=7*60, environ={
Craig Tillerd4b13622015-05-29 09:10:10 -0700463 'ASAN_OPTIONS': 'detect_leaks=1:color=always:suppressions=tools/tsan_suppressions.txt',
464 'LSAN_OPTIONS': 'report_objects=1'}),
Craig Tiller810725c2015-05-12 09:44:41 -0700465 'asan-noleaks': SimpleConfig('asan', environ={
466 'ASAN_OPTIONS': 'detect_leaks=0:color=always:suppressions=tools/tsan_suppressions.txt'}),
Craig Tillerb50d1662015-01-15 17:28:21 -0800467 'gcov': SimpleConfig('gcov'),
Craig Tiller1a305b12015-02-18 13:37:06 -0800468 'memcheck': ValgrindConfig('valgrind', 'memcheck', ['--leak-check=full']),
Craig Tillerb50d1662015-01-15 17:28:21 -0800469 'helgrind': ValgrindConfig('dbg', 'helgrind')
470 }
Craig Tiller738c3342015-01-12 14:28:33 -0800471
472
Nicolas "Pixel" Noble1fb5e822015-03-16 06:20:37 +0100473_DEFAULT = ['opt']
Craig Tillerc7449162015-01-16 14:42:10 -0800474_LANGUAGES = {
Craig Tillere9c959d2015-01-18 10:23:26 -0800475 'c++': CLanguage('cxx', 'c++'),
476 'c': CLanguage('c', 'c'),
murgatroid992c8d5162015-01-26 10:41:21 -0800477 'node': NodeLanguage(),
Nathaniel Manista840615e2015-01-22 20:31:47 +0000478 'php': PhpLanguage(),
479 'python': PythonLanguage(),
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800480 'ruby': RubyLanguage(),
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100481 'csharp': CSharpLanguage(),
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700482 'objc' : ObjCLanguage(),
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100483 'sanity': Sanity(),
Nicolas "Pixel" Noblefd2b0932015-03-26 00:26:29 +0100484 'build': Build(),
Craig Tillereb272bc2015-01-30 13:13:14 -0800485 }
Nicolas Nobleddef2462015-01-06 18:08:25 -0800486
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700487_WINDOWS_CONFIG = {
488 'dbg': 'Debug',
489 'opt': 'Release',
490 }
491
David Garcia Quintase90cd372015-05-31 18:15:26 -0700492
493def runs_per_test_type(arg_str):
494 """Auxilary function to parse the "runs_per_test" flag.
495
496 Returns:
497 A positive integer or 0, the latter indicating an infinite number of
498 runs.
499
500 Raises:
501 argparse.ArgumentTypeError: Upon invalid input.
502 """
503 if arg_str == 'inf':
504 return 0
505 try:
506 n = int(arg_str)
507 if n <= 0: raise ValueError
Craig Tiller50e53e22015-06-01 20:18:21 -0700508 return n
David Garcia Quintase90cd372015-05-31 18:15:26 -0700509 except:
510 msg = "'{}' isn't a positive integer or 'inf'".format(arg_str)
511 raise argparse.ArgumentTypeError(msg)
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700512
513# parse command line
514argp = argparse.ArgumentParser(description='Run grpc tests.')
515argp.add_argument('-c', '--config',
516 choices=['all'] + sorted(_CONFIGS.keys()),
517 nargs='+',
518 default=_DEFAULT)
David Garcia Quintase90cd372015-05-31 18:15:26 -0700519argp.add_argument('-n', '--runs_per_test', default=1, type=runs_per_test_type,
520 help='A positive integer or "inf". If "inf", all tests will run in an '
521 'infinite loop. Especially useful in combination with "-f"')
Craig Tillerfe406ec2015-02-24 13:55:12 -0800522argp.add_argument('-r', '--regex', default='.*', type=str)
Craig Tiller83762ac2015-05-22 14:04:06 -0700523argp.add_argument('-j', '--jobs', default=2 * multiprocessing.cpu_count(), type=int)
Craig Tiller8451e872015-02-27 09:25:51 -0800524argp.add_argument('-s', '--slowdown', default=1.0, type=float)
ctiller3040cb72015-01-07 12:13:17 -0800525argp.add_argument('-f', '--forever',
526 default=False,
527 action='store_const',
528 const=True)
Nicolas "Pixel" Noblea7df3f92015-02-26 22:07:04 +0100529argp.add_argument('-t', '--travis',
530 default=False,
531 action='store_const',
532 const=True)
Nicolas Noble044db742015-01-14 16:57:24 -0800533argp.add_argument('--newline_on_success',
534 default=False,
535 action='store_const',
536 const=True)
Craig Tiller686fb262015-01-15 07:39:09 -0800537argp.add_argument('-l', '--language',
Craig Tiller60f15e62015-05-13 09:05:17 -0700538 choices=['all'] + sorted(_LANGUAGES.keys()),
Craig Tiller686fb262015-01-15 07:39:09 -0800539 nargs='+',
Craig Tiller60f15e62015-05-13 09:05:17 -0700540 default=['all'])
Craig Tillercd43da82015-05-29 08:41:29 -0700541argp.add_argument('-S', '--stop_on_failure',
542 default=False,
543 action='store_const',
544 const=True)
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700545argp.add_argument('--use_docker',
546 default=False,
547 action='store_const',
548 const=True,
549 help="Run all the tests under docker. That provides " +
Jan Tattermusch8266c672015-09-17 09:18:03 -0700550 "additional isolation and prevents the need to install " +
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700551 "language specific prerequisites. Only available on Linux.")
Craig Tillerd4509a12015-09-28 09:18:40 -0700552argp.add_argument('--allow_flakes',
553 default=False,
554 action='store_const',
555 const=True,
556 help="Allow flaky tests to show as passing (re-runs failed tests up to five times)")
Craig Tiller234b6e72015-05-23 10:12:40 -0700557argp.add_argument('-a', '--antagonists', default=0, type=int)
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +0200558argp.add_argument('-x', '--xml_report', default=None, type=str,
559 help='Generates a JUnit-compatible XML report')
Nicolas Nobleddef2462015-01-06 18:08:25 -0800560args = argp.parse_args()
561
Jan Tattermuschc96b9eb2015-09-18 16:01:21 -0700562if args.use_docker:
563 if not args.travis:
564 print 'Seen --use_docker flag, will run tests under docker.'
565 print
566 print 'IMPORTANT: The changes you are testing need to be locally committed'
567 print 'because only the committed changes in the current branch will be'
568 print 'copied to the docker environment.'
569 time.sleep(5)
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700570
571 child_argv = [ arg for arg in sys.argv if not arg == '--use_docker' ]
572 run_tests_cmd = 'tools/run_tests/run_tests.py %s' % " ".join(child_argv[1:])
573
574 # TODO(jtattermusch): revisit if we need special handling for arch here
575 # set arch command prefix in case we are working with different arch.
576 arch_env = os.getenv('arch')
577 if arch_env:
578 run_test_cmd = 'arch %s %s' % (arch_env, run_test_cmd)
579
580 env = os.environ.copy()
581 env['RUN_TESTS_COMMAND'] = run_tests_cmd
582 if args.xml_report:
583 env['XML_REPORT'] = args.xml_report
Jan Tattermusch261b58c2015-09-18 17:15:48 -0700584 if not args.travis:
585 env['TTY_FLAG'] = '-t' # enables Ctrl-C when not on Jenkins.
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700586
587 subprocess.check_call(['tools/jenkins/build_docker_and_run_tests.sh'],
588 shell=True,
589 env=env)
590 sys.exit(0)
591
Nicolas Nobleddef2462015-01-06 18:08:25 -0800592# grab config
Craig Tiller738c3342015-01-12 14:28:33 -0800593run_configs = set(_CONFIGS[cfg]
594 for cfg in itertools.chain.from_iterable(
595 _CONFIGS.iterkeys() if x == 'all' else [x]
596 for x in args.config))
597build_configs = set(cfg.build_config for cfg in run_configs)
Craig Tillerf1973b02015-01-16 12:32:13 -0800598
Craig Tiller06805272015-06-11 14:46:47 -0700599if args.travis:
600 _FORCE_ENVIRON_FOR_WRAPPERS = {'GRPC_TRACE': 'surface,batch'}
601
Craig Tiller60f15e62015-05-13 09:05:17 -0700602languages = set(_LANGUAGES[l]
603 for l in itertools.chain.from_iterable(
604 _LANGUAGES.iterkeys() if x == 'all' else [x]
605 for x in args.language))
murgatroid99132ce6a2015-03-04 17:29:14 -0800606
607if len(build_configs) > 1:
608 for language in languages:
609 if not language.supports_multi_config():
610 print language, 'does not support multiple build configurations'
611 sys.exit(1)
612
Craig Tiller5058c692015-04-08 09:42:04 -0700613if platform.system() == 'Windows':
murgatroid99a3e244f2015-09-22 11:25:53 -0700614 def make_jobspec(cfg, targets, makefile='Makefile'):
Craig Tillerfc3c0c42015-09-01 16:47:54 -0700615 extra_args = []
Craig Tillerb5391e12015-09-03 14:35:18 -0700616 # better do parallel compilation
Jan Tattermusch47eeb2b2015-10-07 14:09:18 -0700617 # empirically /m:2 gives the best performance/price and should prevent
618 # overloading the windows workers.
619 extra_args.extend(["/m:2"])
Craig Tillerb5391e12015-09-03 14:35:18 -0700620 # disable PDB generation: it's broken, and we don't need it during CI
Craig Tiller3ef8c082015-09-04 15:17:12 -0700621 extra_args.extend(["/p:Jenkins=true"])
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(
Nicolas "Pixel" Noble351da8d2015-10-08 02:55:08 +0200645 jobset.JobSpec(cmdline, environ={'CONFIG': cfg}, flake_retries=5)
murgatroid99256d3df2015-09-21 16:58:02 -0700646 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(
Jan Tattermusch21897192015-10-07 15:42:21 -0700653 jobset.JobSpec(cmdline, environ={'CONFIG': cfg}, timeout_seconds=10*60)
murgatroid99132ce6a2015-03-04 17:29:14 -0800654 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 "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200658post_tests_steps = list(set(
659 jobset.JobSpec(cmdline, environ={'CONFIG': cfg})
660 for cfg in build_configs
661 for l in languages
662 for cmdline in l.post_tests_steps()))
Nicolas Nobleddef2462015-01-06 18:08:25 -0800663runs_per_test = args.runs_per_test
ctiller3040cb72015-01-07 12:13:17 -0800664forever = args.forever
Nicolas Nobleddef2462015-01-06 18:08:25 -0800665
Nicolas Nobleddef2462015-01-06 18:08:25 -0800666
Craig Tiller71735182015-01-15 17:07:13 -0800667class TestCache(object):
Craig Tillerb50d1662015-01-15 17:28:21 -0800668 """Cache for running tests."""
669
David Klempner25739582015-02-11 15:57:32 -0800670 def __init__(self, use_cache_results):
Craig Tiller71735182015-01-15 17:07:13 -0800671 self._last_successful_run = {}
David Klempner25739582015-02-11 15:57:32 -0800672 self._use_cache_results = use_cache_results
Craig Tiller69cd2372015-06-11 09:38:09 -0700673 self._last_save = time.time()
Craig Tiller71735182015-01-15 17:07:13 -0800674
675 def should_run(self, cmdline, bin_hash):
Craig Tiller71735182015-01-15 17:07:13 -0800676 if cmdline not in self._last_successful_run:
677 return True
678 if self._last_successful_run[cmdline] != bin_hash:
679 return True
David Klempner25739582015-02-11 15:57:32 -0800680 if not self._use_cache_results:
681 return True
Craig Tiller71735182015-01-15 17:07:13 -0800682 return False
683
684 def finished(self, cmdline, bin_hash):
Craig Tiller547db2b2015-01-30 14:08:39 -0800685 self._last_successful_run[cmdline] = bin_hash
Craig Tiller69cd2372015-06-11 09:38:09 -0700686 if time.time() - self._last_save > 1:
687 self.save()
Craig Tiller71735182015-01-15 17:07:13 -0800688
689 def dump(self):
Craig Tillerb50d1662015-01-15 17:28:21 -0800690 return [{'cmdline': k, 'hash': v}
691 for k, v in self._last_successful_run.iteritems()]
Craig Tiller71735182015-01-15 17:07:13 -0800692
693 def parse(self, exdump):
694 self._last_successful_run = dict((o['cmdline'], o['hash']) for o in exdump)
695
696 def save(self):
697 with open('.run_tests_cache', 'w') as f:
Craig Tiller261dd982015-01-16 16:41:45 -0800698 f.write(json.dumps(self.dump()))
Craig Tiller69cd2372015-06-11 09:38:09 -0700699 self._last_save = time.time()
Craig Tiller71735182015-01-15 17:07:13 -0800700
Craig Tiller1cc11db2015-01-15 22:50:50 -0800701 def maybe_load(self):
702 if os.path.exists('.run_tests_cache'):
703 with open('.run_tests_cache') as f:
Craig Tiller261dd982015-01-16 16:41:45 -0800704 self.parse(json.loads(f.read()))
Craig Tiller71735182015-01-15 17:07:13 -0800705
706
Craig Tillerf53d9c82015-08-04 14:19:43 -0700707def _start_port_server(port_server_port):
708 # check if a compatible port server is running
709 # if incompatible (version mismatch) ==> start a new one
710 # if not running ==> start a new one
711 # otherwise, leave it up
712 try:
Craig Tillerfe4939f2015-10-06 12:55:36 -0700713 version = int(urllib2.urlopen(
714 'http://localhost:%d/version_number' % port_server_port,
715 timeout=1).read())
716 print 'detected port server running version %d' % version
Craig Tillerf53d9c82015-08-04 14:19:43 -0700717 running = True
Craig Tillerfe4939f2015-10-06 12:55:36 -0700718 except Exception as e:
Craig Tiller0d6499e2015-10-05 14:00:47 -0700719 print 'failed to detect port server: %s' % sys.exc_info()[0]
Craig Tillerfe4939f2015-10-06 12:55:36 -0700720 print e.strerror
Craig Tillerf53d9c82015-08-04 14:19:43 -0700721 running = False
722 if running:
Craig Tillerfe4939f2015-10-06 12:55:36 -0700723 current_version = int(subprocess.check_output(
724 [sys.executable, 'tools/run_tests/port_server.py', 'dump_version']))
725 print 'my port server is version %d' % current_version
726 running = (version >= current_version)
727 if not running:
728 print 'port_server version mismatch: killing the old one'
729 urllib2.urlopen('http://localhost:%d/quitquitquit' % port_server_port).read()
730 time.sleep(1)
Craig Tillerf53d9c82015-08-04 14:19:43 -0700731 if not running:
Craig Tiller0d6499e2015-10-05 14:00:47 -0700732 print 'starting port_server'
Craig Tillerf53d9c82015-08-04 14:19:43 -0700733 port_log = open('portlog.txt', 'w')
734 port_server = subprocess.Popen(
Craig Tiller1447ece2015-10-05 14:44:32 -0700735 [sys.executable, 'tools/run_tests/port_server.py', '-p', '%d' % port_server_port],
Craig Tillerf53d9c82015-08-04 14:19:43 -0700736 stderr=subprocess.STDOUT,
737 stdout=port_log)
Craig Tiller8b5f4dc2015-08-26 08:02:01 -0700738 # ensure port server is up
Craig Tillerabd37fd2015-08-26 07:54:01 -0700739 waits = 0
Craig Tillerf53d9c82015-08-04 14:19:43 -0700740 while True:
Craig Tillerabd37fd2015-08-26 07:54:01 -0700741 if waits > 10:
742 port_server.kill()
Craig Tillera2f38b02015-09-24 11:19:17 -0700743 if port_server.poll() is not None:
Craig Tiller0d6499e2015-10-05 14:00:47 -0700744 print 'port_server failed to start'
Craig Tillera2f38b02015-09-24 11:19:17 -0700745 port_log = open('portlog.txt', 'r').read()
746 print port_log
Craig Tillerabd37fd2015-08-26 07:54:01 -0700747 sys.exit(1)
Craig Tillerf53d9c82015-08-04 14:19:43 -0700748 try:
Craig Tillerabd37fd2015-08-26 07:54:01 -0700749 urllib2.urlopen('http://localhost:%d/get' % port_server_port,
750 timeout=1).read()
Craig Tillerf53d9c82015-08-04 14:19:43 -0700751 break
Craig Tiller31fdaa42015-09-25 13:09:59 -0700752 except socket.timeout:
Craig Tiller0d6499e2015-10-05 14:00:47 -0700753 print 'waiting for port_server: timeout'
Craig Tiller31fdaa42015-09-25 13:09:59 -0700754 time.sleep(0.5)
755 waits += 1
Craig Tillerf53d9c82015-08-04 14:19:43 -0700756 except urllib2.URLError:
Craig Tiller0d6499e2015-10-05 14:00:47 -0700757 print 'waiting for port_server: urlerror'
Craig Tillerf53d9c82015-08-04 14:19:43 -0700758 time.sleep(0.5)
Craig Tillerabd37fd2015-08-26 07:54:01 -0700759 waits += 1
Craig Tillerf53d9c82015-08-04 14:19:43 -0700760 except:
761 port_server.kill()
762 raise
763
764
765def _build_and_run(
766 check_cancelled, newline_on_success, travis, cache, xml_report=None):
ctiller3040cb72015-01-07 12:13:17 -0800767 """Do one pass of building & running tests."""
murgatroid99666450e2015-01-26 13:03:31 -0800768 # build latest sequentially
Nicolas "Pixel" Noble351da8d2015-10-08 02:55:08 +0200769 if not jobset.run(build_steps, maxjobs=1, stop_on_failure=True,
Nicolas "Pixel" Noblea7df3f92015-02-26 22:07:04 +0100770 newline_on_success=newline_on_success, travis=travis):
Craig Tillerd86a3942015-01-14 12:48:54 -0800771 return 1
ctiller3040cb72015-01-07 12:13:17 -0800772
Craig Tiller234b6e72015-05-23 10:12:40 -0700773 # start antagonists
David Garcia Quintas79e389f2015-06-02 17:49:42 -0700774 antagonists = [subprocess.Popen(['tools/run_tests/antagonist.py'])
Craig Tiller234b6e72015-05-23 10:12:40 -0700775 for _ in range(0, args.antagonists)]
Craig Tillerfe4939f2015-10-06 12:55:36 -0700776 port_server_port = 32767
Craig Tillerf53d9c82015-08-04 14:19:43 -0700777 _start_port_server(port_server_port)
Craig Tiller234b6e72015-05-23 10:12:40 -0700778 try:
David Garcia Quintase90cd372015-05-31 18:15:26 -0700779 infinite_runs = runs_per_test == 0
yang-g6c1fdc62015-08-18 11:57:42 -0700780 one_run = set(
781 spec
782 for config in run_configs
783 for language in languages
784 for spec in language.test_specs(config, args.travis)
785 if re.search(args.regex, spec.shortname))
David Garcia Quintas79e389f2015-06-02 17:49:42 -0700786 # When running on travis, we want out test runs to be as similar as possible
787 # for reproducibility purposes.
788 if travis:
789 massaged_one_run = sorted(one_run, key=lambda x: x.shortname)
790 else:
791 # whereas otherwise, we want to shuffle things up to give all tests a
792 # chance to run.
793 massaged_one_run = list(one_run) # random.shuffle needs an indexable seq.
794 random.shuffle(massaged_one_run) # which it modifies in-place.
Craig Tillerf7b7c892015-06-22 14:33:25 -0700795 if infinite_runs:
796 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 -0700797 runs_sequence = (itertools.repeat(massaged_one_run) if infinite_runs
798 else itertools.repeat(massaged_one_run, runs_per_test))
David Garcia Quintase90cd372015-05-31 18:15:26 -0700799 all_runs = itertools.chain.from_iterable(runs_sequence)
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +0200800
801 root = ET.Element('testsuites') if xml_report else None
802 testsuite = ET.SubElement(root, 'testsuite', id='1', package='grpc', name='tests') if xml_report else None
803
Craig Tiller234b6e72015-05-23 10:12:40 -0700804 if not jobset.run(all_runs, check_cancelled,
805 newline_on_success=newline_on_success, travis=travis,
David Garcia Quintase90cd372015-05-31 18:15:26 -0700806 infinite_runs=infinite_runs,
Craig Tillerda2220a2015-05-27 07:50:53 -0700807 maxjobs=args.jobs,
Craig Tillercd43da82015-05-29 08:41:29 -0700808 stop_on_failure=args.stop_on_failure,
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +0200809 cache=cache if not xml_report else None,
Craig Tillerf53d9c82015-08-04 14:19:43 -0700810 xml_report=testsuite,
811 add_env={'GRPC_TEST_PORT_SERVER': 'localhost:%d' % port_server_port}):
Craig Tiller234b6e72015-05-23 10:12:40 -0700812 return 2
813 finally:
814 for antagonist in antagonists:
815 antagonist.kill()
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +0200816 if xml_report:
817 tree = ET.ElementTree(root)
818 tree.write(xml_report, encoding='UTF-8')
Craig Tillerd86a3942015-01-14 12:48:54 -0800819
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200820 if not jobset.run(post_tests_steps, maxjobs=1, stop_on_failure=True,
821 newline_on_success=newline_on_success, travis=travis):
822 return 3
823
Craig Tiller69cd2372015-06-11 09:38:09 -0700824 if cache: cache.save()
825
Craig Tillerd86a3942015-01-14 12:48:54 -0800826 return 0
ctiller3040cb72015-01-07 12:13:17 -0800827
828
David Klempner25739582015-02-11 15:57:32 -0800829test_cache = TestCache(runs_per_test == 1)
Craig Tiller547db2b2015-01-30 14:08:39 -0800830test_cache.maybe_load()
Craig Tiller71735182015-01-15 17:07:13 -0800831
ctiller3040cb72015-01-07 12:13:17 -0800832if forever:
Nicolas Noble044db742015-01-14 16:57:24 -0800833 success = True
ctiller3040cb72015-01-07 12:13:17 -0800834 while True:
Craig Tiller42bc87c2015-02-23 08:50:19 -0800835 dw = watch_dirs.DirWatcher(['src', 'include', 'test', 'examples'])
ctiller3040cb72015-01-07 12:13:17 -0800836 initial_time = dw.most_recent_change()
837 have_files_changed = lambda: dw.most_recent_change() != initial_time
Nicolas Noble044db742015-01-14 16:57:24 -0800838 previous_success = success
Craig Tiller71735182015-01-15 17:07:13 -0800839 success = _build_and_run(check_cancelled=have_files_changed,
Nicolas Nobleb09078f2015-01-14 18:06:05 -0800840 newline_on_success=False,
Craig Tiller9a5a9402015-04-16 10:39:50 -0700841 travis=args.travis,
Craig Tiller71735182015-01-15 17:07:13 -0800842 cache=test_cache) == 0
Nicolas Noble044db742015-01-14 16:57:24 -0800843 if not previous_success and success:
Nicolas Nobleb09078f2015-01-14 18:06:05 -0800844 jobset.message('SUCCESS',
845 'All tests are now passing properly',
846 do_newline=True)
Nicolas Noble044db742015-01-14 16:57:24 -0800847 jobset.message('IDLE', 'No change detected')
ctiller3040cb72015-01-07 12:13:17 -0800848 while not have_files_changed():
849 time.sleep(1)
850else:
Craig Tiller71735182015-01-15 17:07:13 -0800851 result = _build_and_run(check_cancelled=lambda: False,
852 newline_on_success=args.newline_on_success,
Nicolas "Pixel" Noblea7df3f92015-02-26 22:07:04 +0100853 travis=args.travis,
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +0200854 cache=test_cache,
855 xml_report=args.xml_report)
Nicolas Nobleb09078f2015-01-14 18:06:05 -0800856 if result == 0:
857 jobset.message('SUCCESS', 'All tests passed', do_newline=True)
858 else:
859 jobset.message('FAILED', 'Some tests failed', do_newline=True)
860 sys.exit(result)