Auto-set nullable notification payload fields when needed

Currently, the populate_schema method in the notification payload base
class raises an exception whenever any payload field in the notification
schema is missing from the populating object, even if that field is
nullable in the payload.

This behavior is not expected and results in unintended failures when
populating a schema with an object missing nullable payload fields.

Change-Id: I05d7f373ee441b63d833b3c90cc5f225cd81b5be
Closes-Bug: #1651517
This commit is contained in:
Mario Villaplana 2016-12-20 18:03:55 +00:00 committed by Yuriy Zveryanskyy
parent 2a4d3cc5e8
commit 9cd777fe2a
2 changed files with 39 additions and 4 deletions

View File

@ -153,6 +153,19 @@ class NotificationPayloadBase(base.IronicObject):
source=kwargs)
try:
setattr(self, key, getattr(source, field))
except NotImplementedError:
# The object is missing (a value for) field. Oslo try to load
# value via obj_load_attr() method which is not implemented.
# If this field is nullable in this payload, set its payload
# value to None.
field_obj = self.fields.get(key)
if field_obj is not None and getattr(field_obj, 'nullable',
False):
setattr(self, key, None)
continue
raise exception.NotificationSchemaKeyError(obj=obj,
field=field,
key=key)
except Exception:
raise exception.NotificationSchemaKeyError(obj=obj,
field=field,

View File

@ -25,10 +25,17 @@ class TestNotificationBase(test_base.TestCase):
class TestObject(base.IronicObject):
VERSION = '1.0'
fields = {
'fake_field_1': fields.StringField(),
'fake_field_1': fields.StringField(nullable=True),
'fake_field_2': fields.IntegerField(nullable=True)
}
@base.IronicObjectRegistry.register_if(False)
class TestObjectMissingField(base.IronicObject):
VERSION = '1.0'
fields = {
'fake_field_1': fields.StringField(nullable=True),
}
@base.IronicObjectRegistry.register_if(False)
class TestNotificationPayload(notification.NotificationPayloadBase):
VERSION = '1.0'
@ -39,8 +46,8 @@ class TestNotificationBase(test_base.TestCase):
}
fields = {
'fake_field_a': fields.StringField(),
'fake_field_b': fields.IntegerField(),
'fake_field_a': fields.StringField(nullable=True),
'fake_field_b': fields.IntegerField(nullable=False),
'an_extra_field': fields.StringField(nullable=False),
'an_optional_field': fields.IntegerField(nullable=True)
}
@ -228,13 +235,28 @@ class TestNotificationBase(test_base.TestCase):
self.assertEqual(self.fake_obj.fake_field_1, payload.fake_field_a)
self.assertEqual(self.fake_obj.fake_field_2, payload.fake_field_b)
def test_populate_schema_missing_obj_field(self):
def test_populate_schema_missing_required_obj_field(self):
test_obj = self.TestObject(fake_field_1='populated')
# this payload requires missing fake_field_b
payload = self.TestNotificationPayload(an_extra_field='too extra')
self.assertRaises(exception.NotificationSchemaKeyError,
payload.populate_schema,
test_obj=test_obj)
def test_populate_schema_nullable_field_auto_populates(self):
"""Test that nullable fields always end up in the payload."""
test_obj = self.TestObject(fake_field_2=123)
payload = self.TestNotificationPayload()
payload.populate_schema(test_obj=test_obj)
self.assertIsNone(payload.fake_field_a)
def test_populate_schema_no_object_field(self):
test_obj = self.TestObjectMissingField(fake_field_1='foo')
payload = self.TestNotificationPayload()
self.assertRaises(exception.NotificationSchemaKeyError,
payload.populate_schema,
test_obj=test_obj)
def test_event_type_with_status(self):
event_type = notification.EventType(
object="some_obj", action="some_action", status="success")