blob: c6c9b11647c62f7e69a0fc318a9867eae4329d54 [file] [log] [blame]
Nathaniel Manistaae4fbcd2015-09-23 16:29:44 +00001#!/usr/bin/env python2.7
Craig Tiller6169d5f2016-03-31 07:46:18 -07002# Copyright 2015, 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
Masood Malekghassemi3b5b2062016-06-02 20:27:20 -070035import collections
Nicolas Nobleddef2462015-01-06 18:08:25 -080036import glob
37import 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
Masood Malekghassemi3b5b2062016-06-02 20:27:20 -070041import os.path
Craig Tiller38fb8de2016-07-13 08:23:32 -070042import pipes
David Garcia Quintas79e389f2015-06-02 17:49:42 -070043import platform
44import random
Craig Tillerfe406ec2015-02-24 13:55:12 -080045import re
Craig Tiller82875232015-09-25 13:57:34 -070046import socket
David Garcia Quintas79e389f2015-06-02 17:49:42 -070047import subprocess
Nicolas Nobleddef2462015-01-06 18:08:25 -080048import sys
Craig Tillerf0a293e2015-10-12 10:05:50 -070049import tempfile
50import traceback
ctiller3040cb72015-01-07 12:13:17 -080051import time
Craig Tillerf53d9c82015-08-04 14:19:43 -070052import urllib2
Jan Tattermusch03c01062015-12-11 14:28:56 -080053import uuid
Nicolas Nobleddef2462015-01-06 18:08:25 -080054
55import jobset
Adele Zhoua30f8292015-11-02 13:15:46 -080056import report_utils
ctiller3040cb72015-01-07 12:13:17 -080057import watch_dirs
Nicolas Nobleddef2462015-01-06 18:08:25 -080058
Craig Tillerb361b4e2016-01-06 11:44:17 -080059
Jan Tattermusch3b5121b2016-02-22 17:41:05 -080060_ROOT = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), '../..'))
61os.chdir(_ROOT)
Craig Tiller2cc2b842015-02-27 11:38:31 -080062
63
Craig Tiller06805272015-06-11 14:46:47 -070064_FORCE_ENVIRON_FOR_WRAPPERS = {}
65
66
Craig Tiller123f1372016-06-15 15:06:14 -070067_POLLING_STRATEGIES = {
Sree Kuchibhotlac3a9fae2016-06-21 16:31:08 -070068 'linux': ['epoll', 'poll', 'legacy']
Craig Tiller123f1372016-06-15 15:06:14 -070069}
70
71
Craig Tillerd50993d2015-08-05 08:04:36 -070072def platform_string():
Nicolas "Pixel" Noblef72d7b52015-12-03 03:07:43 +010073 return jobset.platform_string()
Craig Tillerd50993d2015-08-05 08:04:36 -070074
75
Craig Tiller38fb8de2016-07-13 08:23:32 -070076_DEFAULT_TIMEOUT_SECONDS = 5 * 60
77
78
Craig Tiller738c3342015-01-12 14:28:33 -080079# SimpleConfig: just compile with CONFIG=config, and run the binary to test
Craig Tillera0f85172016-01-20 15:56:06 -080080class Config(object):
Craig Tillerb50d1662015-01-15 17:28:21 -080081
Craig Tillera0f85172016-01-20 15:56:06 -080082 def __init__(self, config, environ=None, timeout_multiplier=1, tool_prefix=[]):
murgatroid99132ce6a2015-03-04 17:29:14 -080083 if environ is None:
84 environ = {}
Craig Tiller738c3342015-01-12 14:28:33 -080085 self.build_config = config
Craig Tiller547db2b2015-01-30 14:08:39 -080086 self.environ = environ
murgatroid99132ce6a2015-03-04 17:29:14 -080087 self.environ['CONFIG'] = config
Craig Tillera0f85172016-01-20 15:56:06 -080088 self.tool_prefix = tool_prefix
Masood Malekghassemi26ea9e22015-10-09 15:19:17 -070089 self.timeout_multiplier = timeout_multiplier
Craig Tiller738c3342015-01-12 14:28:33 -080090
Craig Tiller38fb8de2016-07-13 08:23:32 -070091 def job_spec(self, cmdline, timeout_seconds=_DEFAULT_TIMEOUT_SECONDS,
Craig Tillerde7edf82016-03-20 09:12:16 -070092 shortname=None, environ={}, cpu_cost=1.0, flaky=False):
Craig Tiller49f61322015-03-03 13:02:11 -080093 """Construct a jobset.JobSpec for a test under this config
94
95 Args:
96 cmdline: a list of strings specifying the command line the test
97 would like to run
Craig Tiller49f61322015-03-03 13:02:11 -080098 """
Craig Tiller4fc90032015-05-21 10:39:52 -070099 actual_environ = self.environ.copy()
100 for k, v in environ.iteritems():
101 actual_environ[k] = v
Craig Tillera0f85172016-01-20 15:56:06 -0800102 return jobset.JobSpec(cmdline=self.tool_prefix + cmdline,
Jan Tattermusch9a7d30c2015-04-23 16:12:55 -0700103 shortname=shortname,
Craig Tiller4fc90032015-05-21 10:39:52 -0700104 environ=actual_environ,
Craig Tiller56c6b6a2016-01-20 08:27:37 -0800105 cpu_cost=cpu_cost,
Craig Tiller94d04a52016-01-20 10:58:23 -0800106 timeout_seconds=(self.timeout_multiplier * timeout_seconds if timeout_seconds else None),
Craig Tillerde7edf82016-03-20 09:12:16 -0700107 flake_retries=5 if flaky or args.allow_flakes else 0,
Craig Tiller35505de2015-10-08 13:31:33 -0700108 timeout_retries=3 if args.allow_flakes else 0)
Craig Tiller738c3342015-01-12 14:28:33 -0800109
110
murgatroid99cf08daf2015-09-21 15:33:16 -0700111def get_c_tests(travis, test_lang) :
112 out = []
113 platforms_str = 'ci_platforms' if travis else 'platforms'
114 with open('tools/run_tests/tests.json') as f:
murgatroid9989899b12015-09-22 09:14:48 -0700115 js = json.load(f)
murgatroid99a3e244f2015-09-22 11:25:53 -0700116 return [tgt
117 for tgt in js
118 if tgt['language'] == test_lang and
119 platform_string() in tgt[platforms_str] and
120 not (travis and tgt['flaky'])]
murgatroid99cf08daf2015-09-21 15:33:16 -0700121
murgatroid99fafeeb32015-09-22 09:13:03 -0700122
Jan Tattermusch77db4322016-02-20 20:19:35 -0800123def _check_compiler(compiler, supported_compilers):
124 if compiler not in supported_compilers:
Jan Tattermuschb2531e22016-03-25 16:14:41 -0700125 raise Exception('Compiler %s not supported (on this platform).' % compiler)
126
127
128def _check_arch(arch, supported_archs):
129 if arch not in supported_archs:
130 raise Exception('Architecture %s not supported.' % arch)
Jan Tattermusch77db4322016-02-20 20:19:35 -0800131
132
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800133def _is_use_docker_child():
134 """Returns True if running running as a --use_docker child."""
135 return True if os.getenv('RUN_TESTS_COMMAND') else False
136
137
Craig Tillerc7449162015-01-16 14:42:10 -0800138class CLanguage(object):
139
Craig Tillere9c959d2015-01-18 10:23:26 -0800140 def __init__(self, make_target, test_lang):
Craig Tillerc7449162015-01-16 14:42:10 -0800141 self.make_target = make_target
Craig Tillerd50993d2015-08-05 08:04:36 -0700142 self.platform = platform_string()
Craig Tiller711bbe62015-08-19 12:35:16 -0700143 self.test_lang = test_lang
Craig Tillerc7449162015-01-16 14:42:10 -0800144
Jan Tattermusch77db4322016-02-20 20:19:35 -0800145 def configure(self, config, args):
146 self.config = config
147 self.args = args
148 if self.platform == 'windows':
Jan Tattermuschc96caf82016-02-22 17:31:02 -0800149 self._make_options = [_windows_toolset_option(self.args.compiler),
150 _windows_arch_option(self.args.arch)]
Jan Tattermusch77db4322016-02-20 20:19:35 -0800151 else:
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800152 self._docker_distro, self._make_options = self._compiler_options(self.args.use_docker,
153 self.args.compiler)
Jan Tattermusch77db4322016-02-20 20:19:35 -0800154
155 def test_specs(self):
Craig Tiller547db2b2015-01-30 14:08:39 -0800156 out = []
Jan Tattermusch77db4322016-02-20 20:19:35 -0800157 binaries = get_c_tests(self.args.travis, self.test_lang)
Craig Tiller946ce7a2016-04-06 10:35:58 -0700158 for target in binaries:
Craig Tiller123f1372016-06-15 15:06:14 -0700159 polling_strategies = (_POLLING_STRATEGIES.get(self.platform, ['all'])
Craig Tiller946ce7a2016-04-06 10:35:58 -0700160 if target.get('uses_polling', True)
161 else ['all'])
162 for polling_strategy in polling_strategies:
163 env={'GRPC_DEFAULT_SSL_ROOTS_FILE_PATH':
164 _ROOT + '/src/core/lib/tsi/test_creds/ca.pem',
Craig Tillered735102016-04-06 12:59:23 -0700165 'GRPC_POLL_STRATEGY': polling_strategy}
Craig Tiller38fb8de2016-07-13 08:23:32 -0700166 shortname_ext = '' if polling_strategy=='all' else ' GRPC_POLL_STRATEGY=%s' % polling_strategy
Craig Tillerb38197e2016-02-26 10:14:54 -0800167 if self.config.build_config in target['exclude_configs']:
168 continue
169 if self.platform == 'windows':
170 binary = 'vsprojects/%s%s/%s.exe' % (
171 'x64/' if self.args.arch == 'x64' else '',
172 _MSBUILD_CONFIG[self.config.build_config],
173 target['name'])
Craig Tillerca62ff02016-02-24 22:22:57 -0800174 else:
Craig Tillerb38197e2016-02-26 10:14:54 -0800175 binary = 'bins/%s/%s' % (self.config.build_config, target['name'])
176 if os.path.isfile(binary):
177 if 'gtest' in target and target['gtest']:
178 # here we parse the output of --gtest_list_tests to build up a
179 # complete list of the tests contained in a binary
180 # for each test, we then add a job to run, filtering for just that
181 # test
182 with open(os.devnull, 'w') as fnull:
183 tests = subprocess.check_output([binary, '--gtest_list_tests'],
184 stderr=fnull)
185 base = None
186 for line in tests.split('\n'):
187 i = line.find('#')
188 if i >= 0: line = line[:i]
189 if not line: continue
190 if line[0] != ' ':
191 base = line.strip()
192 else:
193 assert base is not None
194 assert line[1] == ' '
195 test = base + line.strip()
196 cmdline = [binary] + ['--gtest_filter=%s' % test]
Craig Tiller38fb8de2016-07-13 08:23:32 -0700197 out.append(self.config.job_spec(cmdline,
198 shortname='%s --gtest_filter=%s %s' % (binary, test, shortname_ext),
Craig Tillerb38197e2016-02-26 10:14:54 -0800199 cpu_cost=target['cpu_cost'],
200 environ=env))
201 else:
202 cmdline = [binary] + target['args']
Craig Tiller38fb8de2016-07-13 08:23:32 -0700203 out.append(self.config.job_spec(cmdline,
204 shortname=' '.join(
205 pipes.quote(arg)
206 for arg in cmdline) +
207 shortname_ext,
Craig Tillerb38197e2016-02-26 10:14:54 -0800208 cpu_cost=target['cpu_cost'],
Craig Tillerc2278152016-03-21 08:59:54 -0700209 flaky=target.get('flaky', False),
Craig Tiller38fb8de2016-07-13 08:23:32 -0700210 timeout_seconds=target.get('timeout_seconds', _DEFAULT_TIMEOUT_SECONDS),
Craig Tillerb38197e2016-02-26 10:14:54 -0800211 environ=env))
212 elif self.args.regex == '.*' or self.platform == 'windows':
213 print '\nWARNING: binary not found, skipping', binary
Nicolas Noblee1445362015-05-11 17:40:26 -0700214 return sorted(out)
Craig Tillerc7449162015-01-16 14:42:10 -0800215
Jan Tattermusch77db4322016-02-20 20:19:35 -0800216 def make_targets(self):
Jan Tattermusch77db4322016-02-20 20:19:35 -0800217 if self.platform == 'windows':
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700218 # don't build tools on windows just yet
219 return ['buildtests_%s' % self.make_target]
Craig Tiller7552f0f2015-06-19 17:46:20 -0700220 return ['buildtests_%s' % self.make_target, 'tools_%s' % self.make_target]
Craig Tillerc7449162015-01-16 14:42:10 -0800221
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800222 def make_options(self):
Jan Tattermuschc96caf82016-02-22 17:31:02 -0800223 return self._make_options;
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800224
murgatroid99256d3df2015-09-21 16:58:02 -0700225 def pre_build_steps(self):
Jan Tattermusch874aec02015-10-07 19:26:19 -0700226 if self.platform == 'windows':
227 return [['tools\\run_tests\\pre_build_c.bat']]
228 else:
229 return []
murgatroid99256d3df2015-09-21 16:58:02 -0700230
Craig Tillerc7449162015-01-16 14:42:10 -0800231 def build_steps(self):
232 return []
233
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200234 def post_tests_steps(self):
235 if self.platform == 'windows':
236 return []
237 else:
238 return [['tools/run_tests/post_tests_c.sh']]
239
murgatroid99a3e244f2015-09-22 11:25:53 -0700240 def makefile_name(self):
241 return 'Makefile'
242
Jan Tattermusch6d258c52016-06-10 09:36:51 -0700243 def _clang_make_options(self, version_suffix=''):
244 return ['CC=clang%s' % version_suffix,
245 'CXX=clang++%s' % version_suffix,
246 'LD=clang%s' % version_suffix,
247 'LDXX=clang++%s' % version_suffix]
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800248
Jan Tattermusch6d258c52016-06-10 09:36:51 -0700249 def _gcc_make_options(self, version_suffix):
250 return ['CC=gcc%s' % version_suffix,
251 'CXX=g++%s' % version_suffix,
252 'LD=gcc%s' % version_suffix,
253 'LDXX=g++%s' % version_suffix]
Jan Tattermusch9bb70622016-03-18 10:28:54 -0700254
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800255 def _compiler_options(self, use_docker, compiler):
256 """Returns docker distro and make options to use for given compiler."""
Jan Tattermuschfd3857b2016-06-03 12:24:03 -0700257 if not use_docker and not _is_use_docker_child():
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800258 _check_compiler(compiler, ['default'])
259
260 if compiler == 'gcc4.9' or compiler == 'default':
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800261 return ('jessie', [])
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800262 elif compiler == 'gcc4.4':
Jan Tattermusch6d258c52016-06-10 09:36:51 -0700263 return ('wheezy', self._gcc_make_options(version_suffix='-4.4'))
264 elif compiler == 'gcc4.6':
265 return ('wheezy', self._gcc_make_options(version_suffix='-4.6'))
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800266 elif compiler == 'gcc5.3':
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800267 return ('ubuntu1604', [])
268 elif compiler == 'clang3.4':
Jan Tattermusch6d258c52016-06-10 09:36:51 -0700269 # on ubuntu1404, clang-3.4 alias doesn't exist, just use 'clang'
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800270 return ('ubuntu1404', self._clang_make_options())
Jan Tattermusch6d258c52016-06-10 09:36:51 -0700271 elif compiler == 'clang3.5':
272 return ('jessie', self._clang_make_options(version_suffix='-3.5'))
Jan Tattermuschd4726c12016-02-23 16:57:36 -0800273 elif compiler == 'clang3.6':
Jan Tattermusch6d258c52016-06-10 09:36:51 -0700274 return ('ubuntu1604', self._clang_make_options(version_suffix='-3.6'))
275 elif compiler == 'clang3.7':
276 return ('ubuntu1604', self._clang_make_options(version_suffix='-3.7'))
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800277 else:
278 raise Exception('Compiler %s not supported.' % compiler)
279
Jan Tattermusch77db4322016-02-20 20:19:35 -0800280 def dockerfile_dir(self):
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800281 return 'tools/dockerfile/test/cxx_%s_%s' % (self._docker_distro,
282 _docker_arch_suffix(self.args.arch))
Jan Tattermusch788ee232016-01-26 12:19:44 -0800283
murgatroid99132ce6a2015-03-04 17:29:14 -0800284 def __str__(self):
285 return self.make_target
286
Craig Tillercc0535d2015-12-08 15:14:47 -0800287
murgatroid992c8d5162015-01-26 10:41:21 -0800288class NodeLanguage(object):
289
Jan Tattermusche477b842016-02-06 22:19:01 -0800290 def __init__(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800291 self.platform = platform_string()
Jan Tattermusche477b842016-02-06 22:19:01 -0800292
Jan Tattermusch77db4322016-02-20 20:19:35 -0800293 def configure(self, config, args):
294 self.config = config
295 self.args = args
murgatroid999fab4382016-04-29 15:05:00 -0700296 _check_compiler(self.args.compiler, ['default', 'node0.12',
297 'node4', 'node5'])
298 if self.args.compiler == 'default':
299 self.node_version = '4'
300 else:
301 # Take off the word "node"
302 self.node_version = self.args.compiler[4:]
Jan Tattermusch77db4322016-02-20 20:19:35 -0800303
304 def test_specs(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800305 if self.platform == 'windows':
Jan Tattermusch77db4322016-02-20 20:19:35 -0800306 return [self.config.job_spec(['tools\\run_tests\\run_node.bat'], None)]
Michael Lumishaaa876a2016-02-10 15:27:58 -0800307 else:
Jan Tattermusch77db4322016-02-20 20:19:35 -0800308 return [self.config.job_spec(['tools/run_tests/run_node.sh', self.node_version],
309 None,
310 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
murgatroid992c8d5162015-01-26 10:41:21 -0800311
murgatroid99256d3df2015-09-21 16:58:02 -0700312 def pre_build_steps(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800313 if self.platform == 'windows':
314 return [['tools\\run_tests\\pre_build_node.bat']]
315 else:
316 return [['tools/run_tests/pre_build_node.sh', self.node_version]]
murgatroid99256d3df2015-09-21 16:58:02 -0700317
Jan Tattermusch77db4322016-02-20 20:19:35 -0800318 def make_targets(self):
murgatroid99db5b1602015-10-01 13:20:11 -0700319 return []
murgatroid992c8d5162015-01-26 10:41:21 -0800320
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800321 def make_options(self):
322 return []
323
murgatroid992c8d5162015-01-26 10:41:21 -0800324 def build_steps(self):
Michael Lumishaaa876a2016-02-10 15:27:58 -0800325 if self.platform == 'windows':
326 return [['tools\\run_tests\\build_node.bat']]
327 else:
328 return [['tools/run_tests/build_node.sh', self.node_version]]
Craig Tillerc7449162015-01-16 14:42:10 -0800329
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200330 def post_tests_steps(self):
331 return []
332
murgatroid99a3e244f2015-09-22 11:25:53 -0700333 def makefile_name(self):
334 return 'Makefile'
335
Jan Tattermusch77db4322016-02-20 20:19:35 -0800336 def dockerfile_dir(self):
337 return 'tools/dockerfile/test/node_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800338
murgatroid99132ce6a2015-03-04 17:29:14 -0800339 def __str__(self):
340 return 'node'
341
Craig Tiller99775822015-01-30 13:07:16 -0800342
Craig Tillerc7449162015-01-16 14:42:10 -0800343class PhpLanguage(object):
344
Jan Tattermusch77db4322016-02-20 20:19:35 -0800345 def configure(self, config, args):
346 self.config = config
347 self.args = args
348 _check_compiler(self.args.compiler, ['default'])
349
350 def test_specs(self):
351 return [self.config.job_spec(['src/php/bin/run_tests.sh'], None,
352 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
Craig Tillerc7449162015-01-16 14:42:10 -0800353
murgatroid99256d3df2015-09-21 16:58:02 -0700354 def pre_build_steps(self):
355 return []
356
Jan Tattermusch77db4322016-02-20 20:19:35 -0800357 def make_targets(self):
Craig Tilleraf7cf542015-05-22 10:07:34 -0700358 return ['static_c', 'shared_c']
Craig Tillerc7449162015-01-16 14:42:10 -0800359
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800360 def make_options(self):
361 return []
362
Craig Tillerc7449162015-01-16 14:42:10 -0800363 def build_steps(self):
364 return [['tools/run_tests/build_php.sh']]
365
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200366 def post_tests_steps(self):
Stanley Cheunga6b95482016-01-13 16:10:48 -0800367 return [['tools/run_tests/post_tests_php.sh']]
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200368
murgatroid99a3e244f2015-09-22 11:25:53 -0700369 def makefile_name(self):
370 return 'Makefile'
371
Jan Tattermusch77db4322016-02-20 20:19:35 -0800372 def dockerfile_dir(self):
373 return 'tools/dockerfile/test/php_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800374
murgatroid99132ce6a2015-03-04 17:29:14 -0800375 def __str__(self):
376 return 'php'
377
Craig Tillerc7449162015-01-16 14:42:10 -0800378
Masood Malekghassemi3b5b2062016-06-02 20:27:20 -0700379class PythonConfig(collections.namedtuple('PythonConfig', [
Masood Malekghassemicab9d4f2016-06-28 09:09:31 -0700380 'name', 'build', 'run'])):
381 """Tuple of commands (named s.t. 'what it says on the tin' applies)"""
Masood Malekghassemi3b5b2062016-06-02 20:27:20 -0700382
Nathaniel Manista840615e2015-01-22 20:31:47 +0000383class PythonLanguage(object):
384
Jan Tattermusch77db4322016-02-20 20:19:35 -0800385 def configure(self, config, args):
386 self.config = config
387 self.args = args
Masood Malekghassemicab9d4f2016-06-28 09:09:31 -0700388 self.pythons = self._get_pythons(self.args)
Jan Tattermusch77db4322016-02-20 20:19:35 -0800389
390 def test_specs(self):
Jan Tattermusch072ebaa2016-03-01 18:33:12 -0800391 # load list of known test suites
Masood Malekghassemi1ff429d2016-06-02 16:39:20 -0700392 with open('src/python/grpcio_tests/tests/tests.json') as tests_json_file:
Jan Tattermusch072ebaa2016-03-01 18:33:12 -0800393 tests_json = json.load(tests_json_file)
Masood Malekghassemi2b841622015-07-28 17:39:02 -0700394 environment = dict(_FORCE_ENVIRON_FOR_WRAPPERS)
Masood Malekghassemi1c062bd2016-06-13 18:41:36 -0700395 return [self.config.job_spec(
Masood Malekghassemicab9d4f2016-06-28 09:09:31 -0700396 config.run,
Masood Malekghassemie6a23e22016-06-28 13:58:42 -0700397 timeout_seconds=5*60,
Masood Malekghassemi1c062bd2016-06-13 18:41:36 -0700398 environ=dict(environment.items() +
399 [('GRPC_PYTHON_TESTRUNNER_FILTER', suite_name)]),
Masood Malekghassemicab9d4f2016-06-28 09:09:31 -0700400 shortname='%s.test.%s' % (config.name, suite_name),)
Masood Malekghassemi1c062bd2016-06-13 18:41:36 -0700401 for suite_name in tests_json
402 for config in self.pythons]
Nathaniel Manista840615e2015-01-22 20:31:47 +0000403
murgatroid99256d3df2015-09-21 16:58:02 -0700404 def pre_build_steps(self):
405 return []
406
Jan Tattermusch77db4322016-02-20 20:19:35 -0800407 def make_targets(self):
Masood Malekghassemi3b5b2062016-06-02 20:27:20 -0700408 return []
Nathaniel Manista840615e2015-01-22 20:31:47 +0000409
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800410 def make_options(self):
411 return []
412
Nathaniel Manista840615e2015-01-22 20:31:47 +0000413 def build_steps(self):
Masood Malekghassemicab9d4f2016-06-28 09:09:31 -0700414 return [config.build for config in self.pythons]
Nathaniel Manista840615e2015-01-22 20:31:47 +0000415
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200416 def post_tests_steps(self):
417 return []
418
murgatroid99a3e244f2015-09-22 11:25:53 -0700419 def makefile_name(self):
420 return 'Makefile'
421
Jan Tattermusch77db4322016-02-20 20:19:35 -0800422 def dockerfile_dir(self):
423 return 'tools/dockerfile/test/python_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800424
Masood Malekghassemicab9d4f2016-06-28 09:09:31 -0700425 def _get_pythons(self, args):
426 if args.arch == 'x86':
427 bits = '32'
Masood Malekghassemi3b5b2062016-06-02 20:27:20 -0700428 else:
Masood Malekghassemicab9d4f2016-06-28 09:09:31 -0700429 bits = '64'
430 if os.name == 'nt':
431 shell = ['bash']
432 builder = [os.path.abspath('tools/run_tests/build_python_msys2.sh')]
433 builder_prefix_arguments = ['MINGW{}'.format(bits)]
434 venv_relative_python = ['Scripts/python.exe']
435 toolchain = ['mingw32']
436 python_pattern_function = lambda major, minor, bits: (
437 '/c/Python{major}{minor}/python.exe'.format(major=major, minor=minor, bits=bits)
438 if bits == '64' else
439 '/c/Python{major}{minor}_{bits}bits/python.exe'.format(
440 major=major, minor=minor, bits=bits))
441 else:
442 shell = []
443 builder = [os.path.abspath('tools/run_tests/build_python.sh')]
444 builder_prefix_arguments = []
445 venv_relative_python = ['bin/python']
446 toolchain = ['unix']
447 # Bit-ness is handled by the test machine's environment
448 python_pattern_function = lambda major, minor, bits: 'python{major}.{minor}'.format(major=major, minor=minor)
449 runner = [os.path.abspath('tools/run_tests/run_python.sh')]
450 python_config_generator = lambda name, major, minor, bits: PythonConfig(
451 name,
452 shell + builder + builder_prefix_arguments
453 + [python_pattern_function(major=major, minor=minor, bits=bits)]
454 + [name] + venv_relative_python + toolchain,
455 shell + runner + [os.path.join(name, venv_relative_python[0])])
456 python27_config = python_config_generator(name='py27', major='2', minor='7', bits=bits)
457 python34_config = python_config_generator(name='py34', major='3', minor='4', bits=bits)
458 if args.compiler == 'default':
459 if os.name == 'nt':
460 return (python27_config,)
461 else:
462 return (python27_config, python34_config,)
463 elif args.compiler == 'python2.7':
Masood Malekghassemi3b5b2062016-06-02 20:27:20 -0700464 return (python27_config,)
Masood Malekghassemicab9d4f2016-06-28 09:09:31 -0700465 elif args.compiler == 'python3.4':
Masood Malekghassemi3b5b2062016-06-02 20:27:20 -0700466 return (python34_config,)
Jan Tattermusch825471c2016-04-25 16:52:25 -0700467 else:
Masood Malekghassemicab9d4f2016-06-28 09:09:31 -0700468 raise Exception('Compiler %s not supported.' % args.compiler)
Jan Tattermusch825471c2016-04-25 16:52:25 -0700469
murgatroid99132ce6a2015-03-04 17:29:14 -0800470 def __str__(self):
471 return 'python'
472
Craig Tillerd625d812015-04-08 15:52:35 -0700473
murgatroid996a4c4fa2015-02-27 12:08:57 -0800474class RubyLanguage(object):
475
Jan Tattermusch77db4322016-02-20 20:19:35 -0800476 def configure(self, config, args):
477 self.config = config
478 self.args = args
479 _check_compiler(self.args.compiler, ['default'])
480
481 def test_specs(self):
Craig Tillereb5e4372016-06-23 16:16:10 -0700482 return [self.config.job_spec(['tools/run_tests/run_ruby.sh'],
Jan Tattermusch77db4322016-02-20 20:19:35 -0800483 timeout_seconds=10*60,
484 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
murgatroid996a4c4fa2015-02-27 12:08:57 -0800485
murgatroid99256d3df2015-09-21 16:58:02 -0700486 def pre_build_steps(self):
Nicolas "Pixel" Noblebcf988f2015-10-08 03:00:42 +0200487 return [['tools/run_tests/pre_build_ruby.sh']]
murgatroid99256d3df2015-09-21 16:58:02 -0700488
Jan Tattermusch4651bef2016-02-23 08:31:25 -0800489 def make_targets(self):
murgatroid997d243df2016-02-18 09:58:05 -0800490 return []
murgatroid996a4c4fa2015-02-27 12:08:57 -0800491
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800492 def make_options(self):
493 return []
494
murgatroid996a4c4fa2015-02-27 12:08:57 -0800495 def build_steps(self):
496 return [['tools/run_tests/build_ruby.sh']]
497
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200498 def post_tests_steps(self):
Nicolas "Pixel" Noble7ef1e532015-12-02 00:55:33 +0100499 return [['tools/run_tests/post_tests_ruby.sh']]
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200500
murgatroid99a3e244f2015-09-22 11:25:53 -0700501 def makefile_name(self):
502 return 'Makefile'
503
Jan Tattermusch77db4322016-02-20 20:19:35 -0800504 def dockerfile_dir(self):
505 return 'tools/dockerfile/test/ruby_jessie_%s' % _docker_arch_suffix(self.args.arch)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800506
murgatroid99132ce6a2015-03-04 17:29:14 -0800507 def __str__(self):
508 return 'ruby'
509
Craig Tillerd625d812015-04-08 15:52:35 -0700510
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800511class CSharpLanguage(object):
Jan Tattermusch77db4322016-02-20 20:19:35 -0800512
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700513 def __init__(self):
Craig Tillerd50993d2015-08-05 08:04:36 -0700514 self.platform = platform_string()
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700515
Jan Tattermusch77db4322016-02-20 20:19:35 -0800516 def configure(self, config, args):
517 self.config = config
518 self.args = args
Jan Tattermusch6d28d352016-03-25 15:07:22 -0700519 if self.platform == 'windows':
Jan Tattermuschb2531e22016-03-25 16:14:41 -0700520 # Explicitly choosing between x86 and x64 arch doesn't work yet
521 _check_arch(self.args.arch, ['default'])
Jan Tattermusch6e2f88c2016-06-21 10:52:40 -0700522 # CoreCLR use 64bit runtime by default.
523 arch_option = 'x64' if self.args.compiler == 'coreclr' else self.args.arch
Jan Tattermusch6d28d352016-03-25 15:07:22 -0700524 self._make_options = [_windows_toolset_option(self.args.compiler),
Jan Tattermusch6e2f88c2016-06-21 10:52:40 -0700525 _windows_arch_option(arch_option)]
Jan Tattermusch6d28d352016-03-25 15:07:22 -0700526 else:
Jan Tattermuschbc98af12016-06-17 18:38:27 -0700527 _check_compiler(self.args.compiler, ['default', 'coreclr'])
528 if self.platform == 'linux' and self.args.compiler == 'coreclr':
529 self._docker_distro = 'coreclr'
Jan Tattermusch743decd2016-06-21 11:40:47 -0700530 else:
531 self._docker_distro = 'jessie'
Jan Tattermusch76511a52016-06-17 14:00:57 -0700532
Jan Tattermusch6d28d352016-03-25 15:07:22 -0700533 if self.platform == 'mac':
Jan Tattermusch2a322c22016-03-30 13:55:07 -0700534 # TODO(jtattermusch): EMBED_ZLIB=true currently breaks the mac build
Jan Tattermusch6d082202016-06-21 10:03:38 -0700535 self._make_options = ['EMBED_OPENSSL=true']
536 if self.args.compiler != 'coreclr':
537 # On Mac, official distribution of mono is 32bit.
538 self._make_options += ['CFLAGS=-m32', 'LDFLAGS=-m32']
Jan Tattermusch6d28d352016-03-25 15:07:22 -0700539 else:
540 self._make_options = ['EMBED_OPENSSL=true', 'EMBED_ZLIB=true']
Jan Tattermusch77db4322016-02-20 20:19:35 -0800541
542 def test_specs(self):
Jan Tattermusch03c01062015-12-11 14:28:56 -0800543 with open('src/csharp/tests.json') as f:
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700544 tests_by_assembly = json.load(f)
Jan Tattermusch03c01062015-12-11 14:28:56 -0800545
Jan Tattermuscha2d964c2016-02-22 17:33:09 -0800546 msbuild_config = _MSBUILD_CONFIG[self.config.build_config]
Jan Tattermuschbc98af12016-06-17 18:38:27 -0700547 nunit_args = ['--labels=All']
Jan Tattermusch76511a52016-06-17 14:00:57 -0700548 assembly_subdir = 'bin/%s' % msbuild_config
549 assembly_extension = '.exe'
550
551 if self.args.compiler == 'coreclr':
Jan Tattermusch64c137c2016-06-20 17:54:19 -0700552 if self.platform == 'linux':
553 assembly_subdir += '/netstandard1.5/debian.8-x64'
554 assembly_extension = ''
Jan Tattermusch14a301d2016-06-27 17:45:29 -0700555 elif self.platform == 'mac':
Jan Tattermusch6d082202016-06-21 10:03:38 -0700556 assembly_subdir += '/netstandard1.5/osx.10.11-x64'
557 assembly_extension = ''
Jan Tattermusch64c137c2016-06-20 17:54:19 -0700558 else:
559 assembly_subdir += '/netstandard1.5/win7-x64'
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700560 runtime_cmd = []
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700561 else:
Jan Tattermuschbc98af12016-06-17 18:38:27 -0700562 nunit_args += ['--noresult', '--workers=1']
563 if self.platform == 'windows':
564 runtime_cmd = []
565 else:
566 runtime_cmd = ['mono']
Jan Tattermuschbf3b1532015-10-26 10:24:42 -0700567
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700568 specs = []
569 for assembly in tests_by_assembly.iterkeys():
Jan Tattermusch76511a52016-06-17 14:00:57 -0700570 assembly_file = 'src/csharp/%s/%s/%s%s' % (assembly,
571 assembly_subdir,
572 assembly,
573 assembly_extension)
Jan Tattermuscha5f1f122016-04-11 15:49:56 -0700574 if self.config.build_config != 'gcov' or self.platform != 'windows':
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700575 # normally, run each test as a separate process
576 for test in tests_by_assembly[assembly]:
577 cmdline = runtime_cmd + [assembly_file, '--test=%s' % test] + nunit_args
578 specs.append(self.config.job_spec(cmdline,
579 None,
580 shortname='csharp.%s' % test,
581 environ=_FORCE_ENVIRON_FOR_WRAPPERS))
582 else:
Jan Tattermuscha5f1f122016-04-11 15:49:56 -0700583 # For C# test coverage, run all tests from the same assembly at once
584 # using OpenCover.Console (only works on Windows).
585 cmdline = ['src\\csharp\\packages\\OpenCover.4.6.519\\tools\\OpenCover.Console.exe',
586 '-target:%s' % assembly_file,
587 '-targetdir:src\\csharp',
588 '-targetargs:%s' % ' '.join(nunit_args),
589 '-filter:+[Grpc.Core]*',
590 '-register:user',
591 '-output:src\\csharp\\coverage_csharp_%s.xml' % assembly]
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700592
Jan Tattermuscha5f1f122016-04-11 15:49:56 -0700593 # set really high cpu_cost to make sure instances of OpenCover.Console run exclusively
594 # to prevent problems with registering the profiler.
595 run_exclusive = 1000000
Jan Tattermusch35e608f2016-04-09 16:35:06 -0700596 specs.append(self.config.job_spec(cmdline,
597 None,
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700598 shortname='csharp.coverage.%s' % assembly,
Jan Tattermuscha5f1f122016-04-11 15:49:56 -0700599 cpu_cost=run_exclusive,
Jan Tattermusch77db4322016-02-20 20:19:35 -0800600 environ=_FORCE_ENVIRON_FOR_WRAPPERS))
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700601 return specs
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800602
murgatroid99256d3df2015-09-21 16:58:02 -0700603 def pre_build_steps(self):
Jan Tattermusch48423fc2015-10-07 18:59:16 -0700604 if self.platform == 'windows':
Jan Tattermusch874aec02015-10-07 19:26:19 -0700605 return [['tools\\run_tests\\pre_build_csharp.bat']]
Jan Tattermusch48423fc2015-10-07 18:59:16 -0700606 else:
607 return [['tools/run_tests/pre_build_csharp.sh']]
murgatroid99256d3df2015-09-21 16:58:02 -0700608
Jan Tattermusch77db4322016-02-20 20:19:35 -0800609 def make_targets(self):
Jan Tattermusch6d28d352016-03-25 15:07:22 -0700610 return ['grpc_csharp_ext']
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800611
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800612 def make_options(self):
Jan Tattermusch6d28d352016-03-25 15:07:22 -0700613 return self._make_options;
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800614
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800615 def build_steps(self):
Jan Tattermusch76511a52016-06-17 14:00:57 -0700616 if self.args.compiler == 'coreclr':
Jan Tattermuschbc98af12016-06-17 18:38:27 -0700617 if self.platform == 'windows':
618 return [['tools\\run_tests\\build_csharp_coreclr.bat']]
619 else:
620 return [['tools/run_tests/build_csharp_coreclr.sh']]
Jan Tattermuschb00aa672015-06-01 15:48:03 -0700621 else:
Jan Tattermusch76511a52016-06-17 14:00:57 -0700622 if self.platform == 'windows':
623 return [[_windows_build_bat(self.args.compiler),
624 'src/csharp/Grpc.sln',
625 '/p:Configuration=%s' % _MSBUILD_CONFIG[self.config.build_config]]]
626 else:
627 return [['tools/run_tests/build_csharp.sh']]
Nathaniel Manista840615e2015-01-22 20:31:47 +0000628
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200629 def post_tests_steps(self):
Jan Tattermusch38ed2cf2016-04-09 16:24:16 -0700630 if self.platform == 'windows':
631 return [['tools\\run_tests\\post_tests_csharp.bat']]
632 else:
633 return [['tools/run_tests/post_tests_csharp.sh']]
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200634
murgatroid99a3e244f2015-09-22 11:25:53 -0700635 def makefile_name(self):
636 return 'Makefile'
637
Jan Tattermusch77db4322016-02-20 20:19:35 -0800638 def dockerfile_dir(self):
Jan Tattermusch76511a52016-06-17 14:00:57 -0700639 return 'tools/dockerfile/test/csharp_%s_%s' % (self._docker_distro,
640 _docker_arch_suffix(self.args.arch))
Jan Tattermusch788ee232016-01-26 12:19:44 -0800641
murgatroid99132ce6a2015-03-04 17:29:14 -0800642 def __str__(self):
643 return 'csharp'
644
Craig Tillerd625d812015-04-08 15:52:35 -0700645
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700646class ObjCLanguage(object):
647
Jan Tattermusch77db4322016-02-20 20:19:35 -0800648 def configure(self, config, args):
649 self.config = config
650 self.args = args
651 _check_compiler(self.args.compiler, ['default'])
652
653 def test_specs(self):
Jorge Canizales6ec3b532016-07-01 11:34:32 -0700654 return [self.config.job_spec(['src/objective-c/tests/run_tests.sh'],
655 timeout_seconds=None,
656 shortname='objc-tests',
657 environ=_FORCE_ENVIRON_FOR_WRAPPERS),
Yuchen Zengf95a4892016-06-21 23:27:46 -0700658 self.config.job_spec(['src/objective-c/tests/build_example_test.sh'],
Jorge Canizales6ec3b532016-07-01 11:34:32 -0700659 timeout_seconds=15*60,
660 shortname='objc-examples-build',
Yuchen Zengc0668c82016-06-22 01:30:47 -0700661 environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700662
murgatroid99256d3df2015-09-21 16:58:02 -0700663 def pre_build_steps(self):
664 return []
665
Jan Tattermusch77db4322016-02-20 20:19:35 -0800666 def make_targets(self):
Jorge Canizalesd0b32e92015-07-30 23:08:43 -0700667 return ['grpc_objective_c_plugin', 'interop_server']
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700668
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800669 def make_options(self):
670 return []
671
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700672 def build_steps(self):
Jorge Canizalesd0b32e92015-07-30 23:08:43 -0700673 return [['src/objective-c/tests/build_tests.sh']]
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700674
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +0200675 def post_tests_steps(self):
676 return []
677
murgatroid99a3e244f2015-09-22 11:25:53 -0700678 def makefile_name(self):
679 return 'Makefile'
680
Jan Tattermusch77db4322016-02-20 20:19:35 -0800681 def dockerfile_dir(self):
Jan Tattermusch788ee232016-01-26 12:19:44 -0800682 return None
683
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700684 def __str__(self):
685 return 'objc'
686
687
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100688class Sanity(object):
689
Jan Tattermusch77db4322016-02-20 20:19:35 -0800690 def configure(self, config, args):
691 self.config = config
692 self.args = args
693 _check_compiler(self.args.compiler, ['default'])
694
695 def test_specs(self):
Craig Tiller94d04a52016-01-20 10:58:23 -0800696 import yaml
Jan Tattermusch788ee232016-01-26 12:19:44 -0800697 with open('tools/run_tests/sanity/sanity_tests.yaml', 'r') as f:
Craig Tiller34226af2016-06-24 16:46:25 -0700698 return [self.config.job_spec(cmd['script'].split(),
Jan Tattermusch77db4322016-02-20 20:19:35 -0800699 timeout_seconds=None, environ={'TEST': 'true'},
700 cpu_cost=cmd.get('cpu_cost', 1))
Craig Tiller94d04a52016-01-20 10:58:23 -0800701 for cmd in yaml.load(f)]
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100702
murgatroid99256d3df2015-09-21 16:58:02 -0700703 def pre_build_steps(self):
704 return []
705
Jan Tattermusch77db4322016-02-20 20:19:35 -0800706 def make_targets(self):
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100707 return ['run_dep_checks']
708
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800709 def make_options(self):
710 return []
711
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100712 def build_steps(self):
713 return []
714
Nicolas "Pixel" Noble87879b32015-10-12 23:28:53 +0200715 def post_tests_steps(self):
716 return []
717
murgatroid99a3e244f2015-09-22 11:25:53 -0700718 def makefile_name(self):
719 return 'Makefile'
720
Jan Tattermusch77db4322016-02-20 20:19:35 -0800721 def dockerfile_dir(self):
Jan Tattermusche70b3c52016-02-07 20:21:02 -0800722 return 'tools/dockerfile/test/sanity'
Jan Tattermusch788ee232016-01-26 12:19:44 -0800723
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100724 def __str__(self):
725 return 'sanity'
726
Nicolas "Pixel" Noblee55cd7f2015-04-14 17:59:13 +0200727
Craig Tiller738c3342015-01-12 14:28:33 -0800728# different configurations we can run under
Craig Tillera0f85172016-01-20 15:56:06 -0800729with open('tools/run_tests/configs.json') as f:
Craig Tiller1dce9062016-01-20 17:01:56 -0800730 _CONFIGS = dict((cfg['config'], Config(**cfg)) for cfg in ast.literal_eval(f.read()))
Craig Tiller738c3342015-01-12 14:28:33 -0800731
732
Craig Tillerc7449162015-01-16 14:42:10 -0800733_LANGUAGES = {
Craig Tillere9c959d2015-01-18 10:23:26 -0800734 'c++': CLanguage('cxx', 'c++'),
735 'c': CLanguage('c', 'c'),
murgatroid992c8d5162015-01-26 10:41:21 -0800736 'node': NodeLanguage(),
Nathaniel Manista840615e2015-01-22 20:31:47 +0000737 'php': PhpLanguage(),
738 'python': PythonLanguage(),
Jan Tattermusch1970a5b2015-03-03 15:17:25 -0800739 'ruby': RubyLanguage(),
Nicolas "Pixel" Noble9f728642015-03-24 18:50:30 +0100740 'csharp': CSharpLanguage(),
Jorge Canizalesa0b3bfa2015-07-30 19:25:52 -0700741 'objc' : ObjCLanguage(),
Jan Tattermusch70a57e42016-02-20 18:50:27 -0800742 'sanity': Sanity()
Craig Tillereb272bc2015-01-30 13:13:14 -0800743 }
Nicolas Nobleddef2462015-01-06 18:08:25 -0800744
Jan Tattermusch77db4322016-02-20 20:19:35 -0800745
Jan Tattermuscha2d964c2016-02-22 17:33:09 -0800746_MSBUILD_CONFIG = {
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700747 'dbg': 'Debug',
748 'opt': 'Release',
Jan Tattermusche4a69182015-12-15 09:53:01 -0800749 'gcov': 'Debug',
Craig Tiller7bb3efd2015-09-01 08:04:03 -0700750 }
751
David Garcia Quintase90cd372015-05-31 18:15:26 -0700752
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800753def _windows_arch_option(arch):
754 """Returns msbuild cmdline option for selected architecture."""
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800755 if arch == 'default' or arch == 'x86':
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800756 return '/p:Platform=Win32'
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800757 elif arch == 'x64':
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800758 return '/p:Platform=x64'
759 else:
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800760 print 'Architecture %s not supported.' % arch
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800761 sys.exit(1)
Jan Tattermusch788ee232016-01-26 12:19:44 -0800762
Jan Tattermuschf08018a2016-01-26 08:22:09 -0800763
764def _check_arch_option(arch):
765 """Checks that architecture option is valid."""
766 if platform_string() == 'windows':
767 _windows_arch_option(arch)
768 elif platform_string() == 'linux':
769 # On linux, we need to be running under docker with the right architecture.
Jan Tattermusch07fb0422016-01-26 10:46:56 -0800770 runtime_arch = platform.architecture()[0]
Jan Tattermuschf08018a2016-01-26 08:22:09 -0800771 if arch == 'default':
772 return
773 elif runtime_arch == '64bit' and arch == 'x64':
774 return
775 elif runtime_arch == '32bit' and arch == 'x86':
776 return
777 else:
778 print 'Architecture %s does not match current runtime architecture.' % arch
779 sys.exit(1)
780 else:
781 if args.arch != 'default':
782 print 'Architecture %s not supported on current platform.' % args.arch
783 sys.exit(1)
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800784
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800785
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800786def _windows_build_bat(compiler):
787 """Returns name of build.bat for selected compiler."""
Jan Tattermuschbc98af12016-06-17 18:38:27 -0700788 # For CoreCLR, fall back to the default compiler for C core
789 if compiler == 'default' or compiler == 'vs2013' or compiler == 'coreclr':
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800790 return 'vsprojects\\build_vs2013.bat'
791 elif compiler == 'vs2015':
792 return 'vsprojects\\build_vs2015.bat'
793 elif compiler == 'vs2010':
794 return 'vsprojects\\build_vs2010.bat'
795 else:
796 print 'Compiler %s not supported.' % compiler
797 sys.exit(1)
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800798
799
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800800def _windows_toolset_option(compiler):
801 """Returns msbuild PlatformToolset for selected compiler."""
Jan Tattermuschbc98af12016-06-17 18:38:27 -0700802 # For CoreCLR, fall back to the default compiler for C core
803 if compiler == 'default' or compiler == 'vs2013' or compiler == 'coreclr':
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800804 return '/p:PlatformToolset=v120'
805 elif compiler == 'vs2015':
806 return '/p:PlatformToolset=v140'
807 elif compiler == 'vs2010':
808 return '/p:PlatformToolset=v100'
809 else:
810 print 'Compiler %s not supported.' % compiler
811 sys.exit(1)
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800812
813
Jan Tattermusche70b3c52016-02-07 20:21:02 -0800814def _docker_arch_suffix(arch):
815 """Returns suffix to dockerfile dir to use."""
816 if arch == 'default' or arch == 'x64':
817 return 'x64'
818 elif arch == 'x86':
819 return 'x86'
820 else:
821 print 'Architecture %s not supported with current settings.' % arch
822 sys.exit(1)
823
824
David Garcia Quintase90cd372015-05-31 18:15:26 -0700825def runs_per_test_type(arg_str):
826 """Auxilary function to parse the "runs_per_test" flag.
827
828 Returns:
829 A positive integer or 0, the latter indicating an infinite number of
830 runs.
831
832 Raises:
833 argparse.ArgumentTypeError: Upon invalid input.
834 """
835 if arg_str == 'inf':
836 return 0
837 try:
838 n = int(arg_str)
839 if n <= 0: raise ValueError
Craig Tiller50e53e22015-06-01 20:18:21 -0700840 return n
David Garcia Quintase90cd372015-05-31 18:15:26 -0700841 except:
Adele Zhoue4c35612015-10-16 15:34:23 -0700842 msg = '\'{}\' is not a positive integer or \'inf\''.format(arg_str)
David Garcia Quintase90cd372015-05-31 18:15:26 -0700843 raise argparse.ArgumentTypeError(msg)
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700844
845# parse command line
846argp = argparse.ArgumentParser(description='Run grpc tests.')
847argp.add_argument('-c', '--config',
Jan Tattermusch77db4322016-02-20 20:19:35 -0800848 choices=sorted(_CONFIGS.keys()),
849 default='opt')
David Garcia Quintase90cd372015-05-31 18:15:26 -0700850argp.add_argument('-n', '--runs_per_test', default=1, type=runs_per_test_type,
851 help='A positive integer or "inf". If "inf", all tests will run in an '
852 'infinite loop. Especially useful in combination with "-f"')
Craig Tillerfe406ec2015-02-24 13:55:12 -0800853argp.add_argument('-r', '--regex', default='.*', type=str)
Vijay Pai488fd0e2016-06-13 12:37:12 -0700854argp.add_argument('--regex_exclude', default='', type=str)
Craig Tiller5f735a62016-01-20 09:31:15 -0800855argp.add_argument('-j', '--jobs', default=multiprocessing.cpu_count(), type=int)
Craig Tiller8451e872015-02-27 09:25:51 -0800856argp.add_argument('-s', '--slowdown', default=1.0, type=float)
ctiller3040cb72015-01-07 12:13:17 -0800857argp.add_argument('-f', '--forever',
858 default=False,
859 action='store_const',
860 const=True)
Nicolas "Pixel" Noblea7df3f92015-02-26 22:07:04 +0100861argp.add_argument('-t', '--travis',
862 default=False,
863 action='store_const',
864 const=True)
Nicolas Noble044db742015-01-14 16:57:24 -0800865argp.add_argument('--newline_on_success',
866 default=False,
867 action='store_const',
868 const=True)
Craig Tiller686fb262015-01-15 07:39:09 -0800869argp.add_argument('-l', '--language',
Craig Tiller60f15e62015-05-13 09:05:17 -0700870 choices=['all'] + sorted(_LANGUAGES.keys()),
Craig Tiller686fb262015-01-15 07:39:09 -0800871 nargs='+',
Craig Tiller60f15e62015-05-13 09:05:17 -0700872 default=['all'])
Craig Tillercd43da82015-05-29 08:41:29 -0700873argp.add_argument('-S', '--stop_on_failure',
874 default=False,
875 action='store_const',
876 const=True)
Jan Tattermuschc95eead2015-09-18 13:03:50 -0700877argp.add_argument('--use_docker',
878 default=False,
879 action='store_const',
880 const=True,
Adele Zhoue4c35612015-10-16 15:34:23 -0700881 help='Run all the tests under docker. That provides ' +
882 'additional isolation and prevents the need to install ' +
883 'language specific prerequisites. Only available on Linux.')
Craig Tillerd4509a12015-09-28 09:18:40 -0700884argp.add_argument('--allow_flakes',
885 default=False,
886 action='store_const',
887 const=True,
Adele Zhoue4c35612015-10-16 15:34:23 -0700888 help='Allow flaky tests to show as passing (re-runs failed tests up to five times)')
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800889argp.add_argument('--arch',
Jan Tattermusch9be594f2016-01-25 18:08:47 -0800890 choices=['default', 'x86', 'x64'],
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800891 default='default',
892 help='Selects architecture to target. For some platforms "default" is the only supported choice.')
893argp.add_argument('--compiler',
Jan Tattermuschc4cbe392016-02-22 19:29:38 -0800894 choices=['default',
Jan Tattermusch6d258c52016-06-10 09:36:51 -0700895 'gcc4.4', 'gcc4.6', 'gcc4.9', 'gcc5.3',
896 'clang3.4', 'clang3.5', 'clang3.6', 'clang3.7',
Jan Tattermusch825471c2016-04-25 16:52:25 -0700897 'vs2010', 'vs2013', 'vs2015',
murgatroid999fab4382016-04-29 15:05:00 -0700898 'python2.7', 'python3.4',
Jan Tattermusch76511a52016-06-17 14:00:57 -0700899 'node0.12', 'node4', 'node5',
900 'coreclr'],
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800901 default='default',
Jan Tattermusch77db4322016-02-20 20:19:35 -0800902 help='Selects compiler to use. Allowed values depend on the platform and language.')
Jan Tattermusch2dd156e2015-12-04 18:26:17 -0800903argp.add_argument('--build_only',
904 default=False,
905 action='store_const',
906 const=True,
907 help='Perform all the build steps but dont run any tests.')
Craig Tiller5f735a62016-01-20 09:31:15 -0800908argp.add_argument('--measure_cpu_costs', default=False, action='store_const', const=True,
909 help='Measure the cpu costs of tests')
Craig Tiller1676f912016-01-05 10:49:44 -0800910argp.add_argument('--update_submodules', default=[], nargs='*',
911 help='Update some submodules before building. If any are updated, also run generate_projects. ' +
912 'Submodules are specified as SUBMODULE_NAME:BRANCH; if BRANCH is omitted, master is assumed.')
Craig Tiller234b6e72015-05-23 10:12:40 -0700913argp.add_argument('-a', '--antagonists', default=0, type=int)
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +0200914argp.add_argument('-x', '--xml_report', default=None, type=str,
915 help='Generates a JUnit-compatible XML report')
Craig Tiller123f1372016-06-15 15:06:14 -0700916argp.add_argument('--force_default_poller', default=False, action='store_const', const=True,
917 help='Dont try to iterate over many polling strategies when they exist')
Nicolas Nobleddef2462015-01-06 18:08:25 -0800918args = argp.parse_args()
919
Craig Tiller123f1372016-06-15 15:06:14 -0700920if args.force_default_poller:
921 _POLLING_STRATEGIES = {}
922
Craig Tiller5f735a62016-01-20 09:31:15 -0800923jobset.measure_cpu_costs = args.measure_cpu_costs
924
Craig Tiller1676f912016-01-05 10:49:44 -0800925# update submodules if necessary
Craig Tillerb361b4e2016-01-06 11:44:17 -0800926need_to_regenerate_projects = False
927for spec in args.update_submodules:
928 spec = spec.split(':', 1)
929 if len(spec) == 1:
930 submodule = spec[0]
931 branch = 'master'
932 elif len(spec) == 2:
933 submodule = spec[0]
934 branch = spec[1]
935 cwd = 'third_party/%s' % submodule
936 def git(cmd, cwd=cwd):
937 print 'in %s: git %s' % (cwd, cmd)
938 subprocess.check_call('git %s' % cmd, cwd=cwd, shell=True)
939 git('fetch')
940 git('checkout %s' % branch)
941 git('pull origin %s' % branch)
942 if os.path.exists('src/%s/gen_build_yaml.py' % submodule):
943 need_to_regenerate_projects = True
944if need_to_regenerate_projects:
945 if jobset.platform_string() == 'linux':
946 subprocess.check_call('tools/buildgen/generate_projects.sh', shell=True)
947 else:
948 print 'WARNING: may need to regenerate projects, but since we are not on'
949 print ' Linux this step is being skipped. Compilation MAY fail.'
Craig Tiller1676f912016-01-05 10:49:44 -0800950
951
Nicolas Nobleddef2462015-01-06 18:08:25 -0800952# grab config
Jan Tattermusch77db4322016-02-20 20:19:35 -0800953run_config = _CONFIGS[args.config]
954build_config = run_config.build_config
Craig Tillerf1973b02015-01-16 12:32:13 -0800955
Craig Tiller06805272015-06-11 14:46:47 -0700956if args.travis:
murgatroid99d3b5b7f2015-10-06 17:02:03 -0700957 _FORCE_ENVIRON_FOR_WRAPPERS = {'GRPC_TRACE': 'api'}
Craig Tiller06805272015-06-11 14:46:47 -0700958
Adele Zhou6b9527c2015-11-20 15:56:35 -0800959if 'all' in args.language:
Craig Tiller1676f912016-01-05 10:49:44 -0800960 lang_list = _LANGUAGES.keys()
Adele Zhou6b9527c2015-11-20 15:56:35 -0800961else:
962 lang_list = args.language
Craig Tiller16900662016-01-07 19:30:54 -0800963# We don't support code coverage on some languages
964if 'gcov' in args.config:
Jan Tattermusch3b5121b2016-02-22 17:41:05 -0800965 for bad in ['objc', 'sanity']:
Craig Tiller16900662016-01-07 19:30:54 -0800966 if bad in lang_list:
967 lang_list.remove(bad)
Adele Zhou6b9527c2015-11-20 15:56:35 -0800968
969languages = set(_LANGUAGES[l] for l in lang_list)
Jan Tattermusch77db4322016-02-20 20:19:35 -0800970for l in languages:
971 l.configure(run_config, args)
murgatroid99132ce6a2015-03-04 17:29:14 -0800972
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800973language_make_options=[]
974if any(language.make_options() for language in languages):
Adele Zhou3b6ab812016-05-18 17:04:20 -0700975 if not 'gcov' in args.config and len(languages) != 1:
Jan Tattermuschc895fe02016-01-20 09:13:09 -0800976 print 'languages with custom make options cannot be built simultaneously with other languages'
977 sys.exit(1)
978 else:
979 language_make_options = next(iter(languages)).make_options()
980
Jan Tattermusch4dc9e722016-01-25 17:00:54 -0800981if args.use_docker:
982 if not args.travis:
983 print 'Seen --use_docker flag, will run tests under docker.'
984 print
985 print 'IMPORTANT: The changes you are testing need to be locally committed'
986 print 'because only the committed changes in the current branch will be'
987 print 'copied to the docker environment.'
988 time.sleep(5)
989
Jan Tattermusch3b5121b2016-02-22 17:41:05 -0800990 dockerfile_dirs = set([l.dockerfile_dir() for l in languages])
991 if len(dockerfile_dirs) > 1:
Adele Zhou9506ef22016-03-02 13:53:34 -0800992 if 'gcov' in args.config:
993 dockerfile_dir = 'tools/dockerfile/test/multilang_jessie_x64'
994 print ('Using multilang_jessie_x64 docker image for code coverage for '
995 'all languages.')
996 else:
997 print ('Languages to be tested require running under different docker '
998 'images.')
999 sys.exit(1)
1000 else:
1001 dockerfile_dir = next(iter(dockerfile_dirs))
Craig Tillerde7edf82016-03-20 09:12:16 -07001002
Jan Tattermusch4dc9e722016-01-25 17:00:54 -08001003 child_argv = [ arg for arg in sys.argv if not arg == '--use_docker' ]
Jan Tattermusched342b12016-01-26 14:40:31 -08001004 run_tests_cmd = 'python tools/run_tests/run_tests.py %s' % ' '.join(child_argv[1:])
Jan Tattermusch4dc9e722016-01-25 17:00:54 -08001005
Jan Tattermusch4dc9e722016-01-25 17:00:54 -08001006 env = os.environ.copy()
1007 env['RUN_TESTS_COMMAND'] = run_tests_cmd
Jan Tattermusch3b5121b2016-02-22 17:41:05 -08001008 env['DOCKERFILE_DIR'] = dockerfile_dir
Jan Tattermusch9835d4b2016-04-29 15:05:05 -07001009 env['DOCKER_RUN_SCRIPT'] = 'tools/run_tests/dockerize/docker_run_tests.sh'
Jan Tattermusch4dc9e722016-01-25 17:00:54 -08001010 if args.xml_report:
1011 env['XML_REPORT'] = args.xml_report
1012 if not args.travis:
1013 env['TTY_FLAG'] = '-t' # enables Ctrl-C when not on Jenkins.
1014
Jan Tattermusch9835d4b2016-04-29 15:05:05 -07001015 subprocess.check_call(['tools/run_tests/dockerize/build_docker_and_run_tests.sh'],
Jan Tattermusch4dc9e722016-01-25 17:00:54 -08001016 shell=True,
1017 env=env)
1018 sys.exit(0)
Jan Tattermusch788ee232016-01-26 12:19:44 -08001019
Jan Tattermuschf08018a2016-01-26 08:22:09 -08001020_check_arch_option(args.arch)
Jan Tattermusch4dc9e722016-01-25 17:00:54 -08001021
Jan Tattermuschfba65302016-01-25 18:21:14 -08001022def make_jobspec(cfg, targets, makefile='Makefile'):
1023 if platform_string() == 'windows':
Craig Tillerfc3c0c42015-09-01 16:47:54 -07001024 extra_args = []
Craig Tillerb5391e12015-09-03 14:35:18 -07001025 # better do parallel compilation
Jan Tattermusch47eeb2b2015-10-07 14:09:18 -07001026 # empirically /m:2 gives the best performance/price and should prevent
1027 # overloading the windows workers.
Adele Zhoue4c35612015-10-16 15:34:23 -07001028 extra_args.extend(['/m:2'])
Craig Tillerb5391e12015-09-03 14:35:18 -07001029 # disable PDB generation: it's broken, and we don't need it during CI
Adele Zhoue4c35612015-10-16 15:34:23 -07001030 extra_args.extend(['/p:Jenkins=true'])
Craig Tiller6fd23842015-09-01 07:36:31 -07001031 return [
Jan Tattermusch2dd156e2015-12-04 18:26:17 -08001032 jobset.JobSpec([_windows_build_bat(args.compiler),
murgatroid99cf08daf2015-09-21 15:33:16 -07001033 'vsprojects\\%s.sln' % target,
Jan Tattermuscha2d964c2016-02-22 17:33:09 -08001034 '/p:Configuration=%s' % _MSBUILD_CONFIG[cfg]] +
Jan Tattermuschc895fe02016-01-20 09:13:09 -08001035 extra_args +
1036 language_make_options,
Craig Tiller590105a2016-01-19 13:03:46 -08001037 shell=True, timeout_seconds=None)
Craig Tiller6fd23842015-09-01 07:36:31 -07001038 for target in targets]
Jan Tattermuschfba65302016-01-25 18:21:14 -08001039 else:
murgatroid998ae409f2015-10-26 16:39:00 -07001040 if targets:
1041 return [jobset.JobSpec([os.getenv('MAKE', 'make'),
1042 '-f', makefile,
Craig Tillerdd6f7ed2016-01-21 12:54:42 -08001043 '-j', '%d' % args.jobs,
Craig Tiller71a86042016-01-15 14:59:58 -08001044 'EXTRA_DEFINES=GRPC_TEST_SLOWDOWN_MACHINE_FACTOR=%f' % args.slowdown,
1045 'CONFIG=%s' % cfg] +
Jan Tattermuschc895fe02016-01-20 09:13:09 -08001046 language_make_options +
Craig Tiller71a86042016-01-15 14:59:58 -08001047 ([] if not args.travis else ['JENKINS_BUILD=1']) +
1048 targets,
Craig Tiller590105a2016-01-19 13:03:46 -08001049 timeout_seconds=None)]
murgatroid998ae409f2015-10-26 16:39:00 -07001050 else:
1051 return []
Jan Tattermuschfba65302016-01-25 18:21:14 -08001052
murgatroid99a3e244f2015-09-22 11:25:53 -07001053make_targets = {}
1054for l in languages:
1055 makefile = l.makefile_name()
1056 make_targets[makefile] = make_targets.get(makefile, set()).union(
Jan Tattermusch77db4322016-02-20 20:19:35 -08001057 set(l.make_targets()))
Craig Tiller5058c692015-04-08 09:42:04 -07001058
Jan Tattermusche4a69182015-12-15 09:53:01 -08001059def build_step_environ(cfg):
1060 environ = {'CONFIG': cfg}
Jan Tattermuscha2d964c2016-02-22 17:33:09 -08001061 msbuild_cfg = _MSBUILD_CONFIG.get(cfg)
Jan Tattermusche4a69182015-12-15 09:53:01 -08001062 if msbuild_cfg:
1063 environ['MSBUILD_CONFIG'] = msbuild_cfg
1064 return environ
1065
murgatroid99fddac962015-09-22 09:20:11 -07001066build_steps = list(set(
Jan Tattermusch77db4322016-02-20 20:19:35 -08001067 jobset.JobSpec(cmdline, environ=build_step_environ(build_config), flake_retries=5)
murgatroid99256d3df2015-09-21 16:58:02 -07001068 for l in languages
1069 for cmdline in l.pre_build_steps()))
Craig Tillerbd4e3782015-09-01 06:48:55 -07001070if make_targets:
Jan Tattermusch77db4322016-02-20 20:19:35 -08001071 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 -07001072 build_steps.extend(set(make_commands))
Craig Tiller5058c692015-04-08 09:42:04 -07001073build_steps.extend(set(
Jan Tattermusch77db4322016-02-20 20:19:35 -08001074 jobset.JobSpec(cmdline, environ=build_step_environ(build_config), timeout_seconds=None)
Craig Tiller547db2b2015-01-30 14:08:39 -08001075 for l in languages
Craig Tiller533b1a22015-05-29 08:41:29 -07001076 for cmdline in l.build_steps()))
Craig Tillerf1973b02015-01-16 12:32:13 -08001077
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +02001078post_tests_steps = list(set(
Jan Tattermusch77db4322016-02-20 20:19:35 -08001079 jobset.JobSpec(cmdline, environ=build_step_environ(build_config))
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +02001080 for l in languages
1081 for cmdline in l.post_tests_steps()))
Nicolas Nobleddef2462015-01-06 18:08:25 -08001082runs_per_test = args.runs_per_test
ctiller3040cb72015-01-07 12:13:17 -08001083forever = args.forever
Nicolas Nobleddef2462015-01-06 18:08:25 -08001084
Nicolas Nobleddef2462015-01-06 18:08:25 -08001085
Ken Paysonfa51de52016-06-30 23:50:48 -07001086def _shut_down_legacy_server(legacy_server_port):
1087 try:
1088 version = int(urllib2.urlopen(
1089 'http://localhost:%d/version_number' % legacy_server_port,
1090 timeout=10).read())
1091 except:
1092 pass
1093 else:
1094 urllib2.urlopen(
1095 'http://localhost:%d/quitquitquit' % legacy_server_port).read()
1096
1097
Ken Paysond9dfc672016-06-30 23:50:48 -07001098def _shut_down_legacy_server(legacy_server_port):
1099 try:
1100 version = int(urllib2.urlopen(
1101 'http://localhost:%d/version_number' % legacy_server_port,
1102 timeout=10).read())
1103 except:
1104 pass
1105 else:
1106 urllib2.urlopen(
1107 'http://localhost:%d/quitquitquit' % legacy_server_port).read()
1108
1109
Craig Tillerf53d9c82015-08-04 14:19:43 -07001110def _start_port_server(port_server_port):
1111 # check if a compatible port server is running
1112 # if incompatible (version mismatch) ==> start a new one
1113 # if not running ==> start a new one
1114 # otherwise, leave it up
1115 try:
Craig Tillerfe4939f2015-10-06 12:55:36 -07001116 version = int(urllib2.urlopen(
1117 'http://localhost:%d/version_number' % port_server_port,
Jan Tattermusch292d0102016-06-28 10:29:41 -07001118 timeout=10).read())
Craig Tillerfe4939f2015-10-06 12:55:36 -07001119 print 'detected port server running version %d' % version
Craig Tillerf53d9c82015-08-04 14:19:43 -07001120 running = True
Craig Tillerfe4939f2015-10-06 12:55:36 -07001121 except Exception as e:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001122 print 'failed to detect port server: %s' % sys.exc_info()[0]
Craig Tillerfe4939f2015-10-06 12:55:36 -07001123 print e.strerror
Craig Tillerf53d9c82015-08-04 14:19:43 -07001124 running = False
1125 if running:
Craig Tillerfe4939f2015-10-06 12:55:36 -07001126 current_version = int(subprocess.check_output(
Jan Tattermusch3bd08272015-11-04 19:24:37 -08001127 [sys.executable, os.path.abspath('tools/run_tests/port_server.py'),
1128 'dump_version']))
Craig Tillerfe4939f2015-10-06 12:55:36 -07001129 print 'my port server is version %d' % current_version
1130 running = (version >= current_version)
1131 if not running:
1132 print 'port_server version mismatch: killing the old one'
1133 urllib2.urlopen('http://localhost:%d/quitquitquit' % port_server_port).read()
1134 time.sleep(1)
Craig Tillerf53d9c82015-08-04 14:19:43 -07001135 if not running:
Craig Tillerf0a293e2015-10-12 10:05:50 -07001136 fd, logfile = tempfile.mkstemp()
1137 os.close(fd)
1138 print 'starting port_server, with log file %s' % logfile
Jan Tattermusch3bd08272015-11-04 19:24:37 -08001139 args = [sys.executable, os.path.abspath('tools/run_tests/port_server.py'),
1140 '-p', '%d' % port_server_port, '-l', logfile]
Craig Tiller367d41d2015-10-12 13:00:22 -07001141 env = dict(os.environ)
1142 env['BUILD_ID'] = 'pleaseDontKillMeJenkins'
Nicolas "Pixel" Noblef72d7b52015-12-03 03:07:43 +01001143 if platform_string() == 'windows':
Jan Tattermusch3bd08272015-11-04 19:24:37 -08001144 # Working directory of port server needs to be outside of Jenkins
1145 # workspace to prevent file lock issues.
1146 tempdir = tempfile.mkdtemp()
Craig Tillerd2c39712015-10-12 11:08:49 -07001147 port_server = subprocess.Popen(
Craig Tiller367d41d2015-10-12 13:00:22 -07001148 args,
1149 env=env,
Jan Tattermusch3bd08272015-11-04 19:24:37 -08001150 cwd=tempdir,
Craig Tiller367d41d2015-10-12 13:00:22 -07001151 creationflags = 0x00000008, # detached process
1152 close_fds=True)
Craig Tillerd2c39712015-10-12 11:08:49 -07001153 else:
1154 port_server = subprocess.Popen(
1155 args,
Craig Tiller367d41d2015-10-12 13:00:22 -07001156 env=env,
Craig Tillerd2c39712015-10-12 11:08:49 -07001157 preexec_fn=os.setsid,
1158 close_fds=True)
Craig Tillerf0a293e2015-10-12 10:05:50 -07001159 time.sleep(1)
Craig Tiller8b5f4dc2015-08-26 08:02:01 -07001160 # ensure port server is up
Craig Tillerabd37fd2015-08-26 07:54:01 -07001161 waits = 0
Craig Tillerf53d9c82015-08-04 14:19:43 -07001162 while True:
Craig Tillerabd37fd2015-08-26 07:54:01 -07001163 if waits > 10:
Craig Tillerf0a293e2015-10-12 10:05:50 -07001164 print 'killing port server due to excessive start up waits'
Craig Tillerabd37fd2015-08-26 07:54:01 -07001165 port_server.kill()
Craig Tillera2f38b02015-09-24 11:19:17 -07001166 if port_server.poll() is not None:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001167 print 'port_server failed to start'
Craig Tillerf0a293e2015-10-12 10:05:50 -07001168 # try one final time: maybe another build managed to start one
1169 time.sleep(1)
1170 try:
1171 urllib2.urlopen('http://localhost:%d/get' % port_server_port,
1172 timeout=1).read()
1173 print 'last ditch attempt to contact port server succeeded'
1174 break
1175 except:
Jan Tattermusch3b5121b2016-02-22 17:41:05 -08001176 traceback.print_exc()
Craig Tillerf0a293e2015-10-12 10:05:50 -07001177 port_log = open(logfile, 'r').read()
1178 print port_log
1179 sys.exit(1)
Craig Tillerf53d9c82015-08-04 14:19:43 -07001180 try:
Craig Tillerabd37fd2015-08-26 07:54:01 -07001181 urllib2.urlopen('http://localhost:%d/get' % port_server_port,
1182 timeout=1).read()
Craig Tillerf0a293e2015-10-12 10:05:50 -07001183 print 'port server is up and ready'
Craig Tillerf53d9c82015-08-04 14:19:43 -07001184 break
Craig Tiller31fdaa42015-09-25 13:09:59 -07001185 except socket.timeout:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001186 print 'waiting for port_server: timeout'
Craig Tillerf0a293e2015-10-12 10:05:50 -07001187 traceback.print_exc();
1188 time.sleep(1)
Craig Tiller31fdaa42015-09-25 13:09:59 -07001189 waits += 1
Craig Tillerf53d9c82015-08-04 14:19:43 -07001190 except urllib2.URLError:
Craig Tiller0d6499e2015-10-05 14:00:47 -07001191 print 'waiting for port_server: urlerror'
Craig Tillerf0a293e2015-10-12 10:05:50 -07001192 traceback.print_exc();
1193 time.sleep(1)
Craig Tillerabd37fd2015-08-26 07:54:01 -07001194 waits += 1
Craig Tillerf53d9c82015-08-04 14:19:43 -07001195 except:
Jan Tattermusch3b5121b2016-02-22 17:41:05 -08001196 traceback.print_exc()
Craig Tillerf53d9c82015-08-04 14:19:43 -07001197 port_server.kill()
1198 raise
1199
1200
Adele Zhoud5fffa52015-10-23 15:51:42 -07001201def _calculate_num_runs_failures(list_of_results):
1202 """Caculate number of runs and failures for a particular test.
1203
1204 Args:
1205 list_of_results: (List) of JobResult object.
1206 Returns:
1207 A tuple of total number of runs and failures.
1208 """
1209 num_runs = len(list_of_results) # By default, there is 1 run per JobResult.
1210 num_failures = 0
1211 for jobresult in list_of_results:
1212 if jobresult.retries > 0:
1213 num_runs += jobresult.retries
1214 if jobresult.num_failures > 0:
1215 num_failures += jobresult.num_failures
1216 return num_runs, num_failures
1217
Adele Zhou6b9527c2015-11-20 15:56:35 -08001218
Craig Tillereb9de8b2016-01-08 08:57:41 -08001219# _build_and_run results
1220class BuildAndRunError(object):
1221
1222 BUILD = object()
1223 TEST = object()
1224 POST_TEST = object()
1225
1226
1227# returns a list of things that failed (or an empty list on success)
Craig Tillerf53d9c82015-08-04 14:19:43 -07001228def _build_and_run(
Craig Tiller74189cd2016-06-23 15:39:06 -07001229 check_cancelled, newline_on_success, xml_report=None, build_only=False):
ctiller3040cb72015-01-07 12:13:17 -08001230 """Do one pass of building & running tests."""
murgatroid99666450e2015-01-26 13:03:31 -08001231 # build latest sequentially
Jan Tattermuschaab1e512016-01-28 09:30:44 -08001232 num_failures, resultset = jobset.run(
Adele Zhoue4c35612015-10-16 15:34:23 -07001233 build_steps, maxjobs=1, stop_on_failure=True,
Craig Tiller883064c2015-11-04 10:06:10 -08001234 newline_on_success=newline_on_success, travis=args.travis)
Adele Zhoue4c35612015-10-16 15:34:23 -07001235 if num_failures:
Craig Tillereb9de8b2016-01-08 08:57:41 -08001236 return [BuildAndRunError.BUILD]
Craig Tillerb361b4e2016-01-06 11:44:17 -08001237
Jan Tattermusch2dd156e2015-12-04 18:26:17 -08001238 if build_only:
Jan Tattermuschaab1e512016-01-28 09:30:44 -08001239 if xml_report:
1240 report_utils.render_junit_xml_report(resultset, xml_report)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001241 return []
ctiller3040cb72015-01-07 12:13:17 -08001242
Craig Tiller234b6e72015-05-23 10:12:40 -07001243 # start antagonists
David Garcia Quintas79e389f2015-06-02 17:49:42 -07001244 antagonists = [subprocess.Popen(['tools/run_tests/antagonist.py'])
Craig Tiller234b6e72015-05-23 10:12:40 -07001245 for _ in range(0, args.antagonists)]
Ken Paysonfa51de52016-06-30 23:50:48 -07001246 port_server_port = 32766
Craig Tillerf53d9c82015-08-04 14:19:43 -07001247 _start_port_server(port_server_port)
Adele Zhou7cf72112015-11-04 11:18:43 -08001248 resultset = None
Adele Zhou803af152015-11-30 15:16:16 -08001249 num_test_failures = 0
Craig Tiller234b6e72015-05-23 10:12:40 -07001250 try:
David Garcia Quintase90cd372015-05-31 18:15:26 -07001251 infinite_runs = runs_per_test == 0
yang-g6c1fdc62015-08-18 11:57:42 -07001252 one_run = set(
1253 spec
yang-g6c1fdc62015-08-18 11:57:42 -07001254 for language in languages
Jan Tattermusch77db4322016-02-20 20:19:35 -08001255 for spec in language.test_specs()
Vijay Pai488fd0e2016-06-13 12:37:12 -07001256 if (re.search(args.regex, spec.shortname) and
1257 (args.regex_exclude == '' or
1258 not re.search(args.regex_exclude, spec.shortname))))
David Garcia Quintas79e389f2015-06-02 17:49:42 -07001259 # When running on travis, we want out test runs to be as similar as possible
1260 # for reproducibility purposes.
Craig Tiller883064c2015-11-04 10:06:10 -08001261 if args.travis:
David Garcia Quintas79e389f2015-06-02 17:49:42 -07001262 massaged_one_run = sorted(one_run, key=lambda x: x.shortname)
1263 else:
1264 # whereas otherwise, we want to shuffle things up to give all tests a
1265 # chance to run.
1266 massaged_one_run = list(one_run) # random.shuffle needs an indexable seq.
1267 random.shuffle(massaged_one_run) # which it modifies in-place.
Craig Tillerf7b7c892015-06-22 14:33:25 -07001268 if infinite_runs:
1269 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 -07001270 runs_sequence = (itertools.repeat(massaged_one_run) if infinite_runs
1271 else itertools.repeat(massaged_one_run, runs_per_test))
David Garcia Quintase90cd372015-05-31 18:15:26 -07001272 all_runs = itertools.chain.from_iterable(runs_sequence)
Nicolas "Pixel" Noble5937b5b2015-06-26 02:04:12 +02001273
Adele Zhou803af152015-11-30 15:16:16 -08001274 num_test_failures, resultset = jobset.run(
Adele Zhou2271ab52015-10-28 13:59:14 -07001275 all_runs, check_cancelled, newline_on_success=newline_on_success,
Craig Tiller883064c2015-11-04 10:06:10 -08001276 travis=args.travis, infinite_runs=infinite_runs, maxjobs=args.jobs,
murgatroid998ae409f2015-10-26 16:39:00 -07001277 stop_on_failure=args.stop_on_failure,
Adele Zhouf2ca7bc2015-10-23 15:38:00 -07001278 add_env={'GRPC_TEST_PORT_SERVER': 'localhost:%d' % port_server_port})
Adele Zhoud5fffa52015-10-23 15:51:42 -07001279 if resultset:
Craig Tiller2b59dbc2016-05-13 15:59:09 -07001280 for k, v in sorted(resultset.items()):
Adele Zhoud5fffa52015-10-23 15:51:42 -07001281 num_runs, num_failures = _calculate_num_runs_failures(v)
1282 if num_failures == num_runs: # what about infinite_runs???
1283 jobset.message('FAILED', k, do_newline=True)
1284 elif num_failures > 0:
1285 jobset.message(
1286 'FLAKE', '%s [%d/%d runs flaked]' % (k, num_failures, num_runs),
1287 do_newline=True)
Craig Tiller234b6e72015-05-23 10:12:40 -07001288 finally:
1289 for antagonist in antagonists:
1290 antagonist.kill()
Adele Zhou7cf72112015-11-04 11:18:43 -08001291 if xml_report and resultset:
Adele Zhou3bc7ba42015-11-05 10:21:58 -08001292 report_utils.render_junit_xml_report(resultset, xml_report)
Craig Tillerd86a3942015-01-14 12:48:54 -08001293
Adele Zhouf2ca7bc2015-10-23 15:38:00 -07001294 number_failures, _ = jobset.run(
1295 post_tests_steps, maxjobs=1, stop_on_failure=True,
Craig Tiller883064c2015-11-04 10:06:10 -08001296 newline_on_success=newline_on_success, travis=args.travis)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001297
1298 out = []
1299 if number_failures:
1300 out.append(BuildAndRunError.POST_TEST)
1301 if num_test_failures:
1302 out.append(BuildAndRunError.TEST)
Nicolas "Pixel" Noble3fcd3bf2015-10-10 02:30:38 +02001303
Craig Tillereb9de8b2016-01-08 08:57:41 -08001304 return out
ctiller3040cb72015-01-07 12:13:17 -08001305
1306
1307if forever:
Nicolas Noble044db742015-01-14 16:57:24 -08001308 success = True
ctiller3040cb72015-01-07 12:13:17 -08001309 while True:
Craig Tiller42bc87c2015-02-23 08:50:19 -08001310 dw = watch_dirs.DirWatcher(['src', 'include', 'test', 'examples'])
ctiller3040cb72015-01-07 12:13:17 -08001311 initial_time = dw.most_recent_change()
1312 have_files_changed = lambda: dw.most_recent_change() != initial_time
Nicolas Noble044db742015-01-14 16:57:24 -08001313 previous_success = success
Craig Tillereb9de8b2016-01-08 08:57:41 -08001314 errors = _build_and_run(check_cancelled=have_files_changed,
1315 newline_on_success=False,
Craig Tillereb9de8b2016-01-08 08:57:41 -08001316 build_only=args.build_only) == 0
1317 if not previous_success and not errors:
Nicolas Nobleb09078f2015-01-14 18:06:05 -08001318 jobset.message('SUCCESS',
1319 'All tests are now passing properly',
1320 do_newline=True)
Nicolas Noble044db742015-01-14 16:57:24 -08001321 jobset.message('IDLE', 'No change detected')
ctiller3040cb72015-01-07 12:13:17 -08001322 while not have_files_changed():
1323 time.sleep(1)
1324else:
Craig Tillereb9de8b2016-01-08 08:57:41 -08001325 errors = _build_and_run(check_cancelled=lambda: False,
Craig Tiller71735182015-01-15 17:07:13 -08001326 newline_on_success=args.newline_on_success,
Jan Tattermusch2dd156e2015-12-04 18:26:17 -08001327 xml_report=args.xml_report,
1328 build_only=args.build_only)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001329 if not errors:
Nicolas Nobleb09078f2015-01-14 18:06:05 -08001330 jobset.message('SUCCESS', 'All tests passed', do_newline=True)
1331 else:
1332 jobset.message('FAILED', 'Some tests failed', do_newline=True)
Craig Tillereb9de8b2016-01-08 08:57:41 -08001333 exit_code = 0
1334 if BuildAndRunError.BUILD in errors:
1335 exit_code |= 1
Craig Tiller4f2be362016-01-08 08:59:20 -08001336 if BuildAndRunError.TEST in errors and not args.travis:
Craig Tillereb9de8b2016-01-08 08:57:41 -08001337 exit_code |= 2
Craig Tiller4f2be362016-01-08 08:59:20 -08001338 if BuildAndRunError.POST_TEST in errors:
1339 exit_code |= 4
Craig Tillereb9de8b2016-01-08 08:57:41 -08001340 sys.exit(exit_code)