summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.coveragerc6
-rw-r--r--.gitignore7
-rw-r--r--contrib/boto_v6/ec2/connection.py2
-rw-r--r--nova/log.py4
-rwxr-xr-xnova/network/linux_net.py6
-rw-r--r--nova/testing/runner.py368
-rw-r--r--nova/tests/__init__.py8
-rw-r--r--nova/tests/test_iptables_network.py22
-rwxr-xr-xrun_tests.sh11
-rw-r--r--setup.cfg9
-rw-r--r--tools/test-requires3
-rw-r--r--tox.ini28
12 files changed, 65 insertions, 409 deletions
diff --git a/.coveragerc b/.coveragerc
new file mode 100644
index 0000000000..82fe477929
--- /dev/null
+++ b/.coveragerc
@@ -0,0 +1,6 @@
+[run]
+branch = True
+omit = /usr*,setup.py,*egg*,.venv/*,.tox/*,nova/tests/*
+
+[report]
+ignore-errors = True
diff --git a/.gitignore b/.gitignore
index eee73ee900..d61dac1f1e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,7 @@
*.DS_Store
local_settings.py
ChangeLog
+MANIFEST
CA/
keeper
instances
@@ -15,9 +16,13 @@ nova.egg-info
*.sqlite
*.log
*.mo
+nosetests.xml
+coverage.xml
tools/conf/nova.conf*
cover/*
+nova/tests/cover/*
+nova/vcsversion.py
+.autogenerated
dist/*
.coverage
covhtml
-nova/tests/coverage.xml
diff --git a/contrib/boto_v6/ec2/connection.py b/contrib/boto_v6/ec2/connection.py
index 868c93c11c..a0cfd7e260 100644
--- a/contrib/boto_v6/ec2/connection.py
+++ b/contrib/boto_v6/ec2/connection.py
@@ -6,7 +6,7 @@ Created on 2010/12/20
import boto
import base64
import boto.ec2
-from boto_v6.ec2.instance import ReservationV6
+from boto_v6.ec2.instance import ReservationV6
from boto.ec2.securitygroup import SecurityGroup
diff --git a/nova/log.py b/nova/log.py
index 7970802f3a..46a07b26cc 100644
--- a/nova/log.py
+++ b/nova/log.py
@@ -361,7 +361,9 @@ def _setup_logging_from_flags():
nova_root.addHandler(streamlog)
elif not FLAGS.log_file:
- streamlog = logging.StreamHandler(stream=sys.stdout)
+ # pass sys.stdout as a positional argument
+ # python2.6 calls the argument strm, in 2.7 it's stream
+ streamlog = logging.StreamHandler(sys.stdout)
nova_root.addHandler(streamlog)
if FLAGS.publish_errors:
diff --git a/nova/network/linux_net.py b/nova/network/linux_net.py
index b2b68b5b7c..811395f9cf 100755
--- a/nova/network/linux_net.py
+++ b/nova/network/linux_net.py
@@ -90,7 +90,11 @@ FLAGS.register_opts(linux_net_opts)
# add up to 12 characters to binary_name which is used as a prefix,
# so we limit it to 16 characters.
# (max_chain_name_length - len('-POSTROUTING') == 16)
-binary_name = os.path.basename(inspect.stack()[-1][1])[:16]
+def get_binary_name():
+ """Grab the name of the binary we're running in."""
+ return os.path.basename(inspect.stack()[-1][1])[:16]
+
+binary_name = get_binary_name()
class IptablesRule(object):
diff --git a/nova/testing/runner.py b/nova/testing/runner.py
deleted file mode 100644
index 9abef4feef..0000000000
--- a/nova/testing/runner.py
+++ /dev/null
@@ -1,368 +0,0 @@
-#!/usr/bin/env python
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# 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 nova/testing/runner.py
-
-To run a single test module:
- python nova/testing/runner.py test_compute
-
- or
-
- python nova/testing/runner.py api.test_wsgi
-
-To run a single test:
- python nova/testing/runner.py
- test_compute:ComputeTestCase.test_run_terminate
-
-"""
-
-import gettext
-import heapq
-import os
-import sys
-import time
-import unittest
-
-import eventlet
-from nose import config
-from nose import core
-from nose import result
-
-gettext.install('nova', unicode=1)
-reldir = os.path.join(os.path.dirname(__file__), '..', '..')
-absdir = os.path.abspath(reldir)
-sys.path.insert(0, absdir)
-
-from nova import log as logging
-
-
-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 Exception:
- 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):
- import win32console as win
- red, green, blue, bold = (win.FOREGROUND_RED, win.FOREGROUND_GREEN,
- win.FOREGROUND_BLUE, win.FOREGROUND_INTENSITY)
- self.stream = stream
- self.screenBuffer = win.GetStdHandle(win.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_
-
-
-def run():
- # This is a fix to allow the --hide-elapsed flag while accepting
- # arbitrary nosetest flags as well
- argv = [x for x in sys.argv if x != '--hide-elapsed']
- hide_elapsed = argv != sys.argv
- logging.setup()
-
- # 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
- for i, arg in enumerate(argv):
- if arg.startswith('test_'):
- argv[i] = 'nova.tests.%s' % arg
-
- testdir = os.path.abspath(os.path.join("nova", "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=not hide_elapsed)
- sys.exit(not core.run(config=c, testRunner=runner, argv=argv))
-
-
-if __name__ == '__main__':
- eventlet.monkey_patch()
- run()
diff --git a/nova/tests/__init__.py b/nova/tests/__init__.py
index d1fa17185f..32dbca7a12 100644
--- a/nova/tests/__init__.py
+++ b/nova/tests/__init__.py
@@ -39,8 +39,16 @@ import shutil
from nova.db.sqlalchemy.session import get_engine
from nova import flags
+from nova import log as logging
+
+import eventlet
+
+eventlet.monkey_patch()
FLAGS = flags.FLAGS
+FLAGS.use_stderr = False
+
+logging.setup()
_DB = None
diff --git a/nova/tests/test_iptables_network.py b/nova/tests/test_iptables_network.py
index b23846bb5e..0d7e54723c 100644
--- a/nova/tests/test_iptables_network.py
+++ b/nova/tests/test_iptables_network.py
@@ -22,6 +22,9 @@ from nova import test
class IptablesManagerTestCase(test.TestCase):
+
+ binary_name = linux_net.get_binary_name()
+
sample_filter = ['#Generated by iptables-save on Fri Feb 18 15:17:05 2011',
'*filter',
':INPUT ACCEPT [2223527:305688874]',
@@ -82,13 +85,14 @@ class IptablesManagerTestCase(test.TestCase):
table = self.manager.ipv4['filter']
table.add_rule('FORWARD', '-s 1.2.3.4/5 -j DROP')
new_lines = self.manager._modify_rules(current_lines, table)
- self.assertTrue('-A runner.py-FORWARD '
- '-s 1.2.3.4/5 -j DROP' in new_lines)
+ self.assertTrue('-A %s-FORWARD '
+ '-s 1.2.3.4/5 -j DROP' % self.binary_name in new_lines)
table.remove_rule('FORWARD', '-s 1.2.3.4/5 -j DROP')
new_lines = self.manager._modify_rules(current_lines, table)
- self.assertTrue('-A runner.py-FORWARD '
- '-s 1.2.3.4/5 -j DROP' not in new_lines)
+ self.assertTrue('-A %s-FORWARD '
+ '-s 1.2.3.4/5 -j DROP' % self.binary_name \
+ not in new_lines)
def test_nat_rules(self):
current_lines = self.sample_nat
@@ -121,8 +125,8 @@ class IptablesManagerTestCase(test.TestCase):
"nova-postouting-bottom: %s" % last_postrouting_line)
for chain in ['POSTROUTING', 'PREROUTING', 'OUTPUT']:
- self.assertTrue('-A %s -j runner.py-%s' %
- (chain, chain) in new_lines,
+ self.assertTrue('-A %s -j %s-%s' %
+ (chain, self.binary_name, chain) in new_lines,
"Built-in chain %s not wrapped" % (chain,))
def test_filter_rules(self):
@@ -153,10 +157,10 @@ class IptablesManagerTestCase(test.TestCase):
break
self.assertTrue('-A nova-filter-top '
- '-j runner.py-local' in new_lines,
+ '-j %s-local' % self.binary_name in new_lines,
"nova-filter-top does not jump to wrapped local chain")
for chain in ['INPUT', 'OUTPUT', 'FORWARD']:
- self.assertTrue('-A %s -j runner.py-%s' %
- (chain, chain) in new_lines,
+ self.assertTrue('-A %s -j %s-%s' %
+ (chain, self.binary_name, chain) in new_lines,
"Built-in chain %s not wrapped" % (chain,))
diff --git a/run_tests.sh b/run_tests.sh
index aab28ed3b3..c814b1adf8 100755
--- a/run_tests.sh
+++ b/run_tests.sh
@@ -60,6 +60,13 @@ coverage=0
recreate_db=1
patch_migrate=1
+export NOSE_WITH_OPENSTACK=1
+export NOSE_OPENSTACK_COLOR=1
+export NOSE_OPENSTACK_RED=0.05
+export NOSE_OPENSTACK_YELLOW=0.025
+export NOSE_OPENSTACK_SHOW_ELAPSED=1
+export NOSE_OPENSTACK_STDOUT=1
+
for arg in "$@"; do
process_option $arg
done
@@ -77,7 +84,7 @@ function run_tests {
# Cleanup *pyc
${wrapper} find . -type f -name "*.pyc" -delete
# Just run the test suites in current environment
- ${wrapper} $NOSETESTS 2> run_tests.log
+ ${wrapper} $NOSETESTS
# If we get some short import error right away, print the error log directly
RESULT=$?
if [ "$RESULT" -ne "0" ];
@@ -115,7 +122,7 @@ function run_pep8 {
}
-NOSETESTS="python nova/testing/runner.py $noseopts $noseargs"
+NOSETESTS="nosetests $noseopts $noseargs"
if [ $never_venv -eq 0 ]
then
diff --git a/setup.cfg b/setup.cfg
index 6588b199f7..8c7bef0711 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -25,8 +25,7 @@ output_file = nova/locale/nova.pot
[nosetests]
verbosity=2
detailed-errors=1
-with-openstack=1
-openstack-red=0.05
-openstack-yellow=0.025
-openstack-show-elapsed=1
-openstack-color=1
+cover-package = nova
+cover-html = true
+cover-erase = true
+where=nova/tests
diff --git a/tools/test-requires b/tools/test-requires
index 51ef2ff632..3adddefe6f 100644
--- a/tools/test-requires
+++ b/tools/test-requires
@@ -4,8 +4,7 @@ distribute>=0.6.24
coverage
mox==0.5.3
nose
-nosexcover
-openstack.nose_plugin
+openstack.nose_plugin>=0.7
pep8==1.1
sphinx>=1.1.2
MySQL-python
diff --git a/tox.ini b/tox.ini
index fac0d7f96f..a68e37c6f5 100644
--- a/tox.ini
+++ b/tox.ini
@@ -3,9 +3,15 @@ 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
deps = -r{toxinidir}/tools/pip-requires
-r{toxinidir}/tools/test-requires
-commands = /bin/bash run_tests.sh -N -P
+commands = nosetests {posargs}
[tox:jenkins]
sitepackages = True
@@ -13,26 +19,10 @@ downloadcache = ~/cache/pip
[testenv:pep8]
deps = pep8==1.1
-commands = /bin/bash run_tests.sh -N --pep8
+commands = pep8 --repeat --show-source --exclude=.venv,.tox,dist,doc .
[testenv:cover]
-commands = /bin/bash run_tests.sh -N -P --cover-package=nova --cover-erase --with-xcoverage
+setenv = NOSE_WITH_COVERAGE=1
[testenv:venv]
commands = {posargs}
-
-[testenv:jenkins26]
-basepython = python2.6
-deps = file://{toxinidir}/.cache.bundle
-
-[testenv:jenkins27]
-basepython = python2.7
-deps = file://{toxinidir}/.cache.bundle
-
-[testenv:jenkinscover]
-commands = /bin/bash run_tests.sh -N -P --cover-package=nova --cover-erase --with-xcoverage
-
-[testenv:jenkinsvenv]
-deps = file://{toxinidir}/.cache.bundle
-commands = {posargs}
-