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