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/30 22:13:21 UTC
[05/10] incubator-ariatosca git commit: Initial work on mechanism,
imports, and metadata
Initial work on mechanism, imports, and metadata
* Metadata 'template_version' is now version data type
* Unicode support for version
* Better Unicode support for validation issues
Project: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/commit/36e0aa56
Tree: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/tree/36e0aa56
Diff: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/diff/36e0aa56
Branch: refs/heads/ARIA-1-parser-test-suite
Commit: 36e0aa56615cbf0f836c2fdcfce6c21323b511aa
Parents: 969149b
Author: Tal Liron <ta...@gmail.com>
Authored: Thu Aug 17 17:50:27 2017 -0500
Committer: Tal Liron <ta...@gmail.com>
Committed: Wed Aug 30 10:40:50 2017 -0500
----------------------------------------------------------------------
aria/modeling/service_common.py | 6 +-
aria/parser/validation/issue.py | 4 +-
.../simple_v1_0/data_types.py | 21 ++-
.../aria_extension_tosca/simple_v1_0/misc.py | 9 +-
.../simple_v1_0/presentation/field_getters.py | 6 +-
tests/extensions/__init__.py | 14 ++
.../extensions/aria_extension_tosca/__init__.py | 14 ++
.../simple_v1_0/__init__.py | 14 ++
.../simple_v1_0/conftest.py | 28 ++++
.../simple_v1_0/test_imports.py | 152 +++++++++++++++++++
.../simple_v1_0/test_metadata.py | 124 +++++++++++++++
tests/mechanisms/__init__.py | 14 ++
tests/mechanisms/parsing/__init__.py | 55 +++++++
tests/mechanisms/parsing/aria.py | 63 ++++++++
tests/mechanisms/web_server.py | 75 +++++++++
tests/requirements.txt | 1 +
16 files changed, 578 insertions(+), 22 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/36e0aa56/aria/modeling/service_common.py
----------------------------------------------------------------------
diff --git a/aria/modeling/service_common.py b/aria/modeling/service_common.py
index 478e530..0cc88f4 100644
--- a/aria/modeling/service_common.py
+++ b/aria/modeling/service_common.py
@@ -22,7 +22,8 @@ ARIA modeling service common module
from sqlalchemy import (
Column,
Text,
- Boolean
+ Boolean,
+ PickleType
)
from sqlalchemy.ext.declarative import declared_attr
@@ -587,12 +588,11 @@ class MetadataBase(TemplateModelMixin):
:ivar name: name
:vartype name: basestring
:ivar value: value
- :vartype value: basestring
"""
__tablename__ = 'metadata'
- value = Column(Text)
+ value = Column(PickleType)
@property
def as_raw(self):
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/36e0aa56/aria/parser/validation/issue.py
----------------------------------------------------------------------
diff --git a/aria/parser/validation/issue.py b/aria/parser/validation/issue.py
index 42fc580..cc68737 100644
--- a/aria/parser/validation/issue.py
+++ b/aria/parser/validation/issue.py
@@ -66,9 +66,9 @@ class Issue(object):
def __init__(self, message=None, exception=None, location=None, line=None,
column=None, locator=None, snippet=None, level=0):
if message is not None:
- self.message = str(message)
+ self.message = unicode(message)
elif exception is not None:
- self.message = str(exception)
+ self.message = unicode(exception)
else:
self.message = 'unknown issue'
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/36e0aa56/extensions/aria_extension_tosca/simple_v1_0/data_types.py
----------------------------------------------------------------------
diff --git a/extensions/aria_extension_tosca/simple_v1_0/data_types.py b/extensions/aria_extension_tosca/simple_v1_0/data_types.py
index 513b517..23417b0 100644
--- a/extensions/aria_extension_tosca/simple_v1_0/data_types.py
+++ b/extensions/aria_extension_tosca/simple_v1_0/data_types.py
@@ -41,7 +41,7 @@ class Timezone(tzinfo):
return self._offset
def tzname(self, dt): # pylint: disable=unused-argument
- return str(self._offset)
+ return unicode(self._offset)
def dst(self, dt): # pylint: disable=unused-argument
return Timezone._ZERO
@@ -75,7 +75,7 @@ class Timestamp(object):
CANONICAL = '%Y-%m-%dT%H:%M:%S'
def __init__(self, entry_schema, constraints, value, aspect): # pylint: disable=unused-argument
- value = str(value)
+ value = unicode(value)
match = re.match(Timestamp.REGULAR_SHORT, value)
if match is not None:
# Parse short form
@@ -165,7 +165,7 @@ class Version(object):
REGULAR = \
r'^(?P<major>\d+)\.(?P<minor>\d+)(\.(?P<fix>\d+)' + \
- r'((\.(?P<qualifier>\d+))(\-(?P<build>\d+))?)?)?$'
+ r'((\.(?P<qualifier>\w+))(\-(?P<build>\d+))?)?)?$'
@staticmethod
def key(version):
@@ -175,8 +175,8 @@ class Version(object):
return (version.major, version.minor, version.fix, version.qualifier, version.build)
def __init__(self, entry_schema, constraints, value, aspect): # pylint: disable=unused-argument
- str_value = str(value)
- match = re.match(Version.REGULAR, str_value)
+ str_value = unicode(value)
+ match = re.match(Version.REGULAR, str_value, flags=re.UNICODE)
if match is None:
raise ValueError(
'version must be formatted as <major_version>.<minor_version>'
@@ -193,8 +193,6 @@ class Version(object):
if self.fix is not None:
self.fix = int(self.fix)
self.qualifier = match.group('qualifier')
- if self.qualifier is not None:
- self.qualifier = int(self.qualifier)
self.build = match.group('build')
if self.build is not None:
self.build = int(self.build)
@@ -215,6 +213,7 @@ class Version(object):
return (self.major, self.minor, self.fix, self.qualifier, self.build) == \
(version.major, version.minor, version.fix, version.qualifier, version.build)
+ @implements_specification('3.2.2.1', 'tosca-simple-1.0')
def __lt__(self, version):
if self.major < version.major:
return True
@@ -225,9 +224,7 @@ class Version(object):
if self.fix < version.fix:
return True
elif self.fix == version.fix:
- if self.qualifier < version.qualifier:
- return True
- elif self.qualifier == version.qualifier:
+ if self.qualifier == version.qualifier:
if self.build < version.build:
return True
return False
@@ -375,8 +372,8 @@ class Scalar(object):
return scalar.value
def __init__(self, entry_schema, constraints, value, aspect): # pylint: disable=unused-argument
- str_value = str(value)
- match = re.match(self.REGULAR, str_value) # pylint: disable=no-member
+ str_value = unicode(value)
+ match = re.match(self.REGULAR, str_value, flags=re.UNICODE) # pylint: disable=no-member
if match is None:
raise ValueError('scalar must be formatted as <scalar> <unit>: %s' % safe_repr(value))
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/36e0aa56/extensions/aria_extension_tosca/simple_v1_0/misc.py
----------------------------------------------------------------------
diff --git a/extensions/aria_extension_tosca/simple_v1_0/misc.py b/extensions/aria_extension_tosca/simple_v1_0/misc.py
index 221163c..418fe31 100644
--- a/extensions/aria_extension_tosca/simple_v1_0/misc.py
+++ b/extensions/aria_extension_tosca/simple_v1_0/misc.py
@@ -20,14 +20,16 @@ from aria.parser import implements_specification
from aria.parser.presentation import (AsIsPresentation, has_fields, allow_unknown_fields,
short_form_field, primitive_field, primitive_list_field,
primitive_dict_unknown_fields, object_field,
- object_list_field, object_dict_field, field_validator,
- type_validator)
+ object_list_field, object_dict_field, field_getter,
+ field_validator, type_validator)
+from .data_types import Version
from .modeling.data_types import (get_data_type, get_data_type_value, get_property_constraints,
apply_constraint_to_value)
from .modeling.substitution_mappings import (validate_substitution_mappings_requirement,
validate_substitution_mappings_capability)
from .presentation.extensible import ExtensiblePresentation
+from .presentation.field_getters import data_type_class_getter
from .presentation.field_validators import (constraint_clause_field_validator,
constraint_clause_in_range_validator,
constraint_clause_valid_values_validator,
@@ -79,6 +81,7 @@ class MetaData(ExtensiblePresentation):
as a single-line string value.
"""
+ @field_getter(data_type_class_getter(Version))
@primitive_field(str)
@implements_specification('3.9.3.5', 'tosca-simple-1.0')
def template_version(self):
@@ -87,7 +90,7 @@ class MetaData(ExtensiblePresentation):
service template as a single-line string value.
"""
- @primitive_dict_unknown_fields()
+ @primitive_dict_unknown_fields(str)
def custom(self):
"""
:type: dict
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/36e0aa56/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 f14164a..34dacd6 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
@@ -14,6 +14,7 @@
# limitations under the License.
from aria.utils.formatting import safe_repr
+from aria.utils.type import full_type_name
from aria.parser.exceptions import InvalidValueError
@@ -31,7 +32,8 @@ def data_type_class_getter(cls):
return cls(None, None, raw, None)
except ValueError as e:
raise InvalidValueError(
- '%s is not a valid "%s" in "%s": %s'
- % (field.full_name, field.full_cls_name, presentation._name, safe_repr(raw)),
+ '{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/36e0aa56/tests/extensions/__init__.py
----------------------------------------------------------------------
diff --git a/tests/extensions/__init__.py b/tests/extensions/__init__.py
new file mode 100644
index 0000000..ae1e83e
--- /dev/null
+++ b/tests/extensions/__init__.py
@@ -0,0 +1,14 @@
+# 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.
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/36e0aa56/tests/extensions/aria_extension_tosca/__init__.py
----------------------------------------------------------------------
diff --git a/tests/extensions/aria_extension_tosca/__init__.py b/tests/extensions/aria_extension_tosca/__init__.py
new file mode 100644
index 0000000..ae1e83e
--- /dev/null
+++ b/tests/extensions/aria_extension_tosca/__init__.py
@@ -0,0 +1,14 @@
+# 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.
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/36e0aa56/tests/extensions/aria_extension_tosca/simple_v1_0/__init__.py
----------------------------------------------------------------------
diff --git a/tests/extensions/aria_extension_tosca/simple_v1_0/__init__.py b/tests/extensions/aria_extension_tosca/simple_v1_0/__init__.py
new file mode 100644
index 0000000..ae1e83e
--- /dev/null
+++ b/tests/extensions/aria_extension_tosca/simple_v1_0/__init__.py
@@ -0,0 +1,14 @@
+# 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.
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/36e0aa56/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
new file mode 100644
index 0000000..86bbc3f
--- /dev/null
+++ b/tests/extensions/aria_extension_tosca/simple_v1_0/conftest.py
@@ -0,0 +1,28 @@
+# 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 pytest
+
+from ....mechanisms.parsing.aria import AriaParser
+
+
+def pytest_report_header(config):
+ return 'parser: ARIA'
+
+
+@pytest.fixture(scope='session')
+def parser():
+ with AriaParser() as p:
+ yield p
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/36e0aa56/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
new file mode 100644
index 0000000..4d78f40
--- /dev/null
+++ b/tests/extensions/aria_extension_tosca/simple_v1_0/test_imports.py
@@ -0,0 +1,152 @@
+# -*- 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 pytest
+
+from ....mechanisms.web_server import WebServer
+
+
+NODE_TYPE_IMPORT = """
+node_types:
+ MyNode:
+ derived_from: tosca.nodes.Root
+"""
+
+BAD_IMPORT = """
+node_types:
+ MyNode:
+ derived_from: not.a.node.type
+"""
+
+@pytest.fixture(scope='session')
+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('詠嘆調')),
+ NODE_TYPE_IMPORT)
+ repository.add_text_yaml('/imports/bad.yaml', BAD_IMPORT)
+ repository.start()
+ yield repository.root
+ repository.stop()
+
+
+# Syntax
+
+@pytest.mark.parametrize('value', ('null', 'a_string', '123', '0.123', '{}'))
+def test_imports_wrong_yaml_type(parser, value):
+ parser.parse_literal("""
+tosca_definitions_version: tosca_simple_yaml_1_0
+imports: {{ value }}
+""", dict(value=value)).assert_failure()
+
+
+def test_imports_empty_list(parser):
+ parser.parse_literal("""
+tosca_definitions_version: tosca_simple_yaml_1_0
+imports: []
+""").assert_success()
+
+
+# Variants
+
+def test_import_single_short_form(parser, repository):
+ parser.parse_literal("""
+tosca_definitions_version: tosca_simple_yaml_1_0
+imports:
+ - {{ repository }}/imports/node-type.yaml
+topology_template:
+ node_templates:
+ my_node:
+ type: MyNode
+""", dict(repository=repository)).assert_success()
+
+
+def test_import_single_short_form_unicode(parser, repository):
+ parser.parse_literal(u"""
+tosca_definitions_version: tosca_simple_yaml_1_0
+imports:
+ - {{ repository }}/imports/詠嘆調.yaml
+topology_template:
+ node_templates:
+ my_node:
+ type: MyNode
+""", dict(repository=repository)).assert_success()
+
+
+def test_import_single_long_form(parser, repository):
+ parser.parse_literal("""
+tosca_definitions_version: tosca_simple_yaml_1_0
+imports:
+ - file: {{ repository }}/imports/node-type.yaml
+topology_template:
+ node_templates:
+ my_node:
+ type: MyNode
+""", dict(repository=repository)).assert_success()
+
+
+@pytest.mark.skip(reason='not yet supported')
+def test_import_single_repository(parser, repository):
+ parser.parse_literal("""
+tosca_definitions_version: tosca_simple_yaml_1_0
+repositories:
+ myrepository:
+ url: {{ repository }}/imports/
+imports:
+ - file: node-type.yaml
+ repository: myrepository
+topology_template:
+ node_templates:
+ my_node:
+ type: MyNode
+""", dict(repository=repository)).assert_success()
+
+
+@pytest.mark.skip(reason='not yet supported')
+def test_import_single_namespace(parser, repository):
+ parser.parse_literal("""
+tosca_definitions_version: tosca_simple_yaml_1_0
+imports:
+ - file: {{ repository }}/imports/node-type.yaml
+ namespace_uri:
+ namespace_prefix: my_namespace
+topology_template:
+ node_templates:
+ my_node:
+ type: my_namespace.MyNode
+""", dict(repository=repository)).assert_success()
+
+
+# Failures
+
+def test_import_not_found(parser):
+ parser.parse_literal("""
+tosca_definitions_version: tosca_simple_yaml_1_0
+imports:
+ - does_not_exist
+""").assert_failure()
+
+
+def test_import_bad(parser, repository):
+ parser.parse_literal("""
+tosca_definitions_version: tosca_simple_yaml_1_0
+imports:
+ - {{ repository }}/imports/bad.yaml
+topology_template:
+ node_templates:
+ my_node:
+ type: MyNode
+""", dict(repository=repository)).assert_failure()
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/36e0aa56/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
new file mode 100644
index 0000000..dae5631
--- /dev/null
+++ b/tests/extensions/aria_extension_tosca/simple_v1_0/test_metadata.py
@@ -0,0 +1,124 @@
+# -*- 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 pytest
+
+
+# Syntax
+
+@pytest.mark.parametrize('value', ('null', 'a_string', '123', '0.123', '[]'))
+def test_metadata_wrong_yaml_type(parser, value):
+ parser.parse_literal("""
+tosca_definitions_version: tosca_simple_yaml_1_0
+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):
+ parser.parse_literal("""
+tosca_definitions_version: tosca_simple_yaml_1_0
+metadata:
+ {{ field }}: {{ value }}
+""", dict(field=field, value=value)).assert_failure()
+
+
+@pytest.mark.parametrize('value', ('123', '0.123', '[]', '{}'))
+def test_metadata_non_normative_wrong_yaml_type(parser, value):
+ parser.parse_literal("""
+tosca_definitions_version: tosca_simple_yaml_1_0
+metadata:
+ non_normative: {{ value }}
+""", dict(value=value)).assert_failure()
+
+
+def test_metadata_empty_dict(parser):
+ parser.parse_literal("""
+tosca_definitions_version: tosca_simple_yaml_1_0
+metadata: {}
+""").assert_success()
+
+
+# Normative
+
+@pytest.mark.parametrize('value', ('null', 'a_string', '1.2.3.4.5'))
+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_failure()
+
+
+@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):
+ parser.parse_literal("""
+tosca_definitions_version: tosca_simple_yaml_1_0
+metadata:
+ template_version: {{ value }}
+""", dict(value=value)).assert_success()
+
+# Non-normative
+
+def test_metadata_with_non_normative_fields(parser):
+ parser.parse_literal("""
+tosca_definitions_version: tosca_simple_yaml_1_0
+metadata:
+ template_name: name
+ template_author: author
+ template_version: 1.0.0.beta
+ non_normative1: non_normative1
+ non_normative2: non_normative2
+ non_normative3: non_normative3
+""").assert_success()
+
+
+def test_metadata_with_non_normative_fields_nulls(parser):
+ parser.parse_literal("""
+tosca_definitions_version: tosca_simple_yaml_1_0
+metadata:
+ template_name: null
+ template_author: null
+ template_version: 1.0.0.beta
+ non_normative1: null
+ non_normative2: null
+ non_normative3: null
+""").assert_success()
+
+
+def test_metadata_with_non_normative_fields_unicode(parser):
+ parser.parse_literal(u"""
+tosca_definitions_version: tosca_simple_yaml_1_0
+metadata:
+ template_name: 詠嘆調
+ template_author: 詠嘆調
+ template_version: 1.0.0.詠嘆調
+ non_normative1: 詠嘆調
+ non_normative2: 詠嘆調
+ non_normative3: 詠嘆調
+""").assert_success()
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/36e0aa56/tests/mechanisms/__init__.py
----------------------------------------------------------------------
diff --git a/tests/mechanisms/__init__.py b/tests/mechanisms/__init__.py
new file mode 100644
index 0000000..ae1e83e
--- /dev/null
+++ b/tests/mechanisms/__init__.py
@@ -0,0 +1,14 @@
+# 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.
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/36e0aa56/tests/mechanisms/parsing/__init__.py
----------------------------------------------------------------------
diff --git a/tests/mechanisms/parsing/__init__.py b/tests/mechanisms/parsing/__init__.py
new file mode 100644
index 0000000..c1525a8
--- /dev/null
+++ b/tests/mechanisms/parsing/__init__.py
@@ -0,0 +1,55 @@
+# 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 pytest
+from jinja2 import Template
+
+
+class Parsed(object):
+ def __init__(self):
+ self.issues = []
+ self.text = ''
+
+ 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)))
+
+ def assert_failure(self):
+ __tracebackhide__ = True # pylint: disable=unused-variable
+ if len(self.issues) > 0:
+ pass
+ else:
+ pytest.fail(u'expected parsing errors but got none\n\n{0}'
+ .format(self.text.strip()))
+
+
+class Parser(object):
+ def parse_literal(self, text, context=None):
+ text = render(text, context)
+ return self._parse_literal(text)
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, exc_type, exc_val, exc_tb):
+ pass
+
+
+def render(template, context=None):
+ template = Template(template)
+ template = template.render(context or {})
+ return template
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/36e0aa56/tests/mechanisms/parsing/aria.py
----------------------------------------------------------------------
diff --git a/tests/mechanisms/parsing/aria.py b/tests/mechanisms/parsing/aria.py
new file mode 100644
index 0000000..c02d387
--- /dev/null
+++ b/tests/mechanisms/parsing/aria.py
@@ -0,0 +1,63 @@
+# 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.
+
+from __future__ import absolute_import # so we can import root 'aria'
+
+from aria.parser.loading import LiteralLocation
+from aria.parser.consumption import (
+ ConsumptionContext,
+ ConsumerChain,
+ Read,
+ Validate,
+ ServiceTemplate
+)
+from aria.utils.imports import import_fullname
+
+from . import Parser, Parsed
+
+
+class AriaParser(Parser):
+ def _parse_literal(self, text):
+ context = AriaParser.create_context()
+ context.presentation.location = LiteralLocation(text)
+ consumer = AriaParser.create_consumer(context)
+ consumer.consume()
+ parsed = Parsed()
+ parsed.text = text
+ for issue in context.validation.issues:
+ parsed.issues.append(unicode(issue))
+ return parsed
+
+ @staticmethod
+ def create_context(loader_source='aria.parser.loading.DefaultLoaderSource',
+ reader_source='aria.parser.reading.DefaultReaderSource',
+ presenter_source='aria.parser.presentation.DefaultPresenterSource',
+ presenter=None,
+ debug=False):
+ context = ConsumptionContext()
+ context.loading.loader_source = import_fullname(loader_source)()
+ context.reading.reader_source = import_fullname(reader_source)()
+ context.presentation.presenter_source = import_fullname(presenter_source)()
+ context.presentation.presenter_class = import_fullname(presenter)
+ context.presentation.print_exceptions = debug
+ return context
+
+ @staticmethod
+ def create_consumer(context):
+ return ConsumerChain(context, (
+ Read,
+ Validate,
+ ServiceTemplate
+ ))
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/36e0aa56/tests/mechanisms/web_server.py
----------------------------------------------------------------------
diff --git a/tests/mechanisms/web_server.py b/tests/mechanisms/web_server.py
new file mode 100644
index 0000000..7db901e
--- /dev/null
+++ b/tests/mechanisms/web_server.py
@@ -0,0 +1,75 @@
+# 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 logging
+import threading
+
+import tornado.web
+import tornado.ioloop
+import tornado.netutil
+
+
+logging.getLogger('tornado.access').disabled = True
+
+
+class WebServer(threading.Thread):
+ def __init__(self):
+ super(WebServer, self).__init__()
+ self.daemon = True
+
+ self.content = []
+
+ # Arbitrary free socket
+ self.sockets = tornado.netutil.bind_sockets(0, '')
+ for s in self.sockets:
+ name = s.getsockname()
+ if name[0] == '0.0.0.0': # IPv4 (IPv6 would be '::')
+ self.port = name[1]
+ break
+
+ @property
+ def root(self):
+ return 'http://localhost:{0}'.format(self.port)
+
+ def add_text(self, url, content, content_type):
+ self.content.append((url, TextHandler, dict(content=content, content_type=content_type)))
+
+ def add_text_yaml(self, url, content):
+ self.add_text(url, content, 'application/x-yaml')
+
+ def stop(self):
+ self.ioloop.add_callback(self.ioloop.stop)
+
+ def run(self): # Thread override
+ application = tornado.web.Application(self.content)
+ server = tornado.httpserver.HTTPServer(application)
+ server.add_sockets(self.sockets)
+ self.ioloop = tornado.ioloop.IOLoop.current()
+ print 'Tornado starting'
+ self.ioloop.start()
+ print 'Tornado stopped'
+
+ @staticmethod
+ def escape(segment):
+ return tornado.escape.url_escape(segment)
+
+class TextHandler(tornado.web.RequestHandler):
+ def initialize(self, content, content_type): # pylint: disable=arguments-differ
+ self.content = content
+ self.content_type = content_type
+
+ def get(self):
+ self.write(self.content)
+ self.set_header('Content-Type', self.content_type)
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/36e0aa56/tests/requirements.txt
----------------------------------------------------------------------
diff --git a/tests/requirements.txt b/tests/requirements.txt
index 56a7bf5..bdd5e2c 100644
--- a/tests/requirements.txt
+++ b/tests/requirements.txt
@@ -13,6 +13,7 @@
testtools==2.3.0
fasteners==0.14.1
sh==1.12.14
+tornado==4.3 # last release to support Python 2.6
psutil==5.2.2
mock==2.0.0
pylint==1.6.5