Clean up tests for dropping obj_relationships

Change-Id: I58280c9289ae91c06d7d98f0ffae54f9caf3d383
This commit is contained in:
Dan Smith 2015-10-05 16:48:58 -07:00
parent 5cba110707
commit d33be98eee
6 changed files with 25 additions and 311 deletions

View File

@ -75,46 +75,6 @@ class NovaObject(ovoo_base.VersionedObject):
OBJ_SERIAL_NAMESPACE = 'nova_object'
OBJ_PROJECT_NAMESPACE = 'nova'
# NOTE(danms): Keep the compatibility bits in nova separate from o.vo
# for the time being so that we can keep changes required to use
# the base version of those risky methods separate from the rest of the
# simple inherited methods.
def obj_calculate_child_version(self, target_version, child):
"""Calculate the appropriate version for a child object.
This is to be used when backporting an object for an older client.
A sub-object will need to be backported to a suitable version for
the client as well, and this method will calculate what that
version should be, based on obj_relationships.
:param target_version: Version this object is being backported to
:param child: The child field for which the appropriate version
is to be calculated
:returns: None if the child should be omitted from the backport,
otherwise, the version to which the child should be
backported
"""
target_version = utils.convert_version_to_tuple(target_version)
for index, versions in enumerate(self.obj_relationships[child]):
my_version, child_version = versions
my_version = utils.convert_version_to_tuple(my_version)
if target_version < my_version:
if index == 0:
# We're backporting to a version from before this
# subobject was added: delete it from the primitive.
return None
else:
# We're in the gap between index-1 and index, so
# backport to the older version
return self.obj_relationships[child][index - 1][1]
elif target_version == my_version:
# This is the first mapping that satisfies the
# target_version request: backport the object.
return child_version
# No need to backport, as far as we know, so return the latest
# version of the sub-object we know about
return self.obj_relationships[child][-1][1]
# NOTE(danms): This has some minor change between the nova and o.vo
# version, so avoid inheriting it for the moment so we can make that
# transition separately for clarity.

View File

@ -17,6 +17,7 @@ import mock
import netaddr
from oslo_serialization import jsonutils
from oslo_utils import timeutils
from oslo_versionedobjects import base as ovo_base
from oslo_versionedobjects import exception as ovo_exc
from nova import db
@ -429,13 +430,17 @@ class _TestComputeNodeObject(object):
def test_compat_numa_topology(self):
compute = compute_node.ComputeNode()
primitive = compute.obj_to_primitive(target_version='1.4')
versions = ovo_base.obj_tree_get_versions('ComputeNode')
primitive = compute.obj_to_primitive(target_version='1.4',
version_manifest=versions)
self.assertNotIn('numa_topology', primitive)
def test_compat_supported_hv_specs(self):
compute = compute_node.ComputeNode()
compute.supported_hv_specs = fake_supported_hv_specs
primitive = compute.obj_to_primitive(target_version='1.5')
versions = ovo_base.obj_tree_get_versions('ComputeNode')
primitive = compute.obj_to_primitive(target_version='1.5',
version_manifest=versions)
self.assertNotIn('supported_hv_specs', primitive)
def test_compat_host(self):
@ -446,7 +451,9 @@ class _TestComputeNodeObject(object):
def test_compat_pci_device_pools(self):
compute = compute_node.ComputeNode()
compute.pci_device_pools = fake_pci_device_pools.fake_pool_list
primitive = compute.obj_to_primitive(target_version='1.8')
versions = ovo_base.obj_tree_get_versions('ComputeNode')
primitive = compute.obj_to_primitive(target_version='1.8',
version_manifest=versions)
self.assertNotIn('pci_device_pools', primitive)
@mock.patch('nova.objects.Service.get_by_compute_host')

View File

@ -18,6 +18,7 @@ import iso8601
import mock
import netaddr
from oslo_utils import timeutils
from oslo_versionedobjects import base as ovo_base
from nova import exception
from nova.objects import fixed_ip
@ -349,7 +350,11 @@ class _TestFixedIPObject(object):
self.context, {'id': 0}, host='fake-host')
primitive = fixed_ips[0].obj_to_primitive()
self.assertIn('default_route', primitive['nova_object.data'])
fixed_ips[0].obj_make_compatible(primitive['nova_object.data'], '1.1')
versions = ovo_base.obj_tree_get_versions('FixedIP')
fixed_ips[0].obj_make_compatible_from_manifest(
primitive['nova_object.data'],
target_version='1.1',
version_manifest=versions)
self.assertNotIn('default_route', primitive['nova_object.data'])

View File

@ -15,6 +15,8 @@
import mock
import netaddr
from oslo_versionedobjects import base as ovo_base
from nova import exception
from nova import objects
from nova.objects import floating_ip
@ -245,7 +247,10 @@ class _TestFloatingIPObject(object):
floating = objects.FloatingIP()
fixed = objects.FixedIP()
floating.fixed_ip = fixed
primitive = floating.obj_to_primitive(target_version='1.1')
versions = ovo_base.obj_tree_get_versions('FloatingIP')
versions['FixedIP'] = '1.1'
primitive = floating.obj_to_primitive(target_version='1.1',
version_manifest=versions)
self.assertEqual('1.1',
primitive['nova_object.data']['fixed_ip']['nova_object.version'])

View File

@ -133,14 +133,6 @@ class _TestNUMA(object):
inst_cell = objects.NUMACell()
self.assertEqual(0, len(inst_cell.obj_get_changes()))
def test_obj_cell_relationships(self):
obj = objects.NUMATopology(cells=[objects.NUMACell()])
rel = objects.NUMATopology.obj_relationships['cells']
for topo_ver, cell_ver in rel:
prim = obj.obj_to_primitive(target_version=topo_ver)
cell = objects.NUMATopology.obj_from_primitive(prim).cells[0]
self.assertEqual(cell_ver, cell.VERSION)
def test_numa_pages_equivalent(self):
pt1 = objects.NUMAPagesTopology(size_kb=1024, total=32, used=0)
pt2 = objects.NUMAPagesTopology(size_kb=1024, total=32, used=0)

View File

@ -1382,79 +1382,6 @@ class TestObjectVersions(test.NoDBTestCase):
return field._type._element_type._type._obj_name
return None
def _get_obj_cls(self, name):
# NOTE(danms): We're moving to using manifest-based backports,
# which don't depend on relationships. Given that we only had
# one major version of each object before that change, we can
# make sure to pull the older version of objects that have
# a 2.0 version while calculating the old-style relationship
# mapping. Once we drop all the 1.x versions, we can drop this
# relationship test altogether.
new_objects = ['Instance', 'InstanceList']
versions = base.NovaObjectRegistry.obj_classes()[name]
if len(versions) > 1 and name in new_objects:
return versions[1]
else:
return versions[0]
def _build_tree(self, tree, obj_class, get_current_versions=True):
obj_name = obj_class.obj_name()
if obj_name in tree:
return
for name, field in obj_class.fields.items():
sub_obj_name = self._get_object_field_name(field)
if sub_obj_name:
sub_obj_class = self._get_obj_cls(sub_obj_name)
tree.setdefault(obj_name, {})
if get_current_versions:
sub_obj_ver = sub_obj_class.VERSION
else:
# get the most recent subobject version
# from obj_relationships
sub_obj_ver = obj_class.obj_relationships[name][-1][1]
tree[obj_name][sub_obj_name] = sub_obj_ver
def test_relationships(self):
# This test asserts that the obj_relationship map of all objects
# contain the current versions of any subobjects.
current_versions_tree = {}
obj_relationships_tree = {}
obj_classes = base.NovaObjectRegistry.obj_classes()
for obj_name in obj_classes.keys():
obj_cls = self._get_obj_cls(obj_name)
self._build_tree(current_versions_tree, obj_cls)
self._build_tree(obj_relationships_tree, obj_cls,
get_current_versions=False)
stored = set([(x, str(y))
for x, y in obj_relationships_tree.items()])
computed = set([(x, str(y))
for x, y in current_versions_tree.items()])
changed = stored.symmetric_difference(computed)
expected = {}
actual = {}
for name, deps in changed:
expected[name] = current_versions_tree.get(name)
actual[name] = obj_relationships_tree.get(name)
# If this assertion is failing, this means an object is holding a
# non-current version of another object.
# Example: if Instance is bumped from version 1.1 to 1.2,
# and InstanceList is still only has obj_relationships with 1.1,
# this assertion will fail. InstanceList will need to also be bumped
# a version, with the relationship to Instance 1.2 added.
self.assertEqual(expected, actual,
'Some objects have changed dependencies. '
'Please make sure to bump the versions of '
'parent objects and provide a rule in their '
'obj_make_compatible() routines to backlevel '
'the child object. The expected dict is the '
'current versions of all objects held by other '
'objects, and the actual dict is what is held '
'within obj_relationships on the given objects.')
def test_obj_make_compatible(self):
# Iterate all object classes and verify that we can run
# obj_make_compatible with every older version than current.
@ -1463,13 +1390,15 @@ class TestObjectVersions(test.NoDBTestCase):
# expecting the wrong version format.
obj_classes = base.NovaObjectRegistry.obj_classes()
for obj_name in obj_classes:
versions = ovo_base.obj_tree_get_versions(obj_name)
obj_class = obj_classes[obj_name][0]
version = utils.convert_version_to_tuple(obj_class.VERSION)
for n in range(version[1]):
test_version = '%d.%d' % (version[0], n)
LOG.info('testing obj: %s version: %s' %
(obj_name, test_version))
obj_class().obj_to_primitive(target_version=test_version)
obj_class().obj_to_primitive(target_version=test_version,
version_manifest=versions)
def test_list_obj_make_compatible(self):
@base.NovaObjectRegistry.register_if(False)
@ -1527,190 +1456,6 @@ class TestObjectVersions(test.NoDBTestCase):
"List was backported to before 'objects' existed."
" 'objects' should not be in the primitive.")
def test_obj_bad_relationships(self):
# Make sure having an object with bad relationships is caught by
# _build_tree()
@base.NovaObjectRegistry.register
class TestObj(base.NovaObject):
VERSION = '1.1'
fields = {'foo': fields.IntegerField()}
@base.NovaObjectRegistry.register
class OtherTestObj(base.NovaObject):
VERSION = '1.2'
fields = {'test': fields.ObjectField('TestObj')}
obj_relationships = {'test': [('1.0', '1.0')]}
current_versions_tree = {}
obj_relationships_tree = {}
obj_classes = base.NovaObjectRegistry.obj_classes()
expected_current = {'OtherTestObj': {'TestObj': '1.1'}}
self._build_tree(current_versions_tree,
obj_classes['OtherTestObj'][0])
expected_obj_relationships = {'OtherTestObj': {'TestObj': '1.0'}}
self._build_tree(obj_relationships_tree,
obj_classes['OtherTestObj'][0],
get_current_versions=False)
self.assertEqual(expected_current, current_versions_tree)
self.assertEqual(expected_obj_relationships, obj_relationships_tree)
def _get_obj_same_major(self, this_cls, obj_name):
this_major = this_cls.VERSION.split('.')[0]
obj_classes = base.NovaObjectRegistry.obj_classes()
for cls_version in obj_classes[obj_name]:
major = cls_version.VERSION.split('.')[0]
if major == this_major:
return cls_version
def _get_obj_to_test(self, obj_class):
obj = obj_class()
for fname, ftype in obj.fields.items():
if isinstance(ftype, fields.ObjectField):
fobjname = ftype.AUTO_TYPE._obj_name
fobjcls = self._get_obj_same_major(obj_class, fobjname)
setattr(obj, fname, self._get_obj_to_test(fobjcls))
elif isinstance(ftype, fields.ListOfObjectsField):
# FIXME(danms): This will result in no tests for this
# field type...
setattr(obj, fname, [])
return obj
def _find_version_mapping(self, my_ver, versions):
closest = None
my_ver = utils.convert_version_to_tuple(my_ver)
for _my, _child in versions:
_my = utils.convert_version_to_tuple(_my)
_child = utils.convert_version_to_tuple(_child)
if _my == my_ver:
return '%s.%s' % _child
elif _my < my_ver:
closest = _child
if closest:
return '%s.%s' % closest
else:
return None
def _validate_object_fields(self, obj_class, primitive):
for fname, ftype in obj_class.fields.items():
if isinstance(ftype, fields.ObjectField):
exp_vers = obj_class.obj_relationships[fname]
exp_ver = self._find_version_mapping(
primitive['nova_object.version'], exp_vers)
if exp_ver is None:
self.assertNotIn(fname, primitive['nova_object.data'])
else:
child_p = primitive['nova_object.data'][fname]
self.assertEqual(exp_ver,
child_p['nova_object.version'])
def test_obj_make_compatible_with_data(self):
# Iterate all object classes and verify that we can run
# obj_make_compatible with every older version than current.
# This doesn't actually test the data conversions, but it at least
# makes sure the method doesn't blow up on something basic like
# expecting the wrong version format.
obj_classes = base.NovaObjectRegistry.obj_classes()
for obj_name in obj_classes:
for obj_class in obj_classes[obj_name]:
if obj_class.VERSION.startswith('2'):
# NOTE(danms): Objects with major versions >=2 will
# use version_manifest for backports, which is a
# different test than this one, so skip.
continue
if 'tests.unit' in obj_class.__module__:
# NOTE(danms): Skip test objects. When we move to
# oslo.versionedobjects, we won't have to do this
continue
version = utils.convert_version_to_tuple(obj_class.VERSION)
for n in range(version[1]):
test_version = '%d.%d' % (version[0], n)
LOG.info('testing obj: %s version: %s' %
(obj_name, test_version))
test_object = self._get_obj_to_test(obj_class)
obj_p = test_object.obj_to_primitive(
target_version=test_version)
self._validate_object_fields(obj_class, obj_p)
def test_obj_relationships_in_order(self):
# Iterate all object classes and verify that we can run
# obj_make_compatible with every older version than current.
# This doesn't actually test the data conversions, but it at least
# makes sure the method doesn't blow up on something basic like
# expecting the wrong version format.
obj_classes = base.NovaObjectRegistry.obj_classes()
for obj_name in obj_classes:
obj_class = obj_classes[obj_name][0]
for field, versions in obj_class.obj_relationships.items():
last_my_version = (0, 0)
last_child_version = (0, 0)
for my_version, child_version in versions:
_my_version = utils.convert_version_to_tuple(my_version)
_ch_version = utils.convert_version_to_tuple(child_version)
self.assertTrue((last_my_version < _my_version
and last_child_version <= _ch_version),
'Object %s relationship '
'%s->%s for field %s is out of order' % (
obj_name, my_version, child_version,
field))
last_my_version = _my_version
last_child_version = _ch_version
def test_objects_use_obj_relationships(self):
obj_classes = base.NovaObjectRegistry.obj_classes()
for obj_name in obj_classes:
obj_class = obj_classes[obj_name][0]
self.assertFalse((hasattr(obj_class, 'child_versions')
and obj_class.child_versions),
'Object %s should be using obj_relationships, '
'not child_versions.' % obj_name)
def test_obj_relationships_not_past_current_parent_version(self):
# Iterate all object classes to verify that all versions of the parent
# held in obj_relationships are at or before the current version
obj_classes = base.NovaObjectRegistry.obj_classes()
for obj_name in obj_classes:
obj_class = obj_classes[obj_name][0]
cur_version = utils.convert_version_to_tuple(obj_class.VERSION)
for field, versions in obj_class.obj_relationships.items():
for my_version, child_version in versions:
tup_version = utils.convert_version_to_tuple(my_version)
self.assertTrue(tup_version <= cur_version,
"Field '%(field)s' of %(obj)s contains a "
"relationship that is past the current "
"version. Relationship version is %(ov)s."
" Current version is %(cv)s." %
{'field': field, 'obj': obj_name,
'ov': my_version,
'cv': obj_class.VERSION})
def test_obj_relationships_not_past_current_child_version(self):
# Iterate all object classes to verify that all versions of subobjects
# held in obj_relationships are at or before the current version
obj_classes = base.NovaObjectRegistry.obj_classes()
for obj_name in obj_classes:
obj_class = obj_classes[obj_name][0]
for field, versions in obj_class.obj_relationships.items():
obj_field = obj_class.fields[field]
child_name = self._get_object_field_name(obj_field)
child_class = obj_classes[child_name][0]
curr_child_ver = child_class.VERSION
tup_curr_child_ver = utils.convert_version_to_tuple(
curr_child_ver)
for parent_ver, child_ver in versions:
tup_version = utils.convert_version_to_tuple(child_ver)
self.assertTrue(tup_version <= tup_curr_child_ver,
"Field '%(field)s' of %(obj)s contains a "
"relationship that is past the current "
"version of %(child_obj)s. Relationship "
"version is %(ov)s. Current version is "
"%(cv)s." %
{'field': field, 'obj': obj_name,
'child_obj': child_name,
'ov': child_ver, 'cv': curr_child_ver})
class TestObjEqualPrims(_BaseTestCase):