Merge "Add required definition in class of Input."
[parser.git] / tosca2heat / tosca-parser / toscaparser / tests / test_toscatpl.py
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
4 #
5 #         http://www.apache.org/licenses/LICENSE-2.0
6 #
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
11 #    under the License.
12
13 import os
14 import six
15 from toscaparser.common import exception
16 import toscaparser.elements.interfaces as ifaces
17 from toscaparser.elements.nodetype import NodeType
18 from toscaparser.elements.portspectype import PortSpec
19 from toscaparser.functions import GetInput
20 from toscaparser.functions import GetProperty
21 from toscaparser.nodetemplate import NodeTemplate
22 from toscaparser.tests.base import TestCase
23 from toscaparser.tosca_template import ToscaTemplate
24 from toscaparser.utils.gettextutils import _
25 import toscaparser.utils.yamlparser
26
27
28 class ToscaTemplateTest(TestCase):
29     '''TOSCA template.'''
30     tosca_tpl = os.path.join(
31         os.path.dirname(os.path.abspath(__file__)),
32         "data/tosca_single_instance_wordpress.yaml")
33     tosca = ToscaTemplate(tosca_tpl)
34     tosca_elk_tpl = os.path.join(
35         os.path.dirname(os.path.abspath(__file__)),
36         "data/tosca_elk.yaml")
37     tosca_repo_tpl = os.path.join(
38         os.path.dirname(os.path.abspath(__file__)),
39         "data/tosca_repositories_test_definition.yaml")
40
41     def test_version(self):
42         self.assertEqual(self.tosca.version, "tosca_simple_yaml_1_0")
43
44     def test_description(self):
45         expected_description = "TOSCA simple profile with wordpress, " \
46                                "web server and mysql on the same server."
47         self.assertEqual(self.tosca.description, expected_description)
48
49     def test_inputs(self):
50         self.assertEqual(
51             ['cpus', 'db_name', 'db_port',
52              'db_pwd', 'db_root_pwd', 'db_user'],
53             sorted([input.name for input in self.tosca.inputs]))
54
55         input_name = "db_port"
56         expected_description = "Port for the MySQL database."
57         for input in self.tosca.inputs:
58             if input.name == input_name:
59                 self.assertEqual(input.description, expected_description)
60
61     def test_node_tpls(self):
62         '''Test nodetemplate names.'''
63         self.assertEqual(
64             ['mysql_database', 'mysql_dbms', 'server',
65              'webserver', 'wordpress'],
66             sorted([tpl.name for tpl in self.tosca.nodetemplates]))
67
68         tpl_name = "mysql_database"
69         expected_type = "tosca.nodes.Database"
70         expected_properties = ['name', 'password', 'user']
71         expected_capabilities = ['database_endpoint', 'feature']
72         expected_requirements = [{'host': 'mysql_dbms'}]
73         ''' TODO: needs enhancement in tosca_elk.yaml..
74         expected_relationshp = ['tosca.relationships.HostedOn']
75         expected_host = ['mysql_dbms']
76         '''
77         expected_interface = [ifaces.LIFECYCLE_SHORTNAME]
78
79         for tpl in self.tosca.nodetemplates:
80             if tpl_name == tpl.name:
81                 '''Test node type.'''
82                 self.assertEqual(tpl.type, expected_type)
83
84                 '''Test properties.'''
85                 self.assertEqual(
86                     expected_properties,
87                     sorted(tpl.get_properties().keys()))
88
89                 '''Test capabilities.'''
90                 self.assertEqual(
91                     expected_capabilities,
92                     sorted(tpl.get_capabilities().keys()))
93
94                 '''Test requirements.'''
95                 self.assertEqual(
96                     expected_requirements, tpl.requirements)
97
98                 '''Test relationship.'''
99                 ''' needs enhancements in tosca_elk.yaml
100                 self.assertEqual(
101                     expected_relationshp,
102                     [x.type for x in tpl.relationships.keys()])
103                 self.assertEqual(
104                     expected_host,
105                     [y.name for y in tpl.relationships.values()])
106                 '''
107                 '''Test interfaces.'''
108                 self.assertEqual(
109                     expected_interface,
110                     [x.type for x in tpl.interfaces])
111
112             if tpl.name == 'server':
113                 '''Test property value'''
114                 props = tpl.get_properties()
115                 if props and 'mem_size' in props.keys():
116                     self.assertEqual(props['mem_size'].value, '4096 MB')
117                 '''Test capability'''
118                 caps = tpl.get_capabilities()
119                 self.assertIn('os', caps.keys())
120                 os_props_objs = None
121                 os_props = None
122                 os_type_prop = None
123                 if caps and 'os' in caps.keys():
124                     capability = caps['os']
125                     os_props_objs = capability.get_properties_objects()
126                     os_props = capability.get_properties()
127                     os_type_prop = capability.get_property_value('type')
128                     break
129                 self.assertEqual(
130                     ['Linux'],
131                     [p.value for p in os_props_objs if p.name == 'type'])
132                 self.assertEqual(
133                     'Linux',
134                     os_props['type'].value if 'type' in os_props else '')
135                 self.assertEqual('Linux', os_props['type'].value)
136                 self.assertEqual('Linux', os_type_prop)
137
138     def test_node_inheritance_type(self):
139         wordpress_node = [
140             node for node in self.tosca.nodetemplates
141             if node.name == 'wordpress'][0]
142         self.assertTrue(
143             wordpress_node.is_derived_from("tosca.nodes.WebApplication"))
144         self.assertTrue(
145             wordpress_node.is_derived_from("tosca.nodes.Root"))
146         self.assertFalse(
147             wordpress_node.is_derived_from("tosca.policies.Root"))
148         self.assertFalse(
149             wordpress_node.is_derived_from("tosca.groups.Root"))
150
151     def test_outputs(self):
152         self.assertEqual(
153             ['website_url'],
154             sorted([output.name for output in self.tosca.outputs]))
155
156     def test_interfaces(self):
157         wordpress_node = [
158             node for node in self.tosca.nodetemplates
159             if node.name == 'wordpress'][0]
160         interfaces = wordpress_node.interfaces
161         self.assertEqual(2, len(interfaces))
162         for interface in interfaces:
163             if interface.name == 'create':
164                 self.assertEqual(ifaces.LIFECYCLE_SHORTNAME,
165                                  interface.type)
166                 self.assertEqual('wordpress/wordpress_install.sh',
167                                  interface.implementation)
168                 self.assertIsNone(interface.inputs)
169             elif interface.name == 'configure':
170                 self.assertEqual(ifaces.LIFECYCLE_SHORTNAME,
171                                  interface.type)
172                 self.assertEqual('wordpress/wordpress_configure.sh',
173                                  interface.implementation)
174                 self.assertEqual(3, len(interface.inputs))
175                 TestCase.skip(self, 'bug #1440247')
176                 wp_db_port = interface.inputs['wp_db_port']
177                 self.assertTrue(isinstance(wp_db_port, GetProperty))
178                 self.assertEqual('get_property', wp_db_port.name)
179                 self.assertEqual(['SELF',
180                                   'database_endpoint',
181                                   'port'],
182                                  wp_db_port.args)
183                 result = wp_db_port.result()
184                 self.assertTrue(isinstance(result, GetInput))
185             else:
186                 raise AssertionError(
187                     'Unexpected interface: {0}'.format(interface.name))
188
189     def test_normative_type_by_short_name(self):
190         # test template with a short name Compute
191         template = os.path.join(
192             os.path.dirname(os.path.abspath(__file__)),
193             "data/test_tosca_normative_type_by_shortname.yaml")
194
195         tosca_tpl = ToscaTemplate(template)
196         expected_type = "tosca.nodes.Compute"
197         for tpl in tosca_tpl.nodetemplates:
198             self.assertEqual(tpl.type, expected_type)
199         for tpl in tosca_tpl.nodetemplates:
200             compute_type = NodeType(tpl.type)
201             self.assertEqual(
202                 sorted(['tosca.capabilities.Container',
203                         'tosca.capabilities.Node',
204                         'tosca.capabilities.OperatingSystem',
205                         'tosca.capabilities.network.Bindable',
206                         'tosca.capabilities.Scalable']),
207                 sorted([c.type
208                         for c in compute_type.get_capabilities_objects()]))
209
210     def test_template_with_no_inputs(self):
211         tosca_tpl = self._load_template('test_no_inputs_in_template.yaml')
212         self.assertEqual(0, len(tosca_tpl.inputs))
213
214     def test_template_with_no_outputs(self):
215         tosca_tpl = self._load_template('test_no_outputs_in_template.yaml')
216         self.assertEqual(0, len(tosca_tpl.outputs))
217
218     def test_relationship_interface(self):
219         template = ToscaTemplate(self.tosca_elk_tpl)
220         for node_tpl in template.nodetemplates:
221             if node_tpl.name == 'logstash':
222                 config_interface = 'Configure'
223                 artifact = 'logstash/configure_elasticsearch.py'
224                 relation = node_tpl.relationships
225                 for key in relation.keys():
226                     rel_tpl = relation.get(key).get_relationship_template()
227                     if rel_tpl:
228                         self.assertTrue(rel_tpl[0].is_derived_from(
229                             "tosca.relationships.Root"))
230                         interfaces = rel_tpl[0].interfaces
231                         for interface in interfaces:
232                             self.assertEqual(config_interface,
233                                              interface.type)
234                             self.assertEqual('pre_configure_source',
235                                              interface.name)
236                             self.assertEqual(artifact,
237                                              interface.implementation)
238
239     def test_relationship(self):
240         template = ToscaTemplate(self.tosca_elk_tpl)
241         for node_tpl in template.nodetemplates:
242             if node_tpl.name == 'paypal_pizzastore':
243                 expected_relationships = ['tosca.relationships.ConnectsTo',
244                                           'tosca.relationships.HostedOn']
245                 expected_hosts = ['tosca.nodes.Database',
246                                   'tosca.nodes.WebServer']
247                 self.assertEqual(len(node_tpl.relationships), 2)
248                 self.assertEqual(
249                     expected_relationships,
250                     sorted([k.type for k in node_tpl.relationships.keys()]))
251                 self.assertEqual(
252                     expected_hosts,
253                     sorted([v.type for v in node_tpl.relationships.values()]))
254
255     def test_repositories(self):
256         template = ToscaTemplate(self.tosca_repo_tpl)
257         self.assertEqual(
258             ['repo_code0', 'repo_code1', 'repo_code2'],
259             sorted([input.name for input in template.repositories]))
260
261         input_name = "repo_code2"
262         expected_url = "https://github.com/nandinivemula/intern/master"
263         for input in template.repositories:
264             if input.name == input_name:
265                 self.assertEqual(input.url, expected_url)
266
267     def test_template_macro(self):
268         template = ToscaTemplate(self.tosca_elk_tpl)
269         for node_tpl in template.nodetemplates:
270             if node_tpl.name == 'mongo_server':
271                 self.assertEqual(
272                     ['disk_size', 'mem_size', 'num_cpus'],
273                     sorted(node_tpl.get_capability('host').
274                            get_properties().keys()))
275
276     def test_template_requirements(self):
277         """Test different formats of requirements
278
279         The requirements can be defined in few different ways,
280         1. Requirement expressed as a capability with an implicit relationship.
281         2. Requirement expressed with explicit relationship.
282         3. Requirement expressed with a relationship template.
283         4. Requirement expressed via TOSCA types to provision a node
284            with explicit relationship.
285         5. Requirement expressed via TOSCA types with a filter.
286         """
287         tosca_tpl = os.path.join(
288             os.path.dirname(os.path.abspath(__file__)),
289             "data/test_requirements.yaml")
290         tosca = ToscaTemplate(tosca_tpl)
291         for node_tpl in tosca.nodetemplates:
292             if node_tpl.name == 'my_app':
293                 expected_relationship = [
294                     ('tosca.relationships.ConnectsTo', 'mysql_database'),
295                     ('tosca.relationships.HostedOn', 'my_webserver')]
296                 actual_relationship = sorted([
297                     (relation.type, node.name) for
298                     relation, node in node_tpl.relationships.items()])
299                 self.assertEqual(expected_relationship, actual_relationship)
300             if node_tpl.name == 'mysql_database':
301                     self.assertEqual(
302                         [('tosca.relationships.HostedOn', 'my_dbms')],
303                         [(relation.type, node.name) for
304                          relation,
305                          node in node_tpl.relationships.items()])
306             if node_tpl.name == 'my_server':
307                     self.assertEqual(
308                         [('tosca.relationships.AttachesTo', 'my_storage')],
309                         [(relation.type, node.name) for
310                          relation,
311                          node in node_tpl.relationships.items()])
312
313     def test_template_requirements_not_implemented(self):
314         # TODO(spzala): replace this test with new one once TOSCA types look up
315         # support is implemented.
316         """Requirements that yet need to be implemented
317
318         The following requirement formats are not yet implemented,
319         due to look up dependency:
320         1. Requirement expressed via TOSCA types to provision a node
321            with explicit relationship.
322         2. Requirement expressed via TOSCA types with a filter.
323         """
324         tpl_snippet_1 = '''
325         node_templates:
326           mysql_database:
327             type: tosca.nodes.Database
328             description: Requires a particular node type and relationship.
329                         To be full-filled via lookup into node repository.
330             requirements:
331               - req1:
332                   node: tosca.nodes.DBMS
333                   relationship: tosca.relationships.HostedOn
334         '''
335
336         tpl_snippet_2 = '''
337         node_templates:
338           my_webserver:
339             type: tosca.nodes.WebServer
340             description: Requires a particular node type with a filter.
341                          To be full-filled via lookup into node repository.
342             requirements:
343               - req1:
344                   node: tosca.nodes.Compute
345                   target_filter:
346                     properties:
347                       num_cpus: { in_range: [ 1, 4 ] }
348                       mem_size: { greater_or_equal: 2 }
349                     capabilities:
350                       - tosca.capabilities.OS:
351                           properties:
352                             architecture: x86_64
353                             type: linux
354         '''
355
356         tpl_snippet_3 = '''
357         node_templates:
358           my_webserver2:
359             type: tosca.nodes.WebServer
360             description: Requires a node type with a particular capability.
361                          To be full-filled via lookup into node repository.
362             requirements:
363               - req1:
364                   node: tosca.nodes.Compute
365                   relationship: tosca.relationships.HostedOn
366                   capability: tosca.capabilities.Container
367         '''
368         self._requirements_not_implemented(tpl_snippet_1, 'mysql_database')
369         self._requirements_not_implemented(tpl_snippet_2, 'my_webserver')
370         self._requirements_not_implemented(tpl_snippet_3, 'my_webserver2')
371
372     def _requirements_not_implemented(self, tpl_snippet, tpl_name):
373         nodetemplates = (toscaparser.utils.yamlparser.
374                          simple_parse(tpl_snippet))['node_templates']
375         self.assertRaises(
376             NotImplementedError,
377             lambda: NodeTemplate(tpl_name, nodetemplates).relationships)
378
379     # Test the following:
380     # 1. Custom node type derived from 'WebApplication' named 'TestApp'
381     #    with a custom Capability Type 'TestCapability'
382     # 2. Same as #1, but referencing a custom 'TestCapability' Capability Type
383     #    that is not defined
384     def test_custom_capability_type_definition(self):
385         tpl_snippet = '''
386         node_templates:
387           test_app:
388             type: tosca.nodes.WebApplication.TestApp
389             capabilities:
390               test_cap:
391                 properties:
392                   test: 1
393         '''
394         # custom node type definition with custom capability type definition
395         custom_def = '''
396         tosca.nodes.WebApplication.TestApp:
397           derived_from: tosca.nodes.WebApplication
398           capabilities:
399             test_cap:
400                type: tosca.capabilities.TestCapability
401         tosca.capabilities.TestCapability:
402           derived_from: tosca.capabilities.Root
403           properties:
404             test:
405               type: integer
406               required: false
407         '''
408         expected_capabilities = ['app_endpoint', 'feature', 'test_cap']
409         nodetemplates = (toscaparser.utils.yamlparser.
410                          simple_parse(tpl_snippet))['node_templates']
411         custom_def = (toscaparser.utils.yamlparser.
412                       simple_parse(custom_def))
413         name = list(nodetemplates.keys())[0]
414         tpl = NodeTemplate(name, nodetemplates, custom_def)
415         self.assertEqual(
416             expected_capabilities,
417             sorted(tpl.get_capabilities().keys()))
418
419         # custom definition without valid capability type definition
420         custom_def = '''
421         tosca.nodes.WebApplication.TestApp:
422           derived_from: tosca.nodes.WebApplication
423           capabilities:
424             test_cap:
425                type: tosca.capabilities.TestCapability
426         '''
427         custom_def = (toscaparser.utils.yamlparser.
428                       simple_parse(custom_def))
429         tpl = NodeTemplate(name, nodetemplates, custom_def)
430         err = self.assertRaises(
431             exception.InvalidTypeError,
432             lambda: NodeTemplate(name, nodetemplates,
433                                  custom_def).get_capabilities_objects())
434         self.assertEqual('Type "tosca.capabilities.TestCapability" is not '
435                          'a valid type.', six.text_type(err))
436
437     def test_local_template_with_local_relpath_import(self):
438         tosca_tpl = os.path.join(
439             os.path.dirname(os.path.abspath(__file__)),
440             "data/tosca_single_instance_wordpress.yaml")
441         tosca = ToscaTemplate(tosca_tpl)
442         self.assertTrue(tosca.topology_template.custom_defs)
443
444     def test_local_template_with_url_import(self):
445         tosca_tpl = os.path.join(
446             os.path.dirname(os.path.abspath(__file__)),
447             "data/tosca_single_instance_wordpress_with_url_import.yaml")
448         tosca = ToscaTemplate(tosca_tpl)
449         self.assertTrue(tosca.topology_template.custom_defs)
450
451     def test_url_template_with_local_relpath_import(self):
452         tosca_tpl = ('https://raw.githubusercontent.com/openstack/'
453                      'tosca-parser/master/toscaparser/tests/data/'
454                      'tosca_single_instance_wordpress.yaml')
455         tosca = ToscaTemplate(tosca_tpl, a_file=False,
456                               parsed_params={"db_name": "mysql",
457                                              "db_user": "mysql",
458                                              "db_root_pwd": "1234",
459                                              "db_pwd": "5678",
460                                              "db_port": 3306,
461                                              "cpus": 4})
462         self.assertTrue(tosca.topology_template.custom_defs)
463
464     def test_url_template_with_local_abspath_import(self):
465         tosca_tpl = ('https://raw.githubusercontent.com/openstack/'
466                      'tosca-parser/master/toscaparser/tests/data/'
467                      'tosca_single_instance_wordpress_with_local_abspath_'
468                      'import.yaml')
469         self.assertRaises(exception.ValidationError, ToscaTemplate, tosca_tpl,
470                           None, False)
471         err_msg = (_('Absolute file name "/tmp/tosca-parser/toscaparser/tests'
472                      '/data/custom_types/wordpress.yaml" cannot be used in a '
473                      'URL-based input template "%(tpl)s".')
474                    % {'tpl': tosca_tpl})
475         exception.ExceptionCollector.assertExceptionMessage(ImportError,
476                                                             err_msg)
477
478     def test_url_template_with_url_import(self):
479         tosca_tpl = ('https://raw.githubusercontent.com/openstack/'
480                      'tosca-parser/master/toscaparser/tests/data/'
481                      'tosca_single_instance_wordpress_with_url_import.yaml')
482         tosca = ToscaTemplate(tosca_tpl, a_file=False,
483                               parsed_params={"db_root_pwd": "1234"})
484         self.assertTrue(tosca.topology_template.custom_defs)
485
486     def test_csar_parsing_wordpress(self):
487         csar_archive = os.path.join(
488             os.path.dirname(os.path.abspath(__file__)),
489             'data/CSAR/csar_wordpress.zip')
490         self.assertTrue(ToscaTemplate(csar_archive,
491                                       parsed_params={"db_name": "mysql",
492                                                      "db_user": "mysql",
493                                                      "db_root_pwd": "1234",
494                                                      "db_pwd": "5678",
495                                                      "db_port": 3306,
496                                                      "cpus": 4}))
497
498     def test_csar_parsing_elk_url_based(self):
499         csar_archive = ('https://github.com/openstack/tosca-parser/raw/master/'
500                         'toscaparser/tests/data/CSAR/csar_elk.zip')
501         self.assertTrue(ToscaTemplate(csar_archive, a_file=False,
502                                       parsed_params={"my_cpus": 4}))
503
504     def test_nested_imports_in_templates(self):
505         tosca_tpl = os.path.join(
506             os.path.dirname(os.path.abspath(__file__)),
507             "data/test_instance_nested_imports.yaml")
508         tosca = ToscaTemplate(tosca_tpl)
509         expected_custom_types = ['tosca.nodes.WebApplication.WordPress',
510                                  'test_namespace_prefix.Rsyslog',
511                                  'Test2ndRsyslogType',
512                                  'test_2nd_namespace_prefix.Rsyslog',
513                                  'tosca.nodes.SoftwareComponent.Logstash',
514                                  'tosca.nodes.SoftwareComponent.Rsyslog.'
515                                  'TestRsyslogType']
516         self.assertItemsEqual(tosca.topology_template.custom_defs.keys(),
517                               expected_custom_types)
518
519     def test_invalid_template_file(self):
520         template_file = 'invalid template file'
521         expected_msg = (_('"%s" is not a valid file.') % template_file)
522         self.assertRaises(
523             exception.ValidationError,
524             ToscaTemplate, template_file, None, False)
525         exception.ExceptionCollector.assertExceptionMessage(ValueError,
526                                                             expected_msg)
527
528     def test_multiple_validation_errors(self):
529         tosca_tpl = os.path.join(
530             os.path.dirname(os.path.abspath(__file__)),
531             "data/test_multiple_validation_errors.yaml")
532         self.assertRaises(exception.ValidationError, ToscaTemplate, tosca_tpl,
533                           None)
534         valid_versions = ', '.join(ToscaTemplate.VALID_TEMPLATE_VERSIONS)
535         err1_msg = (_('The template version "tosca_simple_yaml_1" is invalid. '
536                       'Valid versions are "%s".') % valid_versions)
537         exception.ExceptionCollector.assertExceptionMessage(
538             exception.InvalidTemplateVersion, err1_msg)
539
540         err2_msg = _('Import "custom_types/not_there.yaml" is not valid.')
541         exception.ExceptionCollector.assertExceptionMessage(
542             ImportError, err2_msg)
543
544         err3_msg = _('Type "tosca.nodes.WebApplication.WordPress" is not a '
545                      'valid type.')
546         exception.ExceptionCollector.assertExceptionMessage(
547             exception.InvalidTypeError, err3_msg)
548
549         err4_msg = _('Node template "wordpress" contains unknown field '
550                      '"requirement". Refer to the definition to verify valid '
551                      'values.')
552         exception.ExceptionCollector.assertExceptionMessage(
553             exception.UnknownFieldError, err4_msg)
554
555         err5_msg = _('\'Property "passwords" was not found in node template '
556                      '"mysql_database".\'')
557         exception.ExceptionCollector.assertExceptionMessage(
558             KeyError, err5_msg)
559
560         err6_msg = _('Template "mysql_dbms" is missing required field "type".')
561         exception.ExceptionCollector.assertExceptionMessage(
562             exception.MissingRequiredFieldError, err6_msg)
563
564         err7_msg = _('Node template "mysql_dbms" contains unknown field '
565                      '"type1". Refer to the definition to verify valid '
566                      'values.')
567         exception.ExceptionCollector.assertExceptionMessage(
568             exception.UnknownFieldError, err7_msg)
569
570         err8_msg = _('\'Node template "server1" was not found.\'')
571         exception.ExceptionCollector.assertExceptionMessage(
572             KeyError, err8_msg)
573
574         err9_msg = _('"relationship" used in template "webserver" is missing '
575                      'required field "type".')
576         exception.ExceptionCollector.assertExceptionMessage(
577             exception.MissingRequiredFieldError, err9_msg)
578
579     def test_invalid_section_names(self):
580         tosca_tpl = os.path.join(
581             os.path.dirname(os.path.abspath(__file__)),
582             "data/test_invalid_section_names.yaml")
583         self.assertRaises(exception.ValidationError, ToscaTemplate, tosca_tpl,
584                           None)
585         err1_msg = _('Template contains unknown field '
586                      '"tosca_definitions_versions". Refer to the definition '
587                      'to verify valid values.')
588         exception.ExceptionCollector.assertExceptionMessage(
589             exception.UnknownFieldError, err1_msg)
590
591         err2_msg = _('Template contains unknown field "descriptions". '
592                      'Refer to the definition to verify valid values.')
593         exception.ExceptionCollector.assertExceptionMessage(
594             exception.UnknownFieldError, err2_msg)
595
596         err3_msg = _('Template contains unknown field "import". Refer to '
597                      'the definition to verify valid values.')
598         exception.ExceptionCollector.assertExceptionMessage(
599             exception.UnknownFieldError, err3_msg)
600
601         err4_msg = _('Template contains unknown field "topology_templates". '
602                      'Refer to the definition to verify valid values.')
603         exception.ExceptionCollector.assertExceptionMessage(
604             exception.UnknownFieldError, err4_msg)
605
606     def test_csar_with_alternate_extenstion(self):
607         tosca_tpl = os.path.join(
608             os.path.dirname(os.path.abspath(__file__)),
609             "data/CSAR/csar_elk.csar")
610         tosca = ToscaTemplate(tosca_tpl, parsed_params={"my_cpus": 2})
611         self.assertTrue(tosca.topology_template.custom_defs)
612
613     def test_available_rel_tpls(self):
614         tosca_tpl = os.path.join(
615             os.path.dirname(os.path.abspath(__file__)),
616             "data/test_available_rel_tpls.yaml")
617         tosca = ToscaTemplate(tosca_tpl)
618         for node in tosca.nodetemplates:
619             for relationship, target in node.relationships.items():
620                 try:
621                     target.relationships
622                 except TypeError as error:
623                     self.fail(error)
624
625     def test_no_input(self):
626         self.assertRaises(exception.ValidationError, ToscaTemplate, None,
627                           None, False, None)
628         err_msg = (('No path or yaml_dict_tpl was provided. '
629                     'There is nothing to parse.'))
630         exception.ExceptionCollector.assertExceptionMessage(ValueError,
631                                                             err_msg)
632
633     def test_path_and_yaml_dict_tpl_input(self):
634         test_tpl = os.path.join(
635             os.path.dirname(os.path.abspath(__file__)),
636             "data/tosca_helloworld.yaml")
637
638         yaml_dict_tpl = toscaparser.utils.yamlparser.load_yaml(test_tpl)
639
640         tosca = ToscaTemplate(test_tpl, yaml_dict_tpl=yaml_dict_tpl)
641
642         self.assertEqual(tosca.version, "tosca_simple_yaml_1_0")
643
644     def test_yaml_dict_tpl_input(self):
645         test_tpl = os.path.join(
646             os.path.dirname(os.path.abspath(__file__)),
647             "data/tosca_helloworld.yaml")
648
649         yaml_dict_tpl = toscaparser.utils.yamlparser.load_yaml(test_tpl)
650
651         tosca = ToscaTemplate(yaml_dict_tpl=yaml_dict_tpl)
652
653         self.assertEqual(tosca.version, "tosca_simple_yaml_1_0")
654
655     def test_yaml_dict_tpl_with_params_and_url_import(self):
656         test_tpl = os.path.join(
657             os.path.dirname(os.path.abspath(__file__)),
658             "data/tosca_single_instance_wordpress_with_url_import.yaml")
659
660         yaml_dict_tpl = toscaparser.utils.yamlparser.load_yaml(test_tpl)
661
662         params = {'db_name': 'my_wordpress', 'db_user': 'my_db_user',
663                   'db_root_pwd': 'mypasswd'}
664
665         tosca = ToscaTemplate(parsed_params=params,
666                               yaml_dict_tpl=yaml_dict_tpl)
667
668         self.assertEqual(tosca.version, "tosca_simple_yaml_1_0")
669
670     def test_yaml_dict_tpl_with_rel_import(self):
671         test_tpl = os.path.join(
672             os.path.dirname(os.path.abspath(__file__)),
673             "data/tosca_single_instance_wordpress.yaml")
674
675         yaml_dict_tpl = toscaparser.utils.yamlparser.load_yaml(test_tpl)
676
677         self.assertRaises(exception.ValidationError, ToscaTemplate, None,
678                           None, False, yaml_dict_tpl)
679         err_msg = (_('Relative file name "custom_types/wordpress.yaml" '
680                      'cannot be used in a pre-parsed input template.'))
681         exception.ExceptionCollector.assertExceptionMessage(ImportError,
682                                                             err_msg)
683
684     def test_yaml_dict_tpl_with_fullpath_import(self):
685         test_tpl = os.path.join(
686             os.path.dirname(os.path.abspath(__file__)),
687             "data/tosca_single_instance_wordpress.yaml")
688
689         yaml_dict_tpl = toscaparser.utils.yamlparser.load_yaml(test_tpl)
690
691         yaml_dict_tpl['imports'] = [os.path.join(os.path.dirname(
692             os.path.abspath(__file__)), "data/custom_types/wordpress.yaml")]
693
694         params = {'db_name': 'my_wordpress', 'db_user': 'my_db_user',
695                   'db_root_pwd': 'mypasswd'}
696
697         tosca = ToscaTemplate(parsed_params=params,
698                               yaml_dict_tpl=yaml_dict_tpl)
699
700         self.assertEqual(tosca.version, "tosca_simple_yaml_1_0")
701
702     def test_policies_for_node_templates(self):
703         tosca_tpl = os.path.join(
704             os.path.dirname(os.path.abspath(__file__)),
705             "data/policies/tosca_policy_template.yaml")
706         tosca = ToscaTemplate(tosca_tpl)
707
708         for policy in tosca.topology_template.policies:
709             if policy.name == 'my_compute_placement_policy':
710                 self.assertEqual('tosca.policies.Placement', policy.type)
711                 self.assertEqual(['my_server_1', 'my_server_2'],
712                                  policy.targets)
713                 self.assertEqual('node_templates', policy.get_targets_type())
714                 for node in policy.targets_list:
715                     if node.name == 'my_server_1':
716                         '''Test property value'''
717                         props = node.get_properties()
718                         if props and 'mem_size' in props.keys():
719                             self.assertEqual(props['mem_size'].value,
720                                              '4096 MB')
721
722     def test_policies_for_groups(self):
723         tosca_tpl = os.path.join(
724             os.path.dirname(os.path.abspath(__file__)),
725             "data/policies/tosca_policy_template.yaml")
726         tosca = ToscaTemplate(tosca_tpl)
727
728         for policy in tosca.topology_template.policies:
729             if policy.name == 'my_groups_placement':
730                 self.assertEqual('mycompany.mytypes.myScalingPolicy',
731                                  policy.type)
732                 self.assertEqual(['webserver_group'], policy.targets)
733                 self.assertEqual('groups', policy.get_targets_type())
734                 group = policy.get_targets_list()[0]
735                 for node in group.get_member_nodes():
736                     if node.name == 'my_server_2':
737                         '''Test property value'''
738                         props = node.get_properties()
739                         if props and 'mem_size' in props.keys():
740                             self.assertEqual(props['mem_size'].value,
741                                              '4096 MB')
742
743     def test_node_filter(self):
744         tosca_tpl = os.path.join(
745             os.path.dirname(os.path.abspath(__file__)),
746             "data/test_node_filter.yaml")
747         ToscaTemplate(tosca_tpl)
748
749     def test_attributes_inheritance(self):
750         tosca_tpl = os.path.join(
751             os.path.dirname(os.path.abspath(__file__)),
752             "data/test_attributes_inheritance.yaml")
753         ToscaTemplate(tosca_tpl)
754
755     def test_repositories_definition(self):
756         tosca_tpl = os.path.join(
757             os.path.dirname(os.path.abspath(__file__)),
758             "data/test_repositories_definition.yaml")
759         ToscaTemplate(tosca_tpl)
760
761     def test_custom_caps_def(self):
762         tosca_tpl = os.path.join(
763             os.path.dirname(os.path.abspath(__file__)),
764             "data/test_custom_caps_def.yaml")
765         ToscaTemplate(tosca_tpl)
766
767     def test_custom_rel_with_script(self):
768         tosca_tpl = os.path.join(
769             os.path.dirname(os.path.abspath(__file__)),
770             "data/test_tosca_custom_rel_with_script.yaml")
771         tosca = ToscaTemplate(tosca_tpl)
772         rel = tosca.relationship_templates[0]
773         self.assertEqual(rel.type, "tosca.relationships.HostedOn")
774         self.assertTrue(rel.is_derived_from("tosca.relationships.Root"))
775         self.assertEqual(len(rel.interfaces), 1)
776         self.assertEqual(rel.interfaces[0].type, "Configure")
777
778     def test_various_portspec_errors(self):
779         tosca_tpl = os.path.join(
780             os.path.dirname(os.path.abspath(__file__)),
781             "data/datatypes/test_datatype_portspec_add_req.yaml")
782         self.assertRaises(exception.ValidationError, ToscaTemplate, tosca_tpl,
783                           None)
784
785         # TODO(TBD) find way to reuse error messages from constraints.py
786         msg = (_('The value "%(pvalue)s" of property "%(pname)s" is out of '
787                  'range "(min:%(vmin)s, max:%(vmax)s)".') %
788                dict(pname=PortSpec.SOURCE,
789                     pvalue='0',
790                     vmin='1',
791                     vmax='65535'))
792         exception.ExceptionCollector.assertExceptionMessage(
793             exception.ValidationError, msg)
794
795         # Test value below range min.
796         msg = (_('The value "%(pvalue)s" of property "%(pname)s" is out of '
797                  'range "(min:%(vmin)s, max:%(vmax)s)".') %
798                dict(pname=PortSpec.SOURCE,
799                     pvalue='1',
800                     vmin='2',
801                     vmax='65534'))
802         exception.ExceptionCollector.assertExceptionMessage(
803             exception.RangeValueError, msg)
804
805         # Test value above range max.
806         msg = (_('The value "%(pvalue)s" of property "%(pname)s" is out of '
807                  'range "(min:%(vmin)s, max:%(vmax)s)".') %
808                dict(pname=PortSpec.SOURCE,
809                     pvalue='65535',
810                     vmin='2',
811                     vmax='65534'))
812         exception.ExceptionCollector.assertExceptionMessage(
813             exception.RangeValueError, msg)
814
815     def test_containers(self):
816         tosca_tpl = os.path.join(
817             os.path.dirname(os.path.abspath(__file__)),
818             "data/test_containers.yaml")
819         ToscaTemplate(tosca_tpl, parsed_params={"mysql_root_pwd": "12345678"})