blob: 885a79c07b096afd8f1701bc7aafb05063dae04d [file] [log] [blame]
Nathaniel Manistaae4fbcd2015-09-23 16:29:44 +00001#!/usr/bin/env python2.7
Craig Tiller40839772016-01-05 12:34:49 -08002# Copyright 2015-2016, Google Inc.
Craig Tillerc2c79212015-02-16 12:00:01 -08003# 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
Craig Tiller9279ac22016-01-20 17:05:23 -080034import ast
Nicolas Nobleddef2462015-01-06 18:08:25 -080035import glob
Craig Tillerf53d9c82015-08-04 14:19:43 -070036import hashlib
Nicolas Nobleddef2462015-01-06 18:08:25 -080037import itertools
Craig Tiller261dd982015-01-16 16:41:45 -080038import json
Nicolas Nobleddef2462015-01-06 18:08:25 -080039import multiprocessing
Craig Tiller1cc11db2015-01-15 22:50:50 -080040import os
David Garcia Quintas79e389f2015-06-02 17:49:42 -070041import platform
42import random
Craig Tillerfe406ec2015-02-24 13:55:12 -080043import re
Craig Tiller82875232015-09-25 13:57:34 -070044import socket
David Garcia Quintas79e389f2015-06-02 17:49:42 -070045import subprocess
Nicolas Nobleddef2462015-01-06 18:08:25 -080046import sys
Craig Tillerf0a293e2015-10-12 10:05:50 -070047import tempfile
48import traceback
ctiller3040cb72015-01-07 12:13:17 -080049import time
Craig Tillerf53d9c82015-08-04 14:19:43 -070050import urllib2
Jan Tattermusch03c01062015-12-11 14:28:56 -080051import uuid
Nicolas Nobleddef2462015-01-06 18:08:25 -080052
53import jobset
Adele Zhoua30f8292015-11-02 13:15:46 -080054import report_utils
ctiller3040cb72015-01-07 12:13:17 -080055import watch_dirs
Nicolas Nobleddef2462015-01-06 18:08:25 -080056
Craig Tillerb361b4e2016-01-06 11:44:17 -080057
Craig Tiller2cc2b842015-02-27 11:38:31 -080058ROOT = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), '../..'))
59os.chdir(ROOT)
60
61
Craig Tiller06805272015-06-11 14:46:47 -070062_FORCE_ENVIRON_FOR_WRAPPERS = {}
63
64
Craig Tillerd50993d2015-08-05 08:04:36 -070065def platform_string():
Nicolas "Pixel" Noblef72d7b52015-12-03 03:07:43 +010066 return jobset.platform_string()
Craig Tillerd50993d2015-08-05 08:04:36 -070067
68
Craig Tiller738c3342015-01-12 14:28:33 -080069# SimpleConfig: just compile with CONFIG=config, and run the binary to test
Craig Tillera0f85172016-01-20 15:56:06 -080070class Config(object):
Craig Tillerb50d1662015-01-15 17:28:21 -080071
Craig Tillera0f85172016-01-20 15:56:06 -080072 def __init__(self, config, environ=None, timeout_multiplier=1, tool_prefix=[]):
murgatroid99132ce6a2015-03-04 17:29:14 -080073 if environ is None:
74 environ = {}
Craig Tiller738c3342015-01-12 14:28:33 -080075 self.build_config = config
Craig Tillerc7449162015-01-16 14:42:10 -080076 self.allow_hashing = (config != 'gcov')
Craig Tiller547db2b2015-01-30 14:08:39 -080077 self.environ = environ
murgatroid99132ce6a2015-03-04 17:29:14 -080078 self.environ['CONFIG'] = config
Craig Tillera0f85172016-01-20 15:56:06 -080079 self.tool_prefix = tool_prefix
Masood Malekghassemi26ea9e22015-10-09 15:19:17 -070080 self.timeout_multiplier = timeout_multiplier
Craig Tiller738c3342015-01-12 14:28:33 -080081
Masood Malekghassemi26ea9e22015-10-09 15:19:17 -070082 def job_spec(self, cmdline, hash_targets, timeout_seconds=5*60,
Craig Tiller56c6b6a2016-01-20 08:27:37 -080083 shortname=None, environ={}, cpu_cost=1.0):
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 Tillera0f85172016-01-20 15:56:06 -080098 return jobset.JobSpec(cmdline=self.tool_prefix + cmdline,
Jan Tattermusch9a7d30c2015-04-23 16:12:55 -070099 shortname=shortname,
Craig Tiller4fc90032015-05-21 10:39:52 -0700100 environ=actual_environ,
Craig Tiller56c6b6a2016-01-20 08:27:37 -0800101 cpu_cost=cpu_cost,
Craig Tiller94d04a52016-01-20 10:58:23 -0800102 timeout_seconds=(self.timeout_multiplier * timeout_seconds if timeout_seconds else None),
Craig Tiller547db2b2015-01-30 14:08:39 -0800103 hash_targets=hash_targets
Craig Tillerd4509a12015-09-28 09:18:40 -0700104 if self.allow_hashing else None,
Craig Tiller35505de2015-10-08 13:31:33 -0700105 flake_retries=5 if args.allow_flakes else 0,
106 timeout_retries=3 if args.allow_flakes else 0)
Craig Tiller738c3342015-01-12 14:28:33 -0800107
108
murgatroid99cf08daf2015-09-21 15:33:16 -0700109def get_c_tests(travis, test_lang) :
110 out = []
111 platforms_str = 'ci_platforms' if travis else 'platforms'
112 with open('tools/run_tests/tests.json') as f:
murgatroid9989899b12015-09-22 09:14:48 -0700113 js = json.load(f)
murgatroid99a3e244f2015-09-22 11:25:53 -0700114 return [tgt
115 for tgt in js
116 if tgt['language'] == test_lang and
117 platform_string() in tgt[platforms_str] and
118 not (travis and tgt['flaky'])]
murgatroid99cf08daf2015-09-21 15:33:16 -0700119
murgatroid99fafeeb32015-09-22 09:13:03 -0700120
Craig Tillerc7449162015-01-16 14:42:10 -0800121class CLanguage(object):
122
Craig Tillere9c959d2015-01-18 10:23:26 -0800123 def __init__(self, make_target, test_lang):
Craig Tillerc7449162015-01-16 14:42:10 -0800124 self.make_target = make_target
Craig Tillerd50993d2015-08-05 08:04:36 -0700125 self.platform = platform_string()
Craig Tiller711bbe62015-08-19 12:35:16 -0700126 self.test_lang = test_lang
Craig Tillerc7449162015-01-16 14:42:10 -0800127
Craig Tiller883064c2015-11-04 10:06:10 -0800128 def test_specs(self, config, args):
Craig Tiller547db2b2015-01-30 14:08:39 -0800129 out = []
Craig Tiller883064c2015-11-04 10:06:10 -0800130 binaries = get_c_tests(args.travis, self.test_lang)
Craig Tiller711bbe62015-08-19 12:35:16 -0700131 for target in binaries:
murgatroid99a3e244f2015-09-22 11:25:53 -0700132 if config.build_config in target['exclude_configs']:
murgatroid99fafeeb32015-09-22 09:13:03 -0700133 continue
Nicolas Noblee1445362015-05-11 17:40:26 -0700134 if self.platform == 'windows':
Craig Tillerf4182602015-09-01 12:23:16 -0700135 binary = 'vsprojects/%s/%s.exe' % (
136 _WINDOWS_CONFIG[config.build_config], target['name'])
Nicolas Noblee1445362015-05-11 17:40:26 -0700137 else:
138 binary = 'bins/%s/%s' % (config.build_config, target['name'])
yang-g6c1fdc62015-08-18 11:57:42 -0700139 if os.path.isfile(binary):
Craig Tiller0fe5ee72015-12-22 12:50:36 -0800140 cmdline = [binary] + target['args']
141 out.append(config.job_spec(cmdline, [binary],
142 shortname=' '.join(cmdline),
Craig Tiller56c6b6a2016-01-20 08:27:37 -0800143 cpu_cost=target['cpu_cost'],
Craig Tillercc0535d2015-12-08 15:14:47 -0800144 environ={'GRPC_DEFAULT_SSL_ROOTS_FILE_PATH':
145 os.path.abspath(os.path.dirname(
Craig Tillered2164d2015-12-08 22:03:36 -0800146 sys.argv[0]) + '/../../src/core/tsi/test_creds/ca.pem')}))
Craig Tiller883064c2015-11-04 10:06:10 -0800147 elif args.regex == '.*' or platform_string() == 'windows':
Adele Zhoue4c35612015-10-16 15:34:23 -0700148 print '\nWARNING: binary not found, skipping', binary
Nicolas Noblee1445362015-05-11 17:40:26 -0700149 return sorted(out)
Craig Tillerc7449162015-01-16 14:42:10 -0800150
Craig Tiller883064c2015-11-04 10:06:10 -0800151 def make_targets(self, test_regex):
152 if platform_string() != 'windows' and test_regex != '.*':
153 # use the regex to minimize the number of things to build
154 return [target['name']
155 for target in get_c_tests(False, self.test_lang)
156 if re.search(test_regex, target['name'])]
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700157 if platform_string() == 'windows':
158 # don't build tools on windows just yet
159 return ['buildtests_%s' % self.make_target]
Craig Tiller7552f0f2015-06-19 17:46:20 -0700160 return ['buildtests_%s' % self.make_target, 'tools_%s' % self.make_target]
Craig Tillerc7449162015-01-16 14:42:10 -0800161
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800162 def make_options(self):
163 return []
164
murgatroid99256d3df2015-09-21 16:58:02 -0700165 def pre_build_steps(self):
Jan Tattermusch874aec02015-10-07 19:26:19 -0700166 if self.platform == 'windows':
167 return [['tools\\run_tests\\pre_build_c.bat']]
168 else:
169 return []
murgatroid99256d3df2015-09-21 16:58:02 -0700170
Craig Tillerc7449162015-01-16 14:42:10 -0800171 def build_steps(self):
172 return []
173
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200174 def post_tests_steps(self):
175 if self.platform == 'windows':
176 return []
177 else:
178 return [['tools/run_tests/post_tests_c.sh']]
179
murgatroid99a3e244f2015-09-22 11:25:53 -0700180 def makefile_name(self):
181 return 'Makefile'
182
murgatroid99132ce6a2015-03-04 17:29:14 -0800183 def supports_multi_config(self):
184 return True
185
Jan Tattermusch788ee232016-01-26 12:19:44 -0800186 def dockerfile_dir(self, config, arch):
187 return None
188
murgatroid99132ce6a2015-03-04 17:29:14 -0800189 def __str__(self):
190 return self.make_target
191
Craig Tillercc0535d2015-12-08 15:14:47 -0800192
murgatroid992c8d5162015-01-26 10:41:21 -0800193class NodeLanguage(object):
194
Craig Tiller883064c2015-11-04 10:06:10 -0800195 def test_specs(self, config, args):
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):
murgatroid99ae369de2015-10-09 15:40:48 -0700200 # Default to 1 week cache expiration
murgatroid9993758952015-10-14 11:51:05 -0700201 return [['tools/run_tests/pre_build_node.sh']]
murgatroid99256d3df2015-09-21 16:58:02 -0700202
Craig Tiller883064c2015-11-04 10:06:10 -0800203 def make_targets(self, test_regex):
murgatroid99db5b1602015-10-01 13:20:11 -0700204 return []
murgatroid992c8d5162015-01-26 10:41:21 -0800205
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800206 def make_options(self):
207 return []
208
murgatroid992c8d5162015-01-26 10:41:21 -0800209 def build_steps(self):
210 return [['tools/run_tests/build_node.sh']]
Craig Tillerc7449162015-01-16 14:42:10 -0800211
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200212 def post_tests_steps(self):
213 return []
214
murgatroid99a3e244f2015-09-22 11:25:53 -0700215 def makefile_name(self):
216 return 'Makefile'
217
murgatroid99132ce6a2015-03-04 17:29:14 -0800218 def supports_multi_config(self):
219 return False
220
Jan Tattermusch788ee232016-01-26 12:19:44 -0800221 def dockerfile_dir(self, config, arch):
222 return None
223
murgatroid99132ce6a2015-03-04 17:29:14 -0800224 def __str__(self):
225 return 'node'
226
Craig Tiller99775822015-01-30 13:07:16 -0800227
Craig Tillerc7449162015-01-16 14:42:10 -0800228class PhpLanguage(object):
229
Craig Tiller883064c2015-11-04 10:06:10 -0800230 def test_specs(self, config, args):
Craig Tiller4fc90032015-05-21 10:39:52 -0700231 return [config.job_spec(['src/php/bin/run_tests.sh'], None,
Craig Tiller06805272015-06-11 14:46:47 -0700232 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
Craig Tillerc7449162015-01-16 14:42:10 -0800233
murgatroid99256d3df2015-09-21 16:58:02 -0700234 def pre_build_steps(self):
235 return []
236
Craig Tiller883064c2015-11-04 10:06:10 -0800237 def make_targets(self, test_regex):
Craig Tilleraf7cf542015-05-22 10:07:34 -0700238 return ['static_c', 'shared_c']
Craig Tillerc7449162015-01-16 14:42:10 -0800239
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800240 def make_options(self):
241 return []
242
Craig Tillerc7449162015-01-16 14:42:10 -0800243 def build_steps(self):
244 return [['tools/run_tests/build_php.sh']]
245
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200246 def post_tests_steps(self):
Stanley Cheunga6b95482016-01-13 16:10:48 -0800247 return [['tools/run_tests/post_tests_php.sh']]
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200248
murgatroid99a3e244f2015-09-22 11:25:53 -0700249 def makefile_name(self):
250 return 'Makefile'
251
murgatroid99132ce6a2015-03-04 17:29:14 -0800252 def supports_multi_config(self):
253 return False
254
Jan Tattermusch788ee232016-01-26 12:19:44 -0800255 def dockerfile_dir(self, config, arch):
256 return None
257
murgatroid99132ce6a2015-03-04 17:29:14 -0800258 def __str__(self):
259 return 'php'
260
Craig Tillerc7449162015-01-16 14:42:10 -0800261
Nathaniel Manista840615e2015-01-22 20:31:47 +0000262class PythonLanguage(object):
263
Craig Tiller49f61322015-03-03 13:02:11 -0800264 def __init__(self):
Masood Malekghassemi2b841622015-07-28 17:39:02 -0700265 self._build_python_versions = ['2.7']
Masood Malekghassemie5f70022015-06-29 09:20:26 -0700266 self._has_python_versions = []
Craig Tiller49f61322015-03-03 13:02:11 -0800267
Craig Tiller883064c2015-11-04 10:06:10 -0800268 def test_specs(self, config, args):
Masood Malekghassemi2b841622015-07-28 17:39:02 -0700269 environment = dict(_FORCE_ENVIRON_FOR_WRAPPERS)
270 environment['PYVER'] = '2.7'
271 return [config.job_spec(
272 ['tools/run_tests/run_python.sh'],
273 None,
274 environ=environment,
275 shortname='py.test',
Masood Malekghassemi26ea9e22015-10-09 15:19:17 -0700276 timeout_seconds=15*60
Masood Malekghassemi2b841622015-07-28 17:39:02 -0700277 )]
Nathaniel Manista840615e2015-01-22 20:31:47 +0000278
murgatroid99256d3df2015-09-21 16:58:02 -0700279 def pre_build_steps(self):
280 return []
281
Craig Tiller883064c2015-11-04 10:06:10 -0800282 def make_targets(self, test_regex):
Craig Tilleraf7cf542015-05-22 10:07:34 -0700283 return ['static_c', 'grpc_python_plugin', 'shared_c']
Nathaniel Manista840615e2015-01-22 20:31:47 +0000284
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800285 def make_options(self):
286 return []
287
Nathaniel Manista840615e2015-01-22 20:31:47 +0000288 def build_steps(self):
Masood Malekghassemie5f70022015-06-29 09:20:26 -0700289 commands = []
290 for python_version in self._build_python_versions:
291 try:
292 with open(os.devnull, 'w') as output:
293 subprocess.check_call(['which', 'python' + python_version],
294 stdout=output, stderr=output)
295 commands.append(['tools/run_tests/build_python.sh', python_version])
296 self._has_python_versions.append(python_version)
297 except:
298 jobset.message('WARNING', 'Missing Python ' + python_version,
299 do_newline=True)
300 return commands
Nathaniel Manista840615e2015-01-22 20:31:47 +0000301
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200302 def post_tests_steps(self):
303 return []
304
murgatroid99a3e244f2015-09-22 11:25:53 -0700305 def makefile_name(self):
306 return 'Makefile'
307
murgatroid99132ce6a2015-03-04 17:29:14 -0800308 def supports_multi_config(self):
309 return False
310
Jan Tattermusch788ee232016-01-26 12:19:44 -0800311 def dockerfile_dir(self, config, arch):
312 return None
313
murgatroid99132ce6a2015-03-04 17:29:14 -0800314 def __str__(self):
315 return 'python'
316
Craig Tillerd625d812015-04-08 15:52:35 -0700317
murgatroid996a4c4fa2015-02-27 12:08:57 -0800318class RubyLanguage(object):
319
Craig Tiller883064c2015-11-04 10:06:10 -0800320 def test_specs(self, config, args):
Craig Tiller4fc90032015-05-21 10:39:52 -0700321 return [config.job_spec(['tools/run_tests/run_ruby.sh'], None,
Craig Tiller06805272015-06-11 14:46:47 -0700322 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
murgatroid996a4c4fa2015-02-27 12:08:57 -0800323
murgatroid99256d3df2015-09-21 16:58:02 -0700324 def pre_build_steps(self):
Nicolas "Pixel" Noblebcf988f2015-10-08 03:00:42 +0200325 return [['tools/run_tests/pre_build_ruby.sh']]
murgatroid99256d3df2015-09-21 16:58:02 -0700326
Craig Tiller883064c2015-11-04 10:06:10 -0800327 def make_targets(self, test_regex):
murgatroid99a43c14f2015-07-30 13:31:23 -0700328 return ['static_c']
murgatroid996a4c4fa2015-02-27 12:08:57 -0800329
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800330 def make_options(self):
331 return []
332
murgatroid996a4c4fa2015-02-27 12:08:57 -0800333 def build_steps(self):
334 return [['tools/run_tests/build_ruby.sh']]
335
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200336 def post_tests_steps(self):
Nicolas "Pixel" Noble7ef1e532015-12-02 00:55:33 +0100337 return [['tools/run_tests/post_tests_ruby.sh']]
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200338
murgatroid99a3e244f2015-09-22 11:25:53 -0700339 def makefile_name(self):
340 return 'Makefile'
341
murgatroid99132ce6a2015-03-04 17:29:14 -0800342 def supports_multi_config(self):
343 return False
344
Jan Tattermusch788ee232016-01-26 12:19:44 -0800345 def dockerfile_dir(self, config, arch):
346 return None
347
murgatroid99132ce6a2015-03-04 17:29:14 -0800348 def __str__(self):
349 return 'ruby'
350
Craig Tillerd625d812015-04-08 15:52:35 -0700351
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800352class CSharpLanguage(object):
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700353 def __init__(self):
Craig Tillerd50993d2015-08-05 08:04:36 -0700354 self.platform = platform_string()
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700355
Craig Tiller883064c2015-11-04 10:06:10 -0800356 def test_specs(self, config, args):
Jan Tattermusch03c01062015-12-11 14:28:56 -0800357 with open('src/csharp/tests.json') as f:
358 tests_json = json.load(f)
359 assemblies = tests_json['assemblies']
360 tests = tests_json['tests']
361
362 msbuild_config = _WINDOWS_CONFIG[config.build_config]
363 assembly_files = ['%s/bin/%s/%s.dll' % (a, msbuild_config, a)
364 for a in assemblies]
365
366 extra_args = ['-labels'] + assembly_files
367
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700368 if self.platform == 'windows':
Jan Tattermusch03c01062015-12-11 14:28:56 -0800369 script_name = 'tools\\run_tests\\run_csharp.bat'
370 extra_args += ['-domain=None']
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700371 else:
Jan Tattermusch03c01062015-12-11 14:28:56 -0800372 script_name = 'tools/run_tests/run_csharp.sh'
Jan Tattermuschbf3b1532015-10-26 10:24:42 -0700373
Jan Tattermuschbdf4b2e2015-10-28 08:22:34 -0700374 if config.build_config == 'gcov':
375 # On Windows, we only collect C# code coverage.
376 # On Linux, we only collect coverage for native extension.
377 # For code coverage all tests need to run as one suite.
Jan Tattermusch03c01062015-12-11 14:28:56 -0800378 return [config.job_spec([script_name] + extra_args, None,
379 shortname='csharp.coverage',
380 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
Jan Tattermusch61c3a832015-10-27 17:54:50 -0700381 else:
Jan Tattermusch03c01062015-12-11 14:28:56 -0800382 specs = []
383 for test in tests:
384 cmdline = [script_name, '-run=%s' % test] + extra_args
385 if self.platform == 'windows':
386 # use different output directory for each test to prevent
387 # TestResult.xml clash between parallel test runs.
388 cmdline += ['-work=test-result/%s' % uuid.uuid4()]
389 specs.append(config.job_spec(cmdline, None,
390 shortname='csharp.%s' % test,
391 environ=_FORCE_ENVIRON_FOR_WRAPPERS))
392 return specs
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800393
murgatroid99256d3df2015-09-21 16:58:02 -0700394 def pre_build_steps(self):
Jan Tattermusch48423fc2015-10-07 18:59:16 -0700395 if self.platform == 'windows':
Jan Tattermusch874aec02015-10-07 19:26:19 -0700396 return [['tools\\run_tests\\pre_build_csharp.bat']]
Jan Tattermusch48423fc2015-10-07 18:59:16 -0700397 else:
398 return [['tools/run_tests/pre_build_csharp.sh']]
murgatroid99256d3df2015-09-21 16:58:02 -0700399
Craig Tiller883064c2015-11-04 10:06:10 -0800400 def make_targets(self, test_regex):
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700401 # For Windows, this target doesn't really build anything,
402 # everything is build by buildall script later.
Craig Tillerd5904822015-08-31 21:30:58 -0700403 if self.platform == 'windows':
404 return []
405 else:
406 return ['grpc_csharp_ext']
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800407
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800408 def make_options(self):
409 if self.platform == 'mac':
410 # On Mac, official distribution of mono is 32bit.
411 return ['CFLAGS=-arch i386', 'LDFLAGS=-arch i386']
412 else:
413 return []
414
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800415 def build_steps(self):
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700416 if self.platform == 'windows':
417 return [['src\\csharp\\buildall.bat']]
418 else:
419 return [['tools/run_tests/build_csharp.sh']]
Nathaniel Manista840615e2015-01-22 20:31:47 +0000420
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200421 def post_tests_steps(self):
422 return []
423
murgatroid99a3e244f2015-09-22 11:25:53 -0700424 def makefile_name(self):
425 return 'Makefile'
426
murgatroid99132ce6a2015-03-04 17:29:14 -0800427 def supports_multi_config(self):
428 return False
429
Jan Tattermusch788ee232016-01-26 12:19:44 -0800430 def dockerfile_dir(self, config, arch):
431 return None
432
murgatroid99132ce6a2015-03-04 17:29:14 -0800433 def __str__(self):
434 return 'csharp'
435
Craig Tillerd625d812015-04-08 15:52:35 -0700436
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700437class ObjCLanguage(object):
438
Craig Tiller883064c2015-11-04 10:06:10 -0800439 def test_specs(self, config, args):
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700440 return [config.job_spec(['src/objective-c/tests/run_tests.sh'], None,
441 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
442
murgatroid99256d3df2015-09-21 16:58:02 -0700443 def pre_build_steps(self):
444 return []
445
Craig Tiller883064c2015-11-04 10:06:10 -0800446 def make_targets(self, test_regex):
Jorge Canizalesd0b32e92015-07-30 23:08:43 -0700447 return ['grpc_objective_c_plugin', 'interop_server']
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700448
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800449 def make_options(self):
450 return []
451
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700452 def build_steps(self):
Jorge Canizalesd0b32e92015-07-30 23:08:43 -0700453 return [['src/objective-c/tests/build_tests.sh']]
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700454
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200455 def post_tests_steps(self):
456 return []
457
murgatroid99a3e244f2015-09-22 11:25:53 -0700458 def makefile_name(self):
459 return 'Makefile'
460
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700461 def supports_multi_config(self):
462 return False
463
Jan Tattermusch788ee232016-01-26 12:19:44 -0800464 def dockerfile_dir(self, config, arch):
465 return None
466
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700467 def __str__(self):
468 return 'objc'
469
470
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100471class Sanity(object):
472
Craig Tiller883064c2015-11-04 10:06:10 -0800473 def test_specs(self, config, args):
Craig Tiller94d04a52016-01-20 10:58:23 -0800474 import yaml
Jan Tattermusch788ee232016-01-26 12:19:44 -0800475 with open('tools/run_tests/sanity/sanity_tests.yaml', 'r') as f:
476 return [config.job_spec(cmd['script'].split(), None,
477 timeout_seconds=None, environ={'TEST': 'true'},
478 cpu_cost=cmd.get('cpu_cost', 1))
Craig Tiller94d04a52016-01-20 10:58:23 -0800479 for cmd in yaml.load(f)]
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100480
murgatroid99256d3df2015-09-21 16:58:02 -0700481 def pre_build_steps(self):
482 return []
483
Craig Tiller883064c2015-11-04 10:06:10 -0800484 def make_targets(self, test_regex):
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100485 return ['run_dep_checks']
486
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800487 def make_options(self):
488 return []
489
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100490 def build_steps(self):
491 return []
492
Nicolas "Pixel" Noble87879b32015-10-12 23:28:53 +0200493 def post_tests_steps(self):
494 return []
495
murgatroid99a3e244f2015-09-22 11:25:53 -0700496 def makefile_name(self):
497 return 'Makefile'
498
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100499 def supports_multi_config(self):
500 return False
501
Jan Tattermusch788ee232016-01-26 12:19:44 -0800502 def dockerfile_dir(self, config, arch):
503 return 'tools/dockerfile/grpc_sanity'
504
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100505 def __str__(self):
506 return 'sanity'
507
Nicolas "Pixel" Noblee55cd7f2015-04-14 17:59:13 +0200508
Nicolas "Pixel" Noblefd2b0932015-03-26 00:26:29 +0100509class Build(object):
510
Craig Tiller883064c2015-11-04 10:06:10 -0800511 def test_specs(self, config, args):
Nicolas "Pixel" Noblefd2b0932015-03-26 00:26:29 +0100512 return []
513
murgatroid99256d3df2015-09-21 16:58:02 -0700514 def pre_build_steps(self):
515 return []
516
Craig Tiller883064c2015-11-04 10:06:10 -0800517 def make_targets(self, test_regex):
Nicolas "Pixel" Noblec23827b2015-04-23 06:17:55 +0200518 return ['static']
Nicolas "Pixel" Noblefd2b0932015-03-26 00:26:29 +0100519
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800520 def make_options(self):
521 return []
522
Nicolas "Pixel" Noblefd2b0932015-03-26 00:26:29 +0100523 def build_steps(self):
524 return []
525
Nicolas "Pixel" Noblefe300452015-10-27 23:05:10 +0100526 def post_tests_steps(self):
527 return []
528
murgatroid99a3e244f2015-09-22 11:25:53 -0700529 def makefile_name(self):
530 return 'Makefile'
531
Nicolas "Pixel" Noblefd2b0932015-03-26 00:26:29 +0100532 def supports_multi_config(self):
533 return True
534
Jan Tattermusch788ee232016-01-26 12:19:44 -0800535 def dockerfile_dir(self, config, arch):
536 return None
537
Nicolas "Pixel" Noblefd2b0932015-03-26 00:26:29 +0100538 def __str__(self):
539 return self.make_target
540
541
Craig Tiller738c3342015-01-12 14:28:33 -0800542# different configurations we can run under
Craig Tillera0f85172016-01-20 15:56:06 -0800543with open('tools/run_tests/configs.json') as f:
Craig Tiller1dce9062016-01-20 17:01:56 -0800544 _CONFIGS = dict((cfg['config'], Config(**cfg)) for cfg in ast.literal_eval(f.read()))
Craig Tiller738c3342015-01-12 14:28:33 -0800545
546
Nicolas "Pixel" Noble1fb5e822015-03-16 06:20:37 +0100547_DEFAULT = ['opt']
Craig Tillerc7449162015-01-16 14:42:10 -0800548_LANGUAGES = {
Craig Tillere9c959d2015-01-18 10:23:26 -0800549 'c++': CLanguage('cxx', 'c++'),
550 'c': CLanguage('c', 'c'),
murgatroid992c8d5162015-01-26 10:41:21 -0800551 'node': NodeLanguage(),
Nathaniel Manista840615e2015-01-22 20:31:47 +0000552 'php': PhpLanguage(),
553 'python': PythonLanguage(),
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800554 'ruby': RubyLanguage(),
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100555 'csharp': CSharpLanguage(),
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700556 'objc' : ObjCLanguage(),
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100557 'sanity': Sanity(),
Nicolas "Pixel" Noblefd2b0932015-03-26 00:26:29 +0100558 'build': Build(),
Craig Tillereb272bc2015-01-30 13:13:14 -0800559 }
Nicolas Nobleddef2462015-01-06 18:08:25 -0800560
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700561_WINDOWS_CONFIG = {
562 'dbg': 'Debug',
563 'opt': 'Release',
Jan Tattermusche4a69182015-12-15 09:53:01 -0800564 'gcov': 'Debug',
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700565 }
566
David Garcia Quintase90cd372015-05-31 18:15:26 -0700567
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800568def _windows_arch_option(arch):
569 """Returns msbuild cmdline option for selected architecture."""
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800570 if arch == 'default' or arch == 'x86':
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800571 return '/p:Platform=Win32'
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800572 elif arch == 'x64':
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800573 return '/p:Platform=x64'
574 else:
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800575 print 'Architecture %s not supported.' % arch
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800576 sys.exit(1)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800577
Jan Tattermuschf08018a2016-01-26 08:22:09 -0800578
579def _check_arch_option(arch):
580 """Checks that architecture option is valid."""
581 if platform_string() == 'windows':
582 _windows_arch_option(arch)
583 elif platform_string() == 'linux':
584 # On linux, we need to be running under docker with the right architecture.
Jan Tattermusch07fb0422016-01-26 10:46:56 -0800585 runtime_arch = platform.architecture()[0]
Jan Tattermuschf08018a2016-01-26 08:22:09 -0800586 if arch == 'default':
587 return
588 elif runtime_arch == '64bit' and arch == 'x64':
589 return
590 elif runtime_arch == '32bit' and arch == 'x86':
591 return
592 else:
593 print 'Architecture %s does not match current runtime architecture.' % arch
594 sys.exit(1)
595 else:
596 if args.arch != 'default':
597 print 'Architecture %s not supported on current platform.' % args.arch
598 sys.exit(1)
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800599
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800600
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800601def _windows_build_bat(compiler):
602 """Returns name of build.bat for selected compiler."""
603 if compiler == 'default' or compiler == 'vs2013':
604 return 'vsprojects\\build_vs2013.bat'
605 elif compiler == 'vs2015':
606 return 'vsprojects\\build_vs2015.bat'
607 elif compiler == 'vs2010':
608 return 'vsprojects\\build_vs2010.bat'
609 else:
610 print 'Compiler %s not supported.' % compiler
611 sys.exit(1)
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800612
613
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800614def _windows_toolset_option(compiler):
615 """Returns msbuild PlatformToolset for selected compiler."""
616 if compiler == 'default' or compiler == 'vs2013':
617 return '/p:PlatformToolset=v120'
618 elif compiler == 'vs2015':
619 return '/p:PlatformToolset=v140'
620 elif compiler == 'vs2010':
621 return '/p:PlatformToolset=v100'
622 else:
623 print 'Compiler %s not supported.' % compiler
624 sys.exit(1)
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800625
626
Jan Tattermusch788ee232016-01-26 12:19:44 -0800627def _get_dockerfile_dir(language, cfg, arch):
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800628 """Returns dockerfile to use"""
Jan Tattermusch788ee232016-01-26 12:19:44 -0800629 custom = language.dockerfile_dir(cfg, arch)
630 if custom:
631 return custom
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800632 else:
Jan Tattermusch788ee232016-01-26 12:19:44 -0800633 if arch == 'default' or arch == 'x64':
Jan Tattermusched342b12016-01-26 14:40:31 -0800634 return 'tools/dockerfile/grpc_tests_multilang_x64'
Jan Tattermusch788ee232016-01-26 12:19:44 -0800635 elif arch == 'x86':
Jan Tattermusched342b12016-01-26 14:40:31 -0800636 return 'tools/dockerfile/grpc_tests_multilang_x86'
Jan Tattermusch788ee232016-01-26 12:19:44 -0800637 else:
638 print 'Architecture %s not supported with current settings.' % arch
639 sys.exit(1)
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800640
David Garcia Quintase90cd372015-05-31 18:15:26 -0700641def runs_per_test_type(arg_str):
642 """Auxilary function to parse the "runs_per_test" flag.
643
644 Returns:
645 A positive integer or 0, the latter indicating an infinite number of
646 runs.
647
648 Raises:
649 argparse.ArgumentTypeError: Upon invalid input.
650 """
651 if arg_str == 'inf':
652 return 0
653 try:
654 n = int(arg_str)
655 if n <= 0: raise ValueError
Craig Tiller50e53e22015-06-01 20:18:21 -0700656 return n
David Garcia Quintase90cd372015-05-31 18:15:26 -0700657 except:
Adele Zhoue4c35612015-10-16 15:34:23 -0700658 msg = '\'{}\' is not a positive integer or \'inf\''.format(arg_str)
David Garcia Quintase90cd372015-05-31 18:15:26 -0700659 raise argparse.ArgumentTypeError(msg)
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700660
661# parse command line
662argp = argparse.ArgumentParser(description='Run grpc tests.')
663argp.add_argument('-c', '--config',
664 choices=['all'] + sorted(_CONFIGS.keys()),
665 nargs='+',
666 default=_DEFAULT)
David Garcia Quintase90cd372015-05-31 18:15:26 -0700667argp.add_argument('-n', '--runs_per_test', default=1, type=runs_per_test_type,
668 help='A positive integer or "inf". If "inf", all tests will run in an '
669 'infinite loop. Especially useful in combination with "-f"')
Craig Tillerfe406ec2015-02-24 13:55:12 -0800670argp.add_argument('-r', '--regex', default='.*', type=str)
Craig Tiller5f735a62016-01-20 09:31:15 -0800671argp.add_argument('-j', '--jobs', default=multiprocessing.cpu_count(), type=int)
Craig Tiller8451e872015-02-27 09:25:51 -0800672argp.add_argument('-s', '--slowdown', default=1.0, type=float)
ctiller3040cb72015-01-07 12:13:17 -0800673argp.add_argument('-f', '--forever',
674 default=False,
675 action='store_const',
676 const=True)
Nicolas "Pixel" Noblea7df3f92015-02-26 22:07:04 +0100677argp.add_argument('-t', '--travis',
678 default=False,
679 action='store_const',
680 const=True)
Nicolas Noble044db742015-01-14 16:57:24 -0800681argp.add_argument('--newline_on_success',
682 default=False,
683 action='store_const',
684 const=True)
Craig Tiller686fb262015-01-15 07:39:09 -0800685argp.add_argument('-l', '--language',
Craig Tiller60f15e62015-05-13 09:05:17 -0700686 choices=['all'] + sorted(_LANGUAGES.keys()),
Craig Tiller686fb262015-01-15 07:39:09 -0800687 nargs='+',
Craig Tiller60f15e62015-05-13 09:05:17 -0700688 default=['all'])
Craig Tillercd43da82015-05-29 08:41:29 -0700689argp.add_argument('-S', '--stop_on_failure',
690 default=False,
691 action='store_const',
692 const=True)
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700693argp.add_argument('--use_docker',
694 default=False,
695 action='store_const',
696 const=True,
Adele Zhoue4c35612015-10-16 15:34:23 -0700697 help='Run all the tests under docker. That provides ' +
698 'additional isolation and prevents the need to install ' +
699 'language specific prerequisites. Only available on Linux.')
Craig Tillerd4509a12015-09-28 09:18:40 -0700700argp.add_argument('--allow_flakes',
701 default=False,
702 action='store_const',
703 const=True,
Adele Zhoue4c35612015-10-16 15:34:23 -0700704 help='Allow flaky tests to show as passing (re-runs failed tests up to five times)')
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800705argp.add_argument('--arch',
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800706 choices=['default', 'x86', 'x64'],
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800707 default='default',
708 help='Selects architecture to target. For some platforms "default" is the only supported choice.')
709argp.add_argument('--compiler',
710 choices=['default', 'vs2010', 'vs2013', 'vs2015'],
711 default='default',
712 help='Selects compiler to use. For some platforms "default" is the only supported choice.')
713argp.add_argument('--build_only',
714 default=False,
715 action='store_const',
716 const=True,
717 help='Perform all the build steps but dont run any tests.')
Craig Tiller5f735a62016-01-20 09:31:15 -0800718argp.add_argument('--measure_cpu_costs', default=False, action='store_const', const=True,
719 help='Measure the cpu costs of tests')
Craig Tiller1676f912016-01-05 10:49:44 -0800720argp.add_argument('--update_submodules', default=[], nargs='*',
721 help='Update some submodules before building. If any are updated, also run generate_projects. ' +
722 'Submodules are specified as SUBMODULE_NAME:BRANCH; if BRANCH is omitted, master is assumed.')
Craig Tiller234b6e72015-05-23 10:12:40 -0700723argp.add_argument('-a', '--antagonists', default=0, type=int)
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +0200724argp.add_argument('-x', '--xml_report', default=None, type=str,
725 help='Generates a JUnit-compatible XML report')
Nicolas Nobleddef2462015-01-06 18:08:25 -0800726args = argp.parse_args()
727
Craig Tiller5f735a62016-01-20 09:31:15 -0800728jobset.measure_cpu_costs = args.measure_cpu_costs
729
Craig Tiller1676f912016-01-05 10:49:44 -0800730# update submodules if necessary
Craig Tillerb361b4e2016-01-06 11:44:17 -0800731need_to_regenerate_projects = False
732for spec in args.update_submodules:
733 spec = spec.split(':', 1)
734 if len(spec) == 1:
735 submodule = spec[0]
736 branch = 'master'
737 elif len(spec) == 2:
738 submodule = spec[0]
739 branch = spec[1]
740 cwd = 'third_party/%s' % submodule
741 def git(cmd, cwd=cwd):
742 print 'in %s: git %s' % (cwd, cmd)
743 subprocess.check_call('git %s' % cmd, cwd=cwd, shell=True)
744 git('fetch')
745 git('checkout %s' % branch)
746 git('pull origin %s' % branch)
747 if os.path.exists('src/%s/gen_build_yaml.py' % submodule):
748 need_to_regenerate_projects = True
749if need_to_regenerate_projects:
750 if jobset.platform_string() == 'linux':
751 subprocess.check_call('tools/buildgen/generate_projects.sh', shell=True)
752 else:
753 print 'WARNING: may need to regenerate projects, but since we are not on'
754 print ' Linux this step is being skipped. Compilation MAY fail.'
Craig Tiller1676f912016-01-05 10:49:44 -0800755
756
Nicolas Nobleddef2462015-01-06 18:08:25 -0800757# grab config
Craig Tiller738c3342015-01-12 14:28:33 -0800758run_configs = set(_CONFIGS[cfg]
759 for cfg in itertools.chain.from_iterable(
760 _CONFIGS.iterkeys() if x == 'all' else [x]
761 for x in args.config))
762build_configs = set(cfg.build_config for cfg in run_configs)
Craig Tillerf1973b02015-01-16 12:32:13 -0800763
Craig Tiller06805272015-06-11 14:46:47 -0700764if args.travis:
murgatroid99d3b5b7f2015-10-06 17:02:03 -0700765 _FORCE_ENVIRON_FOR_WRAPPERS = {'GRPC_TRACE': 'api'}
Craig Tiller06805272015-06-11 14:46:47 -0700766
Adele Zhou6b9527c2015-11-20 15:56:35 -0800767if 'all' in args.language:
Craig Tiller1676f912016-01-05 10:49:44 -0800768 lang_list = _LANGUAGES.keys()
Adele Zhou6b9527c2015-11-20 15:56:35 -0800769else:
770 lang_list = args.language
Craig Tiller16900662016-01-07 19:30:54 -0800771# We don't support code coverage on some languages
772if 'gcov' in args.config:
773 for bad in ['objc', 'sanity', 'build']:
774 if bad in lang_list:
775 lang_list.remove(bad)
Adele Zhou6b9527c2015-11-20 15:56:35 -0800776
777languages = set(_LANGUAGES[l] for l in lang_list)
murgatroid99132ce6a2015-03-04 17:29:14 -0800778
779if len(build_configs) > 1:
780 for language in languages:
781 if not language.supports_multi_config():
782 print language, 'does not support multiple build configurations'
783 sys.exit(1)
784
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800785language_make_options=[]
786if any(language.make_options() for language in languages):
787 if len(languages) != 1:
788 print 'languages with custom make options cannot be built simultaneously with other languages'
789 sys.exit(1)
790 else:
791 language_make_options = next(iter(languages)).make_options()
792
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800793if len(languages) != 1 or len(build_configs) != 1:
794 print 'Multi-language and multi-config testing is not supported.'
795 sys.exit(1)
796
797if args.use_docker:
798 if not args.travis:
799 print 'Seen --use_docker flag, will run tests under docker.'
800 print
801 print 'IMPORTANT: The changes you are testing need to be locally committed'
802 print 'because only the committed changes in the current branch will be'
803 print 'copied to the docker environment.'
804 time.sleep(5)
805
806 child_argv = [ arg for arg in sys.argv if not arg == '--use_docker' ]
Jan Tattermusched342b12016-01-26 14:40:31 -0800807 run_tests_cmd = 'python tools/run_tests/run_tests.py %s' % ' '.join(child_argv[1:])
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800808
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800809 env = os.environ.copy()
810 env['RUN_TESTS_COMMAND'] = run_tests_cmd
Jan Tattermusch788ee232016-01-26 12:19:44 -0800811 env['DOCKERFILE_DIR'] = _get_dockerfile_dir(next(iter(languages)),
812 next(iter(build_configs)),
813 args.arch)
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800814 env['DOCKER_RUN_SCRIPT'] = 'tools/jenkins/docker_run_tests.sh'
815 if args.xml_report:
816 env['XML_REPORT'] = args.xml_report
817 if not args.travis:
818 env['TTY_FLAG'] = '-t' # enables Ctrl-C when not on Jenkins.
819
820 subprocess.check_call(['tools/jenkins/build_docker_and_run_tests.sh'],
821 shell=True,
822 env=env)
823 sys.exit(0)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800824
Jan Tattermuschf08018a2016-01-26 08:22:09 -0800825if platform_string() != 'windows' and args.compiler != 'default':
826 print 'Compiler %s not supported on current platform.' % args.compiler
827 sys.exit(1)
828
829_check_arch_option(args.arch)
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800830
Jan Tattermuschfba65302016-01-25 18:21:14 -0800831def make_jobspec(cfg, targets, makefile='Makefile'):
832 if platform_string() == 'windows':
Craig Tillerfc3c0c42015-09-01 16:47:54 -0700833 extra_args = []
Craig Tillerb5391e12015-09-03 14:35:18 -0700834 # better do parallel compilation
Jan Tattermusch47eeb2b2015-10-07 14:09:18 -0700835 # empirically /m:2 gives the best performance/price and should prevent
836 # overloading the windows workers.
Adele Zhoue4c35612015-10-16 15:34:23 -0700837 extra_args.extend(['/m:2'])
Craig Tillerb5391e12015-09-03 14:35:18 -0700838 # disable PDB generation: it's broken, and we don't need it during CI
Adele Zhoue4c35612015-10-16 15:34:23 -0700839 extra_args.extend(['/p:Jenkins=true'])
Craig Tiller6fd23842015-09-01 07:36:31 -0700840 return [
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800841 jobset.JobSpec([_windows_build_bat(args.compiler),
murgatroid99cf08daf2015-09-21 15:33:16 -0700842 'vsprojects\\%s.sln' % target,
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800843 '/p:Configuration=%s' % _WINDOWS_CONFIG[cfg],
844 _windows_toolset_option(args.compiler),
845 _windows_arch_option(args.arch)] +
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800846 extra_args +
847 language_make_options,
Craig Tiller590105a2016-01-19 13:03:46 -0800848 shell=True, timeout_seconds=None)
Craig Tiller6fd23842015-09-01 07:36:31 -0700849 for target in targets]
Jan Tattermuschfba65302016-01-25 18:21:14 -0800850 else:
murgatroid998ae409f2015-10-26 16:39:00 -0700851 if targets:
852 return [jobset.JobSpec([os.getenv('MAKE', 'make'),
853 '-f', makefile,
Craig Tillerdd6f7ed2016-01-21 12:54:42 -0800854 '-j', '%d' % args.jobs,
Craig Tiller71a86042016-01-15 14:59:58 -0800855 'EXTRA_DEFINES=GRPC_TEST_SLOWDOWN_MACHINE_FACTOR=%f' % args.slowdown,
856 'CONFIG=%s' % cfg] +
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800857 language_make_options +
Craig Tiller71a86042016-01-15 14:59:58 -0800858 ([] if not args.travis else ['JENKINS_BUILD=1']) +
859 targets,
Craig Tiller590105a2016-01-19 13:03:46 -0800860 timeout_seconds=None)]
murgatroid998ae409f2015-10-26 16:39:00 -0700861 else:
862 return []
Jan Tattermuschfba65302016-01-25 18:21:14 -0800863
murgatroid99a3e244f2015-09-22 11:25:53 -0700864make_targets = {}
865for l in languages:
866 makefile = l.makefile_name()
867 make_targets[makefile] = make_targets.get(makefile, set()).union(
Craig Tiller883064c2015-11-04 10:06:10 -0800868 set(l.make_targets(args.regex)))
Craig Tiller5058c692015-04-08 09:42:04 -0700869
Jan Tattermusche4a69182015-12-15 09:53:01 -0800870def build_step_environ(cfg):
871 environ = {'CONFIG': cfg}
Jan Tattermusch68016a12015-12-16 15:31:33 -0800872 msbuild_cfg = _WINDOWS_CONFIG.get(cfg)
Jan Tattermusche4a69182015-12-15 09:53:01 -0800873 if msbuild_cfg:
874 environ['MSBUILD_CONFIG'] = msbuild_cfg
875 return environ
876
murgatroid99fddac962015-09-22 09:20:11 -0700877build_steps = list(set(
Jan Tattermusche4a69182015-12-15 09:53:01 -0800878 jobset.JobSpec(cmdline, environ=build_step_environ(cfg), flake_retries=5)
murgatroid99256d3df2015-09-21 16:58:02 -0700879 for cfg in build_configs
880 for l in languages
881 for cmdline in l.pre_build_steps()))
Craig Tillerbd4e3782015-09-01 06:48:55 -0700882if make_targets:
murgatroid99a3e244f2015-09-22 11:25:53 -0700883 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 -0700884 build_steps.extend(set(make_commands))
Craig Tiller5058c692015-04-08 09:42:04 -0700885build_steps.extend(set(
Craig Tiller590105a2016-01-19 13:03:46 -0800886 jobset.JobSpec(cmdline, environ=build_step_environ(cfg), timeout_seconds=None)
murgatroid99132ce6a2015-03-04 17:29:14 -0800887 for cfg in build_configs
Craig Tiller547db2b2015-01-30 14:08:39 -0800888 for l in languages
Craig Tiller533b1a22015-05-29 08:41:29 -0700889 for cmdline in l.build_steps()))
Craig Tillerf1973b02015-01-16 12:32:13 -0800890
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200891post_tests_steps = list(set(
Jan Tattermusche4a69182015-12-15 09:53:01 -0800892 jobset.JobSpec(cmdline, environ=build_step_environ(cfg))
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200893 for cfg in build_configs
894 for l in languages
895 for cmdline in l.post_tests_steps()))
Nicolas Nobleddef2462015-01-06 18:08:25 -0800896runs_per_test = args.runs_per_test
ctiller3040cb72015-01-07 12:13:17 -0800897forever = args.forever
Nicolas Nobleddef2462015-01-06 18:08:25 -0800898
Nicolas Nobleddef2462015-01-06 18:08:25 -0800899
Craig Tiller71735182015-01-15 17:07:13 -0800900class TestCache(object):
Craig Tillerb50d1662015-01-15 17:28:21 -0800901 """Cache for running tests."""
902
David Klempner25739582015-02-11 15:57:32 -0800903 def __init__(self, use_cache_results):
Craig Tiller71735182015-01-15 17:07:13 -0800904 self._last_successful_run = {}
David Klempner25739582015-02-11 15:57:32 -0800905 self._use_cache_results = use_cache_results
Craig Tiller69cd2372015-06-11 09:38:09 -0700906 self._last_save = time.time()
Craig Tiller71735182015-01-15 17:07:13 -0800907
908 def should_run(self, cmdline, bin_hash):
Craig Tiller71735182015-01-15 17:07:13 -0800909 if cmdline not in self._last_successful_run:
910 return True
911 if self._last_successful_run[cmdline] != bin_hash:
912 return True
David Klempner25739582015-02-11 15:57:32 -0800913 if not self._use_cache_results:
914 return True
Craig Tiller71735182015-01-15 17:07:13 -0800915 return False
916
917 def finished(self, cmdline, bin_hash):
Craig Tiller547db2b2015-01-30 14:08:39 -0800918 self._last_successful_run[cmdline] = bin_hash
Craig Tiller69cd2372015-06-11 09:38:09 -0700919 if time.time() - self._last_save > 1:
920 self.save()
Craig Tiller71735182015-01-15 17:07:13 -0800921
922 def dump(self):
Craig Tillerb50d1662015-01-15 17:28:21 -0800923 return [{'cmdline': k, 'hash': v}
924 for k, v in self._last_successful_run.iteritems()]
Craig Tiller71735182015-01-15 17:07:13 -0800925
926 def parse(self, exdump):
927 self._last_successful_run = dict((o['cmdline'], o['hash']) for o in exdump)
928
929 def save(self):
930 with open('.run_tests_cache', 'w') as f:
Craig Tiller261dd982015-01-16 16:41:45 -0800931 f.write(json.dumps(self.dump()))
Craig Tiller69cd2372015-06-11 09:38:09 -0700932 self._last_save = time.time()
Craig Tiller71735182015-01-15 17:07:13 -0800933
Craig Tiller1cc11db2015-01-15 22:50:50 -0800934 def maybe_load(self):
935 if os.path.exists('.run_tests_cache'):
936 with open('.run_tests_cache') as f:
Craig Tiller261dd982015-01-16 16:41:45 -0800937 self.parse(json.loads(f.read()))
Craig Tiller71735182015-01-15 17:07:13 -0800938
939
Craig Tillerf53d9c82015-08-04 14:19:43 -0700940def _start_port_server(port_server_port):
941 # check if a compatible port server is running
942 # if incompatible (version mismatch) ==> start a new one
943 # if not running ==> start a new one
944 # otherwise, leave it up
945 try:
Craig Tillerfe4939f2015-10-06 12:55:36 -0700946 version = int(urllib2.urlopen(
947 'http://localhost:%d/version_number' % port_server_port,
948 timeout=1).read())
949 print 'detected port server running version %d' % version
Craig Tillerf53d9c82015-08-04 14:19:43 -0700950 running = True
Craig Tillerfe4939f2015-10-06 12:55:36 -0700951 except Exception as e:
Craig Tiller0d6499e2015-10-05 14:00:47 -0700952 print 'failed to detect port server: %s' % sys.exc_info()[0]
Craig Tillerfe4939f2015-10-06 12:55:36 -0700953 print e.strerror
Craig Tillerf53d9c82015-08-04 14:19:43 -0700954 running = False
955 if running:
Craig Tillerfe4939f2015-10-06 12:55:36 -0700956 current_version = int(subprocess.check_output(
Jan Tattermusch3bd08272015-11-04 19:24:37 -0800957 [sys.executable, os.path.abspath('tools/run_tests/port_server.py'),
958 'dump_version']))
Craig Tillerfe4939f2015-10-06 12:55:36 -0700959 print 'my port server is version %d' % current_version
960 running = (version >= current_version)
961 if not running:
962 print 'port_server version mismatch: killing the old one'
963 urllib2.urlopen('http://localhost:%d/quitquitquit' % port_server_port).read()
964 time.sleep(1)
Craig Tillerf53d9c82015-08-04 14:19:43 -0700965 if not running:
Craig Tillerf0a293e2015-10-12 10:05:50 -0700966 fd, logfile = tempfile.mkstemp()
967 os.close(fd)
968 print 'starting port_server, with log file %s' % logfile
Jan Tattermusch3bd08272015-11-04 19:24:37 -0800969 args = [sys.executable, os.path.abspath('tools/run_tests/port_server.py'),
970 '-p', '%d' % port_server_port, '-l', logfile]
Craig Tiller367d41d2015-10-12 13:00:22 -0700971 env = dict(os.environ)
972 env['BUILD_ID'] = 'pleaseDontKillMeJenkins'
Nicolas "Pixel" Noblef72d7b52015-12-03 03:07:43 +0100973 if platform_string() == 'windows':
Jan Tattermusch3bd08272015-11-04 19:24:37 -0800974 # Working directory of port server needs to be outside of Jenkins
975 # workspace to prevent file lock issues.
976 tempdir = tempfile.mkdtemp()
Craig Tillerd2c39712015-10-12 11:08:49 -0700977 port_server = subprocess.Popen(
Craig Tiller367d41d2015-10-12 13:00:22 -0700978 args,
979 env=env,
Jan Tattermusch3bd08272015-11-04 19:24:37 -0800980 cwd=tempdir,
Craig Tiller367d41d2015-10-12 13:00:22 -0700981 creationflags = 0x00000008, # detached process
982 close_fds=True)
Craig Tillerd2c39712015-10-12 11:08:49 -0700983 else:
984 port_server = subprocess.Popen(
985 args,
Craig Tiller367d41d2015-10-12 13:00:22 -0700986 env=env,
Craig Tillerd2c39712015-10-12 11:08:49 -0700987 preexec_fn=os.setsid,
988 close_fds=True)
Craig Tillerf0a293e2015-10-12 10:05:50 -0700989 time.sleep(1)
Craig Tiller8b5f4dc2015-08-26 08:02:01 -0700990 # ensure port server is up
Craig Tillerabd37fd2015-08-26 07:54:01 -0700991 waits = 0
Craig Tillerf53d9c82015-08-04 14:19:43 -0700992 while True:
Craig Tillerabd37fd2015-08-26 07:54:01 -0700993 if waits > 10:
Craig Tillerf0a293e2015-10-12 10:05:50 -0700994 print 'killing port server due to excessive start up waits'
Craig Tillerabd37fd2015-08-26 07:54:01 -0700995 port_server.kill()
Craig Tillera2f38b02015-09-24 11:19:17 -0700996 if port_server.poll() is not None:
Craig Tiller0d6499e2015-10-05 14:00:47 -0700997 print 'port_server failed to start'
Craig Tillerf0a293e2015-10-12 10:05:50 -0700998 # try one final time: maybe another build managed to start one
999 time.sleep(1)
1000 try:
1001 urllib2.urlopen('http://localhost:%d/get' % port_server_port,
1002 timeout=1).read()
1003 print 'last ditch attempt to contact port server succeeded'
1004 break
1005 except:
1006 traceback.print_exc();
1007 port_log = open(logfile, 'r').read()
1008 print port_log
1009 sys.exit(1)
Craig Tillerf53d9c82015-08-04 14:19:43 -07001010 try:
Craig Tillerabd37fd2015-08-26 07:54:01 -07001011 urllib2.urlopen('http://localhost:%d/get' % port_server_port,
1012 timeout=1).read()
Craig Tillerf0a293e2015-10-12 10:05:50 -07001013 print 'port server is up and ready'
Craig Tillerf53d9c82015-08-04 14:19:43 -07001014 break
Craig Tiller31fdaa42015-09-25 13:09:59 -07001015 except socket.timeout:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001016 print 'waiting for port_server: timeout'
Craig Tillerf0a293e2015-10-12 10:05:50 -07001017 traceback.print_exc();
1018 time.sleep(1)
Craig Tiller31fdaa42015-09-25 13:09:59 -07001019 waits += 1
Craig Tillerf53d9c82015-08-04 14:19:43 -07001020 except urllib2.URLError:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001021 print 'waiting for port_server: urlerror'
Craig Tillerf0a293e2015-10-12 10:05:50 -07001022 traceback.print_exc();
1023 time.sleep(1)
Craig Tillerabd37fd2015-08-26 07:54:01 -07001024 waits += 1
Craig Tillerf53d9c82015-08-04 14:19:43 -07001025 except:
Craig Tillerf0a293e2015-10-12 10:05:50 -07001026 traceback.print_exc();
Craig Tillerf53d9c82015-08-04 14:19:43 -07001027 port_server.kill()
1028 raise
1029
1030
Adele Zhoud5fffa52015-10-23 15:51:42 -07001031def _calculate_num_runs_failures(list_of_results):
1032 """Caculate number of runs and failures for a particular test.
1033
1034 Args:
1035 list_of_results: (List) of JobResult object.
1036 Returns:
1037 A tuple of total number of runs and failures.
1038 """
1039 num_runs = len(list_of_results) # By default, there is 1 run per JobResult.
1040 num_failures = 0
1041 for jobresult in list_of_results:
1042 if jobresult.retries > 0:
1043 num_runs += jobresult.retries
1044 if jobresult.num_failures > 0:
1045 num_failures += jobresult.num_failures
1046 return num_runs, num_failures
1047
Adele Zhou6b9527c2015-11-20 15:56:35 -08001048
Craig Tillereb9de8b2016-01-08 08:57:41 -08001049# _build_and_run results
1050class BuildAndRunError(object):
1051
1052 BUILD = object()
1053 TEST = object()
1054 POST_TEST = object()
1055
1056
1057# returns a list of things that failed (or an empty list on success)
Craig Tillerf53d9c82015-08-04 14:19:43 -07001058def _build_and_run(
Jan Tattermusch2dd156e2015-12-04 18:26:17 -08001059 check_cancelled, newline_on_success, cache, xml_report=None, build_only=False):
ctiller3040cb72015-01-07 12:13:17 -08001060 """Do one pass of building & running tests."""
murgatroid99666450e2015-01-26 13:03:31 -08001061 # build latest sequentially
Adele Zhoue4c35612015-10-16 15:34:23 -07001062 num_failures, _ = jobset.run(
1063 build_steps, maxjobs=1, stop_on_failure=True,
Craig Tiller883064c2015-11-04 10:06:10 -08001064 newline_on_success=newline_on_success, travis=args.travis)
Adele Zhoue4c35612015-10-16 15:34:23 -07001065 if num_failures:
Craig Tillereb9de8b2016-01-08 08:57:41 -08001066 return [BuildAndRunError.BUILD]
Craig Tillerb361b4e2016-01-06 11:44:17 -08001067
Jan Tattermusch2dd156e2015-12-04 18:26:17 -08001068 if build_only:
Craig Tillereb9de8b2016-01-08 08:57:41 -08001069 return []
ctiller3040cb72015-01-07 12:13:17 -08001070
Craig Tiller234b6e72015-05-23 10:12:40 -07001071 # start antagonists
David Garcia Quintas79e389f2015-06-02 17:49:42 -07001072 antagonists = [subprocess.Popen(['tools/run_tests/antagonist.py'])
Craig Tiller234b6e72015-05-23 10:12:40 -07001073 for _ in range(0, args.antagonists)]
Craig Tillerfe4939f2015-10-06 12:55:36 -07001074 port_server_port = 32767
Craig Tillerf53d9c82015-08-04 14:19:43 -07001075 _start_port_server(port_server_port)
Adele Zhou7cf72112015-11-04 11:18:43 -08001076 resultset = None
Adele Zhou803af152015-11-30 15:16:16 -08001077 num_test_failures = 0
Craig Tiller234b6e72015-05-23 10:12:40 -07001078 try:
David Garcia Quintase90cd372015-05-31 18:15:26 -07001079 infinite_runs = runs_per_test == 0
yang-g6c1fdc62015-08-18 11:57:42 -07001080 one_run = set(
1081 spec
1082 for config in run_configs
1083 for language in languages
Craig Tiller883064c2015-11-04 10:06:10 -08001084 for spec in language.test_specs(config, args)
yang-g6c1fdc62015-08-18 11:57:42 -07001085 if re.search(args.regex, spec.shortname))
David Garcia Quintas79e389f2015-06-02 17:49:42 -07001086 # When running on travis, we want out test runs to be as similar as possible
1087 # for reproducibility purposes.
Craig Tiller883064c2015-11-04 10:06:10 -08001088 if args.travis:
David Garcia Quintas79e389f2015-06-02 17:49:42 -07001089 massaged_one_run = sorted(one_run, key=lambda x: x.shortname)
1090 else:
1091 # whereas otherwise, we want to shuffle things up to give all tests a
1092 # chance to run.
1093 massaged_one_run = list(one_run) # random.shuffle needs an indexable seq.
1094 random.shuffle(massaged_one_run) # which it modifies in-place.
Craig Tillerf7b7c892015-06-22 14:33:25 -07001095 if infinite_runs:
1096 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 -07001097 runs_sequence = (itertools.repeat(massaged_one_run) if infinite_runs
1098 else itertools.repeat(massaged_one_run, runs_per_test))
David Garcia Quintase90cd372015-05-31 18:15:26 -07001099 all_runs = itertools.chain.from_iterable(runs_sequence)
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +02001100
Adele Zhou803af152015-11-30 15:16:16 -08001101 num_test_failures, resultset = jobset.run(
Adele Zhou2271ab52015-10-28 13:59:14 -07001102 all_runs, check_cancelled, newline_on_success=newline_on_success,
Craig Tiller883064c2015-11-04 10:06:10 -08001103 travis=args.travis, infinite_runs=infinite_runs, maxjobs=args.jobs,
murgatroid998ae409f2015-10-26 16:39:00 -07001104 stop_on_failure=args.stop_on_failure,
Adele Zhouf2ca7bc2015-10-23 15:38:00 -07001105 cache=cache if not xml_report else None,
Adele Zhouf2ca7bc2015-10-23 15:38:00 -07001106 add_env={'GRPC_TEST_PORT_SERVER': 'localhost:%d' % port_server_port})
Adele Zhoud5fffa52015-10-23 15:51:42 -07001107 if resultset:
1108 for k, v in resultset.iteritems():
1109 num_runs, num_failures = _calculate_num_runs_failures(v)
1110 if num_failures == num_runs: # what about infinite_runs???
1111 jobset.message('FAILED', k, do_newline=True)
1112 elif num_failures > 0:
1113 jobset.message(
1114 'FLAKE', '%s [%d/%d runs flaked]' % (k, num_failures, num_runs),
1115 do_newline=True)
1116 else:
1117 jobset.message('PASSED', k, do_newline=True)
Craig Tiller234b6e72015-05-23 10:12:40 -07001118 finally:
1119 for antagonist in antagonists:
1120 antagonist.kill()
Adele Zhou7cf72112015-11-04 11:18:43 -08001121 if xml_report and resultset:
Adele Zhou3bc7ba42015-11-05 10:21:58 -08001122 report_utils.render_junit_xml_report(resultset, xml_report)
Craig Tillerd86a3942015-01-14 12:48:54 -08001123
Adele Zhouf2ca7bc2015-10-23 15:38:00 -07001124 number_failures, _ = jobset.run(
1125 post_tests_steps, maxjobs=1, stop_on_failure=True,
Craig Tiller883064c2015-11-04 10:06:10 -08001126 newline_on_success=newline_on_success, travis=args.travis)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001127
1128 out = []
1129 if number_failures:
1130 out.append(BuildAndRunError.POST_TEST)
1131 if num_test_failures:
1132 out.append(BuildAndRunError.TEST)
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +02001133
Craig Tiller69cd2372015-06-11 09:38:09 -07001134 if cache: cache.save()
1135
Craig Tillereb9de8b2016-01-08 08:57:41 -08001136 return out
ctiller3040cb72015-01-07 12:13:17 -08001137
1138
David Klempner25739582015-02-11 15:57:32 -08001139test_cache = TestCache(runs_per_test == 1)
Craig Tiller547db2b2015-01-30 14:08:39 -08001140test_cache.maybe_load()
Craig Tiller71735182015-01-15 17:07:13 -08001141
ctiller3040cb72015-01-07 12:13:17 -08001142if forever:
Nicolas Noble044db742015-01-14 16:57:24 -08001143 success = True
ctiller3040cb72015-01-07 12:13:17 -08001144 while True:
Craig Tiller42bc87c2015-02-23 08:50:19 -08001145 dw = watch_dirs.DirWatcher(['src', 'include', 'test', 'examples'])
ctiller3040cb72015-01-07 12:13:17 -08001146 initial_time = dw.most_recent_change()
1147 have_files_changed = lambda: dw.most_recent_change() != initial_time
Nicolas Noble044db742015-01-14 16:57:24 -08001148 previous_success = success
Craig Tillereb9de8b2016-01-08 08:57:41 -08001149 errors = _build_and_run(check_cancelled=have_files_changed,
1150 newline_on_success=False,
1151 cache=test_cache,
1152 build_only=args.build_only) == 0
1153 if not previous_success and not errors:
Nicolas Nobleb09078f2015-01-14 18:06:05 -08001154 jobset.message('SUCCESS',
1155 'All tests are now passing properly',
1156 do_newline=True)
Nicolas Noble044db742015-01-14 16:57:24 -08001157 jobset.message('IDLE', 'No change detected')
ctiller3040cb72015-01-07 12:13:17 -08001158 while not have_files_changed():
1159 time.sleep(1)
1160else:
Craig Tillereb9de8b2016-01-08 08:57:41 -08001161 errors = _build_and_run(check_cancelled=lambda: False,
Craig Tiller71735182015-01-15 17:07:13 -08001162 newline_on_success=args.newline_on_success,
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +02001163 cache=test_cache,
Jan Tattermusch2dd156e2015-12-04 18:26:17 -08001164 xml_report=args.xml_report,
1165 build_only=args.build_only)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001166 if not errors:
Nicolas Nobleb09078f2015-01-14 18:06:05 -08001167 jobset.message('SUCCESS', 'All tests passed', do_newline=True)
1168 else:
1169 jobset.message('FAILED', 'Some tests failed', do_newline=True)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001170 exit_code = 0
1171 if BuildAndRunError.BUILD in errors:
1172 exit_code |= 1
Craig Tiller4f2be362016-01-08 08:59:20 -08001173 if BuildAndRunError.TEST in errors and not args.travis:
Craig Tillereb9de8b2016-01-08 08:57:41 -08001174 exit_code |= 2
Craig Tiller4f2be362016-01-08 08:59:20 -08001175 if BuildAndRunError.POST_TEST in errors:
1176 exit_code |= 4
Craig Tillereb9de8b2016-01-08 08:57:41 -08001177 sys.exit(exit_code)
Craig Tillera0f85172016-01-20 15:56:06 -08001178