Fix more unhandled errors for full validation

Fix some errors that are not being handled for full validation.
They include some invalid node template and outputs property names,
and references to non-existing node templates. Also, add proper
unit tests.

Change-Id: Idba3382f3c8e1fcf6671a166f21ad003fdfbcc6b
Closes-Bug: #1517728
This commit is contained in:
Vahid Hashemian 2015-11-19 11:06:41 -08:00
parent a2c5ba1ab9
commit b27cd33ad8
10 changed files with 68 additions and 27 deletions

View File

@ -53,14 +53,15 @@ class Schema(collections.Mapping):
def __init__(self, name, schema_dict):
self.name = name
if not isinstance(schema_dict, collections.Mapping):
msg = _('Schema "%(pname)s" must be a dict.') % dict(pname=name)
msg = (_('Schema definition of "%(pname)s" must be a dict.')
% dict(pname=name))
ExceptionCollector.appendException(InvalidSchemaError(message=msg))
try:
schema_dict['type']
except KeyError:
msg = (_('Schema "%(pname)s" must have a "type" attribute.')
% dict(pname=name))
msg = (_('Schema definition of "%(pname)s" must have a "type" '
'attribute.') % dict(pname=name))
ExceptionCollector.appendException(InvalidSchemaError(message=msg))
self.schema = schema_dict

View File

@ -26,7 +26,7 @@ class PropertyDef(object):
try:
self.schema['type']
except KeyError:
msg = (_('Property definition of "%(pname)s" must have a "type" '
msg = (_('Schema definition of "%(pname)s" must have a "type" '
'attribute.') % dict(pname=self.name))
ExceptionCollector.appendException(
InvalidSchemaError(message=msg))

View File

@ -42,8 +42,9 @@ class EntityTemplate(object):
self.custom_def = custom_def
self._validate_field(self.entity_tpl)
if entity_name == 'node_type':
self.type_definition = NodeType(self.entity_tpl['type'],
custom_def)
type = self.entity_tpl.get('type')
self.type_definition = NodeType(type, custom_def) \
if type is not None else None
if entity_name == 'relationship_type':
relationship = template.get('relationship')
type = None
@ -62,7 +63,8 @@ class EntityTemplate(object):
@property
def type(self):
return self.type_definition.type
if self.type_definition:
return self.type_definition.type
@property
def requirements(self):

View File

@ -15,6 +15,7 @@ import logging
from toscaparser.common.exception import ExceptionCollector
from toscaparser.common.exception import InvalidPropertyValueError
from toscaparser.common.exception import MissingRequiredFieldError
from toscaparser.common.exception import TypeMismatchError
from toscaparser.common.exception import UnknownFieldError
from toscaparser.dataentity import DataEntity
@ -79,6 +80,13 @@ class NodeTemplate(EntityTemplate):
if (node in list(self.type_definition.TOSCA_DEF.keys())
or node in self.custom_def):
ExceptionCollector.appendException(NotImplementedError(msg))
return
if node not in self.templates:
ExceptionCollector.appendException(
KeyError(_('Node template "%s" was not found.') % node))
return
related_tpl = NodeTemplate(node, self.templates, self.custom_def)
relationship = value.get('relationship') \
if isinstance(value, dict) else None
@ -106,11 +114,18 @@ class NodeTemplate(EntityTemplate):
if not found_relationship_tpl:
if isinstance(relationship, dict):
relationship = relationship.get('type')
if self.available_rel_types and \
relationship in self.available_rel_types.keys():
pass
elif not relationship.startswith(rel_prfx):
relationship = rel_prfx + relationship
if relationship:
if self.available_rel_types and \
relationship in self.available_rel_types.keys():
pass
elif not relationship.startswith(rel_prfx):
relationship = rel_prfx + relationship
else:
ExceptionCollector.appendException(
MissingRequiredFieldError(
what=_('"relationship" used in template '
'"%s"') % related_tpl.name,
required=self.TYPE))
for rtype in self.type_definition.relationship.keys():
if rtype.type == relationship:
explicit_relation[rtype] = related_tpl

View File

@ -89,11 +89,11 @@ class Output(object):
@property
def description(self):
return self.attrs[self.DESCRIPTION]
return self.attrs.get(self.DESCRIPTION)
@property
def value(self):
return self.attrs[self.VALUE]
return self.attrs.get(self.VALUE)
def validate(self):
self._validate_field()
@ -103,9 +103,7 @@ class Output(object):
ExceptionCollector.appendException(
MissingRequiredFieldError(what='Output "%s"' % self.name,
required=self.VALUE))
try:
self.value
except KeyError:
if self.value is None:
ExceptionCollector.appendException(
MissingRequiredFieldError(what='Output "%s"' % self.name,
required=self.VALUE))

View File

@ -73,7 +73,7 @@ topology_template:
db_root_password: { get_property: [ mysql_dbms, root_password ] }
mysql_dbms:
type: tosca.nodes.DBMS
type1: tosca.nodes.DBMS
properties:
root_password: { get_input: db_root_pwd }
port: { get_input: db_port }
@ -94,7 +94,11 @@ topology_template:
webserver:
type: tosca.nodes.WebServer
requirements:
- host: server
- host: server1
- database_endpoint:
node: webserver
relationship:
type1: tosca.relationships.ConnectsTo
interfaces:
Standard:
create: webserver/webserver_install.sh

View File

@ -47,7 +47,8 @@ class ConstraintTest(TestCase):
schema = yamlparser.simple_parse(tpl_snippet)
error = self.assertRaises(exception.InvalidSchemaError, Schema,
'cpus', schema['cpus'])
self.assertEqual(_('Schema "cpus" must be a dict.'), str(error))
self.assertEqual(_('Schema definition of "cpus" must be a dict.'),
str(error))
def test_schema_miss_type(self):
tpl_snippet = '''
@ -57,8 +58,8 @@ class ConstraintTest(TestCase):
schema = yamlparser.simple_parse(tpl_snippet)
error = self.assertRaises(exception.InvalidSchemaError, Schema,
'cpus', schema['cpus'])
self.assertEqual(_('Schema "cpus" must have a "type" attribute.'),
str(error))
self.assertEqual(_('Schema definition of "cpus" must have a "type" '
'attribute.'), str(error))
def test_schema_none_description(self):
tpl_snippet = '''

View File

@ -232,5 +232,5 @@ class PropertyTest(TestCase):
schema = yamlparser.simple_parse(tpl_snippet)
error = self.assertRaises(exception.InvalidSchemaError, PropertyDef,
'prop', None, schema['properties']['prop'])
self.assertEqual(_('Property definition of "prop" '
'must have a "type" attribute.'), str(error))
self.assertEqual(_('Schema definition of "prop" must have a "type" '
'attribute.'), str(error))

View File

@ -490,6 +490,25 @@ class ToscaTemplateTest(TestCase):
exception.ExceptionCollector.assertExceptionMessage(
KeyError, err5_msg)
err6_msg = _('Template "mysql_dbms" is missing required field "type".')
exception.ExceptionCollector.assertExceptionMessage(
exception.MissingRequiredFieldError, err6_msg)
err7_msg = _('Node template "mysql_dbms" contains unknown field '
'"type1". Refer to the definition to verify valid '
'values.')
exception.ExceptionCollector.assertExceptionMessage(
exception.UnknownFieldError, err7_msg)
err8_msg = _('\'Node template "server1" was not found.\'')
exception.ExceptionCollector.assertExceptionMessage(
KeyError, err8_msg)
err9_msg = _('"relationship" used in template "webserver" is missing '
'required field "type".')
exception.ExceptionCollector.assertExceptionMessage(
exception.MissingRequiredFieldError, err9_msg)
def test_invalid_section_names(self):
tosca_tpl = os.path.join(
os.path.dirname(os.path.abspath(__file__)),

View File

@ -72,9 +72,10 @@ class TopologyTemplate(object):
tpl = NodeTemplate(name, tpls, self.custom_defs,
self.relationship_templates,
self.rel_types)
if (tpl.type in tpl.type_definition.TOSCA_DEF or
(tpl.type not in tpl.type_definition.TOSCA_DEF and
bool(tpl.custom_def))):
if (tpl.type_definition and
(tpl.type in tpl.type_definition.TOSCA_DEF or
(tpl.type not in tpl.type_definition.TOSCA_DEF and
bool(tpl.custom_def)))):
tpl.validate(self)
nodetemplates.append(tpl)
return nodetemplates