Added support for range type

The current code is missing support for handling range type which
is used is in PortSpec. Hence added support for it

Change-Id: I97bf1c68280dce3dba01938790ff4f4aee86dc1a
Closes-Bug: #1528164
This commit is contained in:
Zahra 2016-02-04 18:53:12 +05:30 committed by Matt Rutkowski
parent 0a0abe5b42
commit 9f3e954a89
4 changed files with 91 additions and 8 deletions

View File

@ -97,7 +97,11 @@ class DataEntity(object):
# check if field value meets constraints defined
if prop_schema.constraints:
for constraint in prop_schema.constraints:
constraint.validate(value)
if isinstance(value, list):
for val in value:
constraint.validate(val)
else:
constraint.validate(value)
return self.value
@ -122,6 +126,8 @@ class DataEntity(object):
return validateutils.validate_number(value)
elif type == Schema.BOOLEAN:
return validateutils.validate_boolean(value)
elif type == Schema.RANGE:
return validateutils.validate_range(value)
elif type == Schema.TIMESTAMP:
validateutils.validate_timestamp(value)
return value

View File

@ -33,12 +33,12 @@ class Schema(collections.Mapping):
)
PROPERTY_TYPES = (
INTEGER, STRING, BOOLEAN, FLOAT,
INTEGER, STRING, BOOLEAN, FLOAT, RANGE,
NUMBER, TIMESTAMP, LIST, MAP,
SCALAR_UNIT_SIZE, SCALAR_UNIT_FREQUENCY, SCALAR_UNIT_TIME,
PORTDEF, VERSION
) = (
'integer', 'string', 'boolean', 'float',
'integer', 'string', 'boolean', 'float', 'range',
'number', 'timestamp', 'list', 'map',
'scalar-unit.size', 'scalar-unit.frequency', 'scalar-unit.time',
'PortDef', 'version'
@ -127,6 +127,8 @@ class Constraint(object):
'less_or_equal', 'in_range', 'valid_values', 'length',
'min_length', 'max_length', 'pattern')
UNBOUNDED = 'UNBOUNDED'
def __new__(cls, property_name, property_type, constraint):
if cls is not Constraint:
return super(Constraint, cls).__new__(cls)
@ -372,11 +374,11 @@ class InRange(Constraint):
constraint_key = Constraint.IN_RANGE
valid_types = (int, float, datetime.date,
datetime.time, datetime.datetime)
datetime.time, datetime.datetime, str)
valid_prop_types = (Schema.INTEGER, Schema.FLOAT, Schema.TIMESTAMP,
Schema.SCALAR_UNIT_SIZE, Schema.SCALAR_UNIT_FREQUENCY,
Schema.SCALAR_UNIT_TIME)
Schema.SCALAR_UNIT_TIME, Schema.RANGE)
def __init__(self, property_name, property_type, constraint):
super(InRange, self).__init__(property_name, property_type, constraint)
@ -391,16 +393,27 @@ class InRange(Constraint):
ExceptionCollector.appendException(
InvalidSchemaError(_('The property "in_range" expects '
'comparable values.')))
# The only string we allow for range is the special value
# 'UNBOUNDED'
if(isinstance(value, str) and value != self.UNBOUNDED):
ExceptionCollector.appendException(
InvalidSchemaError(_('The property "in_range" expects '
'comparable values.')))
self.min = self.constraint_value[0]
self.max = self.constraint_value[1]
def _is_valid(self, value):
if value < self.min:
if not isinstance(self.min, str):
if value < self.min:
return False
elif self.min != self.UNBOUNDED:
return False
if value > self.max:
if not isinstance(self.max, str):
if value > self.max:
return False
elif self.max != self.UNBOUNDED:
return False
return True
def _err_msg(self, value):

View File

@ -61,6 +61,13 @@ class DataTypeTest(TestCase):
type: string
contact_phone:
type: string
tosca.my.datatypes.TestLab:
properties:
temperature:
type: range
constraints:
- in_range: [-256, UNBOUNDED]
'''
custom_type_def = yamlparser.simple_parse(custom_type_schema)
@ -325,3 +332,48 @@ class DataTypeTest(TestCase):
self.assertRaises(exception.ValidationError, ToscaTemplate, tpl_path)
exception.ExceptionCollector.assertExceptionMessage(
ValueError, _('"123456789" is not a string.'))
def test_valid_range_type(self):
value_snippet = '''
user_port:
protocol: tcp
target_range: [20000, 60000]
source_range: [1000, 3000]
'''
value = yamlparser.simple_parse(value_snippet)
data = DataEntity('PortSpec', value.get('user_port'))
self.assertIsNotNone(data.validate())
def test_invalid_range_datatype(self):
value_snippet = '''
user_port:
protocol: tcp
target_range: [20000]
'''
value = yamlparser.simple_parse(value_snippet)
data = DataEntity('PortSpec', value.get('user_port'))
err = self.assertRaises(ValueError, data.validate)
self.assertEqual(_('"[20000]" is not a valid range.'
),
err.__str__())
value_snippet = '''
user_port:
protocol: tcp
target_range: [20000, 3000]
'''
value = yamlparser.simple_parse(value_snippet)
data = DataEntity('PortSpec', value.get('user_port'))
err = self.assertRaises(ValueError, data.validate)
self.assertEqual(_('"[20000, 3000]" is not a valid range.'
),
err.__str__())
def test_range_unbounded(self):
value_snippet = '''
temperature: [-100, 999999]
'''
value = yamlparser.simple_parse(value_snippet)
data = DataEntity('tosca.my.datatypes.TestLab', value,
DataTypeTest.custom_type_def)
self.assertIsNotNone(data.validate())

View File

@ -68,6 +68,18 @@ def validate_list(value):
return value
def validate_range(value):
validate_list(value)
if isinstance(value, list):
if len(value) != 2 or not (value[0] <= value[1]):
ExceptionCollector.appendException(
ValueError(_('"%s" is not a valid range.') % value))
validate_integer(value[0])
if not value[1] == "UNBOUNDED":
validate_integer(value[1])
return value
def validate_map(value):
if not isinstance(value, collections.Mapping):
ExceptionCollector.appendException(