blob: c78a120fc6569510842a59bab8999dea14fc6646 [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
Craig Tillerf0a293e2015-10-12 10:05:50 -070046import tempfile
47import traceback
ctiller3040cb72015-01-07 12:13:17 -080048import time
Craig Tillerf53d9c82015-08-04 14:19:43 -070049import urllib2
Nicolas Nobleddef2462015-01-06 18:08:25 -080050
51import jobset
Adele Zhoua30f8292015-11-02 13:15:46 -080052import report_utils
ctiller3040cb72015-01-07 12:13:17 -080053import watch_dirs
Nicolas Nobleddef2462015-01-06 18:08:25 -080054
Craig Tiller2cc2b842015-02-27 11:38:31 -080055ROOT = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), '../..'))
56os.chdir(ROOT)
57
58
Craig Tiller06805272015-06-11 14:46:47 -070059_FORCE_ENVIRON_FOR_WRAPPERS = {}
60
61
Craig Tillerd50993d2015-08-05 08:04:36 -070062def platform_string():
63 if platform.system() == 'Windows':
64 return 'windows'
65 elif platform.system() == 'Darwin':
66 return 'mac'
67 elif platform.system() == 'Linux':
68 return 'linux'
69 else:
70 return 'posix'
71
72
Craig Tiller738c3342015-01-12 14:28:33 -080073# SimpleConfig: just compile with CONFIG=config, and run the binary to test
74class SimpleConfig(object):
Craig Tillerb50d1662015-01-15 17:28:21 -080075
Masood Malekghassemi26ea9e22015-10-09 15:19:17 -070076 def __init__(self, config, environ=None, timeout_multiplier=1):
murgatroid99132ce6a2015-03-04 17:29:14 -080077 if environ is None:
78 environ = {}
Craig Tiller738c3342015-01-12 14:28:33 -080079 self.build_config = config
Craig Tillerc7449162015-01-16 14:42:10 -080080 self.allow_hashing = (config != 'gcov')
Craig Tiller547db2b2015-01-30 14:08:39 -080081 self.environ = environ
murgatroid99132ce6a2015-03-04 17:29:14 -080082 self.environ['CONFIG'] = config
Masood Malekghassemi26ea9e22015-10-09 15:19:17 -070083 self.timeout_multiplier = timeout_multiplier
Craig Tiller738c3342015-01-12 14:28:33 -080084
Masood Malekghassemi26ea9e22015-10-09 15:19:17 -070085 def job_spec(self, cmdline, hash_targets, timeout_seconds=5*60,
86 shortname=None, environ={}):
Craig Tiller49f61322015-03-03 13:02:11 -080087 """Construct a jobset.JobSpec for a test under this config
88
89 Args:
90 cmdline: a list of strings specifying the command line the test
91 would like to run
92 hash_targets: either None (don't do caching of test results), or
93 a list of strings specifying files to include in a
94 binary hash to check if a test has changed
95 -- if used, all artifacts needed to run the test must
96 be listed
97 """
Craig Tiller4fc90032015-05-21 10:39:52 -070098 actual_environ = self.environ.copy()
99 for k, v in environ.iteritems():
100 actual_environ[k] = v
Craig Tiller49f61322015-03-03 13:02:11 -0800101 return jobset.JobSpec(cmdline=cmdline,
Jan Tattermusch9a7d30c2015-04-23 16:12:55 -0700102 shortname=shortname,
Craig Tiller4fc90032015-05-21 10:39:52 -0700103 environ=actual_environ,
Masood Malekghassemi26ea9e22015-10-09 15:19:17 -0700104 timeout_seconds=self.timeout_multiplier * timeout_seconds,
Craig Tiller547db2b2015-01-30 14:08:39 -0800105 hash_targets=hash_targets
Craig Tillerd4509a12015-09-28 09:18:40 -0700106 if self.allow_hashing else None,
Craig Tiller35505de2015-10-08 13:31:33 -0700107 flake_retries=5 if args.allow_flakes else 0,
108 timeout_retries=3 if args.allow_flakes else 0)
Craig Tiller738c3342015-01-12 14:28:33 -0800109
110
111# ValgrindConfig: compile with some CONFIG=config, but use valgrind to run
112class ValgrindConfig(object):
Craig Tillerb50d1662015-01-15 17:28:21 -0800113
murgatroid99132ce6a2015-03-04 17:29:14 -0800114 def __init__(self, config, tool, args=None):
115 if args is None:
116 args = []
Craig Tiller738c3342015-01-12 14:28:33 -0800117 self.build_config = config
Craig Tiller2aa4d642015-01-14 15:59:44 -0800118 self.tool = tool
Craig Tiller1a305b12015-02-18 13:37:06 -0800119 self.args = args
Craig Tillerc7449162015-01-16 14:42:10 -0800120 self.allow_hashing = False
Craig Tiller738c3342015-01-12 14:28:33 -0800121
Craig Tiller49f61322015-03-03 13:02:11 -0800122 def job_spec(self, cmdline, hash_targets):
Craig Tiller1a305b12015-02-18 13:37:06 -0800123 return jobset.JobSpec(cmdline=['valgrind', '--tool=%s' % self.tool] +
Craig Tiller49f61322015-03-03 13:02:11 -0800124 self.args + cmdline,
Craig Tiller71ec6cb2015-06-03 00:51:11 -0700125 shortname='valgrind %s' % cmdline[0],
Craig Tillerd4509a12015-09-28 09:18:40 -0700126 hash_targets=None,
Craig Tiller95cc07b2015-09-28 13:41:30 -0700127 flake_retries=5 if args.allow_flakes else 0,
Craig Tiller35505de2015-10-08 13:31:33 -0700128 timeout_retries=3 if args.allow_flakes else 0)
Craig Tiller738c3342015-01-12 14:28:33 -0800129
130
murgatroid99cf08daf2015-09-21 15:33:16 -0700131def get_c_tests(travis, test_lang) :
132 out = []
133 platforms_str = 'ci_platforms' if travis else 'platforms'
134 with open('tools/run_tests/tests.json') as f:
murgatroid9989899b12015-09-22 09:14:48 -0700135 js = json.load(f)
murgatroid99a3e244f2015-09-22 11:25:53 -0700136 return [tgt
137 for tgt in js
138 if tgt['language'] == test_lang and
139 platform_string() in tgt[platforms_str] and
140 not (travis and tgt['flaky'])]
murgatroid99cf08daf2015-09-21 15:33:16 -0700141
murgatroid99fafeeb32015-09-22 09:13:03 -0700142
Craig Tillerc7449162015-01-16 14:42:10 -0800143class CLanguage(object):
144
Craig Tillere9c959d2015-01-18 10:23:26 -0800145 def __init__(self, make_target, test_lang):
Craig Tillerc7449162015-01-16 14:42:10 -0800146 self.make_target = make_target
Craig Tillerd50993d2015-08-05 08:04:36 -0700147 self.platform = platform_string()
Craig Tiller711bbe62015-08-19 12:35:16 -0700148 self.test_lang = test_lang
Craig Tillerc7449162015-01-16 14:42:10 -0800149
Nicolas "Pixel" Noble9db7c3b2015-02-27 06:03:00 +0100150 def test_specs(self, config, travis):
Craig Tiller547db2b2015-01-30 14:08:39 -0800151 out = []
murgatroid99cf08daf2015-09-21 15:33:16 -0700152 binaries = get_c_tests(travis, self.test_lang)
Craig Tiller711bbe62015-08-19 12:35:16 -0700153 for target in binaries:
murgatroid99a3e244f2015-09-22 11:25:53 -0700154 if config.build_config in target['exclude_configs']:
murgatroid99fafeeb32015-09-22 09:13:03 -0700155 continue
Nicolas Noblee1445362015-05-11 17:40:26 -0700156 if self.platform == 'windows':
Craig Tillerf4182602015-09-01 12:23:16 -0700157 binary = 'vsprojects/%s/%s.exe' % (
158 _WINDOWS_CONFIG[config.build_config], target['name'])
Nicolas Noblee1445362015-05-11 17:40:26 -0700159 else:
160 binary = 'bins/%s/%s' % (config.build_config, target['name'])
yang-g6c1fdc62015-08-18 11:57:42 -0700161 if os.path.isfile(binary):
162 out.append(config.job_spec([binary], [binary]))
163 else:
Adele Zhoue4c35612015-10-16 15:34:23 -0700164 print '\nWARNING: binary not found, skipping', binary
Nicolas Noblee1445362015-05-11 17:40:26 -0700165 return sorted(out)
Craig Tillerc7449162015-01-16 14:42:10 -0800166
167 def make_targets(self):
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700168 if platform_string() == 'windows':
169 # don't build tools on windows just yet
170 return ['buildtests_%s' % self.make_target]
Craig Tiller7552f0f2015-06-19 17:46:20 -0700171 return ['buildtests_%s' % self.make_target, 'tools_%s' % self.make_target]
Craig Tillerc7449162015-01-16 14:42:10 -0800172
murgatroid99256d3df2015-09-21 16:58:02 -0700173 def pre_build_steps(self):
Jan Tattermusch874aec02015-10-07 19:26:19 -0700174 if self.platform == 'windows':
175 return [['tools\\run_tests\\pre_build_c.bat']]
176 else:
177 return []
murgatroid99256d3df2015-09-21 16:58:02 -0700178
Craig Tillerc7449162015-01-16 14:42:10 -0800179 def build_steps(self):
180 return []
181
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200182 def post_tests_steps(self):
183 if self.platform == 'windows':
184 return []
185 else:
186 return [['tools/run_tests/post_tests_c.sh']]
187
murgatroid99a3e244f2015-09-22 11:25:53 -0700188 def makefile_name(self):
189 return 'Makefile'
190
murgatroid99132ce6a2015-03-04 17:29:14 -0800191 def supports_multi_config(self):
192 return True
193
194 def __str__(self):
195 return self.make_target
196
murgatroid992c8d5162015-01-26 10:41:21 -0800197class NodeLanguage(object):
198
Nicolas "Pixel" Noble9db7c3b2015-02-27 06:03:00 +0100199 def test_specs(self, config, travis):
Craig Tiller4fc90032015-05-21 10:39:52 -0700200 return [config.job_spec(['tools/run_tests/run_node.sh'], None,
Craig Tiller06805272015-06-11 14:46:47 -0700201 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
murgatroid992c8d5162015-01-26 10:41:21 -0800202
murgatroid99256d3df2015-09-21 16:58:02 -0700203 def pre_build_steps(self):
murgatroid99ae369de2015-10-09 15:40:48 -0700204 # Default to 1 week cache expiration
murgatroid9993758952015-10-14 11:51:05 -0700205 return [['tools/run_tests/pre_build_node.sh']]
murgatroid99256d3df2015-09-21 16:58:02 -0700206
murgatroid992c8d5162015-01-26 10:41:21 -0800207 def make_targets(self):
murgatroid99db5b1602015-10-01 13:20:11 -0700208 return []
murgatroid992c8d5162015-01-26 10:41:21 -0800209
210 def build_steps(self):
211 return [['tools/run_tests/build_node.sh']]
Craig Tillerc7449162015-01-16 14:42:10 -0800212
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200213 def post_tests_steps(self):
214 return []
215
murgatroid99a3e244f2015-09-22 11:25:53 -0700216 def makefile_name(self):
217 return 'Makefile'
218
murgatroid99132ce6a2015-03-04 17:29:14 -0800219 def supports_multi_config(self):
220 return False
221
222 def __str__(self):
223 return 'node'
224
Craig Tiller99775822015-01-30 13:07:16 -0800225
Craig Tillerc7449162015-01-16 14:42:10 -0800226class PhpLanguage(object):
227
Nicolas "Pixel" Noble9db7c3b2015-02-27 06:03:00 +0100228 def test_specs(self, config, travis):
Craig Tiller4fc90032015-05-21 10:39:52 -0700229 return [config.job_spec(['src/php/bin/run_tests.sh'], None,
Craig Tiller06805272015-06-11 14:46:47 -0700230 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
Craig Tillerc7449162015-01-16 14:42:10 -0800231
murgatroid99256d3df2015-09-21 16:58:02 -0700232 def pre_build_steps(self):
233 return []
234
Craig Tillerc7449162015-01-16 14:42:10 -0800235 def make_targets(self):
Craig Tilleraf7cf542015-05-22 10:07:34 -0700236 return ['static_c', 'shared_c']
Craig Tillerc7449162015-01-16 14:42:10 -0800237
238 def build_steps(self):
239 return [['tools/run_tests/build_php.sh']]
240
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200241 def post_tests_steps(self):
242 return []
243
murgatroid99a3e244f2015-09-22 11:25:53 -0700244 def makefile_name(self):
245 return 'Makefile'
246
murgatroid99132ce6a2015-03-04 17:29:14 -0800247 def supports_multi_config(self):
248 return False
249
250 def __str__(self):
251 return 'php'
252
Craig Tillerc7449162015-01-16 14:42:10 -0800253
Nathaniel Manista840615e2015-01-22 20:31:47 +0000254class PythonLanguage(object):
255
Craig Tiller49f61322015-03-03 13:02:11 -0800256 def __init__(self):
Masood Malekghassemi2b841622015-07-28 17:39:02 -0700257 self._build_python_versions = ['2.7']
Masood Malekghassemie5f70022015-06-29 09:20:26 -0700258 self._has_python_versions = []
Craig Tiller49f61322015-03-03 13:02:11 -0800259
Nicolas "Pixel" Noble9db7c3b2015-02-27 06:03:00 +0100260 def test_specs(self, config, travis):
Masood Malekghassemi2b841622015-07-28 17:39:02 -0700261 environment = dict(_FORCE_ENVIRON_FOR_WRAPPERS)
262 environment['PYVER'] = '2.7'
263 return [config.job_spec(
264 ['tools/run_tests/run_python.sh'],
265 None,
266 environ=environment,
267 shortname='py.test',
Masood Malekghassemi26ea9e22015-10-09 15:19:17 -0700268 timeout_seconds=15*60
Masood Malekghassemi2b841622015-07-28 17:39:02 -0700269 )]
Nathaniel Manista840615e2015-01-22 20:31:47 +0000270
murgatroid99256d3df2015-09-21 16:58:02 -0700271 def pre_build_steps(self):
272 return []
273
Nathaniel Manista840615e2015-01-22 20:31:47 +0000274 def make_targets(self):
Craig Tilleraf7cf542015-05-22 10:07:34 -0700275 return ['static_c', 'grpc_python_plugin', 'shared_c']
Nathaniel Manista840615e2015-01-22 20:31:47 +0000276
277 def build_steps(self):
Masood Malekghassemie5f70022015-06-29 09:20:26 -0700278 commands = []
279 for python_version in self._build_python_versions:
280 try:
281 with open(os.devnull, 'w') as output:
282 subprocess.check_call(['which', 'python' + python_version],
283 stdout=output, stderr=output)
284 commands.append(['tools/run_tests/build_python.sh', python_version])
285 self._has_python_versions.append(python_version)
286 except:
287 jobset.message('WARNING', 'Missing Python ' + python_version,
288 do_newline=True)
289 return commands
Nathaniel Manista840615e2015-01-22 20:31:47 +0000290
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200291 def post_tests_steps(self):
292 return []
293
murgatroid99a3e244f2015-09-22 11:25:53 -0700294 def makefile_name(self):
295 return 'Makefile'
296
murgatroid99132ce6a2015-03-04 17:29:14 -0800297 def supports_multi_config(self):
298 return False
299
300 def __str__(self):
301 return 'python'
302
Craig Tillerd625d812015-04-08 15:52:35 -0700303
murgatroid996a4c4fa2015-02-27 12:08:57 -0800304class RubyLanguage(object):
305
306 def test_specs(self, config, travis):
Craig Tiller4fc90032015-05-21 10:39:52 -0700307 return [config.job_spec(['tools/run_tests/run_ruby.sh'], None,
Craig Tiller06805272015-06-11 14:46:47 -0700308 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
murgatroid996a4c4fa2015-02-27 12:08:57 -0800309
murgatroid99256d3df2015-09-21 16:58:02 -0700310 def pre_build_steps(self):
Nicolas "Pixel" Noblebcf988f2015-10-08 03:00:42 +0200311 return [['tools/run_tests/pre_build_ruby.sh']]
murgatroid99256d3df2015-09-21 16:58:02 -0700312
murgatroid996a4c4fa2015-02-27 12:08:57 -0800313 def make_targets(self):
murgatroid99a43c14f2015-07-30 13:31:23 -0700314 return ['static_c']
murgatroid996a4c4fa2015-02-27 12:08:57 -0800315
316 def build_steps(self):
317 return [['tools/run_tests/build_ruby.sh']]
318
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200319 def post_tests_steps(self):
320 return []
321
murgatroid99a3e244f2015-09-22 11:25:53 -0700322 def makefile_name(self):
323 return 'Makefile'
324
murgatroid99132ce6a2015-03-04 17:29:14 -0800325 def supports_multi_config(self):
326 return False
327
328 def __str__(self):
329 return 'ruby'
330
Craig Tillerd625d812015-04-08 15:52:35 -0700331
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800332class CSharpLanguage(object):
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700333 def __init__(self):
Craig Tillerd50993d2015-08-05 08:04:36 -0700334 self.platform = platform_string()
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700335
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800336 def test_specs(self, config, travis):
Jan Tattermusch9a7d30c2015-04-23 16:12:55 -0700337 assemblies = ['Grpc.Core.Tests',
338 'Grpc.Examples.Tests',
Jan Tattermusch9d67d8d2015-08-01 20:39:16 -0700339 'Grpc.HealthCheck.Tests',
Jan Tattermusch9a7d30c2015-04-23 16:12:55 -0700340 'Grpc.IntegrationTesting']
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700341 if self.platform == 'windows':
342 cmd = 'tools\\run_tests\\run_csharp.bat'
343 else:
344 cmd = 'tools/run_tests/run_csharp.sh'
Jan Tattermuschbf3b1532015-10-26 10:24:42 -0700345
Jan Tattermuschbdf4b2e2015-10-28 08:22:34 -0700346 if config.build_config == 'gcov':
347 # On Windows, we only collect C# code coverage.
348 # On Linux, we only collect coverage for native extension.
349 # For code coverage all tests need to run as one suite.
Jan Tattermusch61c3a832015-10-27 17:54:50 -0700350 return [config.job_spec([cmd], None,
351 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
352 else:
Jan Tattermuschbf3b1532015-10-26 10:24:42 -0700353 return [config.job_spec([cmd, assembly],
354 None, shortname=assembly,
355 environ=_FORCE_ENVIRON_FOR_WRAPPERS)
356 for assembly in assemblies]
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800357
murgatroid99256d3df2015-09-21 16:58:02 -0700358 def pre_build_steps(self):
Jan Tattermusch48423fc2015-10-07 18:59:16 -0700359 if self.platform == 'windows':
Jan Tattermusch874aec02015-10-07 19:26:19 -0700360 return [['tools\\run_tests\\pre_build_csharp.bat']]
Jan Tattermusch48423fc2015-10-07 18:59:16 -0700361 else:
362 return [['tools/run_tests/pre_build_csharp.sh']]
murgatroid99256d3df2015-09-21 16:58:02 -0700363
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800364 def make_targets(self):
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700365 # For Windows, this target doesn't really build anything,
366 # everything is build by buildall script later.
Craig Tillerd5904822015-08-31 21:30:58 -0700367 if self.platform == 'windows':
368 return []
369 else:
370 return ['grpc_csharp_ext']
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800371
372 def build_steps(self):
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700373 if self.platform == 'windows':
374 return [['src\\csharp\\buildall.bat']]
375 else:
376 return [['tools/run_tests/build_csharp.sh']]
Nathaniel Manista840615e2015-01-22 20:31:47 +0000377
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200378 def post_tests_steps(self):
379 return []
380
murgatroid99a3e244f2015-09-22 11:25:53 -0700381 def makefile_name(self):
382 return 'Makefile'
383
murgatroid99132ce6a2015-03-04 17:29:14 -0800384 def supports_multi_config(self):
385 return False
386
387 def __str__(self):
388 return 'csharp'
389
Craig Tillerd625d812015-04-08 15:52:35 -0700390
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700391class ObjCLanguage(object):
392
393 def test_specs(self, config, travis):
394 return [config.job_spec(['src/objective-c/tests/run_tests.sh'], None,
395 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
396
murgatroid99256d3df2015-09-21 16:58:02 -0700397 def pre_build_steps(self):
398 return []
399
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700400 def make_targets(self):
Jorge Canizalesd0b32e92015-07-30 23:08:43 -0700401 return ['grpc_objective_c_plugin', 'interop_server']
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700402
403 def build_steps(self):
Jorge Canizalesd0b32e92015-07-30 23:08:43 -0700404 return [['src/objective-c/tests/build_tests.sh']]
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700405
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200406 def post_tests_steps(self):
407 return []
408
murgatroid99a3e244f2015-09-22 11:25:53 -0700409 def makefile_name(self):
410 return 'Makefile'
411
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700412 def supports_multi_config(self):
413 return False
414
415 def __str__(self):
416 return 'objc'
417
418
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100419class Sanity(object):
420
421 def test_specs(self, config, travis):
Jan Tattermusche3d66252015-10-26 11:33:45 -0700422 return [config.job_spec(['tools/run_tests/run_sanity.sh'], None),
423 config.job_spec(['tools/run_tests/check_sources_and_headers.py'], None)]
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100424
murgatroid99256d3df2015-09-21 16:58:02 -0700425 def pre_build_steps(self):
426 return []
427
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100428 def make_targets(self):
429 return ['run_dep_checks']
430
431 def build_steps(self):
432 return []
433
Nicolas "Pixel" Noble87879b32015-10-12 23:28:53 +0200434 def post_tests_steps(self):
435 return []
436
murgatroid99a3e244f2015-09-22 11:25:53 -0700437 def makefile_name(self):
438 return 'Makefile'
439
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100440 def supports_multi_config(self):
441 return False
442
443 def __str__(self):
444 return 'sanity'
445
Nicolas "Pixel" Noblee55cd7f2015-04-14 17:59:13 +0200446
Nicolas "Pixel" Noblefd2b0932015-03-26 00:26:29 +0100447class Build(object):
448
449 def test_specs(self, config, travis):
450 return []
451
murgatroid99256d3df2015-09-21 16:58:02 -0700452 def pre_build_steps(self):
453 return []
454
Nicolas "Pixel" Noblefd2b0932015-03-26 00:26:29 +0100455 def make_targets(self):
Nicolas "Pixel" Noblec23827b2015-04-23 06:17:55 +0200456 return ['static']
Nicolas "Pixel" Noblefd2b0932015-03-26 00:26:29 +0100457
458 def build_steps(self):
459 return []
460
Nicolas "Pixel" Noblefe300452015-10-27 23:05:10 +0100461 def post_tests_steps(self):
462 return []
463
murgatroid99a3e244f2015-09-22 11:25:53 -0700464 def makefile_name(self):
465 return 'Makefile'
466
Nicolas "Pixel" Noblefd2b0932015-03-26 00:26:29 +0100467 def supports_multi_config(self):
468 return True
469
470 def __str__(self):
471 return self.make_target
472
473
Craig Tiller738c3342015-01-12 14:28:33 -0800474# different configurations we can run under
475_CONFIGS = {
Craig Tillerb50d1662015-01-15 17:28:21 -0800476 'dbg': SimpleConfig('dbg'),
477 'opt': SimpleConfig('opt'),
Masood Malekghassemi26ea9e22015-10-09 15:19:17 -0700478 'tsan': SimpleConfig('tsan', timeout_multiplier=2, environ={
Craig Tiller1ada6ad2015-07-16 16:19:14 -0700479 'TSAN_OPTIONS': 'suppressions=tools/tsan_suppressions.txt:halt_on_error=1:second_deadlock_stack=1'}),
Masood Malekghassemi26ea9e22015-10-09 15:19:17 -0700480 'msan': SimpleConfig('msan', timeout_multiplier=1.5),
Craig Tiller96bd5f62015-02-13 09:04:13 -0800481 'ubsan': SimpleConfig('ubsan'),
Masood Malekghassemi26ea9e22015-10-09 15:19:17 -0700482 'asan': SimpleConfig('asan', timeout_multiplier=1.5, environ={
Craig Tillerd4b13622015-05-29 09:10:10 -0700483 'ASAN_OPTIONS': 'detect_leaks=1:color=always:suppressions=tools/tsan_suppressions.txt',
484 'LSAN_OPTIONS': 'report_objects=1'}),
Craig Tiller810725c2015-05-12 09:44:41 -0700485 'asan-noleaks': SimpleConfig('asan', environ={
486 'ASAN_OPTIONS': 'detect_leaks=0:color=always:suppressions=tools/tsan_suppressions.txt'}),
Craig Tillerb50d1662015-01-15 17:28:21 -0800487 'gcov': SimpleConfig('gcov'),
Craig Tiller1a305b12015-02-18 13:37:06 -0800488 'memcheck': ValgrindConfig('valgrind', 'memcheck', ['--leak-check=full']),
Craig Tillerb50d1662015-01-15 17:28:21 -0800489 'helgrind': ValgrindConfig('dbg', 'helgrind')
490 }
Craig Tiller738c3342015-01-12 14:28:33 -0800491
492
Nicolas "Pixel" Noble1fb5e822015-03-16 06:20:37 +0100493_DEFAULT = ['opt']
Craig Tillerc7449162015-01-16 14:42:10 -0800494_LANGUAGES = {
Craig Tillere9c959d2015-01-18 10:23:26 -0800495 'c++': CLanguage('cxx', 'c++'),
496 'c': CLanguage('c', 'c'),
murgatroid992c8d5162015-01-26 10:41:21 -0800497 'node': NodeLanguage(),
Nathaniel Manista840615e2015-01-22 20:31:47 +0000498 'php': PhpLanguage(),
499 'python': PythonLanguage(),
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800500 'ruby': RubyLanguage(),
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100501 'csharp': CSharpLanguage(),
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700502 'objc' : ObjCLanguage(),
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100503 'sanity': Sanity(),
Nicolas "Pixel" Noblefd2b0932015-03-26 00:26:29 +0100504 'build': Build(),
Craig Tillereb272bc2015-01-30 13:13:14 -0800505 }
Nicolas Nobleddef2462015-01-06 18:08:25 -0800506
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700507_WINDOWS_CONFIG = {
508 'dbg': 'Debug',
509 'opt': 'Release',
510 }
511
David Garcia Quintase90cd372015-05-31 18:15:26 -0700512
513def runs_per_test_type(arg_str):
514 """Auxilary function to parse the "runs_per_test" flag.
515
516 Returns:
517 A positive integer or 0, the latter indicating an infinite number of
518 runs.
519
520 Raises:
521 argparse.ArgumentTypeError: Upon invalid input.
522 """
523 if arg_str == 'inf':
524 return 0
525 try:
526 n = int(arg_str)
527 if n <= 0: raise ValueError
Craig Tiller50e53e22015-06-01 20:18:21 -0700528 return n
David Garcia Quintase90cd372015-05-31 18:15:26 -0700529 except:
Adele Zhoue4c35612015-10-16 15:34:23 -0700530 msg = '\'{}\' is not a positive integer or \'inf\''.format(arg_str)
David Garcia Quintase90cd372015-05-31 18:15:26 -0700531 raise argparse.ArgumentTypeError(msg)
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700532
533# parse command line
534argp = argparse.ArgumentParser(description='Run grpc tests.')
535argp.add_argument('-c', '--config',
536 choices=['all'] + sorted(_CONFIGS.keys()),
537 nargs='+',
538 default=_DEFAULT)
David Garcia Quintase90cd372015-05-31 18:15:26 -0700539argp.add_argument('-n', '--runs_per_test', default=1, type=runs_per_test_type,
540 help='A positive integer or "inf". If "inf", all tests will run in an '
541 'infinite loop. Especially useful in combination with "-f"')
Craig Tillerfe406ec2015-02-24 13:55:12 -0800542argp.add_argument('-r', '--regex', default='.*', type=str)
Craig Tiller83762ac2015-05-22 14:04:06 -0700543argp.add_argument('-j', '--jobs', default=2 * multiprocessing.cpu_count(), type=int)
Craig Tiller8451e872015-02-27 09:25:51 -0800544argp.add_argument('-s', '--slowdown', default=1.0, type=float)
ctiller3040cb72015-01-07 12:13:17 -0800545argp.add_argument('-f', '--forever',
546 default=False,
547 action='store_const',
548 const=True)
Nicolas "Pixel" Noblea7df3f92015-02-26 22:07:04 +0100549argp.add_argument('-t', '--travis',
550 default=False,
551 action='store_const',
552 const=True)
Nicolas Noble044db742015-01-14 16:57:24 -0800553argp.add_argument('--newline_on_success',
554 default=False,
555 action='store_const',
556 const=True)
Craig Tiller686fb262015-01-15 07:39:09 -0800557argp.add_argument('-l', '--language',
Craig Tiller60f15e62015-05-13 09:05:17 -0700558 choices=['all'] + sorted(_LANGUAGES.keys()),
Craig Tiller686fb262015-01-15 07:39:09 -0800559 nargs='+',
Craig Tiller60f15e62015-05-13 09:05:17 -0700560 default=['all'])
Craig Tillercd43da82015-05-29 08:41:29 -0700561argp.add_argument('-S', '--stop_on_failure',
562 default=False,
563 action='store_const',
564 const=True)
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700565argp.add_argument('--use_docker',
566 default=False,
567 action='store_const',
568 const=True,
Adele Zhoue4c35612015-10-16 15:34:23 -0700569 help='Run all the tests under docker. That provides ' +
570 'additional isolation and prevents the need to install ' +
571 'language specific prerequisites. Only available on Linux.')
Craig Tillerd4509a12015-09-28 09:18:40 -0700572argp.add_argument('--allow_flakes',
573 default=False,
574 action='store_const',
575 const=True,
Adele Zhoue4c35612015-10-16 15:34:23 -0700576 help='Allow flaky tests to show as passing (re-runs failed tests up to five times)')
Craig Tiller234b6e72015-05-23 10:12:40 -0700577argp.add_argument('-a', '--antagonists', default=0, type=int)
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +0200578argp.add_argument('-x', '--xml_report', default=None, type=str,
579 help='Generates a JUnit-compatible XML report')
Nicolas Nobleddef2462015-01-06 18:08:25 -0800580args = argp.parse_args()
581
Jan Tattermuschc96b9eb2015-09-18 16:01:21 -0700582if args.use_docker:
583 if not args.travis:
584 print 'Seen --use_docker flag, will run tests under docker.'
585 print
586 print 'IMPORTANT: The changes you are testing need to be locally committed'
587 print 'because only the committed changes in the current branch will be'
588 print 'copied to the docker environment.'
589 time.sleep(5)
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700590
591 child_argv = [ arg for arg in sys.argv if not arg == '--use_docker' ]
Adele Zhoue4c35612015-10-16 15:34:23 -0700592 run_tests_cmd = 'tools/run_tests/run_tests.py %s' % ' '.join(child_argv[1:])
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700593
594 # TODO(jtattermusch): revisit if we need special handling for arch here
595 # set arch command prefix in case we are working with different arch.
596 arch_env = os.getenv('arch')
597 if arch_env:
598 run_test_cmd = 'arch %s %s' % (arch_env, run_test_cmd)
599
600 env = os.environ.copy()
601 env['RUN_TESTS_COMMAND'] = run_tests_cmd
602 if args.xml_report:
603 env['XML_REPORT'] = args.xml_report
Jan Tattermusch261b58c2015-09-18 17:15:48 -0700604 if not args.travis:
605 env['TTY_FLAG'] = '-t' # enables Ctrl-C when not on Jenkins.
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700606
607 subprocess.check_call(['tools/jenkins/build_docker_and_run_tests.sh'],
608 shell=True,
609 env=env)
610 sys.exit(0)
611
Nicolas Nobleddef2462015-01-06 18:08:25 -0800612# grab config
Craig Tiller738c3342015-01-12 14:28:33 -0800613run_configs = set(_CONFIGS[cfg]
614 for cfg in itertools.chain.from_iterable(
615 _CONFIGS.iterkeys() if x == 'all' else [x]
616 for x in args.config))
617build_configs = set(cfg.build_config for cfg in run_configs)
Craig Tillerf1973b02015-01-16 12:32:13 -0800618
Craig Tiller06805272015-06-11 14:46:47 -0700619if args.travis:
murgatroid99d3b5b7f2015-10-06 17:02:03 -0700620 _FORCE_ENVIRON_FOR_WRAPPERS = {'GRPC_TRACE': 'api'}
Craig Tiller06805272015-06-11 14:46:47 -0700621
Craig Tiller60f15e62015-05-13 09:05:17 -0700622languages = set(_LANGUAGES[l]
623 for l in itertools.chain.from_iterable(
624 _LANGUAGES.iterkeys() if x == 'all' else [x]
625 for x in args.language))
murgatroid99132ce6a2015-03-04 17:29:14 -0800626
627if len(build_configs) > 1:
628 for language in languages:
629 if not language.supports_multi_config():
630 print language, 'does not support multiple build configurations'
631 sys.exit(1)
632
Craig Tiller5058c692015-04-08 09:42:04 -0700633if platform.system() == 'Windows':
murgatroid99a3e244f2015-09-22 11:25:53 -0700634 def make_jobspec(cfg, targets, makefile='Makefile'):
Craig Tillerfc3c0c42015-09-01 16:47:54 -0700635 extra_args = []
Craig Tillerb5391e12015-09-03 14:35:18 -0700636 # better do parallel compilation
Jan Tattermusch47eeb2b2015-10-07 14:09:18 -0700637 # empirically /m:2 gives the best performance/price and should prevent
638 # overloading the windows workers.
Adele Zhoue4c35612015-10-16 15:34:23 -0700639 extra_args.extend(['/m:2'])
Craig Tillerb5391e12015-09-03 14:35:18 -0700640 # disable PDB generation: it's broken, and we don't need it during CI
Adele Zhoue4c35612015-10-16 15:34:23 -0700641 extra_args.extend(['/p:Jenkins=true'])
Craig Tiller6fd23842015-09-01 07:36:31 -0700642 return [
murgatroid99cf08daf2015-09-21 15:33:16 -0700643 jobset.JobSpec(['vsprojects\\build.bat',
644 'vsprojects\\%s.sln' % target,
Craig Tillerfc3c0c42015-09-01 16:47:54 -0700645 '/p:Configuration=%s' % _WINDOWS_CONFIG[cfg]] +
646 extra_args,
Craig Tillerdfc3eee2015-09-01 16:32:16 -0700647 shell=True, timeout_seconds=90*60)
Craig Tiller6fd23842015-09-01 07:36:31 -0700648 for target in targets]
Craig Tiller5058c692015-04-08 09:42:04 -0700649else:
murgatroid99a3e244f2015-09-22 11:25:53 -0700650 def make_jobspec(cfg, targets, makefile='Makefile'):
murgatroid998ae409f2015-10-26 16:39:00 -0700651 if targets:
652 return [jobset.JobSpec([os.getenv('MAKE', 'make'),
653 '-f', makefile,
654 '-j', '%d' % (multiprocessing.cpu_count() + 1),
655 'EXTRA_DEFINES=GRPC_TEST_SLOWDOWN_MACHINE_FACTOR=%f' %
656 args.slowdown,
657 'CONFIG=%s' % cfg] + targets,
658 timeout_seconds=30*60)]
659 else:
660 return []
murgatroid99a3e244f2015-09-22 11:25:53 -0700661make_targets = {}
662for l in languages:
663 makefile = l.makefile_name()
664 make_targets[makefile] = make_targets.get(makefile, set()).union(
665 set(l.make_targets()))
Craig Tiller5058c692015-04-08 09:42:04 -0700666
murgatroid99fddac962015-09-22 09:20:11 -0700667build_steps = list(set(
Nicolas "Pixel" Noble351da8d2015-10-08 02:55:08 +0200668 jobset.JobSpec(cmdline, environ={'CONFIG': cfg}, flake_retries=5)
murgatroid99256d3df2015-09-21 16:58:02 -0700669 for cfg in build_configs
670 for l in languages
671 for cmdline in l.pre_build_steps()))
Craig Tillerbd4e3782015-09-01 06:48:55 -0700672if make_targets:
murgatroid99a3e244f2015-09-22 11:25:53 -0700673 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 -0700674 build_steps.extend(set(make_commands))
Craig Tiller5058c692015-04-08 09:42:04 -0700675build_steps.extend(set(
Jan Tattermusch21897192015-10-07 15:42:21 -0700676 jobset.JobSpec(cmdline, environ={'CONFIG': cfg}, timeout_seconds=10*60)
murgatroid99132ce6a2015-03-04 17:29:14 -0800677 for cfg in build_configs
Craig Tiller547db2b2015-01-30 14:08:39 -0800678 for l in languages
Craig Tiller533b1a22015-05-29 08:41:29 -0700679 for cmdline in l.build_steps()))
Craig Tillerf1973b02015-01-16 12:32:13 -0800680
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200681post_tests_steps = list(set(
682 jobset.JobSpec(cmdline, environ={'CONFIG': cfg})
683 for cfg in build_configs
684 for l in languages
685 for cmdline in l.post_tests_steps()))
Nicolas Nobleddef2462015-01-06 18:08:25 -0800686runs_per_test = args.runs_per_test
ctiller3040cb72015-01-07 12:13:17 -0800687forever = args.forever
Nicolas Nobleddef2462015-01-06 18:08:25 -0800688
Nicolas Nobleddef2462015-01-06 18:08:25 -0800689
Craig Tiller71735182015-01-15 17:07:13 -0800690class TestCache(object):
Craig Tillerb50d1662015-01-15 17:28:21 -0800691 """Cache for running tests."""
692
David Klempner25739582015-02-11 15:57:32 -0800693 def __init__(self, use_cache_results):
Craig Tiller71735182015-01-15 17:07:13 -0800694 self._last_successful_run = {}
David Klempner25739582015-02-11 15:57:32 -0800695 self._use_cache_results = use_cache_results
Craig Tiller69cd2372015-06-11 09:38:09 -0700696 self._last_save = time.time()
Craig Tiller71735182015-01-15 17:07:13 -0800697
698 def should_run(self, cmdline, bin_hash):
Craig Tiller71735182015-01-15 17:07:13 -0800699 if cmdline not in self._last_successful_run:
700 return True
701 if self._last_successful_run[cmdline] != bin_hash:
702 return True
David Klempner25739582015-02-11 15:57:32 -0800703 if not self._use_cache_results:
704 return True
Craig Tiller71735182015-01-15 17:07:13 -0800705 return False
706
707 def finished(self, cmdline, bin_hash):
Craig Tiller547db2b2015-01-30 14:08:39 -0800708 self._last_successful_run[cmdline] = bin_hash
Craig Tiller69cd2372015-06-11 09:38:09 -0700709 if time.time() - self._last_save > 1:
710 self.save()
Craig Tiller71735182015-01-15 17:07:13 -0800711
712 def dump(self):
Craig Tillerb50d1662015-01-15 17:28:21 -0800713 return [{'cmdline': k, 'hash': v}
714 for k, v in self._last_successful_run.iteritems()]
Craig Tiller71735182015-01-15 17:07:13 -0800715
716 def parse(self, exdump):
717 self._last_successful_run = dict((o['cmdline'], o['hash']) for o in exdump)
718
719 def save(self):
720 with open('.run_tests_cache', 'w') as f:
Craig Tiller261dd982015-01-16 16:41:45 -0800721 f.write(json.dumps(self.dump()))
Craig Tiller69cd2372015-06-11 09:38:09 -0700722 self._last_save = time.time()
Craig Tiller71735182015-01-15 17:07:13 -0800723
Craig Tiller1cc11db2015-01-15 22:50:50 -0800724 def maybe_load(self):
725 if os.path.exists('.run_tests_cache'):
726 with open('.run_tests_cache') as f:
Craig Tiller261dd982015-01-16 16:41:45 -0800727 self.parse(json.loads(f.read()))
Craig Tiller71735182015-01-15 17:07:13 -0800728
729
Craig Tillerf53d9c82015-08-04 14:19:43 -0700730def _start_port_server(port_server_port):
731 # check if a compatible port server is running
732 # if incompatible (version mismatch) ==> start a new one
733 # if not running ==> start a new one
734 # otherwise, leave it up
735 try:
Craig Tillerfe4939f2015-10-06 12:55:36 -0700736 version = int(urllib2.urlopen(
737 'http://localhost:%d/version_number' % port_server_port,
738 timeout=1).read())
739 print 'detected port server running version %d' % version
Craig Tillerf53d9c82015-08-04 14:19:43 -0700740 running = True
Craig Tillerfe4939f2015-10-06 12:55:36 -0700741 except Exception as e:
Craig Tiller0d6499e2015-10-05 14:00:47 -0700742 print 'failed to detect port server: %s' % sys.exc_info()[0]
Craig Tillerfe4939f2015-10-06 12:55:36 -0700743 print e.strerror
Craig Tillerf53d9c82015-08-04 14:19:43 -0700744 running = False
745 if running:
Craig Tillerfe4939f2015-10-06 12:55:36 -0700746 current_version = int(subprocess.check_output(
747 [sys.executable, 'tools/run_tests/port_server.py', 'dump_version']))
748 print 'my port server is version %d' % current_version
749 running = (version >= current_version)
750 if not running:
751 print 'port_server version mismatch: killing the old one'
752 urllib2.urlopen('http://localhost:%d/quitquitquit' % port_server_port).read()
753 time.sleep(1)
Craig Tillerf53d9c82015-08-04 14:19:43 -0700754 if not running:
Craig Tillerf0a293e2015-10-12 10:05:50 -0700755 fd, logfile = tempfile.mkstemp()
756 os.close(fd)
757 print 'starting port_server, with log file %s' % logfile
Craig Tillerd2c39712015-10-12 11:08:49 -0700758 args = [sys.executable, 'tools/run_tests/port_server.py', '-p', '%d' % port_server_port, '-l', logfile]
Craig Tiller367d41d2015-10-12 13:00:22 -0700759 env = dict(os.environ)
760 env['BUILD_ID'] = 'pleaseDontKillMeJenkins'
Craig Tillerd2c39712015-10-12 11:08:49 -0700761 if platform.system() == 'Windows':
762 port_server = subprocess.Popen(
Craig Tiller367d41d2015-10-12 13:00:22 -0700763 args,
764 env=env,
765 creationflags = 0x00000008, # detached process
766 close_fds=True)
Craig Tillerd2c39712015-10-12 11:08:49 -0700767 else:
768 port_server = subprocess.Popen(
769 args,
Craig Tiller367d41d2015-10-12 13:00:22 -0700770 env=env,
Craig Tillerd2c39712015-10-12 11:08:49 -0700771 preexec_fn=os.setsid,
772 close_fds=True)
Craig Tillerf0a293e2015-10-12 10:05:50 -0700773 time.sleep(1)
Craig Tiller8b5f4dc2015-08-26 08:02:01 -0700774 # ensure port server is up
Craig Tillerabd37fd2015-08-26 07:54:01 -0700775 waits = 0
Craig Tillerf53d9c82015-08-04 14:19:43 -0700776 while True:
Craig Tillerabd37fd2015-08-26 07:54:01 -0700777 if waits > 10:
Craig Tillerf0a293e2015-10-12 10:05:50 -0700778 print 'killing port server due to excessive start up waits'
Craig Tillerabd37fd2015-08-26 07:54:01 -0700779 port_server.kill()
Craig Tillera2f38b02015-09-24 11:19:17 -0700780 if port_server.poll() is not None:
Craig Tiller0d6499e2015-10-05 14:00:47 -0700781 print 'port_server failed to start'
Craig Tillerf0a293e2015-10-12 10:05:50 -0700782 # try one final time: maybe another build managed to start one
783 time.sleep(1)
784 try:
785 urllib2.urlopen('http://localhost:%d/get' % port_server_port,
786 timeout=1).read()
787 print 'last ditch attempt to contact port server succeeded'
788 break
789 except:
790 traceback.print_exc();
791 port_log = open(logfile, 'r').read()
792 print port_log
793 sys.exit(1)
Craig Tillerf53d9c82015-08-04 14:19:43 -0700794 try:
Craig Tillerabd37fd2015-08-26 07:54:01 -0700795 urllib2.urlopen('http://localhost:%d/get' % port_server_port,
796 timeout=1).read()
Craig Tillerf0a293e2015-10-12 10:05:50 -0700797 print 'port server is up and ready'
Craig Tillerf53d9c82015-08-04 14:19:43 -0700798 break
Craig Tiller31fdaa42015-09-25 13:09:59 -0700799 except socket.timeout:
Craig Tiller0d6499e2015-10-05 14:00:47 -0700800 print 'waiting for port_server: timeout'
Craig Tillerf0a293e2015-10-12 10:05:50 -0700801 traceback.print_exc();
802 time.sleep(1)
Craig Tiller31fdaa42015-09-25 13:09:59 -0700803 waits += 1
Craig Tillerf53d9c82015-08-04 14:19:43 -0700804 except urllib2.URLError:
Craig Tiller0d6499e2015-10-05 14:00:47 -0700805 print 'waiting for port_server: urlerror'
Craig Tillerf0a293e2015-10-12 10:05:50 -0700806 traceback.print_exc();
807 time.sleep(1)
Craig Tillerabd37fd2015-08-26 07:54:01 -0700808 waits += 1
Craig Tillerf53d9c82015-08-04 14:19:43 -0700809 except:
Craig Tillerf0a293e2015-10-12 10:05:50 -0700810 traceback.print_exc();
Craig Tillerf53d9c82015-08-04 14:19:43 -0700811 port_server.kill()
812 raise
813
814
Adele Zhoud5fffa52015-10-23 15:51:42 -0700815def _calculate_num_runs_failures(list_of_results):
816 """Caculate number of runs and failures for a particular test.
817
818 Args:
819 list_of_results: (List) of JobResult object.
820 Returns:
821 A tuple of total number of runs and failures.
822 """
823 num_runs = len(list_of_results) # By default, there is 1 run per JobResult.
824 num_failures = 0
825 for jobresult in list_of_results:
826 if jobresult.retries > 0:
827 num_runs += jobresult.retries
828 if jobresult.num_failures > 0:
829 num_failures += jobresult.num_failures
830 return num_runs, num_failures
831
Craig Tillerf53d9c82015-08-04 14:19:43 -0700832def _build_and_run(
833 check_cancelled, newline_on_success, travis, cache, xml_report=None):
ctiller3040cb72015-01-07 12:13:17 -0800834 """Do one pass of building & running tests."""
murgatroid99666450e2015-01-26 13:03:31 -0800835 # build latest sequentially
Adele Zhoue4c35612015-10-16 15:34:23 -0700836 num_failures, _ = jobset.run(
837 build_steps, maxjobs=1, stop_on_failure=True,
838 newline_on_success=newline_on_success, travis=travis)
839 if num_failures:
Craig Tillerd86a3942015-01-14 12:48:54 -0800840 return 1
ctiller3040cb72015-01-07 12:13:17 -0800841
Craig Tiller234b6e72015-05-23 10:12:40 -0700842 # start antagonists
David Garcia Quintas79e389f2015-06-02 17:49:42 -0700843 antagonists = [subprocess.Popen(['tools/run_tests/antagonist.py'])
Craig Tiller234b6e72015-05-23 10:12:40 -0700844 for _ in range(0, args.antagonists)]
Craig Tillerfe4939f2015-10-06 12:55:36 -0700845 port_server_port = 32767
Craig Tillerf53d9c82015-08-04 14:19:43 -0700846 _start_port_server(port_server_port)
Adele Zhou7cf72112015-11-04 11:18:43 -0800847 resultset = None
Craig Tiller234b6e72015-05-23 10:12:40 -0700848 try:
David Garcia Quintase90cd372015-05-31 18:15:26 -0700849 infinite_runs = runs_per_test == 0
yang-g6c1fdc62015-08-18 11:57:42 -0700850 one_run = set(
851 spec
852 for config in run_configs
853 for language in languages
854 for spec in language.test_specs(config, args.travis)
855 if re.search(args.regex, spec.shortname))
David Garcia Quintas79e389f2015-06-02 17:49:42 -0700856 # When running on travis, we want out test runs to be as similar as possible
857 # for reproducibility purposes.
858 if travis:
859 massaged_one_run = sorted(one_run, key=lambda x: x.shortname)
860 else:
861 # whereas otherwise, we want to shuffle things up to give all tests a
862 # chance to run.
863 massaged_one_run = list(one_run) # random.shuffle needs an indexable seq.
864 random.shuffle(massaged_one_run) # which it modifies in-place.
Craig Tillerf7b7c892015-06-22 14:33:25 -0700865 if infinite_runs:
866 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 -0700867 runs_sequence = (itertools.repeat(massaged_one_run) if infinite_runs
868 else itertools.repeat(massaged_one_run, runs_per_test))
David Garcia Quintase90cd372015-05-31 18:15:26 -0700869 all_runs = itertools.chain.from_iterable(runs_sequence)
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +0200870
Adele Zhoud5fffa52015-10-23 15:51:42 -0700871 number_failures, resultset = jobset.run(
Adele Zhou2271ab52015-10-28 13:59:14 -0700872 all_runs, check_cancelled, newline_on_success=newline_on_success,
Adele Zhouf2ca7bc2015-10-23 15:38:00 -0700873 travis=travis, infinite_runs=infinite_runs, maxjobs=args.jobs,
murgatroid998ae409f2015-10-26 16:39:00 -0700874 stop_on_failure=args.stop_on_failure,
Adele Zhouf2ca7bc2015-10-23 15:38:00 -0700875 cache=cache if not xml_report else None,
Adele Zhouf2ca7bc2015-10-23 15:38:00 -0700876 add_env={'GRPC_TEST_PORT_SERVER': 'localhost:%d' % port_server_port})
Adele Zhoud5fffa52015-10-23 15:51:42 -0700877 if resultset:
878 for k, v in resultset.iteritems():
879 num_runs, num_failures = _calculate_num_runs_failures(v)
880 if num_failures == num_runs: # what about infinite_runs???
881 jobset.message('FAILED', k, do_newline=True)
882 elif num_failures > 0:
883 jobset.message(
884 'FLAKE', '%s [%d/%d runs flaked]' % (k, num_failures, num_runs),
885 do_newline=True)
886 else:
887 jobset.message('PASSED', k, do_newline=True)
Adele Zhouf2ca7bc2015-10-23 15:38:00 -0700888 if number_failures:
Craig Tiller234b6e72015-05-23 10:12:40 -0700889 return 2
890 finally:
891 for antagonist in antagonists:
892 antagonist.kill()
Adele Zhou7cf72112015-11-04 11:18:43 -0800893 if xml_report and resultset:
Adele Zhoua30f8292015-11-02 13:15:46 -0800894 report_utils.render_xml_report(resultset, xml_report)
Craig Tillerd86a3942015-01-14 12:48:54 -0800895
Adele Zhouf2ca7bc2015-10-23 15:38:00 -0700896 number_failures, _ = jobset.run(
897 post_tests_steps, maxjobs=1, stop_on_failure=True,
898 newline_on_success=newline_on_success, travis=travis)
899 if number_failures:
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200900 return 3
901
Craig Tiller69cd2372015-06-11 09:38:09 -0700902 if cache: cache.save()
903
Craig Tillerd86a3942015-01-14 12:48:54 -0800904 return 0
ctiller3040cb72015-01-07 12:13:17 -0800905
906
David Klempner25739582015-02-11 15:57:32 -0800907test_cache = TestCache(runs_per_test == 1)
Craig Tiller547db2b2015-01-30 14:08:39 -0800908test_cache.maybe_load()
Craig Tiller71735182015-01-15 17:07:13 -0800909
ctiller3040cb72015-01-07 12:13:17 -0800910if forever:
Nicolas Noble044db742015-01-14 16:57:24 -0800911 success = True
ctiller3040cb72015-01-07 12:13:17 -0800912 while True:
Craig Tiller42bc87c2015-02-23 08:50:19 -0800913 dw = watch_dirs.DirWatcher(['src', 'include', 'test', 'examples'])
ctiller3040cb72015-01-07 12:13:17 -0800914 initial_time = dw.most_recent_change()
915 have_files_changed = lambda: dw.most_recent_change() != initial_time
Nicolas Noble044db742015-01-14 16:57:24 -0800916 previous_success = success
Craig Tiller71735182015-01-15 17:07:13 -0800917 success = _build_and_run(check_cancelled=have_files_changed,
Nicolas Nobleb09078f2015-01-14 18:06:05 -0800918 newline_on_success=False,
Craig Tiller9a5a9402015-04-16 10:39:50 -0700919 travis=args.travis,
Craig Tiller71735182015-01-15 17:07:13 -0800920 cache=test_cache) == 0
Nicolas Noble044db742015-01-14 16:57:24 -0800921 if not previous_success and success:
Nicolas Nobleb09078f2015-01-14 18:06:05 -0800922 jobset.message('SUCCESS',
923 'All tests are now passing properly',
924 do_newline=True)
Nicolas Noble044db742015-01-14 16:57:24 -0800925 jobset.message('IDLE', 'No change detected')
ctiller3040cb72015-01-07 12:13:17 -0800926 while not have_files_changed():
927 time.sleep(1)
928else:
Craig Tiller71735182015-01-15 17:07:13 -0800929 result = _build_and_run(check_cancelled=lambda: False,
930 newline_on_success=args.newline_on_success,
Nicolas "Pixel" Noblea7df3f92015-02-26 22:07:04 +0100931 travis=args.travis,
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +0200932 cache=test_cache,
933 xml_report=args.xml_report)
Nicolas Nobleb09078f2015-01-14 18:06:05 -0800934 if result == 0:
935 jobset.message('SUCCESS', 'All tests passed', do_newline=True)
936 else:
937 jobset.message('FAILED', 'Some tests failed', do_newline=True)
938 sys.exit(result)