You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ariatosca.apache.org by em...@apache.org on 2017/08/18 20:59:02 UTC

incubator-ariatosca git commit: Testing types and templates [Forced Update!]

Repository: incubator-ariatosca
Updated Branches:
  refs/heads/ARIA-1-parser-test-suite bd95c4f47 -> 93c88803b (forced update)


Testing types and templates

* Fix "version" fields in types
* Improve version testing


Project: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/commit/93c88803
Tree: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/tree/93c88803
Diff: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/diff/93c88803

Branch: refs/heads/ARIA-1-parser-test-suite
Commit: 93c88803bb469b8e4a8e8a0f5883b31ba67db25a
Parents: 526befd
Author: Tal Liron <ta...@gmail.com>
Authored: Fri Aug 18 15:52:31 2017 -0500
Committer: Tal Liron <ta...@gmail.com>
Committed: Fri Aug 18 15:58:56 2017 -0500

----------------------------------------------------------------------
 aria/parser/presentation/fields.py              |   2 +-
 aria/utils/versions.py                          |   2 +-
 .../simple_v1_0/presentation/field_getters.py   |  20 +--
 .../aria_extension_tosca/simple_v1_0/types.py   |  23 +--
 .../simple_v1_0/conftest.py                     |  23 ++-
 .../aria_extension_tosca/simple_v1_0/data.py    |  40 ++++++
 .../simple_v1_0/test_imports.py                 |  18 +--
 .../simple_v1_0/test_metadata.py                |  58 ++++----
 .../simple_v1_0/test_templates.py               | 116 +++++++++++++++
 .../simple_v1_0/test_types.py                   | 141 +++++++++++++++++++
 tests/mechanisms/parsing/__init__.py            |  28 +++-
 tests/mechanisms/web_server.py                  |  10 +-
 .../node-cellar/node-cellar.yaml                |   2 +-
 tests/utils/test_versions.py                    |   8 +-
 14 files changed, 421 insertions(+), 70 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/93c88803/aria/parser/presentation/fields.py
----------------------------------------------------------------------
diff --git a/aria/parser/presentation/fields.py b/aria/parser/presentation/fields.py
index 5c08d4a..98394d9 100644
--- a/aria/parser/presentation/fields.py
+++ b/aria/parser/presentation/fields.py
@@ -733,7 +733,7 @@ class Field(object):
                             primitive_dict[k] = self._coerce_primitive(v, context)
                         except ValueError as e:
                             raise InvalidValueError('%s is not a dict of "%s" values:'
-                                                    ' entry "%d" is %s'
+                                                    ' entry "%s" is %s'
                                                     % (self.full_name, self.full_cls_name,
                                                        k, safe_repr(v)),
                                                     locator=self.get_locator(raw),

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/93c88803/aria/utils/versions.py
----------------------------------------------------------------------
diff --git a/aria/utils/versions.py b/aria/utils/versions.py
index 521004c..507f055 100644
--- a/aria/utils/versions.py
+++ b/aria/utils/versions.py
@@ -24,7 +24,7 @@ _INF = float('inf')
 
 _NULL = (), _INF
 
-_DIGITS_RE = re.compile(r'^\d+$')
+_DIGITS_RE = re.compile(r'^\d+$', flags=re.UNICODE)
 
 _PREFIXES = {
     'dev':   0.0001,

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/93c88803/extensions/aria_extension_tosca/simple_v1_0/presentation/field_getters.py
----------------------------------------------------------------------
diff --git a/extensions/aria_extension_tosca/simple_v1_0/presentation/field_getters.py b/extensions/aria_extension_tosca/simple_v1_0/presentation/field_getters.py
index 34dacd6..f53a5cc 100644
--- a/extensions/aria_extension_tosca/simple_v1_0/presentation/field_getters.py
+++ b/extensions/aria_extension_tosca/simple_v1_0/presentation/field_getters.py
@@ -16,6 +16,7 @@
 from aria.utils.formatting import safe_repr
 from aria.utils.type import full_type_name
 from aria.parser.exceptions import InvalidValueError
+from aria.parser.presentation import NULL
 
 
 def data_type_class_getter(cls):
@@ -27,13 +28,14 @@ def data_type_class_getter(cls):
 
     def getter(field, presentation, context=None):
         raw = field.default_get(presentation, context)
-        if raw is not None:
-            try:
-                return cls(None, None, raw, None)
-            except ValueError as e:
-                raise InvalidValueError(
-                    '{0} is not a valid "{1}" in "{2}": {3}'
-                    .format(field.full_name, full_type_name(cls), presentation._name,
-                            safe_repr(raw)),
-                    cause=e, locator=field.get_locator(raw))
+        if (raw is None) or (raw is NULL):
+            return raw
+        try:
+            return cls(None, None, raw, None)
+        except ValueError as e:
+            raise InvalidValueError(
+                '{0} is not a valid "{1}" in "{2}": {3}'
+                .format(field.full_name, full_type_name(cls), presentation._name,
+                        safe_repr(raw)),
+                cause=e, locator=field.get_locator(raw))
     return getter

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/93c88803/extensions/aria_extension_tosca/simple_v1_0/types.py
----------------------------------------------------------------------
diff --git a/extensions/aria_extension_tosca/simple_v1_0/types.py b/extensions/aria_extension_tosca/simple_v1_0/types.py
index 787aac2..e118c9f 100644
--- a/extensions/aria_extension_tosca/simple_v1_0/types.py
+++ b/extensions/aria_extension_tosca/simple_v1_0/types.py
@@ -70,7 +70,7 @@ class ArtifactType(ExtensiblePresentation):
         """
 
     @field_getter(data_type_class_getter(Version))
-    @primitive_field()
+    @primitive_field(str)
     def version(self):
         """
         An optional version for the Artifact Type definition.
@@ -153,7 +153,8 @@ class DataType(ExtensiblePresentation):
         :type: :obj:`basestring`
         """
 
-    @object_field(Version)
+    @field_getter(data_type_class_getter(Version))
+    @primitive_field(str)
     def version(self):
         """
         An optional version for the Data Type definition.
@@ -250,7 +251,8 @@ class CapabilityType(ExtensiblePresentation):
         :type: :obj:`basestring`
         """
 
-    @object_field(Version)
+    @field_getter(data_type_class_getter(Version))
+    @primitive_field(str)
     def version(self):
         """
         An optional version for the Capability Type definition.
@@ -351,7 +353,8 @@ class InterfaceType(ExtensiblePresentation):
         :type: :obj:`basestring`
         """
 
-    @object_field(Version)
+    @field_getter(data_type_class_getter(Version))
+    @primitive_field(str)
     def version(self):
         """
         An optional version for the Interface Type definition.
@@ -430,7 +433,8 @@ class RelationshipType(ExtensiblePresentation):
         :type: :obj:`basestring`
         """
 
-    @object_field(Version)
+    @field_getter(data_type_class_getter(Version))
+    @primitive_field(str)
     def version(self):
         """
         An optional version for the Relationship Type definition.
@@ -545,7 +549,8 @@ class NodeType(ExtensiblePresentation):
         :type: :obj:`basestring`
         """
 
-    @object_field(Version)
+    @field_getter(data_type_class_getter(Version))
+    @primitive_field(str)
     def version(self):
         """
         An optional version for the Node Type definition.
@@ -701,7 +706,8 @@ class GroupType(ExtensiblePresentation):
         :type: :obj:`basestring`
         """
 
-    @object_field(Version)
+    @field_getter(data_type_class_getter(Version))
+    @primitive_field(str)
     def version(self):
         """
         An optional version for the Group Type definition.
@@ -807,7 +813,8 @@ class PolicyType(ExtensiblePresentation):
         :type: :obj:`basestring`
         """
 
-    @object_field(Version)
+    @field_getter(data_type_class_getter(Version))
+    @primitive_field(str)
     def version(self):
         """
         An optional version for the Policy Type definition.

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/93c88803/tests/extensions/aria_extension_tosca/simple_v1_0/conftest.py
----------------------------------------------------------------------
diff --git a/tests/extensions/aria_extension_tosca/simple_v1_0/conftest.py b/tests/extensions/aria_extension_tosca/simple_v1_0/conftest.py
index 86bbc3f..399e8c8 100644
--- a/tests/extensions/aria_extension_tosca/simple_v1_0/conftest.py
+++ b/tests/extensions/aria_extension_tosca/simple_v1_0/conftest.py
@@ -13,16 +13,31 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+"""
+PyTest configuration module.
+"""
+
 import pytest
 
 from ....mechanisms.parsing.aria import AriaParser
 
 
+def pytest_addoption(parser):
+    parser.addoption('--tosca-parser', action='store', default='aria', help='TOSCA parser')
+
+
 def pytest_report_header(config):
-    return 'parser: ARIA'
+    tosca_parser = config.getoption('--tosca-parser')
+    return 'tosca-parser: {0}'.format(tosca_parser)
 
 
 @pytest.fixture(scope='session')
-def parser():
-    with AriaParser() as p:
-        yield p
+def parser(request):
+    tosca_parser = request.config.getoption('--tosca-parser')
+    verbose = request.config.getoption('verbose') > 0
+    if tosca_parser == 'aria':
+        with AriaParser() as p:
+            p.verbose = verbose
+            yield p
+    else:
+        pytest.fail('configured tosca-parser not supported: {0}'.format(tosca_parser))

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/93c88803/tests/extensions/aria_extension_tosca/simple_v1_0/data.py
----------------------------------------------------------------------
diff --git a/tests/extensions/aria_extension_tosca/simple_v1_0/data.py b/tests/extensions/aria_extension_tosca/simple_v1_0/data.py
new file mode 100644
index 0000000..b24fb29
--- /dev/null
+++ b/tests/extensions/aria_extension_tosca/simple_v1_0/data.py
@@ -0,0 +1,40 @@
+# -*- coding: utf-8 -*-
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+NOT_A_DICT = ('null', 'a string', '123', '0.123', '[]')
+NOT_A_LIST = ('null', 'a string', '123', '0.123', '{}')
+NOT_A_STRING = ('123', '0.123', '[]', '{}')
+TYPE_NAMES = ('artifact', 'data', 'capability', 'interface', 'relationship', 'node', 'group',
+              'policy')
+TYPE_NAME_PLURAL = {
+    'artifact': 'artifacts',
+    'data': 'datatypes',
+    'capability': 'capabilities',
+    'interface': 'interfaces',
+    'relationship': 'relationships',
+    'node': 'nodes',
+    'group': 'groups',
+    'policy': 'policies'
+}
+TEMPLATE_NAMES = ('node', 'group', 'policy')
+TEMPLATE_NAME_SECTION = {
+    'node': 'node_templates',
+    'group': 'groups',
+    'policy': 'policies'
+}
+GOOD_VERSIONS = ("'6.1'", '2.0.1', '3.1.0.beta', "'1.0.0.alpha-10'")
+BAD_VERSIONS = ('a_string', '1.2.3.4.5', '1.2.beta', '1.0.0.alpha-x')

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/93c88803/tests/extensions/aria_extension_tosca/simple_v1_0/test_imports.py
----------------------------------------------------------------------
diff --git a/tests/extensions/aria_extension_tosca/simple_v1_0/test_imports.py b/tests/extensions/aria_extension_tosca/simple_v1_0/test_imports.py
index 4d78f40..765cd8b 100644
--- a/tests/extensions/aria_extension_tosca/simple_v1_0/test_imports.py
+++ b/tests/extensions/aria_extension_tosca/simple_v1_0/test_imports.py
@@ -16,9 +16,12 @@
 
 import pytest
 
+from . import data
 from ....mechanisms.web_server import WebServer
 
 
+# Fixtures
+
 NODE_TYPE_IMPORT = """
 node_types:
   MyNode:
@@ -35,17 +38,16 @@ node_types:
 def repository():
     repository = WebServer()
     repository.add_text_yaml('/imports/node-type.yaml', NODE_TYPE_IMPORT)
-    repository.add_text_yaml('/imports/{0}.yaml'.format(WebServer.escape('詠嘆調')),
+    repository.add_text_yaml('/imports/{0}.yaml'.format(WebServer.escape('節點類型')),
                              NODE_TYPE_IMPORT)
     repository.add_text_yaml('/imports/bad.yaml', BAD_IMPORT)
-    repository.start()
-    yield repository.root
-    repository.stop()
+    with repository:
+        yield repository.root
 
 
 # Syntax
 
-@pytest.mark.parametrize('value', ('null', 'a_string', '123', '0.123', '{}'))
+@pytest.mark.parametrize('value', data.NOT_A_LIST)
 def test_imports_wrong_yaml_type(parser, value):
     parser.parse_literal("""
 tosca_definitions_version: tosca_simple_yaml_1_0
@@ -53,7 +55,7 @@ imports: {{ value }}
 """, dict(value=value)).assert_failure()
 
 
-def test_imports_empty_list(parser):
+def test_imports_empty(parser):
     parser.parse_literal("""
 tosca_definitions_version: tosca_simple_yaml_1_0
 imports: []
@@ -75,10 +77,10 @@ topology_template:
 
 
 def test_import_single_short_form_unicode(parser, repository):
-    parser.parse_literal(u"""
+    parser.parse_literal("""
 tosca_definitions_version: tosca_simple_yaml_1_0
 imports:
-  - {{ repository }}/imports/詠嘆調.yaml
+  - {{ repository }}/imports/節點類型.yaml
 topology_template:
   node_templates:
     my_node:

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/93c88803/tests/extensions/aria_extension_tosca/simple_v1_0/test_metadata.py
----------------------------------------------------------------------
diff --git a/tests/extensions/aria_extension_tosca/simple_v1_0/test_metadata.py b/tests/extensions/aria_extension_tosca/simple_v1_0/test_metadata.py
index dae5631..3f89bf6 100644
--- a/tests/extensions/aria_extension_tosca/simple_v1_0/test_metadata.py
+++ b/tests/extensions/aria_extension_tosca/simple_v1_0/test_metadata.py
@@ -14,12 +14,16 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+import itertools
+
 import pytest
 
+from . import data
+
 
 # Syntax
 
-@pytest.mark.parametrize('value', ('null', 'a_string', '123', '0.123', '[]'))
+@pytest.mark.parametrize('value', data.NOT_A_DICT)
 def test_metadata_wrong_yaml_type(parser, value):
     parser.parse_literal("""
 tosca_definitions_version: tosca_simple_yaml_1_0
@@ -27,20 +31,11 @@ metadata: {{ value }}
 """, dict(value=value)).assert_failure()
 
 
-@pytest.mark.parametrize('field,value', (
-    ('template_name', '123'),
-    ('template_name', '0.123'),
-    ('template_name', '[]'),
-    ('template_name', '{}'),
-    ('template_author', '123'),
-    ('template_author', '0.123'),
-    ('template_author', '[]'),
-    ('template_author', '{}'),
-    ('template_version', '123'),
-    ('template_version', '0.123'),
-    ('template_version', '[]'),
-    ('template_version', '{}')))
-def test_metadata_normative_wrong_yaml_type(parser, field, value):
+@pytest.mark.parametrize('field,value', itertools.product(
+    ('template_name', 'template_author', 'template_version'),
+    data.NOT_A_STRING
+))
+def test_metadata_normative_fields_wrong_yaml_type(parser, field, value):
     parser.parse_literal("""
 tosca_definitions_version: tosca_simple_yaml_1_0
 metadata:
@@ -48,8 +43,8 @@ metadata:
 """, dict(field=field, value=value)).assert_failure()
 
 
-@pytest.mark.parametrize('value', ('123', '0.123', '[]', '{}'))
-def test_metadata_non_normative_wrong_yaml_type(parser, value):
+@pytest.mark.parametrize('value', data.NOT_A_STRING)
+def test_metadata_non_normative_fields_wrong_yaml_type(parser, value):
     parser.parse_literal("""
 tosca_definitions_version: tosca_simple_yaml_1_0
 metadata:
@@ -57,7 +52,7 @@ metadata:
 """, dict(value=value)).assert_failure()
 
 
-def test_metadata_empty_dict(parser):
+def test_metadata_empty(parser):
     parser.parse_literal("""
 tosca_definitions_version: tosca_simple_yaml_1_0
 metadata: {}
@@ -66,22 +61,23 @@ metadata: {}
 
 # Normative
 
-@pytest.mark.parametrize('value', ('null', 'a_string', '1.2.3.4.5'))
-def test_metadata_normative_template_bad_version(parser, value):
+@pytest.mark.parametrize('value', data.GOOD_VERSIONS)
+def test_metadata_normative_template_version(parser, value):
     parser.parse_literal("""
 tosca_definitions_version: tosca_simple_yaml_1_0
 metadata:
     template_version: {{ value }}
-""", dict(value=value)).assert_failure()
+""", dict(value=value)).assert_success()
 
 
-@pytest.mark.parametrize('value', ("'6.1'", '2.0.1', '3.1.0.beta', "'1.0.0.alpha-10'"))
-def test_metadata_normative_template_version(parser, value):
+@pytest.mark.parametrize('value', data.BAD_VERSIONS)
+def test_metadata_normative_template_bad_version(parser, value):
     parser.parse_literal("""
 tosca_definitions_version: tosca_simple_yaml_1_0
 metadata:
     template_version: {{ value }}
-""", dict(value=value)).assert_success()
+""", dict(value=value)).assert_failure()
+
 
 # Non-normative
 
@@ -91,7 +87,7 @@ tosca_definitions_version: tosca_simple_yaml_1_0
 metadata:
   template_name: name
   template_author: author
-  template_version: 1.0.0.beta
+  template_version: 1.0.0.alpha-10
   non_normative1: non_normative1
   non_normative2: non_normative2
   non_normative3: non_normative3
@@ -104,7 +100,7 @@ tosca_definitions_version: tosca_simple_yaml_1_0
 metadata:
   template_name: null
   template_author: null
-  template_version: 1.0.0.beta
+  template_version: null
   non_normative1: null
   non_normative2: null
   non_normative3: null
@@ -112,13 +108,13 @@ metadata:
 
 
 def test_metadata_with_non_normative_fields_unicode(parser):
-    parser.parse_literal(u"""
+    parser.parse_literal("""
 tosca_definitions_version: tosca_simple_yaml_1_0
 metadata:
   template_name: 詠嘆調
   template_author: 詠嘆調
-  template_version: 1.0.0.詠嘆調
-  non_normative1: 詠嘆調
-  non_normative2: 詠嘆調
-  non_normative3: 詠嘆調
+  template_version: 1.0.0.詠嘆調-10
+  non_normative1: 詠嘆調一
+  non_normative2: 詠嘆調二
+  non_normative3: 詠嘆調三
 """).assert_success()

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/93c88803/tests/extensions/aria_extension_tosca/simple_v1_0/test_templates.py
----------------------------------------------------------------------
diff --git a/tests/extensions/aria_extension_tosca/simple_v1_0/test_templates.py b/tests/extensions/aria_extension_tosca/simple_v1_0/test_templates.py
new file mode 100644
index 0000000..ecbc2d9
--- /dev/null
+++ b/tests/extensions/aria_extension_tosca/simple_v1_0/test_templates.py
@@ -0,0 +1,116 @@
+# -*- coding: utf-8 -*-
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import itertools
+
+import pytest
+
+from . import data
+
+
+# Syntax
+
+@pytest.mark.parametrize('value', data.NOT_A_DICT)
+def test_topology_template_wrong_yaml_type(parser, value):
+    parser.parse_literal("""
+tosca_definitions_version: tosca_simple_yaml_1_0
+topology_template: {{ value }}
+""", dict(value=value)).assert_failure()
+
+
+def test_topology_template_emtpy(parser):
+    parser.parse_literal("""
+tosca_definitions_version: tosca_simple_yaml_1_0
+topology_template: {}
+""").assert_success()
+
+
+@pytest.mark.parametrize('name,value', itertools.product(
+    data.TEMPLATE_NAMES,
+    data.NOT_A_DICT
+))
+def test_template_section_wrong_yaml_type(parser, name, value):
+    parser.parse_literal("""
+tosca_definitions_version: tosca_simple_yaml_1_0
+topology_template:
+  {{ section }}: {{ value }}
+""", dict(section=data.TEMPLATE_NAME_SECTION[name], value=value)).assert_failure()
+
+
+@pytest.mark.parametrize('name,value', itertools.product(
+    data.TEMPLATE_NAMES,
+    data.NOT_A_STRING
+))
+def test_template_type_wrong_yaml_type(parser, name, value):
+    parser.parse_literal("""
+tosca_definitions_version: tosca_simple_yaml_1_0
+topology_template:
+  {{ section }}:
+    my_template:
+      type: {{ value }}
+""", dict(section=data.TEMPLATE_NAME_SECTION[name], value=value)).assert_failure()
+
+
+# Common fields
+
+@pytest.mark.parametrize('name', data.TEMPLATE_NAMES)
+def test_template_fields(parser, name):
+    parser.parse_literal("""
+tosca_definitions_version: tosca_simple_yaml_1_0
+topology_template:
+  {{ section }}:
+    my_template:
+      type: tosca.{{ plural }}.Root
+      description: a description
+""", dict(section=data.TEMPLATE_NAME_SECTION[name],
+          plural=data.TYPE_NAME_PLURAL[name])).assert_success()
+
+
+# Of types
+
+@pytest.mark.parametrize('name', data.TEMPLATE_NAMES)
+def test_template_of_type(parser, name):
+    parser.parse_literal("""
+tosca_definitions_version: tosca_simple_yaml_1_0
+{{ name }}_types:
+    MyType: {}
+topology_template:
+  {{ section }}:
+    my_template:
+      type: MyType
+""", dict(name=name, section=data.TEMPLATE_NAME_SECTION[name])).assert_success()
+
+
+@pytest.mark.parametrize('name', data.TEMPLATE_NAMES)
+def test_template_of_unknown_type(parser, name):
+    parser.parse_literal("""
+tosca_definitions_version: tosca_simple_yaml_1_0
+topology_template:
+  {{ section }}:
+    my_template:
+      type: UnknownType
+""", dict(section=data.TEMPLATE_NAME_SECTION[name])).assert_failure()
+
+
+@pytest.mark.parametrize('name', data.TEMPLATE_NAMES)
+def test_template_of_null_type(parser, name):
+    parser.parse_literal("""
+tosca_definitions_version: tosca_simple_yaml_1_0
+topology_template:
+  {{ section }}:
+    my_template:
+      type: null
+""", dict(section=data.TEMPLATE_NAME_SECTION[name])).assert_failure()

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/93c88803/tests/extensions/aria_extension_tosca/simple_v1_0/test_types.py
----------------------------------------------------------------------
diff --git a/tests/extensions/aria_extension_tosca/simple_v1_0/test_types.py b/tests/extensions/aria_extension_tosca/simple_v1_0/test_types.py
new file mode 100644
index 0000000..3728851
--- /dev/null
+++ b/tests/extensions/aria_extension_tosca/simple_v1_0/test_types.py
@@ -0,0 +1,141 @@
+# -*- coding: utf-8 -*-
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import itertools
+
+import pytest
+
+from . import data
+
+
+# Syntax
+
+@pytest.mark.parametrize('name,value', itertools.product(
+    data.TYPE_NAMES,
+    data.NOT_A_DICT
+))
+def test_type_wrong_yaml_type(parser, name, value):
+    parser.parse_literal("""
+tosca_definitions_version: tosca_simple_yaml_1_0
+{{ name }}_types:
+  MyType: {{ value }}
+""", dict(name=name, value=value)).assert_failure()
+
+
+@pytest.mark.parametrize('name', data.TYPE_NAMES)
+def test_type_empty(parser, name):
+    parser.parse_literal("""
+tosca_definitions_version: tosca_simple_yaml_1_0
+{{ name }}_types:
+  MyType: {}
+""", dict(name=name)).assert_success()
+
+
+@pytest.mark.parametrize('name,value', itertools.product(
+    data.TYPE_NAMES,
+    data.NOT_A_STRING
+))
+def test_type_derived_from_wrong_yaml_type(parser, name, value):
+    parser.parse_literal("""
+tosca_definitions_version: tosca_simple_yaml_1_0
+{{ name }}_types:
+  MyType:
+    derived_from: {{ value }}
+""", dict(name=name, value=value)).assert_failure()
+
+
+
+# Derivation
+
+@pytest.mark.parametrize('name', data.TYPE_NAMES)
+def test_type_derived_from_unknown(parser, name):
+    parser.parse_literal("""
+tosca_definitions_version: tosca_simple_yaml_1_0
+{{ name }}_types:
+  MyType:
+    derived_from: UnknownType
+""", dict(name=name)).assert_failure()
+
+
+@pytest.mark.parametrize('name', data.TYPE_NAMES)
+def test_type_derived_from_null(parser, name):
+    parser.parse_literal("""
+tosca_definitions_version: tosca_simple_yaml_1_0
+{{ name }}_types:
+  MyType:
+    derived_from: null
+""", dict(name=name)).assert_failure()
+
+
+@pytest.mark.parametrize('name', data.TYPE_NAMES)
+def test_type_derived_from_self(parser, name):
+    parser.parse_literal("""
+tosca_definitions_version: tosca_simple_yaml_1_0
+{{ name }}_types:
+  MyType:
+    derived_from: MyType
+""", dict(name=name)).assert_failure()
+
+
+@pytest.mark.parametrize('name', data.TYPE_NAMES)
+def test_type_derived_from_circular(parser, name):
+    parser.parse_literal("""
+tosca_definitions_version: tosca_simple_yaml_1_0
+{{ name }}_types:
+  MyType1:
+    derived_from: MyType3
+  MyType2:
+    derived_from: MyType1
+  MyType3:
+    derived_from: MyType2
+""", dict(name=name)).assert_failure()
+
+
+@pytest.mark.parametrize('name', data.TYPE_NAMES)
+def test_type_derived_from_root(parser, name):
+    parser.parse_literal("""
+tosca_definitions_version: tosca_simple_yaml_1_0
+{{ name }}_types:
+  MyType:
+    derived_from: tosca.{{ plural }}.Root
+""", dict(name=name, plural=data.TYPE_NAME_PLURAL[name])).assert_success()
+
+
+# Common fields
+
+@pytest.mark.parametrize('name', data.TYPE_NAMES)
+def test_type_fields(parser, name):
+    parser.parse_literal("""
+tosca_definitions_version: tosca_simple_yaml_1_0
+{{ name }}_types:
+  MyType:
+    derived_from: tosca.{{ plural }}.Root
+    version: 1.0.0
+    description: a description
+""", dict(name=name, plural=data.TYPE_NAME_PLURAL[name])).assert_success()
+
+
+@pytest.mark.parametrize('name,value', itertools.product(
+    data.TYPE_NAMES,
+    data.BAD_VERSIONS
+))
+def test_type_bad_version(parser, name, value):
+    parser.parse_literal("""
+tosca_definitions_version: tosca_simple_yaml_1_0
+{{ name }}_types:
+  MyType:
+    version: {{ value }}
+""", dict(name=name, value=value)).assert_failure()

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/93c88803/tests/mechanisms/parsing/__init__.py
----------------------------------------------------------------------
diff --git a/tests/mechanisms/parsing/__init__.py b/tests/mechanisms/parsing/__init__.py
index c1525a8..b2b5146 100644
--- a/tests/mechanisms/parsing/__init__.py
+++ b/tests/mechanisms/parsing/__init__.py
@@ -14,33 +14,51 @@
 # limitations under the License.
 
 import pytest
-from jinja2 import Template
+import jinja2
+
+
+LINE_BREAK = '\n' + '-' * 60
 
 
 class Parsed(object):
     def __init__(self):
         self.issues = []
         self.text = ''
+        self.verbose = False
 
     def assert_success(self):
         __tracebackhide__ = True # pylint: disable=unused-variable
         if len(self.issues) > 0:
             pytest.fail(u'did not expect parsing errors\n\n{0}\n\n{1}'
                         .format(self.text.strip(), u'\n'.join(self.issues)))
+        else:
+            if self.verbose:
+                print LINE_BREAK
+                print self.text.strip()
 
     def assert_failure(self):
         __tracebackhide__ = True # pylint: disable=unused-variable
         if len(self.issues) > 0:
-            pass
+            if self.verbose:
+                print LINE_BREAK
+                print u'{0}\n\n{1}'.format(self.text.strip(), u'\n'.join(self.issues))
         else:
             pytest.fail(u'expected parsing errors but got none\n\n{0}'
                         .format(self.text.strip()))
 
 
 class Parser(object):
+    def __init__(self):
+        self.verbose = False
+
     def parse_literal(self, text, context=None):
         text = render(text, context)
-        return self._parse_literal(text)
+        parsed = self._parse_literal(text)
+        parsed.verbose = self.verbose
+        return parsed
+
+    def _parse_literal(self, text):
+        raise NotImplementedError
 
     def __enter__(self):
         return self
@@ -50,6 +68,8 @@ class Parser(object):
 
 
 def render(template, context=None):
-    template = Template(template)
+    if not isinstance(template, unicode):
+        template = template.decode('utf-8')
+    template = jinja2.Template(template)
     template = template.render(context or {})
     return template

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/93c88803/tests/mechanisms/web_server.py
----------------------------------------------------------------------
diff --git a/tests/mechanisms/web_server.py b/tests/mechanisms/web_server.py
index 7db901e..20f003b 100644
--- a/tests/mechanisms/web_server.py
+++ b/tests/mechanisms/web_server.py
@@ -43,7 +43,7 @@ class WebServer(threading.Thread):
     def root(self):
         return 'http://localhost:{0}'.format(self.port)
 
-    def add_text(self, url, content, content_type):
+    def add_text(self, url, content, content_type='text/plain'):
         self.content.append((url, TextHandler, dict(content=content, content_type=content_type)))
 
     def add_text_yaml(self, url, content):
@@ -65,6 +65,14 @@ class WebServer(threading.Thread):
     def escape(segment):
         return tornado.escape.url_escape(segment)
 
+    def __enter__(self):
+        self.start()
+        return self
+
+    def __exit__(self, exc_type, exc_val, exc_tb):
+        self.stop()
+
+
 class TextHandler(tornado.web.RequestHandler):
     def initialize(self, content, content_type): # pylint: disable=arguments-differ
         self.content = content

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/93c88803/tests/resources/service-templates/tosca-simple-1.0/node-cellar/node-cellar.yaml
----------------------------------------------------------------------
diff --git a/tests/resources/service-templates/tosca-simple-1.0/node-cellar/node-cellar.yaml b/tests/resources/service-templates/tosca-simple-1.0/node-cellar/node-cellar.yaml
index 5a46532..ef62676 100644
--- a/tests/resources/service-templates/tosca-simple-1.0/node-cellar/node-cellar.yaml
+++ b/tests/resources/service-templates/tosca-simple-1.0/node-cellar/node-cellar.yaml
@@ -19,7 +19,7 @@ tosca_definitions_version: tosca_simple_profile_for_nfv_1_0
 
 description: >-
   Node Cellar TOSCA blueprint.
-  Here is some Unicode: 中國.
+  Here is some Unicode: 詠嘆調.
 
 metadata:
   template_name: node-cellar

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/93c88803/tests/utils/test_versions.py
----------------------------------------------------------------------
diff --git a/tests/utils/test_versions.py b/tests/utils/test_versions.py
index 222949c..bcbf9ef 100644
--- a/tests/utils/test_versions.py
+++ b/tests/utils/test_versions.py
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
 # Licensed to the Apache Software Foundation (ASF) under one or more
 # contributor license agreements.  See the NOTICE file distributed with
 # this work for additional information regarding copyright ownership.
@@ -34,8 +35,11 @@ def test_version_string():
     assert VersionString('20.0.1-beta1') < VersionString('20.0.1')
     assert VersionString('20.0.1-beta2') < VersionString('20.0.1-rc2')
     assert VersionString('20.0.1-alpha2') < VersionString('20.0.1-beta1')
-    assert VersionString('20.0.1-dev2') < VersionString('20.0.1-alpha1')
-    assert VersionString('20.0.1-DEV2') < VersionString('20.0.1-ALPHA1')
+    assert VersionString('20.0.1-dev2') < VersionString('20.0.1-ALPHA1')
+    assert VersionString('20.0.1-DEV2') < VersionString('20.0.1-alpha1')
+
+    # With Unicode qualifier
+    assert VersionString(u'20.0.1-詠嘆調1') == VersionString(u'20.0.1-詠嘆調2')
 
     # Coercive comparisons
     assert VersionString('20.0.0') == VersionString(10 * 2)