Merge "template syntax validation - adding error_messages dict"

This commit is contained in:
Jenkins 2016-05-22 13:12:54 +00:00 committed by Gerrit Code Review
commit 6cec6bbf03
3 changed files with 149 additions and 196 deletions

View File

@ -0,0 +1,61 @@
# Copyright 2015 - Nokia
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from vitrage.common.constants import entities_categories
error_msgs = {
# General 1-19
1: '"template_id" field contains incorrect string value',
2: 'value must be from dict type',
3: 'value must be from list type',
# definitions section 20-39
20: 'definitions section must contain "entities" Field.',
21: '"definitions" is mandatory section in template file.',
# Entities syntax error messages 40-59
40: '"type" field in entity definition must be a string',
41: 'Entity definition must contain "template_id" Field.',
42: 'Entity definition must contain "category" Field.',
43: 'At least one entity must be defined.',
44: 'Entity must refer to dictionary.',
45: 'Invalid entity category. Category must be from types: '
'%s' % entities_categories,
46: 'Entity field is required.',
# metadata section syntax error messages 60-79
60: 'metadata section must contain "id" field.',
61: '"description" field in metadata section must be a string',
62: '"metadata" is mandatory section in template file.',
# scenarios section 80-99
80: '"scenarios" is mandatory section in template file.',
81: 'At least one scenario must be defined.',
82: 'scenario field is required.',
83: 'Entity definition must contain "condition" field.',
84: 'Entity definition must contain "actions" field.',
# relationships syntax error messages 100-119
100: 'Relationship must refer to dictionary.',
101: 'Relationship field is required.',
102: 'Relationship definition must contain "source" field.',
103: 'Relationship definition must contain "target" field.',
104: 'Relationship definition must contain "template_id" field.',
# actions syntax error messages 120-139
121: 'At least one action must be defined.',
122: 'Action field is required.',
123: 'Relationship definition must contain "action_type" Field.',
124: 'Relationship definition must contain "action_target" Field.',
}

View File

@ -20,19 +20,13 @@ from voluptuous import Required
from voluptuous import Schema
from vitrage.evaluator.template_fields import TemplateFields
from vitrage.evaluator.template_validation.error_messages import error_msgs
from vitrage.evaluator.template_validation.utils import Result
LOG = log.getLogger(__name__)
MANDATORY_SECTIONS_ERROR = '"definitions", "metadata" and "scenarios are ' \
'mandatory sections in template file.'
ELEMENTS_MIN_NUM_ERROR = 'At least one %s must be defined.'
DICT_STRUCTURE_SCHEMA_ERROR = '%s must refer to dictionary.'
SCHEMA_CONTENT_ERROR = '%s must contain %s Fields.'
RESULT_DESCRIPTION = 'template syntax validation'
RESULT_DESCRIPTION = 'Template syntax validation'
def syntax_validation(template_conf):
@ -57,39 +51,31 @@ def syntax_validation(template_conf):
def validate_template_sections(template_conf):
schema = Schema({
Required(TemplateFields.DEFINITIONS): dict,
Required(TemplateFields.METADATA): dict,
Required(TemplateFields.SCENARIOS): list
Required(TemplateFields.DEFINITIONS, msg=error_msgs[21]): dict,
Required(TemplateFields.METADATA, msg=error_msgs[62]): dict,
Required(TemplateFields.SCENARIOS, msg=error_msgs[80]): list
})
return _validate_dict_schema(schema,
template_conf,
MANDATORY_SECTIONS_ERROR)
return _validate_dict_schema(schema, template_conf)
def validate_metadata_section(metadata):
schema = Schema({
Required(TemplateFields.ID): Any(str, six.text_type),
TemplateFields.DESCRIPTION: Any(str, six.text_type)
})
any_str = Any(str, six.text_type)
error_msg = SCHEMA_CONTENT_ERROR % (
TemplateFields.METADATA, TemplateFields.ID)
return _validate_dict_schema(schema, metadata, error_msg)
schema = Schema({
Required(TemplateFields.ID, msg=error_msgs[60]): any_str,
TemplateFields.DESCRIPTION: any_str
})
return _validate_dict_schema(schema, metadata)
def validate_definitions_section(definitions):
schema = Schema({
Required(TemplateFields.ENTITIES): list,
Required(TemplateFields.ENTITIES, error_msgs[20]): list,
TemplateFields.RELATIONSHIPS: list
})
error_msg = SCHEMA_CONTENT_ERROR % (
TemplateFields.DEFINITIONS,
'"%s"' % TemplateFields.ENTITIES
)
result = _validate_dict_schema(schema, definitions, error_msg)
result = _validate_dict_schema(schema, definitions)
if result.is_valid:
result = validate_entities(definitions[TemplateFields.ENTITIES])
@ -104,18 +90,15 @@ def validate_definitions_section(definitions):
def validate_entities(entities):
if len(entities) <= 0:
error_msg = ELEMENTS_MIN_NUM_ERROR % TemplateFields.ENTITY
LOG.error(error_msg)
return _get_fault_result(error_msg)
LOG.error(error_msgs[43])
return _get_fault_result(error_msgs[43])
for entity in entities:
schema = Schema({
Required(TemplateFields.ENTITY): dict,
Required(TemplateFields.ENTITY, msg=error_msgs[46]): dict,
})
error_msg = DICT_STRUCTURE_SCHEMA_ERROR % TemplateFields.ENTITY
result = _validate_dict_schema(schema, entity, error_msg)
result = _validate_dict_schema(schema, entity)
if result.is_valid:
result = validate_entity_dict(entity[TemplateFields.ENTITY])
@ -128,18 +111,14 @@ def validate_entities(entities):
def validate_entity_dict(entity_dict):
any_str = Any(str, six.text_type)
schema = Schema({
Required(TemplateFields.CATEGORY): Any(str, six.text_type),
TemplateFields.TYPE: Any(str, six.text_type),
Required(TemplateFields.TEMPLATE_ID): Any(str, six.text_type, int)
Required(TemplateFields.CATEGORY, msg=error_msgs[42]): any_str,
TemplateFields.TYPE: any_str,
Required(TemplateFields.TEMPLATE_ID, msg=error_msgs[41]): any_str
}, extra=True)
error_msg = SCHEMA_CONTENT_ERROR % (
TemplateFields.ENTITY,
'"%s" and "%s"' % (TemplateFields.CATEGORY,
TemplateFields.TEMPLATE_ID)
)
return _validate_dict_schema(schema, entity_dict, error_msg)
return _validate_dict_schema(schema, entity_dict)
def validate_relationships(relationships):
@ -147,10 +126,9 @@ def validate_relationships(relationships):
for relationship in relationships:
schema = Schema({
Required(TemplateFields.RELATIONSHIP): dict,
Required(TemplateFields.RELATIONSHIP, msg=error_msgs[101]): dict,
})
error_msg = DICT_STRUCTURE_SCHEMA_ERROR % TemplateFields.RELATIONSHIP
result = _validate_dict_schema(schema, relationship, error_msg)
result = _validate_dict_schema(schema, relationship)
if result.is_valid:
relationship_dict = relationship[TemplateFields.RELATIONSHIP]
@ -158,43 +136,33 @@ def validate_relationships(relationships):
if not result.is_valid:
return result
return result
def validate_relationship_dict(relationship_dict):
any_str = Any(str, six.text_type)
schema = Schema({
Required(TemplateFields.SOURCE): Any(str, six.text_type, int),
Required(TemplateFields.TARGET): Any(str, six.text_type, int),
Required(TemplateFields.SOURCE, msg=error_msgs[102]): any_str,
Required(TemplateFields.TARGET, msg=error_msgs[103]): any_str,
TemplateFields.RELATIONSHIP_TYPE: Any(str, six.text_type),
Required(TemplateFields.TEMPLATE_ID): Any(str, six.text_type, int)
Required(TemplateFields.TEMPLATE_ID, msg=error_msgs[104]): any_str
})
error_msg = SCHEMA_CONTENT_ERROR % (
TemplateFields.RELATIONSHIP, '"%s", "%s" and "%s"' % (
TemplateFields.SOURCE,
TemplateFields.TARGET,
TemplateFields.TEMPLATE_ID
)
)
return _validate_dict_schema(schema, relationship_dict, error_msg)
return _validate_dict_schema(schema, relationship_dict)
def validate_scenarios_section(scenarios):
if len(scenarios) <= 0:
error_msg = ELEMENTS_MIN_NUM_ERROR % TemplateFields.SCENARIO
LOG.error(error_msg)
return _get_fault_result(error_msg)
LOG.error(error_msgs[81])
return _get_fault_result(error_msgs[81])
for scenario in scenarios:
schema = Schema({
Required(TemplateFields.SCENARIO): dict,
Required(TemplateFields.SCENARIO, msg=error_msgs[82]): dict,
})
error_msg = DICT_STRUCTURE_SCHEMA_ERROR % TemplateFields.SCENARIO
result = _validate_dict_schema(schema, scenario, error_msg)
result = _validate_dict_schema(schema, scenario)
if result.is_valid:
result = validate_scenario(scenario[TemplateFields.SCENARIO])
@ -207,16 +175,12 @@ def validate_scenarios_section(scenarios):
def validate_scenario(scenario):
any_str = Any(str, six.text_type)
schema = Schema({
Required(TemplateFields.CONDITION): Any(str, six.text_type),
Required(TemplateFields.ACTIONS): list
Required(TemplateFields.CONDITION, msg=error_msgs[83]): any_str,
Required(TemplateFields.ACTIONS, msg=error_msgs[84]): list
})
error_msg = SCHEMA_CONTENT_ERROR % (
TemplateFields.SCENARIOS,
'"%s" and "%s"' % (TemplateFields.CONDITION, TemplateFields.ACTIONS)
)
result = _validate_dict_schema(schema, scenario, error_msg)
result = _validate_dict_schema(schema, scenario)
if result.is_valid:
return validate_actions_schema(scenario[TemplateFields.ACTIONS])
@ -227,17 +191,15 @@ def validate_scenario(scenario):
def validate_actions_schema(actions):
if len(actions) <= 0:
error_msg = ELEMENTS_MIN_NUM_ERROR % TemplateFields.ACTION
LOG.error(error_msg)
return _get_fault_result(error_msg)
LOG.error(error_msgs[121])
return _get_fault_result(error_msgs[121])
for action in actions:
schema = Schema({
Required(TemplateFields.ACTION): dict,
Required(TemplateFields.ACTION, msg=error_msgs[122]): dict,
})
error_msg = DICT_STRUCTURE_SCHEMA_ERROR % TemplateFields.ACTION
result = _validate_dict_schema(schema, action, error_msg)
result = _validate_dict_schema(schema, action)
if result.is_valid:
result = validate_action_schema(action[TemplateFields.ACTION])
@ -250,29 +212,22 @@ def validate_actions_schema(actions):
def validate_action_schema(action):
any_str = Any(str, six.text_type)
schema = Schema({
Required(TemplateFields.ACTION_TYPE): Any(str, six.text_type),
Required(TemplateFields.ACTION_TYPE, msg=error_msgs[123]): any_str,
TemplateFields.PROPERTIES: dict,
Required(TemplateFields.ACTION_TARGET): dict
Required(TemplateFields.ACTION_TARGET, msg=error_msgs[124]): dict
})
error_msg = SCHEMA_CONTENT_ERROR % (
TemplateFields.ACTION,
'"%s" and "%s"' % (
TemplateFields.ACTION_TYPE,
TemplateFields.ACTION_TARGET
)
)
return _validate_dict_schema(schema, action, error_msg)
return _validate_dict_schema(schema, action)
def _validate_dict_schema(schema, value, error_msg):
def _validate_dict_schema(schema, value):
try:
schema(value)
except Error as e:
LOG.error('%s %s' % (error_msg, e))
return _get_fault_result(error_msg)
LOG.error(e)
return _get_fault_result(e)
return _get_correct_result()

View File

@ -17,13 +17,8 @@ from oslo_log import log as logging
from vitrage.common import file_utils
from vitrage.evaluator.template_fields import TemplateFields
from vitrage.evaluator.template_validation.error_messages import error_msgs
from vitrage.evaluator.template_validation import template_syntax_validator
from vitrage.evaluator.template_validation.template_syntax_validator import \
ELEMENTS_MIN_NUM_ERROR
from vitrage.evaluator.template_validation.template_syntax_validator import \
MANDATORY_SECTIONS_ERROR
from vitrage.evaluator.template_validation.template_syntax_validator import \
SCHEMA_CONTENT_ERROR
from vitrage.tests import base
from vitrage.tests.mocks import utils
@ -54,181 +49,123 @@ class TemplateSyntaxValidatorTest(base.BaseTest):
template = self.clone_template
template.pop(TemplateFields.METADATA)
self._test_execution(template, MANDATORY_SECTIONS_ERROR)
self._test_execution(template, error_msgs[62])
def test_validate_template_without_id_in_metadata_section(self):
template = self.clone_template
template[TemplateFields.METADATA].pop(TemplateFields.ID)
expected_comment = SCHEMA_CONTENT_ERROR % (
TemplateFields.METADATA, TemplateFields.ID)
self._test_execution(template, expected_comment)
self._test_execution(template, error_msgs[60])
def test_validate_template_without_definitions_section(self):
template = self.clone_template
template.pop(TemplateFields.DEFINITIONS)
self._test_execution(template, MANDATORY_SECTIONS_ERROR)
self._test_execution(template, error_msgs[21])
def test_validate_template_without_entities(self):
template = self.clone_template
template[TemplateFields.DEFINITIONS].pop(TemplateFields.ENTITIES)
expected_comment = SCHEMA_CONTENT_ERROR % (
TemplateFields.DEFINITIONS,
'"%s"' % TemplateFields.ENTITIES
)
self._test_execution(template, expected_comment)
self._test_execution(template, error_msgs[20])
def test_validate_template_with_empty_entities(self):
# Test setup
template = self.clone_template
template[TemplateFields.DEFINITIONS][TemplateFields.ENTITIES] = []
expected_comment = ELEMENTS_MIN_NUM_ERROR % TemplateFields.ENTITY
self._test_execution(template, expected_comment)
self._test_execution(template, error_msgs[43])
def test_validate_entity_without_required_fields(self):
self._validate_entity_without_missing_required_field(
TemplateFields.CATEGORY)
self._validate_entity_without_required_field(
TemplateFields.CATEGORY,
error_msgs[42])
self._validate_entity_without_missing_required_field(
TemplateFields.TEMPLATE_ID)
self._validate_entity_without_required_field(
TemplateFields.TEMPLATE_ID,
error_msgs[41])
def _validate_entity_without_missing_required_field(self, field_name):
# Test setup
def _validate_entity_without_required_field(self,
field_name,
expected_comment):
template = self.clone_template
definitions = template[TemplateFields.DEFINITIONS]
entity = definitions[TemplateFields.ENTITIES][0]
entity[TemplateFields.ENTITY].pop(field_name)
expected_comment = SCHEMA_CONTENT_ERROR % (
TemplateFields.ENTITY,
'"%s" and "%s"' % (TemplateFields.CATEGORY,
TemplateFields.TEMPLATE_ID)
)
self._test_execution(template, expected_comment)
def test_validate_relationships_without_required_fields(self):
self._validate_relationships_with_missing_required_field(
TemplateFields.SOURCE)
TemplateFields.SOURCE, error_msgs[102])
self._validate_relationships_with_missing_required_field(
TemplateFields.TARGET)
TemplateFields.TARGET, error_msgs[103])
self._validate_relationships_with_missing_required_field(
TemplateFields.TEMPLATE_ID)
TemplateFields.TEMPLATE_ID, error_msgs[104])
def _validate_relationships_with_missing_required_field(self, field_name):
# Test setup
def _validate_relationships_with_missing_required_field(self,
field_name,
expected_comment):
template = self.clone_template
definitions = template[TemplateFields.DEFINITIONS]
relationship = definitions[TemplateFields.RELATIONSHIPS][0]
relationship[TemplateFields.RELATIONSHIP].pop(field_name)
expected_comment = SCHEMA_CONTENT_ERROR % (
TemplateFields.RELATIONSHIP, '"%s", "%s" and "%s"' % (
TemplateFields.SOURCE,
TemplateFields.TARGET,
TemplateFields.TEMPLATE_ID
)
)
self._test_execution(template, expected_comment)
def test_validate_template_without_scenarios_section(self):
# Test setup
template = self.clone_template
template.pop(TemplateFields.SCENARIOS)
self._test_execution(template, MANDATORY_SECTIONS_ERROR)
self._test_execution(template, error_msgs[80])
def test_validate_template_with_empty_scenarios(self):
# Test setup
template = self.clone_template
template[TemplateFields.SCENARIOS] = []
expected_comment = ELEMENTS_MIN_NUM_ERROR % TemplateFields.SCENARIO
self._test_execution(template, expected_comment)
self._test_execution(template, error_msgs[81])
def test_validate_scenario_without_required_condition_field(self):
# Test setup
template = self.clone_template
scenario = template[TemplateFields.SCENARIOS][0]
scenario[TemplateFields.SCENARIO].pop(TemplateFields.CONDITION)
expected_comment = SCHEMA_CONTENT_ERROR % (
TemplateFields.SCENARIOS,
'"%s" and "%s"' % (TemplateFields.CONDITION,
TemplateFields.ACTIONS)
)
self._test_execution(template, expected_comment)
self._test_execution(template, error_msgs[83])
def test_validate_scenario_without_required_actions_field(self):
# Test setup
template = self.clone_template
scenario = template[TemplateFields.SCENARIOS][0]
scenario[TemplateFields.SCENARIO].pop(TemplateFields.ACTIONS)
expected_comment = SCHEMA_CONTENT_ERROR % (
TemplateFields.SCENARIOS,
'"%s" and "%s"' % (TemplateFields.CONDITION,
TemplateFields.ACTIONS)
)
self._test_execution(template, expected_comment)
self._test_execution(template, error_msgs[84])
def test_validate_template_with_no_actions(self):
# Test setup
template = self.clone_template
scenario = template[TemplateFields.SCENARIOS][0]
scenario[TemplateFields.SCENARIO][TemplateFields.ACTIONS] = []
expected_comment = ELEMENTS_MIN_NUM_ERROR % TemplateFields.ACTION
self._test_execution(template, error_msgs[121])
self._test_execution(template, expected_comment)
def _test_validate_action_without_required_fields(self):
def test_validate_action_without_required_action_target_field(self):
self._test_validate_action_without_required_field(
TemplateFields.ACTION_TYPE,
error_msgs[123])
# Test setup
self._test_validate_action_without_required_field(
TemplateFields.ACTION_TARGET,
error_msgs[124])
def _test_validate_action_without_required_field(self,
field_name,
expected_comment):
template = self.clone_template
scenario = template[TemplateFields.SCENARIOS][0]
action = scenario[TemplateFields.SCENARIO][TemplateFields.ACTIONS][0]
action[TemplateFields.ACTION].pop(TemplateFields.ACTION_TARGET)
expected_comment = SCHEMA_CONTENT_ERROR % (
TemplateFields.ACTION, '"%s" and "%s"' % (
TemplateFields.ACTION_TYPE, TemplateFields.ACTION_TARGET)
)
self._test_execution(template, expected_comment)
def test_validate_action_without_required_action_type_field(self):
# Test setup
template = self.clone_template
scenario = template[TemplateFields.SCENARIOS][0]
action = scenario[TemplateFields.SCENARIO][TemplateFields.ACTIONS][0]
action[TemplateFields.ACTION].pop(TemplateFields.ACTION_TYPE)
expected_comment = SCHEMA_CONTENT_ERROR % (
TemplateFields.ACTION, '"%s" and "%s"' % (
TemplateFields.ACTION_TYPE, TemplateFields.ACTION_TARGET)
)
action[TemplateFields.ACTION].pop(field_name)
self._test_execution(template, expected_comment)
def _test_execution(self, template, expected_comment):
@ -238,4 +175,4 @@ class TemplateSyntaxValidatorTest(base.BaseTest):
# Test assertions
self.assertFalse(result.is_valid)
self.assertEqual(expected_comment, result.comment)
self.assertTrue(str(result.comment).startswith(expected_comment))