From 63c8bb5306d15c7679b2cd1d22b6ee556967863d Mon Sep 17 00:00:00 2001 From: Josh Kearney Date: Tue, 22 Jan 2013 11:09:11 -0600 Subject: [PATCH] Migrate from nose to testr. Run tests with testr for parallel execution. Part of blueprint grizzly-testtools. Change-Id: I560592186f2f440049a451a32e58067262ab62d0 --- .gitignore | 1 + .testr.conf | 4 +++ HACKING | 8 ++++++ run_tests.sh | 60 +++++++++++++++++++++++++++++++++------------ setup.cfg | 8 ------ setup.py | 1 - tests/utils.py | 17 +++++++------ tools/test-requires | 11 ++++----- tox.ini | 32 ++++-------------------- 9 files changed, 78 insertions(+), 64 deletions(-) create mode 100644 .testr.conf diff --git a/.gitignore b/.gitignore index e038b53ce1..8b413ce11d 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ *.swp *~ .openstackclient-venv +.testrepository .tox .venv AUTHORS diff --git a/.testr.conf b/.testr.conf new file mode 100644 index 0000000000..2109af6ce0 --- /dev/null +++ b/.testr.conf @@ -0,0 +1,4 @@ +[DEFAULT] +test_command=OS_STDOUT_CAPTURE=1 OS_STDERR_CAPTURE=1 ${PYTHON:-python} -m subunit.run discover -t ./ ./tests $LISTOPT $IDOPTION +test_id_option=--load-list $IDFILE +test_list_option=--list diff --git a/HACKING b/HACKING index 1218e5f712..e9bcb7eaf4 100644 --- a/HACKING +++ b/HACKING @@ -112,3 +112,11 @@ Text encoding returntext = do_some_magic_with(mytext) returnstring = returntext.encode('utf-8') outfile.write(returnstring) + +Running Tests +------------- +The testing system is based on a combination of tox and testr. If you just +want to run the whole suite, run `tox` and all will be fine. However, if +you'd like to dig in a bit more, you might want to learn some things about +testr itself. A basic walkthrough for OpenStack can be found at +http://wiki.openstack.org/testr diff --git a/run_tests.sh b/run_tests.sh index 4700c1164a..ff5f83ec4e 100755 --- a/run_tests.sh +++ b/run_tests.sh @@ -33,8 +33,8 @@ function process_option { -p|--pep8) just_pep8=1;; -P|--no-pep8) no_pep8=1;; -c|--coverage) coverage=1;; - -*) noseopts="$noseopts $1";; - *) noseargs="$noseargs $1" + -*) testropts="$testropts $1";; + *) testrargs="$testrargs $1" esac } @@ -45,34 +45,62 @@ never_venv=0 force=0 no_site_packages=0 installvenvopts= -noseargs= -noseopts= +testrargs= +testropts= wrapper="" just_pep8=0 no_pep8=0 coverage=0 +LANG=en_US.UTF-8 +LANGUAGE=en_US:en +LC_ALL=C + for arg in "$@"; do process_option $arg done -# If enabled, tell nose to collect coverage data -if [ $coverage -eq 1 ]; then - noseopts="$noseopts --with-coverage --cover-package=openstackclient" -fi - if [ $no_site_packages -eq 1 ]; then installvenvopts="--no-site-packages" fi +function init_testr { + if [ ! -d .testrepository ]; then + ${wrapper} testr init + fi +} + function run_tests { + # Cleanup *.pyc + ${wrapper} find . -type f -name "*.pyc" -delete + + if [ $coverage -eq 1 ]; then + # Do not test test_coverage_ext when gathering coverage. + if [ "x$testrargs" = "x" ]; then + testrargs = "^(?!.*test_coverage_ext).*$" + fi + export PYTHON="${wrapper} coverage run --source novaclient --parallel-mode" + fi # Just run the test suites in current environment - ${wrapper} $NOSETESTS - # If we get some short import error right away, print the error log directly + set +e + TESTRTESTS="$TESTRTESTS $testrargs" + echo "Running \`${wrapper} $TESTRTESTS\`" + ${wrapper} $TESTRTESTS RESULT=$? + set -e + + copy_subunit_log + return $RESULT } +function copy_subunit_log { + LOGNAME=`cat .testrepository/next-stream` + LOGNAME=$(($LOGNAME - 1)) + LOGNAME=".testrepository/${LOGNAME}" + cp $LOGNAME subunit.log +} + function run_pep8 { echo "Running pep8 ..." srcfiles="openstackclient tests" @@ -96,7 +124,7 @@ function run_pep8 { ${wrapper} pep8 ${pep8_opts} ${srcfiles} } -NOSETESTS="nosetests $noseopts $noseargs" +TESTRTESTS="testr run --parallel $testropts" if [ $never_venv -eq 0 ] then @@ -134,13 +162,14 @@ if [ $just_pep8 -eq 1 ]; then exit fi +init_testr run_tests # NOTE(sirp): we only want to run pep8 when we're running the full-test suite, # not when we're running tests individually. To handle this, we need to # distinguish between options (noseopts), which begin with a '-', and -# arguments (noseargs). -if [ -z "$noseargs" ]; then +# arguments (testrargs). +if [ -z "$testrargs" ]; then if [ $no_pep8 -eq 0 ]; then run_pep8 fi @@ -148,5 +177,6 @@ fi if [ $coverage -eq 1 ]; then echo "Generating coverage report in covhtml/" - ${wrapper} coverage html -d covhtml -i + ${wrapper} cverage combine + ${wrapper} coverage html --include='novaclient/*' --omit='novaclient/openstack/common/*' -d covhtml -i fi diff --git a/setup.cfg b/setup.cfg index 27d2986511..11c72013c2 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,11 +1,3 @@ -[nosetests] -cover-package = openstackclient -cover-html = true -cover-erase = true -cover-inclusive = true -verbosity=2 -detailed-errors=1 - [build_sphinx] source-dir = doc/source build-dir = doc/build diff --git a/setup.py b/setup.py index df9fefffe7..fe0c2ebdb8 100644 --- a/setup.py +++ b/setup.py @@ -52,7 +52,6 @@ setuptools.setup( install_requires=requires, dependency_links=dependency_links, cmdclass=setup.get_cmdclass(), - test_suite="nose.collector", entry_points={ 'console_scripts': ['openstack=openstackclient.shell:main'], 'openstack.cli': [ diff --git a/tests/utils.py b/tests/utils.py index 633442c92f..9027472578 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -1,17 +1,20 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -import time +import os +import fixtures import testtools class TestCase(testtools.TestCase): - def setUp(self): super(TestCase, self).setUp() - self._original_time = time.time - time.time = lambda: 1234 + if (os.environ.get("OS_STDOUT_NOCAPTURE") == "True" and + os.environ.get("OS_STDOUT_NOCAPTURE") == "1"): + stdout = self.useFixture(fixtures.StringStream("stdout")).stream + self.useFixture(fixtures.MonkeyPatch("sys.stdout", stdout)) + if (os.environ.get("OS_STDERR_NOCAPTURE") == "True" and + os.environ.get("OS_STDERR_NOCAPTURE") == "1"): + stderr = self.useFixture(fixtures.StringStream("stderr")).stream + self.useFixture(fixtures.MonkeyPatch("sys.stderr", stderr)) def tearDown(self): - time.time = self._original_time super(TestCase, self).tearDown() diff --git a/tools/test-requires b/tools/test-requires index d96d52b60d..7fb687d25c 100644 --- a/tools/test-requires +++ b/tools/test-requires @@ -1,12 +1,11 @@ distribute>=0.6.24 -fixtures +coverage +discover +fixtures>=0.3.12 mock -nose -nose-exclude -nosexcover -nosehtmloutput openstack.nose_plugin pep8==1.1 sphinx>=1.1.2 -testtools>=0.9.22 +testrepository>=0.0.13 +testtools>=0.9.26 diff --git a/tox.ini b/tox.ini index f562534181..6b4a96dbdb 100644 --- a/tox.ini +++ b/tox.ini @@ -3,14 +3,12 @@ envlist = py26,py27,pep8 [testenv] setenv = VIRTUAL_ENV={envdir} - NOSE_WITH_OPENSTACK=1 - NOSE_OPENSTACK_COLOR=1 - NOSE_OPENSTACK_RED=0.05 - NOSE_OPENSTACK_YELLOW=0.025 - NOSE_OPENSTACK_SHOW_ELAPSED=1 + LANG=en_US.UTF-8 + LANGUAGE=en_US:en + LC_ALL=C deps = -r{toxinidir}/tools/pip-requires -r{toxinidir}/tools/test-requires -commands = nosetests +commands = python setup.py testr --testr-args='{posargs}' [testenv:pep8] deps = pep8==1.1 @@ -20,27 +18,7 @@ commands = pep8 --repeat --show-source openstackclient setup.py commands = {posargs} [testenv:cover] -commands = nosetests --cover-erase --cover-package=openstackclient --with-xcoverage +commands = python setup.py testr --coverage --testr-args='{posargs}' [tox:jenkins] downloadcache = ~/cache/pip - -[testenv:jenkins26] -basepython = python2.6 -setenv = NOSE_WITH_XUNIT=1 -deps = file://{toxinidir}/.cache.bundle - -[testenv:jenkins27] -basepython = python2.7 -setenv = NOSE_WITH_XUNIT=1 -deps = file://{toxinidir}/.cache.bundle - -[testenv:jenkinscover] -deps = file://{toxinidir}/.cache.bundle -setenv = NOSE_WITH_XUNIT=1 -commands = nosetests --cover-erase --cover-package=openstackclient --with-xcoverage - -[testenv:jenkinsvenv] -deps = file://{toxinidir}/.cache.bundle -setenv = NOSE_WITH_XUNIT=1 -commands = {posargs}