summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMonty Taylor <mordred@inaugust.com>2012-12-25 00:02:54 -0600
committerClark Boylan <clark.boylan@gmail.com>2013-05-10 15:39:10 -0700
commit11263ac3186e1ccfce0d59592d64b6857673601d (patch)
tree61a38cbdf9b355bf9443d80feea83ab79a5bfb90
parent548b52336f19ea91dde3076ff85dbce9735f5420 (diff)
downloadpython-keystoneclient-11263ac3186e1ccfce0d59592d64b6857673601d.tar.gz
Use testr instead of nose.
Part of blueprint grizzly-testtools Change-Id: I76dee19781eaac21901b5c0258e83a42180c1702
-rw-r--r--.gitignore2
-rw-r--r--.testr.conf4
-rw-r--r--HACKING14
-rw-r--r--keystoneclient/middleware/test.py67
-rwxr-xr-xrun_tests.sh90
-rw-r--r--setup.cfg7
-rw-r--r--setup.py1
-rw-r--r--tests/test_auth_token_middleware.py270
-rw-r--r--tools/test-requires5
-rw-r--r--tox.ini26
10 files changed, 267 insertions, 219 deletions
diff --git a/.gitignore b/.gitignore
index a74a7b3..e51d749 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,6 @@
.coverage
+.testrepository
+subunit.log
.venv
*,cover
cover
diff --git a/.testr.conf b/.testr.conf
new file mode 100644
index 0000000..081907d
--- /dev/null
+++ b/.testr.conf
@@ -0,0 +1,4 @@
+[DEFAULT]
+test_command=${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 bac532f..010be5b 100644
--- a/HACKING
+++ b/HACKING
@@ -81,3 +81,17 @@ Exceptions
When dealing with exceptions from underlying libraries, translate those
exceptions to an instance or subclass of ClientException.
+
+=======
+Testing
+=======
+
+python-keystoneclient uses testtools and testr for its unittest suite
+and its test runner. Basic workflow around our use of tox and testr can
+be found at http://wiki.openstack.org/testr. If you'd like to learn more
+in depth:
+
+ https://testtools.readthedocs.org/
+ https://testrepository.readthedocs.org/
+
+Happy hacking!
diff --git a/keystoneclient/middleware/test.py b/keystoneclient/middleware/test.py
deleted file mode 100644
index 7751141..0000000
--- a/keystoneclient/middleware/test.py
+++ /dev/null
@@ -1,67 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2012 OpenStack LLC
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-#
-# Test support for middleware authentication
-#
-
-import os
-import sys
-
-
-ROOTDIR = os.path.abspath(os.curdir)
-
-
-def rootdir(*p):
- return os.path.join(ROOTDIR, *p)
-
-
-class NoModule(object):
- """A mixin class to provide support for unloading/disabling modules."""
-
- def __init__(self, *args, **kw):
- super(NoModule, self).__init__(*args, **kw)
- self._finders = []
- self._cleared_modules = {}
-
- def tearDown(self):
- super(NoModule, self).tearDown()
- for finder in self._finders:
- sys.meta_path.remove(finder)
- sys.modules.update(self._cleared_modules)
-
- def clear_module(self, module):
- cleared_modules = {}
- for fullname in sys.modules.keys():
- if fullname == module or fullname.startswith(module + '.'):
- cleared_modules[fullname] = sys.modules.pop(fullname)
- return cleared_modules
-
- def disable_module(self, module):
- """Ensure ImportError for the specified module."""
-
- # Clear 'module' references in sys.modules
- self._cleared_modules.update(self.clear_module(module))
-
- # Disallow further imports of 'module'
- class NoModule(object):
- def find_module(self, fullname, path):
- if fullname == module or fullname.startswith(module + '.'):
- raise ImportError
-
- finder = NoModule()
- self._finders.append(finder)
- sys.meta_path.insert(0, finder)
diff --git a/run_tests.sh b/run_tests.sh
index 782c365..12ed568 100755
--- a/run_tests.sh
+++ b/run_tests.sh
@@ -14,6 +14,7 @@ function usage {
echo " -p, --pep8 Just run pep8"
echo " -P, --no-pep8 Don't run pep8"
echo " -c, --coverage Generate coverage report"
+ echo " -d, --debug Run tests with testtools instead of testr. This allows you to use the debugger."
echo " -h, --help Print this usage message"
echo " --hide-elapsed Don't print the elapsed time for each test along with slow test list"
echo ""
@@ -33,8 +34,9 @@ function process_option {
-p|--pep8) just_pep8=1;;
-P|--no-pep8) no_pep8=1;;
-c|--coverage) coverage=1;;
- -*) noseopts="$noseopts $1";;
- *) noseargs="$noseargs $1"
+ -d|--debug) debug=1;;
+ -*) testropts="$testropts $1";;
+ *) testrargs="$testrargs $1"
esac
}
@@ -45,34 +47,86 @@ never_venv=0
force=0
no_site_packages=0
installvenvopts=
-noseargs=
-noseopts=
+testrargs=
+testropts=
wrapper=""
just_pep8=0
no_pep8=0
coverage=0
+debug=0
+
+LANG=en_US.UTF-8
+LANGUAGE=en_US:en
+LC_ALL=C
+OS_STDOUT_NOCAPTURE=False
+OS_STDERR_NOCAPTURE=False
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=keystoneclient"
-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 [ $debug -eq 1 ]; then
+ if [ "$testropts" = "" ] && [ "$testrargs" = "" ]; then
+ # Default to running all tests if specific test is not
+ # provided.
+ testrargs="discover ./tests"
+ fi
+ ${wrapper} python -m testtools.run $testropts $testrargs
+
+ # Short circuit because all of the testr and coverage stuff
+ # below does not make sense when running testtools.run for
+ # debugging purposes.
+ return $?
+ fi
+
+ if [ $coverage -eq 1 ]; then
+ TESTRTESTS="$TESTRTESTS --coverage"
+ else
+ TESTRTESTS="$TESTRTESTS"
+ 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
+ testrargs=`echo "$testrargs" | sed -e's/^\s*\(.*\)\s*$/\1/'`
+ TESTRTESTS="$TESTRTESTS --testr-args='$testropts $testrargs'"
+ echo "Running \`${wrapper} $TESTRTESTS\`"
+ bash -c "${wrapper} $TESTRTESTS"
RESULT=$?
+ set -e
+
+ copy_subunit_log
+
+ if [ $coverage -eq 1 ]; then
+ echo "Generating coverage report in covhtml/"
+ # Don't compute coverage for common code, which is tested elsewhere
+ ${wrapper} coverage combine
+ ${wrapper} coverage html --include='keystoneclient/*' --omit='keystoneclient/openstack/common/*' -d covhtml -i
+ fi
+
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="keystoneclient tests"
@@ -85,7 +139,7 @@ function run_pep8 {
${srcfiles}
}
-NOSETESTS="nosetests $noseopts $noseargs"
+TESTRTESTS="python setup.py testr"
if [ $never_venv -eq 0 ]
then
@@ -123,19 +177,15 @@ 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
+# distinguish between options (testropts), which begin with a '-', and
+# arguments (testrargs).
+if [ -z "$testrargs" ]; then
if [ $no_pep8 -eq 0 ]; then
run_pep8
fi
fi
-
-if [ $coverage -eq 1 ]; then
- echo "Generating coverage report in covhtml/"
- ${wrapper} coverage html -d covhtml -i
-fi
diff --git a/setup.cfg b/setup.cfg
index 3421101..876bc6d 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,10 +1,3 @@
-[nosetests]
-verbosity=2
-detailed-errors=1
-cover-package = keystoneclient
-cover-erase = true
-cover-inclusive = true
-
[build_sphinx]
source-dir = doc/source
build-dir = doc/build
diff --git a/setup.py b/setup.py
index c6a9e6b..8bec3bc 100644
--- a/setup.py
+++ b/setup.py
@@ -37,7 +37,6 @@ setuptools.setup(
cmdclass=setup.get_cmdclass(),
tests_require=tests_require,
- test_suite="nose.collector",
entry_points={
'console_scripts': ['keystone = keystoneclient.shell:main']
diff --git a/tests/test_auth_token_middleware.py b/tests/test_auth_token_middleware.py
index 86d9ee2..5723e15 100644
--- a/tests/test_auth_token_middleware.py
+++ b/tests/test_auth_token_middleware.py
@@ -22,6 +22,7 @@ import sys
import tempfile
import testtools
+import fixtures
import webob
from keystoneclient.common import cms
@@ -31,12 +32,13 @@ from keystoneclient.middleware import memcache_crypt
from keystoneclient.openstack.common import memorycache
from keystoneclient.openstack.common import jsonutils
from keystoneclient.openstack.common import timeutils
-from keystoneclient.middleware import test
-CERTDIR = test.rootdir('examples', 'pki', 'certs')
-KEYDIR = test.rootdir('examples', 'pki', 'private')
-CMSDIR = test.rootdir('examples', 'pki', 'cms')
+ROOTDIR = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
+
+CERTDIR = os.path.join(ROOTDIR, "examples/pki/certs")
+KEYDIR = os.path.join(ROOTDIR, "examples/pki/private")
+CMSDIR = os.path.join(ROOTDIR, "examples/pki/cms")
SIGNING_CERT = os.path.join(CERTDIR, 'signing_cert.pem')
SIGNING_KEY = os.path.join(KEYDIR, 'signing_key.pem')
CA = os.path.join(CERTDIR, 'ca.pem')
@@ -239,95 +241,96 @@ EXPECTED_V2_DEFAULT_ENV_RESPONSE = {
FAKE_RESPONSE_STACK = []
+# @TODO(mordred) This should become a testresources resource attached to the
+# class
# The data for these tests are signed using openssl and are stored in files
# in the signing subdirectory. In order to keep the values consistent between
# the tests and the signed documents, we read them in for use in the tests.
-def setUpModule(self):
- signing_path = CMSDIR
- with open(os.path.join(signing_path, 'auth_token_scoped.pem')) as f:
- self.SIGNED_TOKEN_SCOPED = cms.cms_to_token(f.read())
- with open(os.path.join(signing_path, 'auth_token_unscoped.pem')) as f:
- self.SIGNED_TOKEN_UNSCOPED = cms.cms_to_token(f.read())
- with open(os.path.join(signing_path, 'auth_v3_token_scoped.pem')) as f:
- self.SIGNED_v3_TOKEN_SCOPED = cms.cms_to_token(f.read())
- with open(os.path.join(signing_path, 'auth_token_revoked.pem')) as f:
- self.REVOKED_TOKEN = cms.cms_to_token(f.read())
- self.REVOKED_TOKEN_HASH = utils.hash_signed_token(self.REVOKED_TOKEN)
- with open(os.path.join(signing_path, 'auth_v3_token_revoked.pem')) as f:
- self.REVOKED_v3_TOKEN = cms.cms_to_token(f.read())
- self.REVOKED_v3_TOKEN_HASH = utils.hash_signed_token(self.REVOKED_v3_TOKEN)
- with open(os.path.join(signing_path, 'revocation_list.json')) as f:
- self.REVOCATION_LIST = jsonutils.loads(f.read())
- with open(os.path.join(signing_path, 'revocation_list.pem')) as f:
- self.VALID_SIGNED_REVOCATION_LIST = jsonutils.dumps(
- {'signed': f.read()})
- self.SIGNED_TOKEN_SCOPED_KEY = (
- cms.cms_hash_token(self.SIGNED_TOKEN_SCOPED))
- self.SIGNED_TOKEN_UNSCOPED_KEY = (
- cms.cms_hash_token(self.SIGNED_TOKEN_UNSCOPED))
- self.SIGNED_v3_TOKEN_SCOPED_KEY = (
- cms.cms_hash_token(self.SIGNED_v3_TOKEN_SCOPED))
-
- self.TOKEN_RESPONSES[self.SIGNED_TOKEN_SCOPED_KEY] = {
- 'access': {
- 'token': {
- 'id': self.SIGNED_TOKEN_SCOPED_KEY,
- },
- 'user': {
- 'id': 'user_id1',
- 'name': 'user_name1',
- 'tenantId': 'tenant_id1',
- 'tenantName': 'tenant_name1',
- 'roles': [
- {'name': 'role1'},
- {'name': 'role2'},
- ],
- },
+signing_path = CMSDIR
+with open(os.path.join(signing_path, 'auth_token_scoped.pem')) as f:
+ SIGNED_TOKEN_SCOPED = cms.cms_to_token(f.read())
+with open(os.path.join(signing_path, 'auth_token_unscoped.pem')) as f:
+ SIGNED_TOKEN_UNSCOPED = cms.cms_to_token(f.read())
+with open(os.path.join(signing_path, 'auth_v3_token_scoped.pem')) as f:
+ SIGNED_v3_TOKEN_SCOPED = cms.cms_to_token(f.read())
+with open(os.path.join(signing_path, 'auth_token_revoked.pem')) as f:
+ REVOKED_TOKEN = cms.cms_to_token(f.read())
+REVOKED_TOKEN_HASH = utils.hash_signed_token(REVOKED_TOKEN)
+with open(os.path.join(signing_path, 'auth_v3_token_revoked.pem')) as f:
+ REVOKED_v3_TOKEN = cms.cms_to_token(f.read())
+REVOKED_v3_TOKEN_HASH = utils.hash_signed_token(REVOKED_v3_TOKEN)
+with open(os.path.join(signing_path, 'revocation_list.json')) as f:
+ REVOCATION_LIST = jsonutils.loads(f.read())
+with open(os.path.join(signing_path, 'revocation_list.pem')) as f:
+ VALID_SIGNED_REVOCATION_LIST = jsonutils.dumps(
+ {'signed': f.read()})
+SIGNED_TOKEN_SCOPED_KEY =\
+ cms.cms_hash_token(SIGNED_TOKEN_SCOPED)
+SIGNED_TOKEN_UNSCOPED_KEY =\
+ cms.cms_hash_token(SIGNED_TOKEN_UNSCOPED)
+SIGNED_v3_TOKEN_SCOPED_KEY = (
+ cms.cms_hash_token(SIGNED_v3_TOKEN_SCOPED))
+
+TOKEN_RESPONSES[SIGNED_TOKEN_SCOPED_KEY] = {
+ 'access': {
+ 'token': {
+ 'id': SIGNED_TOKEN_SCOPED_KEY,
},
- }
-
- self.TOKEN_RESPONSES[SIGNED_TOKEN_UNSCOPED_KEY] = {
- 'access': {
- 'token': {
- 'id': SIGNED_TOKEN_UNSCOPED_KEY,
- },
- 'user': {
- 'id': 'user_id1',
- 'name': 'user_name1',
- 'roles': [
- {'name': 'role1'},
- {'name': 'role2'},
- ],
- },
+ 'user': {
+ 'id': 'user_id1',
+ 'name': 'user_name1',
+ 'tenantId': 'tenant_id1',
+ 'tenantName': 'tenant_name1',
+ 'roles': [
+ {'name': 'role1'},
+ {'name': 'role2'},
+ ],
},
},
+}
- self.TOKEN_RESPONSES[self.SIGNED_v3_TOKEN_SCOPED_KEY] = {
+TOKEN_RESPONSES[SIGNED_TOKEN_UNSCOPED_KEY] = {
+ 'access': {
'token': {
- 'expires': '2020-01-01T00:00:10.000123Z',
- 'user': {
- 'id': 'user_id1',
- 'name': 'user_name1',
- 'domain': {
- 'id': 'domain_id1',
- 'name': 'domain_name1'
- }
- },
- 'project': {
- 'id': 'tenant_id1',
- 'name': 'tenant_name1',
- 'domain': {
- 'id': 'domain_id1',
- 'name': 'domain_name1'
- }
- },
+ 'id': SIGNED_TOKEN_UNSCOPED_KEY,
+ },
+ 'user': {
+ 'id': 'user_id1',
+ 'name': 'user_name1',
'roles': [
- {'name': 'role1'},
- {'name': 'role2'}
+ {'name': 'role1'},
+ {'name': 'role2'},
],
- 'catalog': {}
- }
+ },
+ },
+}
+
+TOKEN_RESPONSES[SIGNED_v3_TOKEN_SCOPED_KEY] = {
+ 'token': {
+ 'expires': '2020-01-01T00:00:10.000123Z',
+ 'user': {
+ 'id': 'user_id1',
+ 'name': 'user_name1',
+ 'domain': {
+ 'id': 'domain_id1',
+ 'name': 'domain_name1'
+ }
+ },
+ 'project': {
+ 'id': 'tenant_id1',
+ 'name': 'tenant_name1',
+ 'domain': {
+ 'id': 'domain_id1',
+ 'name': 'domain_name1'
+ }
+ },
+ 'roles': [
+ {'name': 'role1'},
+ {'name': 'role2'}
+ ],
+ 'catalog': {}
}
+}
VERSION_LIST_v3 = {
"versions": {
@@ -362,6 +365,53 @@ VERSION_LIST_v2 = {
}
+class NoModuleFinder(object):
+ """ Disallow further imports of 'module' """
+
+ def __init__(self, module):
+ self.module = module
+
+ def find_module(self, fullname, path):
+ if fullname == self.module or fullname.startswith(self.module + '.'):
+ raise ImportError
+
+
+class DisableModuleFixture(fixtures.Fixture):
+ """A fixture to provide support for unloading/disabling modules."""
+
+ def __init__(self, module, *args, **kw):
+ super(DisableModuleFixture, self).__init__(*args, **kw)
+ self.module = module
+ self._finders = []
+ self._cleared_modules = {}
+
+ def tearDown(self):
+ super(DisableModuleFixture, self).tearDown()
+ for finder in self._finders:
+ sys.meta_path.remove(finder)
+ sys.modules.update(self._cleared_modules)
+
+ def clear_module(self):
+ cleared_modules = {}
+ for fullname in sys.modules.keys():
+ if (fullname == self.module or
+ fullname.startswith(self.module + '.')):
+ cleared_modules[fullname] = sys.modules.pop(fullname)
+ return cleared_modules
+
+ def setUp(self):
+ """Ensure ImportError for the specified module."""
+
+ super(DisableModuleFixture, self).setUp()
+
+ # Clear 'module' references in sys.modules
+ self._cleared_modules.update(self.clear_module())
+
+ finder = NoModuleFinder(self.module)
+ self._finders.append(finder)
+ sys.meta_path.insert(0, finder)
+
+
class FakeSwiftMemcacheRing(memorycache.Client):
# NOTE(vish): swift memcache uses param timeout instead of time
def set(self, key, value, timeout=0, min_compress_len=0):
@@ -741,7 +791,36 @@ class DiabloAuthTokenMiddlewareTest(BaseAuthTokenMiddlewareTest):
self.assertTrue('keystone.token_info' in req.environ)
-class AuthTokenMiddlewareTest(test.NoModule, BaseAuthTokenMiddlewareTest):
+class NoMemcacheAuthToken(BaseAuthTokenMiddlewareTest):
+
+ def setUp(self):
+ super(NoMemcacheAuthToken, self).setUp()
+ self.useFixture(DisableModuleFixture('memcache'))
+
+ def test_nomemcache(self):
+ conf = {
+ 'admin_token': 'admin_token1',
+ 'auth_host': 'keystone.example.com',
+ 'auth_port': 1234,
+ 'memcache_servers': 'localhost:11211',
+ }
+
+ auth_token.AuthProtocol(FakeApp(), conf)
+
+ def test_not_use_cache_from_env(self):
+ env = {'swift.cache': 'CACHE_TEST'}
+ conf = {
+ 'auth_host': 'keystone.example.com',
+ 'auth_port': 1234,
+ 'auth_admin_prefix': '/testadmin',
+ 'memcache_servers': 'localhost:11211'
+ }
+ self.set_middleware(conf=conf)
+ self.middleware._init_cache(env)
+ self.assertNotEqual(self.middleware._cache, 'CACHE_TEST')
+
+
+class AuthTokenMiddlewareTest(BaseAuthTokenMiddlewareTest):
def test_init_does_not_call_http(self):
conf = {
@@ -975,17 +1054,6 @@ class AuthTokenMiddlewareTest(test.NoModule, BaseAuthTokenMiddlewareTest):
self.middleware._cache_initialized = True
self.test_memcache_set_expired()
- def test_nomemcache(self):
- self.disable_module('memcache')
-
- conf = {
- 'auth_host': 'keystone.example.com',
- 'auth_port': 1234,
- 'auth_admin_prefix': '/testadmin',
- 'memcache_servers': 'localhost:11211'
- }
- self.set_middleware(conf=conf)
-
def test_use_cache_from_env(self):
env = {'swift.cache': 'CACHE_TEST'}
conf = {
@@ -999,18 +1067,6 @@ class AuthTokenMiddlewareTest(test.NoModule, BaseAuthTokenMiddlewareTest):
self.middleware._init_cache(env)
self.assertEqual(self.middleware._cache, 'CACHE_TEST')
- def test_not_use_cache_from_env(self):
- env = {'swift.cache': 'CACHE_TEST'}
- conf = {
- 'auth_host': 'keystone.example.com',
- 'auth_port': 1234,
- 'auth_admin_prefix': '/testadmin',
- 'memcache_servers': 'localhost:11211'
- }
- self.set_middleware(conf=conf)
- self.middleware._init_cache(env)
- self.assertNotEqual(self.middleware._cache, 'CACHE_TEST')
-
def test_will_expire_soon(self):
tenseconds = datetime.datetime.utcnow() + datetime.timedelta(
seconds=10)
@@ -1176,7 +1232,7 @@ class AuthTokenMiddlewareTest(test.NoModule, BaseAuthTokenMiddlewareTest):
datetime.timedelta(seconds=24))
-class v2AuthTokenMiddlewareTest(test.NoModule, BaseAuthTokenMiddlewareTest):
+class v2AuthTokenMiddlewareTest(BaseAuthTokenMiddlewareTest):
""" v2 token specific tests.
There are some differences between how the auth-token middleware handles
diff --git a/tools/test-requires b/tools/test-requires
index d0abb32..41348f1 100644
--- a/tools/test-requires
+++ b/tools/test-requires
@@ -5,13 +5,10 @@ fixtures
keyring
mock
mox
-nose
-nose-exclude
-openstack.nose_plugin
-nosehtmloutput
pep8==1.3.3
pycrypto
sphinx>=1.1.2
+testrepository>=0.0.13
testtools>=0.9.22
WebOb>=1.0.8
diff --git a/tox.ini b/tox.ini
index 6533a18..915cab2 100644
--- a/tox.ini
+++ b/tox.ini
@@ -3,24 +3,24 @@ 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
- NOSE_OPENSTACK_STDOUT=1
+ LANG=en_US.UTF-8
+ LANGUAGE=en_US:en
+ LC_ALL=C
+ OS_STDOUT_NOCAPTURE=False
+ OS_STDERR_NOCAPTURE=False
+
deps = -r{toxinidir}/tools/pip-requires
-r{toxinidir}/tools/test-requires
-commands = nosetests {posargs}
-
-[tox:jenkins]
-downloadcache = ~/cache/pip
+commands = python setup.py testr --testr-args='{posargs}'
[testenv:pep8]
commands = pep8 --repeat --show-source --ignore=E711,E712,E125,E126 --exclude=.venv,.tox,dist,doc .
-[testenv:cover]
-setenv = NOSE_WITH_COVERAGE=1
-
[testenv:venv]
commands = {posargs}
+
+[testenv:cover]
+commands = python setup.py testr --coverage --testr-args='{posargs}'
+
+[tox:jenkins]
+downloadcache = ~/cache/pip