Adding invalid_property attr to support test code

Moving all base class calls to first line

Adding invalid_property to InvalidObject exception and
invalid_field to UnsupportedField exception.
Modified test code to check these attributes instead of
checking the exception message string.

Also updating NewOrderValidator and VerificationValidator
per bug #1246871

Change-Id: I0776d4a33652ec28c713037c2ef49e35c9b39e54
Implements: blueprint validation-improve-err-msgs
This commit is contained in:
Huseyin Gedikli 2014-01-08 15:03:55 -08:00
parent 9dc1c17058
commit e51ca90944
3 changed files with 69 additions and 43 deletions

View File

@ -40,6 +40,7 @@ class BarbicanException(Exception):
message = _("An unknown exception occurred")
def __init__(self, message=None, *args, **kwargs):
super(BarbicanException, self).__init__(message)
if not message:
message = self.message
try:
@ -51,8 +52,6 @@ class BarbicanException(Exception):
# at least get the core message out if something happened
pass
super(BarbicanException, self).__init__(message)
class MissingArgumentError(BarbicanException):
message = _("Missing required argument.")
@ -180,9 +179,9 @@ class LimitExceeded(BarbicanException):
"breached.\n\nThe response body:\n%(body)s")
def __init__(self, *args, **kwargs):
super(LimitExceeded, self).__init__(*args, **kwargs)
self.retry_after = (int(kwargs['retry']) if kwargs.get('retry')
else None)
super(LimitExceeded, self).__init__(*args, **kwargs)
class ServiceUnavailable(BarbicanException):
@ -191,9 +190,9 @@ class ServiceUnavailable(BarbicanException):
"outage.")
def __init__(self, *args, **kwargs):
super(ServiceUnavailable, self).__init__(*args, **kwargs)
self.retry_after = (int(kwargs['retry']) if kwargs.get('retry')
else None)
super(ServiceUnavailable, self).__init__(*args, **kwargs)
class ServerError(BarbicanException):
@ -275,11 +274,19 @@ class InvalidObject(BarbicanException):
message = _("Provided object does not match schema "
"'%(schema)s': %(reason)s")
def __init__(self, *args, **kwargs):
super(InvalidObject, self).__init__(*args, **kwargs)
self.invalid_property = kwargs.get('property')
class UnsupportedField(BarbicanException):
message = _("No support for value set on field '%(field)s' on "
"schema '%(schema)s': %(reason)s")
def __init__(self, *args, **kwargs):
super(UnsupportedField, self).__init__(*args, **kwargs)
self.invalid_field = kwargs.get('field')
class UnsupportedHeaderFeature(BarbicanException):
message = _("Provided header feature is unsupported: %(feature)s")

View File

@ -29,6 +29,12 @@ def secret_too_big(data):
return len(data.encode('utf-8')) > CONF.max_allowed_secret_in_bytes
def get_invalid_property(validation_error):
# we are interested in the second item which is the failed propertyName.
if validation_error.schema_path and len(validation_error.schema_path) > 1:
return validation_error.schema_path[1]
class ValidatorBase(object):
"""Base class for validators."""
@ -94,7 +100,9 @@ class NewSecretValidator(ValidatorBase):
try:
schema.validate(json_data, self.schema)
except schema.ValidationError as e:
raise exception.InvalidObject(schema=schema_name, reason=e.message)
raise exception.InvalidObject(schema=schema_name,
reason=e.message,
property=get_invalid_property(e))
# Validate/normalize 'name'.
name = json_data.get('name', '').strip()
@ -110,7 +118,8 @@ class NewSecretValidator(ValidatorBase):
if expiration <= utcnow:
raise exception.InvalidObject(schema=schema_name,
reason=_("'expiration' is "
"before current time"))
"before current time"),
property="expiration")
json_data['expiration'] = expiration
# Validate/convert 'payload' if provided.
@ -120,7 +129,8 @@ class NewSecretValidator(ValidatorBase):
raise exception.InvalidObject(
schema=schema_name,
reason=_("If 'payload' is supplied, 'payload_content_type'"
" must also be supplied.")
" must also be supplied."),
property="payload_content_type"
)
content_encoding = json_data.get('payload_content_encoding')
@ -130,7 +140,8 @@ class NewSecretValidator(ValidatorBase):
schema=schema_name,
reason=_("payload_content_encoding must be specified "
"when payload_content_type is application/"
"octet-stream.")
"octet-stream."),
property="payload_content_encoding"
)
if content_type.startswith('text/plain') and \
@ -138,7 +149,8 @@ class NewSecretValidator(ValidatorBase):
raise exception.InvalidObject(
schema=schema_name,
reason=_("payload_content_encoding must not be specified "
"when payload_content_type is text/plain")
"when payload_content_type is text/plain"),
property="payload_content_encoding"
)
payload = json_data['payload']
@ -150,7 +162,8 @@ class NewSecretValidator(ValidatorBase):
raise exception.InvalidObject(schema=schema_name,
reason=_("If 'payload' "
"specified, must be "
"non empty"))
"non empty"),
property="payload")
json_data['payload'] = payload
@ -168,7 +181,8 @@ class NewSecretValidator(ValidatorBase):
LOG.exception("Problem parsing expiration date")
raise exception.InvalidObject(schema=schema_name,
reason=_("Invalid date "
"for 'expiration'"))
"for 'expiration'"),
property="expiration")
return expiration
@ -191,13 +205,15 @@ class NewOrderValidator(ValidatorBase):
try:
schema.validate(json_data, self.schema)
except schema.ValidationError as e:
raise exception.InvalidObject(schema=schema_name, reason=str(e))
raise exception.InvalidObject(schema=schema_name, reason=e.message,
property=get_invalid_property(e))
secret = json_data.get('secret')
if secret is None:
raise exception.InvalidObject(schema=schema_name,
reason=_("'secret' attributes "
"are required"))
"are required"),
property="secret")
# If secret group is provided, validate it now.
self.secret_validator.validate(secret, parent_schema=self.name)
@ -205,7 +221,8 @@ class NewOrderValidator(ValidatorBase):
raise exception.InvalidObject(schema=schema_name,
reason=_("'payload' not "
"allowed for secret "
"generation"))
"generation"),
property="secret")
# Validation secret generation related fields.
# TODO: Invoke the crypto plugin for this purpose
@ -279,6 +296,7 @@ class VerificationValidator(ValidatorBase):
try:
schema.validate(json_data, self.schema)
except schema.ValidationError as e:
raise exception.InvalidObject(schema=schema_name, reason=str(e))
raise exception.InvalidObject(schema=schema_name, reason=e.message,
property=get_invalid_property(e))
return json_data

View File

@ -123,29 +123,34 @@ class WhenTestingSecretValidator(unittest.TestCase):
def test_should_fail_numeric_name(self):
self.secret_req['name'] = 123
with self.assertRaises(excep.InvalidObject):
with self.assertRaises(excep.InvalidObject) as e:
self.validator.validate(self.secret_req)
self.assertEqual('name', e.exception.invalid_property)
def test_should_fail_negative_bit_length(self):
self.secret_req['bit_length'] = -23
with self.assertRaises(excep.InvalidObject):
with self.assertRaises(excep.InvalidObject) as e:
self.validator.validate(self.secret_req)
self.assertEqual('bit_length', e.exception.invalid_property)
def test_should_fail_non_integer_bit_length(self):
self.secret_req['bit_length'] = "23"
with self.assertRaises(excep.InvalidObject):
with self.assertRaises(excep.InvalidObject) as e:
self.validator.validate(self.secret_req)
self.assertEqual('bit_length', e.exception.invalid_property)
def test_validation_should_fail_with_empty_payload(self):
self.secret_req['payload'] = ' '
with self.assertRaises(excep.InvalidObject) as e:
self.validator.validate(self.secret_req)
exception = e.exception
self.assertTrue('payload' in str(exception))
self.assertEqual('payload', e.exception.invalid_property)
def test_should_fail_already_expired(self):
self.secret_req['expiration'] = '2004-02-28T19:14:44.180394'
@ -153,8 +158,7 @@ class WhenTestingSecretValidator(unittest.TestCase):
with self.assertRaises(excep.InvalidObject) as e:
self.validator.validate(self.secret_req)
exception = e.exception
self.assertTrue('expiration' in str(exception))
self.assertEqual('expiration', e.exception.invalid_property)
def test_should_fail_expiration_nonsense(self):
self.secret_req['expiration'] = 'nonsense'
@ -162,8 +166,7 @@ class WhenTestingSecretValidator(unittest.TestCase):
with self.assertRaises(excep.InvalidObject) as e:
self.validator.validate(self.secret_req)
exception = e.exception
self.assertTrue('expiration' in str(exception))
self.assertEqual('expiration', e.exception.invalid_property)
def test_should_fail_all_nulls(self):
self.secret_req = {'name': None,
@ -264,45 +267,48 @@ class WhenTestingOrderValidator(unittest.TestCase):
def test_should_fail_numeric_name(self):
self.secret_req['name'] = 123
with self.assertRaises(excep.InvalidObject):
with self.assertRaises(excep.InvalidObject) as e:
self.validator.validate(self.order_req)
self.assertEqual('name', e.exception.invalid_property)
def test_should_fail_bad_mode(self):
self.secret_req['mode'] = 'badmode'
with self.assertRaises(excep.UnsupportedField) as e:
self.validator.validate(self.order_req)
exception = e.exception
self.assertTrue('mode' in str(exception))
self.assertEqual('mode', e.exception.invalid_field)
def test_should_fail_negative_bit_length(self):
self.secret_req['bit_length'] = -23
with self.assertRaises(excep.InvalidObject):
with self.assertRaises(excep.InvalidObject) as e:
self.validator.validate(self.order_req)
self.assertEqual('bit_length', e.exception.invalid_property)
def test_should_fail_non_integer_bit_length(self):
self.secret_req['bit_length'] = "23"
with self.assertRaises(excep.InvalidObject):
with self.assertRaises(excep.InvalidObject) as e:
self.validator.validate(self.order_req)
self.assertEqual('bit_length', e.exception.invalid_property)
def test_should_fail_non_multiple_eight_bit_length(self):
self.secret_req['bit_length'] = 129
with self.assertRaises(excep.UnsupportedField) as e:
self.validator.validate(self.order_req)
exception = e.exception
self.assertTrue('bit_length' in str(exception))
self.assertEqual('bit_length', e.exception.invalid_field)
def test_should_fail_secret_not_order_schema_provided(self):
with self.assertRaises(excep.InvalidObject) as e:
self.validator.validate(self.secret_req)
exception = e.exception
self.assertTrue('secret' in str(exception))
self.assertEqual('secret', e.exception.invalid_property)
def test_should_fail_payload_provided(self):
self.secret_req['payload'] = ' '
@ -310,8 +316,7 @@ class WhenTestingOrderValidator(unittest.TestCase):
with self.assertRaises(excep.InvalidObject) as e:
self.validator.validate(self.order_req)
exception = e.exception
self.assertTrue('payload' in str(exception))
self.assertTrue('payload' in e.exception.invalid_property)
def test_should_fail_already_expired(self):
self.secret_req['expiration'] = '2004-02-28T19:14:44.180394'
@ -319,8 +324,7 @@ class WhenTestingOrderValidator(unittest.TestCase):
with self.assertRaises(excep.InvalidObject) as e:
self.validator.validate(self.order_req)
exception = e.exception
self.assertTrue('expiration' in str(exception))
self.assertEqual('expiration', e.exception.invalid_property)
def test_should_fail_expiration_nonsense(self):
self.secret_req['expiration'] = 'nonsense'
@ -328,8 +332,7 @@ class WhenTestingOrderValidator(unittest.TestCase):
with self.assertRaises(excep.InvalidObject) as e:
self.validator.validate(self.order_req)
exception = e.exception
self.assertTrue('expiration' in str(exception))
self.assertEqual('expiration', e.exception.invalid_property)
def test_should_fail_all_nulls(self):
self.secret_req = {'name': None,
@ -369,8 +372,7 @@ class WhenTestingOrderValidator(unittest.TestCase):
with self.assertRaises(excep.UnsupportedField) as e:
self.validator.validate(self.order_req)
exception = e.exception
self.assertTrue('mode' in str(exception))
self.assertEqual('mode', e.exception.invalid_field)
def test_should_fail_empty_algorithm(self):
del self.secret_req['algorithm']
@ -378,8 +380,7 @@ class WhenTestingOrderValidator(unittest.TestCase):
with self.assertRaises(excep.UnsupportedField) as e:
self.validator.validate(self.order_req)
exception = e.exception
self.assertTrue('algorithm' in str(exception))
self.assertEqual('algorithm', e.exception.invalid_field)
if __name__ == '__main__':
unittest.main()