Rebase fixture management on top fo fixtures library.

Change-Id: Idb34d4bebc1be6d753e4805f58a1a71c84ee15b7
This commit is contained in:
Federico Ressi 2019-03-02 11:22:00 +01:00
parent 88943f69f5
commit 903e85083d
4 changed files with 183 additions and 224 deletions

View File

@ -1,5 +1,6 @@
# Tobiko framework requirements
fixtures>=3.0.0 # Apache-2.0/BSD
keystoneauth1>=2.0.0 # Apache-2.0
oslo.config>=5.2.0 # Apache-2.0
oslo.log>=3.36.0 # Apache-2.0
@ -7,5 +8,6 @@ python-heatclient>=1.5.0 # Apache-2.0
python-neutronclient>=6.7.0 # Apache-2.0
python-novaclient>=9.1.0 # Apache-2.0
stestr>=2.0 # Apache-2.0
six>=1.10.0 # MIT
testtools>=2.2.0 # MIT
testscenarios>=0.4 # Apache-2.0/BSD

View File

@ -22,13 +22,12 @@ load_module = loader_manager.load_module
discover_testcases = testcase_manager.discover_testcases
Fixture = fixture_manager.Fixture
fixture = fixture_manager.fixture
is_fixture = fixture_manager.is_fixture
get_fixture = fixture_manager.get_fixture
create_fixture = fixture_manager.create_fixture
delete_fixture = fixture_manager.delete_fixture
get_required_fixtures = fixture_manager.get_required_fixtures
discover_required_fixtures = fixture_manager.discover_required_fixtures
create_fixtures = fixture_manager.create_fixtures
delete_fixtures = fixture_manager.delete_fixtures
get_fixture_name = fixture_manager.get_fixture_name
setup_fixture = fixture_manager.setup_fixture
cleanup_fixture = fixture_manager.cleanup_fixture
list_required_fixtures = fixture_manager.list_required_fixtures
iter_required_fixtures = fixture_manager.iter_required_fixtures
setup_required_fixtures = fixture_manager.setup_required_fixtures
cleanup_required_fixtures = fixture_manager.cleanup_required_fixtures

View File

@ -13,22 +13,18 @@
# under the License.
from __future__ import absolute_import
import abc
import contextlib
import inspect
import fixtures
import six
import tobiko
def fixture(obj):
obj.__tobiko_fixture__ = True
return object
def is_fixture(obj):
return getattr(obj, '__tobiko_fixture__', False)
return (getattr(obj, '__tobiko_fixture__', False) or
isinstance(obj, fixtures.Fixture) or
(inspect.isclass(obj) and issubclass(obj, fixtures.Fixture)))
def get_fixture(obj, manager=None):
@ -36,183 +32,109 @@ def get_fixture(obj, manager=None):
return manager.get_fixture(obj)
def create_fixture(obj, manager=None):
manager = manager or FIXTURES
return manager.create_fixture(obj)
def get_fixture_name(obj):
return get_fixture(obj).__tobiko_fixture_name__
def delete_fixture(obj, manager=None):
manager = manager or FIXTURES
return manager.delete_fixture(obj)
def setup_fixture(obj, manager=None):
get_fixture(obj, manager=manager).setUp()
def get_required_fixtures(obj, manager=None):
manager = manager or FIXTURES
return manager.get_required_fixtures(obj)
def cleanup_fixture(obj, manager=None):
get_fixture(obj, manager=manager).cleanUp()
def discover_required_fixtures(objects, manager=None):
manager = manager or FIXTURES
return sorted(set(manager.discover_required_fixtures(objects, manager)))
def create_fixtures(objects, manager=None):
manager = manager or FIXTURES
for _fixture in discover_required_fixtures(objects=objects,
manager=manager):
manager.create_fixture(_fixture)
def delete_fixtures(objects, manager=None):
manager = manager or FIXTURES
for _fixture in discover_required_fixtures(objects=objects,
manager=manager):
return manager.delete_fixture(_fixture)
class FixtureManager(object):
def __init__(self):
self.fixtures = {}
def get_fixture(self, obj):
name = get_object_name(obj)
_fixture = self.fixtures.get(name)
if _fixture is None:
_fixture = self.init_fixture(name=name, obj=obj)
assert isinstance(_fixture, Fixture)
self.fixtures[name] = _fixture
return _fixture
def create_fixture(self, obj):
return self.get_fixture(obj).create_fixture()
def delete_fixture(self, obj):
return self.get_fixture(obj).delete_fixture()
def init_fixture(self, obj, name):
def iter_required_fixtures(objects):
objects = list(objects)
while objects:
obj = objects.pop()
if isinstance(obj, six.string_types):
if name != obj:
msg = ("Fixture name mismatch: "
"{!r} != {!r}").format(name, obj.fixture_name)
raise ValueError(msg)
obj = tobiko.load_object(name)
object_id = obj
obj = tobiko.load_object(object_id)
else:
object_id = get_object_name(obj)
if is_fixture(obj):
yield object_id
elif inspect.isfunction(obj) or inspect.ismethod(obj):
for default in get_default_param_values(obj):
if is_fixture(default):
yield get_object_name(default)
if inspect.ismodule(obj):
members = [obj for _, obj in inspect.getmembers(obj)
if (inspect.isfunction(obj) or
inspect.isclass(obj))]
objects.extend(members)
if isinstance(obj, Fixture):
if name != obj.fixture_name:
msg = ("Fixture name mismatch: "
"{!r} != {!r}").format(name, obj.fixture_name)
raise ValueError(msg)
return obj
elif inspect.isclass(obj):
if issubclass(obj, Fixture):
return obj(fixture_name=name)
elif inspect.isgeneratorfunction(obj):
return ContextFixture(
fixture_name=name, context=contextlib.contextmanager(obj))
elif inspect.isfunction(obj):
return FunctionFixture(fixture_name=name, function=obj)
raise TypeError("Invalid fixture object type: {!r}".format(object))
def get_required_fixtures(self, obj):
return sorted(set(self.discover_required_fixtures([obj])))
def discover_required_fixtures(self, objects):
objects = list(objects)
while objects:
obj = objects.pop()
if isinstance(obj, six.string_types):
object_id = obj
obj = tobiko.load_object(object_id)
else:
object_id = get_object_name(obj)
if is_fixture(obj):
yield object_id
elif inspect.isfunction(obj) or inspect.ismethod(obj):
for default in get_default_param_values(obj):
if is_fixture(default):
yield get_object_name(default)
if inspect.ismodule(obj):
members = [obj for _, obj in inspect.getmembers(obj)
if (inspect.isfunction(obj) or
inspect.isclass(obj))]
objects.extend(members)
elif inspect.isclass(obj):
members = [obj for _, obj in inspect.getmembers(obj)
if (inspect.isfunction(obj) or
inspect.ismethod(obj))]
objects.extend(members)
members = [obj for _, obj in inspect.getmembers(obj)
if (inspect.isfunction(obj) or
inspect.ismethod(obj))]
objects.extend(members)
FIXTURES = FixtureManager()
def list_required_fixtures(objects):
return sorted(set(iter_required_fixtures(objects)))
class Fixture(object):
__tobiko_fixture__ = True
def __init__(self, fixture_name):
self.fixture_name = fixture_name
@abc.abstractmethod
def create_fixture(self):
pass
def delete_fixture(self):
pass
def setup_required_fixtures(objects, manager=None):
manager = manager or FIXTURES
for _fixture in iter_required_fixtures(objects=objects):
manager.get_fixture(_fixture).setUp()
class FunctionFixture(Fixture):
def __init__(self, fixture_name, function):
super(FunctionFixture, self).__init__(fixture_name=fixture_name)
assert callable(function)
self.function = function
def create_fixture(self):
return self.function()
def cleanup_required_fixtures(objects, manager=None):
manager = manager or FIXTURES
for _fixture in iter_required_fixtures(objects=objects):
manager.get_fixture(_fixture).cleanUp()
class ContextFixture(Fixture):
def init_fixture(obj, name):
if isinstance(obj, six.string_types):
obj = tobiko.load_object(name)
def __init__(self, fixture_name, context):
super(ContextFixture, self).__init__(fixture_name=fixture_name)
self.context = context
if (inspect.isclass(obj) and issubclass(obj, fixtures.Fixture)):
obj = obj()
def create_fixture(self):
return self.context.__enter__()
if isinstance(obj, fixtures.Fixture):
obj.__tobiko_fixture__ = True
obj.__tobiko_fixture_name__ = name
return obj
def delete_fixture(self):
return self.context.__exit__(None, None, None)
raise TypeError("Invalid fixture object type: {!r}".format(object))
def get_object_name(obj):
if isinstance(obj, six.string_types):
return obj
if is_fixture(obj):
name = getattr(obj, 'fixture_name', None)
if name:
return name
name = getattr(obj, '__qualname__', None)
name = getattr(obj, '__tobiko_fixture_name__', None)
if name:
return obj.__module__ + '.' + name
return name
module = inspect.getmodule(obj).__name__
if inspect.isclass(obj):
return module + '.' + obj.__name__
parent_class = getattr(obj, 'im_class', None)
if parent_class:
return module + parent_class.__name__ + '.' + obj.__name__
if six.PY2:
# Below code is only for old Python versions
if inspect.isclass(obj):
# This doesn't work for nested classes
return module + '.' + obj.__name__
if inspect.isfunction(obj):
return module + '.' + obj.func_name
method_class = getattr(obj, 'im_class', None)
if method_class:
# This doesn't work for nested classes
return module + method_class.__name__ + '.' + obj.__name__
if inspect.isfunction(obj):
return module + '.' + obj.func_name
else:
# Only Python 3 defines __qualname__
name = getattr(obj, '__qualname__', None)
if name:
return module + '.' + name
msg = "Unable to get fixture name from object {!r}".format(obj)
raise TypeError(msg)
@ -231,3 +153,20 @@ def get_default_param_values(obj):
# Use old deprecated function 'getargspec'
return list(inspect.getargspec(obj).defaults or # pylint: disable=W1505
tuple())
class FixtureManager(object):
def __init__(self):
self.fixtures = {}
def get_fixture(self, obj, init=init_fixture):
name = get_object_name(obj)
_fixture = self.fixtures.get(name)
if _fixture is None:
self.fixtures[name] = _fixture = init(name=name, obj=obj)
assert isinstance(_fixture, fixtures.Fixture)
return _fixture
FIXTURES = FixtureManager()

View File

@ -13,90 +13,109 @@
# under the License.
from __future__ import absolute_import
import fixtures
import tobiko
from tobiko.tests import base
class TestFixture(tobiko.Fixture):
class MyFixtureClass(fixtures.Fixture):
created = False
deleted = False
def _setUp(self):
self.setup_executed = True
self.addCleanup(self._cleanUp)
def reset(self):
self.created = False
self.deleted = False
def _cleanUp(self):
self.cleanup_executed = True
def create_fixture(self):
self.created = True
return 'created'
def delete_fixture(self):
self.deleted = True
return 'deleted'
MY_FIXTURE_NAME = __name__ + '.' + MyFixtureClass.__name__
class FixtureTypeTest(base.TobikoTest):
fixture_type = TestFixture
fixture_name = __name__ + '.' + TestFixture.__name__
@classmethod
def setUpClass(cls):
super(FixtureTypeTest, cls).setUpClass()
cls.fixture = tobiko.get_fixture(cls.fixture_name)
def setUp(self):
super(FixtureTypeTest, self).setUp()
self.fixture.reset()
def test_fixture_type(self):
self.assertIsInstance(self.fixture, self.fixture_type)
def test_fixture_name(self):
self.assertEqual(self.fixture_name, self.fixture.fixture_name)
def test_get_fixture_by_name(self):
self._test_get_fixture(self.fixture_name)
self._test_get_fixture(MY_FIXTURE_NAME, fixture_type=MyFixtureClass)
def test_get_fixture_by_type(self):
self._test_get_fixture(self.fixture_type)
self._test_get_fixture(MyFixtureClass, fixture_type=MyFixtureClass)
def _test_get_fixture(self, obj):
def _test_get_fixture(self, obj, fixture_type):
fixture = tobiko.get_fixture(obj)
self.assertIs(self.fixture, fixture)
self.assertFalse(fixture.created)
self.assertFalse(fixture.deleted)
self.assertIsInstance(fixture, fixture_type)
self.assertIs(fixture, tobiko.get_fixture(obj))
def test_create_fixture_by_name(self):
self._test_create_fixture(self.fixture_name)
def test_get_name(self):
fixture = tobiko.get_fixture(MY_FIXTURE_NAME)
result = tobiko.get_fixture_name(fixture)
self.assertEqual(MY_FIXTURE_NAME, result)
def test_create_fixture_by_type(self):
self._test_create_fixture(self.fixture_type)
def test_setup_fixture_by_name(self):
self._test_setup_fixture(MY_FIXTURE_NAME)
def _test_create_fixture(self, obj):
result = tobiko.create_fixture(obj)
self.assertEqual('created', result)
self.assertTrue(self.fixture.created)
self.assertFalse(self.fixture.deleted)
def test_setup_fixture_by_type(self):
self._test_setup_fixture(MyFixtureClass)
def test_delete_fixture_by_name(self):
self._test_delete_fixture(self.fixture_name)
def _test_setup_fixture(self, obj):
fixture = tobiko.get_fixture(obj)
fixture.setup_executed = False
def test_delete_fixture_by_type(self):
self._test_delete_fixture(self.fixture_type)
tobiko.setup_fixture(obj)
def _test_delete_fixture(self, obj=TestFixture):
result = tobiko.delete_fixture(obj)
self.assertEqual('deleted', result)
self.assertFalse(self.fixture.created)
self.assertTrue(self.fixture.deleted)
self.assertTrue(fixture.setup_executed)
def test_get_required_fixtures_from_method_by_type(
self, _required_fixture=TestFixture):
result = tobiko.get_required_fixtures(self.id())
self.assertEqual([self.fixture_name], result)
def test_cleanup_fixture_by_name(self):
self._test_cleanup_fixture(MY_FIXTURE_NAME)
def test_get_required_fixtures_from_test_class(
self, _required_fixture=TestFixture):
result = tobiko.get_required_fixtures(FixtureTypeTest)
self.assertEqual([self.fixture_name], result)
def test_cleanup_fixture_by_type(self):
self._test_cleanup_fixture(MyFixtureClass)
def _test_cleanup_fixture(self, obj):
fixture = tobiko.get_fixture(obj)
fixture.setUp()
tobiko.cleanup_fixture(obj)
self.assertTrue(fixture.cleanup_executed)
def test_list_required_fixtures_from_module(self):
result = tobiko.list_required_fixtures([__name__])
self.assertEqual([MY_FIXTURE_NAME], result)
def test_list_required_fixtures_from_testcase_type(self):
result = tobiko.list_required_fixtures([FixtureTypeTest])
self.assertEqual([MY_FIXTURE_NAME], result)
def test_list_required_fixtures_from_fixture_type(self):
result = tobiko.list_required_fixtures([MyFixtureClass])
self.assertEqual([MY_FIXTURE_NAME], result)
def test_list_required_fixtures_from_fixture_name(self):
result = tobiko.list_required_fixtures([MY_FIXTURE_NAME])
self.assertEqual([MY_FIXTURE_NAME], result)
def test_list_required_fixtures_from_method(
self, fixture_type=MyFixtureClass):
result = tobiko.list_required_fixtures([self.id()])
self.assertEqual([MY_FIXTURE_NAME], result)
self.assertIsInstance(tobiko.get_fixture(MY_FIXTURE_NAME),
fixture_type)
def test_list_required_fixtures_from_fixture_object(self):
fixture = tobiko.get_fixture(MY_FIXTURE_NAME)
result = tobiko.list_required_fixtures([fixture])
self.assertEqual([MY_FIXTURE_NAME], result)
def test_setup_required_fixtures(self, fixture_type=MyFixtureClass):
fixture = tobiko.get_fixture(fixture_type)
fixture.setup_executed = False
tobiko.setup_required_fixtures([self.id()])
self.assertTrue(fixture.setup_executed)
def test_cleanup_required_fixtures(self, fixture_type=MyFixtureClass):
fixture = tobiko.get_fixture(fixture_type)
fixture.cleanup_executed = False
fixture.setUp()
tobiko.cleanup_required_fixtures([self.id()])
self.assertTrue(fixture.setup_executed)
self.assertTrue(fixture.cleanup_executed)