summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AUTHORS1
-rw-r--r--run_tests.py360
-rwxr-xr-xrun_tests.sh88
-rw-r--r--setup.cfg5
-rw-r--r--tools/install_venv.py129
-rwxr-xr-xtools/with_venv.sh12
-rw-r--r--tox.ini11
7 files changed, 41 insertions, 565 deletions
diff --git a/AUTHORS b/AUTHORS
index b0eb421..4646e60 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -3,3 +3,4 @@ Jay Pipes <jaypipes@gmail.com>
Monty Taylor <mordred@inaugust.com>
Dean Troyer <dtroyer@gmail.com>
Gabriel Hurley <gabriel@strikeawe.com>
+James E. Blair <jeblair@hp.com>
diff --git a/run_tests.py b/run_tests.py
deleted file mode 100644
index ffa35c6..0000000
--- a/run_tests.py
+++ /dev/null
@@ -1,360 +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 heapq
-import os
-import sys
-import time
-import unittest
-
-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
- 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
- else:
- argv.append(x)
-
- 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)
- sys.exit(not core.run(config=c, testRunner=runner, argv=argv))
diff --git a/run_tests.sh b/run_tests.sh
index 2ecbc4a..dc6cf22 100755
--- a/run_tests.sh
+++ b/run_tests.sh
@@ -4,92 +4,46 @@ function usage {
echo "Usage: $0 [OPTION]..."
echo "Run python-glanceclient's test suite(s)"
echo ""
- echo " -V, --virtual-env Always use virtualenv. Install automatically if not present"
- echo " -N, --no-virtual-env Don't use virtualenv. Run tests in local environment"
- echo " -f, --force Force a clean re-build of the virtual environment. Useful when dependencies have been added."
- echo " --unittests-only Run unit tests only, exclude functional tests."
echo " -p, --pep8 Just run pep8"
echo " -h, --help Print this usage message"
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 "
- echo " prefer to run tests NOT in a virtual environment, simply pass the -N option."
+ echo "This script is deprecated and currently retained for compatibility."
+ echo 'You can run the full test suite for multiple environments by running "tox".'
+ echo 'You can run tests for only python 2.7 by running "tox -e py27", or run only'
+ echo 'the pep8 tests with "tox -e pep8".'
exit
}
+command -v tox > /dev/null 2>&1
+if [ $? -ne 0 ]; then
+ echo 'This script requires "tox" to run.'
+ echo 'You can install it with "pip install tox".'
+ exit 1;
+fi
+
+just_pep8=0
+
function process_option {
case "$1" in
-h|--help) usage;;
- -V|--virtual-env) let always_venv=1; let never_venv=0;;
- -N|--no-virtual-env) let always_venv=0; let never_venv=1;;
-p|--pep8) let just_pep8=1;;
- -f|--force) let force=1;;
- *) noseargs="$noseargs $1"
esac
}
-venv=.venv
-with_venv=tools/with_venv.sh
-always_venv=0
-never_venv=0
-force=0
-noseargs=
-wrapper=""
-just_pep8=0
-
for arg in "$@"; do
process_option $arg
done
-function run_tests {
- # Just run the test suites in current environment
- ${wrapper} rm -f tests.sqlite
- ${wrapper} $NOSETESTS 2> run_tests.err.log
-}
-
-function run_pep8 {
- echo "Running pep8..."
- PEP8_OPTIONS="--exclude=$PEP8_EXCLUDE --repeat"
- PEP8_INCLUDE="glanceclient/*.py setup.py run_tests.py tools/install_venv.py"
- ${wrapper} pep8 $PEP8_OPTIONS $PEP8_INCLUDE
-}
-
-
-NOSETESTS="python run_tests.py $noseargs"
-
-if [ $never_venv -eq 0 ]
-then
- # Remove the virtual environment if --force used
- if [ $force -eq 1 ]; then
- echo "Cleaning virtualenv..."
- rm -rf ${venv}
- fi
- if [ -e ${venv} ]; then
- wrapper="${with_venv}"
- else
- if [ $always_venv -eq 1 ]; then
- # Automatically install the virtualenv
- python tools/install_venv.py
- wrapper="${with_venv}"
- else
- echo -e "No virtual environment found...create one? (Y/n) \c"
- read use_ve
- if [ "x$use_ve" = "xY" -o "x$use_ve" = "x" -o "x$use_ve" = "xy" ]; then
- # Install the virtualenv and run the test suite in it
- python tools/install_venv.py
- wrapper=${with_venv}
- fi
- fi
- fi
-fi
-
if [ $just_pep8 -eq 1 ]; then
- run_pep8
- exit
+ tox -e pep8
+ exit
fi
-run_tests || exit
+tox -e py27 $toxargs 2>&1 | tee run_tests.err.log || exit
+if [ ${PIPESTATUS[0]} -ne 0 ]; then
+ exit ${PIPESTATUS[0]}
+fi
-if [ -z "$noseargs" ]; then
- run_pep8
+if [ -z "$toxargs" ]; then
+ tox -e pep8
fi
diff --git a/setup.cfg b/setup.cfg
index 3ef59d0..5f86012 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -5,11 +5,6 @@ cover-erase = true
cover-inclusive = true
verbosity=2
detailed-errors=1
-with-openstack=1
-openstack-red=0.05
-openstack-yellow=0.025
-openstack-show-elapsed=1
-openstack-color=1
[build_sphinx]
source-dir = docs/
diff --git a/tools/install_venv.py b/tools/install_venv.py
deleted file mode 100644
index d404744..0000000
--- a/tools/install_venv.py
+++ /dev/null
@@ -1,129 +0,0 @@
-# Copyright 2012 OpenStack LLC
-# 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.
-
-"""
-virtualenv installation script
-"""
-
-import os
-import subprocess
-import sys
-
-
-ROOT = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
-VENV = os.path.join(ROOT, '.venv')
-PIP_REQUIRES = os.path.join(ROOT, 'tools', 'pip-requires')
-TEST_REQUIRES = os.path.join(ROOT, 'tools', 'test-requires')
-PY_VERSION = "python%s.%s" % (sys.version_info[0], sys.version_info[1])
-
-
-def die(message, *args):
- print >>sys.stderr, message % args
- sys.exit(1)
-
-
-def check_python_version():
- if sys.version_info < (2, 6):
- die("Need Python Version >= 2.6")
-
-
-def run_command(cmd, redirect_output=True, check_exit_code=True):
- """
- Runs a command in an out-of-process shell, returning the
- output of that command. Working directory is ROOT.
- """
- if redirect_output:
- stdout = subprocess.PIPE
- else:
- stdout = None
-
- proc = subprocess.Popen(cmd, cwd=ROOT, stdout=stdout)
- output = proc.communicate()[0]
- if check_exit_code and proc.returncode != 0:
- die('Command "%s" failed.\n%s', ' '.join(cmd), output)
- return output
-
-
-HAS_EASY_INSTALL = bool(run_command(['which', 'easy_install'],
- check_exit_code=False).strip())
-HAS_VIRTUALENV = bool(run_command(['which', 'virtualenv'],
- check_exit_code=False).strip())
-
-
-def check_dependencies():
- """Make sure virtualenv is in the path."""
-
- print 'Checking for virtualenv...'
- if not HAS_VIRTUALENV:
- print 'not found.'
- # Try installing it via easy_install...
- if HAS_EASY_INSTALL:
- print 'Installing virtualenv via easy_install...',
- if not (run_command(['which', 'easy_install']) and
- run_command(['easy_install', 'virtualenv'])):
- die('ERROR: virtualenv not found.\n\nNova development'
- ' requires virtualenv, please install it using your'
- ' favorite package management tool')
- print 'done.'
- print 'done.'
-
-
-def create_virtualenv(venv=VENV):
- """Creates the virtual environment and installs PIP only into the
- virtual environment
- """
- print 'Creating venv...',
- run_command(['virtualenv', '-q', '--no-site-packages', VENV])
- print 'done.'
- print 'Installing pip in virtualenv...',
- if not run_command(['tools/with_venv.sh', 'easy_install', 'pip']).strip():
- die("Failed to install pip.")
- print 'done.'
-
-
-def install_dependencies(venv=VENV):
- print 'Installing dependencies with pip (this can take a while)...'
- run_command(['tools/with_venv.sh', 'pip', 'install', '-r',
- PIP_REQUIRES, '-r', TEST_REQUIRES], redirect_output=False)
-
-
-def print_help():
- help = """
- Virtual environment configuration complete.
-
- To activate the virtualenv for the extent of your current shell
- session you can run:
-
- $ source %s/bin/activate
-
- Or, if you prefer, you can run commands in the virtualenv on a case by case
- basis by running:
-
- $ tools/with_venv.sh <your command>
-
- """ % VENV
- print help
-
-
-def main(argv):
- check_python_version()
- check_dependencies()
- create_virtualenv()
- install_dependencies()
- print_help()
-
-if __name__ == '__main__':
- main(sys.argv)
diff --git a/tools/with_venv.sh b/tools/with_venv.sh
index c8d2940..e6e44f5 100755
--- a/tools/with_venv.sh
+++ b/tools/with_venv.sh
@@ -1,4 +1,10 @@
#!/bin/bash
-TOOLS=`dirname $0`
-VENV=$TOOLS/../.venv
-source $VENV/bin/activate && $@
+
+command -v tox > /dev/null 2>&1
+if [ $? -ne 0 ]; then
+ echo 'This script requires "tox" to run.'
+ echo 'You can install it with "pip install tox".'
+ exit 1;
+fi
+
+tox -evenv -- $@
diff --git a/tox.ini b/tox.ini
index 40de0f6..e618c83 100644
--- a/tox.ini
+++ b/tox.ini
@@ -3,6 +3,11 @@ 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
deps = -r{toxinidir}/tools/pip-requires
-r{toxinidir}/tools/test-requires
commands = nosetests
@@ -17,21 +22,25 @@ commands = {posargs}
[testenv:cover]
commands = nosetests --cover-erase --cover-package=glanceclient --with-xcoverage
-[testenv:hudson]
+[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=glanceclient --with-xcoverage
[testenv:jenkinsvenv]
deps = file://{toxinidir}/.cache.bundle
+setenv = NOSE_WITH_XUNIT=1
commands = {posargs}