Merge "Add function to perform profile validation"

This commit is contained in:
Jenkins 2016-08-19 09:12:59 +00:00 committed by Gerrit Code Review
commit cfb3def6d1
4 changed files with 84 additions and 4 deletions

View File

@ -334,7 +334,7 @@ class EngineService(service.Service):
return [p.to_dict() for p in profiles]
def _validate_profile(self, context, spec, name=None,
metadata=None):
metadata=None, validate_props=False):
"""Validate a profile.
:param context: An instance of the request context.
@ -342,6 +342,8 @@ class EngineService(service.Service):
:param spec: A dictionary containing the spec for the profile.
:param metadata: A dictionary containing optional key-value pairs to
be associated with the profile.
:param validate_props: Whether to validate if provide a valid Value
to property.
:return: Validated profile object.
"""
type_name, version = schema.get_spec_version(spec)
@ -363,7 +365,7 @@ class EngineService(service.Service):
name = 'validated_profile'
profile = plugin(name, spec, **kwargs)
try:
profile.validate()
profile.validate(validate_props=validate_props)
except exception.InvalidSpec as ex:
msg = six.text_type(ex)
LOG.error(_LE("Failed in validating profile: %s"), msg)
@ -402,6 +404,19 @@ class EngineService(service.Service):
return profile.to_dict()
@request_context
def profile_validate(self, context, spec):
"""Validate a profile with the given properties.
:param context: An instance of the request context.
:param spec: A dictionary containing the spec for the profile.
:return: A dictionary containing the details of the profile object
validated.
"""
profile = self._validate_profile(context, spec, validate_props=True)
return profile.to_dict()
@request_context
def profile_get(self, context, identity):
"""Retrieve the details about a profile.

View File

@ -231,7 +231,7 @@ class Profile(object):
profile = cls.load(ctx, profile_id=obj.profile_id)
return profile.do_recover(obj, **options)
def validate(self):
def validate(self, validate_props=False):
'''Validate the schema and the data provided.'''
# general validation
self.spec_data.validate()
@ -239,6 +239,9 @@ class Profile(object):
# TODO(Anyone): need to check the contents in self.CONTEXT
if validate_props:
self.do_validate(obj=self.context)
@classmethod
def get_schema(cls):
return dict((name, dict(schema))
@ -336,6 +339,11 @@ class Profile(object):
return res
def do_validate(self, obj):
"""For subclass to override."""
LOG.warning(_LW("Validate operation not supported."))
return True
def to_dict(self):
pb_dict = {
'id': self.id,

View File

@ -283,6 +283,47 @@ class ProfileTest(base.SenlinTestCase):
self.assertEqual('BOOM',
six.text_type(ex.exc_info[1]))
def test_profile_validate_pass(self):
self._setup_fakes()
expected_resp = {
'created_at': None,
'domain': '',
'id': None,
'metadata': None,
'name': 'validated_profile',
'project': 'profile_test_project',
'type': 'TestProfile-1.0',
'updated_at': None,
'user': 'test_user_id',
'spec': {
'type': 'TestProfile',
'version': '1.0',
'properties': {
'INT': 1,
'STR': 'str',
'LIST': ['v1', 'v2'],
'MAP': {'KEY1': 1, 'KEY2': 'v2'},
}
}
}
resp = self.eng.profile_validate(self.ctx, self.spec)
self.assertEqual(expected_resp, resp)
def test_profile_validate_failed(self):
self._setup_fakes()
mock_do_validate = self.patchobject(fakes.TestProfile, 'do_validate')
mock_do_validate.side_effect = exc.InvalidSpec(message='BOOM')
ex = self.assertRaises(rpc.ExpectedException,
self.eng.profile_validate,
self.ctx, self.spec)
self.assertEqual(exc.SpecValidationFailed, ex.exc_info[0])
self.assertEqual('BOOM',
six.text_type(ex.exc_info[1]))
@mock.patch.object(pb.Profile, 'load')
@mock.patch.object(service.EngineService, 'profile_find')
def test_profile_get(self, mock_find, mock_load):

View File

@ -488,16 +488,31 @@ class TestProfileBase(base.SenlinTestCase):
res_obj = profile.do_leave.return_value
self.assertEqual(res_obj, res)
def test_validate(self):
def test_validate_without_properties(self):
profile = self._create_profile('test_profile')
profile.spec_data = mock.Mock()
profile.properties = mock.Mock()
profile.do_validate = mock.Mock()
profile.validate()
profile.spec_data.validate.assert_called_once_with()
profile.properties.validate.assert_called_once_with()
profile.do_validate.assert_not_called()
def test_validate_with_properties(self):
profile = self._create_profile('test_profile')
profile.spec_data = mock.Mock()
profile.properties = mock.Mock()
profile.do_validate = mock.Mock()
profile.validate(validate_props=True)
profile.spec_data.validate.assert_called_once_with()
profile.properties.validate.assert_called_once_with()
profile.do_validate.assert_called_once_with(obj=profile.context)
@mock.patch.object(senlin_ctx, 'get_service_context')
def test__init_context(self, mock_get):
@ -609,6 +624,7 @@ class TestProfileBase(base.SenlinTestCase):
self.assertEqual(True, profile.do_join(mock.Mock(), mock.Mock()))
self.assertEqual(True, profile.do_leave(mock.Mock()))
self.assertEqual(True, profile.do_rebuild(mock.Mock()))
self.assertEqual(True, profile.do_validate(mock.Mock()))
def test_do_recover_default(self):
profile = self._create_profile('test-profile')