Add Schema parent class for Property, Input, Output
Add a Schema class that handle all schema-related information (description, type, constraints, required etc) of Property, Input, Output. Change-Id: Ic4e4e5e1a5fa29fc3d668c295d6b2ea85eecb0cd Closes-Bug:#1349457
This commit is contained in:
parent
ccefa3514e
commit
853fb5c2b6
@ -65,11 +65,8 @@ class TranslateInputs():
|
||||
hot_constraints = []
|
||||
if input.constraints:
|
||||
for constraint in input.constraints:
|
||||
for name, value in constraint.items():
|
||||
constraint_name = name
|
||||
value = value
|
||||
hc, hvalue = self._translate_constraints(constraint_name,
|
||||
value)
|
||||
hc, hvalue = self._translate_constraints(
|
||||
constraint.constraint_key, constraint.constraint_value)
|
||||
hot_constraints.append({hc: hvalue})
|
||||
cli_value = self.parsed_params[input.name]
|
||||
hot_inputs.append(HotParameter(name=input.name,
|
||||
|
@ -72,3 +72,11 @@ class TypeMismatchError(TOSCAException):
|
||||
|
||||
class InvalidNodeTypeError(TOSCAException):
|
||||
msg_fmt = _('Node type "%(what)s" is not a valid type.')
|
||||
|
||||
|
||||
class InvalidSchemaError(TOSCAException):
|
||||
msg_fmt = _("%(message)s")
|
||||
|
||||
|
||||
class ValidationError(TOSCAException):
|
||||
msg_fmt = _("%(message)s")
|
||||
|
@ -18,16 +18,86 @@ import datetime
|
||||
import numbers
|
||||
import re
|
||||
|
||||
from translator.toscalib.common.exception import InvalidSchemaError
|
||||
from translator.toscalib.common.exception import ValidationError
|
||||
from translator.toscalib.utils.gettextutils import _
|
||||
|
||||
|
||||
class ValidationError(Exception):
|
||||
class Schema(collections.Mapping):
|
||||
|
||||
def __init__(self, message):
|
||||
self.message = message
|
||||
KEYS = (
|
||||
TYPE, REQUIRED, DESCRIPTION, DEFAULT, CONSTRAINTS,
|
||||
) = (
|
||||
'type', 'required', 'description', 'default', 'constraints'
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return str(self.message)
|
||||
PROPERTY_TYPES = (
|
||||
INTEGER, STRING, BOOLEAN,
|
||||
FLOAT, TIMESTAMP
|
||||
) = (
|
||||
'integer', 'string', 'boolean',
|
||||
'float', 'timestamp'
|
||||
)
|
||||
|
||||
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)
|
||||
raise InvalidSchemaError(message=msg)
|
||||
|
||||
try:
|
||||
schema_dict['type']
|
||||
except KeyError:
|
||||
msg = _("Schema %(pname)s must have type.") % dict(pname=name)
|
||||
raise InvalidSchemaError(message=msg)
|
||||
|
||||
self.schema = schema_dict
|
||||
self._len = None
|
||||
self.constraints_list = []
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
return self.schema[self.TYPE]
|
||||
|
||||
@property
|
||||
def required(self):
|
||||
return self.schema.get(self.REQUIRED, False)
|
||||
|
||||
@property
|
||||
def description(self):
|
||||
return self.schema.get(self.DESCRIPTION, '')
|
||||
|
||||
@property
|
||||
def default(self):
|
||||
return self.schema.get(self.DEFAULT)
|
||||
|
||||
@property
|
||||
def constraints(self):
|
||||
if not self.constraints_list:
|
||||
constraint_schemata = self.schema.get(self.CONSTRAINTS)
|
||||
if constraint_schemata:
|
||||
self.constraints_list = [Constraint(self.name,
|
||||
self.type,
|
||||
cschema)
|
||||
for cschema in constraint_schemata]
|
||||
return self.constraints_list
|
||||
|
||||
def __getitem__(self, key):
|
||||
return self.schema[key]
|
||||
|
||||
def __iter__(self):
|
||||
for k in self.KEYS:
|
||||
try:
|
||||
self.schema[k]
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
yield k
|
||||
|
||||
def __len__(self):
|
||||
if self._len is None:
|
||||
self._len = len(list(iter(self)))
|
||||
return self._len
|
||||
|
||||
|
||||
class Constraint(object):
|
||||
@ -40,27 +110,19 @@ class Constraint(object):
|
||||
'less_or_equal', 'in_range', 'valid_values', 'length',
|
||||
'min_length', 'max_length', 'pattern')
|
||||
|
||||
PROPERTY_TYPES = (
|
||||
INTEGER, STRING, BOOLEAN,
|
||||
FLOAT, TIMESTAMP
|
||||
) = (
|
||||
'integer', 'string', 'boolean',
|
||||
'float', 'timestamp'
|
||||
)
|
||||
|
||||
def __new__(cls, property_name, property_type, constraint):
|
||||
if cls is not Constraint:
|
||||
return super(Constraint, cls).__new__(cls)
|
||||
|
||||
if(not isinstance(constraint, collections.Mapping) or
|
||||
len(constraint) != 1):
|
||||
raise ValidationError(_('Invalid constraint schema.'))
|
||||
raise InvalidSchemaError(message=_('Invalid constraint schema.'))
|
||||
|
||||
for type in constraint.keys():
|
||||
ConstraintClass = get_constraint_class(type)
|
||||
if not ConstraintClass:
|
||||
raise ValidationError(_('Invalid constraint type "%s".') %
|
||||
type)
|
||||
msg = _('Invalid constraint type "%s".') % type
|
||||
raise InvalidSchemaError(message=msg)
|
||||
|
||||
return ConstraintClass(property_name, property_type, constraint)
|
||||
|
||||
@ -70,10 +132,11 @@ class Constraint(object):
|
||||
self.constraint_value = constraint[self.constraint_key]
|
||||
# check if constraint is valid for property type
|
||||
if property_type not in self.valid_prop_types:
|
||||
raise ValidationError(_('Constraint type "%(ctype)s" is not valid '
|
||||
'for data type "%(dtype)s".') %
|
||||
{'ctype': self.constraint_key,
|
||||
'dtype': property_type})
|
||||
msg = _('Constraint type "%(ctype)s" is not valid '
|
||||
'for data type "%(dtype)s".') % dict(
|
||||
ctype=self.constraint_key,
|
||||
dtype=property_type)
|
||||
raise InvalidSchemaError(message=msg)
|
||||
|
||||
def _err_msg(self, value):
|
||||
return _('Property %s could not be validated.') % self.property_name
|
||||
@ -81,7 +144,7 @@ class Constraint(object):
|
||||
def validate(self, value):
|
||||
if not self._is_valid(value):
|
||||
err_msg = self._err_msg(value)
|
||||
raise ValidationError(err_msg)
|
||||
raise ValidationError(message=err_msg)
|
||||
|
||||
@staticmethod
|
||||
def validate_integer(value):
|
||||
@ -125,7 +188,7 @@ class Equal(Constraint):
|
||||
|
||||
constraint_key = Constraint.EQUAL
|
||||
|
||||
valid_prop_types = Constraint.PROPERTY_TYPES
|
||||
valid_prop_types = Schema.PROPERTY_TYPES
|
||||
|
||||
def _is_valid(self, value):
|
||||
if value == self.constraint_value:
|
||||
@ -152,14 +215,15 @@ class GreaterThan(Constraint):
|
||||
valid_types = (int, float, datetime.date,
|
||||
datetime.time, datetime.datetime)
|
||||
|
||||
valid_prop_types = (Constraint.INTEGER, Constraint.FLOAT,
|
||||
Constraint.TIMESTAMP)
|
||||
valid_prop_types = (Schema.INTEGER, Schema.FLOAT,
|
||||
Schema.TIMESTAMP)
|
||||
|
||||
def __init__(self, property_name, property_type, constraint):
|
||||
super(GreaterThan, self).__init__(property_name, property_type,
|
||||
constraint)
|
||||
if not isinstance(constraint[self.GREATER_THAN], self.valid_types):
|
||||
raise ValidationError(_('greater_than must be comparable.'))
|
||||
raise InvalidSchemaError(message=_('greater_than must '
|
||||
'be comparable.'))
|
||||
|
||||
def _is_valid(self, value):
|
||||
if value > self.constraint_value:
|
||||
@ -186,14 +250,15 @@ class GreaterOrEqual(Constraint):
|
||||
valid_types = (int, float, datetime.date,
|
||||
datetime.time, datetime.datetime)
|
||||
|
||||
valid_prop_types = (Constraint.INTEGER, Constraint.FLOAT,
|
||||
Constraint.TIMESTAMP)
|
||||
valid_prop_types = (Schema.INTEGER, Schema.FLOAT,
|
||||
Schema.TIMESTAMP)
|
||||
|
||||
def __init__(self, property_name, property_type, constraint):
|
||||
super(GreaterOrEqual, self).__init__(property_name, property_type,
|
||||
constraint)
|
||||
if not isinstance(self.constraint_value, self.valid_types):
|
||||
raise ValidationError(_('greater_or_equal must be comparable.'))
|
||||
raise InvalidSchemaError(message=_('greater_or_equal must '
|
||||
'be comparable.'))
|
||||
|
||||
def _is_valid(self, value):
|
||||
if value >= self.constraint_value:
|
||||
@ -221,14 +286,15 @@ class LessThan(Constraint):
|
||||
valid_types = (int, float, datetime.date,
|
||||
datetime.time, datetime.datetime)
|
||||
|
||||
valid_prop_types = (Constraint.INTEGER, Constraint.FLOAT,
|
||||
Constraint.TIMESTAMP)
|
||||
valid_prop_types = (Schema.INTEGER, Schema.FLOAT,
|
||||
Schema.TIMESTAMP)
|
||||
|
||||
def __init__(self, property_name, property_type, constraint):
|
||||
super(LessThan, self).__init__(property_name, property_type,
|
||||
constraint)
|
||||
if not isinstance(self.constraint_value, self.valid_types):
|
||||
raise ValidationError(_('less_than must be comparable.'))
|
||||
raise InvalidSchemaError(message=_('less_than must '
|
||||
'be comparable.'))
|
||||
|
||||
def _is_valid(self, value):
|
||||
if value < self.constraint_value:
|
||||
@ -255,14 +321,15 @@ class LessOrEqual(Constraint):
|
||||
valid_types = (int, float, datetime.date,
|
||||
datetime.time, datetime.datetime)
|
||||
|
||||
valid_prop_types = (Constraint.INTEGER, Constraint.FLOAT,
|
||||
Constraint.TIMESTAMP)
|
||||
valid_prop_types = (Schema.INTEGER, Schema.FLOAT,
|
||||
Schema.TIMESTAMP)
|
||||
|
||||
def __init__(self, property_name, property_type, constraint):
|
||||
super(LessOrEqual, self).__init__(property_name, property_type,
|
||||
constraint)
|
||||
if not isinstance(self.constraint_value, self.valid_types):
|
||||
raise ValidationError(_('less_or_equal must be comparable.'))
|
||||
raise InvalidSchemaError(message=_('less_or_equal must '
|
||||
'be comparable.'))
|
||||
|
||||
def _is_valid(self, value):
|
||||
if value <= self.constraint_value:
|
||||
@ -290,18 +357,19 @@ class InRange(Constraint):
|
||||
valid_types = (int, float, datetime.date,
|
||||
datetime.time, datetime.datetime)
|
||||
|
||||
valid_prop_types = (Constraint.INTEGER, Constraint.FLOAT,
|
||||
Constraint.TIMESTAMP)
|
||||
valid_prop_types = (Schema.INTEGER, Schema.FLOAT,
|
||||
Schema.TIMESTAMP)
|
||||
|
||||
def __init__(self, property_name, property_type, constraint):
|
||||
super(InRange, self).__init__(property_name, property_type, constraint)
|
||||
if(not isinstance(self.constraint_value, collections.Sequence) or
|
||||
(len(constraint[self.IN_RANGE]) != 2)):
|
||||
raise ValidationError(_('in_range must be a list.'))
|
||||
raise InvalidSchemaError(message=_('in_range must be a list.'))
|
||||
|
||||
for value in self.constraint_value:
|
||||
if not isinstance(value, self.valid_types):
|
||||
raise ValidationError(_('in_range value must be comparable.'))
|
||||
raise InvalidSchemaError(_('in_range value must '
|
||||
'be comparable.'))
|
||||
|
||||
self.min = self.constraint_value[0]
|
||||
self.max = self.constraint_value[1]
|
||||
@ -331,13 +399,13 @@ class ValidValues(Constraint):
|
||||
"""
|
||||
constraint_key = Constraint.VALID_VALUES
|
||||
|
||||
valid_prop_types = Constraint.PROPERTY_TYPES
|
||||
valid_prop_types = Schema.PROPERTY_TYPES
|
||||
|
||||
def __init__(self, property_name, property_type, constraint):
|
||||
super(ValidValues, self).__init__(property_name, property_type,
|
||||
constraint)
|
||||
if not isinstance(self.constraint_value, collections.Sequence):
|
||||
raise ValidationError(_('valid_values must be a list.'))
|
||||
raise InvalidSchemaError(message=_('valid_values must be a list.'))
|
||||
|
||||
def _is_valid(self, value):
|
||||
if isinstance(value, collections.Sequence):
|
||||
@ -363,12 +431,12 @@ class Length(Constraint):
|
||||
|
||||
valid_types = (int, )
|
||||
|
||||
valid_prop_types = (Constraint.STRING, )
|
||||
valid_prop_types = (Schema.STRING, )
|
||||
|
||||
def __init__(self, property_name, property_type, constraint):
|
||||
super(Length, self).__init__(property_name, property_type, constraint)
|
||||
if not isinstance(self.constraint_value, self.valid_types):
|
||||
raise ValidationError(_('length must be integer.'))
|
||||
raise InvalidSchemaError(message=_('length must be integer.'))
|
||||
|
||||
def _is_valid(self, value):
|
||||
if isinstance(value, str) and len(value) == self.constraint_value:
|
||||
@ -394,13 +462,13 @@ class MinLength(Constraint):
|
||||
|
||||
valid_types = (int, )
|
||||
|
||||
valid_prop_types = (Constraint.STRING, )
|
||||
valid_prop_types = (Schema.STRING, )
|
||||
|
||||
def __init__(self, property_name, property_type, constraint):
|
||||
super(MinLength, self).__init__(property_name, property_type,
|
||||
constraint)
|
||||
if not isinstance(self.constraint_value, self.valid_types):
|
||||
raise ValidationError(_('min_length must be integer.'))
|
||||
raise InvalidSchemaError(message=_('min_length must be integer.'))
|
||||
|
||||
def _is_valid(self, value):
|
||||
if isinstance(value, str) and len(value) >= self.constraint_value:
|
||||
@ -426,13 +494,13 @@ class MaxLength(Constraint):
|
||||
|
||||
valid_types = (int, )
|
||||
|
||||
valid_prop_types = (Constraint.STRING, )
|
||||
valid_prop_types = (Schema.STRING, )
|
||||
|
||||
def __init__(self, property_name, property_type, constraint):
|
||||
super(MaxLength, self).__init__(property_name, property_type,
|
||||
constraint)
|
||||
if not isinstance(self.constraint_value, self.valid_types):
|
||||
raise ValidationError(_('max_length must be integer.'))
|
||||
raise InvalidSchemaError(message=_('max_length must be integer.'))
|
||||
|
||||
def _is_valid(self, value):
|
||||
if isinstance(value, str) and len(value) <= self.constraint_value:
|
||||
@ -459,12 +527,12 @@ class Pattern(Constraint):
|
||||
|
||||
valid_types = (str, )
|
||||
|
||||
valid_prop_types = (Constraint.STRING, )
|
||||
valid_prop_types = (Schema.STRING, )
|
||||
|
||||
def __init__(self, property_name, property_type, constraint):
|
||||
super(Pattern, self).__init__(property_name, property_type, constraint)
|
||||
if not isinstance(self.constraint_value, self.valid_types):
|
||||
raise ValidationError(_('pattern must be string.'))
|
||||
raise InvalidSchemaError(message=_('pattern must be string.'))
|
||||
self.match = re.compile(self.constraint_value).match
|
||||
|
||||
def _is_valid(self, value):
|
||||
|
@ -18,8 +18,7 @@ import logging
|
||||
|
||||
from translator.toscalib.common.exception import MissingRequiredFieldError
|
||||
from translator.toscalib.common.exception import UnknownFieldError
|
||||
from translator.toscalib.elements.constraints import Constraint
|
||||
from translator.toscalib.properties import Property
|
||||
from translator.toscalib.elements.constraints import Schema
|
||||
|
||||
|
||||
log = logging.getLogger('tosca')
|
||||
@ -30,57 +29,40 @@ class Input(object):
|
||||
INPUTFIELD = (TYPE, DESCRIPTION, DEFAULT, CONSTRAINTS) = \
|
||||
('type', 'description', 'default', 'constraints')
|
||||
|
||||
def __init__(self, name, schema):
|
||||
def __init__(self, name, schema_dict):
|
||||
self.name = name
|
||||
self.schema = schema
|
||||
self.schema = Schema(name, schema_dict)
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
return self.schema[self.TYPE]
|
||||
return self.schema.type
|
||||
|
||||
@property
|
||||
def description(self):
|
||||
if Property.DESCRIPTION in self.schema:
|
||||
return self.schema[self.DESCRIPTION]
|
||||
return self.schema.description
|
||||
|
||||
@property
|
||||
def default(self):
|
||||
if self.Property.DEFAULT in self.schema:
|
||||
return self.schema[self.DEFAULT]
|
||||
return self.schema.default
|
||||
|
||||
@property
|
||||
def constraints(self):
|
||||
if Property.CONSTRAINTS in self.schema:
|
||||
return self.schema[self.CONSTRAINTS]
|
||||
return self.schema.constraints
|
||||
|
||||
def validate(self):
|
||||
self._validate_field()
|
||||
self.validate_type(self.type)
|
||||
if self.constraints:
|
||||
self.validate_constraints(self.constraints)
|
||||
|
||||
def _validate_field(self):
|
||||
if not isinstance(self.schema, dict):
|
||||
raise MissingRequiredFieldError(what='Input %s' % self.name,
|
||||
required=self.TYPE)
|
||||
try:
|
||||
self.type
|
||||
except KeyError:
|
||||
raise MissingRequiredFieldError(what='Input %s' % self.name,
|
||||
required=self.TYPE)
|
||||
for name in self.schema:
|
||||
if name not in self.INPUTFIELD:
|
||||
raise UnknownFieldError(what='Input %s' % self.name,
|
||||
field=name)
|
||||
|
||||
def validate_type(self, input_type):
|
||||
if input_type not in Constraint.PROPERTY_TYPES:
|
||||
if input_type not in Schema.PROPERTY_TYPES:
|
||||
raise ValueError(_('Invalid type %s') % type)
|
||||
|
||||
def validate_constraints(self, constraints):
|
||||
for constraint in constraints:
|
||||
Constraint(self.name, self.type, constraint)
|
||||
|
||||
|
||||
class Output(object):
|
||||
|
||||
|
@ -14,6 +14,7 @@
|
||||
# under the License.
|
||||
|
||||
from translator.toscalib.elements.constraints import Constraint
|
||||
from translator.toscalib.elements.constraints import Schema
|
||||
|
||||
|
||||
class Property(object):
|
||||
@ -25,29 +26,30 @@ class Property(object):
|
||||
'type', 'required', 'description', 'default', 'constraints'
|
||||
)
|
||||
|
||||
def __init__(self, property_name, value, schema=None):
|
||||
def __init__(self, property_name, value, schema_dict):
|
||||
self.name = property_name
|
||||
self.value = value
|
||||
self.schema = schema
|
||||
self.schema = Schema(property_name, schema_dict)
|
||||
|
||||
@property
|
||||
def constraints(self):
|
||||
try:
|
||||
if self.CONSTRAINTS in self.schema:
|
||||
return self.schema[self.CONSTRAINTS]
|
||||
except Exception:
|
||||
#Simply passing the exception to ignore Node Type in-line value.
|
||||
#Exception will not be needed when Node Type and Node Template
|
||||
#properties are separated.
|
||||
#TODO(spzala)
|
||||
pass
|
||||
def type(self):
|
||||
return self.schema.type
|
||||
|
||||
@property
|
||||
def required(self):
|
||||
return self.schema.required
|
||||
|
||||
@property
|
||||
def description(self):
|
||||
if self.schema:
|
||||
if self.DESCRIPTION in self.schema:
|
||||
return self.schema[self.DESCRIPTION]
|
||||
return ''
|
||||
return self.schema.description
|
||||
|
||||
@property
|
||||
def default(self):
|
||||
return self.schema.default
|
||||
|
||||
@property
|
||||
def constraints(self):
|
||||
return self.schema.constraints
|
||||
|
||||
def validate(self):
|
||||
'''Validate if not a reference property.'''
|
||||
@ -57,23 +59,19 @@ class Property(object):
|
||||
|
||||
def _validate_datatype(self):
|
||||
try:
|
||||
if self.TYPE in self.schema:
|
||||
dtype = self.schema[self.TYPE]
|
||||
if dtype == Constraint.STRING:
|
||||
return Constraint.validate_string(self.value)
|
||||
elif dtype == Constraint.INTEGER:
|
||||
return Constraint.validate_integer(self.value)
|
||||
elif dtype == Constraint.NUMBER:
|
||||
return Constraint.validate_number(self.value)
|
||||
elif dtype == Constraint.LIST:
|
||||
return Constraint.validate_list(self.value)
|
||||
dtype = self.type
|
||||
if dtype == Schema.STRING:
|
||||
return Constraint.validate_string(self.value)
|
||||
elif dtype == Schema.INTEGER:
|
||||
return Constraint.validate_integer(self.value)
|
||||
elif dtype == Schema.NUMBER:
|
||||
return Constraint.validate_number(self.value)
|
||||
elif dtype == Schema.LIST:
|
||||
return Constraint.validate_list(self.value)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def _validate_constraints(self):
|
||||
constraints = self.constraints
|
||||
dtype = self.schema[self.TYPE]
|
||||
if constraints:
|
||||
for constraint in constraints:
|
||||
Constraint(self.name, dtype,
|
||||
constraint).validate(self.value)
|
||||
if self.constraints:
|
||||
for constraint in self.constraints:
|
||||
constraint.validate(self.value)
|
||||
|
@ -16,43 +16,92 @@
|
||||
import datetime
|
||||
import yaml
|
||||
|
||||
from translator.toscalib.common.exception import InvalidSchemaError
|
||||
from translator.toscalib.common.exception import ValidationError
|
||||
from translator.toscalib.elements.constraints import Constraint
|
||||
from translator.toscalib.elements.constraints import ValidationError
|
||||
from translator.toscalib.elements.constraints import Schema
|
||||
from translator.toscalib.tests.base import TestCase
|
||||
from translator.toscalib.utils import yamlparser
|
||||
|
||||
|
||||
class ConstraintTest(TestCase):
|
||||
|
||||
def test_schema_dict(self):
|
||||
tpl_snippet = '''
|
||||
cpus:
|
||||
type: integer
|
||||
description: Number of CPUs for the server.
|
||||
'''
|
||||
schema = yamlparser.simple_parse(tpl_snippet)
|
||||
cpus_schema = Schema('cpus', schema['cpus'])
|
||||
self.assertEqual(len(cpus_schema), 2)
|
||||
self.assertEqual('integer', cpus_schema.type)
|
||||
self.assertEqual('Number of CPUs for the server.',
|
||||
cpus_schema.description)
|
||||
self.assertEqual(False, cpus_schema.required)
|
||||
self.assertIsNone(cpus_schema.default)
|
||||
|
||||
def test_schema_not_dict(self):
|
||||
tpl_snippet = '''
|
||||
cpus:
|
||||
- type: integer
|
||||
- description: Number of CPUs for the server.
|
||||
'''
|
||||
schema = yamlparser.simple_parse(tpl_snippet)
|
||||
error = self.assertRaises(InvalidSchemaError, Schema,
|
||||
'cpus', schema['cpus'])
|
||||
self.assertEqual('Schema cpus must be a dict.', str(error))
|
||||
|
||||
def test_schema_miss_type(self):
|
||||
tpl_snippet = '''
|
||||
cpus:
|
||||
description: Number of CPUs for the server.
|
||||
'''
|
||||
schema = yamlparser.simple_parse(tpl_snippet)
|
||||
error = self.assertRaises(InvalidSchemaError, Schema,
|
||||
'cpus', schema['cpus'])
|
||||
self.assertEqual('Schema cpus must have type.', str(error))
|
||||
|
||||
def test_schema_none_description(self):
|
||||
tpl_snippet = '''
|
||||
cpus:
|
||||
type: integer
|
||||
'''
|
||||
schema = yamlparser.simple_parse(tpl_snippet)
|
||||
cpus_schema = Schema('cpus', schema['cpus'])
|
||||
self.assertEqual('', cpus_schema.description)
|
||||
|
||||
def test_invalid_constraint_type(self):
|
||||
schema = {'invalid_type': 2}
|
||||
error = self.assertRaises(ValidationError, Constraint,
|
||||
'prop', Constraint.INTEGER,
|
||||
error = self.assertRaises(InvalidSchemaError, Constraint,
|
||||
'prop', Schema.INTEGER,
|
||||
schema)
|
||||
self.assertEqual('Invalid constraint type "invalid_type".',
|
||||
str(error))
|
||||
|
||||
def test_invalid_prop_type(self):
|
||||
schema = {'length': 5}
|
||||
error = self.assertRaises(ValidationError, Constraint,
|
||||
'prop', Constraint.INTEGER,
|
||||
error = self.assertRaises(InvalidSchemaError, Constraint,
|
||||
'prop', Schema.INTEGER,
|
||||
schema)
|
||||
self.assertEqual('Constraint type "length" is not valid for '
|
||||
'data type "integer".', str(error))
|
||||
|
||||
def test_invalid_validvalues(self):
|
||||
schema = {'valid_values': 2}
|
||||
error = self.assertRaises(ValidationError, Constraint,
|
||||
'prop', Constraint.INTEGER,
|
||||
error = self.assertRaises(InvalidSchemaError, Constraint,
|
||||
'prop', Schema.INTEGER,
|
||||
schema)
|
||||
self.assertEqual('valid_values must be a list.', str(error))
|
||||
|
||||
def test_validvalues_validate(self):
|
||||
schema = {'valid_values': [2, 4, 6, 8]}
|
||||
constraint = Constraint('prop', Constraint.INTEGER, schema)
|
||||
constraint = Constraint('prop', Schema.INTEGER, schema)
|
||||
self.assertIsNone(constraint.validate(4))
|
||||
|
||||
def test_validvalues_validate_fail(self):
|
||||
schema = {'valid_values': [2, 4, 6, 8]}
|
||||
constraint = Constraint('prop', Constraint.INTEGER, schema)
|
||||
constraint = Constraint('prop', Schema.INTEGER, schema)
|
||||
error = self.assertRaises(ValidationError, constraint.validate, 5)
|
||||
self.assertEqual('prop: 5 is not an valid value "[2, 4, 6, 8]".',
|
||||
str(error))
|
||||
@ -60,50 +109,50 @@ class ConstraintTest(TestCase):
|
||||
def test_invalid_in_range(self):
|
||||
snippet = 'in_range: {2, 6}'
|
||||
schema = yaml.load(snippet)
|
||||
error = self.assertRaises(ValidationError, Constraint,
|
||||
'prop', Constraint.INTEGER,
|
||||
error = self.assertRaises(InvalidSchemaError, Constraint,
|
||||
'prop', Schema.INTEGER,
|
||||
schema)
|
||||
self.assertEqual('in_range must be a list.', str(error))
|
||||
|
||||
def test_in_range_min_max(self):
|
||||
schema = {'in_range': [2, 6]}
|
||||
constraint = Constraint('prop', Constraint.INTEGER, schema)
|
||||
constraint = Constraint('prop', Schema.INTEGER, schema)
|
||||
self.assertEqual(2, constraint.min)
|
||||
self.assertEqual(6, constraint.max)
|
||||
|
||||
def test_in_range_validate(self):
|
||||
schema = {'in_range': [2, 6]}
|
||||
constraint = Constraint('prop', Constraint.INTEGER, schema)
|
||||
constraint = Constraint('prop', Schema.INTEGER, schema)
|
||||
self.assertIsNone(constraint.validate(2))
|
||||
self.assertIsNone(constraint.validate(4))
|
||||
self.assertIsNone(constraint.validate(6))
|
||||
|
||||
def test_in_range_validate_fail(self):
|
||||
schema = {'in_range': [2, 6]}
|
||||
constraint = Constraint('prop', Constraint.INTEGER, schema)
|
||||
constraint = Constraint('prop', Schema.INTEGER, schema)
|
||||
error = self.assertRaises(ValidationError, constraint.validate, 8)
|
||||
self.assertEqual('prop: 8 is out of range (min:2, max:6).',
|
||||
str(error))
|
||||
|
||||
def test_equal_validate(self):
|
||||
schema = {'equal': 4}
|
||||
constraint = Constraint('prop', Constraint.INTEGER, schema)
|
||||
constraint = Constraint('prop', Schema.INTEGER, schema)
|
||||
self.assertIsNone(constraint.validate(4))
|
||||
|
||||
def test_equal_validate_fail(self):
|
||||
schema = {'equal': 4}
|
||||
constraint = Constraint('prop', Constraint.INTEGER, schema)
|
||||
constraint = Constraint('prop', Schema.INTEGER, schema)
|
||||
error = self.assertRaises(ValidationError, constraint.validate, 8)
|
||||
self.assertEqual('prop: 8 is not equal to "4".', str(error))
|
||||
|
||||
def test_greater_than_validate(self):
|
||||
schema = {'greater_than': 4}
|
||||
constraint = Constraint('prop', Constraint.INTEGER, schema)
|
||||
constraint = Constraint('prop', Schema.INTEGER, schema)
|
||||
self.assertIsNone(constraint.validate(6))
|
||||
|
||||
def test_greater_than_validate_fail(self):
|
||||
schema = {'greater_than': 4}
|
||||
constraint = Constraint('prop', Constraint.INTEGER, schema)
|
||||
constraint = Constraint('prop', Schema.INTEGER, schema)
|
||||
error = self.assertRaises(ValidationError, constraint.validate, 3)
|
||||
self.assertEqual('prop: 3 must be greater than "4".', str(error))
|
||||
|
||||
@ -112,13 +161,13 @@ class ConstraintTest(TestCase):
|
||||
|
||||
def test_greater_or_equal_validate(self):
|
||||
schema = {'greater_or_equal': 3.9}
|
||||
constraint = Constraint('prop', Constraint.FLOAT, schema)
|
||||
constraint = Constraint('prop', Schema.FLOAT, schema)
|
||||
self.assertIsNone(constraint.validate(3.9))
|
||||
self.assertIsNone(constraint.validate(4.0))
|
||||
|
||||
def test_greater_or_equal_validate_fail(self):
|
||||
schema = {'greater_or_equal': 3.9}
|
||||
constraint = Constraint('prop', Constraint.FLOAT, schema)
|
||||
constraint = Constraint('prop', Schema.FLOAT, schema)
|
||||
error = self.assertRaises(ValidationError, constraint.validate, 3.0)
|
||||
self.assertEqual('prop: 3.0 must be greater or equal to "3.9".',
|
||||
str(error))
|
||||
@ -129,13 +178,13 @@ class ConstraintTest(TestCase):
|
||||
|
||||
def test_less_than_validate(self):
|
||||
schema = {'less_than': datetime.date(2014, 0o7, 25)}
|
||||
constraint = Constraint('prop', Constraint.TIMESTAMP, schema)
|
||||
constraint = Constraint('prop', Schema.TIMESTAMP, schema)
|
||||
self.assertIsNone(constraint.validate(datetime.date(2014, 0o7, 20)))
|
||||
self.assertIsNone(constraint.validate(datetime.date(2014, 0o7, 24)))
|
||||
|
||||
def test_less_than_validate_fail(self):
|
||||
schema = {'less_than': datetime.date(2014, 0o7, 25)}
|
||||
constraint = Constraint('prop', Constraint.TIMESTAMP, schema)
|
||||
constraint = Constraint('prop', Schema.TIMESTAMP, schema)
|
||||
error = self.assertRaises(ValidationError,
|
||||
constraint.validate,
|
||||
datetime.date(2014, 0o7, 25))
|
||||
@ -152,37 +201,37 @@ class ConstraintTest(TestCase):
|
||||
|
||||
def test_less_or_equal_validate(self):
|
||||
schema = {'less_or_equal': 4}
|
||||
constraint = Constraint('prop', Constraint.INTEGER, schema)
|
||||
constraint = Constraint('prop', Schema.INTEGER, schema)
|
||||
self.assertIsNone(constraint.validate(4))
|
||||
self.assertIsNone(constraint.validate(3))
|
||||
|
||||
def test_less_or_equal_validate_fail(self):
|
||||
schema = {'less_or_equal': 4}
|
||||
constraint = Constraint('prop', Constraint.INTEGER, schema)
|
||||
constraint = Constraint('prop', Schema.INTEGER, schema)
|
||||
error = self.assertRaises(ValidationError, constraint.validate, 5)
|
||||
self.assertEqual('prop: 5 must be less or equal to "4".', str(error))
|
||||
|
||||
def test_invalid_length(self):
|
||||
schema = {'length': 'four'}
|
||||
error = self.assertRaises(ValidationError, Constraint,
|
||||
'prop', Constraint.STRING,
|
||||
error = self.assertRaises(InvalidSchemaError, Constraint,
|
||||
'prop', Schema.STRING,
|
||||
schema)
|
||||
self.assertEqual('length must be integer.', str(error))
|
||||
|
||||
schema = {'length': 4.5}
|
||||
error = self.assertRaises(ValidationError, Constraint,
|
||||
'prop', Constraint.STRING,
|
||||
error = self.assertRaises(InvalidSchemaError, Constraint,
|
||||
'prop', Schema.STRING,
|
||||
schema)
|
||||
self.assertEqual('length must be integer.', str(error))
|
||||
|
||||
def test_length_validate(self):
|
||||
schema = {'length': 4}
|
||||
constraint = Constraint('prop', Constraint.STRING, schema)
|
||||
constraint = Constraint('prop', Schema.STRING, schema)
|
||||
self.assertIsNone(constraint.validate('abcd'))
|
||||
|
||||
def test_length_validate_fail(self):
|
||||
schema = {'length': 4}
|
||||
constraint = Constraint('prop', Constraint.STRING, schema)
|
||||
constraint = Constraint('prop', Schema.STRING, schema)
|
||||
error = self.assertRaises(ValidationError, constraint.validate, 'abc')
|
||||
self.assertEqual('length of prop: abc must be equal to "4".',
|
||||
str(error))
|
||||
@ -195,40 +244,40 @@ class ConstraintTest(TestCase):
|
||||
|
||||
def test_invalid_min_length(self):
|
||||
schema = {'min_length': 'four'}
|
||||
error = self.assertRaises(ValidationError, Constraint,
|
||||
'prop', Constraint.STRING,
|
||||
error = self.assertRaises(InvalidSchemaError, Constraint,
|
||||
'prop', Schema.STRING,
|
||||
schema)
|
||||
self.assertEqual('min_length must be integer.', str(error))
|
||||
|
||||
def test_min_length_validate(self):
|
||||
schema = {'min_length': 4}
|
||||
constraint = Constraint('prop', Constraint.STRING, schema)
|
||||
constraint = Constraint('prop', Schema.STRING, schema)
|
||||
self.assertIsNone(constraint.validate('abcd'))
|
||||
self.assertIsNone(constraint.validate('abcde'))
|
||||
|
||||
def test_min_length_validate_fail(self):
|
||||
schema = {'min_length': 4}
|
||||
constraint = Constraint('prop', Constraint.STRING, schema)
|
||||
constraint = Constraint('prop', Schema.STRING, schema)
|
||||
error = self.assertRaises(ValidationError, constraint.validate, 'abc')
|
||||
self.assertEqual('length of prop: abc must be at least "4".',
|
||||
str(error))
|
||||
|
||||
def test_invalid_max_length(self):
|
||||
schema = {'max_length': 'four'}
|
||||
error = self.assertRaises(ValidationError, Constraint,
|
||||
'prop', Constraint.STRING,
|
||||
error = self.assertRaises(InvalidSchemaError, Constraint,
|
||||
'prop', Schema.STRING,
|
||||
schema)
|
||||
self.assertEqual('max_length must be integer.', str(error))
|
||||
|
||||
def test_max_length_validate(self):
|
||||
schema = {'max_length': 4}
|
||||
constraint = Constraint('prop', Constraint.STRING, schema)
|
||||
constraint = Constraint('prop', Schema.STRING, schema)
|
||||
self.assertIsNone(constraint.validate('abcd'))
|
||||
self.assertIsNone(constraint.validate('abc'))
|
||||
|
||||
def test_max_length_validate_fail(self):
|
||||
schema = {'max_length': 4}
|
||||
constraint = Constraint('prop', Constraint.STRING, schema)
|
||||
constraint = Constraint('prop', Schema.STRING, schema)
|
||||
error = self.assertRaises(ValidationError,
|
||||
constraint.validate,
|
||||
'abcde')
|
||||
@ -237,12 +286,12 @@ class ConstraintTest(TestCase):
|
||||
|
||||
def test_pattern_validate(self):
|
||||
schema = {'pattern': '[0-9]*'}
|
||||
constraint = Constraint('prop', Constraint.STRING, schema)
|
||||
constraint = Constraint('prop', Schema.STRING, schema)
|
||||
self.assertIsNone(constraint.validate('123'))
|
||||
|
||||
def test_pattern_validate_fail(self):
|
||||
schema = {'pattern': '[0-9]*'}
|
||||
constraint = Constraint('prop', Constraint.STRING, schema)
|
||||
constraint = Constraint('prop', Schema.STRING, schema)
|
||||
error = self.assertRaises(ValidationError, constraint.validate, 'abc')
|
||||
self.assertEqual('prop: "abc" does not match pattern "[0-9]*".',
|
||||
str(error))
|
||||
|
@ -59,24 +59,6 @@ class ToscaTemplateValidationTest(TestCase):
|
||||
'to verify valid values.', err.__str__())
|
||||
|
||||
def test_inputs(self):
|
||||
tpl_snippet = '''
|
||||
inputs:
|
||||
cpus:
|
||||
description: Number of CPUs for the server.
|
||||
constraints:
|
||||
- valid_values: [ 1, 2, 4, 8 ]
|
||||
'''
|
||||
inputs = (translator.toscalib.utils.yamlparser.
|
||||
simple_parse(tpl_snippet)['inputs'])
|
||||
name, attrs = list(inputs.items())[0]
|
||||
input = Input(name, attrs)
|
||||
try:
|
||||
input.validate()
|
||||
except Exception as err:
|
||||
self.assertTrue(isinstance(err, MissingRequiredFieldError))
|
||||
self.assertEqual('Input cpus is missing required field: '
|
||||
'"type".', err.__str__())
|
||||
|
||||
tpl_snippet = '''
|
||||
inputs:
|
||||
cpus:
|
||||
|
Loading…
Reference in New Issue
Block a user