objects: fixed base to_dict implementation

The implementation was using wrong approach to detect field type, and it
never triggered the actual code. Adopting the base class implementation
for QoS policy object revealed the problem.

Now, we fix the base class to_dict implementation for synthetic fields,
and are able to adopt it for the policy object.

Note that the bug in the base class was never exposed in production
because no objects are currently relying on it.

Change-Id: I3b8727fd3837b51cc1a778dc73d8a1e06f2de5a9
Partial-Bug: #1541928
This commit is contained in:
Ihar Hrachyshka 2016-03-17 15:01:03 +01:00
parent 8bccf9c2a5
commit d503c830fb
3 changed files with 45 additions and 13 deletions

View File

@ -78,15 +78,20 @@ class NeutronObject(obj_base.VersionedObject,
super(NeutronObject, self).__init__(context, **kwargs)
self.obj_set_defaults()
def _synthetic_fields_items(self):
for field in self.synthetic_fields:
if field in self:
yield field, getattr(self, field)
def to_dict(self):
dict_ = dict(self.items())
for field in self.synthetic_fields:
if field in dict_:
if isinstance(dict_[field], obj_fields.ListOfObjectsField):
dict_[field] = [obj.to_dict() for obj in dict_[field]]
elif isinstance(dict_[field], obj_fields.ObjectField):
dict_[field] = (
dict_[field].to_dict() if dict_[field] else None)
for field_name, value in self._synthetic_fields_items():
field = self.fields[field_name]
if isinstance(field, obj_fields.ListOfObjectsField):
dict_[field_name] = [obj.to_dict() for obj in value]
elif isinstance(field, obj_fields.ObjectField):
dict_[field_name] = (
dict_[field_name].to_dict() if value else None)
return dict_
@classmethod

View File

@ -61,12 +61,6 @@ class QosPolicy(base.NeutronDbObject):
binding_models = {'network': network_binding_model,
'port': port_binding_model}
def to_dict(self):
dict_ = super(QosPolicy, self).to_dict()
if 'rules' in dict_:
dict_['rules'] = [rule.to_dict() for rule in dict_['rules']]
return dict_
def obj_load_attr(self, attrname):
if attrname != 'rules':
raise exceptions.ObjectActionError(

View File

@ -488,6 +488,39 @@ class BaseObjectIfaceTestCase(_BaseObjectTestCase, test_base.BaseTestCase):
self.assertRaises(base.NeutronObjectUpdateForbidden, obj.update)
def test_to_dict_synthetic_fields(self):
cls_ = self._test_class
object_fields = [
field
for field in cls_.synthetic_fields
if cls_.is_object_field(field)
]
if not object_fields:
self.skipTest(
'No object fields found in test class %r' % cls_)
for field in object_fields:
obj = cls_(self.context, **self.db_obj)
objclasses = obj_base.VersionedObjectRegistry.obj_classes(
).get(cls_.fields[field].objname)
if not objclasses:
# NOTE(ihrachys): this test does not handle fields of types
# that are not registered (for example, QosRule)
continue
objclass = objclasses[0]
child = objclass(
self.context, **self.get_random_fields(obj_cls=objclass)
)
child_dict = child.to_dict()
if isinstance(cls_.fields[field], obj_fields.ListOfObjectsField):
setattr(obj, field, [child])
dict_ = obj.to_dict()
self.assertEqual([child_dict], dict_[field])
else:
setattr(obj, field, child)
dict_ = obj.to_dict()
self.assertEqual(child_dict, dict_[field])
class BaseDbObjectNonStandardPrimaryKeyTestCase(BaseObjectIfaceTestCase):