summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.coveragerc6
-rw-r--r--.gitignore2
-rw-r--r--keystone/common/sql/util.py5
-rw-r--r--keystone/test.py7
-rw-r--r--run_tests.py367
-rwxr-xr-xrun_tests.sh6
-rw-r--r--setup.cfg1
-rw-r--r--tests/test_backend_sql.py12
-rw-r--r--tests/test_import_legacy.py4
-rw-r--r--tests/test_keystoneclient_sql.py4
-rw-r--r--tests/test_migrate_nova_auth.py4
-rw-r--r--tox.ini4
12 files changed, 51 insertions, 371 deletions
diff --git a/.coveragerc b/.coveragerc
new file mode 100644
index 00000000..41845590
--- /dev/null
+++ b/.coveragerc
@@ -0,0 +1,6 @@
+[run]
+branch = True
+omit = /usr*,setup.py,*egg*,.venv/*,.tox/*,tests/*
+
+[report]
+ignore-errors = True
diff --git a/.gitignore b/.gitignore
index 1e51ffcf..1cf971c7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,6 +7,8 @@ vendor
keystone.egg-info/
*.log
.coverage
+coverage.xml
+cover/*
covhtml
pep8.txt
nosetests.xml
diff --git a/keystone/common/sql/util.py b/keystone/common/sql/util.py
index 195adc83..65e87bec 100644
--- a/keystone/common/sql/util.py
+++ b/keystone/common/sql/util.py
@@ -35,3 +35,8 @@ def setup_test_database():
shutil.copyfile('test.db.pristine', 'test.db')
except Exception:
pass
+
+
+def teardown_test_database():
+ if os.path.exists('test.db.pristine'):
+ os.unlink('test.db.pristine')
diff --git a/keystone/test.py b/keystone/test.py
index 44857d7e..519008dc 100644
--- a/keystone/test.py
+++ b/keystone/test.py
@@ -19,6 +19,7 @@ import subprocess
import sys
import time
+import eventlet
import mox
from paste import deploy
import stubout
@@ -32,8 +33,12 @@ from keystone import config
from keystone.openstack.common import importutils
+do_monkeypatch = not os.getenv('STANDARD_THREADS')
+eventlet.patcher.monkey_patch(all=False, socket=True, time=True,
+ thread=do_monkeypatch)
+
LOG = logging.getLogger(__name__)
-ROOTDIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+ROOTDIR = os.path.dirname(os.path.abspath(os.curdir))
VENDOR = os.path.join(ROOTDIR, 'vendor')
TESTSDIR = os.path.join(ROOTDIR, 'tests')
ETCDIR = os.path.join(ROOTDIR, 'etc')
diff --git a/run_tests.py b/run_tests.py
deleted file mode 100644
index 429eb30e..00000000
--- a/run_tests.py
+++ /dev/null
@@ -1,367 +0,0 @@
-#!/usr/bin/env python
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2012 OpenStack LLC
-# Copyright 2010 United States Government as represented by the
-# Administrator of the National Aeronautics and Space Administration.
-# All Rights Reserved.
-#
-# 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.
-
-# Colorizer Code is borrowed from Twisted:
-# Copyright (c) 2001-2010 Twisted Matrix Laboratories.
-#
-# Permission is hereby granted, free of charge, to any person obtaining
-# a copy of this software and associated documentation files (the
-# "Software"), to deal in the Software without restriction, including
-# without limitation the rights to use, copy, modify, merge, publish,
-# distribute, sublicense, and/or sell copies of the Software, and to
-# permit persons to whom the Software is furnished to do so, subject to
-# the following conditions:
-#
-# The above copyright notice and this permission notice shall be
-# included in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-"""Unittest runner for Nova.
-
-To run all tests
- python run_tests.py
-
-To run a single test:
- python run_tests.py test_compute:ComputeTestCase.test_run_terminate
-
-To run a single test module:
- python run_tests.py test_compute
-
- or
-
- python run_tests.py api.test_wsgi
-
-"""
-import eventlet
-import heapq
-import os
-import unittest
-import sys
-import time
-
-from nose import config
-from nose import core
-from nose import result
-
-
-class _AnsiColorizer(object):
- """
- A colorizer is an object that loosely wraps around a stream, allowing
- callers to write text to the stream in a particular color.
-
- Colorizer classes must implement C{supported()} and C{write(text, color)}.
- """
- _colors = dict(black=30, red=31, green=32, yellow=33,
- blue=34, magenta=35, cyan=36, white=37)
-
- def __init__(self, stream):
- self.stream = stream
-
- def supported(cls, stream=sys.stdout):
- """
- A class method that returns True if the current platform supports
- coloring terminal output using this method. Returns False otherwise.
- """
- if not stream.isatty():
- return False # auto color only on TTYs
- try:
- import curses
- except ImportError:
- return False
- else:
- try:
- try:
- return curses.tigetnum("colors") > 2
- except curses.error:
- curses.setupterm()
- return curses.tigetnum("colors") > 2
- except:
- raise
- # guess false in case of error
- return False
- supported = classmethod(supported)
-
- def write(self, text, color):
- """
- Write the given text to the stream in the given color.
-
- @param text: Text to be written to the stream.
-
- @param color: A string label for a color. e.g. 'red', 'white'.
- """
- color = self._colors[color]
- self.stream.write('\x1b[%s;1m%s\x1b[0m' % (color, text))
-
-
-class _Win32Colorizer(object):
- """
- See _AnsiColorizer docstring.
- """
- def __init__(self, stream):
- from win32console import (GetStdHandle, STD_OUT_HANDLE,
- FOREGROUND_RED, FOREGROUND_GREEN,
- FOREGROUND_BLUE, FOREGROUND_INTENSITY)
- red, green, blue, bold = (FOREGROUND_RED, FOREGROUND_GREEN,
- FOREGROUND_BLUE, FOREGROUND_INTENSITY)
- self.stream = stream
- self.screenBuffer = GetStdHandle(STD_OUT_HANDLE)
- self._colors = {
- 'normal': red | green | blue,
- 'red': red | bold,
- 'green': green | bold,
- 'blue': blue | bold,
- 'yellow': red | green | bold,
- 'magenta': red | blue | bold,
- 'cyan': green | blue | bold,
- 'white': red | green | blue | bold
- }
-
- def supported(cls, stream=sys.stdout):
- try:
- import win32console
- screenBuffer = win32console.GetStdHandle(
- win32console.STD_OUT_HANDLE)
- except ImportError:
- return False
- import pywintypes
- try:
- screenBuffer.SetConsoleTextAttribute(
- win32console.FOREGROUND_RED |
- win32console.FOREGROUND_GREEN |
- win32console.FOREGROUND_BLUE)
- except pywintypes.error:
- return False
- else:
- return True
- supported = classmethod(supported)
-
- def write(self, text, color):
- color = self._colors[color]
- self.screenBuffer.SetConsoleTextAttribute(color)
- self.stream.write(text)
- self.screenBuffer.SetConsoleTextAttribute(self._colors['normal'])
-
-
-class _NullColorizer(object):
- """
- See _AnsiColorizer docstring.
- """
- def __init__(self, stream):
- self.stream = stream
-
- def supported(cls, stream=sys.stdout):
- return True
- supported = classmethod(supported)
-
- def write(self, text, color):
- self.stream.write(text)
-
-
-def get_elapsed_time_color(elapsed_time):
- if elapsed_time > 1.0:
- return 'red'
- elif elapsed_time > 0.25:
- return 'yellow'
- else:
- return 'green'
-
-
-class NovaTestResult(result.TextTestResult):
- def __init__(self, *args, **kw):
- self.show_elapsed = kw.pop('show_elapsed')
- result.TextTestResult.__init__(self, *args, **kw)
- self.num_slow_tests = 5
- self.slow_tests = [] # this is a fixed-sized heap
- self._last_case = None
- self.colorizer = None
- # NOTE(vish): reset stdout for the terminal check
- stdout = sys.stdout
- sys.stdout = sys.__stdout__
- for colorizer in [_Win32Colorizer, _AnsiColorizer, _NullColorizer]:
- if colorizer.supported():
- self.colorizer = colorizer(self.stream)
- break
- sys.stdout = stdout
-
- # NOTE(lorinh): Initialize start_time in case a sqlalchemy-migrate
- # error results in it failing to be initialized later. Otherwise,
- # _handleElapsedTime will fail, causing the wrong error message to
- # be outputted.
- self.start_time = time.time()
-
- def getDescription(self, test):
- return str(test)
-
- def _handleElapsedTime(self, test):
- self.elapsed_time = time.time() - self.start_time
- item = (self.elapsed_time, test)
- # Record only the n-slowest tests using heap
- if len(self.slow_tests) >= self.num_slow_tests:
- heapq.heappushpop(self.slow_tests, item)
- else:
- heapq.heappush(self.slow_tests, item)
-
- def _writeElapsedTime(self, test):
- color = get_elapsed_time_color(self.elapsed_time)
- self.colorizer.write(" %.2f" % self.elapsed_time, color)
-
- def _writeResult(self, test, long_result, color, short_result, success):
- if self.showAll:
- self.colorizer.write(long_result, color)
- if self.show_elapsed and success:
- self._writeElapsedTime(test)
- self.stream.writeln()
- elif self.dots:
- self.stream.write(short_result)
- self.stream.flush()
-
- # NOTE(vish): copied from unittest with edit to add color
- def addSuccess(self, test):
- unittest.TestResult.addSuccess(self, test)
- self._handleElapsedTime(test)
- self._writeResult(test, 'OK', 'green', '.', True)
-
- # NOTE(vish): copied from unittest with edit to add color
- def addFailure(self, test, err):
- unittest.TestResult.addFailure(self, test, err)
- self._handleElapsedTime(test)
- self._writeResult(test, 'FAIL', 'red', 'F', False)
-
- # NOTE(vish): copied from nose with edit to add color
- def addError(self, test, err):
- """Overrides normal addError to add support for
- errorClasses. If the exception is a registered class, the
- error will be added to the list for that class, not errors.
- """
- self._handleElapsedTime(test)
- stream = getattr(self, 'stream', None)
- ec, ev, tb = err
- try:
- exc_info = self._exc_info_to_string(err, test)
- except TypeError:
- # 2.3 compat
- exc_info = self._exc_info_to_string(err)
- for cls, (storage, label, isfail) in self.errorClasses.items():
- if result.isclass(ec) and issubclass(ec, cls):
- if isfail:
- test.passed = False
- storage.append((test, exc_info))
- # Might get patched into a streamless result
- if stream is not None:
- if self.showAll:
- message = [label]
- detail = result._exception_detail(err[1])
- if detail:
- message.append(detail)
- stream.writeln(": ".join(message))
- elif self.dots:
- stream.write(label[:1])
- return
- self.errors.append((test, exc_info))
- test.passed = False
- if stream is not None:
- self._writeResult(test, 'ERROR', 'red', 'E', False)
-
- def startTest(self, test):
- unittest.TestResult.startTest(self, test)
- self.start_time = time.time()
- current_case = test.test.__class__.__name__
-
- if self.showAll:
- if current_case != self._last_case:
- self.stream.writeln(current_case)
- self._last_case = current_case
-
- self.stream.write(
- ' %s' % str(test.test._testMethodName).ljust(60))
- self.stream.flush()
-
-
-class NovaTestRunner(core.TextTestRunner):
- def __init__(self, *args, **kwargs):
- self.show_elapsed = kwargs.pop('show_elapsed')
- core.TextTestRunner.__init__(self, *args, **kwargs)
-
- def _makeResult(self):
- return NovaTestResult(self.stream,
- self.descriptions,
- self.verbosity,
- self.config,
- show_elapsed=self.show_elapsed)
-
- def _writeSlowTests(self, result_):
- # Pare out 'fast' tests
- slow_tests = [item for item in result_.slow_tests
- if get_elapsed_time_color(item[0]) != 'green']
- if slow_tests:
- slow_total_time = sum(item[0] for item in slow_tests)
- self.stream.writeln("Slowest %i tests took %.2f secs:"
- % (len(slow_tests), slow_total_time))
- for elapsed_time, test in sorted(slow_tests, reverse=True):
- time_str = "%.2f" % elapsed_time
- self.stream.writeln(" %s %s" % (time_str.ljust(10), test))
-
- def run(self, test):
- result_ = core.TextTestRunner.run(self, test)
- if self.show_elapsed:
- self._writeSlowTests(result_)
- return result_
-
-
-if __name__ == '__main__':
- # If any argument looks like a test name but doesn't have "nova.tests" in
- # front of it, automatically add that so we don't have to type as much
- show_elapsed = True
- do_monkeypatch = True
- argv = []
- for x in sys.argv:
- if x.startswith('test_'):
- pass
- #argv.append('tests.%s' % x)
- argv.append(x)
- elif x.startswith('--hide-elapsed'):
- show_elapsed = False
- elif x.startswith('--no-monkeypatch'):
- do_monkeypatch = False
- else:
- argv.append(x)
- eventlet.patcher.monkey_patch(all=False, socket=True, time=True,
- thread=do_monkeypatch)
- testdir = os.path.abspath(os.path.join("tests"))
- c = config.Config(stream=sys.stdout,
- env=os.environ,
- verbosity=3,
- workingDir=testdir,
- plugins=core.DefaultPluginManager())
-
- runner = NovaTestRunner(stream=c.stream,
- verbosity=c.verbosity,
- config=c,
- show_elapsed=show_elapsed)
- if os.path.exists('tests/test.db.pristine'):
- os.unlink('tests/test.db.pristine')
-
- sys.exit(not core.run(config=c, testRunner=runner, argv=argv))
diff --git a/run_tests.sh b/run_tests.sh
index a225d78d..2e21e24f 100755
--- a/run_tests.sh
+++ b/run_tests.sh
@@ -32,6 +32,7 @@ function usage {
echo " -h, --help Print this usage message"
echo " -xintegration Ignore all keystoneclient test cases (integration tests)"
echo " --hide-elapsed Don't print the elapsed time for each test along with slow test list"
+ echo " --standard-threads Don't do the eventlet threading monkeypatch."
echo ""
echo "Note: with no options specified, the script will try to run the tests in a virtual environment,"
echo " If no virtualenv is found, the script will ask if you would like to create one. If you "
@@ -51,6 +52,9 @@ function process_option {
-P|--no-pep8) no_pep8=1;;
-c|--coverage) coverage=1;;
-xintegration) nokeystoneclient=1;;
+ --standard-threads)
+ export STANDARD_THREADS=1
+ ;;
-*) noseopts="$noseopts $1";;
*) noseargs="$noseargs $1"
esac
@@ -114,7 +118,7 @@ function run_pep8 {
--exclude=vcsversion.py ${srcfiles} | tee pep8.txt
}
-NOSETESTS="python run_tests.py $noseopts $noseargs"
+NOSETESTS="nosetests $noseopts $noseargs"
if [ $never_venv -eq 0 ]
then
diff --git a/setup.cfg b/setup.cfg
index 2454585d..b43ee455 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -32,3 +32,4 @@ detailed-errors=1
cover-package = keystone
cover-html = true
cover-erase = true
+where=tests
diff --git a/tests/test_backend_sql.py b/tests/test_backend_sql.py
index ee181dee..e8c345a7 100644
--- a/tests/test_backend_sql.py
+++ b/tests/test_backend_sql.py
@@ -42,6 +42,10 @@ class SqlIdentity(test.TestCase, test_backend.IdentityTests):
self.identity_api = identity_sql.Identity()
self.load_fixtures(default_fixtures)
+ def tearDown(self):
+ sql_util.teardown_test_database()
+ super(SqlIdentity, self).tearDown()
+
def test_delete_user_with_tenant_association(self):
user = {'id': uuid.uuid4().hex,
'name': uuid.uuid4().hex,
@@ -143,6 +147,10 @@ class SqlToken(test.TestCase, test_backend.TokenTests):
sql_util.setup_test_database()
self.token_api = token_sql.Token()
+ def tearDown(self):
+ sql_util.teardown_test_database()
+ super(SqlToken, self).tearDown()
+
class SqlCatalog(test.TestCase, test_backend.CatalogTests):
def setUp(self):
@@ -154,3 +162,7 @@ class SqlCatalog(test.TestCase, test_backend.CatalogTests):
self.catalog_api = catalog_sql.Catalog()
self.catalog_man = catalog.Manager()
self.load_fixtures(default_fixtures)
+
+ def tearDown(self):
+ sql_util.teardown_test_database()
+ super(SqlCatalog, self).tearDown()
diff --git a/tests/test_import_legacy.py b/tests/test_import_legacy.py
index 84c4bb6b..c5cd481f 100644
--- a/tests/test_import_legacy.py
+++ b/tests/test_import_legacy.py
@@ -39,6 +39,10 @@ class ImportLegacy(test.TestCase):
sql_util.setup_test_database()
self.identity_api = identity_sql.Identity()
+ def tearDown(self):
+ sql_util.teardown_test_database()
+ super(ImportLegacy, self).tearDown()
+
def setup_old_database(self, sql_dump):
sql_path = test.testsdir(sql_dump)
db_path = test.testsdir('%s.db' % sql_dump)
diff --git a/tests/test_keystoneclient_sql.py b/tests/test_keystoneclient_sql.py
index e4178dc8..541ca670 100644
--- a/tests/test_keystoneclient_sql.py
+++ b/tests/test_keystoneclient_sql.py
@@ -34,6 +34,10 @@ class KcMasterSqlTestCase(test_keystoneclient.KcMasterTestCase):
test.testsdir('backend_sql.conf')])
sql_util.setup_test_database()
+ def tearDown(self):
+ sql_util.teardown_test_database()
+ super(KcMasterSqlTestCase, self).tearDown()
+
def test_endpoint_crud(self):
from keystoneclient import exceptions as client_exceptions
diff --git a/tests/test_migrate_nova_auth.py b/tests/test_migrate_nova_auth.py
index 34375d12..d699d4b8 100644
--- a/tests/test_migrate_nova_auth.py
+++ b/tests/test_migrate_nova_auth.py
@@ -75,6 +75,10 @@ class MigrateNovaAuth(test.TestCase):
self.identity_api = identity_sql.Identity()
self.ec2_api = ec2_sql.Ec2()
+ def tearDown(self):
+ sql_util.teardown_test_database()
+ super(MigrateNovaAuth, self).tearDown()
+
def _create_role(self, role_name):
role_id = uuid.uuid4().hex
role_dict = {'id': role_id, 'name': role_name}
diff --git a/tox.ini b/tox.ini
index ec562420..344f60ad 100644
--- a/tox.ini
+++ b/tox.ini
@@ -11,7 +11,7 @@ setenv = VIRTUAL_ENV={envdir}
NOSE_OPENSTACK_STDOUT=1
deps = -r{toxinidir}/tools/pip-requires
-r{toxinidir}/tools/test-requires
-commands = bash run_tests.sh -N --no-pep8
+commands = nosetests {posargs}
[testenv:pep8]
deps = pep8==1.3.3
@@ -21,7 +21,7 @@ commands = pep8 --exclude=vcsversion.py,*.pyc,openstack --repeat --show-source b
downloadcache = ~/cache/pip
[testenv:cover]
-commands = /bin/bash run_tests.sh -N -P --with-xcoverage --cover-erase --cover-package=keystone
+setenv = NOSE_WITH_COVERAGE=1
[testenv:venv]
commands = {posargs}