Merge "Relax required Redfish fields handling"

This commit is contained in:
Zuul 2020-02-11 23:14:16 +00:00 committed by Gerrit Code Review
commit cf7d87ff85
3 changed files with 35 additions and 20 deletions

View File

@ -40,10 +40,9 @@ class Field(object):
:param path: JSON field to fetch the value from. Either a string,
or a list of strings in case of a nested field.
:param required: whether this field is required. Missing required
fields result in MissingAttributeError.
:param required: whether this field is required. Missing required,
but not defaulted, fields result in MissingAttributeError.
:param default: the default value to use when the field is missing.
Only has effect when the field is not required.
:param adapter: a function to call to transform and/or validate
the received value. UnicodeError, ValueError or TypeError from
this call are reraised as MalformedAttributeError.
@ -80,7 +79,8 @@ class Field(object):
:param resource: ResourceBase instance for which the field is loaded.
:param nested_in: parent resource path (for error reporting only),
must be a list of strings or None.
:raises: MissingAttributeError if a required field is missing.
:raises: MissingAttributeError if a required field is missing
and not defaulted.
:raises: MalformedAttributeError on invalid field value or type.
:returns: loaded and verified value
"""
@ -94,12 +94,18 @@ class Field(object):
except KeyError:
if self._required:
path = (nested_in or []) + self._path
raise exceptions.MissingAttributeError(
attribute='/'.join(path),
resource=resource.path)
else:
# Do not run the adapter on the default value
return self._default
if self._default is None:
raise exceptions.MissingAttributeError(
attribute='/'.join(path),
resource=resource.path)
logging.warning(
'Applying default "%s" on required, but missing '
'attribute "%s"' % (self._default, path))
# Do not run the adapter on the default value
return self._default
# NOTE(etingof): this is just to account for schema violation
if item is None:
@ -251,11 +257,10 @@ class MappedField(Field):
a string or a list of string. In the latter case, the value will
be fetched from a nested object.
:param mapping: a mapping to take values from.
:param required: whether this field is required. Missing required
fields result in MissingAttributeError.
:param required: whether this field is required. Missing required,
but not defaulted, fields result in MissingAttributeError.
:param default: the default value to use when the field is missing.
Only has effect when the field is not required. This value is not
matched against the mapping.
This value is not matched against the mapping.
"""
if not isinstance(mapping, collections.abc.Mapping):
raise TypeError("The mapping argument must be a mapping")
@ -278,10 +283,9 @@ class MappedListField(Field):
:param field: JSON field to fetch the list of values from.
:param mapping: a mapping for the list elements.
:param required: whether this field is required. Missing required
fields result in MissingAttributeError.
:param required: whether this field is required. Missing required,
but not defaulted, fields result in MissingAttributeError.
:param default: the default value to use when the field is missing.
Only has effect when the field is not required.
"""
if not isinstance(mapping, collections.abc.Mapping):
raise TypeError("The mapping argument must be a mapping")

View File

@ -21,7 +21,7 @@ from sushy.resources import mappings as res_maps
class MessageDictionaryField(base.DictionaryField):
description = base.Field('Description', required=False)
description = base.Field('Description', required=True, default='')
"""Indicates how and when the message is returned by the Redfish service"""
message = base.Field('Message', required=True)
@ -47,7 +47,8 @@ class MessageDictionaryField(base.DictionaryField):
severity = base.MappedField('Severity',
res_maps.SEVERITY_VALUE_MAP,
default=res_cons.SEVERITY_CRITICAL)
required=True,
default=res_cons.SEVERITY_WARNING)
"""Mapped severity of the message"""

View File

@ -63,7 +63,7 @@ class MessageRegistryTestCase(base.TestCase):
self.assertEqual('Panic', self.registry.messages['Failed'].resolution)
self.assertEqual(
2, len(self.registry.messages['MissingThings'].param_types))
self.assertEqual(res_cons.SEVERITY_CRITICAL,
self.assertEqual(res_cons.SEVERITY_WARNING,
self.registry.messages['MissingThings'].severity)
self.assertEqual(
res_cons.PARAMTYPE_STRING,
@ -74,6 +74,16 @@ class MessageRegistryTestCase(base.TestCase):
self.assertEqual(
'Try Later', self.registry.messages['MissingThings'].resolution)
def test__parse_attributes_missing_msg_desc(self):
self.json_doc['Messages']['Success'].pop('Description')
self.registry._parse_attributes(self.json_doc)
self.assertEqual('', self.registry.messages['Success'].description)
def test__parse_attributes_missing_msg_severity(self):
self.json_doc['Messages']['Success'].pop('Severity')
self.registry._parse_attributes(self.json_doc)
self.assertEqual('warning', self.registry.messages['Success'].severity)
def test__parse_attribtues_unknown_param_type(self):
self.registry.json['Messages']['Failed']['ParamTypes'] = \
['unknown_type']