Fix translation issue with interface inputs and functions

Fix the issue with interface inputs described using intrinsic
functions, that produces an invalid HOT output. Also, include
necessary unit tests, and revert templates that were simplified
due to this issue..

This patch includes changes required in tosca-parser for
resolving the issue.

Change-Id: Iefde09d4633a1cadfe2c6b9ac28c58d2da79a37d
Partial-Bug: #1440247
This commit is contained in:
Vahid Hashemian 2015-09-24 10:23:24 -07:00
parent 6a9483180d
commit a80b6893c2
13 changed files with 92 additions and 112 deletions

View File

@ -14,10 +14,10 @@ import collections
import datetime import datetime
import re import re
import toscaparser
from toscaparser.common.exception import InvalidSchemaError from toscaparser.common.exception import InvalidSchemaError
from toscaparser.common.exception import ValidationError from toscaparser.common.exception import ValidationError
from toscaparser.elements import scalarunit from toscaparser.elements import scalarunit
from toscaparser.functions import is_function
from toscaparser.utils.gettextutils import _ from toscaparser.utils.gettextutils import _
@ -262,7 +262,8 @@ class GreaterOrEqual(Constraint):
'be comparable.')) 'be comparable.'))
def _is_valid(self, value): def _is_valid(self, value):
if is_function(value) or value >= self.constraint_value: if toscaparser.functions.is_function(value) or \
value >= self.constraint_value:
return True return True
return False return False
@ -417,8 +418,8 @@ class ValidValues(Constraint):
def _err_msg(self, value): def _err_msg(self, value):
allowed = '[%s]' % ', '.join(str(a) for a in self.constraint_value) allowed = '[%s]' % ', '.join(str(a) for a in self.constraint_value)
return (_('%(pname)s: %(pvalue)s is not an valid ' return (_('%(pname)s: %(pvalue)s is not a valid value. Expected a '
'value "%(cvalue)s".') % 'value from "%(cvalue)s".') %
dict(pname=self.property_name, dict(pname=self.property_name,
pvalue=value, pvalue=value,
cvalue=allowed)) cvalue=allowed))

View File

@ -16,6 +16,7 @@ import abc
import six import six
from toscaparser.common.exception import UnknownInputError from toscaparser.common.exception import UnknownInputError
from toscaparser.dataentity import DataEntity
from toscaparser.utils.gettextutils import _ from toscaparser.utils.gettextutils import _
@ -80,9 +81,15 @@ class GetInput(Function):
raise UnknownInputError(input_name=self.args[0]) raise UnknownInputError(input_name=self.args[0])
def result(self): def result(self):
found_input = [input_def for input_def in self.tosca_tpl.inputs if self.tosca_tpl.parsed_params and \
self.input_name in self.tosca_tpl.parsed_params:
return DataEntity.validate_datatype(
self.tosca_tpl.tpl['inputs'][self.input_name]['type'],
self.tosca_tpl.parsed_params[self.input_name])
input = [input_def for input_def in self.tosca_tpl.inputs
if self.input_name == input_def.name][0] if self.input_name == input_def.name][0]
return found_input.default return input.default
@property @property
def input_name(self): def input_name(self):
@ -307,7 +314,7 @@ class GetProperty(Function):
else: else:
property_value = self._find_property(self.args[1]).value property_value = self._find_property(self.args[1]).value
if isinstance(property_value, Function): if isinstance(property_value, Function):
return property_value return property_value.result()
return get_function(self.tosca_tpl, return get_function(self.tosca_tpl,
self.context, self.context,
property_value) property_value)

View File

@ -43,16 +43,14 @@ topology_template:
properties: properties:
github_url: { get_input: github_url } github_url: { get_input: github_url }
requirements: requirements:
- host: - host: nodejs
node: nodejs - database_connection: mongo_db
- database_connection:
node: mongo_db
interfaces: interfaces:
Standard: Standard:
configure: configure:
implementation: ../Scripts/nodejs/config.sh implementation: ../Scripts/nodejs/config.sh
inputs: inputs:
github_url: http://github.com/paypal/rest-api-sample-app-nodejs.git github_url: { get_property: [ SELF, github_url ] }
mongodb_ip: { get_attribute: [mongo_server, private_address] } mongodb_ip: { get_attribute: [mongo_server, private_address] }
start: ../Scripts/nodejs/start.sh start: ../Scripts/nodejs/start.sh
nodejs: nodejs:
@ -66,16 +64,14 @@ topology_template:
mongo_db: mongo_db:
type: tosca.nodes.Database type: tosca.nodes.Database
requirements: requirements:
- host: - host: mongo_dbms
node: mongo_dbms
interfaces: interfaces:
Standard: Standard:
create: ../Scripts/mongodb/create_database.sh create: ../Scripts/mongodb/create_database.sh
mongo_dbms: mongo_dbms:
type: tosca.nodes.DBMS type: tosca.nodes.DBMS
requirements: requirements:
- host: - host: mongo_server
node: mongo_server
interfaces: interfaces:
Standard: Standard:
create: ../Scripts/mongodb/create.sh create: ../Scripts/mongodb/create.sh
@ -87,8 +83,7 @@ topology_template:
elasticsearch: elasticsearch:
type: tosca.nodes.SoftwareComponent.Elasticsearch type: tosca.nodes.SoftwareComponent.Elasticsearch
requirements: requirements:
- host: - host: elasticsearch_server
node: elasticsearch_server
interfaces: interfaces:
Standard: Standard:
create: ../Scripts/elasticsearch/create.sh create: ../Scripts/elasticsearch/create.sh
@ -96,8 +91,7 @@ topology_template:
logstash: logstash:
type: tosca.nodes.SoftwareComponent.Logstash type: tosca.nodes.SoftwareComponent.Logstash
requirements: requirements:
- host: - host: logstash_server
node: logstash_server
- search_endpoint: - search_endpoint:
node: elasticsearch node: elasticsearch
capability: search_endpoint capability: search_endpoint
@ -116,11 +110,8 @@ topology_template:
kibana: kibana:
type: tosca.nodes.SoftwareComponent.Kibana type: tosca.nodes.SoftwareComponent.Kibana
requirements: requirements:
- host: - host: kibana_server
node: kibana_server - search_endpoint: elasticsearch
- search_endpoint:
node: elasticsearch
capability: search_endpoint
interfaces: interfaces:
Standard: Standard:
create: ../Scripts/kibana/create.sh create: ../Scripts/kibana/create.sh
@ -133,8 +124,7 @@ topology_template:
app_collectd: app_collectd:
type: tosca.nodes.SoftwareComponent.Collectd type: tosca.nodes.SoftwareComponent.Collectd
requirements: requirements:
- host: - host: app_server
node: app_server
- log_endpoint: - log_endpoint:
node: logstash node: logstash
capability: log_endpoint capability: log_endpoint
@ -155,8 +145,7 @@ topology_template:
app_rsyslog: app_rsyslog:
type: tosca.nodes.SoftwareComponent.Rsyslog type: tosca.nodes.SoftwareComponent.Rsyslog
requirements: requirements:
- host: - host: app_server
node: app_server
- log_endpoint: - log_endpoint:
node: logstash node: logstash
capability: log_endpoint capability: log_endpoint

View File

@ -33,10 +33,8 @@ topology_template:
wordpress: wordpress:
type: tosca.nodes.WebApplication.WordPress type: tosca.nodes.WebApplication.WordPress
requirements: requirements:
- host: - host: webserver
node: webserver - database_endpoint: mysql_database
- database_endpoint:
node: mysql_database
interfaces: interfaces:
Standard: Standard:
create: Scripts/WordPress/install.sh create: Scripts/WordPress/install.sh
@ -54,8 +52,7 @@ topology_template:
user: { get_input: db_user } user: { get_input: db_user }
password: { get_input: db_pwd } password: { get_input: db_pwd }
requirements: requirements:
- host: - host: mysql_dbms
node: mysql_dbms
interfaces: interfaces:
Standard: Standard:
configure: configure:
@ -72,8 +69,7 @@ topology_template:
root_password: { get_input: db_root_pwd } root_password: { get_input: db_root_pwd }
port: { get_input: db_port } port: { get_input: db_port }
requirements: requirements:
- host: - host: server
node: server
interfaces: interfaces:
Standard: Standard:
create: Scripts/MYSQLDBMS/install.sh create: Scripts/MYSQLDBMS/install.sh
@ -86,8 +82,7 @@ topology_template:
webserver: webserver:
type: tosca.nodes.WebServer type: tosca.nodes.WebServer
requirements: requirements:
- host: - host: server
node: server
interfaces: interfaces:
Standard: Standard:
create: Scripts/WebServer/install.sh create: Scripts/WebServer/install.sh

View File

@ -51,7 +51,7 @@ topology_template:
configure: configure:
implementation: nodejs/config.sh implementation: nodejs/config.sh
inputs: inputs:
github_url: http://github.com/paypal/rest-api-sample-app-nodejs.git github_url: { get_property: [ SELF, github_url ] }
mongodb_ip: { get_attribute: [mongo_server, private_address] } mongodb_ip: { get_attribute: [mongo_server, private_address] }
start: nodejs/start.sh start: nodejs/start.sh
nodejs: nodejs:
@ -111,9 +111,7 @@ topology_template:
type: tosca.nodes.SoftwareComponent.Kibana type: tosca.nodes.SoftwareComponent.Kibana
requirements: requirements:
- host: kibana_server - host: kibana_server
- search_endpoint: - search_endpoint: elasticsearch
node: elasticsearch
capability: search_endpoint
interfaces: interfaces:
Standard: Standard:
create: kibana/create.sh create: kibana/create.sh

View File

@ -46,9 +46,9 @@ topology_template:
configure: configure:
implementation: wordpress/wordpress_configure.sh implementation: wordpress/wordpress_configure.sh
inputs: inputs:
wp_db_name: wordpress wp_db_name: { get_property: [ mysql_database, name ] }
wp_db_user: wp_user wp_db_user: { get_property: [ mysql_database, user ] }
wp_db_password: wp_pass wp_db_password: { get_property: [ mysql_database, password ] }
mysql_database: mysql_database:
type: tosca.nodes.Database type: tosca.nodes.Database
@ -61,17 +61,17 @@ topology_template:
properties: properties:
port: { get_input: db_port } port: { get_input: db_port }
requirements: requirements:
- host: - host: mysql_dbms
node: mysql_dbms
interfaces: interfaces:
Standard: Standard:
configure: configure:
implementation: mysql/mysql_database_configure.sh implementation: mysql/mysql_database_configure.sh
inputs: inputs:
db_name: wordpress db_name: { get_property: [ SELF, name ] }
db_user: wp_user db_user: { get_property: [ SELF, user ] }
db_password: wp_pass db_password: { get_property: [ SELF, password ] }
db_root_password: passw0rd db_root_password: { get_property: [ mysql_dbms, root_password ] }
mysql_dbms: mysql_dbms:
type: tosca.nodes.DBMS type: tosca.nodes.DBMS
properties: properties:
@ -84,12 +84,12 @@ topology_template:
create: create:
implementation: mysql/mysql_dbms_install.sh implementation: mysql/mysql_dbms_install.sh
inputs: inputs:
db_root_password: passw0rd db_root_password: { get_property: [ mysql_dbms, root_password ] }
start: mysql/mysql_dbms_start.sh start: mysql/mysql_dbms_start.sh
configure: configure:
implementation: mysql/mysql_dbms_configure.sh implementation: mysql/mysql_dbms_configure.sh
inputs: inputs:
db_port: 3366 db_port: { get_property: [ mysql_dbms, port ] }
webserver: webserver:
type: tosca.nodes.WebServer type: tosca.nodes.WebServer
@ -99,6 +99,7 @@ topology_template:
Standard: Standard:
create: webserver/webserver_install.sh create: webserver/webserver_install.sh
start: webserver/webserver_start.sh start: webserver/webserver_start.sh
server: server:
type: tosca.nodes.Compute type: tosca.nodes.Compute
capabilities: capabilities:

View File

@ -100,8 +100,8 @@ class ConstraintTest(TestCase):
constraint = Constraint('prop', Schema.INTEGER, schema) constraint = Constraint('prop', Schema.INTEGER, schema)
error = self.assertRaises(exception.ValidationError, error = self.assertRaises(exception.ValidationError,
constraint.validate, 5) constraint.validate, 5)
self.assertEqual('prop: 5 is not an valid value "[2, 4, 6, 8]".', self.assertEqual('prop: 5 is not a valid value. Expected a value from '
str(error)) '"[2, 4, 6, 8]".', str(error))
def test_invalid_in_range(self): def test_invalid_in_range(self):
snippet = 'in_range: {2, 6}' snippet = 'in_range: {2, 6}'

View File

@ -221,7 +221,7 @@ class DataTypeTest(TestCase):
data = DataEntity('tosca.my.datatypes.PeopleBase', value, data = DataEntity('tosca.my.datatypes.PeopleBase', value,
DataTypeTest.custom_type_def) DataTypeTest.custom_type_def)
error = self.assertRaises(ValueError, data.validate) error = self.assertRaises(ValueError, data.validate)
self.assertEqual('"123" is not a string', error.__str__()) self.assertEqual('"123" is not a string.', error.__str__())
# the value of name doesn't meet the defined constraint # the value of name doesn't meet the defined constraint
def test_value_error_in_dataentity(self): def test_value_error_in_dataentity(self):
@ -247,7 +247,7 @@ class DataTypeTest(TestCase):
data = DataEntity('tosca.my.datatypes.People', value, data = DataEntity('tosca.my.datatypes.People', value,
DataTypeTest.custom_type_def) DataTypeTest.custom_type_def)
error = self.assertRaises(ValueError, data.validate) error = self.assertRaises(ValueError, data.validate)
self.assertEqual('"1" is not a string', error.__str__()) self.assertEqual('"1" is not a string.', error.__str__())
# contact_pone is an invalid field name in nested datatype # contact_pone is an invalid field name in nested datatype
def test_validation_in_nested_datatype(self): def test_validation_in_nested_datatype(self):
@ -289,11 +289,11 @@ class DataTypeTest(TestCase):
"data/datatypes/test_custom_datatypes_value_error.yaml") "data/datatypes/test_custom_datatypes_value_error.yaml")
error = self.assertRaises(ValueError, ToscaTemplate, tpl_path) error = self.assertRaises(ValueError, ToscaTemplate, tpl_path)
self.assertEqual('"[\'1 foo street\', \'9 bar avenue\']" ' self.assertEqual('"[\'1 foo street\', \'9 bar avenue\']" '
'is not a map', error.__str__()) 'is not a map.', error.__str__())
def test_datatype_in_template_nested_datatype_error(self): def test_datatype_in_template_nested_datatype_error(self):
tpl_path = os.path.join( tpl_path = os.path.join(
os.path.dirname(os.path.abspath(__file__)), os.path.dirname(os.path.abspath(__file__)),
"data/datatypes/test_custom_datatypes_nested_datatype_error.yaml") "data/datatypes/test_custom_datatypes_nested_datatype_error.yaml")
error = self.assertRaises(ValueError, ToscaTemplate, tpl_path) error = self.assertRaises(ValueError, ToscaTemplate, tpl_path)
self.assertEqual('"123456789" is not a string', error.__str__()) self.assertEqual('"123456789" is not a string.', error.__str__())

View File

@ -23,7 +23,8 @@ class IntrinsicFunctionsTest(TestCase):
tosca_tpl = os.path.join( tosca_tpl = os.path.join(
os.path.dirname(os.path.abspath(__file__)), os.path.dirname(os.path.abspath(__file__)),
"data/tosca_single_instance_wordpress.yaml") "data/tosca_single_instance_wordpress.yaml")
tosca = ToscaTemplate(tosca_tpl) params = {'db_name': 'my_wordpress', 'db_user': 'my_db_user'}
tosca = ToscaTemplate(tosca_tpl, parsed_params=params)
def _get_node(self, node_name): def _get_node(self, node_name):
return [ return [
@ -39,34 +40,30 @@ class IntrinsicFunctionsTest(TestCase):
return [prop.value for prop in node_template.get_properties_objects() return [prop.value for prop in node_template.get_properties_objects()
if prop.name == property_name][0] if prop.name == property_name][0]
def test_get_property(self): def _get_inputs_dict(self):
TestCase.skip(self, 'bug #1440247') inputs = {}
mysql_dbms = self._get_node('mysql_dbms') for input in self.tosca.inputs:
operation = self._get_operation(mysql_dbms.interfaces, 'configure') inputs[input.name] = input.default
db_root_password = operation.inputs['db_root_password'] return inputs
self.assertTrue(isinstance(db_root_password, functions.GetProperty))
result = db_root_password.result()
self.assertTrue(isinstance(result, functions.GetInput))
def test_get_requirement_property(self): def _get_input(self, name):
TestCase.skip(self, 'bug #1440247') self._get_inputs_dict()[name]
def test_get_property(self):
wordpress = self._get_node('wordpress') wordpress = self._get_node('wordpress')
operation = self._get_operation(wordpress.interfaces, 'configure') operation = self._get_operation(wordpress.interfaces, 'configure')
wp_db_port = operation.inputs['wp_db_port'] wp_db_password = operation.inputs['wp_db_password']
self.assertTrue(isinstance(wp_db_port, functions.GetProperty)) self.assertTrue(isinstance(wp_db_password, functions.GetProperty))
result = wp_db_port.result() result = wp_db_password.result()
self.assertTrue(isinstance(result, functions.GetInput)) self.assertEqual('wp_pass', result)
self.assertEqual('db_port', result.input_name)
def test_get_capability_property(self): def test_get_property_with_input_param(self):
TestCase.skip(self, 'bug #1440247') wordpress = self._get_node('wordpress')
mysql_database = self._get_node('mysql_database') operation = self._get_operation(wordpress.interfaces, 'configure')
operation = self._get_operation(mysql_database.interfaces, 'configure') wp_db_user = operation.inputs['wp_db_user']
db_port = operation.inputs['db_port'] self.assertTrue(isinstance(wp_db_user, functions.GetProperty))
self.assertTrue(isinstance(db_port, functions.GetProperty)) result = wp_db_user.result()
result = db_port.result() self.assertEqual('my_db_user', result)
self.assertTrue(isinstance(result, functions.GetInput))
self.assertEqual('db_port', result.input_name)
def test_unknown_capability_property(self): def test_unknown_capability_property(self):
err = self.assertRaises( err = self.assertRaises(
@ -87,13 +84,6 @@ class IntrinsicFunctionsTest(TestCase):
expected_inputs.remove(prop.value.input_name) expected_inputs.remove(prop.value.input_name)
self.assertListEqual(expected_inputs, []) self.assertListEqual(expected_inputs, [])
def test_get_input_in_interface(self):
TestCase.skip(self, 'bug #1440247')
mysql_dbms = self._get_node('mysql_dbms')
operation = self._get_operation(mysql_dbms.interfaces, 'configure')
db_user = operation.inputs['db_user']
self.assertTrue(isinstance(db_user, functions.GetInput))
def test_get_input_validation(self): def test_get_input_validation(self):
self.assertRaises(exception.UnknownInputError, self.assertRaises(exception.UnknownInputError,
self._load_template, self._load_template,

View File

@ -44,7 +44,7 @@ class PropertyTest(TestCase):
propertyInstance = Property('test_property', 'a', propertyInstance = Property('test_property', 'a',
test_property_schema) test_property_schema)
error = self.assertRaises(ValueError, propertyInstance.validate) error = self.assertRaises(ValueError, propertyInstance.validate)
self.assertEqual('"a" is not a list', str(error)) self.assertEqual('"a" is not a list.', str(error))
def test_list_entry_schema(self): def test_list_entry_schema(self):
test_property_schema = {'type': 'list', test_property_schema = {'type': 'list',
@ -73,8 +73,7 @@ class PropertyTest(TestCase):
propertyInstance = Property('test_property', [1, 'b'], propertyInstance = Property('test_property', [1, 'b'],
test_property_schema) test_property_schema)
error = self.assertRaises(ValueError, propertyInstance.validate) error = self.assertRaises(ValueError, propertyInstance.validate)
self.assertEqual('"b" is not an integer', self.assertEqual('"b" is not an integer.', str(error))
str(error))
def test_map(self): def test_map(self):
test_property_schema = {'type': 'map'} test_property_schema = {'type': 'map'}
@ -88,7 +87,7 @@ class PropertyTest(TestCase):
propertyInstance = Property('test_property', 12, propertyInstance = Property('test_property', 12,
test_property_schema) test_property_schema)
error = self.assertRaises(ValueError, propertyInstance.validate) error = self.assertRaises(ValueError, propertyInstance.validate)
self.assertEqual('"12" is not a map', str(error)) self.assertEqual('"12" is not a map.', str(error))
def test_map_entry_schema(self): def test_map_entry_schema(self):
test_property_schema = {'type': 'map', test_property_schema = {'type': 'map',
@ -107,7 +106,7 @@ class PropertyTest(TestCase):
{'valid': True, 'contact_name': 123}, {'valid': True, 'contact_name': 123},
test_property_schema) test_property_schema)
error = self.assertRaises(ValueError, propertyInstance.validate) error = self.assertRaises(ValueError, propertyInstance.validate)
self.assertEqual('"123" is not a boolean', str(error)) self.assertEqual('"123" is not a boolean.', str(error))
def test_boolean(self): def test_boolean(self):
test_property_schema = {'type': 'boolean'} test_property_schema = {'type': 'boolean'}
@ -124,7 +123,7 @@ class PropertyTest(TestCase):
propertyInstance = Property('test_property', 12, propertyInstance = Property('test_property', 12,
test_property_schema) test_property_schema)
error = self.assertRaises(ValueError, propertyInstance.validate) error = self.assertRaises(ValueError, propertyInstance.validate)
self.assertEqual('"12" is not a boolean', str(error)) self.assertEqual('"12" is not a boolean.', str(error))
def test_float(self): def test_float(self):
test_property_schema = {'type': 'float'} test_property_schema = {'type': 'float'}
@ -138,7 +137,7 @@ class PropertyTest(TestCase):
propertyInstance = Property('test_property', 12, propertyInstance = Property('test_property', 12,
test_property_schema) test_property_schema)
error = self.assertRaises(ValueError, propertyInstance.validate) error = self.assertRaises(ValueError, propertyInstance.validate)
self.assertEqual('"12" is not a float', str(error)) self.assertEqual('"12" is not a float.', str(error))
def test_timestamp(self): def test_timestamp(self):
test_property_schema = {'type': 'timestamp'} test_property_schema = {'type': 'timestamp'}

View File

@ -68,7 +68,7 @@ class ToscaTemplateTest(TestCase):
expected_type = "tosca.nodes.Database" expected_type = "tosca.nodes.Database"
expected_properties = ['name', 'password', 'user'] expected_properties = ['name', 'password', 'user']
expected_capabilities = ['database_endpoint'] expected_capabilities = ['database_endpoint']
expected_requirements = [{'host': {'node': 'mysql_dbms'}}] expected_requirements = [{'host': 'mysql_dbms'}]
''' TODO: needs enhancement in tosca_elk.yaml.. ''' TODO: needs enhancement in tosca_elk.yaml..
expected_relationshp = ['tosca.relationships.HostedOn'] expected_relationshp = ['tosca.relationships.HostedOn']
expected_host = ['mysql_dbms'] expected_host = ['mysql_dbms']

View File

@ -730,7 +730,7 @@ custom_types/wordpress.yaml
capability: log_endpoint capability: log_endpoint
occurrences: [a, w] occurrences: [a, w]
''' '''
expectedmessage = ('"a" is not an integer') expectedmessage = ('"a" is not an integer.')
err = self.assertRaises( err = self.assertRaises(
ValueError, ValueError,
lambda: self._single_node_template_content_test(tpl_snippet)) lambda: self._single_node_template_content_test(tpl_snippet))
@ -745,7 +745,7 @@ custom_types/wordpress.yaml
capability: log_endpoint capability: log_endpoint
occurrences: -1 occurrences: -1
''' '''
expectedmessage = ('"-1" is not a list') expectedmessage = ('"-1" is not a list.')
err = self.assertRaises( err = self.assertRaises(
ValueError, ValueError,
lambda: self._single_node_template_content_test(tpl_snippet)) lambda: self._single_node_template_content_test(tpl_snippet))
@ -1000,7 +1000,7 @@ custom_types/wordpress.yaml
lambda: self._single_node_template_content_test(tpl_snippet)) lambda: self._single_node_template_content_test(tpl_snippet))
self.assertEqual(expectedmessage, err.__str__()) self.assertEqual(expectedmessage, err.__str__())
# validatating capability property values # validating capability property values
tpl_snippet = ''' tpl_snippet = '''
node_templates: node_templates:
server: server:
@ -1010,8 +1010,8 @@ custom_types/wordpress.yaml
properties: properties:
initiator: test initiator: test
''' '''
expectedmessage = ('initiator: test is not an valid value ' expectedmessage = ('initiator: test is not a valid value. Expected a '
'"[source, target, peer]".') 'value from "[source, target, peer]".')
err = self.assertRaises( err = self.assertRaises(
exception.ValidationError, exception.ValidationError,

View File

@ -42,31 +42,31 @@ def validate_integer(value):
try: try:
value = int(value) value = int(value)
except Exception: except Exception:
raise ValueError(_('"%s" is not an integer') % value) raise ValueError(_('"%s" is not an integer.') % value)
return value return value
def validate_float(value): def validate_float(value):
if not isinstance(value, float): if not isinstance(value, float):
raise ValueError(_('"%s" is not a float') % value) raise ValueError(_('"%s" is not a float.') % value)
return validate_number(value) return validate_number(value)
def validate_string(value): def validate_string(value):
if not isinstance(value, six.string_types): if not isinstance(value, six.string_types):
raise ValueError(_('"%s" is not a string') % value) raise ValueError(_('"%s" is not a string.') % value)
return value return value
def validate_list(value): def validate_list(value):
if not isinstance(value, list): if not isinstance(value, list):
raise ValueError(_('"%s" is not a list') % value) raise ValueError(_('"%s" is not a list.') % value)
return value return value
def validate_map(value): def validate_map(value):
if not isinstance(value, collections.Mapping): if not isinstance(value, collections.Mapping):
raise ValueError(_('"%s" is not a map') % value) raise ValueError(_('"%s" is not a map.') % value)
return value return value
@ -78,7 +78,7 @@ def validate_boolean(value):
normalised = value.lower() normalised = value.lower()
if normalised in ['true', 'false']: if normalised in ['true', 'false']:
return normalised == 'true' return normalised == 'true'
raise ValueError(_('"%s" is not a boolean') % value) raise ValueError(_('"%s" is not a boolean.') % value)
def validate_timestamp(value): def validate_timestamp(value):