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