Migrate unit test to testtools

Additional changes:
* Removed testing framework for MuranoPL since it was based on Nose
* Made test_log run only on Linux hosts
* Every testcase is now required to have proper setUp method

Change-Id: I86ee5ec487019c2d1b77f0fd34f748cf9c6412a0
Implements: blueprint migrate-murano-ut-to-testtoools
This commit is contained in:
Ruslan Kamaldinov
2014-06-04 16:53:59 +04:00
parent 59a4a7e71e
commit d8ba3ed42b
14 changed files with 104 additions and 228 deletions

3
.gitignore vendored
View File

@@ -12,6 +12,9 @@ dist/
.tox
AUTHORS
ChangeLog
.testrepository
.coverage
cover
#Python
*.pyc

7
.testr.conf Executable file
View File

@@ -0,0 +1,7 @@
[DEFAULT]
test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} \
OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} \
OS_TEST_TIMEOUT=${OS_TEST_TIMEOUT:-60} \
${PYTHON:-python} -m subunit.run discover $DISCOVER_DIRECTORY $LISTOPT $IDOPTION
test_id_option=--load-list $IDFILE
test_list_option=--list

20
murano/tests/base.py Normal file
View File

@@ -0,0 +1,20 @@
# 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.
import testtools
class MuranoTestCase(testtools.TestCase):
def setUp(self):
super(MuranoTestCase, self).setUp()

View File

@@ -12,12 +12,11 @@
# License for the specific language governing permissions and limitations
# under the License.
import unittest2 as unittest
from murano.common.helpers import token_sanitizer
from murano.tests import base
class TokenSanitizerTests(unittest.TestCase):
class TokenSanitizerTests(base.MuranoTestCase):
sanitizer = token_sanitizer.TokenSanitizer()
def test_dict_with_one_value(self):

View File

@@ -12,12 +12,11 @@
# License for the specific language governing permissions and limitations
# under the License.
import unittest2 as unittest
from murano.common import utils
from murano.tests import base
class IsDifferentTests(unittest.TestCase):
class IsDifferentTests(base.MuranoTestCase):
def test_equal_dicts(self):
obj1 = {'first': 10, 'second': 12}
obj2 = {'second': 12, 'first': 10}

View File

@@ -12,12 +12,11 @@
# License for the specific language governing permissions and limitations
# under the License.
import unittest2 as unittest
from murano.common import utils
from murano.tests import base
class TraverseHelperTests(unittest.TestCase):
class TraverseHelperTests(base.MuranoTestCase):
def test_root_get_with_dict(self):
source = {'attr': True}
value = utils.TraverseHelper.get('/', source)

View File

@@ -1,17 +0,0 @@
Namespaces:
=: io.murano.language.tests
Name: ExampleTestCase
Extends: TestCase
Workflow:
testSum:
Body:
- $sum: 1 + 2
- $.assertEqual(3, $sum)
testUpper:
Body:
- $uppedValue: toUpper('test')
- $.assertEqual('TEST', $uppedValue)

View File

@@ -1,9 +0,0 @@
Format: 1.0
Type: Library
FullName: io.murano.language.tests
Name: Example Test Cases
Description: Simple test case intended to be used as example
Author: Example
Tags: [test, example]
Classes:
io.murano.language.tests.ExampleTestCase: ExampleTestCase.yaml

View File

@@ -1,158 +0,0 @@
# Copyright (c) 2014 Mirantis Inc.
#
# 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.
import inspect
import json
import logging
import os
import yaml
import nose
import unittest2 as unittest
from murano.common import uuidutils
from murano.dsl import executor
from murano.dsl import murano_class
from murano.dsl import namespace_resolver
from murano.engine import simple_cloader
from murano.engine.system import system_objects
LOG = logging.getLogger('nose.plugins.munit')
@murano_class.classname('io.murano.language.tests.TestCase')
class BaseTestCase(object):
pass
class ManifestClassLoader(simple_cloader.SimpleClassLoader):
def __init__(self, base_loader, base_path):
self._base_loader = base_loader
super(ManifestClassLoader, self).__init__(base_path)
def load_definition(self, name):
manifest_file = os.path.join(self._base_path, 'manifest.yaml')
if not os.path.exists(manifest_file):
return None
with open(manifest_file) as stream:
manifest = yaml.load(stream)
pkg_classes = manifest.get('Classes', {})
if name in pkg_classes:
class_file = os.path.join(self._base_path, pkg_classes[name])
with open(class_file) as stream:
return yaml.load(stream)
else:
return self._base_loader.load_definition(name)
class MUnitTestCase(unittest.TestCase):
def __init__(self, loader, test_case, case_name):
self._executor = executor.MuranoDslExecutor(loader)
self._test_case = self._executor.load(test_case)
self._case_name = case_name
self.register_asserts()
super(MUnitTestCase, self).__init__(methodName='runTest')
def register_asserts(self):
for item in dir(self):
method = getattr(self, item)
if ((inspect.ismethod(method) or inspect.isfunction(method))
and item.startswith('assert')):
self._test_case.type.add_method(item, method)
def runTest(self):
self._test_case.type.invoke(self._case_name, self._executor,
self._test_case, {})
def __repr__(self):
return "{0} ({1})".format(self._case_name, self._test_case.type.name)
__str__ = __repr__
class MuranoPLUnitTestPlugin(nose.plugins.Plugin):
name = 'munit'
def options(self, parser, env=os.environ):
parser.add_option('--metadata-dir')
super(MuranoPLUnitTestPlugin, self).options(parser, env=env)
def configure(self, options, conf):
self._metadata_dir = options.metadata_dir
super(MuranoPLUnitTestPlugin, self).configure(options, conf)
def loadTestsFromFile(self, filename):
with open(filename) as stream:
manifest = yaml.load(stream)
pkg_directory = os.path.dirname(filename)
base_cloader = simple_cloader.SimpleClassLoader(self._metadata_dir)
cloader = ManifestClassLoader(base_cloader, pkg_directory)
system_objects.register(cloader, pkg_directory)
cloader.import_class(BaseTestCase)
package_classes = manifest.get('Classes', {})
for class_name, class_file in package_classes.iteritems():
class_file = os.path.join(pkg_directory, class_file)
with open(class_file) as stream:
class_definition = yaml.load(stream)
if not self._is_test_suite(class_definition):
yield None
test_object = self._get_test_object(class_name, class_file)
test_cases = class_definition.get('Workflow', {})
for case_name, _ in test_cases.iteritems():
yield MUnitTestCase(cloader, test_object, case_name)
yield None
@staticmethod
def _get_test_object(class_name, class_file):
class_file = os.path.abspath(class_file)
extension_length = os.path.splitext(class_file)
object_file = class_file[:-len(extension_length)] + 'json'
if os.path.exists(object_file):
with open(object_file) as stream:
return json.load(stream)
else:
return {
"Objects": {
"?": {
"id": uuidutils.generate_uuid(),
"type": class_name
}
}
}
@staticmethod
def _is_test_suite(class_definition):
namespaces = class_definition.get('Namespaces', {})
extends = class_definition.get('Extends')
ns_resolver = namespace_resolver.NamespaceResolver(namespaces)
parent_name = ns_resolver.resolve_name(extends)
return parent_name == 'io.murano.language.tests.TestCase'
def wantFile(self, file):
if file.endswith('manifest.yaml'):
return True

View File

@@ -16,7 +16,6 @@
import re
import mock
import unittest2 as unittest
import yaql
import murano.dsl.exceptions as exceptions
@@ -26,11 +25,16 @@ import murano.dsl.murano_object as murano_object
import murano.dsl.namespace_resolver as ns_resolver
import murano.dsl.typespec as typespec
import murano.dsl.yaql_expression as yaql_expression
from murano.tests import base
ROOT_CLASS = 'io.murano.Object'
class TestNamespaceResolving(unittest.TestCase):
class TestNamespaceResolving(base.MuranoTestCase):
def setUp(self):
super(TestNamespaceResolving, self).setUp()
def test_fails_w_empty_name(self):
resolver = ns_resolver.NamespaceResolver({'=': 'com.example.murano'})
@@ -110,9 +114,12 @@ class Bunch(object):
setattr(self, key, value)
class TestClassesManipulation(unittest.TestCase):
class TestClassesManipulation(base.MuranoTestCase):
resolver = mock.Mock(resolve_name=lambda name: name)
def setUp(self):
super(TestClassesManipulation, self).setUp()
def test_class_name(self):
cls = murano_class.MuranoClass(None, self.resolver, ROOT_CLASS, None)
@@ -152,8 +159,9 @@ class TestClassesManipulation(unittest.TestCase):
self.assertRaises(TypeError, cls.add_property, **kwargs)
@unittest.skip
def test_add_property_to_class(self):
self.skipTest("FIXME!")
prop = typespec.PropertySpec({'Default': 1}, self.resolver)
cls = murano_class.MuranoClass(None, self.resolver, ROOT_CLASS, None)
cls.add_property('firstPrime', prop)
@@ -164,8 +172,9 @@ class TestClassesManipulation(unittest.TestCase):
self.assertEqual(['firstPrime'], class_properties)
self.assertEqual(prop, class_property)
@unittest.skip
def test_class_property_search(self):
self.skipTest("FIXME!")
void_prop = typespec.PropertySpec({'Default': 'Void'}, self.resolver)
mother_prop = typespec.PropertySpec({'Default': 'Mother'},
self.resolver)
@@ -224,8 +233,11 @@ class TestClassesManipulation(unittest.TestCase):
self.assertFalse(obj.initialize.called)
class TestObjectsManipulation(unittest.TestCase):
class TestObjectsManipulation(base.MuranoTestCase):
def setUp(self):
super(TestObjectsManipulation, self).setUp()
self.resolver = mock.Mock(resolve_name=lambda name: name)
self.cls = mock.Mock()
self.cls.name = ROOT_CLASS
@@ -275,8 +287,9 @@ class TestObjectsManipulation(unittest.TestCase):
self.assertEqual(parent, obj.parent)
@unittest.skip
def test_fails_internal_property_access(self):
self.skipTest("FIXME!")
cls = murano_class.MuranoClass(None, self.resolver, ROOT_CLASS)
cls.add_property('__hidden',
@@ -285,8 +298,9 @@ class TestObjectsManipulation(unittest.TestCase):
self.assertRaises(AttributeError, lambda: obj.__hidden)
@unittest.skip
def test_proper_property_access(self):
self.skipTest("FIXME!")
cls = murano_class.MuranoClass(None, self.resolver, ROOT_CLASS)
cls.add_property('someProperty',
@@ -295,8 +309,9 @@ class TestObjectsManipulation(unittest.TestCase):
self.assertEqual(0, obj.someProperty)
@unittest.skip
def test_parent_class_property_access(self):
self.skipTest("FIXME!")
cls = murano_class.MuranoClass(None, self.resolver, ROOT_CLASS)
child_cls = murano_class.MuranoClass(None, self.resolver,
'Child', [cls])
@@ -307,8 +322,9 @@ class TestObjectsManipulation(unittest.TestCase):
self.assertEqual(0, obj.anotherProperty)
@unittest.skip
def test_fails_on_parents_property_collision(self):
self.skipTest("FIXME!")
root = murano_class.MuranoClass(None, self.resolver, ROOT_CLASS)
mother = murano_class.MuranoClass(None, self.resolver,
'Mother', [root])
@@ -344,8 +360,9 @@ class TestObjectsManipulation(unittest.TestCase):
self.assertEqual(prop_value, resolved_value)
@unittest.skip
def test_fails_forbidden_set_property(self):
self.skipTest("FIXME!")
cls = murano_class.MuranoClass(None, self.resolver, ROOT_CLASS)
cls.add_property('someProperty',
typespec.PropertySpec({'Default': 0}, self.resolver))
@@ -355,8 +372,9 @@ class TestObjectsManipulation(unittest.TestCase):
self.assertRaises(exceptions.NoWriteAccess, obj.set_property,
'someProperty', 10, caller_class=cls)
@unittest.skip
def test_set_property(self):
self.skipTest("FIXME!")
cls = murano_class.MuranoClass(None, self.resolver, ROOT_CLASS)
cls.add_property('someProperty',
typespec.PropertySpec({'Default': 0}, self.resolver))
@@ -369,8 +387,9 @@ class TestObjectsManipulation(unittest.TestCase):
self.assertEqual(10, obj.someProperty)
@unittest.skip
def test_set_parent_property(self):
self.skipTest("FIXME!")
root = murano_class.MuranoClass(None, self.resolver, ROOT_CLASS)
cls = murano_class.MuranoClass(None, self.resolver,
'SomeClass', [root])
@@ -385,8 +404,9 @@ class TestObjectsManipulation(unittest.TestCase):
self.assertEqual(20, obj.rootProperty)
@unittest.skip
def test_object_up_cast(self):
self.skipTest("FIXME!")
root = murano_class.MuranoClass(None, self.resolver, ROOT_CLASS)
root_alt = murano_class.MuranoClass(None, self.resolver, 'RootAlt', [])
cls = murano_class.MuranoClass(
@@ -413,7 +433,11 @@ class TestObjectsManipulation(unittest.TestCase):
self.assertRaises(TypeError, root_obj.cast, cls)
class TestHelperFunctions(unittest.TestCase):
class TestHelperFunctions(base.MuranoTestCase):
def setUp(self):
super(TestHelperFunctions, self).setUp()
def test_generate_id(self):
generated_id = helpers.generate_id()
@@ -452,7 +476,11 @@ class TestHelperFunctions(unittest.TestCase):
self.assertTrue(testee([yaql_expr]))
class TestYaqlExpression(unittest.TestCase):
class TestYaqlExpression(base.MuranoTestCase):
def setUp(self):
super(TestYaqlExpression, self).setUp()
def test_expression(self):
yaql_expr = yaql_expression.YaqlExpression('string')

View File

@@ -12,15 +12,23 @@
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import logging
import unittest
import sys
from murano.openstack.common import log
from murano.tests import base
class SysLogHandlersTestCase(unittest.TestCase):
class SysLogHandlersTestCase(base.MuranoTestCase):
"""Test for standard and RFC compliant Syslog handlers."""
def setUp(self):
super(SysLogHandlersTestCase, self).setUp()
if sys.platform != 'linux2':
self.skip("SKIP: This test work on Linux platform only.")
self.facility = logging.handlers.SysLogHandler.LOG_USER
self.rfclogger = log.RFCSysLogHandler(address='/dev/log',
facility=self.facility)

View File

@@ -1,14 +1,13 @@
hacking>=0.8.0,<0.9
unittest2
coverage>=3.6
discover
fixtures>=0.3.14
mox>=0.5.3
nose
nose-exclude
openstack.nose_plugin>=0.7
nosehtmloutput>=0.0.3
sphinx>=1.1.2,<1.2
requests>=1.1
testtools>=0.9.34
mock>=1.0
testrepository>=0.0.18
testscenarios>=0.4
testtools>=0.9.34
unittest2
# doc build requirements
sphinx>=1.1.2,<1.2

14
tox.ini
View File

@@ -6,15 +6,13 @@ skipsdist = True
[testenv]
usedevelop = True
install_command = pip install -U {opts} {packages}
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
setenv =
VIRTUAL_ENV={envdir}
DISCOVER_DIRECTORY=murano/tests
deps = -r{toxinidir}/requirements.txt
-r{toxinidir}/test-requirements.txt
commands = nosetests -w murano/tests
commands = python setup.py test --slowest --testr-args="{posargs}"
whitelist_externals = bash
[testenv:pep8]
commands =
@@ -24,7 +22,7 @@ commands =
commands = {posargs}
[testenv:cover]
commands = nosetests --cover-erase --cover-package=murano --with-xcoverage
commands = python setup.py testr --coverage --testr-args='{posargs}'
[testenv:docs]
commands =