blob: 41cf335a812708fc6ef8eb1be88709862d97eae9 [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':
Jan Tattermusch3de6b762016-01-28 11:38:11 -0800135 binary = 'vsprojects/%s%s/%s.exe' % (
136 'x64/' if args.arch == 'x64' else '',
137 _WINDOWS_CONFIG[config.build_config],
138 target['name'])
Nicolas Noblee1445362015-05-11 17:40:26 -0700139 else:
140 binary = 'bins/%s/%s' % (config.build_config, target['name'])
yang-g6c1fdc62015-08-18 11:57:42 -0700141 if os.path.isfile(binary):
Craig Tiller0fe5ee72015-12-22 12:50:36 -0800142 cmdline = [binary] + target['args']
143 out.append(config.job_spec(cmdline, [binary],
144 shortname=' '.join(cmdline),
Craig Tiller56c6b6a2016-01-20 08:27:37 -0800145 cpu_cost=target['cpu_cost'],
Craig Tillercc0535d2015-12-08 15:14:47 -0800146 environ={'GRPC_DEFAULT_SSL_ROOTS_FILE_PATH':
147 os.path.abspath(os.path.dirname(
Craig Tillered2164d2015-12-08 22:03:36 -0800148 sys.argv[0]) + '/../../src/core/tsi/test_creds/ca.pem')}))
Craig Tiller883064c2015-11-04 10:06:10 -0800149 elif args.regex == '.*' or platform_string() == 'windows':
Adele Zhoue4c35612015-10-16 15:34:23 -0700150 print '\nWARNING: binary not found, skipping', binary
Nicolas Noblee1445362015-05-11 17:40:26 -0700151 return sorted(out)
Craig Tillerc7449162015-01-16 14:42:10 -0800152
Craig Tiller883064c2015-11-04 10:06:10 -0800153 def make_targets(self, test_regex):
154 if platform_string() != 'windows' and test_regex != '.*':
155 # use the regex to minimize the number of things to build
Craig Tillerb0f275e2016-01-27 10:45:50 -0800156 return [os.path.basename(target['name'])
Craig Tiller883064c2015-11-04 10:06:10 -0800157 for target in get_c_tests(False, self.test_lang)
Craig Tillerb0f275e2016-01-27 10:45:50 -0800158 if re.search(test_regex, '/' + target['name'])]
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700159 if platform_string() == 'windows':
160 # don't build tools on windows just yet
161 return ['buildtests_%s' % self.make_target]
Craig Tiller7552f0f2015-06-19 17:46:20 -0700162 return ['buildtests_%s' % self.make_target, 'tools_%s' % self.make_target]
Craig Tillerc7449162015-01-16 14:42:10 -0800163
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800164 def make_options(self):
165 return []
166
murgatroid99256d3df2015-09-21 16:58:02 -0700167 def pre_build_steps(self):
Jan Tattermusch874aec02015-10-07 19:26:19 -0700168 if self.platform == 'windows':
169 return [['tools\\run_tests\\pre_build_c.bat']]
170 else:
171 return []
murgatroid99256d3df2015-09-21 16:58:02 -0700172
Craig Tillerc7449162015-01-16 14:42:10 -0800173 def build_steps(self):
174 return []
175
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200176 def post_tests_steps(self):
177 if self.platform == 'windows':
178 return []
179 else:
180 return [['tools/run_tests/post_tests_c.sh']]
181
murgatroid99a3e244f2015-09-22 11:25:53 -0700182 def makefile_name(self):
183 return 'Makefile'
184
murgatroid99132ce6a2015-03-04 17:29:14 -0800185 def supports_multi_config(self):
186 return True
187
Jan Tattermusch788ee232016-01-26 12:19:44 -0800188 def dockerfile_dir(self, config, arch):
Jan Tattermusche70b3c52016-02-07 20:21:02 -0800189 return 'tools/dockerfile/test/cxx_jessie_%s' % _docker_arch_suffix(arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800190
murgatroid99132ce6a2015-03-04 17:29:14 -0800191 def __str__(self):
192 return self.make_target
193
Craig Tillercc0535d2015-12-08 15:14:47 -0800194
murgatroid992c8d5162015-01-26 10:41:21 -0800195class NodeLanguage(object):
196
Jan Tattermusche477b842016-02-06 22:19:01 -0800197 def __init__(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800198 self.platform = platform_string()
Jan Tattermusche477b842016-02-06 22:19:01 -0800199 self.node_version = '0.12'
200
Craig Tiller883064c2015-11-04 10:06:10 -0800201 def test_specs(self, config, args):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800202 if self.platform == 'windows':
203 return [config.job_spec(['tools\\run_tests\\run_node.bat'], None)]
204 else:
205 return [config.job_spec(['tools/run_tests/run_node.sh', self.node_version],
206 None,
207 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
murgatroid992c8d5162015-01-26 10:41:21 -0800208
murgatroid99256d3df2015-09-21 16:58:02 -0700209 def pre_build_steps(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800210 if self.platform == 'windows':
211 return [['tools\\run_tests\\pre_build_node.bat']]
212 else:
213 return [['tools/run_tests/pre_build_node.sh', self.node_version]]
murgatroid99256d3df2015-09-21 16:58:02 -0700214
Craig Tiller883064c2015-11-04 10:06:10 -0800215 def make_targets(self, test_regex):
murgatroid99db5b1602015-10-01 13:20:11 -0700216 return []
murgatroid992c8d5162015-01-26 10:41:21 -0800217
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800218 def make_options(self):
219 return []
220
murgatroid992c8d5162015-01-26 10:41:21 -0800221 def build_steps(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800222 if self.platform == 'windows':
223 return [['tools\\run_tests\\build_node.bat']]
224 else:
225 return [['tools/run_tests/build_node.sh', self.node_version]]
Craig Tillerc7449162015-01-16 14:42:10 -0800226
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200227 def post_tests_steps(self):
228 return []
229
murgatroid99a3e244f2015-09-22 11:25:53 -0700230 def makefile_name(self):
231 return 'Makefile'
232
murgatroid99132ce6a2015-03-04 17:29:14 -0800233 def supports_multi_config(self):
234 return False
235
Jan Tattermusch788ee232016-01-26 12:19:44 -0800236 def dockerfile_dir(self, config, arch):
Jan Tattermusche70b3c52016-02-07 20:21:02 -0800237 return 'tools/dockerfile/test/node_jessie_%s' % _docker_arch_suffix(arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800238
murgatroid99132ce6a2015-03-04 17:29:14 -0800239 def __str__(self):
240 return 'node'
241
Craig Tiller99775822015-01-30 13:07:16 -0800242
Craig Tillerc7449162015-01-16 14:42:10 -0800243class PhpLanguage(object):
244
Craig Tiller883064c2015-11-04 10:06:10 -0800245 def test_specs(self, config, args):
Craig Tiller4fc90032015-05-21 10:39:52 -0700246 return [config.job_spec(['src/php/bin/run_tests.sh'], None,
Craig Tiller06805272015-06-11 14:46:47 -0700247 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
Craig Tillerc7449162015-01-16 14:42:10 -0800248
murgatroid99256d3df2015-09-21 16:58:02 -0700249 def pre_build_steps(self):
250 return []
251
Craig Tiller883064c2015-11-04 10:06:10 -0800252 def make_targets(self, test_regex):
Craig Tilleraf7cf542015-05-22 10:07:34 -0700253 return ['static_c', 'shared_c']
Craig Tillerc7449162015-01-16 14:42:10 -0800254
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800255 def make_options(self):
256 return []
257
Craig Tillerc7449162015-01-16 14:42:10 -0800258 def build_steps(self):
259 return [['tools/run_tests/build_php.sh']]
260
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200261 def post_tests_steps(self):
Stanley Cheunga6b95482016-01-13 16:10:48 -0800262 return [['tools/run_tests/post_tests_php.sh']]
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200263
murgatroid99a3e244f2015-09-22 11:25:53 -0700264 def makefile_name(self):
265 return 'Makefile'
266
murgatroid99132ce6a2015-03-04 17:29:14 -0800267 def supports_multi_config(self):
268 return False
269
Jan Tattermusch788ee232016-01-26 12:19:44 -0800270 def dockerfile_dir(self, config, arch):
Jan Tattermusche70b3c52016-02-07 20:21:02 -0800271 return 'tools/dockerfile/test/php_jessie_%s' % _docker_arch_suffix(arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800272
murgatroid99132ce6a2015-03-04 17:29:14 -0800273 def __str__(self):
274 return 'php'
275
Craig Tillerc7449162015-01-16 14:42:10 -0800276
Nathaniel Manista840615e2015-01-22 20:31:47 +0000277class PythonLanguage(object):
278
Craig Tiller49f61322015-03-03 13:02:11 -0800279 def __init__(self):
Masood Malekghassemi2b841622015-07-28 17:39:02 -0700280 self._build_python_versions = ['2.7']
Masood Malekghassemie5f70022015-06-29 09:20:26 -0700281 self._has_python_versions = []
Craig Tiller49f61322015-03-03 13:02:11 -0800282
Craig Tiller883064c2015-11-04 10:06:10 -0800283 def test_specs(self, config, args):
Masood Malekghassemi2b841622015-07-28 17:39:02 -0700284 environment = dict(_FORCE_ENVIRON_FOR_WRAPPERS)
285 environment['PYVER'] = '2.7'
286 return [config.job_spec(
287 ['tools/run_tests/run_python.sh'],
288 None,
289 environ=environment,
290 shortname='py.test',
Masood Malekghassemi26ea9e22015-10-09 15:19:17 -0700291 timeout_seconds=15*60
Masood Malekghassemi2b841622015-07-28 17:39:02 -0700292 )]
Nathaniel Manista840615e2015-01-22 20:31:47 +0000293
murgatroid99256d3df2015-09-21 16:58:02 -0700294 def pre_build_steps(self):
295 return []
296
Craig Tiller883064c2015-11-04 10:06:10 -0800297 def make_targets(self, test_regex):
Craig Tilleraf7cf542015-05-22 10:07:34 -0700298 return ['static_c', 'grpc_python_plugin', 'shared_c']
Nathaniel Manista840615e2015-01-22 20:31:47 +0000299
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800300 def make_options(self):
301 return []
302
Nathaniel Manista840615e2015-01-22 20:31:47 +0000303 def build_steps(self):
Masood Malekghassemie5f70022015-06-29 09:20:26 -0700304 commands = []
305 for python_version in self._build_python_versions:
306 try:
307 with open(os.devnull, 'w') as output:
308 subprocess.check_call(['which', 'python' + python_version],
309 stdout=output, stderr=output)
310 commands.append(['tools/run_tests/build_python.sh', python_version])
311 self._has_python_versions.append(python_version)
312 except:
313 jobset.message('WARNING', 'Missing Python ' + python_version,
314 do_newline=True)
315 return commands
Nathaniel Manista840615e2015-01-22 20:31:47 +0000316
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200317 def post_tests_steps(self):
318 return []
319
murgatroid99a3e244f2015-09-22 11:25:53 -0700320 def makefile_name(self):
321 return 'Makefile'
322
murgatroid99132ce6a2015-03-04 17:29:14 -0800323 def supports_multi_config(self):
324 return False
325
Jan Tattermusch788ee232016-01-26 12:19:44 -0800326 def dockerfile_dir(self, config, arch):
Jan Tattermusche70b3c52016-02-07 20:21:02 -0800327 return 'tools/dockerfile/test/python_jessie_%s' % _docker_arch_suffix(arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800328
murgatroid99132ce6a2015-03-04 17:29:14 -0800329 def __str__(self):
330 return 'python'
331
Craig Tillerd625d812015-04-08 15:52:35 -0700332
murgatroid996a4c4fa2015-02-27 12:08:57 -0800333class RubyLanguage(object):
334
Craig Tiller883064c2015-11-04 10:06:10 -0800335 def test_specs(self, config, args):
Craig Tiller4fc90032015-05-21 10:39:52 -0700336 return [config.job_spec(['tools/run_tests/run_ruby.sh'], None,
murgatroid997d243df2016-02-18 09:58:05 -0800337 timeout_seconds=10*60,
Craig Tiller06805272015-06-11 14:46:47 -0700338 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
murgatroid996a4c4fa2015-02-27 12:08:57 -0800339
murgatroid99256d3df2015-09-21 16:58:02 -0700340 def pre_build_steps(self):
Nicolas "Pixel" Noblebcf988f2015-10-08 03:00:42 +0200341 return [['tools/run_tests/pre_build_ruby.sh']]
murgatroid99256d3df2015-09-21 16:58:02 -0700342
Craig Tiller883064c2015-11-04 10:06:10 -0800343 def make_targets(self, test_regex):
murgatroid997d243df2016-02-18 09:58:05 -0800344 return []
murgatroid996a4c4fa2015-02-27 12:08:57 -0800345
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800346 def make_options(self):
347 return []
348
murgatroid996a4c4fa2015-02-27 12:08:57 -0800349 def build_steps(self):
350 return [['tools/run_tests/build_ruby.sh']]
351
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200352 def post_tests_steps(self):
Nicolas "Pixel" Noble7ef1e532015-12-02 00:55:33 +0100353 return [['tools/run_tests/post_tests_ruby.sh']]
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200354
murgatroid99a3e244f2015-09-22 11:25:53 -0700355 def makefile_name(self):
356 return 'Makefile'
357
murgatroid99132ce6a2015-03-04 17:29:14 -0800358 def supports_multi_config(self):
359 return False
360
Jan Tattermusch788ee232016-01-26 12:19:44 -0800361 def dockerfile_dir(self, config, arch):
Jan Tattermusche70b3c52016-02-07 20:21:02 -0800362 return 'tools/dockerfile/test/ruby_jessie_%s' % _docker_arch_suffix(arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800363
murgatroid99132ce6a2015-03-04 17:29:14 -0800364 def __str__(self):
365 return 'ruby'
366
Craig Tillerd625d812015-04-08 15:52:35 -0700367
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800368class CSharpLanguage(object):
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700369 def __init__(self):
Craig Tillerd50993d2015-08-05 08:04:36 -0700370 self.platform = platform_string()
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700371
Craig Tiller883064c2015-11-04 10:06:10 -0800372 def test_specs(self, config, args):
Jan Tattermusch03c01062015-12-11 14:28:56 -0800373 with open('src/csharp/tests.json') as f:
374 tests_json = json.load(f)
375 assemblies = tests_json['assemblies']
376 tests = tests_json['tests']
377
378 msbuild_config = _WINDOWS_CONFIG[config.build_config]
379 assembly_files = ['%s/bin/%s/%s.dll' % (a, msbuild_config, a)
380 for a in assemblies]
381
382 extra_args = ['-labels'] + assembly_files
383
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700384 if self.platform == 'windows':
Jan Tattermusch03c01062015-12-11 14:28:56 -0800385 script_name = 'tools\\run_tests\\run_csharp.bat'
386 extra_args += ['-domain=None']
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700387 else:
Jan Tattermusch03c01062015-12-11 14:28:56 -0800388 script_name = 'tools/run_tests/run_csharp.sh'
Jan Tattermuschbf3b1532015-10-26 10:24:42 -0700389
Jan Tattermuschbdf4b2e2015-10-28 08:22:34 -0700390 if config.build_config == 'gcov':
391 # On Windows, we only collect C# code coverage.
392 # On Linux, we only collect coverage for native extension.
393 # For code coverage all tests need to run as one suite.
Jan Tattermusch03c01062015-12-11 14:28:56 -0800394 return [config.job_spec([script_name] + extra_args, None,
395 shortname='csharp.coverage',
396 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
Jan Tattermusch61c3a832015-10-27 17:54:50 -0700397 else:
Jan Tattermusch03c01062015-12-11 14:28:56 -0800398 specs = []
399 for test in tests:
400 cmdline = [script_name, '-run=%s' % test] + extra_args
401 if self.platform == 'windows':
402 # use different output directory for each test to prevent
403 # TestResult.xml clash between parallel test runs.
404 cmdline += ['-work=test-result/%s' % uuid.uuid4()]
405 specs.append(config.job_spec(cmdline, None,
406 shortname='csharp.%s' % test,
407 environ=_FORCE_ENVIRON_FOR_WRAPPERS))
408 return specs
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800409
murgatroid99256d3df2015-09-21 16:58:02 -0700410 def pre_build_steps(self):
Jan Tattermusch48423fc2015-10-07 18:59:16 -0700411 if self.platform == 'windows':
Jan Tattermusch874aec02015-10-07 19:26:19 -0700412 return [['tools\\run_tests\\pre_build_csharp.bat']]
Jan Tattermusch48423fc2015-10-07 18:59:16 -0700413 else:
414 return [['tools/run_tests/pre_build_csharp.sh']]
murgatroid99256d3df2015-09-21 16:58:02 -0700415
Craig Tiller883064c2015-11-04 10:06:10 -0800416 def make_targets(self, test_regex):
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700417 # For Windows, this target doesn't really build anything,
418 # everything is build by buildall script later.
Craig Tillerd5904822015-08-31 21:30:58 -0700419 if self.platform == 'windows':
420 return []
421 else:
422 return ['grpc_csharp_ext']
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800423
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800424 def make_options(self):
425 if self.platform == 'mac':
426 # On Mac, official distribution of mono is 32bit.
427 return ['CFLAGS=-arch i386', 'LDFLAGS=-arch i386']
428 else:
429 return []
430
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800431 def build_steps(self):
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700432 if self.platform == 'windows':
433 return [['src\\csharp\\buildall.bat']]
434 else:
435 return [['tools/run_tests/build_csharp.sh']]
Nathaniel Manista840615e2015-01-22 20:31:47 +0000436
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200437 def post_tests_steps(self):
438 return []
439
murgatroid99a3e244f2015-09-22 11:25:53 -0700440 def makefile_name(self):
441 return 'Makefile'
442
murgatroid99132ce6a2015-03-04 17:29:14 -0800443 def supports_multi_config(self):
444 return False
445
Jan Tattermusch788ee232016-01-26 12:19:44 -0800446 def dockerfile_dir(self, config, arch):
Jan Tattermusche70b3c52016-02-07 20:21:02 -0800447 return 'tools/dockerfile/test/csharp_jessie_%s' % _docker_arch_suffix(arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800448
murgatroid99132ce6a2015-03-04 17:29:14 -0800449 def __str__(self):
450 return 'csharp'
451
Craig Tillerd625d812015-04-08 15:52:35 -0700452
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700453class ObjCLanguage(object):
454
Craig Tiller883064c2015-11-04 10:06:10 -0800455 def test_specs(self, config, args):
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700456 return [config.job_spec(['src/objective-c/tests/run_tests.sh'], None,
457 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
458
murgatroid99256d3df2015-09-21 16:58:02 -0700459 def pre_build_steps(self):
460 return []
461
Craig Tiller883064c2015-11-04 10:06:10 -0800462 def make_targets(self, test_regex):
Jorge Canizalesd0b32e92015-07-30 23:08:43 -0700463 return ['grpc_objective_c_plugin', 'interop_server']
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700464
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800465 def make_options(self):
466 return []
467
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700468 def build_steps(self):
Jorge Canizalesd0b32e92015-07-30 23:08:43 -0700469 return [['src/objective-c/tests/build_tests.sh']]
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700470
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200471 def post_tests_steps(self):
472 return []
473
murgatroid99a3e244f2015-09-22 11:25:53 -0700474 def makefile_name(self):
475 return 'Makefile'
476
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700477 def supports_multi_config(self):
478 return False
479
Jan Tattermusch788ee232016-01-26 12:19:44 -0800480 def dockerfile_dir(self, config, arch):
481 return None
482
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700483 def __str__(self):
484 return 'objc'
485
486
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100487class Sanity(object):
488
Craig Tiller883064c2015-11-04 10:06:10 -0800489 def test_specs(self, config, args):
Craig Tiller94d04a52016-01-20 10:58:23 -0800490 import yaml
Jan Tattermusch788ee232016-01-26 12:19:44 -0800491 with open('tools/run_tests/sanity/sanity_tests.yaml', 'r') as f:
492 return [config.job_spec(cmd['script'].split(), None,
493 timeout_seconds=None, environ={'TEST': 'true'},
494 cpu_cost=cmd.get('cpu_cost', 1))
Craig Tiller94d04a52016-01-20 10:58:23 -0800495 for cmd in yaml.load(f)]
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100496
murgatroid99256d3df2015-09-21 16:58:02 -0700497 def pre_build_steps(self):
498 return []
499
Craig Tiller883064c2015-11-04 10:06:10 -0800500 def make_targets(self, test_regex):
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100501 return ['run_dep_checks']
502
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800503 def make_options(self):
504 return []
505
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100506 def build_steps(self):
507 return []
508
Nicolas "Pixel" Noble87879b32015-10-12 23:28:53 +0200509 def post_tests_steps(self):
510 return []
511
murgatroid99a3e244f2015-09-22 11:25:53 -0700512 def makefile_name(self):
513 return 'Makefile'
514
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100515 def supports_multi_config(self):
516 return False
517
Jan Tattermusch788ee232016-01-26 12:19:44 -0800518 def dockerfile_dir(self, config, arch):
Jan Tattermusche70b3c52016-02-07 20:21:02 -0800519 return 'tools/dockerfile/test/sanity'
Jan Tattermusch788ee232016-01-26 12:19:44 -0800520
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100521 def __str__(self):
522 return 'sanity'
523
Nicolas "Pixel" Noblee55cd7f2015-04-14 17:59:13 +0200524
Craig Tiller738c3342015-01-12 14:28:33 -0800525# different configurations we can run under
Craig Tillera0f85172016-01-20 15:56:06 -0800526with open('tools/run_tests/configs.json') as f:
Craig Tiller1dce9062016-01-20 17:01:56 -0800527 _CONFIGS = dict((cfg['config'], Config(**cfg)) for cfg in ast.literal_eval(f.read()))
Craig Tiller738c3342015-01-12 14:28:33 -0800528
529
Nicolas "Pixel" Noble1fb5e822015-03-16 06:20:37 +0100530_DEFAULT = ['opt']
Craig Tillerc7449162015-01-16 14:42:10 -0800531_LANGUAGES = {
Craig Tillere9c959d2015-01-18 10:23:26 -0800532 'c++': CLanguage('cxx', 'c++'),
533 'c': CLanguage('c', 'c'),
murgatroid992c8d5162015-01-26 10:41:21 -0800534 'node': NodeLanguage(),
Nathaniel Manista840615e2015-01-22 20:31:47 +0000535 'php': PhpLanguage(),
536 'python': PythonLanguage(),
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800537 'ruby': RubyLanguage(),
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100538 'csharp': CSharpLanguage(),
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700539 'objc' : ObjCLanguage(),
Jan Tattermusch70a57e42016-02-20 18:50:27 -0800540 'sanity': Sanity()
Craig Tillereb272bc2015-01-30 13:13:14 -0800541 }
Nicolas Nobleddef2462015-01-06 18:08:25 -0800542
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700543_WINDOWS_CONFIG = {
544 'dbg': 'Debug',
545 'opt': 'Release',
Jan Tattermusche4a69182015-12-15 09:53:01 -0800546 'gcov': 'Debug',
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700547 }
548
David Garcia Quintase90cd372015-05-31 18:15:26 -0700549
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800550def _windows_arch_option(arch):
551 """Returns msbuild cmdline option for selected architecture."""
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800552 if arch == 'default' or arch == 'x86':
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800553 return '/p:Platform=Win32'
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800554 elif arch == 'x64':
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800555 return '/p:Platform=x64'
556 else:
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800557 print 'Architecture %s not supported.' % arch
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800558 sys.exit(1)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800559
Jan Tattermuschf08018a2016-01-26 08:22:09 -0800560
561def _check_arch_option(arch):
562 """Checks that architecture option is valid."""
563 if platform_string() == 'windows':
564 _windows_arch_option(arch)
565 elif platform_string() == 'linux':
566 # On linux, we need to be running under docker with the right architecture.
Jan Tattermusch07fb0422016-01-26 10:46:56 -0800567 runtime_arch = platform.architecture()[0]
Jan Tattermuschf08018a2016-01-26 08:22:09 -0800568 if arch == 'default':
569 return
570 elif runtime_arch == '64bit' and arch == 'x64':
571 return
572 elif runtime_arch == '32bit' and arch == 'x86':
573 return
574 else:
575 print 'Architecture %s does not match current runtime architecture.' % arch
576 sys.exit(1)
577 else:
578 if args.arch != 'default':
579 print 'Architecture %s not supported on current platform.' % args.arch
580 sys.exit(1)
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800581
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800582
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800583def _windows_build_bat(compiler):
584 """Returns name of build.bat for selected compiler."""
585 if compiler == 'default' or compiler == 'vs2013':
586 return 'vsprojects\\build_vs2013.bat'
587 elif compiler == 'vs2015':
588 return 'vsprojects\\build_vs2015.bat'
589 elif compiler == 'vs2010':
590 return 'vsprojects\\build_vs2010.bat'
591 else:
592 print 'Compiler %s not supported.' % compiler
593 sys.exit(1)
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800594
595
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800596def _windows_toolset_option(compiler):
597 """Returns msbuild PlatformToolset for selected compiler."""
598 if compiler == 'default' or compiler == 'vs2013':
599 return '/p:PlatformToolset=v120'
600 elif compiler == 'vs2015':
601 return '/p:PlatformToolset=v140'
602 elif compiler == 'vs2010':
603 return '/p:PlatformToolset=v100'
604 else:
605 print 'Compiler %s not supported.' % compiler
606 sys.exit(1)
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800607
608
Jan Tattermusche70b3c52016-02-07 20:21:02 -0800609def _docker_arch_suffix(arch):
610 """Returns suffix to dockerfile dir to use."""
611 if arch == 'default' or arch == 'x64':
612 return 'x64'
613 elif arch == 'x86':
614 return 'x86'
615 else:
616 print 'Architecture %s not supported with current settings.' % arch
617 sys.exit(1)
618
619
Jan Tattermusch788ee232016-01-26 12:19:44 -0800620def _get_dockerfile_dir(language, cfg, arch):
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800621 """Returns dockerfile to use"""
Jan Tattermusch788ee232016-01-26 12:19:44 -0800622 custom = language.dockerfile_dir(cfg, arch)
623 if custom:
624 return custom
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800625 else:
Jan Tattermusche70b3c52016-02-07 20:21:02 -0800626 return 'tools/dockerfile/grpc_tests_multilang_%s' % _docker_arch_suffix(arch)
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800627
David Garcia Quintase90cd372015-05-31 18:15:26 -0700628def runs_per_test_type(arg_str):
629 """Auxilary function to parse the "runs_per_test" flag.
630
631 Returns:
632 A positive integer or 0, the latter indicating an infinite number of
633 runs.
634
635 Raises:
636 argparse.ArgumentTypeError: Upon invalid input.
637 """
638 if arg_str == 'inf':
639 return 0
640 try:
641 n = int(arg_str)
642 if n <= 0: raise ValueError
Craig Tiller50e53e22015-06-01 20:18:21 -0700643 return n
David Garcia Quintase90cd372015-05-31 18:15:26 -0700644 except:
Adele Zhoue4c35612015-10-16 15:34:23 -0700645 msg = '\'{}\' is not a positive integer or \'inf\''.format(arg_str)
David Garcia Quintase90cd372015-05-31 18:15:26 -0700646 raise argparse.ArgumentTypeError(msg)
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700647
648# parse command line
649argp = argparse.ArgumentParser(description='Run grpc tests.')
650argp.add_argument('-c', '--config',
651 choices=['all'] + sorted(_CONFIGS.keys()),
652 nargs='+',
653 default=_DEFAULT)
David Garcia Quintase90cd372015-05-31 18:15:26 -0700654argp.add_argument('-n', '--runs_per_test', default=1, type=runs_per_test_type,
655 help='A positive integer or "inf". If "inf", all tests will run in an '
656 'infinite loop. Especially useful in combination with "-f"')
Craig Tillerfe406ec2015-02-24 13:55:12 -0800657argp.add_argument('-r', '--regex', default='.*', type=str)
Craig Tiller5f735a62016-01-20 09:31:15 -0800658argp.add_argument('-j', '--jobs', default=multiprocessing.cpu_count(), type=int)
Craig Tiller8451e872015-02-27 09:25:51 -0800659argp.add_argument('-s', '--slowdown', default=1.0, type=float)
ctiller3040cb72015-01-07 12:13:17 -0800660argp.add_argument('-f', '--forever',
661 default=False,
662 action='store_const',
663 const=True)
Nicolas "Pixel" Noblea7df3f92015-02-26 22:07:04 +0100664argp.add_argument('-t', '--travis',
665 default=False,
666 action='store_const',
667 const=True)
Nicolas Noble044db742015-01-14 16:57:24 -0800668argp.add_argument('--newline_on_success',
669 default=False,
670 action='store_const',
671 const=True)
Craig Tiller686fb262015-01-15 07:39:09 -0800672argp.add_argument('-l', '--language',
Craig Tiller60f15e62015-05-13 09:05:17 -0700673 choices=['all'] + sorted(_LANGUAGES.keys()),
Craig Tiller686fb262015-01-15 07:39:09 -0800674 nargs='+',
Craig Tiller60f15e62015-05-13 09:05:17 -0700675 default=['all'])
Craig Tillercd43da82015-05-29 08:41:29 -0700676argp.add_argument('-S', '--stop_on_failure',
677 default=False,
678 action='store_const',
679 const=True)
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700680argp.add_argument('--use_docker',
681 default=False,
682 action='store_const',
683 const=True,
Adele Zhoue4c35612015-10-16 15:34:23 -0700684 help='Run all the tests under docker. That provides ' +
685 'additional isolation and prevents the need to install ' +
686 'language specific prerequisites. Only available on Linux.')
Craig Tillerd4509a12015-09-28 09:18:40 -0700687argp.add_argument('--allow_flakes',
688 default=False,
689 action='store_const',
690 const=True,
Adele Zhoue4c35612015-10-16 15:34:23 -0700691 help='Allow flaky tests to show as passing (re-runs failed tests up to five times)')
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800692argp.add_argument('--arch',
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800693 choices=['default', 'x86', 'x64'],
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800694 default='default',
695 help='Selects architecture to target. For some platforms "default" is the only supported choice.')
696argp.add_argument('--compiler',
697 choices=['default', 'vs2010', 'vs2013', 'vs2015'],
698 default='default',
699 help='Selects compiler to use. For some platforms "default" is the only supported choice.')
700argp.add_argument('--build_only',
701 default=False,
702 action='store_const',
703 const=True,
704 help='Perform all the build steps but dont run any tests.')
Craig Tiller5f735a62016-01-20 09:31:15 -0800705argp.add_argument('--measure_cpu_costs', default=False, action='store_const', const=True,
706 help='Measure the cpu costs of tests')
Craig Tiller1676f912016-01-05 10:49:44 -0800707argp.add_argument('--update_submodules', default=[], nargs='*',
708 help='Update some submodules before building. If any are updated, also run generate_projects. ' +
709 'Submodules are specified as SUBMODULE_NAME:BRANCH; if BRANCH is omitted, master is assumed.')
Craig Tiller234b6e72015-05-23 10:12:40 -0700710argp.add_argument('-a', '--antagonists', default=0, type=int)
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +0200711argp.add_argument('-x', '--xml_report', default=None, type=str,
712 help='Generates a JUnit-compatible XML report')
Nicolas Nobleddef2462015-01-06 18:08:25 -0800713args = argp.parse_args()
714
Craig Tiller5f735a62016-01-20 09:31:15 -0800715jobset.measure_cpu_costs = args.measure_cpu_costs
716
Craig Tiller1676f912016-01-05 10:49:44 -0800717# update submodules if necessary
Craig Tillerb361b4e2016-01-06 11:44:17 -0800718need_to_regenerate_projects = False
719for spec in args.update_submodules:
720 spec = spec.split(':', 1)
721 if len(spec) == 1:
722 submodule = spec[0]
723 branch = 'master'
724 elif len(spec) == 2:
725 submodule = spec[0]
726 branch = spec[1]
727 cwd = 'third_party/%s' % submodule
728 def git(cmd, cwd=cwd):
729 print 'in %s: git %s' % (cwd, cmd)
730 subprocess.check_call('git %s' % cmd, cwd=cwd, shell=True)
731 git('fetch')
732 git('checkout %s' % branch)
733 git('pull origin %s' % branch)
734 if os.path.exists('src/%s/gen_build_yaml.py' % submodule):
735 need_to_regenerate_projects = True
736if need_to_regenerate_projects:
737 if jobset.platform_string() == 'linux':
738 subprocess.check_call('tools/buildgen/generate_projects.sh', shell=True)
739 else:
740 print 'WARNING: may need to regenerate projects, but since we are not on'
741 print ' Linux this step is being skipped. Compilation MAY fail.'
Craig Tiller1676f912016-01-05 10:49:44 -0800742
743
Nicolas Nobleddef2462015-01-06 18:08:25 -0800744# grab config
Craig Tiller738c3342015-01-12 14:28:33 -0800745run_configs = set(_CONFIGS[cfg]
746 for cfg in itertools.chain.from_iterable(
747 _CONFIGS.iterkeys() if x == 'all' else [x]
748 for x in args.config))
749build_configs = set(cfg.build_config for cfg in run_configs)
Craig Tillerf1973b02015-01-16 12:32:13 -0800750
Craig Tiller06805272015-06-11 14:46:47 -0700751if args.travis:
murgatroid99d3b5b7f2015-10-06 17:02:03 -0700752 _FORCE_ENVIRON_FOR_WRAPPERS = {'GRPC_TRACE': 'api'}
Craig Tiller06805272015-06-11 14:46:47 -0700753
Adele Zhou6b9527c2015-11-20 15:56:35 -0800754if 'all' in args.language:
Craig Tiller1676f912016-01-05 10:49:44 -0800755 lang_list = _LANGUAGES.keys()
Adele Zhou6b9527c2015-11-20 15:56:35 -0800756else:
757 lang_list = args.language
Craig Tiller16900662016-01-07 19:30:54 -0800758# We don't support code coverage on some languages
759if 'gcov' in args.config:
760 for bad in ['objc', 'sanity', 'build']:
761 if bad in lang_list:
762 lang_list.remove(bad)
Adele Zhou6b9527c2015-11-20 15:56:35 -0800763
764languages = set(_LANGUAGES[l] for l in lang_list)
murgatroid99132ce6a2015-03-04 17:29:14 -0800765
766if len(build_configs) > 1:
767 for language in languages:
768 if not language.supports_multi_config():
769 print language, 'does not support multiple build configurations'
770 sys.exit(1)
771
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800772language_make_options=[]
773if any(language.make_options() for language in languages):
774 if len(languages) != 1:
775 print 'languages with custom make options cannot be built simultaneously with other languages'
776 sys.exit(1)
777 else:
778 language_make_options = next(iter(languages)).make_options()
779
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800780if len(languages) != 1 or len(build_configs) != 1:
781 print 'Multi-language and multi-config testing is not supported.'
782 sys.exit(1)
783
784if args.use_docker:
785 if not args.travis:
786 print 'Seen --use_docker flag, will run tests under docker.'
787 print
788 print 'IMPORTANT: The changes you are testing need to be locally committed'
789 print 'because only the committed changes in the current branch will be'
790 print 'copied to the docker environment.'
791 time.sleep(5)
792
793 child_argv = [ arg for arg in sys.argv if not arg == '--use_docker' ]
Jan Tattermusched342b12016-01-26 14:40:31 -0800794 run_tests_cmd = 'python tools/run_tests/run_tests.py %s' % ' '.join(child_argv[1:])
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800795
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800796 env = os.environ.copy()
797 env['RUN_TESTS_COMMAND'] = run_tests_cmd
Jan Tattermusch788ee232016-01-26 12:19:44 -0800798 env['DOCKERFILE_DIR'] = _get_dockerfile_dir(next(iter(languages)),
799 next(iter(build_configs)),
800 args.arch)
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800801 env['DOCKER_RUN_SCRIPT'] = 'tools/jenkins/docker_run_tests.sh'
802 if args.xml_report:
803 env['XML_REPORT'] = args.xml_report
804 if not args.travis:
805 env['TTY_FLAG'] = '-t' # enables Ctrl-C when not on Jenkins.
806
807 subprocess.check_call(['tools/jenkins/build_docker_and_run_tests.sh'],
808 shell=True,
809 env=env)
810 sys.exit(0)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800811
Jan Tattermuschf08018a2016-01-26 08:22:09 -0800812if platform_string() != 'windows' and args.compiler != 'default':
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800813 print 'Compiler %s not supported on current platform.' % args.compiler
814 sys.exit(1)
815
Jan Tattermuschf08018a2016-01-26 08:22:09 -0800816_check_arch_option(args.arch)
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800817
Jan Tattermuschfba65302016-01-25 18:21:14 -0800818def make_jobspec(cfg, targets, makefile='Makefile'):
819 if platform_string() == 'windows':
Craig Tillerfc3c0c42015-09-01 16:47:54 -0700820 extra_args = []
Craig Tillerb5391e12015-09-03 14:35:18 -0700821 # better do parallel compilation
Jan Tattermusch47eeb2b2015-10-07 14:09:18 -0700822 # empirically /m:2 gives the best performance/price and should prevent
823 # overloading the windows workers.
Adele Zhoue4c35612015-10-16 15:34:23 -0700824 extra_args.extend(['/m:2'])
Craig Tillerb5391e12015-09-03 14:35:18 -0700825 # disable PDB generation: it's broken, and we don't need it during CI
Adele Zhoue4c35612015-10-16 15:34:23 -0700826 extra_args.extend(['/p:Jenkins=true'])
Craig Tiller6fd23842015-09-01 07:36:31 -0700827 return [
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800828 jobset.JobSpec([_windows_build_bat(args.compiler),
murgatroid99cf08daf2015-09-21 15:33:16 -0700829 'vsprojects\\%s.sln' % target,
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800830 '/p:Configuration=%s' % _WINDOWS_CONFIG[cfg],
831 _windows_toolset_option(args.compiler),
832 _windows_arch_option(args.arch)] +
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800833 extra_args +
834 language_make_options,
Craig Tiller590105a2016-01-19 13:03:46 -0800835 shell=True, timeout_seconds=None)
Craig Tiller6fd23842015-09-01 07:36:31 -0700836 for target in targets]
Jan Tattermuschfba65302016-01-25 18:21:14 -0800837 else:
murgatroid998ae409f2015-10-26 16:39:00 -0700838 if targets:
839 return [jobset.JobSpec([os.getenv('MAKE', 'make'),
840 '-f', makefile,
Craig Tillerdd6f7ed2016-01-21 12:54:42 -0800841 '-j', '%d' % args.jobs,
Craig Tiller71a86042016-01-15 14:59:58 -0800842 'EXTRA_DEFINES=GRPC_TEST_SLOWDOWN_MACHINE_FACTOR=%f' % args.slowdown,
843 'CONFIG=%s' % cfg] +
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800844 language_make_options +
Craig Tiller71a86042016-01-15 14:59:58 -0800845 ([] if not args.travis else ['JENKINS_BUILD=1']) +
846 targets,
Craig Tiller590105a2016-01-19 13:03:46 -0800847 timeout_seconds=None)]
murgatroid998ae409f2015-10-26 16:39:00 -0700848 else:
849 return []
Jan Tattermuschfba65302016-01-25 18:21:14 -0800850
murgatroid99a3e244f2015-09-22 11:25:53 -0700851make_targets = {}
852for l in languages:
853 makefile = l.makefile_name()
854 make_targets[makefile] = make_targets.get(makefile, set()).union(
Craig Tiller883064c2015-11-04 10:06:10 -0800855 set(l.make_targets(args.regex)))
Craig Tiller5058c692015-04-08 09:42:04 -0700856
Jan Tattermusche4a69182015-12-15 09:53:01 -0800857def build_step_environ(cfg):
858 environ = {'CONFIG': cfg}
Jan Tattermusch68016a12015-12-16 15:31:33 -0800859 msbuild_cfg = _WINDOWS_CONFIG.get(cfg)
Jan Tattermusche4a69182015-12-15 09:53:01 -0800860 if msbuild_cfg:
861 environ['MSBUILD_CONFIG'] = msbuild_cfg
862 return environ
863
murgatroid99fddac962015-09-22 09:20:11 -0700864build_steps = list(set(
Jan Tattermusche4a69182015-12-15 09:53:01 -0800865 jobset.JobSpec(cmdline, environ=build_step_environ(cfg), flake_retries=5)
murgatroid99256d3df2015-09-21 16:58:02 -0700866 for cfg in build_configs
867 for l in languages
868 for cmdline in l.pre_build_steps()))
Craig Tillerbd4e3782015-09-01 06:48:55 -0700869if make_targets:
murgatroid99a3e244f2015-09-22 11:25:53 -0700870 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 -0700871 build_steps.extend(set(make_commands))
Craig Tiller5058c692015-04-08 09:42:04 -0700872build_steps.extend(set(
Craig Tiller590105a2016-01-19 13:03:46 -0800873 jobset.JobSpec(cmdline, environ=build_step_environ(cfg), timeout_seconds=None)
murgatroid99132ce6a2015-03-04 17:29:14 -0800874 for cfg in build_configs
Craig Tiller547db2b2015-01-30 14:08:39 -0800875 for l in languages
Craig Tiller533b1a22015-05-29 08:41:29 -0700876 for cmdline in l.build_steps()))
Craig Tillerf1973b02015-01-16 12:32:13 -0800877
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200878post_tests_steps = list(set(
Jan Tattermusche4a69182015-12-15 09:53:01 -0800879 jobset.JobSpec(cmdline, environ=build_step_environ(cfg))
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200880 for cfg in build_configs
881 for l in languages
882 for cmdline in l.post_tests_steps()))
Nicolas Nobleddef2462015-01-06 18:08:25 -0800883runs_per_test = args.runs_per_test
ctiller3040cb72015-01-07 12:13:17 -0800884forever = args.forever
Nicolas Nobleddef2462015-01-06 18:08:25 -0800885
Nicolas Nobleddef2462015-01-06 18:08:25 -0800886
Craig Tiller71735182015-01-15 17:07:13 -0800887class TestCache(object):
Craig Tillerb50d1662015-01-15 17:28:21 -0800888 """Cache for running tests."""
889
David Klempner25739582015-02-11 15:57:32 -0800890 def __init__(self, use_cache_results):
Craig Tiller71735182015-01-15 17:07:13 -0800891 self._last_successful_run = {}
David Klempner25739582015-02-11 15:57:32 -0800892 self._use_cache_results = use_cache_results
Craig Tiller69cd2372015-06-11 09:38:09 -0700893 self._last_save = time.time()
Craig Tiller71735182015-01-15 17:07:13 -0800894
895 def should_run(self, cmdline, bin_hash):
Craig Tiller71735182015-01-15 17:07:13 -0800896 if cmdline not in self._last_successful_run:
897 return True
898 if self._last_successful_run[cmdline] != bin_hash:
899 return True
David Klempner25739582015-02-11 15:57:32 -0800900 if not self._use_cache_results:
901 return True
Craig Tiller71735182015-01-15 17:07:13 -0800902 return False
903
904 def finished(self, cmdline, bin_hash):
Craig Tiller547db2b2015-01-30 14:08:39 -0800905 self._last_successful_run[cmdline] = bin_hash
Craig Tiller69cd2372015-06-11 09:38:09 -0700906 if time.time() - self._last_save > 1:
907 self.save()
Craig Tiller71735182015-01-15 17:07:13 -0800908
909 def dump(self):
Craig Tillerb50d1662015-01-15 17:28:21 -0800910 return [{'cmdline': k, 'hash': v}
911 for k, v in self._last_successful_run.iteritems()]
Craig Tiller71735182015-01-15 17:07:13 -0800912
913 def parse(self, exdump):
914 self._last_successful_run = dict((o['cmdline'], o['hash']) for o in exdump)
915
916 def save(self):
917 with open('.run_tests_cache', 'w') as f:
Craig Tiller261dd982015-01-16 16:41:45 -0800918 f.write(json.dumps(self.dump()))
Craig Tiller69cd2372015-06-11 09:38:09 -0700919 self._last_save = time.time()
Craig Tiller71735182015-01-15 17:07:13 -0800920
Craig Tiller1cc11db2015-01-15 22:50:50 -0800921 def maybe_load(self):
922 if os.path.exists('.run_tests_cache'):
923 with open('.run_tests_cache') as f:
Craig Tiller261dd982015-01-16 16:41:45 -0800924 self.parse(json.loads(f.read()))
Craig Tiller71735182015-01-15 17:07:13 -0800925
926
Craig Tillerf53d9c82015-08-04 14:19:43 -0700927def _start_port_server(port_server_port):
928 # check if a compatible port server is running
929 # if incompatible (version mismatch) ==> start a new one
930 # if not running ==> start a new one
931 # otherwise, leave it up
932 try:
Craig Tillerfe4939f2015-10-06 12:55:36 -0700933 version = int(urllib2.urlopen(
934 'http://localhost:%d/version_number' % port_server_port,
935 timeout=1).read())
936 print 'detected port server running version %d' % version
Craig Tillerf53d9c82015-08-04 14:19:43 -0700937 running = True
Craig Tillerfe4939f2015-10-06 12:55:36 -0700938 except Exception as e:
Craig Tiller0d6499e2015-10-05 14:00:47 -0700939 print 'failed to detect port server: %s' % sys.exc_info()[0]
Craig Tillerfe4939f2015-10-06 12:55:36 -0700940 print e.strerror
Craig Tillerf53d9c82015-08-04 14:19:43 -0700941 running = False
942 if running:
Craig Tillerfe4939f2015-10-06 12:55:36 -0700943 current_version = int(subprocess.check_output(
Jan Tattermusch3bd08272015-11-04 19:24:37 -0800944 [sys.executable, os.path.abspath('tools/run_tests/port_server.py'),
945 'dump_version']))
Craig Tillerfe4939f2015-10-06 12:55:36 -0700946 print 'my port server is version %d' % current_version
947 running = (version >= current_version)
948 if not running:
949 print 'port_server version mismatch: killing the old one'
950 urllib2.urlopen('http://localhost:%d/quitquitquit' % port_server_port).read()
951 time.sleep(1)
Craig Tillerf53d9c82015-08-04 14:19:43 -0700952 if not running:
Craig Tillerf0a293e2015-10-12 10:05:50 -0700953 fd, logfile = tempfile.mkstemp()
954 os.close(fd)
955 print 'starting port_server, with log file %s' % logfile
Jan Tattermusch3bd08272015-11-04 19:24:37 -0800956 args = [sys.executable, os.path.abspath('tools/run_tests/port_server.py'),
957 '-p', '%d' % port_server_port, '-l', logfile]
Craig Tiller367d41d2015-10-12 13:00:22 -0700958 env = dict(os.environ)
959 env['BUILD_ID'] = 'pleaseDontKillMeJenkins'
Nicolas "Pixel" Noblef72d7b52015-12-03 03:07:43 +0100960 if platform_string() == 'windows':
Jan Tattermusch3bd08272015-11-04 19:24:37 -0800961 # Working directory of port server needs to be outside of Jenkins
962 # workspace to prevent file lock issues.
963 tempdir = tempfile.mkdtemp()
Craig Tillerd2c39712015-10-12 11:08:49 -0700964 port_server = subprocess.Popen(
Craig Tiller367d41d2015-10-12 13:00:22 -0700965 args,
966 env=env,
Jan Tattermusch3bd08272015-11-04 19:24:37 -0800967 cwd=tempdir,
Craig Tiller367d41d2015-10-12 13:00:22 -0700968 creationflags = 0x00000008, # detached process
969 close_fds=True)
Craig Tillerd2c39712015-10-12 11:08:49 -0700970 else:
971 port_server = subprocess.Popen(
972 args,
Craig Tiller367d41d2015-10-12 13:00:22 -0700973 env=env,
Craig Tillerd2c39712015-10-12 11:08:49 -0700974 preexec_fn=os.setsid,
975 close_fds=True)
Craig Tillerf0a293e2015-10-12 10:05:50 -0700976 time.sleep(1)
Craig Tiller8b5f4dc2015-08-26 08:02:01 -0700977 # ensure port server is up
Craig Tillerabd37fd2015-08-26 07:54:01 -0700978 waits = 0
Craig Tillerf53d9c82015-08-04 14:19:43 -0700979 while True:
Craig Tillerabd37fd2015-08-26 07:54:01 -0700980 if waits > 10:
Craig Tillerf0a293e2015-10-12 10:05:50 -0700981 print 'killing port server due to excessive start up waits'
Craig Tillerabd37fd2015-08-26 07:54:01 -0700982 port_server.kill()
Craig Tillera2f38b02015-09-24 11:19:17 -0700983 if port_server.poll() is not None:
Craig Tiller0d6499e2015-10-05 14:00:47 -0700984 print 'port_server failed to start'
Craig Tillerf0a293e2015-10-12 10:05:50 -0700985 # try one final time: maybe another build managed to start one
986 time.sleep(1)
987 try:
988 urllib2.urlopen('http://localhost:%d/get' % port_server_port,
989 timeout=1).read()
990 print 'last ditch attempt to contact port server succeeded'
991 break
992 except:
993 traceback.print_exc();
994 port_log = open(logfile, 'r').read()
995 print port_log
996 sys.exit(1)
Craig Tillerf53d9c82015-08-04 14:19:43 -0700997 try:
Craig Tillerabd37fd2015-08-26 07:54:01 -0700998 urllib2.urlopen('http://localhost:%d/get' % port_server_port,
999 timeout=1).read()
Craig Tillerf0a293e2015-10-12 10:05:50 -07001000 print 'port server is up and ready'
Craig Tillerf53d9c82015-08-04 14:19:43 -07001001 break
Craig Tiller31fdaa42015-09-25 13:09:59 -07001002 except socket.timeout:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001003 print 'waiting for port_server: timeout'
Craig Tillerf0a293e2015-10-12 10:05:50 -07001004 traceback.print_exc();
1005 time.sleep(1)
Craig Tiller31fdaa42015-09-25 13:09:59 -07001006 waits += 1
Craig Tillerf53d9c82015-08-04 14:19:43 -07001007 except urllib2.URLError:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001008 print 'waiting for port_server: urlerror'
Craig Tillerf0a293e2015-10-12 10:05:50 -07001009 traceback.print_exc();
1010 time.sleep(1)
Craig Tillerabd37fd2015-08-26 07:54:01 -07001011 waits += 1
Craig Tillerf53d9c82015-08-04 14:19:43 -07001012 except:
Craig Tillerf0a293e2015-10-12 10:05:50 -07001013 traceback.print_exc();
Craig Tillerf53d9c82015-08-04 14:19:43 -07001014 port_server.kill()
1015 raise
1016
1017
Adele Zhoud5fffa52015-10-23 15:51:42 -07001018def _calculate_num_runs_failures(list_of_results):
1019 """Caculate number of runs and failures for a particular test.
1020
1021 Args:
1022 list_of_results: (List) of JobResult object.
1023 Returns:
1024 A tuple of total number of runs and failures.
1025 """
1026 num_runs = len(list_of_results) # By default, there is 1 run per JobResult.
1027 num_failures = 0
1028 for jobresult in list_of_results:
1029 if jobresult.retries > 0:
1030 num_runs += jobresult.retries
1031 if jobresult.num_failures > 0:
1032 num_failures += jobresult.num_failures
1033 return num_runs, num_failures
1034
Adele Zhou6b9527c2015-11-20 15:56:35 -08001035
Craig Tillereb9de8b2016-01-08 08:57:41 -08001036# _build_and_run results
1037class BuildAndRunError(object):
1038
1039 BUILD = object()
1040 TEST = object()
1041 POST_TEST = object()
1042
1043
1044# returns a list of things that failed (or an empty list on success)
Craig Tillerf53d9c82015-08-04 14:19:43 -07001045def _build_and_run(
Jan Tattermusch2dd156e2015-12-04 18:26:17 -08001046 check_cancelled, newline_on_success, cache, xml_report=None, build_only=False):
ctiller3040cb72015-01-07 12:13:17 -08001047 """Do one pass of building & running tests."""
murgatroid99666450e2015-01-26 13:03:31 -08001048 # build latest sequentially
Jan Tattermuschaab1e512016-01-28 09:30:44 -08001049 num_failures, resultset = jobset.run(
Adele Zhoue4c35612015-10-16 15:34:23 -07001050 build_steps, maxjobs=1, stop_on_failure=True,
Craig Tiller883064c2015-11-04 10:06:10 -08001051 newline_on_success=newline_on_success, travis=args.travis)
Adele Zhoue4c35612015-10-16 15:34:23 -07001052 if num_failures:
Craig Tillereb9de8b2016-01-08 08:57:41 -08001053 return [BuildAndRunError.BUILD]
Craig Tillerb361b4e2016-01-06 11:44:17 -08001054
Jan Tattermusch2dd156e2015-12-04 18:26:17 -08001055 if build_only:
Jan Tattermuschaab1e512016-01-28 09:30:44 -08001056 if xml_report:
1057 report_utils.render_junit_xml_report(resultset, xml_report)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001058 return []
ctiller3040cb72015-01-07 12:13:17 -08001059
Craig Tiller234b6e72015-05-23 10:12:40 -07001060 # start antagonists
David Garcia Quintas79e389f2015-06-02 17:49:42 -07001061 antagonists = [subprocess.Popen(['tools/run_tests/antagonist.py'])
Craig Tiller234b6e72015-05-23 10:12:40 -07001062 for _ in range(0, args.antagonists)]
Craig Tillerfe4939f2015-10-06 12:55:36 -07001063 port_server_port = 32767
Craig Tillerf53d9c82015-08-04 14:19:43 -07001064 _start_port_server(port_server_port)
Adele Zhou7cf72112015-11-04 11:18:43 -08001065 resultset = None
Adele Zhou803af152015-11-30 15:16:16 -08001066 num_test_failures = 0
Craig Tiller234b6e72015-05-23 10:12:40 -07001067 try:
David Garcia Quintase90cd372015-05-31 18:15:26 -07001068 infinite_runs = runs_per_test == 0
yang-g6c1fdc62015-08-18 11:57:42 -07001069 one_run = set(
1070 spec
1071 for config in run_configs
1072 for language in languages
Craig Tiller883064c2015-11-04 10:06:10 -08001073 for spec in language.test_specs(config, args)
yang-g6c1fdc62015-08-18 11:57:42 -07001074 if re.search(args.regex, spec.shortname))
David Garcia Quintas79e389f2015-06-02 17:49:42 -07001075 # When running on travis, we want out test runs to be as similar as possible
1076 # for reproducibility purposes.
Craig Tiller883064c2015-11-04 10:06:10 -08001077 if args.travis:
David Garcia Quintas79e389f2015-06-02 17:49:42 -07001078 massaged_one_run = sorted(one_run, key=lambda x: x.shortname)
1079 else:
1080 # whereas otherwise, we want to shuffle things up to give all tests a
1081 # chance to run.
1082 massaged_one_run = list(one_run) # random.shuffle needs an indexable seq.
1083 random.shuffle(massaged_one_run) # which it modifies in-place.
Craig Tillerf7b7c892015-06-22 14:33:25 -07001084 if infinite_runs:
1085 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 -07001086 runs_sequence = (itertools.repeat(massaged_one_run) if infinite_runs
1087 else itertools.repeat(massaged_one_run, runs_per_test))
David Garcia Quintase90cd372015-05-31 18:15:26 -07001088 all_runs = itertools.chain.from_iterable(runs_sequence)
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +02001089
Adele Zhou803af152015-11-30 15:16:16 -08001090 num_test_failures, resultset = jobset.run(
Adele Zhou2271ab52015-10-28 13:59:14 -07001091 all_runs, check_cancelled, newline_on_success=newline_on_success,
Craig Tiller883064c2015-11-04 10:06:10 -08001092 travis=args.travis, infinite_runs=infinite_runs, maxjobs=args.jobs,
murgatroid998ae409f2015-10-26 16:39:00 -07001093 stop_on_failure=args.stop_on_failure,
Adele Zhouf2ca7bc2015-10-23 15:38:00 -07001094 cache=cache if not xml_report else None,
Adele Zhouf2ca7bc2015-10-23 15:38:00 -07001095 add_env={'GRPC_TEST_PORT_SERVER': 'localhost:%d' % port_server_port})
Adele Zhoud5fffa52015-10-23 15:51:42 -07001096 if resultset:
1097 for k, v in resultset.iteritems():
1098 num_runs, num_failures = _calculate_num_runs_failures(v)
1099 if num_failures == num_runs: # what about infinite_runs???
1100 jobset.message('FAILED', k, do_newline=True)
1101 elif num_failures > 0:
1102 jobset.message(
1103 'FLAKE', '%s [%d/%d runs flaked]' % (k, num_failures, num_runs),
1104 do_newline=True)
1105 else:
1106 jobset.message('PASSED', k, do_newline=True)
Craig Tiller234b6e72015-05-23 10:12:40 -07001107 finally:
1108 for antagonist in antagonists:
1109 antagonist.kill()
Adele Zhou7cf72112015-11-04 11:18:43 -08001110 if xml_report and resultset:
Adele Zhou3bc7ba42015-11-05 10:21:58 -08001111 report_utils.render_junit_xml_report(resultset, xml_report)
Craig Tillerd86a3942015-01-14 12:48:54 -08001112
Adele Zhouf2ca7bc2015-10-23 15:38:00 -07001113 number_failures, _ = jobset.run(
1114 post_tests_steps, maxjobs=1, stop_on_failure=True,
Craig Tiller883064c2015-11-04 10:06:10 -08001115 newline_on_success=newline_on_success, travis=args.travis)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001116
1117 out = []
1118 if number_failures:
1119 out.append(BuildAndRunError.POST_TEST)
1120 if num_test_failures:
1121 out.append(BuildAndRunError.TEST)
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +02001122
Craig Tiller69cd2372015-06-11 09:38:09 -07001123 if cache: cache.save()
1124
Craig Tillereb9de8b2016-01-08 08:57:41 -08001125 return out
ctiller3040cb72015-01-07 12:13:17 -08001126
1127
David Klempner25739582015-02-11 15:57:32 -08001128test_cache = TestCache(runs_per_test == 1)
Craig Tiller547db2b2015-01-30 14:08:39 -08001129test_cache.maybe_load()
Craig Tiller71735182015-01-15 17:07:13 -08001130
ctiller3040cb72015-01-07 12:13:17 -08001131if forever:
Nicolas Noble044db742015-01-14 16:57:24 -08001132 success = True
ctiller3040cb72015-01-07 12:13:17 -08001133 while True:
Craig Tiller42bc87c2015-02-23 08:50:19 -08001134 dw = watch_dirs.DirWatcher(['src', 'include', 'test', 'examples'])
ctiller3040cb72015-01-07 12:13:17 -08001135 initial_time = dw.most_recent_change()
1136 have_files_changed = lambda: dw.most_recent_change() != initial_time
Nicolas Noble044db742015-01-14 16:57:24 -08001137 previous_success = success
Craig Tillereb9de8b2016-01-08 08:57:41 -08001138 errors = _build_and_run(check_cancelled=have_files_changed,
1139 newline_on_success=False,
1140 cache=test_cache,
1141 build_only=args.build_only) == 0
1142 if not previous_success and not errors:
Nicolas Nobleb09078f2015-01-14 18:06:05 -08001143 jobset.message('SUCCESS',
1144 'All tests are now passing properly',
1145 do_newline=True)
Nicolas Noble044db742015-01-14 16:57:24 -08001146 jobset.message('IDLE', 'No change detected')
ctiller3040cb72015-01-07 12:13:17 -08001147 while not have_files_changed():
1148 time.sleep(1)
1149else:
Craig Tillereb9de8b2016-01-08 08:57:41 -08001150 errors = _build_and_run(check_cancelled=lambda: False,
Craig Tiller71735182015-01-15 17:07:13 -08001151 newline_on_success=args.newline_on_success,
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +02001152 cache=test_cache,
Jan Tattermusch2dd156e2015-12-04 18:26:17 -08001153 xml_report=args.xml_report,
1154 build_only=args.build_only)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001155 if not errors:
Nicolas Nobleb09078f2015-01-14 18:06:05 -08001156 jobset.message('SUCCESS', 'All tests passed', do_newline=True)
1157 else:
1158 jobset.message('FAILED', 'Some tests failed', do_newline=True)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001159 exit_code = 0
1160 if BuildAndRunError.BUILD in errors:
1161 exit_code |= 1
Craig Tiller4f2be362016-01-08 08:59:20 -08001162 if BuildAndRunError.TEST in errors and not args.travis:
Craig Tillereb9de8b2016-01-08 08:57:41 -08001163 exit_code |= 2
Craig Tiller4f2be362016-01-08 08:59:20 -08001164 if BuildAndRunError.POST_TEST in errors:
1165 exit_code |= 4
Craig Tillereb9de8b2016-01-08 08:57:41 -08001166 sys.exit(exit_code)