blob: 86f9cb1ce7d64b5a55c8c0b761c7998f16c7c215 [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
Jan Tattermusch3b5121b2016-02-22 17:41:05 -080058_ROOT = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), '../..'))
59os.chdir(_ROOT)
Craig Tiller2cc2b842015-02-27 11:38:31 -080060
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 Tillerde7edf82016-03-20 09:12:16 -070083 shortname=None, environ={}, cpu_cost=1.0, flaky=False):
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 Tillerde7edf82016-03-20 09:12:16 -0700105 flake_retries=5 if flaky or args.allow_flakes else 0,
Craig Tiller35505de2015-10-08 13:31:33 -0700106 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
Jan Tattermusch77db4322016-02-20 20:19:35 -0800121def _check_compiler(compiler, supported_compilers):
122 if compiler not in supported_compilers:
Jan Tattermusch3eb403f2016-03-30 07:30:55 -0700123 raise Exception('Compiler %s not supported.' % compiler)
Jan Tattermusch77db4322016-02-20 20:19:35 -0800124
125
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800126def _is_use_docker_child():
127 """Returns True if running running as a --use_docker child."""
128 return True if os.getenv('RUN_TESTS_COMMAND') else False
129
130
Craig Tillerc7449162015-01-16 14:42:10 -0800131class CLanguage(object):
132
Craig Tillere9c959d2015-01-18 10:23:26 -0800133 def __init__(self, make_target, test_lang):
Craig Tillerc7449162015-01-16 14:42:10 -0800134 self.make_target = make_target
Craig Tillerd50993d2015-08-05 08:04:36 -0700135 self.platform = platform_string()
Craig Tiller711bbe62015-08-19 12:35:16 -0700136 self.test_lang = test_lang
Craig Tillerc7449162015-01-16 14:42:10 -0800137
Jan Tattermusch77db4322016-02-20 20:19:35 -0800138 def configure(self, config, args):
139 self.config = config
140 self.args = args
141 if self.platform == 'windows':
Jan Tattermuschc96caf82016-02-22 17:31:02 -0800142 self._make_options = [_windows_toolset_option(self.args.compiler),
143 _windows_arch_option(self.args.arch)]
Jan Tattermusch77db4322016-02-20 20:19:35 -0800144 else:
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800145 self._docker_distro, self._make_options = self._compiler_options(self.args.use_docker,
146 self.args.compiler)
Jan Tattermusch77db4322016-02-20 20:19:35 -0800147
148 def test_specs(self):
Craig Tiller547db2b2015-01-30 14:08:39 -0800149 out = []
Jan Tattermusch77db4322016-02-20 20:19:35 -0800150 binaries = get_c_tests(self.args.travis, self.test_lang)
Craig Tiller711bbe62015-08-19 12:35:16 -0700151 for target in binaries:
Jan Tattermusch77db4322016-02-20 20:19:35 -0800152 if self.config.build_config in target['exclude_configs']:
murgatroid99fafeeb32015-09-22 09:13:03 -0700153 continue
Nicolas Noblee1445362015-05-11 17:40:26 -0700154 if self.platform == 'windows':
Jan Tattermusch3de6b762016-01-28 11:38:11 -0800155 binary = 'vsprojects/%s%s/%s.exe' % (
Jan Tattermusch77db4322016-02-20 20:19:35 -0800156 'x64/' if self.args.arch == 'x64' else '',
Jan Tattermuscha2d964c2016-02-22 17:33:09 -0800157 _MSBUILD_CONFIG[self.config.build_config],
Jan Tattermusch3de6b762016-01-28 11:38:11 -0800158 target['name'])
Nicolas Noblee1445362015-05-11 17:40:26 -0700159 else:
Jan Tattermusch77db4322016-02-20 20:19:35 -0800160 binary = 'bins/%s/%s' % (self.config.build_config, target['name'])
yang-g6c1fdc62015-08-18 11:57:42 -0700161 if os.path.isfile(binary):
Craig Tillerca62ff02016-02-24 22:22:57 -0800162 if 'gtest' in target and target['gtest']:
Craig Tiller0488d142016-02-24 22:34:48 -0800163 # here we parse the output of --gtest_list_tests to build up a
164 # complete list of the tests contained in a binary
165 # for each test, we then add a job to run, filtering for just that
166 # test
Craig Tillerca62ff02016-02-24 22:22:57 -0800167 with open(os.devnull, 'w') as fnull:
168 tests = subprocess.check_output([binary, '--gtest_list_tests'],
169 stderr=fnull)
170 base = None
171 for line in tests.split('\n'):
172 i = line.find('#')
173 if i >= 0: line = line[:i]
174 if not line: continue
175 if line[0] != ' ':
Craig Tiller184e4232016-02-24 22:48:56 -0800176 base = line.strip()
Craig Tillerca62ff02016-02-24 22:22:57 -0800177 else:
178 assert base is not None
179 assert line[1] == ' '
Craig Tiller184e4232016-02-24 22:48:56 -0800180 test = base + line.strip()
Craig Tillerca62ff02016-02-24 22:22:57 -0800181 cmdline = [binary] + ['--gtest_filter=%s' % test]
182 out.append(self.config.job_spec(cmdline, [binary],
183 shortname='%s:%s' % (binary, test),
184 cpu_cost=target['cpu_cost'],
185 environ={'GRPC_DEFAULT_SSL_ROOTS_FILE_PATH':
Craig Tiller1796f872016-03-25 19:42:49 -0700186 _ROOT + '/src/core/lib/tsi/test_creds/ca.pem'}))
Craig Tillerca62ff02016-02-24 22:22:57 -0800187 else:
188 cmdline = [binary] + target['args']
189 out.append(self.config.job_spec(cmdline, [binary],
190 shortname=' '.join(cmdline),
191 cpu_cost=target['cpu_cost'],
Craig Tiller33599972016-03-20 09:15:26 -0700192 flaky=target.get('flaky', False),
Craig Tillerca62ff02016-02-24 22:22:57 -0800193 environ={'GRPC_DEFAULT_SSL_ROOTS_FILE_PATH':
Craig Tiller1796f872016-03-25 19:42:49 -0700194 _ROOT + '/src/core/lib/tsi/test_creds/ca.pem'}))
Jan Tattermusch77db4322016-02-20 20:19:35 -0800195 elif self.args.regex == '.*' or self.platform == 'windows':
Adele Zhoue4c35612015-10-16 15:34:23 -0700196 print '\nWARNING: binary not found, skipping', binary
Nicolas Noblee1445362015-05-11 17:40:26 -0700197 return sorted(out)
Craig Tillerc7449162015-01-16 14:42:10 -0800198
Jan Tattermusch77db4322016-02-20 20:19:35 -0800199 def make_targets(self):
200 test_regex = self.args.regex
201 if self.platform != 'windows' and self.args.regex != '.*':
Craig Tiller883064c2015-11-04 10:06:10 -0800202 # use the regex to minimize the number of things to build
Craig Tillerb0f275e2016-01-27 10:45:50 -0800203 return [os.path.basename(target['name'])
Craig Tiller883064c2015-11-04 10:06:10 -0800204 for target in get_c_tests(False, self.test_lang)
Craig Tillerb0f275e2016-01-27 10:45:50 -0800205 if re.search(test_regex, '/' + target['name'])]
Jan Tattermusch77db4322016-02-20 20:19:35 -0800206 if self.platform == 'windows':
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700207 # don't build tools on windows just yet
208 return ['buildtests_%s' % self.make_target]
Craig Tiller7552f0f2015-06-19 17:46:20 -0700209 return ['buildtests_%s' % self.make_target, 'tools_%s' % self.make_target]
Craig Tillerc7449162015-01-16 14:42:10 -0800210
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800211 def make_options(self):
Jan Tattermuschc96caf82016-02-22 17:31:02 -0800212 return self._make_options;
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800213
murgatroid99256d3df2015-09-21 16:58:02 -0700214 def pre_build_steps(self):
Jan Tattermusch874aec02015-10-07 19:26:19 -0700215 if self.platform == 'windows':
216 return [['tools\\run_tests\\pre_build_c.bat']]
217 else:
218 return []
murgatroid99256d3df2015-09-21 16:58:02 -0700219
Craig Tillerc7449162015-01-16 14:42:10 -0800220 def build_steps(self):
221 return []
222
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200223 def post_tests_steps(self):
224 if self.platform == 'windows':
225 return []
226 else:
227 return [['tools/run_tests/post_tests_c.sh']]
228
murgatroid99a3e244f2015-09-22 11:25:53 -0700229 def makefile_name(self):
230 return 'Makefile'
231
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800232 def _clang_make_options(self):
233 return ['CC=clang', 'CXX=clang++', 'LD=clang', 'LDXX=clang++']
234
Jan Tattermusch9bb70622016-03-18 10:28:54 -0700235 def _gcc44_make_options(self):
236 return ['CC=gcc-4.4', 'CXX=g++-4.4', 'LD=gcc-4.4', 'LDXX=g++-4.4']
237
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800238 def _compiler_options(self, use_docker, compiler):
239 """Returns docker distro and make options to use for given compiler."""
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800240 if _is_use_docker_child():
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800241 return ("already_under_docker", [])
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800242 if not use_docker:
243 _check_compiler(compiler, ['default'])
244
245 if compiler == 'gcc4.9' or compiler == 'default':
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800246 return ('jessie', [])
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800247 elif compiler == 'gcc4.4':
Jan Tattermusch9bb70622016-03-18 10:28:54 -0700248 return ('wheezy', self._gcc44_make_options())
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800249 elif compiler == 'gcc5.3':
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800250 return ('ubuntu1604', [])
251 elif compiler == 'clang3.4':
252 return ('ubuntu1404', self._clang_make_options())
253 elif compiler == 'clang3.6':
254 return ('ubuntu1604', self._clang_make_options())
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800255 else:
256 raise Exception('Compiler %s not supported.' % compiler)
257
Jan Tattermusch77db4322016-02-20 20:19:35 -0800258 def dockerfile_dir(self):
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800259 return 'tools/dockerfile/test/cxx_%s_%s' % (self._docker_distro,
260 _docker_arch_suffix(self.args.arch))
Jan Tattermusch788ee232016-01-26 12:19:44 -0800261
murgatroid99132ce6a2015-03-04 17:29:14 -0800262 def __str__(self):
263 return self.make_target
264
Craig Tillercc0535d2015-12-08 15:14:47 -0800265
murgatroid992c8d5162015-01-26 10:41:21 -0800266class NodeLanguage(object):
267
Jan Tattermusche477b842016-02-06 22:19:01 -0800268 def __init__(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800269 self.platform = platform_string()
Jan Tattermusche477b842016-02-06 22:19:01 -0800270 self.node_version = '0.12'
271
Jan Tattermusch77db4322016-02-20 20:19:35 -0800272 def configure(self, config, args):
273 self.config = config
274 self.args = args
275 _check_compiler(self.args.compiler, ['default'])
276
277 def test_specs(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800278 if self.platform == 'windows':
Jan Tattermusch77db4322016-02-20 20:19:35 -0800279 return [self.config.job_spec(['tools\\run_tests\\run_node.bat'], None)]
Michael Lumishaaa876a2016-02-10 15:27:58 -0800280 else:
Jan Tattermusch77db4322016-02-20 20:19:35 -0800281 return [self.config.job_spec(['tools/run_tests/run_node.sh', self.node_version],
282 None,
283 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
murgatroid992c8d5162015-01-26 10:41:21 -0800284
murgatroid99256d3df2015-09-21 16:58:02 -0700285 def pre_build_steps(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800286 if self.platform == 'windows':
287 return [['tools\\run_tests\\pre_build_node.bat']]
288 else:
289 return [['tools/run_tests/pre_build_node.sh', self.node_version]]
murgatroid99256d3df2015-09-21 16:58:02 -0700290
Jan Tattermusch77db4322016-02-20 20:19:35 -0800291 def make_targets(self):
murgatroid99db5b1602015-10-01 13:20:11 -0700292 return []
murgatroid992c8d5162015-01-26 10:41:21 -0800293
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800294 def make_options(self):
295 return []
296
murgatroid992c8d5162015-01-26 10:41:21 -0800297 def build_steps(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800298 if self.platform == 'windows':
299 return [['tools\\run_tests\\build_node.bat']]
300 else:
301 return [['tools/run_tests/build_node.sh', self.node_version]]
Craig Tillerc7449162015-01-16 14:42:10 -0800302
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200303 def post_tests_steps(self):
Michael Lumish60d38cb2016-03-04 13:05:04 -0800304 return []
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200305
murgatroid99a3e244f2015-09-22 11:25:53 -0700306 def makefile_name(self):
307 return 'Makefile'
308
Jan Tattermusch77db4322016-02-20 20:19:35 -0800309 def dockerfile_dir(self):
310 return 'tools/dockerfile/test/node_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800311
murgatroid99132ce6a2015-03-04 17:29:14 -0800312 def __str__(self):
313 return 'node'
314
Craig Tiller99775822015-01-30 13:07:16 -0800315
Craig Tillerc7449162015-01-16 14:42:10 -0800316class PhpLanguage(object):
317
Jan Tattermusch77db4322016-02-20 20:19:35 -0800318 def configure(self, config, args):
319 self.config = config
320 self.args = args
321 _check_compiler(self.args.compiler, ['default'])
322
323 def test_specs(self):
324 return [self.config.job_spec(['src/php/bin/run_tests.sh'], None,
325 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
Craig Tillerc7449162015-01-16 14:42:10 -0800326
murgatroid99256d3df2015-09-21 16:58:02 -0700327 def pre_build_steps(self):
328 return []
329
Jan Tattermusch77db4322016-02-20 20:19:35 -0800330 def make_targets(self):
Craig Tilleraf7cf542015-05-22 10:07:34 -0700331 return ['static_c', 'shared_c']
Craig Tillerc7449162015-01-16 14:42:10 -0800332
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800333 def make_options(self):
334 return []
335
Craig Tillerc7449162015-01-16 14:42:10 -0800336 def build_steps(self):
337 return [['tools/run_tests/build_php.sh']]
338
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200339 def post_tests_steps(self):
Stanley Cheunga6b95482016-01-13 16:10:48 -0800340 return [['tools/run_tests/post_tests_php.sh']]
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200341
murgatroid99a3e244f2015-09-22 11:25:53 -0700342 def makefile_name(self):
343 return 'Makefile'
344
Jan Tattermusch77db4322016-02-20 20:19:35 -0800345 def dockerfile_dir(self):
346 return 'tools/dockerfile/test/php_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800347
murgatroid99132ce6a2015-03-04 17:29:14 -0800348 def __str__(self):
349 return 'php'
350
Craig Tillerc7449162015-01-16 14:42:10 -0800351
Nathaniel Manista840615e2015-01-22 20:31:47 +0000352class PythonLanguage(object):
353
Craig Tiller49f61322015-03-03 13:02:11 -0800354 def __init__(self):
Masood Malekghassemi2b841622015-07-28 17:39:02 -0700355 self._build_python_versions = ['2.7']
Masood Malekghassemie5f70022015-06-29 09:20:26 -0700356 self._has_python_versions = []
Craig Tiller49f61322015-03-03 13:02:11 -0800357
Jan Tattermusch77db4322016-02-20 20:19:35 -0800358 def configure(self, config, args):
359 self.config = config
360 self.args = args
361 _check_compiler(self.args.compiler, ['default'])
362
363 def test_specs(self):
Jan Tattermusch072ebaa2016-03-01 18:33:12 -0800364 # load list of known test suites
365 with open('src/python/grpcio/tests/tests.json') as tests_json_file:
366 tests_json = json.load(tests_json_file)
Masood Malekghassemi2b841622015-07-28 17:39:02 -0700367 environment = dict(_FORCE_ENVIRON_FOR_WRAPPERS)
368 environment['PYVER'] = '2.7'
Jan Tattermusch072ebaa2016-03-01 18:33:12 -0800369 if self.config.build_config != 'gcov':
370 return [self.config.job_spec(
371 ['tools/run_tests/run_python.sh'],
372 None,
373 environ=dict(environment.items() +
Masood Malekghassemif7ff8be2016-03-09 15:27:28 -0800374 [('GRPC_PYTHON_TESTRUNNER_FILTER', suite_name)]),
Jan Tattermusch072ebaa2016-03-01 18:33:12 -0800375 shortname='py.test.%s' % suite_name,
376 timeout_seconds=5*60)
377 for suite_name in tests_json]
378 else:
379 return [self.config.job_spec(['tools/run_tests/run_python.sh'],
380 None,
381 environ=environment,
382 shortname='py.test.coverage',
383 timeout_seconds=15*60)]
384
Nathaniel Manista840615e2015-01-22 20:31:47 +0000385
murgatroid99256d3df2015-09-21 16:58:02 -0700386 def pre_build_steps(self):
387 return []
388
Jan Tattermusch77db4322016-02-20 20:19:35 -0800389 def make_targets(self):
Craig Tilleraf7cf542015-05-22 10:07:34 -0700390 return ['static_c', 'grpc_python_plugin', 'shared_c']
Nathaniel Manista840615e2015-01-22 20:31:47 +0000391
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800392 def make_options(self):
393 return []
394
Nathaniel Manista840615e2015-01-22 20:31:47 +0000395 def build_steps(self):
Masood Malekghassemie5f70022015-06-29 09:20:26 -0700396 commands = []
397 for python_version in self._build_python_versions:
398 try:
399 with open(os.devnull, 'w') as output:
400 subprocess.check_call(['which', 'python' + python_version],
401 stdout=output, stderr=output)
402 commands.append(['tools/run_tests/build_python.sh', python_version])
403 self._has_python_versions.append(python_version)
404 except:
405 jobset.message('WARNING', 'Missing Python ' + python_version,
406 do_newline=True)
407 return commands
Nathaniel Manista840615e2015-01-22 20:31:47 +0000408
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200409 def post_tests_steps(self):
410 return []
411
murgatroid99a3e244f2015-09-22 11:25:53 -0700412 def makefile_name(self):
413 return 'Makefile'
414
Jan Tattermusch77db4322016-02-20 20:19:35 -0800415 def dockerfile_dir(self):
416 return 'tools/dockerfile/test/python_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800417
murgatroid99132ce6a2015-03-04 17:29:14 -0800418 def __str__(self):
419 return 'python'
420
Craig Tillerd625d812015-04-08 15:52:35 -0700421
murgatroid996a4c4fa2015-02-27 12:08:57 -0800422class RubyLanguage(object):
423
Jan Tattermusch77db4322016-02-20 20:19:35 -0800424 def configure(self, config, args):
425 self.config = config
426 self.args = args
427 _check_compiler(self.args.compiler, ['default'])
428
429 def test_specs(self):
430 return [self.config.job_spec(['tools/run_tests/run_ruby.sh'], None,
431 timeout_seconds=10*60,
432 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
murgatroid996a4c4fa2015-02-27 12:08:57 -0800433
murgatroid99256d3df2015-09-21 16:58:02 -0700434 def pre_build_steps(self):
Nicolas "Pixel" Noblebcf988f2015-10-08 03:00:42 +0200435 return [['tools/run_tests/pre_build_ruby.sh']]
murgatroid99256d3df2015-09-21 16:58:02 -0700436
Jan Tattermusch4651bef2016-02-23 08:31:25 -0800437 def make_targets(self):
murgatroid997d243df2016-02-18 09:58:05 -0800438 return []
murgatroid996a4c4fa2015-02-27 12:08:57 -0800439
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800440 def make_options(self):
441 return []
442
murgatroid996a4c4fa2015-02-27 12:08:57 -0800443 def build_steps(self):
444 return [['tools/run_tests/build_ruby.sh']]
445
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200446 def post_tests_steps(self):
Nicolas "Pixel" Noble7ef1e532015-12-02 00:55:33 +0100447 return [['tools/run_tests/post_tests_ruby.sh']]
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200448
murgatroid99a3e244f2015-09-22 11:25:53 -0700449 def makefile_name(self):
450 return 'Makefile'
451
Jan Tattermusch77db4322016-02-20 20:19:35 -0800452 def dockerfile_dir(self):
453 return 'tools/dockerfile/test/ruby_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800454
murgatroid99132ce6a2015-03-04 17:29:14 -0800455 def __str__(self):
456 return 'ruby'
457
Craig Tillerd625d812015-04-08 15:52:35 -0700458
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800459class CSharpLanguage(object):
Jan Tattermusch77db4322016-02-20 20:19:35 -0800460
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700461 def __init__(self):
Craig Tillerd50993d2015-08-05 08:04:36 -0700462 self.platform = platform_string()
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700463
Jan Tattermusch77db4322016-02-20 20:19:35 -0800464 def configure(self, config, args):
465 self.config = config
466 self.args = args
Jan Tattermusch6d28d352016-03-25 15:07:22 -0700467 if self.platform == 'windows':
468 self._make_options = [_windows_toolset_option(self.args.compiler),
469 _windows_arch_option(self.args.arch)]
470 else:
471 _check_compiler(self.args.compiler, ['default'])
472 if self.platform == 'mac':
473 # On Mac, official distribution of mono is 32bit.
474 self._make_options = ['EMBED_OPENSSL=true', 'EMBED_ZLIB=true',
475 'CFLAGS=-arch i386', 'LDFLAGS=-arch i386']
476 else:
477 self._make_options = ['EMBED_OPENSSL=true', 'EMBED_ZLIB=true']
Jan Tattermusch77db4322016-02-20 20:19:35 -0800478
479 def test_specs(self):
Jan Tattermusch03c01062015-12-11 14:28:56 -0800480 with open('src/csharp/tests.json') as f:
481 tests_json = json.load(f)
482 assemblies = tests_json['assemblies']
483 tests = tests_json['tests']
484
Jan Tattermuscha2d964c2016-02-22 17:33:09 -0800485 msbuild_config = _MSBUILD_CONFIG[self.config.build_config]
Jan Tattermusch03c01062015-12-11 14:28:56 -0800486 assembly_files = ['%s/bin/%s/%s.dll' % (a, msbuild_config, a)
487 for a in assemblies]
488
489 extra_args = ['-labels'] + assembly_files
490
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700491 if self.platform == 'windows':
Jan Tattermusch03c01062015-12-11 14:28:56 -0800492 script_name = 'tools\\run_tests\\run_csharp.bat'
493 extra_args += ['-domain=None']
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700494 else:
Jan Tattermusch03c01062015-12-11 14:28:56 -0800495 script_name = 'tools/run_tests/run_csharp.sh'
Jan Tattermuschbf3b1532015-10-26 10:24:42 -0700496
Jan Tattermusch77db4322016-02-20 20:19:35 -0800497 if self.config.build_config == 'gcov':
Jan Tattermuschbdf4b2e2015-10-28 08:22:34 -0700498 # On Windows, we only collect C# code coverage.
499 # On Linux, we only collect coverage for native extension.
500 # For code coverage all tests need to run as one suite.
Jan Tattermusch77db4322016-02-20 20:19:35 -0800501 return [self.config.job_spec([script_name] + extra_args, None,
502 shortname='csharp.coverage',
503 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
Jan Tattermusch61c3a832015-10-27 17:54:50 -0700504 else:
Jan Tattermusch03c01062015-12-11 14:28:56 -0800505 specs = []
506 for test in tests:
507 cmdline = [script_name, '-run=%s' % test] + extra_args
508 if self.platform == 'windows':
509 # use different output directory for each test to prevent
510 # TestResult.xml clash between parallel test runs.
511 cmdline += ['-work=test-result/%s' % uuid.uuid4()]
Jan Tattermusch77db4322016-02-20 20:19:35 -0800512 specs.append(self.config.job_spec(cmdline, None,
513 shortname='csharp.%s' % test,
514 environ=_FORCE_ENVIRON_FOR_WRAPPERS))
Jan Tattermusch03c01062015-12-11 14:28:56 -0800515 return specs
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800516
murgatroid99256d3df2015-09-21 16:58:02 -0700517 def pre_build_steps(self):
Jan Tattermusch48423fc2015-10-07 18:59:16 -0700518 if self.platform == 'windows':
Jan Tattermusch874aec02015-10-07 19:26:19 -0700519 return [['tools\\run_tests\\pre_build_csharp.bat']]
Jan Tattermusch48423fc2015-10-07 18:59:16 -0700520 else:
521 return [['tools/run_tests/pre_build_csharp.sh']]
murgatroid99256d3df2015-09-21 16:58:02 -0700522
Jan Tattermusch77db4322016-02-20 20:19:35 -0800523 def make_targets(self):
Jan Tattermusch6d28d352016-03-25 15:07:22 -0700524 return ['grpc_csharp_ext']
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800525
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800526 def make_options(self):
Jan Tattermusch6d28d352016-03-25 15:07:22 -0700527 return self._make_options;
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800528
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800529 def build_steps(self):
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700530 if self.platform == 'windows':
Jan Tattermusch6d28d352016-03-25 15:07:22 -0700531 return [[_windows_build_bat(self.args.compiler),
532 'src/csharp/Grpc.sln',
533 '/p:Configuration=%s' % _MSBUILD_CONFIG[self.config.build_config]]]
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700534 else:
535 return [['tools/run_tests/build_csharp.sh']]
Nathaniel Manista840615e2015-01-22 20:31:47 +0000536
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200537 def post_tests_steps(self):
538 return []
539
murgatroid99a3e244f2015-09-22 11:25:53 -0700540 def makefile_name(self):
541 return 'Makefile'
542
Jan Tattermusch77db4322016-02-20 20:19:35 -0800543 def dockerfile_dir(self):
544 return 'tools/dockerfile/test/csharp_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800545
murgatroid99132ce6a2015-03-04 17:29:14 -0800546 def __str__(self):
547 return 'csharp'
548
Craig Tillerd625d812015-04-08 15:52:35 -0700549
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700550class ObjCLanguage(object):
551
Jan Tattermusch77db4322016-02-20 20:19:35 -0800552 def configure(self, config, args):
553 self.config = config
554 self.args = args
555 _check_compiler(self.args.compiler, ['default'])
556
557 def test_specs(self):
558 return [self.config.job_spec(['src/objective-c/tests/run_tests.sh'], None,
559 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700560
murgatroid99256d3df2015-09-21 16:58:02 -0700561 def pre_build_steps(self):
562 return []
563
Jan Tattermusch77db4322016-02-20 20:19:35 -0800564 def make_targets(self):
Jorge Canizalesd0b32e92015-07-30 23:08:43 -0700565 return ['grpc_objective_c_plugin', 'interop_server']
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700566
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800567 def make_options(self):
568 return []
569
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700570 def build_steps(self):
Jorge Canizalesd0b32e92015-07-30 23:08:43 -0700571 return [['src/objective-c/tests/build_tests.sh']]
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700572
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200573 def post_tests_steps(self):
574 return []
575
murgatroid99a3e244f2015-09-22 11:25:53 -0700576 def makefile_name(self):
577 return 'Makefile'
578
Jan Tattermusch77db4322016-02-20 20:19:35 -0800579 def dockerfile_dir(self):
Jan Tattermusch788ee232016-01-26 12:19:44 -0800580 return None
581
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700582 def __str__(self):
583 return 'objc'
584
585
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100586class Sanity(object):
587
Jan Tattermusch77db4322016-02-20 20:19:35 -0800588 def configure(self, config, args):
589 self.config = config
590 self.args = args
591 _check_compiler(self.args.compiler, ['default'])
592
593 def test_specs(self):
Craig Tiller94d04a52016-01-20 10:58:23 -0800594 import yaml
Jan Tattermusch788ee232016-01-26 12:19:44 -0800595 with open('tools/run_tests/sanity/sanity_tests.yaml', 'r') as f:
Jan Tattermusch77db4322016-02-20 20:19:35 -0800596 return [self.config.job_spec(cmd['script'].split(), None,
597 timeout_seconds=None, environ={'TEST': 'true'},
598 cpu_cost=cmd.get('cpu_cost', 1))
Craig Tiller94d04a52016-01-20 10:58:23 -0800599 for cmd in yaml.load(f)]
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100600
murgatroid99256d3df2015-09-21 16:58:02 -0700601 def pre_build_steps(self):
602 return []
603
Jan Tattermusch77db4322016-02-20 20:19:35 -0800604 def make_targets(self):
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100605 return ['run_dep_checks']
606
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800607 def make_options(self):
608 return []
609
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100610 def build_steps(self):
611 return []
612
Nicolas "Pixel" Noble87879b32015-10-12 23:28:53 +0200613 def post_tests_steps(self):
614 return []
615
murgatroid99a3e244f2015-09-22 11:25:53 -0700616 def makefile_name(self):
617 return 'Makefile'
618
Jan Tattermusch77db4322016-02-20 20:19:35 -0800619 def dockerfile_dir(self):
Jan Tattermusche70b3c52016-02-07 20:21:02 -0800620 return 'tools/dockerfile/test/sanity'
Jan Tattermusch788ee232016-01-26 12:19:44 -0800621
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100622 def __str__(self):
623 return 'sanity'
624
Nicolas "Pixel" Noblee55cd7f2015-04-14 17:59:13 +0200625
Craig Tiller738c3342015-01-12 14:28:33 -0800626# different configurations we can run under
Craig Tillera0f85172016-01-20 15:56:06 -0800627with open('tools/run_tests/configs.json') as f:
Craig Tiller1dce9062016-01-20 17:01:56 -0800628 _CONFIGS = dict((cfg['config'], Config(**cfg)) for cfg in ast.literal_eval(f.read()))
Craig Tiller738c3342015-01-12 14:28:33 -0800629
630
Craig Tillerc7449162015-01-16 14:42:10 -0800631_LANGUAGES = {
Craig Tillere9c959d2015-01-18 10:23:26 -0800632 'c++': CLanguage('cxx', 'c++'),
633 'c': CLanguage('c', 'c'),
murgatroid992c8d5162015-01-26 10:41:21 -0800634 'node': NodeLanguage(),
Nathaniel Manista840615e2015-01-22 20:31:47 +0000635 'php': PhpLanguage(),
636 'python': PythonLanguage(),
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800637 'ruby': RubyLanguage(),
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100638 'csharp': CSharpLanguage(),
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700639 'objc' : ObjCLanguage(),
Jan Tattermusch70a57e42016-02-20 18:50:27 -0800640 'sanity': Sanity()
Craig Tillereb272bc2015-01-30 13:13:14 -0800641 }
Nicolas Nobleddef2462015-01-06 18:08:25 -0800642
Jan Tattermusch77db4322016-02-20 20:19:35 -0800643
Jan Tattermuscha2d964c2016-02-22 17:33:09 -0800644_MSBUILD_CONFIG = {
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700645 'dbg': 'Debug',
646 'opt': 'Release',
Jan Tattermusche4a69182015-12-15 09:53:01 -0800647 'gcov': 'Debug',
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700648 }
649
David Garcia Quintase90cd372015-05-31 18:15:26 -0700650
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800651def _windows_arch_option(arch):
652 """Returns msbuild cmdline option for selected architecture."""
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800653 if arch == 'default' or arch == 'x86':
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800654 return '/p:Platform=Win32'
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800655 elif arch == 'x64':
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800656 return '/p:Platform=x64'
657 else:
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800658 print 'Architecture %s not supported.' % arch
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800659 sys.exit(1)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800660
Jan Tattermuschf08018a2016-01-26 08:22:09 -0800661
662def _check_arch_option(arch):
663 """Checks that architecture option is valid."""
664 if platform_string() == 'windows':
665 _windows_arch_option(arch)
666 elif platform_string() == 'linux':
667 # On linux, we need to be running under docker with the right architecture.
Jan Tattermusch07fb0422016-01-26 10:46:56 -0800668 runtime_arch = platform.architecture()[0]
Jan Tattermuschf08018a2016-01-26 08:22:09 -0800669 if arch == 'default':
670 return
671 elif runtime_arch == '64bit' and arch == 'x64':
672 return
673 elif runtime_arch == '32bit' and arch == 'x86':
674 return
675 else:
676 print 'Architecture %s does not match current runtime architecture.' % arch
677 sys.exit(1)
678 else:
679 if args.arch != 'default':
680 print 'Architecture %s not supported on current platform.' % args.arch
681 sys.exit(1)
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800682
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800683
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800684def _windows_build_bat(compiler):
685 """Returns name of build.bat for selected compiler."""
686 if compiler == 'default' or compiler == 'vs2013':
687 return 'vsprojects\\build_vs2013.bat'
688 elif compiler == 'vs2015':
689 return 'vsprojects\\build_vs2015.bat'
690 elif compiler == 'vs2010':
691 return 'vsprojects\\build_vs2010.bat'
692 else:
693 print 'Compiler %s not supported.' % compiler
694 sys.exit(1)
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800695
696
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800697def _windows_toolset_option(compiler):
698 """Returns msbuild PlatformToolset for selected compiler."""
699 if compiler == 'default' or compiler == 'vs2013':
700 return '/p:PlatformToolset=v120'
701 elif compiler == 'vs2015':
702 return '/p:PlatformToolset=v140'
703 elif compiler == 'vs2010':
704 return '/p:PlatformToolset=v100'
705 else:
706 print 'Compiler %s not supported.' % compiler
707 sys.exit(1)
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800708
709
Jan Tattermusche70b3c52016-02-07 20:21:02 -0800710def _docker_arch_suffix(arch):
711 """Returns suffix to dockerfile dir to use."""
712 if arch == 'default' or arch == 'x64':
713 return 'x64'
714 elif arch == 'x86':
715 return 'x86'
716 else:
717 print 'Architecture %s not supported with current settings.' % arch
718 sys.exit(1)
719
720
David Garcia Quintase90cd372015-05-31 18:15:26 -0700721def runs_per_test_type(arg_str):
722 """Auxilary function to parse the "runs_per_test" flag.
723
724 Returns:
725 A positive integer or 0, the latter indicating an infinite number of
726 runs.
727
728 Raises:
729 argparse.ArgumentTypeError: Upon invalid input.
730 """
731 if arg_str == 'inf':
732 return 0
733 try:
734 n = int(arg_str)
735 if n <= 0: raise ValueError
Craig Tiller50e53e22015-06-01 20:18:21 -0700736 return n
David Garcia Quintase90cd372015-05-31 18:15:26 -0700737 except:
Adele Zhoue4c35612015-10-16 15:34:23 -0700738 msg = '\'{}\' is not a positive integer or \'inf\''.format(arg_str)
David Garcia Quintase90cd372015-05-31 18:15:26 -0700739 raise argparse.ArgumentTypeError(msg)
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700740
741# parse command line
742argp = argparse.ArgumentParser(description='Run grpc tests.')
743argp.add_argument('-c', '--config',
Jan Tattermusch77db4322016-02-20 20:19:35 -0800744 choices=sorted(_CONFIGS.keys()),
745 default='opt')
David Garcia Quintase90cd372015-05-31 18:15:26 -0700746argp.add_argument('-n', '--runs_per_test', default=1, type=runs_per_test_type,
747 help='A positive integer or "inf". If "inf", all tests will run in an '
748 'infinite loop. Especially useful in combination with "-f"')
Craig Tillerfe406ec2015-02-24 13:55:12 -0800749argp.add_argument('-r', '--regex', default='.*', type=str)
Craig Tiller5f735a62016-01-20 09:31:15 -0800750argp.add_argument('-j', '--jobs', default=multiprocessing.cpu_count(), type=int)
Craig Tiller8451e872015-02-27 09:25:51 -0800751argp.add_argument('-s', '--slowdown', default=1.0, type=float)
ctiller3040cb72015-01-07 12:13:17 -0800752argp.add_argument('-f', '--forever',
753 default=False,
754 action='store_const',
755 const=True)
Nicolas "Pixel" Noblea7df3f92015-02-26 22:07:04 +0100756argp.add_argument('-t', '--travis',
757 default=False,
758 action='store_const',
759 const=True)
Nicolas Noble044db742015-01-14 16:57:24 -0800760argp.add_argument('--newline_on_success',
761 default=False,
762 action='store_const',
763 const=True)
Craig Tiller686fb262015-01-15 07:39:09 -0800764argp.add_argument('-l', '--language',
Craig Tiller60f15e62015-05-13 09:05:17 -0700765 choices=['all'] + sorted(_LANGUAGES.keys()),
Craig Tiller686fb262015-01-15 07:39:09 -0800766 nargs='+',
Craig Tiller60f15e62015-05-13 09:05:17 -0700767 default=['all'])
Craig Tillercd43da82015-05-29 08:41:29 -0700768argp.add_argument('-S', '--stop_on_failure',
769 default=False,
770 action='store_const',
771 const=True)
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700772argp.add_argument('--use_docker',
773 default=False,
774 action='store_const',
775 const=True,
Adele Zhoue4c35612015-10-16 15:34:23 -0700776 help='Run all the tests under docker. That provides ' +
777 'additional isolation and prevents the need to install ' +
778 'language specific prerequisites. Only available on Linux.')
Craig Tillerd4509a12015-09-28 09:18:40 -0700779argp.add_argument('--allow_flakes',
780 default=False,
781 action='store_const',
782 const=True,
Adele Zhoue4c35612015-10-16 15:34:23 -0700783 help='Allow flaky tests to show as passing (re-runs failed tests up to five times)')
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800784argp.add_argument('--arch',
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800785 choices=['default', 'x86', 'x64'],
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800786 default='default',
787 help='Selects architecture to target. For some platforms "default" is the only supported choice.')
788argp.add_argument('--compiler',
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800789 choices=['default',
790 'gcc4.4', 'gcc4.9', 'gcc5.3',
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800791 'clang3.4', 'clang3.6',
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800792 'vs2010', 'vs2013', 'vs2015'],
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800793 default='default',
Jan Tattermusch77db4322016-02-20 20:19:35 -0800794 help='Selects compiler to use. Allowed values depend on the platform and language.')
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800795argp.add_argument('--build_only',
796 default=False,
797 action='store_const',
798 const=True,
799 help='Perform all the build steps but dont run any tests.')
Craig Tiller5f735a62016-01-20 09:31:15 -0800800argp.add_argument('--measure_cpu_costs', default=False, action='store_const', const=True,
801 help='Measure the cpu costs of tests')
Craig Tiller1676f912016-01-05 10:49:44 -0800802argp.add_argument('--update_submodules', default=[], nargs='*',
803 help='Update some submodules before building. If any are updated, also run generate_projects. ' +
804 'Submodules are specified as SUBMODULE_NAME:BRANCH; if BRANCH is omitted, master is assumed.')
Craig Tiller234b6e72015-05-23 10:12:40 -0700805argp.add_argument('-a', '--antagonists', default=0, type=int)
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +0200806argp.add_argument('-x', '--xml_report', default=None, type=str,
807 help='Generates a JUnit-compatible XML report')
Nicolas Nobleddef2462015-01-06 18:08:25 -0800808args = argp.parse_args()
809
Craig Tiller5f735a62016-01-20 09:31:15 -0800810jobset.measure_cpu_costs = args.measure_cpu_costs
811
Craig Tiller1676f912016-01-05 10:49:44 -0800812# update submodules if necessary
Craig Tillerb361b4e2016-01-06 11:44:17 -0800813need_to_regenerate_projects = False
814for spec in args.update_submodules:
815 spec = spec.split(':', 1)
816 if len(spec) == 1:
817 submodule = spec[0]
818 branch = 'master'
819 elif len(spec) == 2:
820 submodule = spec[0]
821 branch = spec[1]
822 cwd = 'third_party/%s' % submodule
823 def git(cmd, cwd=cwd):
824 print 'in %s: git %s' % (cwd, cmd)
825 subprocess.check_call('git %s' % cmd, cwd=cwd, shell=True)
826 git('fetch')
827 git('checkout %s' % branch)
828 git('pull origin %s' % branch)
829 if os.path.exists('src/%s/gen_build_yaml.py' % submodule):
830 need_to_regenerate_projects = True
831if need_to_regenerate_projects:
832 if jobset.platform_string() == 'linux':
833 subprocess.check_call('tools/buildgen/generate_projects.sh', shell=True)
834 else:
835 print 'WARNING: may need to regenerate projects, but since we are not on'
836 print ' Linux this step is being skipped. Compilation MAY fail.'
Craig Tiller1676f912016-01-05 10:49:44 -0800837
838
Nicolas Nobleddef2462015-01-06 18:08:25 -0800839# grab config
Jan Tattermusch77db4322016-02-20 20:19:35 -0800840run_config = _CONFIGS[args.config]
841build_config = run_config.build_config
Craig Tillerf1973b02015-01-16 12:32:13 -0800842
Craig Tiller06805272015-06-11 14:46:47 -0700843if args.travis:
murgatroid99d3b5b7f2015-10-06 17:02:03 -0700844 _FORCE_ENVIRON_FOR_WRAPPERS = {'GRPC_TRACE': 'api'}
Craig Tiller06805272015-06-11 14:46:47 -0700845
Adele Zhou6b9527c2015-11-20 15:56:35 -0800846if 'all' in args.language:
Craig Tiller1676f912016-01-05 10:49:44 -0800847 lang_list = _LANGUAGES.keys()
Adele Zhou6b9527c2015-11-20 15:56:35 -0800848else:
849 lang_list = args.language
Craig Tiller16900662016-01-07 19:30:54 -0800850# We don't support code coverage on some languages
851if 'gcov' in args.config:
Jan Tattermusch3b5121b2016-02-22 17:41:05 -0800852 for bad in ['objc', 'sanity']:
Craig Tiller16900662016-01-07 19:30:54 -0800853 if bad in lang_list:
854 lang_list.remove(bad)
Adele Zhou6b9527c2015-11-20 15:56:35 -0800855
856languages = set(_LANGUAGES[l] for l in lang_list)
Jan Tattermusch77db4322016-02-20 20:19:35 -0800857for l in languages:
858 l.configure(run_config, args)
murgatroid99132ce6a2015-03-04 17:29:14 -0800859
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800860language_make_options=[]
861if any(language.make_options() for language in languages):
862 if len(languages) != 1:
863 print 'languages with custom make options cannot be built simultaneously with other languages'
864 sys.exit(1)
865 else:
866 language_make_options = next(iter(languages)).make_options()
867
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800868if args.use_docker:
869 if not args.travis:
870 print 'Seen --use_docker flag, will run tests under docker.'
871 print
872 print 'IMPORTANT: The changes you are testing need to be locally committed'
873 print 'because only the committed changes in the current branch will be'
874 print 'copied to the docker environment.'
875 time.sleep(5)
876
Jan Tattermusch3b5121b2016-02-22 17:41:05 -0800877 dockerfile_dirs = set([l.dockerfile_dir() for l in languages])
878 if len(dockerfile_dirs) > 1:
Adele Zhou9506ef22016-03-02 13:53:34 -0800879 if 'gcov' in args.config:
880 dockerfile_dir = 'tools/dockerfile/test/multilang_jessie_x64'
881 print ('Using multilang_jessie_x64 docker image for code coverage for '
882 'all languages.')
883 else:
884 print ('Languages to be tested require running under different docker '
885 'images.')
886 sys.exit(1)
887 else:
888 dockerfile_dir = next(iter(dockerfile_dirs))
Craig Tillerde7edf82016-03-20 09:12:16 -0700889
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800890 child_argv = [ arg for arg in sys.argv if not arg == '--use_docker' ]
Jan Tattermusched342b12016-01-26 14:40:31 -0800891 run_tests_cmd = 'python tools/run_tests/run_tests.py %s' % ' '.join(child_argv[1:])
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800892
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800893 env = os.environ.copy()
894 env['RUN_TESTS_COMMAND'] = run_tests_cmd
Jan Tattermusch3b5121b2016-02-22 17:41:05 -0800895 env['DOCKERFILE_DIR'] = dockerfile_dir
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800896 env['DOCKER_RUN_SCRIPT'] = 'tools/jenkins/docker_run_tests.sh'
897 if args.xml_report:
898 env['XML_REPORT'] = args.xml_report
899 if not args.travis:
900 env['TTY_FLAG'] = '-t' # enables Ctrl-C when not on Jenkins.
901
902 subprocess.check_call(['tools/jenkins/build_docker_and_run_tests.sh'],
903 shell=True,
904 env=env)
905 sys.exit(0)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800906
Jan Tattermuschf08018a2016-01-26 08:22:09 -0800907_check_arch_option(args.arch)
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800908
Jan Tattermuschfba65302016-01-25 18:21:14 -0800909def make_jobspec(cfg, targets, makefile='Makefile'):
910 if platform_string() == 'windows':
Craig Tillerfc3c0c42015-09-01 16:47:54 -0700911 extra_args = []
Craig Tillerb5391e12015-09-03 14:35:18 -0700912 # better do parallel compilation
Jan Tattermusch47eeb2b2015-10-07 14:09:18 -0700913 # empirically /m:2 gives the best performance/price and should prevent
914 # overloading the windows workers.
Adele Zhoue4c35612015-10-16 15:34:23 -0700915 extra_args.extend(['/m:2'])
Craig Tillerb5391e12015-09-03 14:35:18 -0700916 # disable PDB generation: it's broken, and we don't need it during CI
Adele Zhoue4c35612015-10-16 15:34:23 -0700917 extra_args.extend(['/p:Jenkins=true'])
Craig Tiller6fd23842015-09-01 07:36:31 -0700918 return [
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800919 jobset.JobSpec([_windows_build_bat(args.compiler),
murgatroid99cf08daf2015-09-21 15:33:16 -0700920 'vsprojects\\%s.sln' % target,
Jan Tattermuscha2d964c2016-02-22 17:33:09 -0800921 '/p:Configuration=%s' % _MSBUILD_CONFIG[cfg]] +
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800922 extra_args +
923 language_make_options,
Craig Tiller590105a2016-01-19 13:03:46 -0800924 shell=True, timeout_seconds=None)
Craig Tiller6fd23842015-09-01 07:36:31 -0700925 for target in targets]
Jan Tattermuschfba65302016-01-25 18:21:14 -0800926 else:
murgatroid998ae409f2015-10-26 16:39:00 -0700927 if targets:
928 return [jobset.JobSpec([os.getenv('MAKE', 'make'),
929 '-f', makefile,
Craig Tillerdd6f7ed2016-01-21 12:54:42 -0800930 '-j', '%d' % args.jobs,
Craig Tiller71a86042016-01-15 14:59:58 -0800931 'EXTRA_DEFINES=GRPC_TEST_SLOWDOWN_MACHINE_FACTOR=%f' % args.slowdown,
932 'CONFIG=%s' % cfg] +
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800933 language_make_options +
Craig Tiller71a86042016-01-15 14:59:58 -0800934 ([] if not args.travis else ['JENKINS_BUILD=1']) +
935 targets,
Craig Tiller590105a2016-01-19 13:03:46 -0800936 timeout_seconds=None)]
murgatroid998ae409f2015-10-26 16:39:00 -0700937 else:
938 return []
Jan Tattermuschfba65302016-01-25 18:21:14 -0800939
murgatroid99a3e244f2015-09-22 11:25:53 -0700940make_targets = {}
941for l in languages:
942 makefile = l.makefile_name()
943 make_targets[makefile] = make_targets.get(makefile, set()).union(
Jan Tattermusch77db4322016-02-20 20:19:35 -0800944 set(l.make_targets()))
Craig Tiller5058c692015-04-08 09:42:04 -0700945
Jan Tattermusche4a69182015-12-15 09:53:01 -0800946def build_step_environ(cfg):
947 environ = {'CONFIG': cfg}
Jan Tattermuscha2d964c2016-02-22 17:33:09 -0800948 msbuild_cfg = _MSBUILD_CONFIG.get(cfg)
Jan Tattermusche4a69182015-12-15 09:53:01 -0800949 if msbuild_cfg:
950 environ['MSBUILD_CONFIG'] = msbuild_cfg
951 return environ
952
murgatroid99fddac962015-09-22 09:20:11 -0700953build_steps = list(set(
Jan Tattermusch77db4322016-02-20 20:19:35 -0800954 jobset.JobSpec(cmdline, environ=build_step_environ(build_config), flake_retries=5)
murgatroid99256d3df2015-09-21 16:58:02 -0700955 for l in languages
956 for cmdline in l.pre_build_steps()))
Craig Tillerbd4e3782015-09-01 06:48:55 -0700957if make_targets:
Jan Tattermusch77db4322016-02-20 20:19:35 -0800958 make_commands = itertools.chain.from_iterable(make_jobspec(build_config, list(targets), makefile) for (makefile, targets) in make_targets.iteritems())
Craig Tiller6fd23842015-09-01 07:36:31 -0700959 build_steps.extend(set(make_commands))
Craig Tiller5058c692015-04-08 09:42:04 -0700960build_steps.extend(set(
Jan Tattermusch77db4322016-02-20 20:19:35 -0800961 jobset.JobSpec(cmdline, environ=build_step_environ(build_config), timeout_seconds=None)
Craig Tiller547db2b2015-01-30 14:08:39 -0800962 for l in languages
Craig Tiller533b1a22015-05-29 08:41:29 -0700963 for cmdline in l.build_steps()))
Craig Tillerf1973b02015-01-16 12:32:13 -0800964
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200965post_tests_steps = list(set(
Jan Tattermusch77db4322016-02-20 20:19:35 -0800966 jobset.JobSpec(cmdline, environ=build_step_environ(build_config))
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200967 for l in languages
968 for cmdline in l.post_tests_steps()))
Nicolas Nobleddef2462015-01-06 18:08:25 -0800969runs_per_test = args.runs_per_test
ctiller3040cb72015-01-07 12:13:17 -0800970forever = args.forever
Nicolas Nobleddef2462015-01-06 18:08:25 -0800971
Nicolas Nobleddef2462015-01-06 18:08:25 -0800972
Craig Tiller71735182015-01-15 17:07:13 -0800973class TestCache(object):
Craig Tillerb50d1662015-01-15 17:28:21 -0800974 """Cache for running tests."""
975
David Klempner25739582015-02-11 15:57:32 -0800976 def __init__(self, use_cache_results):
Craig Tiller71735182015-01-15 17:07:13 -0800977 self._last_successful_run = {}
David Klempner25739582015-02-11 15:57:32 -0800978 self._use_cache_results = use_cache_results
Craig Tiller69cd2372015-06-11 09:38:09 -0700979 self._last_save = time.time()
Craig Tiller71735182015-01-15 17:07:13 -0800980
981 def should_run(self, cmdline, bin_hash):
Craig Tiller71735182015-01-15 17:07:13 -0800982 if cmdline not in self._last_successful_run:
983 return True
984 if self._last_successful_run[cmdline] != bin_hash:
985 return True
David Klempner25739582015-02-11 15:57:32 -0800986 if not self._use_cache_results:
987 return True
Craig Tiller71735182015-01-15 17:07:13 -0800988 return False
989
990 def finished(self, cmdline, bin_hash):
Craig Tiller547db2b2015-01-30 14:08:39 -0800991 self._last_successful_run[cmdline] = bin_hash
Craig Tiller69cd2372015-06-11 09:38:09 -0700992 if time.time() - self._last_save > 1:
993 self.save()
Craig Tiller71735182015-01-15 17:07:13 -0800994
995 def dump(self):
Craig Tillerb50d1662015-01-15 17:28:21 -0800996 return [{'cmdline': k, 'hash': v}
997 for k, v in self._last_successful_run.iteritems()]
Craig Tiller71735182015-01-15 17:07:13 -0800998
999 def parse(self, exdump):
1000 self._last_successful_run = dict((o['cmdline'], o['hash']) for o in exdump)
1001
1002 def save(self):
1003 with open('.run_tests_cache', 'w') as f:
Craig Tiller261dd982015-01-16 16:41:45 -08001004 f.write(json.dumps(self.dump()))
Craig Tiller69cd2372015-06-11 09:38:09 -07001005 self._last_save = time.time()
Craig Tiller71735182015-01-15 17:07:13 -08001006
Craig Tiller1cc11db2015-01-15 22:50:50 -08001007 def maybe_load(self):
1008 if os.path.exists('.run_tests_cache'):
1009 with open('.run_tests_cache') as f:
Craig Tiller261dd982015-01-16 16:41:45 -08001010 self.parse(json.loads(f.read()))
Craig Tiller71735182015-01-15 17:07:13 -08001011
1012
Craig Tillerf53d9c82015-08-04 14:19:43 -07001013def _start_port_server(port_server_port):
1014 # check if a compatible port server is running
1015 # if incompatible (version mismatch) ==> start a new one
1016 # if not running ==> start a new one
1017 # otherwise, leave it up
1018 try:
Craig Tillerfe4939f2015-10-06 12:55:36 -07001019 version = int(urllib2.urlopen(
1020 'http://localhost:%d/version_number' % port_server_port,
1021 timeout=1).read())
1022 print 'detected port server running version %d' % version
Craig Tillerf53d9c82015-08-04 14:19:43 -07001023 running = True
Craig Tillerfe4939f2015-10-06 12:55:36 -07001024 except Exception as e:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001025 print 'failed to detect port server: %s' % sys.exc_info()[0]
Craig Tillerfe4939f2015-10-06 12:55:36 -07001026 print e.strerror
Craig Tillerf53d9c82015-08-04 14:19:43 -07001027 running = False
1028 if running:
Craig Tillerfe4939f2015-10-06 12:55:36 -07001029 current_version = int(subprocess.check_output(
Jan Tattermusch3bd08272015-11-04 19:24:37 -08001030 [sys.executable, os.path.abspath('tools/run_tests/port_server.py'),
1031 'dump_version']))
Craig Tillerfe4939f2015-10-06 12:55:36 -07001032 print 'my port server is version %d' % current_version
1033 running = (version >= current_version)
1034 if not running:
1035 print 'port_server version mismatch: killing the old one'
1036 urllib2.urlopen('http://localhost:%d/quitquitquit' % port_server_port).read()
1037 time.sleep(1)
Craig Tillerf53d9c82015-08-04 14:19:43 -07001038 if not running:
Craig Tillerf0a293e2015-10-12 10:05:50 -07001039 fd, logfile = tempfile.mkstemp()
1040 os.close(fd)
1041 print 'starting port_server, with log file %s' % logfile
Jan Tattermusch3bd08272015-11-04 19:24:37 -08001042 args = [sys.executable, os.path.abspath('tools/run_tests/port_server.py'),
1043 '-p', '%d' % port_server_port, '-l', logfile]
Craig Tiller367d41d2015-10-12 13:00:22 -07001044 env = dict(os.environ)
1045 env['BUILD_ID'] = 'pleaseDontKillMeJenkins'
Nicolas "Pixel" Noblef72d7b52015-12-03 03:07:43 +01001046 if platform_string() == 'windows':
Jan Tattermusch3bd08272015-11-04 19:24:37 -08001047 # Working directory of port server needs to be outside of Jenkins
1048 # workspace to prevent file lock issues.
1049 tempdir = tempfile.mkdtemp()
Craig Tillerd2c39712015-10-12 11:08:49 -07001050 port_server = subprocess.Popen(
Craig Tiller367d41d2015-10-12 13:00:22 -07001051 args,
1052 env=env,
Jan Tattermusch3bd08272015-11-04 19:24:37 -08001053 cwd=tempdir,
Craig Tiller367d41d2015-10-12 13:00:22 -07001054 creationflags = 0x00000008, # detached process
1055 close_fds=True)
Craig Tillerd2c39712015-10-12 11:08:49 -07001056 else:
1057 port_server = subprocess.Popen(
1058 args,
Craig Tiller367d41d2015-10-12 13:00:22 -07001059 env=env,
Craig Tillerd2c39712015-10-12 11:08:49 -07001060 preexec_fn=os.setsid,
1061 close_fds=True)
Craig Tillerf0a293e2015-10-12 10:05:50 -07001062 time.sleep(1)
Craig Tiller8b5f4dc2015-08-26 08:02:01 -07001063 # ensure port server is up
Craig Tillerabd37fd2015-08-26 07:54:01 -07001064 waits = 0
Craig Tillerf53d9c82015-08-04 14:19:43 -07001065 while True:
Craig Tillerabd37fd2015-08-26 07:54:01 -07001066 if waits > 10:
Craig Tillerf0a293e2015-10-12 10:05:50 -07001067 print 'killing port server due to excessive start up waits'
Craig Tillerabd37fd2015-08-26 07:54:01 -07001068 port_server.kill()
Craig Tillera2f38b02015-09-24 11:19:17 -07001069 if port_server.poll() is not None:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001070 print 'port_server failed to start'
Craig Tillerf0a293e2015-10-12 10:05:50 -07001071 # try one final time: maybe another build managed to start one
1072 time.sleep(1)
1073 try:
1074 urllib2.urlopen('http://localhost:%d/get' % port_server_port,
1075 timeout=1).read()
1076 print 'last ditch attempt to contact port server succeeded'
1077 break
1078 except:
Jan Tattermusch3b5121b2016-02-22 17:41:05 -08001079 traceback.print_exc()
Craig Tillerf0a293e2015-10-12 10:05:50 -07001080 port_log = open(logfile, 'r').read()
1081 print port_log
1082 sys.exit(1)
Craig Tillerf53d9c82015-08-04 14:19:43 -07001083 try:
Craig Tillerabd37fd2015-08-26 07:54:01 -07001084 urllib2.urlopen('http://localhost:%d/get' % port_server_port,
1085 timeout=1).read()
Craig Tillerf0a293e2015-10-12 10:05:50 -07001086 print 'port server is up and ready'
Craig Tillerf53d9c82015-08-04 14:19:43 -07001087 break
Craig Tiller31fdaa42015-09-25 13:09:59 -07001088 except socket.timeout:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001089 print 'waiting for port_server: timeout'
Craig Tillerf0a293e2015-10-12 10:05:50 -07001090 traceback.print_exc();
1091 time.sleep(1)
Craig Tiller31fdaa42015-09-25 13:09:59 -07001092 waits += 1
Craig Tillerf53d9c82015-08-04 14:19:43 -07001093 except urllib2.URLError:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001094 print 'waiting for port_server: urlerror'
Craig Tillerf0a293e2015-10-12 10:05:50 -07001095 traceback.print_exc();
1096 time.sleep(1)
Craig Tillerabd37fd2015-08-26 07:54:01 -07001097 waits += 1
Craig Tillerf53d9c82015-08-04 14:19:43 -07001098 except:
Jan Tattermusch3b5121b2016-02-22 17:41:05 -08001099 traceback.print_exc()
Craig Tillerf53d9c82015-08-04 14:19:43 -07001100 port_server.kill()
1101 raise
1102
1103
Adele Zhoud5fffa52015-10-23 15:51:42 -07001104def _calculate_num_runs_failures(list_of_results):
1105 """Caculate number of runs and failures for a particular test.
1106
1107 Args:
1108 list_of_results: (List) of JobResult object.
1109 Returns:
1110 A tuple of total number of runs and failures.
1111 """
1112 num_runs = len(list_of_results) # By default, there is 1 run per JobResult.
1113 num_failures = 0
1114 for jobresult in list_of_results:
1115 if jobresult.retries > 0:
1116 num_runs += jobresult.retries
1117 if jobresult.num_failures > 0:
1118 num_failures += jobresult.num_failures
1119 return num_runs, num_failures
1120
Adele Zhou6b9527c2015-11-20 15:56:35 -08001121
Craig Tillereb9de8b2016-01-08 08:57:41 -08001122# _build_and_run results
1123class BuildAndRunError(object):
1124
1125 BUILD = object()
1126 TEST = object()
1127 POST_TEST = object()
1128
1129
1130# returns a list of things that failed (or an empty list on success)
Craig Tillerf53d9c82015-08-04 14:19:43 -07001131def _build_and_run(
Jan Tattermusch2dd156e2015-12-04 18:26:17 -08001132 check_cancelled, newline_on_success, cache, xml_report=None, build_only=False):
ctiller3040cb72015-01-07 12:13:17 -08001133 """Do one pass of building & running tests."""
murgatroid99666450e2015-01-26 13:03:31 -08001134 # build latest sequentially
Jan Tattermuschaab1e512016-01-28 09:30:44 -08001135 num_failures, resultset = jobset.run(
Adele Zhoue4c35612015-10-16 15:34:23 -07001136 build_steps, maxjobs=1, stop_on_failure=True,
Craig Tiller883064c2015-11-04 10:06:10 -08001137 newline_on_success=newline_on_success, travis=args.travis)
Adele Zhoue4c35612015-10-16 15:34:23 -07001138 if num_failures:
Craig Tillereb9de8b2016-01-08 08:57:41 -08001139 return [BuildAndRunError.BUILD]
Craig Tillerb361b4e2016-01-06 11:44:17 -08001140
Jan Tattermusch2dd156e2015-12-04 18:26:17 -08001141 if build_only:
Jan Tattermuschaab1e512016-01-28 09:30:44 -08001142 if xml_report:
1143 report_utils.render_junit_xml_report(resultset, xml_report)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001144 return []
ctiller3040cb72015-01-07 12:13:17 -08001145
Craig Tiller234b6e72015-05-23 10:12:40 -07001146 # start antagonists
David Garcia Quintas79e389f2015-06-02 17:49:42 -07001147 antagonists = [subprocess.Popen(['tools/run_tests/antagonist.py'])
Craig Tiller234b6e72015-05-23 10:12:40 -07001148 for _ in range(0, args.antagonists)]
Craig Tillerfe4939f2015-10-06 12:55:36 -07001149 port_server_port = 32767
Craig Tillerf53d9c82015-08-04 14:19:43 -07001150 _start_port_server(port_server_port)
Adele Zhou7cf72112015-11-04 11:18:43 -08001151 resultset = None
Adele Zhou803af152015-11-30 15:16:16 -08001152 num_test_failures = 0
Craig Tiller234b6e72015-05-23 10:12:40 -07001153 try:
David Garcia Quintase90cd372015-05-31 18:15:26 -07001154 infinite_runs = runs_per_test == 0
yang-g6c1fdc62015-08-18 11:57:42 -07001155 one_run = set(
1156 spec
yang-g6c1fdc62015-08-18 11:57:42 -07001157 for language in languages
Jan Tattermusch77db4322016-02-20 20:19:35 -08001158 for spec in language.test_specs()
yang-g6c1fdc62015-08-18 11:57:42 -07001159 if re.search(args.regex, spec.shortname))
David Garcia Quintas79e389f2015-06-02 17:49:42 -07001160 # When running on travis, we want out test runs to be as similar as possible
1161 # for reproducibility purposes.
Craig Tiller883064c2015-11-04 10:06:10 -08001162 if args.travis:
David Garcia Quintas79e389f2015-06-02 17:49:42 -07001163 massaged_one_run = sorted(one_run, key=lambda x: x.shortname)
1164 else:
1165 # whereas otherwise, we want to shuffle things up to give all tests a
1166 # chance to run.
1167 massaged_one_run = list(one_run) # random.shuffle needs an indexable seq.
1168 random.shuffle(massaged_one_run) # which it modifies in-place.
Craig Tillerf7b7c892015-06-22 14:33:25 -07001169 if infinite_runs:
1170 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 -07001171 runs_sequence = (itertools.repeat(massaged_one_run) if infinite_runs
1172 else itertools.repeat(massaged_one_run, runs_per_test))
David Garcia Quintase90cd372015-05-31 18:15:26 -07001173 all_runs = itertools.chain.from_iterable(runs_sequence)
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +02001174
Adele Zhou803af152015-11-30 15:16:16 -08001175 num_test_failures, resultset = jobset.run(
Adele Zhou2271ab52015-10-28 13:59:14 -07001176 all_runs, check_cancelled, newline_on_success=newline_on_success,
Craig Tiller883064c2015-11-04 10:06:10 -08001177 travis=args.travis, infinite_runs=infinite_runs, maxjobs=args.jobs,
murgatroid998ae409f2015-10-26 16:39:00 -07001178 stop_on_failure=args.stop_on_failure,
Adele Zhouf2ca7bc2015-10-23 15:38:00 -07001179 cache=cache if not xml_report else None,
Adele Zhouf2ca7bc2015-10-23 15:38:00 -07001180 add_env={'GRPC_TEST_PORT_SERVER': 'localhost:%d' % port_server_port})
Adele Zhoud5fffa52015-10-23 15:51:42 -07001181 if resultset:
1182 for k, v in resultset.iteritems():
1183 num_runs, num_failures = _calculate_num_runs_failures(v)
1184 if num_failures == num_runs: # what about infinite_runs???
1185 jobset.message('FAILED', k, do_newline=True)
1186 elif num_failures > 0:
1187 jobset.message(
1188 'FLAKE', '%s [%d/%d runs flaked]' % (k, num_failures, num_runs),
1189 do_newline=True)
1190 else:
1191 jobset.message('PASSED', k, do_newline=True)
Craig Tiller234b6e72015-05-23 10:12:40 -07001192 finally:
1193 for antagonist in antagonists:
1194 antagonist.kill()
Adele Zhou7cf72112015-11-04 11:18:43 -08001195 if xml_report and resultset:
Adele Zhou3bc7ba42015-11-05 10:21:58 -08001196 report_utils.render_junit_xml_report(resultset, xml_report)
Craig Tillerd86a3942015-01-14 12:48:54 -08001197
Adele Zhouf2ca7bc2015-10-23 15:38:00 -07001198 number_failures, _ = jobset.run(
1199 post_tests_steps, maxjobs=1, stop_on_failure=True,
Craig Tiller883064c2015-11-04 10:06:10 -08001200 newline_on_success=newline_on_success, travis=args.travis)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001201
1202 out = []
1203 if number_failures:
1204 out.append(BuildAndRunError.POST_TEST)
1205 if num_test_failures:
1206 out.append(BuildAndRunError.TEST)
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +02001207
Craig Tiller69cd2372015-06-11 09:38:09 -07001208 if cache: cache.save()
1209
Craig Tillereb9de8b2016-01-08 08:57:41 -08001210 return out
ctiller3040cb72015-01-07 12:13:17 -08001211
1212
David Klempner25739582015-02-11 15:57:32 -08001213test_cache = TestCache(runs_per_test == 1)
Craig Tiller547db2b2015-01-30 14:08:39 -08001214test_cache.maybe_load()
Craig Tiller71735182015-01-15 17:07:13 -08001215
ctiller3040cb72015-01-07 12:13:17 -08001216if forever:
Nicolas Noble044db742015-01-14 16:57:24 -08001217 success = True
ctiller3040cb72015-01-07 12:13:17 -08001218 while True:
Craig Tiller42bc87c2015-02-23 08:50:19 -08001219 dw = watch_dirs.DirWatcher(['src', 'include', 'test', 'examples'])
ctiller3040cb72015-01-07 12:13:17 -08001220 initial_time = dw.most_recent_change()
1221 have_files_changed = lambda: dw.most_recent_change() != initial_time
Nicolas Noble044db742015-01-14 16:57:24 -08001222 previous_success = success
Craig Tillereb9de8b2016-01-08 08:57:41 -08001223 errors = _build_and_run(check_cancelled=have_files_changed,
1224 newline_on_success=False,
1225 cache=test_cache,
1226 build_only=args.build_only) == 0
1227 if not previous_success and not errors:
Nicolas Nobleb09078f2015-01-14 18:06:05 -08001228 jobset.message('SUCCESS',
1229 'All tests are now passing properly',
1230 do_newline=True)
Nicolas Noble044db742015-01-14 16:57:24 -08001231 jobset.message('IDLE', 'No change detected')
ctiller3040cb72015-01-07 12:13:17 -08001232 while not have_files_changed():
1233 time.sleep(1)
1234else:
Craig Tillereb9de8b2016-01-08 08:57:41 -08001235 errors = _build_and_run(check_cancelled=lambda: False,
Craig Tiller71735182015-01-15 17:07:13 -08001236 newline_on_success=args.newline_on_success,
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +02001237 cache=test_cache,
Jan Tattermusch2dd156e2015-12-04 18:26:17 -08001238 xml_report=args.xml_report,
1239 build_only=args.build_only)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001240 if not errors:
Nicolas Nobleb09078f2015-01-14 18:06:05 -08001241 jobset.message('SUCCESS', 'All tests passed', do_newline=True)
1242 else:
1243 jobset.message('FAILED', 'Some tests failed', do_newline=True)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001244 exit_code = 0
1245 if BuildAndRunError.BUILD in errors:
1246 exit_code |= 1
Craig Tiller4f2be362016-01-08 08:59:20 -08001247 if BuildAndRunError.TEST in errors and not args.travis:
Craig Tillereb9de8b2016-01-08 08:57:41 -08001248 exit_code |= 2
Craig Tiller4f2be362016-01-08 08:59:20 -08001249 if BuildAndRunError.POST_TEST in errors:
1250 exit_code |= 4
Craig Tillereb9de8b2016-01-08 08:57:41 -08001251 sys.exit(exit_code)