Make running individual Python tests less painful

Before this change, running Python tests individually required
building a tox environment via the run_tests script and then specifying
long environment variables to filter out just the test we wanted to run
(and then we wouldn't be able to get the output on interrupt, nor would
we have an easy way of determining the PID of the process for debugger
attachment). Now invoking the build_python.sh script creates a workable
python virtual environment that includes all necessary libraries and
tests (s.t. running a single test is now possible by just knowing the
module name). This does not change existing supported means of running
tests (e.g. through run_tests.py).

An additional way of running individual tests has been introduced.
Following invocation of `./tools/run_tests/build_python.sh` (or
run_tests.py), one may invoke

  ./$VENV/bin/python -m $TEST_MODULE_NAME

and acquire a single running process that *is* the test process (rather
than a parent of the process). $VENV is the virtual environment name
specified to `build_python.sh` (defaults to `py27`) and
$TEST_MODULE_NAME is what it says on the tin.
pull/6791/head
Masood Malekghassemi 9 years ago
parent 1ff429da2a
commit 3b5b20682b
  1. 1
      PYTHON-MANIFEST.in
  2. 71
      tools/run_tests/build_python.sh
  3. 2
      tools/run_tests/performance/run_worker_python.sh
  4. 14
      tools/run_tests/run_interop_tests.py
  5. 17
      tools/run_tests/run_python.sh
  6. 56
      tools/run_tests/run_tests.py

@ -1,6 +1,5 @@
recursive-include src/python/grpcio/grpc *.c *.h *.py *.pyx *.pxd *.pxi *.python *.pem recursive-include src/python/grpcio/grpc *.c *.h *.py *.pyx *.pxd *.pxi *.python *.pem
recursive-exclude src/python/grpcio/grpc/_cython *.so *.pyd recursive-exclude src/python/grpcio/grpc/_cython *.so *.pyd
graft src/python/grpcio/tests
graft src/python/grpcio/grpcio.egg-info graft src/python/grpcio/grpcio.egg-info
graft src/core graft src/core
graft src/boringssl graft src/boringssl

@ -33,25 +33,70 @@ set -ex
# change to grpc repo root # change to grpc repo root
cd $(dirname $0)/../.. cd $(dirname $0)/../..
TOX_PYTHON_ENV="$1" PYTHON=${1:-python2.7}
PY_VERSION="${TOX_PYTHON_ENV: -2}" VENV=${2:-py27}
VENV_RELATIVE_PYTHON=${3:-bin/python}
TOOLCHAIN=${4:-unix}
ROOT=`pwd` ROOT=`pwd`
export CFLAGS="-I$ROOT/include -std=gnu99 -fno-wrapv" export CFLAGS="-I$ROOT/include -std=gnu99 -fno-wrapv"
export GRPC_PYTHON_BUILD_WITH_CYTHON=1 export GRPC_PYTHON_BUILD_WITH_CYTHON=1
if [ "$CONFIG" = "gcov" ] # If ccache is available, use it... unless we're on Mac, then all hell breaks
then # loose because Python does hacky things to support other hacky things done to
# hacky things on Mac OS X
PLATFORM=`uname -s`
if [ "${PLATFORM/Darwin}" = "$PLATFORM" ]; then
# We're not on Darwin (Mac OS X)
if [ -x "$(command -v ccache)" ]; then
if [ -x "$(command -v gcc)" ]; then
export CC='ccache gcc'
elif [ -x "$(command -v clang)" ]; then
export CC='ccache clang'
fi
fi
fi
# Find `realpath`
if [ -x "$(command -v realpath)" ]; then
export REALPATH=realpath
elif [ -x "$(command -v grealpath)" ]; then
export REALPATH=grealpath
else
echo 'Couldn'"'"'t find `realpath` or `grealpath`'
exit 1
fi
if [ "$CONFIG" = "gcov" ]; then
export GRPC_PYTHON_ENABLE_CYTHON_TRACING=1 export GRPC_PYTHON_ENABLE_CYTHON_TRACING=1
fi fi
tox -e ${TOX_PYTHON_ENV} --notest ($PYTHON -m virtualenv $VENV || true)
VENV_PYTHON=`$REALPATH -s "$VENV/$VENV_RELATIVE_PYTHON"`
# pip-installs the directory specified. Used because on MSYS the vanilla Windows
# Python gets confused when parsing paths.
pip_install_dir() {
PWD=`pwd`
cd $1
($VENV_PYTHON setup.py build_ext -c $TOOLCHAIN || true)
# install the dependencies
$VENV_PYTHON -m pip install --upgrade .
# ensure that we've reinstalled the test packages
$VENV_PYTHON -m pip install --upgrade --force-reinstall --no-deps .
cd $PWD
}
$ROOT/.tox/${TOX_PYTHON_ENV}/bin/pip install cython $VENV_PYTHON -m pip install --upgrade pip setuptools
$ROOT/.tox/${TOX_PYTHON_ENV}/bin/pip install $ROOT $VENV_PYTHON -m pip install cython
$ROOT/.tox/${TOX_PYTHON_ENV}/bin/python $ROOT/tools/distrib/python/make_grpcio_tools.py pip_install_dir $ROOT
$ROOT/.tox/${TOX_PYTHON_ENV}/bin/pip install $ROOT/tools/distrib/python/grpcio_tools $VENV_PYTHON $ROOT/tools/distrib/python/make_grpcio_tools.py
$ROOT/.tox/${TOX_PYTHON_ENV}/bin/python $ROOT/src/python/grpcio_health_checking/setup.py preprocess pip_install_dir $ROOT/tools/distrib/python/grpcio_tools
$ROOT/.tox/${TOX_PYTHON_ENV}/bin/pip install $ROOT/src/python/grpcio_health_checking # TODO(atash) figure out namespace packages and grpcio-tools and auditwheel
$ROOT/.tox/${TOX_PYTHON_ENV}/bin/python $ROOT/src/python/grpcio_tests/setup.py preprocess # etc...
$ROOT/.tox/${TOX_PYTHON_ENV}/bin/python $ROOT/src/python/grpcio_tests/setup.py build_proto_modules pip_install_dir $ROOT
$VENV_PYTHON $ROOT/src/python/grpcio_health_checking/setup.py preprocess
pip_install_dir $ROOT/src/python/grpcio_health_checking
$VENV_PYTHON $ROOT/src/python/grpcio_tests/setup.py preprocess
$VENV_PYTHON $ROOT/src/python/grpcio_tests/setup.py build_proto_modules
pip_install_dir $ROOT/src/python/grpcio_tests

@ -32,4 +32,4 @@ set -ex
cd $(dirname $0)/../../.. cd $(dirname $0)/../../..
PYTHONPATH=src/python/grpcio_tests:src/python/grpcio:src/python/gens .tox/py27/bin/python src/python/grpcio_tests/tests/qps/qps_worker.py $@ PYTHONPATH=src/python/grpcio_tests:src/python/grpcio:src/python/gens py27/bin/python src/python/grpcio_tests/tests/qps/qps_worker.py $@

@ -304,8 +304,11 @@ class PythonLanguage:
def client_cmd(self, args): def client_cmd(self, args):
return [ return [
'tox -einterop_client --', 'py27/bin/python',
' '.join(args) 'src/python/grpcio_tests/setup.py',
'run_interop',
'--client',
'--args="{}"'.format(' '.join(args))
] ]
def cloud_to_prod_env(self): def cloud_to_prod_env(self):
@ -313,8 +316,11 @@ class PythonLanguage:
def server_cmd(self, args): def server_cmd(self, args):
return [ return [
'tox -einterop_server --', 'py27/bin/python',
' '.join(args) + ' --use_tls=true' 'src/python/grpcio_tests/setup.py',
'run_interop',
'--server',
'--args="{}"'.format(' '.join(args) + ' --use_tls=true')
] ]
def global_env(self): def global_env(self):

@ -33,24 +33,11 @@ set -ex
# change to grpc repo root # change to grpc repo root
cd $(dirname $0)/../.. cd $(dirname $0)/../..
TOX_PYTHON_ENV="$1" PYTHON=`realpath -s "${1:-py27/bin/python}"`
ROOT=`pwd` ROOT=`pwd`
export LD_LIBRARY_PATH=$ROOT/libs/$CONFIG
export DYLD_LIBRARY_PATH=$ROOT/libs/$CONFIG
export PATH=$ROOT/bins/$CONFIG:$ROOT/bins/$CONFIG/protobuf:$PATH
export CFLAGS="-I$ROOT/include -std=c89"
export LDFLAGS="-L$ROOT/libs/$CONFIG"
export GRPC_PYTHON_BUILD_WITH_CYTHON=1
export GRPC_PYTHON_USE_PRECOMPILED_BINARIES=0
if [ "$CONFIG" = "gcov" ] $PYTHON $ROOT/src/python/grpcio_tests/setup.py test_lite
then
export GRPC_PYTHON_ENABLE_CYTHON_TRACING=1
tox -e ${TOX_PYTHON_ENV}
else
$ROOT/.tox/${TOX_PYTHON_ENV}/bin/python $ROOT/src/python/grpcio_tests/setup.py test_lite
fi
mkdir -p $ROOT/reports mkdir -p $ROOT/reports
rm -rf $ROOT/reports/python-coverage rm -rf $ROOT/reports/python-coverage

@ -32,11 +32,13 @@
import argparse import argparse
import ast import ast
import collections
import glob import glob
import itertools import itertools
import json import json
import multiprocessing import multiprocessing
import os import os
import os.path
import platform import platform
import random import random
import re import re
@ -372,12 +374,20 @@ class PhpLanguage(object):
return 'php' return 'php'
class PythonConfig(collections.namedtuple('PythonConfig', [
'python', 'venv', 'venv_relative_python', 'toolchain',])):
@property
def venv_python(self):
return os.path.abspath('{}/{}'.format(self.venv, self.venv_relative_python))
class PythonLanguage(object): class PythonLanguage(object):
def configure(self, config, args): def configure(self, config, args):
self.config = config self.config = config
self.args = args self.args = args
self._tox_envs = self._get_tox_envs(self.args.compiler) self.pythons = self._get_pythons(self.args.compiler)
def test_specs(self): def test_specs(self):
# load list of known test suites # load list of known test suites
@ -386,33 +396,42 @@ class PythonLanguage(object):
environment = dict(_FORCE_ENVIRON_FOR_WRAPPERS) environment = dict(_FORCE_ENVIRON_FOR_WRAPPERS)
if self.config.build_config != 'gcov': if self.config.build_config != 'gcov':
return [self.config.job_spec( return [self.config.job_spec(
['tools/run_tests/run_python.sh', tox_env], ['tools/run_tests/run_python.sh', config.venv_python],
None,
environ=dict(environment.items() + environ=dict(environment.items() +
[('GRPC_PYTHON_TESTRUNNER_FILTER', suite_name)]), [('GRPC_PYTHON_TESTRUNNER_FILTER', suite_name)]),
shortname='%s.test.%s' % (tox_env, suite_name), shortname='%s.test.%s' % (config.venv, suite_name),
timeout_seconds=5*60) timeout_seconds=5*60)
for suite_name in tests_json for suite_name in tests_json
for tox_env in self._tox_envs] for config in self.pythons]
else: else:
return [self.config.job_spec(['tools/run_tests/run_python.sh', tox_env], return [self.config.job_spec(
['tools/run_tests/run_python.sh', config.venv_python],
None,
environ=environment, environ=environment,
shortname='%s.test.coverage' % tox_env, shortname='%s.test.coverage' % config.venv,
timeout_seconds=15*60) timeout_seconds=15*60)
for tox_env in self._tox_envs] for config in self.pythons]
def pre_build_steps(self): def pre_build_steps(self):
return [] return []
def make_targets(self): def make_targets(self):
return ['static_c', 'grpc_python_plugin', 'shared_c'] return []
def make_options(self): def make_options(self):
return [] return []
def build_steps(self): def build_steps(self):
return [['tools/run_tests/build_python.sh', tox_env] return [
for tox_env in self._tox_envs] [
'tools/run_tests/build_python.sh',
config.python, config.venv,
config.venv_relative_python, config.toolchain
]
for config in self.pythons
]
def post_tests_steps(self): def post_tests_steps(self):
return [] return []
@ -423,14 +442,21 @@ class PythonLanguage(object):
def dockerfile_dir(self): def dockerfile_dir(self):
return 'tools/dockerfile/test/python_jessie_%s' % _docker_arch_suffix(self.args.arch) return 'tools/dockerfile/test/python_jessie_%s' % _docker_arch_suffix(self.args.arch)
def _get_tox_envs(self, compiler): def _get_pythons(self, compiler):
"""Returns name of tox environment based on selected compiler.""" if os.name == 'nt':
venv_relative_python = 'Scripts/python.exe'
toolchain = 'mingw32'
else:
venv_relative_python = 'bin/python'
toolchain = 'unix'
python27_config = PythonConfig('python2.7', 'py27', venv_relative_python, toolchain)
python34_config = PythonConfig('python3.4', 'py34', venv_relative_python, toolchain)
if compiler == 'default': if compiler == 'default':
return ('py27', 'py34') return (python27_config, python34_config,)
elif compiler == 'python2.7': elif compiler == 'python2.7':
return ('py27',) return (python27_config,)
elif compiler == 'python3.4': elif compiler == 'python3.4':
return ('py34',) return (python34_config,)
else: else:
raise Exception('Compiler %s not supported.' % compiler) raise Exception('Compiler %s not supported.' % compiler)

Loading…
Cancel
Save