From 23c1e9709d32cf6ee18746f37b366a67ee1525f9 Mon Sep 17 00:00:00 2001 From: srinivas_tadepalli Date: Tue, 17 Mar 2015 18:12:34 +0530 Subject: [PATCH] validating reference properties in translate_input.py added some validation checks for hosting_server in hot_resource.py Added unit testcases for translate_input.py Change-Id: Ibad2b5b231ac7f119df6d2c5e1eb6949cf9b0be2 Closes-bug: #1321996 --- translator/hot/syntax/hot_resource.py | 15 +- translator/hot/tests/__init__.py | 0 translator/hot/tests/test_translate_inputs.py | 193 ++++++++++++++++++ translator/hot/translate_inputs.py | 26 ++- 4 files changed, 220 insertions(+), 14 deletions(-) create mode 100644 translator/hot/tests/__init__.py create mode 100644 translator/hot/tests/test_translate_inputs.py diff --git a/translator/hot/syntax/hot_resource.py b/translator/hot/syntax/hot_resource.py index 80920234..7409a50e 100644 --- a/translator/hot/syntax/hot_resource.py +++ b/translator/hot/syntax/hot_resource.py @@ -100,9 +100,13 @@ class HotResource(object): self.properties = {'config': {'get_resource': config_name}} deploy_lookup[interface.name] = self else: + # hosting_server is None if requirements is None + hosting_on_server = (hosting_server.name if + hosting_server else None) + sd_config = {'config': {'get_resource': config_name}, 'server': {'get_resource': - hosting_server.name}} + hosting_on_server}} deploy_resource = \ HotResource(self.nodetemplate, deploy_name, @@ -144,12 +148,13 @@ class HotResource(object): if self.type == 'OS::Heat::SoftwareDeployment': # skip if already have hosting # If type is NodeTemplate, look up corresponding HotResrouce - host_server = self.properties.get('server')['get_resource'] - if host_server is None: + host_server = self.properties.get('server') + if host_server is None or not host_server['get_resource']: raise Exception(_("Internal Error: expecting host " "in software deployment")) - elif isinstance(host_server, NodeTemplate): - self.properties['server']['get_resource'] = host_server.name + elif isinstance(host_server['get_resource'], NodeTemplate): + self.properties['server']['get_resource'] = \ + host_server['get_resource'].name def top_of_chain(self): dependent = self.group_dependencies.get(self) diff --git a/translator/hot/tests/__init__.py b/translator/hot/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/translator/hot/tests/test_translate_inputs.py b/translator/hot/tests/test_translate_inputs.py new file mode 100644 index 00000000..90e511fe --- /dev/null +++ b/translator/hot/tests/test_translate_inputs.py @@ -0,0 +1,193 @@ +# 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 translator.hot.translate_inputs import TranslateInputs +from translator.toscalib.parameters import Input +from translator.toscalib.tests.base import TestCase +import translator.toscalib.utils.yamlparser + + +class ToscaTemplateInputValidationTest(TestCase): + + def _translate_input_test(self, tpl_snippet, input_params, + expectedmessage=None): + inputs_dict = (translator.toscalib.utils.yamlparser. + simple_parse(tpl_snippet)['inputs']) + inputs = [] + for name, attrs in inputs_dict.items(): + input = Input(name, attrs) + inputs.append(input) + + translateinput = TranslateInputs(inputs, input_params) + try: + translateinput.translate() + except ValueError: + pass + except Exception as err: + self.assertEqual(expectedmessage, err.__str__()) + + def test_invalid_input_type(self): + tpl_snippet = ''' + inputs: + cpus: + type: integer + description: Number of CPUs for the server. + constraints: + - valid_values: [ 1, 2, 4, 8 ] + ''' + + input_params = {'cpus': 'string'} + expectedmessage = ('could not convert string to float: string') + self._translate_input_test(tpl_snippet, input_params, + expectedmessage) + + def test_invalid_input_constraints_for_equal(self): + tpl_snippet = ''' + inputs: + num_cpus: + type: integer + description: Number of CPUs for the server. + constraints: + - equal: 1 + ''' + + input_params = {'num_cpus': '0'} + expectedmessage = ('num_cpus: 0 is not equal to "1".') + self._translate_input_test(tpl_snippet, input_params, expectedmessage) + + def test_invalid_input_constraints_for_greater_or_equal(self): + tpl_snippet = ''' + inputs: + num_cpus: + type: integer + description: Number of CPUs for the server. + constraints: + - greater_or_equal: 1 + ''' + + input_params = {'num_cpus': '0'} + expectedmessage = ('num_cpus: 0 must be greater or equal to "1".') + self._translate_input_test(tpl_snippet, input_params, expectedmessage) + + def test_invalid_input_constraints_for_greater_than(self): + tpl_snippet = ''' + inputs: + num_cpus: + type: integer + description: Number of CPUs for the server. + constraints: + - greater_than: 1 + ''' + + input_params = {'num_cpus': '0'} + expectedmessage = ('num_cpus: 0 must be greater than "1".') + self._translate_input_test(tpl_snippet, input_params, expectedmessage) + + def test_invalid_input_constraints_for_less_than(self): + tpl_snippet = ''' + inputs: + num_cpus: + type: integer + description: Number of CPUs for the server. + constraints: + - less_than: 8 + ''' + + input_params = {'num_cpus': '8'} + expectedmessage = ('num_cpus: 8 must be less than "8".') + self._translate_input_test(tpl_snippet, input_params, expectedmessage) + + def test_invalid_input_constraints_for_less_or_equal(self): + tpl_snippet = ''' + inputs: + num_cpus: + type: integer + description: Number of CPUs for the server. + constraints: + - less_or_equal: 8 + ''' + + input_params = {'num_cpus': '9'} + expectedmessage = ('num_cpus: 9 must be less or equal to "8".') + self._translate_input_test(tpl_snippet, input_params, expectedmessage) + + def test_invalid_input_constraints_for_valid_values(self): + tpl_snippet = ''' + inputs: + num_cpus: + type: integer + description: Number of CPUs for the server. + constraints: + - valid_values: [ 1, 2, 4, 8 ] + ''' + + input_params = {'num_cpus': '3'} + expectedmessage = ('num_cpus: 3 is not an valid value "[1, 2, 4, 8]".') + self._translate_input_test(tpl_snippet, input_params, expectedmessage) + + def test_invalid_input_constraints_for_in_range(self): + tpl_snippet = ''' + inputs: + num_cpus: + type: integer + description: Number of CPUs for the server. + constraints: + - in_range: [ 1, 8 ] + ''' + + input_params = {'num_cpus': '10'} + expectedmessage = ('num_cpus: 10 is out of range (min:1, max:8).') + self._translate_input_test(tpl_snippet, input_params, expectedmessage) + + def test_invalid_input_constraints_for_min_length(self): + tpl_snippet = ''' + inputs: + user_name: + type: string + description: Name of the user. + constraints: + - min_length: 8 + ''' + + input_params = {'user_name': 'abcd'} + expectedmessage = ('length of user_name: abcd must be at least "8".') + self._translate_input_test(tpl_snippet, input_params, expectedmessage) + + def test_invalid_input_constraints_for_max_length(self): + tpl_snippet = ''' + inputs: + user_name: + type: string + description: Name of the user. + constraints: + - max_length: 6 + ''' + + input_params = {'user_name': 'abcdefg'} + expectedmessage = ('length of user_name: ' + 'abcdefg must be no greater than "6".') + self._translate_input_test(tpl_snippet, input_params, expectedmessage) + + def test_invalid_input_constraints_for_pattern(self): + tpl_snippet = ''' + inputs: + user_name: + type: string + description: Name of the user. + constraints: + - pattern: '^\w+$' + ''' + + input_params = {'user_name': '1-abc'} + expectedmessage = ('user_name: "1-abc" does ' + 'not match pattern "^\\w+$".') + self._translate_input_test(tpl_snippet, input_params, expectedmessage) diff --git a/translator/hot/translate_inputs.py b/translator/hot/translate_inputs.py index 44e318a5..ada5a573 100644 --- a/translator/hot/translate_inputs.py +++ b/translator/hot/translate_inputs.py @@ -12,6 +12,7 @@ # under the License. from translator.hot.syntax.hot_parameter import HotParameter +from translator.toscalib.dataentity import DataEntity from translator.toscalib.utils.gettextutils import _ @@ -60,22 +61,29 @@ class TranslateInputs(): def _translate_inputs(self): hot_inputs = [] + hot_default = None for input in self.inputs: hot_input_type = TOSCA_TO_HOT_INPUT_TYPES[input.type] - hot_constraints = [] - if input.constraints: - for constraint in input.constraints: - hc, hvalue = self._translate_constraints( - constraint.constraint_key, constraint.constraint_value) - hot_constraints.append({hc: hvalue}) if input.name in self.parsed_params: + DataEntity.validate_datatype(hot_input_type, + self.parsed_params[input.name]) hot_default = self.parsed_params[input.name] elif input.default is not None: hot_default = input.default else: raise Exception(_("Need to specify a value " "for input {0}").format(input.name)) + hot_constraints = [] + if input.constraints: + for constraint in input.constraints: + constraint.validate( + int(hot_default) if hot_input_type == "number" + else hot_default) + hc, hvalue = self._translate_constraints( + constraint.constraint_key, constraint.constraint_value) + hot_constraints.append({hc: hvalue}) + hot_inputs.append(HotParameter(name=input.name, type=hot_input_type, description=input.description, @@ -101,9 +109,9 @@ class TranslateInputs(): elif name == LESS_OR_EQUAL: hot_value = {"max": value} elif name == IN_RANGE: - range_values = value.keys() - min_value = min(range_values) - max_value = max(range_values) + # value is list type here + min_value = min(value) + max_value = max(value) hot_value = {"min": min_value, "max": max_value} elif name == LENGTH: hot_value = {"min": value, "max": value}