| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510 | 
							- #!/usr/bin/env python2.7
 
- # Copyright 2015, Google Inc.
 
- # All rights reserved.
 
- #
 
- # Redistribution and use in source and binary forms, with or without
 
- # modification, are permitted provided that the following conditions are
 
- # met:
 
- #
 
- #     * Redistributions of source code must retain the above copyright
 
- # notice, this list of conditions and the following disclaimer.
 
- #     * Redistributions in binary form must reproduce the above
 
- # copyright notice, this list of conditions and the following disclaimer
 
- # in the documentation and/or other materials provided with the
 
- # distribution.
 
- #     * Neither the name of Google Inc. nor the names of its
 
- # contributors may be used to endorse or promote products derived from
 
- # this software without specific prior written permission.
 
- #
 
- # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 
- # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 
- # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 
- # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 
- # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 
- # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 
- # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 
- # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 
- # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
- # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 
- # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
- """Run tests in parallel."""
 
- from __future__ import print_function
 
- import argparse
 
- import ast
 
- import collections
 
- import glob
 
- import itertools
 
- import json
 
- import multiprocessing
 
- import os
 
- import os.path
 
- import pipes
 
- import platform
 
- import random
 
- import re
 
- import socket
 
- import subprocess
 
- import sys
 
- import tempfile
 
- import traceback
 
- import time
 
- from six.moves import urllib
 
- import uuid
 
- import jobset
 
- import report_utils
 
- import watch_dirs
 
- _ROOT = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), '../..'))
 
- os.chdir(_ROOT)
 
- _FORCE_ENVIRON_FOR_WRAPPERS = {
 
-   'GRPC_VERBOSITY': 'DEBUG',
 
- }
 
- _POLLING_STRATEGIES = {
 
-   'linux': ['epoll', 'poll', 'poll-cv']
 
- }
 
- def platform_string():
 
-   return jobset.platform_string()
 
- _DEFAULT_TIMEOUT_SECONDS = 5 * 60
 
- # SimpleConfig: just compile with CONFIG=config, and run the binary to test
 
- class Config(object):
 
-   def __init__(self, config, environ=None, timeout_multiplier=1, tool_prefix=[], iomgr_platform='native'):
 
-     if environ is None:
 
-       environ = {}
 
-     self.build_config = config
 
-     self.environ = environ
 
-     self.environ['CONFIG'] = config
 
-     self.tool_prefix = tool_prefix
 
-     self.timeout_multiplier = timeout_multiplier
 
-     self.iomgr_platform = iomgr_platform
 
-   def job_spec(self, cmdline, timeout_seconds=_DEFAULT_TIMEOUT_SECONDS,
 
-                shortname=None, environ={}, cpu_cost=1.0, flaky=False):
 
-     """Construct a jobset.JobSpec for a test under this config
 
-        Args:
 
-          cmdline:      a list of strings specifying the command line the test
 
-                        would like to run
 
-     """
 
-     actual_environ = self.environ.copy()
 
-     for k, v in environ.items():
 
-       actual_environ[k] = v
 
-     return jobset.JobSpec(cmdline=self.tool_prefix + cmdline,
 
-                           shortname=shortname,
 
-                           environ=actual_environ,
 
-                           cpu_cost=cpu_cost,
 
-                           timeout_seconds=(self.timeout_multiplier * timeout_seconds if timeout_seconds else None),
 
-                           flake_retries=5 if flaky or args.allow_flakes else 0,
 
-                           timeout_retries=3 if args.allow_flakes else 0)
 
- def get_c_tests(travis, test_lang) :
 
-   out = []
 
-   platforms_str = 'ci_platforms' if travis else 'platforms'
 
-   with open('tools/run_tests/tests.json') as f:
 
-     js = json.load(f)
 
-     return [tgt
 
-             for tgt in js
 
-             if tgt['language'] == test_lang and
 
-                 platform_string() in tgt[platforms_str] and
 
-                 not (travis and tgt['flaky'])]
 
- def _check_compiler(compiler, supported_compilers):
 
-   if compiler not in supported_compilers:
 
-     raise Exception('Compiler %s not supported (on this platform).' % compiler)
 
- def _check_arch(arch, supported_archs):
 
-   if arch not in supported_archs:
 
-     raise Exception('Architecture %s not supported.' % arch)
 
- def _is_use_docker_child():
 
-   """Returns True if running running as a --use_docker child."""
 
-   return True if os.getenv('RUN_TESTS_COMMAND') else False
 
- _PythonConfigVars = collections.namedtuple(
 
-   '_ConfigVars', ['shell', 'builder', 'builder_prefix_arguments',
 
-                   'venv_relative_python', 'toolchain', 'runner'])
 
- def _python_config_generator(name, major, minor, bits, config_vars):
 
-   return PythonConfig(
 
-     name,
 
-     config_vars.shell + config_vars.builder + config_vars.builder_prefix_arguments + [
 
-       _python_pattern_function(major=major, minor=minor, bits=bits)] + [
 
-       name] + config_vars.venv_relative_python + config_vars.toolchain,
 
-     config_vars.shell + config_vars.runner + [
 
-       os.path.join(name, config_vars.venv_relative_python[0])])
 
- def _pypy_config_generator(name, major, config_vars):
 
-   return PythonConfig(
 
-     name,
 
-     config_vars.shell + config_vars.builder + config_vars.builder_prefix_arguments + [
 
-       _pypy_pattern_function(major=major)] + [
 
-       name] + config_vars.venv_relative_python + config_vars.toolchain,
 
-     config_vars.shell + config_vars.runner + [
 
-       os.path.join(name, config_vars.venv_relative_python[0])])
 
- def _python_pattern_function(major, minor, bits):
 
-   # Bit-ness is handled by the test machine's environment
 
-   if os.name == "nt":
 
-     if bits == "64":
 
-       return '/c/Python{major}{minor}/python.exe'.format(
 
-         major=major, minor=minor, bits=bits)
 
-     else:
 
-       return '/c/Python{major}{minor}_{bits}bits/python.exe'.format(
 
-         major=major, minor=minor, bits=bits)
 
-   else:
 
-     return 'python{major}.{minor}'.format(major=major, minor=minor)
 
- def _pypy_pattern_function(major):
 
-   if major == '2':
 
-     return 'pypy'
 
-   elif major == '3':
 
-     return 'pypy3'
 
-   else:
 
-     raise ValueError("Unknown PyPy major version")
 
- class CLanguage(object):
 
-   def __init__(self, make_target, test_lang):
 
-     self.make_target = make_target
 
-     self.platform = platform_string()
 
-     self.test_lang = test_lang
 
-   def configure(self, config, args):
 
-     self.config = config
 
-     self.args = args
 
-     if self.platform == 'windows':
 
-       self._make_options = [_windows_toolset_option(self.args.compiler),
 
-                             _windows_arch_option(self.args.arch)]
 
-     else:
 
-       self._docker_distro, self._make_options = self._compiler_options(self.args.use_docker,
 
-                                                                        self.args.compiler)
 
-     if args.iomgr_platform == "uv":
 
-       cflags = '-DGRPC_UV '
 
-       try:
 
-         cflags += subprocess.check_output(['pkg-config', '--cflags', 'libuv']).strip() + ' '
 
-       except (subprocess.CalledProcessError, OSError):
 
-         pass
 
-       try:
 
-         ldflags = subprocess.check_output(['pkg-config', '--libs', 'libuv']).strip() + ' '
 
-       except (subprocess.CalledProcessError, OSError):
 
-         ldflags = '-luv '
 
-       self._make_options += ['EXTRA_CPPFLAGS={}'.format(cflags),
 
-                              'EXTRA_LDLIBS={}'.format(ldflags)]
 
-   def test_specs(self):
 
-     out = []
 
-     binaries = get_c_tests(self.args.travis, self.test_lang)
 
-     for target in binaries:
 
-       polling_strategies = (_POLLING_STRATEGIES.get(self.platform, ['all'])
 
-                             if target.get('uses_polling', True)
 
-                             else ['all'])
 
-       if self.args.iomgr_platform == 'uv':
 
-         polling_strategies = ['all']
 
-       for polling_strategy in polling_strategies:
 
-         env={'GRPC_DEFAULT_SSL_ROOTS_FILE_PATH':
 
-                  _ROOT + '/src/core/lib/tsi/test_creds/ca.pem',
 
-              'GRPC_POLL_STRATEGY': polling_strategy,
 
-              'GRPC_VERBOSITY': 'DEBUG'}
 
-         shortname_ext = '' if polling_strategy=='all' else ' GRPC_POLL_STRATEGY=%s' % polling_strategy
 
-         if self.config.build_config in target['exclude_configs']:
 
-           continue
 
-         if self.args.iomgr_platform in target.get('exclude_iomgrs', []):
 
-           continue
 
-         if self.platform == 'windows':
 
-           binary = 'vsprojects/%s%s/%s.exe' % (
 
-               'x64/' if self.args.arch == 'x64' else '',
 
-               _MSBUILD_CONFIG[self.config.build_config],
 
-               target['name'])
 
-         else:
 
-           binary = 'bins/%s/%s' % (self.config.build_config, target['name'])
 
-         cpu_cost = target['cpu_cost']
 
-         if cpu_cost == 'capacity':
 
-           cpu_cost = multiprocessing.cpu_count()
 
-         if os.path.isfile(binary):
 
-           if 'gtest' in target and target['gtest']:
 
-             # here we parse the output of --gtest_list_tests to build up a
 
-             # complete list of the tests contained in a binary
 
-             # for each test, we then add a job to run, filtering for just that
 
-             # test
 
-             with open(os.devnull, 'w') as fnull:
 
-               tests = subprocess.check_output([binary, '--gtest_list_tests'],
 
-                                               stderr=fnull)
 
-             base = None
 
-             for line in tests.split('\n'):
 
-               i = line.find('#')
 
-               if i >= 0: line = line[:i]
 
-               if not line: continue
 
-               if line[0] != ' ':
 
-                 base = line.strip()
 
-               else:
 
-                 assert base is not None
 
-                 assert line[1] == ' '
 
-                 test = base + line.strip()
 
-                 cmdline = [binary] + ['--gtest_filter=%s' % test]
 
-                 out.append(self.config.job_spec(cmdline,
 
-                                                 shortname='%s --gtest_filter=%s %s' % (binary, test, shortname_ext),
 
-                                                 cpu_cost=cpu_cost,
 
-                                                 environ=env))
 
-           else:
 
-             cmdline = [binary] + target['args']
 
-             out.append(self.config.job_spec(cmdline,
 
-                                             shortname=' '.join(
 
-                                                           pipes.quote(arg)
 
-                                                           for arg in cmdline) +
 
-                                                       shortname_ext,
 
-                                             cpu_cost=cpu_cost,
 
-                                             flaky=target.get('flaky', False),
 
-                                             timeout_seconds=target.get('timeout_seconds', _DEFAULT_TIMEOUT_SECONDS),
 
-                                             environ=env))
 
-         elif self.args.regex == '.*' or self.platform == 'windows':
 
-           print('\nWARNING: binary not found, skipping', binary)
 
-     return sorted(out)
 
-   def make_targets(self):
 
-     if self.platform == 'windows':
 
-       # don't build tools on windows just yet
 
-       return ['buildtests_%s' % self.make_target]
 
-     return ['buildtests_%s' % self.make_target, 'tools_%s' % self.make_target]
 
-   def make_options(self):
 
-     return self._make_options;
 
-   def pre_build_steps(self):
 
-     if self.platform == 'windows':
 
-       return [['tools\\run_tests\\pre_build_c.bat']]
 
-     else:
 
-       return []
 
-   def build_steps(self):
 
-     return []
 
-   def post_tests_steps(self):
 
-     if self.platform == 'windows':
 
-       return []
 
-     else:
 
-       return [['tools/run_tests/post_tests_c.sh']]
 
-   def makefile_name(self):
 
-     return 'Makefile'
 
-   def _clang_make_options(self, version_suffix=''):
 
-     return ['CC=clang%s' % version_suffix,
 
-             'CXX=clang++%s' % version_suffix,
 
-             'LD=clang%s' % version_suffix,
 
-             'LDXX=clang++%s' % version_suffix]
 
-   def _gcc_make_options(self, version_suffix):
 
-     return ['CC=gcc%s' % version_suffix,
 
-             'CXX=g++%s' % version_suffix,
 
-             'LD=gcc%s' % version_suffix,
 
-             'LDXX=g++%s' % version_suffix]
 
-   def _compiler_options(self, use_docker, compiler):
 
-     """Returns docker distro and make options to use for given compiler."""
 
-     if not use_docker and not _is_use_docker_child():
 
-       _check_compiler(compiler, ['default'])
 
-     if compiler == 'gcc4.9' or compiler == 'default':
 
-       return ('jessie', [])
 
-     elif compiler == 'gcc4.4':
 
-       return ('wheezy', self._gcc_make_options(version_suffix='-4.4'))
 
-     elif compiler == 'gcc4.6':
 
-       return ('wheezy', self._gcc_make_options(version_suffix='-4.6'))
 
-     elif compiler == 'gcc4.8':
 
-       return ('jessie', self._gcc_make_options(version_suffix='-4.8'))
 
-     elif compiler == 'gcc5.3':
 
-       return ('ubuntu1604', [])
 
-     elif compiler == 'clang3.4':
 
-       # on ubuntu1404, clang-3.4 alias doesn't exist, just use 'clang'
 
-       return ('ubuntu1404', self._clang_make_options())
 
-     elif compiler == 'clang3.5':
 
-       return ('jessie', self._clang_make_options(version_suffix='-3.5'))
 
-     elif compiler == 'clang3.6':
 
-       return ('ubuntu1604', self._clang_make_options(version_suffix='-3.6'))
 
-     elif compiler == 'clang3.7':
 
-       return ('ubuntu1604', self._clang_make_options(version_suffix='-3.7'))
 
-     else:
 
-       raise Exception('Compiler %s not supported.' % compiler)
 
-   def dockerfile_dir(self):
 
-     return 'tools/dockerfile/test/cxx_%s_%s' % (self._docker_distro,
 
-                                                 _docker_arch_suffix(self.args.arch))
 
-   def __str__(self):
 
-     return self.make_target
 
- class NodeLanguage(object):
 
-   def __init__(self):
 
-     self.platform = platform_string()
 
-   def configure(self, config, args):
 
-     self.config = config
 
-     self.args = args
 
-     _check_compiler(self.args.compiler, ['default', 'node0.12',
 
-                                          'node4', 'node5', 'node6',
 
-                                          'node7'])
 
-     if self.args.compiler == 'default':
 
-       self.node_version = '4'
 
-     else:
 
-       # Take off the word "node"
 
-       self.node_version = self.args.compiler[4:]
 
-   def test_specs(self):
 
-     if self.platform == 'windows':
 
-       return [self.config.job_spec(['tools\\run_tests\\run_node.bat'], None)]
 
-     else:
 
-       return [self.config.job_spec(['tools/run_tests/run_node.sh', self.node_version],
 
-                                    None,
 
-                                    environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
 
-   def pre_build_steps(self):
 
-     if self.platform == 'windows':
 
-       return [['tools\\run_tests\\pre_build_node.bat']]
 
-     else:
 
-       return [['tools/run_tests/pre_build_node.sh', self.node_version]]
 
-   def make_targets(self):
 
-     return []
 
-   def make_options(self):
 
-     return []
 
-   def build_steps(self):
 
-     if self.platform == 'windows':
 
-       return [['tools\\run_tests\\build_node.bat']]
 
-     else:
 
-       return [['tools/run_tests/build_node.sh', self.node_version]]
 
-   def post_tests_steps(self):
 
-     return []
 
-   def makefile_name(self):
 
-     return 'Makefile'
 
-   def dockerfile_dir(self):
 
-     return 'tools/dockerfile/test/node_jessie_%s' % _docker_arch_suffix(self.args.arch)
 
-   def __str__(self):
 
-     return 'node'
 
- class PhpLanguage(object):
 
-   def configure(self, config, args):
 
-     self.config = config
 
-     self.args = args
 
-     _check_compiler(self.args.compiler, ['default'])
 
-   def test_specs(self):
 
-     return [self.config.job_spec(['src/php/bin/run_tests.sh'], None,
 
-                                   environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
 
-   def pre_build_steps(self):
 
-     return []
 
-   def make_targets(self):
 
-     return ['static_c', 'shared_c']
 
-   def make_options(self):
 
-     return []
 
-   def build_steps(self):
 
-     return [['tools/run_tests/build_php.sh']]
 
-   def post_tests_steps(self):
 
-     return [['tools/run_tests/post_tests_php.sh']]
 
-   def makefile_name(self):
 
-     return 'Makefile'
 
-   def dockerfile_dir(self):
 
-     return 'tools/dockerfile/test/php_jessie_%s' % _docker_arch_suffix(self.args.arch)
 
-   def __str__(self):
 
-     return 'php'
 
- class Php7Language(object):
 
-   def configure(self, config, args):
 
-     self.config = config
 
-     self.args = args
 
-     _check_compiler(self.args.compiler, ['default'])
 
-   def test_specs(self):
 
-     return [self.config.job_spec(['src/php/bin/run_tests.sh'], None,
 
-                                   environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
 
-   def pre_build_steps(self):
 
-     return []
 
-   def make_targets(self):
 
-     return ['static_c', 'shared_c']
 
-   def make_options(self):
 
-     return []
 
-   def build_steps(self):
 
-     return [['tools/run_tests/build_php.sh']]
 
-   def post_tests_steps(self):
 
-     return [['tools/run_tests/post_tests_php.sh']]
 
-   def makefile_name(self):
 
-     return 'Makefile'
 
-   def dockerfile_dir(self):
 
-     return 'tools/dockerfile/test/php7_jessie_%s' % _docker_arch_suffix(self.args.arch)
 
-   def __str__(self):
 
-     return 'php7'
 
- class PythonConfig(collections.namedtuple('PythonConfig', [
 
-     'name', 'build', 'run'])):
 
-   """Tuple of commands (named s.t. 'what it says on the tin' applies)"""
 
- class PythonLanguage(object):
 
-   def configure(self, config, args):
 
-     self.config = config
 
-     self.args = args
 
-     self.pythons = self._get_pythons(self.args)
 
-   def test_specs(self):
 
-     # load list of known test suites
 
-     with open('src/python/grpcio_tests/tests/tests.json') as tests_json_file:
 
-       tests_json = json.load(tests_json_file)
 
-     environment = dict(_FORCE_ENVIRON_FOR_WRAPPERS)
 
-     return [self.config.job_spec(
 
-         config.run,
 
-         timeout_seconds=5*60,
 
-         environ=dict(list(environment.items()) +
 
-                      [('GRPC_PYTHON_TESTRUNNER_FILTER', suite_name)]),
 
-         shortname='%s.test.%s' % (config.name, suite_name),)
 
-         for suite_name in tests_json
 
-         for config in self.pythons]
 
-   def pre_build_steps(self):
 
-     return []
 
-   def make_targets(self):
 
-     return []
 
-   def make_options(self):
 
-     return []
 
-   def build_steps(self):
 
-     return [config.build for config in self.pythons]
 
-   def post_tests_steps(self):
 
-     return []
 
-   def makefile_name(self):
 
-     return 'Makefile'
 
-   def dockerfile_dir(self):
 
-     return 'tools/dockerfile/test/python_%s_%s' % (self.python_manager_name(), _docker_arch_suffix(self.args.arch))
 
-   def python_manager_name(self):
 
-     return 'pyenv' if self.args.compiler in ['python3.5', 'python3.6'] else 'jessie'
 
-   def _get_pythons(self, args):
 
-     if args.arch == 'x86':
 
-       bits = '32'
 
-     else:
 
-       bits = '64'
 
-     if os.name == 'nt':
 
-       shell = ['bash']
 
-       builder = [os.path.abspath('tools/run_tests/build_python_msys2.sh')]
 
-       builder_prefix_arguments = ['MINGW{}'.format(bits)]
 
-       venv_relative_python = ['Scripts/python.exe']
 
-       toolchain = ['mingw32']
 
-     else:
 
-       shell = []
 
-       builder = [os.path.abspath('tools/run_tests/build_python.sh')]
 
-       builder_prefix_arguments = []
 
-       venv_relative_python = ['bin/python']
 
-       toolchain = ['unix']
 
-     runner = [os.path.abspath('tools/run_tests/run_python.sh')]
 
-     config_vars = _PythonConfigVars(shell, builder, builder_prefix_arguments,
 
-                               venv_relative_python, toolchain, runner)
 
-     python27_config = _python_config_generator(name='py27', major='2',
 
-                                                minor='7', bits=bits,
 
-                                                config_vars=config_vars)
 
-     python34_config = _python_config_generator(name='py34', major='3',
 
-                                                minor='4', bits=bits,
 
-                                                config_vars=config_vars)
 
-     python35_config = _python_config_generator(name='py35', major='3',
 
-                                                minor='5', bits=bits,
 
-                                                config_vars=config_vars)
 
-     python36_config = _python_config_generator(name='py36', major='3',
 
-                                                minor='6', bits=bits,
 
-                                                config_vars=config_vars)
 
-     pypy27_config = _pypy_config_generator(name='pypy', major='2',
 
-                                            config_vars=config_vars)
 
-     pypy32_config = _pypy_config_generator(name='pypy3', major='3',
 
-                                            config_vars=config_vars)
 
-     if args.compiler == 'default':
 
-       if os.name == 'nt':
 
-         return (python27_config,)
 
-       else:
 
-         return (python27_config, python34_config,)
 
-     elif args.compiler == 'python2.7':
 
-       return (python27_config,)
 
-     elif args.compiler == 'python3.4':
 
-       return (python34_config,)
 
-     elif args.compiler == 'python3.5':
 
-       return (python35_config,)
 
-     elif args.compiler == 'python3.6':
 
-       return (python36_config,)
 
-     elif args.compiler == 'pypy':
 
-       return (pypy27_config,)
 
-     elif args.compiler == 'pypy3':
 
-       return (pypy32_config,)
 
-     else:
 
-       raise Exception('Compiler %s not supported.' % args.compiler)
 
-   def __str__(self):
 
-     return 'python'
 
- class RubyLanguage(object):
 
-   def configure(self, config, args):
 
-     self.config = config
 
-     self.args = args
 
-     _check_compiler(self.args.compiler, ['default'])
 
-   def test_specs(self):
 
-     return [self.config.job_spec(['tools/run_tests/run_ruby.sh'],
 
-                                  timeout_seconds=10*60,
 
-                                  environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
 
-   def pre_build_steps(self):
 
-     return [['tools/run_tests/pre_build_ruby.sh']]
 
-   def make_targets(self):
 
-     return []
 
-   def make_options(self):
 
-     return []
 
-   def build_steps(self):
 
-     return [['tools/run_tests/build_ruby.sh']]
 
-   def post_tests_steps(self):
 
-     return [['tools/run_tests/post_tests_ruby.sh']]
 
-   def makefile_name(self):
 
-     return 'Makefile'
 
-   def dockerfile_dir(self):
 
-     return 'tools/dockerfile/test/ruby_jessie_%s' % _docker_arch_suffix(self.args.arch)
 
-   def __str__(self):
 
-     return 'ruby'
 
- class CSharpLanguage(object):
 
-   def __init__(self):
 
-     self.platform = platform_string()
 
-   def configure(self, config, args):
 
-     self.config = config
 
-     self.args = args
 
-     if self.platform == 'windows':
 
-       # Explicitly choosing between x86 and x64 arch doesn't work yet
 
-       _check_arch(self.args.arch, ['default'])
 
-       # CoreCLR use 64bit runtime by default.
 
-       arch_option = 'x64' if self.args.compiler == 'coreclr' else self.args.arch
 
-       self._make_options = [_windows_toolset_option(self.args.compiler),
 
-                             _windows_arch_option(arch_option)]
 
-     else:
 
-       _check_compiler(self.args.compiler, ['default', 'coreclr'])
 
-       if self.platform == 'linux' and self.args.compiler == 'coreclr':
 
-         self._docker_distro = 'coreclr'
 
-       else:
 
-         self._docker_distro = 'jessie'
 
-       if self.platform == 'mac':
 
-         # TODO(jtattermusch): EMBED_ZLIB=true currently breaks the mac build
 
-         self._make_options = ['EMBED_OPENSSL=true']
 
-         if self.args.compiler != 'coreclr':
 
-           # On Mac, official distribution of mono is 32bit.
 
-           self._make_options += ['CFLAGS=-m32', 'LDFLAGS=-m32']
 
-       else:
 
-         self._make_options = ['EMBED_OPENSSL=true', 'EMBED_ZLIB=true']
 
-   def test_specs(self):
 
-     with open('src/csharp/tests.json') as f:
 
-       tests_by_assembly = json.load(f)
 
-     msbuild_config = _MSBUILD_CONFIG[self.config.build_config]
 
-     nunit_args = ['--labels=All']
 
-     assembly_subdir = 'bin/%s' % msbuild_config
 
-     assembly_extension = '.exe'
 
-     if self.args.compiler == 'coreclr':
 
-       assembly_subdir += '/netcoreapp1.0'
 
-       runtime_cmd = ['dotnet', 'exec']
 
-       assembly_extension = '.dll'
 
-     else:
 
-       nunit_args += ['--noresult', '--workers=1']
 
-       if self.platform == 'windows':
 
-         runtime_cmd = []
 
-       else:
 
-         runtime_cmd = ['mono']
 
-     specs = []
 
-     for assembly in tests_by_assembly.iterkeys():
 
-       assembly_file = 'src/csharp/%s/%s/%s%s' % (assembly,
 
-                                                  assembly_subdir,
 
-                                                  assembly,
 
-                                                  assembly_extension)
 
-       if self.config.build_config != 'gcov' or self.platform != 'windows':
 
-         # normally, run each test as a separate process
 
-         for test in tests_by_assembly[assembly]:
 
-           cmdline = runtime_cmd + [assembly_file, '--test=%s' % test] + nunit_args
 
-           specs.append(self.config.job_spec(cmdline,
 
-                                             None,
 
-                                             shortname='csharp.%s' % test,
 
-                                             environ=_FORCE_ENVIRON_FOR_WRAPPERS))
 
-       else:
 
-         # For C# test coverage, run all tests from the same assembly at once
 
-         # using OpenCover.Console (only works on Windows).
 
-         cmdline = ['src\\csharp\\packages\\OpenCover.4.6.519\\tools\\OpenCover.Console.exe',
 
-                    '-target:%s' % assembly_file,
 
-                    '-targetdir:src\\csharp',
 
-                    '-targetargs:%s' % ' '.join(nunit_args),
 
-                    '-filter:+[Grpc.Core]*',
 
-                    '-register:user',
 
-                    '-output:src\\csharp\\coverage_csharp_%s.xml' % assembly]
 
-         # set really high cpu_cost to make sure instances of OpenCover.Console run exclusively
 
-         # to prevent problems with registering the profiler.
 
-         run_exclusive = 1000000
 
-         specs.append(self.config.job_spec(cmdline,
 
-                                           None,
 
-                                           shortname='csharp.coverage.%s' % assembly,
 
-                                           cpu_cost=run_exclusive,
 
-                                           environ=_FORCE_ENVIRON_FOR_WRAPPERS))
 
-     return specs
 
-   def pre_build_steps(self):
 
-     if self.platform == 'windows':
 
-       return [['tools\\run_tests\\pre_build_csharp.bat']]
 
-     else:
 
-       return [['tools/run_tests/pre_build_csharp.sh']]
 
-   def make_targets(self):
 
-     return ['grpc_csharp_ext']
 
-   def make_options(self):
 
-     return self._make_options;
 
-   def build_steps(self):
 
-     if self.args.compiler == 'coreclr':
 
-       if self.platform == 'windows':
 
-         return [['tools\\run_tests\\build_csharp_coreclr.bat']]
 
-       else:
 
-         return [['tools/run_tests/build_csharp_coreclr.sh']]
 
-     else:
 
-       if self.platform == 'windows':
 
-         return [[_windows_build_bat(self.args.compiler),
 
-                  'src/csharp/Grpc.sln',
 
-                  '/p:Configuration=%s' % _MSBUILD_CONFIG[self.config.build_config]]]
 
-       else:
 
-         return [['tools/run_tests/build_csharp.sh']]
 
-   def post_tests_steps(self):
 
-     if self.platform == 'windows':
 
-       return [['tools\\run_tests\\post_tests_csharp.bat']]
 
-     else:
 
-       return [['tools/run_tests/post_tests_csharp.sh']]
 
-   def makefile_name(self):
 
-     return 'Makefile'
 
-   def dockerfile_dir(self):
 
-     return 'tools/dockerfile/test/csharp_%s_%s' % (self._docker_distro,
 
-                                                    _docker_arch_suffix(self.args.arch))
 
-   def __str__(self):
 
-     return 'csharp'
 
- class ObjCLanguage(object):
 
-   def configure(self, config, args):
 
-     self.config = config
 
-     self.args = args
 
-     _check_compiler(self.args.compiler, ['default'])
 
-   def test_specs(self):
 
-     return [
 
-         self.config.job_spec(['src/objective-c/tests/run_tests.sh'],
 
-                               timeout_seconds=None,
 
-                               shortname='objc-tests',
 
-                               environ=_FORCE_ENVIRON_FOR_WRAPPERS),
 
-         self.config.job_spec(['src/objective-c/tests/build_example_test.sh'],
 
-                               timeout_seconds=30*60,
 
-                               shortname='objc-examples-build',
 
-                               environ=_FORCE_ENVIRON_FOR_WRAPPERS),
 
-     ]
 
-   def pre_build_steps(self):
 
-     return []
 
-   def make_targets(self):
 
-     return ['interop_server']
 
-   def make_options(self):
 
-     return []
 
-   def build_steps(self):
 
-     return [['src/objective-c/tests/build_tests.sh']]
 
-   def post_tests_steps(self):
 
-     return []
 
-   def makefile_name(self):
 
-     return 'Makefile'
 
-   def dockerfile_dir(self):
 
-     return None
 
-   def __str__(self):
 
-     return 'objc'
 
- class Sanity(object):
 
-   def configure(self, config, args):
 
-     self.config = config
 
-     self.args = args
 
-     _check_compiler(self.args.compiler, ['default'])
 
-   def test_specs(self):
 
-     import yaml
 
-     with open('tools/run_tests/sanity/sanity_tests.yaml', 'r') as f:
 
-       return [self.config.job_spec(cmd['script'].split(),
 
-                                    timeout_seconds=None, environ={'TEST': 'true'},
 
-                                    cpu_cost=cmd.get('cpu_cost', 1))
 
-               for cmd in yaml.load(f)]
 
-   def pre_build_steps(self):
 
-     return []
 
-   def make_targets(self):
 
-     return ['run_dep_checks']
 
-   def make_options(self):
 
-     return []
 
-   def build_steps(self):
 
-     return []
 
-   def post_tests_steps(self):
 
-     return []
 
-   def makefile_name(self):
 
-     return 'Makefile'
 
-   def dockerfile_dir(self):
 
-     return 'tools/dockerfile/test/sanity'
 
-   def __str__(self):
 
-     return 'sanity'
 
- class NodeExpressLanguage(object):
 
-   """Dummy Node express test target to enable running express performance
 
-   benchmarks"""
 
-   def __init__(self):
 
-     self.platform = platform_string()
 
-   def configure(self, config, args):
 
-     self.config = config
 
-     self.args = args
 
-     _check_compiler(self.args.compiler, ['default', 'node0.12',
 
-                                          'node4', 'node5', 'node6'])
 
-     if self.args.compiler == 'default':
 
-       self.node_version = '4'
 
-     else:
 
-       # Take off the word "node"
 
-       self.node_version = self.args.compiler[4:]
 
-   def test_specs(self):
 
-     return []
 
-   def pre_build_steps(self):
 
-     if self.platform == 'windows':
 
-       return [['tools\\run_tests\\pre_build_node.bat']]
 
-     else:
 
-       return [['tools/run_tests/pre_build_node.sh', self.node_version]]
 
-   def make_targets(self):
 
-     return []
 
-   def make_options(self):
 
-     return []
 
-   def build_steps(self):
 
-     return []
 
-   def post_tests_steps(self):
 
-     return []
 
-   def makefile_name(self):
 
-     return 'Makefile'
 
-   def dockerfile_dir(self):
 
-     return 'tools/dockerfile/test/node_jessie_%s' % _docker_arch_suffix(self.args.arch)
 
-   def __str__(self):
 
-     return 'node_express'
 
- # different configurations we can run under
 
- with open('tools/run_tests/configs.json') as f:
 
-   _CONFIGS = dict((cfg['config'], Config(**cfg)) for cfg in ast.literal_eval(f.read()))
 
- _LANGUAGES = {
 
-     'c++': CLanguage('cxx', 'c++'),
 
-     'c': CLanguage('c', 'c'),
 
-     'node': NodeLanguage(),
 
-     'node_express': NodeExpressLanguage(),
 
-     'php': PhpLanguage(),
 
-     'php7': Php7Language(),
 
-     'python': PythonLanguage(),
 
-     'ruby': RubyLanguage(),
 
-     'csharp': CSharpLanguage(),
 
-     'objc' : ObjCLanguage(),
 
-     'sanity': Sanity()
 
-     }
 
- _MSBUILD_CONFIG = {
 
-     'dbg': 'Debug',
 
-     'opt': 'Release',
 
-     'gcov': 'Debug',
 
-     }
 
- def _windows_arch_option(arch):
 
-   """Returns msbuild cmdline option for selected architecture."""
 
-   if arch == 'default' or arch == 'x86':
 
-     return '/p:Platform=Win32'
 
-   elif arch == 'x64':
 
-     return '/p:Platform=x64'
 
-   else:
 
-     print('Architecture %s not supported.' % arch)
 
-     sys.exit(1)
 
- def _check_arch_option(arch):
 
-   """Checks that architecture option is valid."""
 
-   if platform_string() == 'windows':
 
-     _windows_arch_option(arch)
 
-   elif platform_string() == 'linux':
 
-     # On linux, we need to be running under docker with the right architecture.
 
-     runtime_arch = platform.architecture()[0]
 
-     if arch == 'default':
 
-       return
 
-     elif runtime_arch == '64bit' and arch == 'x64':
 
-       return
 
-     elif runtime_arch == '32bit' and arch == 'x86':
 
-       return
 
-     else:
 
-       print('Architecture %s does not match current runtime architecture.' % arch)
 
-       sys.exit(1)
 
-   else:
 
-     if args.arch != 'default':
 
-       print('Architecture %s not supported on current platform.' % args.arch)
 
-       sys.exit(1)
 
- def _windows_build_bat(compiler):
 
-   """Returns name of build.bat for selected compiler."""
 
-   # For CoreCLR, fall back to the default compiler for C core
 
-   if compiler == 'default' or compiler == 'vs2013' or compiler == 'coreclr':
 
-     return 'vsprojects\\build_vs2013.bat'
 
-   elif compiler == 'vs2015':
 
-     return 'vsprojects\\build_vs2015.bat'
 
-   elif compiler == 'vs2010':
 
-     return 'vsprojects\\build_vs2010.bat'
 
-   else:
 
-     print('Compiler %s not supported.' % compiler)
 
-     sys.exit(1)
 
- def _windows_toolset_option(compiler):
 
-   """Returns msbuild PlatformToolset for selected compiler."""
 
-   # For CoreCLR, fall back to the default compiler for C core
 
-   if compiler == 'default' or compiler == 'vs2013' or compiler == 'coreclr':
 
-     return '/p:PlatformToolset=v120'
 
-   elif compiler == 'vs2015':
 
-     return '/p:PlatformToolset=v140'
 
-   elif compiler == 'vs2010':
 
-     return '/p:PlatformToolset=v100'
 
-   else:
 
-     print('Compiler %s not supported.' % compiler)
 
-     sys.exit(1)
 
- def _docker_arch_suffix(arch):
 
-   """Returns suffix to dockerfile dir to use."""
 
-   if arch == 'default' or arch == 'x64':
 
-     return 'x64'
 
-   elif arch == 'x86':
 
-     return 'x86'
 
-   else:
 
-     print('Architecture %s not supported with current settings.' % arch)
 
-     sys.exit(1)
 
- def runs_per_test_type(arg_str):
 
-     """Auxilary function to parse the "runs_per_test" flag.
 
-        Returns:
 
-            A positive integer or 0, the latter indicating an infinite number of
 
-            runs.
 
-        Raises:
 
-            argparse.ArgumentTypeError: Upon invalid input.
 
-     """
 
-     if arg_str == 'inf':
 
-         return 0
 
-     try:
 
-         n = int(arg_str)
 
-         if n <= 0: raise ValueError
 
-         return n
 
-     except:
 
-         msg = '\'{}\' is not a positive integer or \'inf\''.format(arg_str)
 
-         raise argparse.ArgumentTypeError(msg)
 
- # parse command line
 
- argp = argparse.ArgumentParser(description='Run grpc tests.')
 
- argp.add_argument('-c', '--config',
 
-                   choices=sorted(_CONFIGS.keys()),
 
-                   default='opt')
 
- argp.add_argument('-n', '--runs_per_test', default=1, type=runs_per_test_type,
 
-         help='A positive integer or "inf". If "inf", all tests will run in an '
 
-              'infinite loop. Especially useful in combination with "-f"')
 
- argp.add_argument('-r', '--regex', default='.*', type=str)
 
- argp.add_argument('--regex_exclude', default='', type=str)
 
- argp.add_argument('-j', '--jobs', default=multiprocessing.cpu_count(), type=int)
 
- argp.add_argument('-s', '--slowdown', default=1.0, type=float)
 
- argp.add_argument('-f', '--forever',
 
-                   default=False,
 
-                   action='store_const',
 
-                   const=True)
 
- argp.add_argument('-t', '--travis',
 
-                   default=False,
 
-                   action='store_const',
 
-                   const=True)
 
- argp.add_argument('--newline_on_success',
 
-                   default=False,
 
-                   action='store_const',
 
-                   const=True)
 
- argp.add_argument('-l', '--language',
 
-                   choices=['all'] + sorted(_LANGUAGES.keys()),
 
-                   nargs='+',
 
-                   default=['all'])
 
- argp.add_argument('-S', '--stop_on_failure',
 
-                   default=False,
 
-                   action='store_const',
 
-                   const=True)
 
- argp.add_argument('--use_docker',
 
-                   default=False,
 
-                   action='store_const',
 
-                   const=True,
 
-                   help='Run all the tests under docker. That provides ' +
 
-                   'additional isolation and prevents the need to install ' +
 
-                   'language specific prerequisites. Only available on Linux.')
 
- argp.add_argument('--allow_flakes',
 
-                   default=False,
 
-                   action='store_const',
 
-                   const=True,
 
-                   help='Allow flaky tests to show as passing (re-runs failed tests up to five times)')
 
- argp.add_argument('--arch',
 
-                   choices=['default', 'x86', 'x64'],
 
-                   default='default',
 
-                   help='Selects architecture to target. For some platforms "default" is the only supported choice.')
 
- argp.add_argument('--compiler',
 
-                   choices=['default',
 
-                            'gcc4.4', 'gcc4.6', 'gcc4.8', 'gcc4.9', 'gcc5.3',
 
-                            'clang3.4', 'clang3.5', 'clang3.6', 'clang3.7',
 
-                            'vs2010', 'vs2013', 'vs2015',
 
-                            'python2.7', 'python3.4', 'python3.5', 'python3.6', 'pypy', 'pypy3',
 
-                            'node0.12', 'node4', 'node5', 'node6', 'node7',
 
-                            'coreclr'],
 
-                   default='default',
 
-                   help='Selects compiler to use. Allowed values depend on the platform and language.')
 
- argp.add_argument('--iomgr_platform',
 
-                   choices=['native', 'uv'],
 
-                   default='native',
 
-                   help='Selects iomgr platform to build on')
 
- argp.add_argument('--build_only',
 
-                   default=False,
 
-                   action='store_const',
 
-                   const=True,
 
-                   help='Perform all the build steps but dont run any tests.')
 
- argp.add_argument('--measure_cpu_costs', default=False, action='store_const', const=True,
 
-                   help='Measure the cpu costs of tests')
 
- argp.add_argument('--update_submodules', default=[], nargs='*',
 
-                   help='Update some submodules before building. If any are updated, also run generate_projects. ' +
 
-                        'Submodules are specified as SUBMODULE_NAME:BRANCH; if BRANCH is omitted, master is assumed.')
 
- argp.add_argument('-a', '--antagonists', default=0, type=int)
 
- argp.add_argument('-x', '--xml_report', default=None, type=str,
 
-         help='Generates a JUnit-compatible XML report')
 
- argp.add_argument('--report_suite_name', default='tests', type=str,
 
-         help='Test suite name to use in generated JUnit XML report')
 
- argp.add_argument('--force_default_poller', default=False, action='store_const', const=True,
 
-                   help='Dont try to iterate over many polling strategies when they exist')
 
- args = argp.parse_args()
 
- if args.force_default_poller:
 
-   _POLLING_STRATEGIES = {}
 
- jobset.measure_cpu_costs = args.measure_cpu_costs
 
- # update submodules if necessary
 
- need_to_regenerate_projects = False
 
- for spec in args.update_submodules:
 
-   spec = spec.split(':', 1)
 
-   if len(spec) == 1:
 
-     submodule = spec[0]
 
-     branch = 'master'
 
-   elif len(spec) == 2:
 
-     submodule = spec[0]
 
-     branch = spec[1]
 
-   cwd = 'third_party/%s' % submodule
 
-   def git(cmd, cwd=cwd):
 
-     print('in %s: git %s' % (cwd, cmd))
 
-     subprocess.check_call('git %s' % cmd, cwd=cwd, shell=True)
 
-   git('fetch')
 
-   git('checkout %s' % branch)
 
-   git('pull origin %s' % branch)
 
-   if os.path.exists('src/%s/gen_build_yaml.py' % submodule):
 
-     need_to_regenerate_projects = True
 
- if need_to_regenerate_projects:
 
-   if jobset.platform_string() == 'linux':
 
-     subprocess.check_call('tools/buildgen/generate_projects.sh', shell=True)
 
-   else:
 
-     print('WARNING: may need to regenerate projects, but since we are not on')
 
-     print('         Linux this step is being skipped. Compilation MAY fail.')
 
- # grab config
 
- run_config = _CONFIGS[args.config]
 
- build_config = run_config.build_config
 
- if args.travis:
 
-   _FORCE_ENVIRON_FOR_WRAPPERS = {'GRPC_TRACE': 'api'}
 
- if 'all' in args.language:
 
-   lang_list = _LANGUAGES.keys()
 
- else:
 
-   lang_list = args.language
 
- # We don't support code coverage on some languages
 
- if 'gcov' in args.config:
 
-   for bad in ['objc', 'sanity']:
 
-     if bad in lang_list:
 
-       lang_list.remove(bad)
 
- languages = set(_LANGUAGES[l] for l in lang_list)
 
- for l in languages:
 
-   l.configure(run_config, args)
 
- language_make_options=[]
 
- if any(language.make_options() for language in languages):
 
-   if not 'gcov' in args.config and len(languages) != 1:
 
-     print('languages with custom make options cannot be built simultaneously with other languages')
 
-     sys.exit(1)
 
-   else:
 
-     language_make_options = next(iter(languages)).make_options()
 
- if args.use_docker:
 
-   if not args.travis:
 
-     print('Seen --use_docker flag, will run tests under docker.')
 
-     print('')
 
-     print('IMPORTANT: The changes you are testing need to be locally committed')
 
-     print('because only the committed changes in the current branch will be')
 
-     print('copied to the docker environment.')
 
-     time.sleep(5)
 
-   dockerfile_dirs = set([l.dockerfile_dir() for l in languages])
 
-   if len(dockerfile_dirs) > 1:
 
-     if 'gcov' in args.config:
 
-       dockerfile_dir = 'tools/dockerfile/test/multilang_jessie_x64'
 
-       print ('Using multilang_jessie_x64 docker image for code coverage for '
 
-              'all languages.')
 
-     else:
 
-       print ('Languages to be tested require running under different docker '
 
-              'images.')
 
-       sys.exit(1)
 
-   else:
 
-     dockerfile_dir = next(iter(dockerfile_dirs))
 
-   child_argv = [ arg for arg in sys.argv if not arg == '--use_docker' ]
 
-   run_tests_cmd = 'python tools/run_tests/run_tests.py %s' % ' '.join(child_argv[1:])
 
-   env = os.environ.copy()
 
-   env['RUN_TESTS_COMMAND'] = run_tests_cmd
 
-   env['DOCKERFILE_DIR'] = dockerfile_dir
 
-   env['DOCKER_RUN_SCRIPT'] = 'tools/run_tests/dockerize/docker_run_tests.sh'
 
-   if args.xml_report:
 
-     env['XML_REPORT'] = args.xml_report
 
-   if not args.travis:
 
-     env['TTY_FLAG'] = '-t'  # enables Ctrl-C when not on Jenkins.
 
-   subprocess.check_call(['tools/run_tests/dockerize/build_docker_and_run_tests.sh'],
 
-                         shell=True,
 
-                         env=env)
 
-   sys.exit(0)
 
- _check_arch_option(args.arch)
 
- def make_jobspec(cfg, targets, makefile='Makefile'):
 
-   if platform_string() == 'windows':
 
-     extra_args = []
 
-     # better do parallel compilation
 
-     # empirically /m:2 gives the best performance/price and should prevent
 
-     # overloading the windows workers.
 
-     extra_args.extend(['/m:2'])
 
-     # disable PDB generation: it's broken, and we don't need it during CI
 
-     extra_args.extend(['/p:Jenkins=true'])
 
-     return [
 
-       jobset.JobSpec([_windows_build_bat(args.compiler),
 
-                       'vsprojects\\%s.sln' % target,
 
-                       '/p:Configuration=%s' % _MSBUILD_CONFIG[cfg]] +
 
-                       extra_args +
 
-                       language_make_options,
 
-                       shell=True, timeout_seconds=None)
 
-       for target in targets]
 
-   else:
 
-     if targets:
 
-       return [jobset.JobSpec([os.getenv('MAKE', 'make'),
 
-                               '-f', makefile,
 
-                               '-j', '%d' % args.jobs,
 
-                               'EXTRA_DEFINES=GRPC_TEST_SLOWDOWN_MACHINE_FACTOR=%f' % args.slowdown,
 
-                               'CONFIG=%s' % cfg] +
 
-                               language_make_options +
 
-                              ([] if not args.travis else ['JENKINS_BUILD=1']) +
 
-                              targets,
 
-                              timeout_seconds=None)]
 
-     else:
 
-       return []
 
- make_targets = {}
 
- for l in languages:
 
-   makefile = l.makefile_name()
 
-   make_targets[makefile] = make_targets.get(makefile, set()).union(
 
-       set(l.make_targets()))
 
- def build_step_environ(cfg):
 
-   environ = {'CONFIG': cfg}
 
-   msbuild_cfg = _MSBUILD_CONFIG.get(cfg)
 
-   if msbuild_cfg:
 
-     environ['MSBUILD_CONFIG'] = msbuild_cfg
 
-   return environ
 
- build_steps = list(set(
 
-                    jobset.JobSpec(cmdline, environ=build_step_environ(build_config), flake_retries=5)
 
-                    for l in languages
 
-                    for cmdline in l.pre_build_steps()))
 
- if make_targets:
 
-   make_commands = itertools.chain.from_iterable(make_jobspec(build_config, list(targets), makefile) for (makefile, targets) in make_targets.items())
 
-   build_steps.extend(set(make_commands))
 
- build_steps.extend(set(
 
-                    jobset.JobSpec(cmdline, environ=build_step_environ(build_config), timeout_seconds=None)
 
-                    for l in languages
 
-                    for cmdline in l.build_steps()))
 
- post_tests_steps = list(set(
 
-                         jobset.JobSpec(cmdline, environ=build_step_environ(build_config))
 
-                         for l in languages
 
-                         for cmdline in l.post_tests_steps()))
 
- runs_per_test = args.runs_per_test
 
- forever = args.forever
 
- def _shut_down_legacy_server(legacy_server_port):
 
-   try:
 
-     version = int(urllib.request.urlopen(
 
-         'http://localhost:%d/version_number' % legacy_server_port,
 
-         timeout=10).read())
 
-   except:
 
-     pass
 
-   else:
 
-     urllib.request.urlopen(
 
-         'http://localhost:%d/quitquitquit' % legacy_server_port).read()
 
- def _start_port_server(port_server_port):
 
-   # check if a compatible port server is running
 
-   # if incompatible (version mismatch) ==> start a new one
 
-   # if not running ==> start a new one
 
-   # otherwise, leave it up
 
-   try:
 
-     version = int(urllib.request.urlopen(
 
-         'http://localhost:%d/version_number' % port_server_port,
 
-         timeout=10).read())
 
-     print('detected port server running version %d' % version)
 
-     running = True
 
-   except Exception as e:
 
-     print('failed to detect port server: %s' % sys.exc_info()[0])
 
-     print(e.strerror)
 
-     running = False
 
-   if running:
 
-     current_version = int(subprocess.check_output(
 
-         [sys.executable, os.path.abspath('tools/run_tests/port_server.py'),
 
-          'dump_version']))
 
-     print('my port server is version %d' % current_version)
 
-     running = (version >= current_version)
 
-     if not running:
 
-       print('port_server version mismatch: killing the old one')
 
-       urllib.request.urlopen('http://localhost:%d/quitquitquit' % port_server_port).read()
 
-       time.sleep(1)
 
-   if not running:
 
-     fd, logfile = tempfile.mkstemp()
 
-     os.close(fd)
 
-     print('starting port_server, with log file %s' % logfile)
 
-     args = [sys.executable, os.path.abspath('tools/run_tests/port_server.py'),
 
-             '-p', '%d' % port_server_port, '-l', logfile]
 
-     env = dict(os.environ)
 
-     env['BUILD_ID'] = 'pleaseDontKillMeJenkins'
 
-     if platform_string() == 'windows':
 
-       # Working directory of port server needs to be outside of Jenkins
 
-       # workspace to prevent file lock issues.
 
-       tempdir = tempfile.mkdtemp()
 
-       port_server = subprocess.Popen(
 
-           args,
 
-           env=env,
 
-           cwd=tempdir,
 
-           creationflags = 0x00000008, # detached process
 
-           close_fds=True)
 
-     else:
 
-       port_server = subprocess.Popen(
 
-           args,
 
-           env=env,
 
-           preexec_fn=os.setsid,
 
-           close_fds=True)
 
-     time.sleep(1)
 
-     # ensure port server is up
 
-     waits = 0
 
-     while True:
 
-       if waits > 10:
 
-         print('killing port server due to excessive start up waits')
 
-         port_server.kill()
 
-       if port_server.poll() is not None:
 
-         print('port_server failed to start')
 
-         # try one final time: maybe another build managed to start one
 
-         time.sleep(1)
 
-         try:
 
-           urllib.request.urlopen('http://localhost:%d/get' % port_server_port,
 
-                           timeout=1).read()
 
-           print('last ditch attempt to contact port server succeeded')
 
-           break
 
-         except:
 
-           traceback.print_exc()
 
-           port_log = open(logfile, 'r').read()
 
-           print(port_log)
 
-           sys.exit(1)
 
-       try:
 
-         urllib.request.urlopen('http://localhost:%d/get' % port_server_port,
 
-                         timeout=1).read()
 
-         print('port server is up and ready')
 
-         break
 
-       except socket.timeout:
 
-         print('waiting for port_server: timeout')
 
-         traceback.print_exc();
 
-         time.sleep(1)
 
-         waits += 1
 
-       except urllib.error.URLError:
 
-         print('waiting for port_server: urlerror')
 
-         traceback.print_exc();
 
-         time.sleep(1)
 
-         waits += 1
 
-       except:
 
-         traceback.print_exc()
 
-         port_server.kill()
 
-         raise
 
- def _calculate_num_runs_failures(list_of_results):
 
-   """Caculate number of runs and failures for a particular test.
 
-   Args:
 
-     list_of_results: (List) of JobResult object.
 
-   Returns:
 
-     A tuple of total number of runs and failures.
 
-   """
 
-   num_runs = len(list_of_results)  # By default, there is 1 run per JobResult.
 
-   num_failures = 0
 
-   for jobresult in list_of_results:
 
-     if jobresult.retries > 0:
 
-       num_runs += jobresult.retries
 
-     if jobresult.num_failures > 0:
 
-       num_failures += jobresult.num_failures
 
-   return num_runs, num_failures
 
- # _build_and_run results
 
- class BuildAndRunError(object):
 
-   BUILD = object()
 
-   TEST = object()
 
-   POST_TEST = object()
 
- # returns a list of things that failed (or an empty list on success)
 
- def _build_and_run(
 
-     check_cancelled, newline_on_success, xml_report=None, build_only=False):
 
-   """Do one pass of building & running tests."""
 
-   # build latest sequentially
 
-   num_failures, resultset = jobset.run(
 
-       build_steps, maxjobs=1, stop_on_failure=True,
 
-       newline_on_success=newline_on_success, travis=args.travis)
 
-   if num_failures:
 
-     return [BuildAndRunError.BUILD]
 
-   if build_only:
 
-     if xml_report:
 
-       report_utils.render_junit_xml_report(resultset, xml_report,
 
-                                            suite_name=args.report_suite_name)
 
-     return []
 
-   # start antagonists
 
-   antagonists = [subprocess.Popen(['tools/run_tests/antagonist.py'])
 
-                  for _ in range(0, args.antagonists)]
 
-   port_server_port = 32766
 
-   _start_port_server(port_server_port)
 
-   resultset = None
 
-   num_test_failures = 0
 
-   try:
 
-     infinite_runs = runs_per_test == 0
 
-     one_run = set(
 
-       spec
 
-       for language in languages
 
-       for spec in language.test_specs()
 
-       if (re.search(args.regex, spec.shortname) and
 
-           (args.regex_exclude == '' or
 
-            not re.search(args.regex_exclude, spec.shortname))))
 
-     # When running on travis, we want out test runs to be as similar as possible
 
-     # for reproducibility purposes.
 
-     if args.travis:
 
-       massaged_one_run = sorted(one_run, key=lambda x: x.shortname)
 
-     else:
 
-       # whereas otherwise, we want to shuffle things up to give all tests a
 
-       # chance to run.
 
-       massaged_one_run = list(one_run)  # random.shuffle needs an indexable seq.
 
-       random.shuffle(massaged_one_run)  # which it modifies in-place.
 
-     if infinite_runs:
 
-       assert len(massaged_one_run) > 0, 'Must have at least one test for a -n inf run'
 
-     runs_sequence = (itertools.repeat(massaged_one_run) if infinite_runs
 
-                      else itertools.repeat(massaged_one_run, runs_per_test))
 
-     all_runs = itertools.chain.from_iterable(runs_sequence)
 
-     num_test_failures, resultset = jobset.run(
 
-         all_runs, check_cancelled, newline_on_success=newline_on_success,
 
-         travis=args.travis, infinite_runs=infinite_runs, maxjobs=args.jobs,
 
-         stop_on_failure=args.stop_on_failure,
 
-         add_env={'GRPC_TEST_PORT_SERVER': 'localhost:%d' % port_server_port})
 
-     if resultset:
 
-       for k, v in sorted(resultset.items()):
 
-         num_runs, num_failures = _calculate_num_runs_failures(v)
 
-         if num_failures == num_runs:  # what about infinite_runs???
 
-           jobset.message('FAILED', k, do_newline=True)
 
-         elif num_failures > 0:
 
-           jobset.message(
 
-               'FLAKE', '%s [%d/%d runs flaked]' % (k, num_failures, num_runs),
 
-               do_newline=True)
 
-   finally:
 
-     for antagonist in antagonists:
 
-       antagonist.kill()
 
-     if xml_report and resultset:
 
-       report_utils.render_junit_xml_report(resultset, xml_report,
 
-                                            suite_name=args.report_suite_name)
 
-   number_failures, _ = jobset.run(
 
-       post_tests_steps, maxjobs=1, stop_on_failure=True,
 
-       newline_on_success=newline_on_success, travis=args.travis)
 
-   out = []
 
-   if number_failures:
 
-     out.append(BuildAndRunError.POST_TEST)
 
-   if num_test_failures:
 
-     out.append(BuildAndRunError.TEST)
 
-   return out
 
- if forever:
 
-   success = True
 
-   while True:
 
-     dw = watch_dirs.DirWatcher(['src', 'include', 'test', 'examples'])
 
-     initial_time = dw.most_recent_change()
 
-     have_files_changed = lambda: dw.most_recent_change() != initial_time
 
-     previous_success = success
 
-     errors = _build_and_run(check_cancelled=have_files_changed,
 
-                             newline_on_success=False,
 
-                             build_only=args.build_only) == 0
 
-     if not previous_success and not errors:
 
-       jobset.message('SUCCESS',
 
-                      'All tests are now passing properly',
 
-                      do_newline=True)
 
-     jobset.message('IDLE', 'No change detected')
 
-     while not have_files_changed():
 
-       time.sleep(1)
 
- else:
 
-   errors = _build_and_run(check_cancelled=lambda: False,
 
-                           newline_on_success=args.newline_on_success,
 
-                           xml_report=args.xml_report,
 
-                           build_only=args.build_only)
 
-   if not errors:
 
-     jobset.message('SUCCESS', 'All tests passed', do_newline=True)
 
-   else:
 
-     jobset.message('FAILED', 'Some tests failed', do_newline=True)
 
-   exit_code = 0
 
-   if BuildAndRunError.BUILD in errors:
 
-     exit_code |= 1
 
-   if BuildAndRunError.TEST in errors:
 
-     exit_code |= 2
 
-   if BuildAndRunError.POST_TEST in errors:
 
-     exit_code |= 4
 
-   sys.exit(exit_code)
 
 
  |