1 # Licensed under the Apache License, Version 2.0 (the "License"); you may
2 # not use this file except in compliance with the License. You may obtain
3 # a copy of the License at
5 # http://www.apache.org/licenses/LICENSE-2.0
7 # Unless required by applicable law or agreed to in writing, software
8 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10 # License for the specific language governing permissions and limitations
13 from testtools import matchers
15 from toscaparser.common import exception
16 from toscaparser.elements.property_definition import PropertyDef
17 from toscaparser.nodetemplate import NodeTemplate
18 from toscaparser.properties import Property
19 from toscaparser.tests.base import TestCase
20 from toscaparser.utils.gettextutils import _
21 from toscaparser.utils import yamlparser
24 class PropertyTest(TestCase):
27 test_property_schema = {'type': 'string'}
28 propertyInstance = Property('test_property', 'Hughes',
30 self.assertEqual('string', propertyInstance.type)
32 def test_type_invalid(self):
33 test_property_schema = {'type': 'Fish'}
34 propertyInstance = Property('test_property', 'Hughes',
36 error = self.assertRaises(exception.InvalidTypeError,
37 propertyInstance.validate)
38 self.assertEqual(_('Type "Fish" is not a valid type.'), str(error))
41 test_property_schema = {'type': 'list'}
42 propertyInstance = Property('test_property', ['a', 'b'],
44 self.assertIsNone(propertyInstance.validate())
45 self.assertEqual(['a', 'b'], propertyInstance.value)
47 def test_list_invalid(self):
48 test_property_schema = {'type': 'list'}
49 propertyInstance = Property('test_property', 'a',
51 error = self.assertRaises(ValueError, propertyInstance.validate)
52 self.assertEqual(_('"a" is not a list.'), str(error))
54 def test_list_entry_schema(self):
55 test_property_schema = {'type': 'list',
56 'entry_schema': {'type': 'string'}}
57 propertyInstance = Property('test_property', ['a', 'b'],
59 self.assertIsNone(propertyInstance.validate())
60 self.assertEqual(['a', 'b'], propertyInstance.value)
69 test_property_schema = yamlparser.simple_parse(schema_snippet)
70 propertyInstance = Property('test_property', ['ab', 'cd'],
72 self.assertIsNone(propertyInstance.validate())
73 self.assertEqual(['ab', 'cd'], propertyInstance.value)
75 def test_list_entry_schema_invalid(self):
76 test_property_schema = {'type': 'list',
77 'entry_schema': {'type': 'integer'}}
78 propertyInstance = Property('test_property', [1, 'b'],
80 error = self.assertRaises(ValueError, propertyInstance.validate)
81 self.assertEqual(_('"b" is not an integer.'), str(error))
84 test_property_schema = {'type': 'map'}
85 propertyInstance = Property('test_property', {'a': 'b'},
87 self.assertIsNone(propertyInstance.validate())
88 self.assertEqual({'a': 'b'}, propertyInstance.value)
90 def test_map_invalid(self):
91 test_property_schema = {'type': 'map'}
92 propertyInstance = Property('test_property', 12,
94 error = self.assertRaises(ValueError, propertyInstance.validate)
95 self.assertEqual(_('"12" is not a map.'), str(error))
97 def test_map_entry_schema(self):
98 test_property_schema = {'type': 'map',
99 'entry_schema': {'type': 'boolean'}}
100 propertyInstance = Property('test_property',
101 {'valid': True, 'required': True},
102 test_property_schema)
103 self.assertIsNone(propertyInstance.validate())
104 self.assertEqual({'valid': True, 'required': True},
105 propertyInstance.value)
107 def test_map_entry_schema_invalid(self):
108 test_property_schema = {'type': 'map',
109 'entry_schema': {'type': 'boolean'}}
110 propertyInstance = Property('test_property',
111 {'valid': True, 'contact_name': 123},
112 test_property_schema)
113 error = self.assertRaises(ValueError, propertyInstance.validate)
114 self.assertEqual(_('"123" is not a boolean.'), str(error))
116 def test_boolean(self):
117 test_property_schema = {'type': 'boolean'}
118 propertyInstance = Property('test_property', 'true',
119 test_property_schema)
120 self.assertIsNone(propertyInstance.validate())
121 propertyInstance = Property('test_property', True,
122 test_property_schema)
123 self.assertIsNone(propertyInstance.validate())
124 self.assertEqual(True, propertyInstance.value)
126 def test_boolean_invalid(self):
127 test_property_schema = {'type': 'boolean'}
128 propertyInstance = Property('test_property', 12,
129 test_property_schema)
130 error = self.assertRaises(ValueError, propertyInstance.validate)
131 self.assertEqual(_('"12" is not a boolean.'), str(error))
133 def test_float(self):
134 test_property_schema = {'type': 'float'}
135 propertyInstance = Property('test_property', 0.1,
136 test_property_schema)
137 self.assertIsNone(propertyInstance.validate())
138 self.assertEqual(0.1, propertyInstance.value)
140 def test_float_invalid(self):
141 test_property_schema = {'type': 'float'}
142 propertyInstance = Property('test_property', 12,
143 test_property_schema)
144 error = self.assertRaises(ValueError, propertyInstance.validate)
145 self.assertEqual(_('"12" is not a float.'), str(error))
147 def test_timestamp(self):
148 test_property_schema = {'type': 'timestamp'}
149 # canonical timestamp
150 propertyInstance = Property('test_property', '2015-04-01T02:59:43.1Z',
151 test_property_schema)
152 self.assertIsNone(propertyInstance.validate())
153 self.assertEqual("2015-04-01T02:59:43.1Z", propertyInstance.value)
156 propertyInstance = Property('test_property',
157 '2015-04-01t21:59:43.10-05:00',
158 test_property_schema)
159 self.assertIsNone(propertyInstance.validate())
160 self.assertEqual("2015-04-01t21:59:43.10-05:00",
161 propertyInstance.value)
163 # space separated timestamp
164 propertyInstance = Property('test_property',
165 '2015-04-01 21:59:43.10 -5',
166 test_property_schema)
167 self.assertIsNone(propertyInstance.validate())
168 self.assertEqual("2015-04-01 21:59:43.10 -5", propertyInstance.value)
170 # no time zone timestamp
171 propertyInstance = Property('test_property', '2015-04-01 21:59:43.10',
172 test_property_schema)
173 self.assertIsNone(propertyInstance.validate())
174 self.assertEqual("2015-04-01 21:59:43.10", propertyInstance.value)
177 propertyInstance = Property('test_property', '2015-04-01',
178 test_property_schema)
179 self.assertIsNone(propertyInstance.validate())
180 self.assertEqual("2015-04-01", propertyInstance.value)
182 def test_timestamp_invalid(self):
183 test_property_schema = {'type': 'timestamp'}
184 # invalid timestamp - day out of range
185 value = '2015-04-115T02:59:43.1Z'
186 propertyInstance = Property('test_property', value,
187 test_property_schema)
188 error = self.assertRaises(ValueError, propertyInstance.validate)
189 expected_message = (_('"%s" is not a valid timestamp.') % value)
190 self.assertThat(str(error), matchers.StartsWith(expected_message))
192 def test_required(self):
193 test_property_schema = {'type': 'string'}
194 propertyInstance = Property('test_property', 'Foo',
195 test_property_schema)
196 self.assertEqual(True, propertyInstance.required)
198 def test_proprety_inheritance(self):
200 tosca_custom_def = '''
201 tosca.nodes.SoftwareComponent.MySoftware:
202 derived_from: SoftwareComponent
207 default: /opt/mysoftware
210 tosca_node_template = '''
213 type: tosca.nodes.SoftwareComponent.MySoftware
215 component_version: 3.1
218 expected_properties = ['component_version',
221 tpl = self._get_nodetemplate(tosca_node_template, tosca_custom_def)
222 self.assertIsNone(tpl.validate())
223 self.assertEqual(expected_properties,
224 sorted(tpl.get_properties().keys()))
226 def test_missing_property_type(self):
230 typo: tosca.mytesttype.Test
232 schema = yamlparser.simple_parse(tpl_snippet)
233 error = self.assertRaises(exception.InvalidSchemaError, PropertyDef,
234 'prop', None, schema['properties']['prop'])
235 self.assertEqual(_('Schema definition of "prop" must have a "type" '
236 'attribute.'), str(error))
238 def test_invalid_required_value(self):
242 type: tosca.mytesttype.Test
245 schema = yamlparser.simple_parse(tpl_snippet)
246 error = self.assertRaises(exception.InvalidSchemaError, PropertyDef,
247 'prop', None, schema['properties']['prop'])
249 valid_values = ', '.join(PropertyDef.VALID_REQUIRED_VALUES)
250 expected_message = (_('Schema definition of "prop" has "required" '
251 'attribute with invalid value "dunno". The '
252 'value must be one of "%s".') % valid_values)
253 self.assertEqual(expected_message, str(error))
255 def test_invalid_property_status(self):
262 schema = yamlparser.simple_parse(tpl_snippet)
263 error = self.assertRaises(exception.InvalidSchemaError, PropertyDef,
264 'prop', None, schema['properties']['prop'])
266 valid_values = ', '.join(PropertyDef.VALID_STATUS_VALUES)
267 expected_message = (_('Schema definition of "prop" has "status" '
268 'attribute with invalid value "unknown". The '
269 'value must be one of "%s".') % valid_values)
270 self.assertEqual(expected_message, str(error))
272 def test_capability_proprety_inheritance(self):
273 tosca_custom_def_example1 = '''
274 tosca.capabilities.ScalableNew:
275 derived_from: tosca.capabilities.Scalable
282 tosca.nodes.ComputeNew:
283 derived_from: tosca.nodes.Compute
286 type: tosca.capabilities.ScalableNew
289 tosca_node_template_example1 = '''
292 type: tosca.nodes.ComputeNew
299 tosca_custom_def_example2 = '''
300 tosca.nodes.ComputeNew:
301 derived_from: tosca.nodes.Compute
304 type: tosca.capabilities.Scalable
307 tosca_node_template_example2 = '''
310 type: tosca.nodes.ComputeNew
317 tpl1 = self._get_nodetemplate(tosca_node_template_example1,
318 tosca_custom_def_example1)
319 self.assertIsNone(tpl1.validate())
321 tpl2 = self._get_nodetemplate(tosca_node_template_example2,
322 tosca_custom_def_example2)
323 self.assertIsNone(tpl2.validate())
325 def _get_nodetemplate(self, tpl_snippet,
326 custom_def_snippet=None):
327 nodetemplates = yamlparser.\
328 simple_parse(tpl_snippet)['node_templates']
330 if custom_def_snippet:
331 custom_def = yamlparser.simple_parse(custom_def_snippet)
332 name = list(nodetemplates.keys())[0]
333 tpl = NodeTemplate(name, nodetemplates, custom_def)
336 def test_explicit_relationship_proprety(self):
338 tosca_node_template = '''
342 type: tosca.nodes.Compute
352 type: tosca.nodes.BlockStorage
357 expected_properties = ['location']
359 nodetemplates = yamlparser.\
360 simple_parse(tosca_node_template)['node_templates']
361 tpl = NodeTemplate('client_node', nodetemplates, [])
363 self.assertIsNone(tpl.validate())
365 for relationship, trgt in tpl.relationships.items():
366 rel_tpls.extend(trgt.get_relationship_template())
367 self.assertEqual(expected_properties,
368 sorted(rel_tpls[0].get_properties().keys()))