You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@ariatosca.apache.org by em...@apache.org on 2017/04/20 01:09:39 UTC
[5/9] incubator-ariatosca git commit: ARIA-48 Revamped ARIA CLI
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8e5a1ec2/aria/utils/http.py
----------------------------------------------------------------------
diff --git a/aria/utils/http.py b/aria/utils/http.py
new file mode 100644
index 0000000..7bdfd79
--- /dev/null
+++ b/aria/utils/http.py
@@ -0,0 +1,62 @@
+# 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 os
+import tempfile
+
+import requests
+
+
+def download_file(url, destination=None, logger=None, progress_handler=None):
+ """Download file.
+
+ May raise IOError as well as requests.exceptions.RequestException
+ :param url: Location of the file to download
+ :type url: str
+ :param destination:
+ Location where the file should be saved (autogenerated by default)
+ :type destination: str | None
+ :returns: Location where the file was saved
+ :rtype: str
+
+ """
+ chunk_size = 1024
+
+ if not destination:
+ file_descriptor, destination = tempfile.mkstemp()
+ os.close(file_descriptor)
+ if logger:
+ logger.info('Downloading {0} to {1}...'.format(url, destination))
+
+ response = requests.get(url, stream=True)
+ final_url = response.url
+ if final_url != url and logger:
+ logger.debug('Redirected to {0}'.format(final_url))
+
+ read_bytes = 0
+ total_size = int(response.headers['Content-Length']) \
+ if 'Content-Length' in response.headers else None
+ try:
+ with open(destination, 'wb') as destination_file:
+ for chunk in response.iter_content(chunk_size):
+ destination_file.write(chunk)
+ if total_size and progress_handler:
+ # Only showing progress bar if we have the total content length
+ read_bytes += chunk_size
+ progress_handler(read_bytes, total_size)
+ finally:
+ response.close()
+
+ return destination
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8e5a1ec2/aria/utils/threading.py
----------------------------------------------------------------------
diff --git a/aria/utils/threading.py b/aria/utils/threading.py
index b99250d..bfd30f5 100644
--- a/aria/utils/threading.py
+++ b/aria/utils/threading.py
@@ -15,6 +15,7 @@
from __future__ import absolute_import # so we can import standard 'threading'
+import sys
import itertools
import multiprocessing
from threading import (Thread, Lock)
@@ -255,3 +256,26 @@ class LockedList(list):
def __exit__(self, the_type, value, traceback):
return self.lock.__exit__(the_type, value, traceback)
+
+
+class ExceptionThread(Thread):
+ """
+ A thread from which top level exceptions can be retrieved or reraised
+ """
+ def __init__(self, *args, **kwargs):
+ Thread.__init__(self, *args, **kwargs)
+ self.exception = None
+
+ def run(self):
+ try:
+ super(ExceptionThread, self).run()
+ except BaseException:
+ self.exception = sys.exc_info()
+
+ def is_error(self):
+ return self.exception is not None
+
+ def raise_error_if_exists(self):
+ if self.is_error():
+ type_, value, trace = self.exception
+ raise type_, value, trace
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8e5a1ec2/aria/utils/type.py
----------------------------------------------------------------------
diff --git a/aria/utils/type.py b/aria/utils/type.py
new file mode 100644
index 0000000..dad5427
--- /dev/null
+++ b/aria/utils/type.py
@@ -0,0 +1,61 @@
+# 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.
+
+
+def validate_value_type(value, type_name):
+ """
+ Validate a value is of a specific type.
+ A ValueError will be raised on type mismatch.
+ Supports both python and yaml type names.
+ """
+
+ #TODO add timestamp type?
+ name_to_type = {
+ 'list': list,
+ 'dict': dict,
+ 'tuple': tuple,
+ 'str': str,
+ 'unicode': str,
+ 'string': str,
+ 'int': int,
+ 'integer': int,
+ 'bool': bool,
+ 'boolean': bool,
+ 'float': float
+ }
+
+ type_ = name_to_type.get(type_name.lower())
+ if type_ is None:
+ raise RuntimeError('No supported type_name was provided')
+
+ if not isinstance(value, type_):
+ raise ValueError('Value {0} is not of type {1}'.format(value, type_name))
+
+
+def convert_value_to_type(str_value, type_name):
+ try:
+ if type_name.lower() in ['str', 'unicode']:
+ return str_value.decode('utf-8')
+ elif type_name.lower() == 'int':
+ return int(str_value)
+ elif type_name.lower() == 'bool':
+ return bool(str_value)
+ elif type_name.lower() == 'float':
+ return float(str_value)
+ else:
+ raise ValueError('No supported type_name was provided')
+ except ValueError:
+ raise ValueError('Trying to convert {0} to {1} failed'.format(str_value,
+ type_name))
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8e5a1ec2/examples/tosca-simple-1.0/use-cases/block-storage-1/inputs.yaml
----------------------------------------------------------------------
diff --git a/examples/tosca-simple-1.0/use-cases/block-storage-1/inputs.yaml b/examples/tosca-simple-1.0/use-cases/block-storage-1/inputs.yaml
new file mode 100644
index 0000000..d0b0854
--- /dev/null
+++ b/examples/tosca-simple-1.0/use-cases/block-storage-1/inputs.yaml
@@ -0,0 +1,3 @@
+storage_snapshot_id: "snapshot-id"
+storage_location: /mnt
+cpus: 4
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8e5a1ec2/examples/tosca-simple-1.0/use-cases/block-storage-2/inputs.yaml
----------------------------------------------------------------------
diff --git a/examples/tosca-simple-1.0/use-cases/block-storage-2/inputs.yaml b/examples/tosca-simple-1.0/use-cases/block-storage-2/inputs.yaml
new file mode 100644
index 0000000..d0b0854
--- /dev/null
+++ b/examples/tosca-simple-1.0/use-cases/block-storage-2/inputs.yaml
@@ -0,0 +1,3 @@
+storage_snapshot_id: "snapshot-id"
+storage_location: /mnt
+cpus: 4
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8e5a1ec2/examples/tosca-simple-1.0/use-cases/block-storage-3/inputs.yaml
----------------------------------------------------------------------
diff --git a/examples/tosca-simple-1.0/use-cases/block-storage-3/inputs.yaml b/examples/tosca-simple-1.0/use-cases/block-storage-3/inputs.yaml
new file mode 100644
index 0000000..daca041
--- /dev/null
+++ b/examples/tosca-simple-1.0/use-cases/block-storage-3/inputs.yaml
@@ -0,0 +1,2 @@
+storage_location: /mnt
+cpus: 4
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8e5a1ec2/examples/tosca-simple-1.0/use-cases/block-storage-4/inputs.yaml
----------------------------------------------------------------------
diff --git a/examples/tosca-simple-1.0/use-cases/block-storage-4/inputs.yaml b/examples/tosca-simple-1.0/use-cases/block-storage-4/inputs.yaml
new file mode 100644
index 0000000..18e457d
--- /dev/null
+++ b/examples/tosca-simple-1.0/use-cases/block-storage-4/inputs.yaml
@@ -0,0 +1,2 @@
+storage_snapshot_id: "snapshot-id"
+cpus: 4
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8e5a1ec2/examples/tosca-simple-1.0/use-cases/block-storage-5/inputs.yaml
----------------------------------------------------------------------
diff --git a/examples/tosca-simple-1.0/use-cases/block-storage-5/inputs.yaml b/examples/tosca-simple-1.0/use-cases/block-storage-5/inputs.yaml
new file mode 100644
index 0000000..d0b0854
--- /dev/null
+++ b/examples/tosca-simple-1.0/use-cases/block-storage-5/inputs.yaml
@@ -0,0 +1,3 @@
+storage_snapshot_id: "snapshot-id"
+storage_location: /mnt
+cpus: 4
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8e5a1ec2/examples/tosca-simple-1.0/use-cases/block-storage-6/inputs.yaml
----------------------------------------------------------------------
diff --git a/examples/tosca-simple-1.0/use-cases/block-storage-6/inputs.yaml b/examples/tosca-simple-1.0/use-cases/block-storage-6/inputs.yaml
new file mode 100644
index 0000000..d0b0854
--- /dev/null
+++ b/examples/tosca-simple-1.0/use-cases/block-storage-6/inputs.yaml
@@ -0,0 +1,3 @@
+storage_snapshot_id: "snapshot-id"
+storage_location: /mnt
+cpus: 4
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8e5a1ec2/examples/tosca-simple-1.0/use-cases/compute-1/inputs.yaml
----------------------------------------------------------------------
diff --git a/examples/tosca-simple-1.0/use-cases/compute-1/inputs.yaml b/examples/tosca-simple-1.0/use-cases/compute-1/inputs.yaml
new file mode 100644
index 0000000..c1ee88a
--- /dev/null
+++ b/examples/tosca-simple-1.0/use-cases/compute-1/inputs.yaml
@@ -0,0 +1 @@
+cpus: 4
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8e5a1ec2/examples/tosca-simple-1.0/use-cases/multi-tier-1/inputs.yaml
----------------------------------------------------------------------
diff --git a/examples/tosca-simple-1.0/use-cases/multi-tier-1/inputs.yaml b/examples/tosca-simple-1.0/use-cases/multi-tier-1/inputs.yaml
new file mode 100644
index 0000000..5302bbf
--- /dev/null
+++ b/examples/tosca-simple-1.0/use-cases/multi-tier-1/inputs.yaml
@@ -0,0 +1 @@
+my_cpus: 8
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8e5a1ec2/examples/tosca-simple-1.0/use-cases/network-1/inputs.yaml
----------------------------------------------------------------------
diff --git a/examples/tosca-simple-1.0/use-cases/network-1/inputs.yaml b/examples/tosca-simple-1.0/use-cases/network-1/inputs.yaml
new file mode 100644
index 0000000..9687bb0
--- /dev/null
+++ b/examples/tosca-simple-1.0/use-cases/network-1/inputs.yaml
@@ -0,0 +1 @@
+network_name: "network"
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8e5a1ec2/examples/tosca-simple-1.0/use-cases/network-2/inputs.yaml
----------------------------------------------------------------------
diff --git a/examples/tosca-simple-1.0/use-cases/network-2/inputs.yaml b/examples/tosca-simple-1.0/use-cases/network-2/inputs.yaml
new file mode 100644
index 0000000..9687bb0
--- /dev/null
+++ b/examples/tosca-simple-1.0/use-cases/network-2/inputs.yaml
@@ -0,0 +1 @@
+network_name: "network"
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8e5a1ec2/examples/tosca-simple-1.0/use-cases/network-3/inputs.yaml
----------------------------------------------------------------------
diff --git a/examples/tosca-simple-1.0/use-cases/network-3/inputs.yaml b/examples/tosca-simple-1.0/use-cases/network-3/inputs.yaml
new file mode 100644
index 0000000..9687bb0
--- /dev/null
+++ b/examples/tosca-simple-1.0/use-cases/network-3/inputs.yaml
@@ -0,0 +1 @@
+network_name: "network"
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8e5a1ec2/examples/tosca-simple-1.0/use-cases/object-storage-1/inputs.yaml
----------------------------------------------------------------------
diff --git a/examples/tosca-simple-1.0/use-cases/object-storage-1/inputs.yaml b/examples/tosca-simple-1.0/use-cases/object-storage-1/inputs.yaml
new file mode 100644
index 0000000..57f99a3
--- /dev/null
+++ b/examples/tosca-simple-1.0/use-cases/object-storage-1/inputs.yaml
@@ -0,0 +1 @@
+objectstore_name: "objectstore"
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8e5a1ec2/examples/tosca-simple-1.0/use-cases/software-component-1/inputs.yaml
----------------------------------------------------------------------
diff --git a/examples/tosca-simple-1.0/use-cases/software-component-1/inputs.yaml b/examples/tosca-simple-1.0/use-cases/software-component-1/inputs.yaml
new file mode 100644
index 0000000..c1ee88a
--- /dev/null
+++ b/examples/tosca-simple-1.0/use-cases/software-component-1/inputs.yaml
@@ -0,0 +1 @@
+cpus: 4
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8e5a1ec2/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py
----------------------------------------------------------------------
diff --git a/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py b/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py
index 0e9177f..9576260 100644
--- a/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py
+++ b/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py
@@ -19,6 +19,7 @@ Creates ARIA service template models based on the TOSCA presentation.
Relies on many helper methods in the presentation classes.
"""
+import os
import re
from types import FunctionType
from datetime import datetime
@@ -41,7 +42,7 @@ IMPLEMENTATION_PREFIX_REGEX = re.compile(r'(?<!\\)(?:\\\\)*>')
def create_service_template_model(context): # pylint: disable=too-many-locals,too-many-branches
model = ServiceTemplate(created_at=datetime.now(),
- main_file_name=str(context.presentation.location))
+ main_file_name=os.path.basename(str(context.presentation.location)))
model.description = context.presentation.get('service_template', 'description', 'value')
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8e5a1ec2/requirements.in
----------------------------------------------------------------------
diff --git a/requirements.in b/requirements.in
index bc27479..3950140 100644
--- a/requirements.in
+++ b/requirements.in
@@ -10,6 +10,9 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+# In order to create the requirements.txt file, execute
+# pip-compile --output-file requirements.txt requirements.in (pip-tools package is needed).
+
PyYAML<3.13
requests>=2.3.0, <2.14.0
networkx>=1.9, <1.10 # version 1.10 dropped support of python 2.6
@@ -25,6 +28,12 @@ SQLAlchemy>=1.1.0, <1.2 # version 1.2 dropped support of python 2.6
wagon==0.6.0
bottle>=0.12.0, <0.13
Fabric>=1.13.0, <1.14
+click>=4.1, < 5.0
+colorama>=0.3.3, < 0.3.5
+PrettyTable>=0.7,<0.8
+click_didyoumean==0.0.3
+backports.shutil_get_terminal_size==1.0.0
+logutils==0.3.4.1
# Since the tool we are using to generate our requirements.txt, `pip-tools`,
# does not currently support conditional dependencies (;), we're adding our original
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8e5a1ec2/requirements.txt
----------------------------------------------------------------------
diff --git a/requirements.txt b/requirements.txt
index 901aa75..3accaa3 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -4,28 +4,30 @@
#
# pip-compile --output-file requirements.txt requirements.in
#
-
-# ----------------------------------------------------------------------------------
# Since the tool we are using to generate our requirements.txt, `pip-tools`,
# does not currently support conditional dependencies (;), we're adding our original
-# conditional dependencies here manually.
+# conditional dependencies here as comments, and manually adding them to our
+# generated requirements.txt file.
# The relevant pip-tools issue: https://github.com/jazzband/pip-tools/issues/435
-importlib==1.0.4 ; python_version < '2.7'
-ordereddict==1.1 ; python_version < '2.7'
-total-ordering==0.1.0 ; python_version < '2.7'
+importlib ; python_version < '2.7'
+ordereddict ; python_version < '2.7'
+total-ordering ; python_version < '2.7' # only one version on pypi
# Fabric makes use of this library, but doesn't bring it :(
pypiwin32==219 ; sys_platform == 'win32'
# ----------------------------------------------------------------------------------
-appdirs==1.4.3 # via setuptools
args==0.1.0 # via clint
asn1crypto==0.22.0 # via cryptography
+backports.shutil_get_terminal_size==1.0.0
blinker==1.4
bottle==0.12.13
cachecontrol[filecache]==0.12.1
cffi==1.10.0 # via cryptography
+click==4.1
+click_didyoumean==0.0.3
clint==0.5.1
+colorama==0.3.4
cryptography==1.8.1 # via paramiko
decorator==4.0.11 # via networkx
enum34==1.1.6 # via cryptography
@@ -35,11 +37,13 @@ ipaddress==1.0.18 # via cryptography
jinja2==2.8.1
jsonpickle==0.9.4
lockfile==0.12.2 # via cachecontrol
+logutils==0.3.4.1
markupsafe==1.0 # via jinja2
msgpack-python==0.4.8 # via cachecontrol
networkx==1.9.1
-packaging==16.8 # via cryptography, setuptools
+packaging==16.8 # via cryptography
paramiko==2.1.2 # via fabric
+prettytable==0.7.2
pyasn1==0.2.3 # via paramiko
pycparser==2.17 # via cffi
pyparsing==2.2.0 # via packaging
@@ -49,7 +53,7 @@ retrying==1.3.3
ruamel.ordereddict==0.4.9 # via ruamel.yaml
ruamel.yaml==0.11.15
shortuuid==0.5.0
-six==1.10.0 # via cryptography, packaging, retrying, setuptools
+six==1.10.0 # via cryptography, packaging, retrying
sqlalchemy==1.1.6
wagon==0.6.0
wheel==0.29.0 # via wagon
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8e5a1ec2/setup.py
----------------------------------------------------------------------
diff --git a/setup.py b/setup.py
index 3d72ebc..b64453a 100644
--- a/setup.py
+++ b/setup.py
@@ -61,7 +61,7 @@ except IOError:
extras_require = {}
-console_scripts = ['aria = aria.cli.cli:main']
+console_scripts = ['aria = aria.cli.main:main']
def _generate_user_options(command):
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8e5a1ec2/tests/.pylintrc
----------------------------------------------------------------------
diff --git a/tests/.pylintrc b/tests/.pylintrc
index 06409e9..eead6e8 100644
--- a/tests/.pylintrc
+++ b/tests/.pylintrc
@@ -77,7 +77,7 @@ confidence=
# --enable=similarities". If you want to run only the classes checker, but have
# no Warning level messages displayed, use"--disable=all --enable=classes
# --disable=W"
-disable=import-star-module-level,old-octal-literal,oct-method,print-statement,unpacking-in-except,parameter-unpacking,backtick,old-raise-syntax,old-ne-operator,long-suffix,dict-view-method,dict-iter-method,metaclass-assignment,next-method-called,raising-string,indexing-exception,raw_input-builtin,long-builtin,file-builtin,execfile-builtin,coerce-builtin,cmp-builtin,buffer-builtin,basestring-builtin,apply-builtin,filter-builtin-not-iterating,using-cmp-argument,useless-suppression,range-builtin-not-iterating,suppressed-message,no-absolute-import,old-division,cmp-method,reload-builtin,zip-builtin-not-iterating,intern-builtin,unichr-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,input-builtin,round-builtin,hex-method,nonzero-method,map-builtin-not-iterating,redefined-builtin,no-self-use,missing-docstring,attribute-defined-outside-init,redefined-outer-name,import-error,redefined-variable-type,broad
-except,protected-access,global-statement,too-many-locals,abstract-method,no-member
+disable=import-star-module-level,old-octal-literal,oct-method,print-statement,unpacking-in-except,parameter-unpacking,backtick,old-raise-syntax,old-ne-operator,long-suffix,dict-view-method,dict-iter-method,metaclass-assignment,next-method-called,raising-string,indexing-exception,raw_input-builtin,long-builtin,file-builtin,execfile-builtin,coerce-builtin,cmp-builtin,buffer-builtin,basestring-builtin,apply-builtin,filter-builtin-not-iterating,using-cmp-argument,useless-suppression,range-builtin-not-iterating,suppressed-message,no-absolute-import,old-division,cmp-method,reload-builtin,zip-builtin-not-iterating,intern-builtin,unichr-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,input-builtin,round-builtin,hex-method,nonzero-method,map-builtin-not-iterating,redefined-builtin,no-self-use,missing-docstring,attribute-defined-outside-init,redefined-outer-name,import-error,redefined-variable-type,broad
-except,protected-access,global-statement,too-many-locals,abstract-method,no-member,unused-argument
[REPORTS]
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8e5a1ec2/tests/cli/__init__.py
----------------------------------------------------------------------
diff --git a/tests/cli/__init__.py b/tests/cli/__init__.py
new file mode 100644
index 0000000..ae1e83e
--- /dev/null
+++ b/tests/cli/__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/8e5a1ec2/tests/cli/base_test.py
----------------------------------------------------------------------
diff --git a/tests/cli/base_test.py b/tests/cli/base_test.py
new file mode 100644
index 0000000..da9d72c
--- /dev/null
+++ b/tests/cli/base_test.py
@@ -0,0 +1,77 @@
+# 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
+from StringIO import StringIO
+
+import pytest
+
+from . import runner
+from . import utils
+
+
+@pytest.fixture
+def mock_storage():
+ return utils.MockStorage()
+
+
+@pytest.mark.usefixtures("redirect_logger")
+class TestCliBase(object):
+
+ @staticmethod
+ @pytest.fixture(scope="class")
+ def redirect_logger():
+
+ utils.setup_logger(logger_name='aria.cli.main',
+ handlers=[logging.StreamHandler(TestCliBase._logger_output)],
+ logger_format='%(message)s')
+ yield
+ utils.setup_logger(logger_name='aria.cli.main',
+ handlers=_default_logger_config['handlers'],
+ level=_default_logger_config['level'])
+
+ _logger_output = StringIO()
+
+ def invoke(self, command):
+ self._logger_output.truncate(0)
+ return runner.invoke(command)
+
+ @property
+ def logger_output_string(self):
+ return self._logger_output.getvalue()
+
+
+def assert_exception_raised(outcome, expected_exception, expected_msg=''):
+ assert isinstance(outcome.exception, expected_exception)
+ assert expected_msg in str(outcome.exception)
+
+
+# This exists as I wanted to mocked a function using monkeypatch to return a function that raises an
+# exception. I tried doing that using a lambda in-place, but this can't be accomplished in a trivial
+# way it seems. So I wrote this silly function instead
+def raise_exception(exception, msg=''):
+
+ def inner(*args, **kwargs):
+ raise exception(msg)
+
+ return inner
+
+
+def get_default_logger_config():
+ logger = logging.getLogger('aria.cli.main')
+ return {'handlers': logger.handlers,
+ 'level': logger.level}
+
+_default_logger_config = get_default_logger_config()
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8e5a1ec2/tests/cli/runner.py
----------------------------------------------------------------------
diff --git a/tests/cli/runner.py b/tests/cli/runner.py
new file mode 100644
index 0000000..7e4243b
--- /dev/null
+++ b/tests/cli/runner.py
@@ -0,0 +1,27 @@
+# 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 click.testing
+
+import aria.cli.commands as commands
+
+
+def invoke(command_string):
+ command_list = command_string.split()
+ command, sub, args = command_list[0], command_list[1], command_list[2:]
+ runner = click.testing.CliRunner()
+ outcome = runner.invoke(getattr(
+ getattr(commands, command), sub), args)
+ return outcome
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8e5a1ec2/tests/cli/test_node_templates.py
----------------------------------------------------------------------
diff --git a/tests/cli/test_node_templates.py b/tests/cli/test_node_templates.py
new file mode 100644
index 0000000..ff7ff28
--- /dev/null
+++ b/tests/cli/test_node_templates.py
@@ -0,0 +1,133 @@
+# 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 mock import ANY, MagicMock
+
+from aria.cli.env import _Environment
+
+from .base_test import ( # pylint: disable=unused-import
+ TestCliBase,
+ mock_storage
+)
+from ..mock import models as mock_models
+
+
+class TestNodeTemplatesShow(TestCliBase):
+
+ def test_header_strings(self, monkeypatch, mock_storage):
+ monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+ self.invoke('node_templates show 1')
+ assert 'Showing node template 1' in self.logger_output_string
+ assert 'Node template properties:' in self.logger_output_string
+ assert 'Nodes:' in self.logger_output_string
+
+ def test_no_properties_no_nodes(self, monkeypatch, mock_storage):
+
+ monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+ self.invoke('node_templates show 1')
+
+ assert 'No properties' in self.logger_output_string
+ assert 'prop1' not in self.logger_output_string
+ assert 'value1' not in self.logger_output_string
+ assert 'No nodes' in self.logger_output_string
+ assert mock_models.NODE_NAME not in self.logger_output_string
+
+ def test_one_property_no_nodes(self, monkeypatch, mock_storage):
+
+ monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+ m = MagicMock(return_value=mock_models.create_node_template_with_dependencies(
+ include_property=True))
+ monkeypatch.setattr(mock_storage.node_template, 'get', m)
+ self.invoke('node_templates show 2')
+ assert 'No properties' not in self.logger_output_string
+ assert 'prop1' in self.logger_output_string and 'value1' in self.logger_output_string
+ assert 'No nodes' in self.logger_output_string
+ assert mock_models.NODE_NAME not in self.logger_output_string
+
+ def test_no_properties_one_node(self, monkeypatch, mock_storage):
+
+ monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+ m = MagicMock(return_value=mock_models.create_node_template_with_dependencies(
+ include_node=True))
+ monkeypatch.setattr(mock_storage.node_template, 'get', m)
+ self.invoke('node_templates show 3')
+ assert 'No properties' in self.logger_output_string
+ assert 'prop1' not in self.logger_output_string
+ assert 'value1' not in self.logger_output_string
+ assert 'No nodes' not in self.logger_output_string
+ assert mock_models.NODE_NAME in self.logger_output_string
+
+ def test_one_property_one_node(self, monkeypatch, mock_storage):
+
+ monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+ m = MagicMock(return_value=mock_models.create_node_template_with_dependencies(
+ include_node=True, include_property=True))
+ monkeypatch.setattr(mock_storage.node_template, 'get', m)
+ self.invoke('node_templates show 4')
+ assert 'No properties' not in self.logger_output_string
+ assert 'prop1' in self.logger_output_string and 'value1' in self.logger_output_string
+ assert 'No nodes' not in self.logger_output_string
+ assert mock_models.NODE_NAME in self.logger_output_string
+
+
+class TestNodeTemplatesList(TestCliBase):
+
+ @pytest.mark.parametrize('sort_by, order, sort_by_in_output, order_in_output', [
+ ('', '', 'service_template_name', 'asc'),
+ ('', ' --descending', 'service_template_name', 'desc'),
+ (' --sort-by name', '', 'name', 'asc'),
+ (' --sort-by name', ' --descending', 'name', 'desc')
+ ])
+ def test_list_specified_service_template(self, monkeypatch, mock_storage, sort_by, order,
+ sort_by_in_output, order_in_output):
+
+ monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+ self.invoke('node_templates list -t {service_template_name}{sort_by}{order}'
+ .format(service_template_name=mock_models.SERVICE_TEMPLATE_NAME,
+ sort_by=sort_by,
+ order=order))
+ assert 'Listing node templates for service template {name}...'\
+ .format(name=mock_models.SERVICE_TEMPLATE_NAME) in self.logger_output_string
+ assert 'Listing all node templates...' not in self.logger_output_string
+
+ node_templates_list = mock_storage.node_template.list
+ node_templates_list.assert_called_once_with(sort={sort_by_in_output: order_in_output},
+ filters={'service_template': ANY})
+ assert 'Node templates:' in self.logger_output_string
+ assert mock_models.SERVICE_TEMPLATE_NAME in self.logger_output_string
+ assert mock_models.NODE_TEMPLATE_NAME in self.logger_output_string
+
+ @pytest.mark.parametrize('sort_by, order, sort_by_in_output, order_in_output', [
+ ('', '', 'service_template_name', 'asc'),
+ ('', ' --descending', 'service_template_name', 'desc'),
+ (' --sort-by name', '', 'name', 'asc'),
+ (' --sort-by name', ' --descending', 'name', 'desc')
+ ])
+ def test_list_no_specified_service_template(self, monkeypatch, mock_storage, sort_by, order,
+ sort_by_in_output, order_in_output):
+
+ monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+ self.invoke('node_templates list{sort_by}{order}'.format(sort_by=sort_by, order=order))
+ assert 'Listing all node templates...' in self.logger_output_string
+ assert 'Listing node templates for service template {name}...'\
+ .format(name=mock_models.SERVICE_TEMPLATE_NAME) not in self.logger_output_string
+
+ node_templates_list = mock_storage.node_template.list
+ node_templates_list.assert_called_once_with(sort={sort_by_in_output: order_in_output},
+ filters={})
+ assert 'Node templates:' in self.logger_output_string
+ assert mock_models.SERVICE_TEMPLATE_NAME in self.logger_output_string
+ assert mock_models.NODE_TEMPLATE_NAME in self.logger_output_string
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8e5a1ec2/tests/cli/test_nodes.py
----------------------------------------------------------------------
diff --git a/tests/cli/test_nodes.py b/tests/cli/test_nodes.py
new file mode 100644
index 0000000..0233989
--- /dev/null
+++ b/tests/cli/test_nodes.py
@@ -0,0 +1,101 @@
+# 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
+import mock
+
+from aria.cli.env import _Environment
+
+from .base_test import ( # pylint: disable=unused-import
+ TestCliBase,
+ mock_storage
+)
+from ..mock import models as mock_models
+
+
+class TestNodesShow(TestCliBase):
+
+ def test_header_strings(self, monkeypatch, mock_storage):
+ monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+ self.invoke('nodes show 1')
+ assert 'Showing node 1' in self.logger_output_string
+ assert 'Node:' in self.logger_output_string
+ assert 'Node attributes:' in self.logger_output_string
+
+ def test_no_attributes(self, monkeypatch, mock_storage):
+
+ monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+ self.invoke('nodes show 2')
+ assert 'No attributes' in self.logger_output_string
+ assert 'attribute1' not in self.logger_output_string
+ assert 'value1' not in self.logger_output_string
+
+ def test_one_attribute(self, monkeypatch, mock_storage):
+
+ monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+ m = mock.MagicMock(
+ return_value=mock_models.create_node_with_dependencies(include_attribute=True))
+ monkeypatch.setattr(mock_storage.node, 'get', m)
+ self.invoke('nodes show 3')
+ assert 'No attributes' not in self.logger_output_string
+ assert 'attribute1' in self.logger_output_string
+ assert 'value1' in self.logger_output_string
+
+
+class TestNodesList(TestCliBase):
+
+ @pytest.mark.parametrize('sort_by, order, sort_by_in_output, order_in_output', [
+ ('', '', 'service_name', 'asc'),
+ ('', ' --descending', 'service_name', 'desc'),
+ (' --sort-by name', '', 'name', 'asc'),
+ (' --sort-by name', ' --descending', 'name', 'desc')
+ ])
+ def test_list_specified_service(self, monkeypatch, mock_storage, sort_by, order,
+ sort_by_in_output, order_in_output):
+
+ monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+ self.invoke('nodes list -s test_s{sort_by}{order}'.format(sort_by=sort_by,
+ order=order))
+ assert 'Listing nodes for service test_s...' in self.logger_output_string
+ assert 'Listing all nodes...' not in self.logger_output_string
+
+ nodes_list = mock_storage.node.list
+ nodes_list.assert_called_once_with(sort={sort_by_in_output: order_in_output},
+ filters={'service': mock.ANY})
+ assert 'Nodes:' in self.logger_output_string
+ assert 'test_s' in self.logger_output_string
+ assert 'test_n' in self.logger_output_string
+
+ @pytest.mark.parametrize('sort_by, order, sort_by_in_output, order_in_output', [
+ ('', '', 'service_name', 'asc'),
+ ('', ' --descending', 'service_name', 'desc'),
+ (' --sort-by name', '', 'name', 'asc'),
+ (' --sort-by name', ' --descending', 'name', 'desc')
+ ])
+ def test_list_no_specified_service(self, monkeypatch, mock_storage, sort_by, order,
+ sort_by_in_output, order_in_output):
+
+ monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+ self.invoke('nodes list{sort_by}{order}'.format(sort_by=sort_by,
+ order=order))
+ assert 'Listing nodes for service test_s...' not in self.logger_output_string
+ assert 'Listing all nodes...' in self.logger_output_string
+
+ nodes_list = mock_storage.node.list
+ nodes_list.assert_called_once_with(sort={sort_by_in_output: order_in_output},
+ filters={})
+ assert 'Nodes:' in self.logger_output_string
+ assert 'test_s' in self.logger_output_string
+ assert 'test_n' in self.logger_output_string
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8e5a1ec2/tests/cli/test_service_templates.py
----------------------------------------------------------------------
diff --git a/tests/cli/test_service_templates.py b/tests/cli/test_service_templates.py
new file mode 100644
index 0000000..01b3f67
--- /dev/null
+++ b/tests/cli/test_service_templates.py
@@ -0,0 +1,246 @@
+# 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
+import mock
+
+from aria.cli import service_template_utils, csar
+from aria.cli.env import _Environment
+from aria.core import Core
+from aria.exceptions import AriaException
+from aria.storage import exceptions as storage_exceptions
+
+from .base_test import ( # pylint: disable=unused-import
+ TestCliBase,
+ assert_exception_raised,
+ raise_exception,
+ mock_storage
+)
+from ..mock import models as mock_models
+
+
+class TestServiceTemplatesShow(TestCliBase):
+
+ def test_header_string(self, monkeypatch, mock_storage):
+
+ monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+ self.invoke('service_templates show test_st')
+ assert 'Showing service template test_st...' in self.logger_output_string
+
+ def test_no_services_no_description(self, monkeypatch, mock_storage):
+
+ monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+ self.invoke('service_templates show test_st')
+
+ assert 'Description:' not in self.logger_output_string
+ assert 'Existing services:' not in self.logger_output_string
+
+ def test_no_services_yes_description(self, monkeypatch, mock_storage):
+
+ monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+ st = mock_models.create_service_template(description='test_description')
+ monkeypatch.setattr(mock_storage.service_template, 'get_by_name',
+ mock.MagicMock(return_value=st))
+
+ self.invoke('service_templates show test_st')
+ assert 'Description:' in self.logger_output_string
+ assert 'test_description' in self.logger_output_string
+ assert 'Existing services:' not in self.logger_output_string
+
+ def test_one_service_no_description(self, monkeypatch, mock_storage):
+
+ monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+ st = mock_models.create_service_template()
+ st.services = [mock_models.create_service(st)]
+ monkeypatch.setattr(mock_storage.service_template, 'get_by_name',
+ mock.MagicMock(return_value=st))
+
+ self.invoke('service_templates show test_st')
+
+ assert 'Description:' not in self.logger_output_string
+ assert 'Existing services:' in self.logger_output_string
+ assert mock_models.SERVICE_NAME in self.logger_output_string
+
+ def test_one_service_yes_description(self, monkeypatch, mock_storage):
+
+ monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+ st = mock_models.create_service_template(description='test_description')
+ st.services = [mock_models.create_service(st)]
+ monkeypatch.setattr(mock_storage.service_template, 'get_by_name',
+ mock.MagicMock(return_value=st))
+
+ self.invoke('service_templates show test_st')
+
+ assert 'Description:' in self.logger_output_string
+ assert 'test_description' in self.logger_output_string
+ assert 'Existing services:' in self.logger_output_string
+ assert 'test_s' in self.logger_output_string
+
+
+class TestServiceTemplatesList(TestCliBase):
+
+ def test_header_string(self, monkeypatch, mock_storage):
+
+ monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+ self.invoke('service_templates list')
+ assert 'Listing all service templates...' in self.logger_output_string
+
+ @pytest.mark.parametrize('sort_by, order, sort_by_in_output, order_in_output', [
+ ('', '', 'created_at', 'asc'),
+ ('', ' --descending', 'created_at', 'desc'),
+ (' --sort-by name', '', 'name', 'asc'),
+ (' --sort-by name', ' --descending', 'name', 'desc')
+ ])
+ def test_all_sorting_combinations(self, monkeypatch, mock_storage, sort_by, order,
+ sort_by_in_output, order_in_output):
+
+ monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+ self.invoke('service_templates list{sort_by}{order}'.format(sort_by=sort_by, order=order))
+
+ mock_storage.service_template.list.assert_called_with(
+ sort={sort_by_in_output: order_in_output})
+ assert mock_models.SERVICE_TEMPLATE_NAME in self.logger_output_string
+
+
+class TestServiceTemplatesStore(TestCliBase):
+
+ def test_header_string(self, monkeypatch, mock_storage):
+
+ monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+ self.invoke('service_templates store stubpath test_st')
+ assert 'Storing service template test_st...' in self.logger_output_string
+
+ def test_store_no_exception(self, monkeypatch, mock_object):
+
+ monkeypatch.setattr(Core, 'create_service_template', mock_object)
+ monkeypatch.setattr(service_template_utils, 'get', mock_object)
+ self.invoke('service_templates store stubpath {name}'.format(
+ name=mock_models.SERVICE_TEMPLATE_NAME))
+ assert 'Service template {name} stored'.format(
+ name=mock_models.SERVICE_TEMPLATE_NAME) in self.logger_output_string
+
+ def test_store_raises_exception_resulting_from_name_uniqueness(self, monkeypatch, mock_object):
+
+ monkeypatch.setattr(service_template_utils, 'get', mock_object)
+ monkeypatch.setattr(Core,
+ 'create_service_template',
+ raise_exception(storage_exceptions.NotFoundError,
+ msg='UNIQUE constraint failed'))
+
+ assert_exception_raised(
+ self.invoke('service_templates store stubpath test_st'),
+ expected_exception=storage_exceptions.NotFoundError,
+ expected_msg='There already a exists a service template with the same name')
+
+ def test_store_raises_exception(self, monkeypatch, mock_object):
+
+ monkeypatch.setattr(service_template_utils, 'get', mock_object)
+ monkeypatch.setattr(Core,
+ 'create_service_template',
+ raise_exception(storage_exceptions.NotFoundError))
+
+ assert_exception_raised(
+ self.invoke('service_templates store stubpath test_st'),
+ expected_exception=storage_exceptions.StorageError)
+
+
+class TestServiceTemplatesDelete(TestCliBase):
+
+ def test_header_string(self, monkeypatch, mock_storage):
+
+ monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+ self.invoke('service_templates delete test_st')
+ assert 'Deleting service template test_st...' in self.logger_output_string
+
+ def test_delete_no_exception(self, monkeypatch, mock_object):
+
+ monkeypatch.setattr(_Environment, 'model_storage', mock_object)
+ monkeypatch.setattr(Core, 'delete_service_template', mock_object)
+ self.invoke('service_templates delete {name}'.format(
+ name=mock_models.SERVICE_TEMPLATE_NAME))
+ assert 'Service template {name} deleted'.format(
+ name=mock_models.SERVICE_TEMPLATE_NAME) in self.logger_output_string
+
+ def test_delete_raises_exception(self, monkeypatch, mock_object):
+
+ monkeypatch.setattr(_Environment, 'model_storage', mock_object)
+ monkeypatch.setattr(Core,
+ 'delete_service_template',
+ raise_exception(storage_exceptions.StorageError))
+
+ assert_exception_raised(
+ self.invoke('service_templates delete test_st'),
+ expected_exception=storage_exceptions.StorageError,
+ expected_msg='')
+
+
+class TestServiceTemplatesInputs(TestCliBase):
+
+ def test_header_string(self, monkeypatch, mock_storage):
+
+ monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+ self.invoke('service_templates inputs test_st')
+ assert 'Showing inputs for service template test_st...' in self.logger_output_string
+
+ def test_inputs_existing_inputs(self, monkeypatch, mock_storage):
+ monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+ input = mock_models.create_parameter(name='input1', value='value1')
+ st = mock_models.create_service_template(inputs={'input1': input})
+ monkeypatch.setattr(mock_storage.service_template, 'get_by_name',
+ mock.MagicMock(return_value=st))
+
+ self.invoke('service_templates inputs with_inputs')
+ assert 'input1' in self.logger_output_string and 'value1' in self.logger_output_string
+
+ def test_inputs_no_inputs(self, monkeypatch, mock_storage):
+ monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+ self.invoke('service_templates inputs without_inputs')
+ assert 'No inputs' in self.logger_output_string
+
+
+class TestServiceTemplatesValidate(TestCliBase):
+
+ def test_header_string(self, monkeypatch, mock_storage):
+
+ monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+ self.invoke('service_templates validate stubpath')
+ assert 'Validating service template: stubpath' in self.logger_output_string
+
+ def test_validate_no_exception(self, monkeypatch, mock_object):
+ monkeypatch.setattr(Core, 'validate_service_template', mock_object)
+ monkeypatch.setattr(service_template_utils, 'get', mock_object)
+ self.invoke('service_templates validate stubpath')
+ assert 'Service template validated successfully' in self.logger_output_string
+
+ def test_validate_raises_exception(self, monkeypatch, mock_object):
+ monkeypatch.setattr(Core, 'validate_service_template', raise_exception(AriaException))
+ monkeypatch.setattr(service_template_utils, 'get', mock_object)
+ assert_exception_raised(
+ self.invoke('service_templates validate stubpath'),
+ expected_exception=AriaException)
+
+
+class TestServiceTemplatesCreateArchive(TestCliBase):
+
+ def test_header_string(self, monkeypatch, mock_storage):
+
+ monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+ self.invoke('service_templates create_archive stubpath stubdest')
+ assert 'Creating a csar archive' in self.logger_output_string
+
+ def test_create_archive_successful(self, monkeypatch, mock_object):
+ monkeypatch.setattr(csar, 'write', mock_object)
+ self.invoke('service_templates create_archive stubpath stubdest')
+ assert 'Csar archive created at stubdest' in self.logger_output_string
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8e5a1ec2/tests/cli/test_services.py
----------------------------------------------------------------------
diff --git a/tests/cli/test_services.py b/tests/cli/test_services.py
new file mode 100644
index 0000000..b1a6ee4
--- /dev/null
+++ b/tests/cli/test_services.py
@@ -0,0 +1,205 @@
+# 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
+import mock
+
+from aria.cli.env import _Environment
+from aria.core import Core
+from aria.exceptions import DependentActiveExecutionsError, DependentAvailableNodesError
+from aria.modeling.exceptions import InputsException
+from aria.storage import exceptions as storage_exceptions
+
+from .base_test import ( # pylint: disable=unused-import
+ TestCliBase,
+ raise_exception,
+ assert_exception_raised,
+ mock_storage
+)
+from ..mock import models as mock_models
+
+
+class TestServicesList(TestCliBase):
+
+ @pytest.mark.parametrize('sort_by, order, sort_by_in_output, order_in_output', [
+ ('', '', 'created_at', 'asc'),
+ ('', ' --descending', 'created_at', 'desc'),
+ (' --sort-by name', '', 'name', 'asc'),
+ (' --sort-by name', ' --descending', 'name', 'desc')
+ ])
+ def test_no_specified_service_template(self, monkeypatch, mock_storage, sort_by, order,
+ sort_by_in_output, order_in_output):
+
+ monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+ self.invoke('services list{sort_by}{order}'.format(sort_by=sort_by, order=order))
+ assert 'Listing all services...' in self.logger_output_string
+ assert 'Listing services for service template' not in self.logger_output_string
+
+ mock_storage.service.list.assert_called_once_with(sort={sort_by_in_output: order_in_output},
+ filters={})
+ assert 'Services:' in self.logger_output_string
+ assert mock_models.SERVICE_TEMPLATE_NAME in self.logger_output_string
+ assert mock_models.SERVICE_NAME in self.logger_output_string
+
+ @pytest.mark.parametrize('sort_by, order, sort_by_in_output, order_in_output', [
+ ('', '', 'created_at', 'asc'),
+ ('', ' --descending', 'created_at', 'desc'),
+ (' --sort-by name', '', 'name', 'asc'),
+ (' --sort-by name', ' --descending', 'name', 'desc')
+ ])
+ def test_specified_service_template(self, monkeypatch, mock_storage, sort_by, order,
+ sort_by_in_output, order_in_output):
+
+ monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+ self.invoke('services list -t test_st{sort_by}{order}'.format(sort_by=sort_by, order=order))
+ assert 'Listing services for service template test_st...' in self.logger_output_string
+ assert 'Listing all services...' not in self.logger_output_string
+
+ mock_storage.service.list.assert_called_once_with(sort={sort_by_in_output: order_in_output},
+ filters={'service_template': mock.ANY})
+ assert 'Services:' in self.logger_output_string
+ assert mock_models.SERVICE_TEMPLATE_NAME in self.logger_output_string
+ assert mock_models.SERVICE_NAME in self.logger_output_string
+
+
+class TestServicesCreate(TestCliBase):
+
+ def test_header_string(self, monkeypatch, mock_storage):
+ monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+ self.invoke('services create -t test_st test_s')
+ assert 'Creating new service from service template test_st...' in self.logger_output_string
+
+ def test_no_exception(self, monkeypatch, mock_storage):
+
+ monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+
+ m = mock.MagicMock(return_value=mock_models.create_service_with_dependencies())
+ monkeypatch.setattr(Core, 'create_service', m)
+ self.invoke('services create -t test_st test_s')
+ assert "Service created. The service's name is test_s" in self.logger_output_string
+
+ def test_raises_storage_error_resulting_from_name_uniqueness(self, monkeypatch,
+ mock_storage):
+ monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+ monkeypatch.setattr(Core,
+ 'create_service',
+ raise_exception(storage_exceptions.NotFoundError,
+ msg='UNIQUE constraint failed'))
+ assert_exception_raised(
+ self.invoke('services create -t test_st test_s'),
+ expected_exception=storage_exceptions.NotFoundError,
+ expected_msg='There already a exists a service with the same name')
+
+ assert "Service created. The service's name is test_s" not in self.logger_output_string
+
+ def test_raises_other_storage_error(self, monkeypatch, mock_object):
+ monkeypatch.setattr(_Environment, 'model_storage', mock_object)
+ monkeypatch.setattr(Core,
+ 'create_service',
+ raise_exception(storage_exceptions.NotFoundError))
+
+ assert_exception_raised(
+ self.invoke('services create -t test_st test_s'),
+ expected_exception=storage_exceptions.NotFoundError)
+
+ assert "Service created. The service's name is test_s" not in self.logger_output_string
+
+ def test_raises_inputs_exception(self, monkeypatch, mock_storage):
+ monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+ monkeypatch.setattr(Core,
+ 'create_service',
+ raise_exception(InputsException))
+
+ assert_exception_raised(
+ self.invoke('services create -t with_inputs test_s'),
+ expected_exception=InputsException)
+
+ assert "Service created. The service's name is test_s" not in self.logger_output_string
+
+
+class TestServicesDelete(TestCliBase):
+
+ def test_header_string(self, monkeypatch, mock_storage):
+ monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+ self.invoke('services delete test_s')
+ assert 'Deleting service test_s...' in self.logger_output_string
+
+ def test_delete_no_exception(self, monkeypatch, mock_storage, mock_object):
+
+ monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+ monkeypatch.setattr(Core, 'delete_service', mock_object)
+ self.invoke('services delete test_s')
+ assert 'Service test_s deleted' in self.logger_output_string
+
+ def test_delete_active_execution_error(self, monkeypatch, mock_storage):
+ monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+ mock_service_with_execution = \
+ mock.MagicMock(return_value=mock_models.create_service_with_dependencies(
+ include_execution=True))
+ monkeypatch.setattr(mock_storage.service, 'get', mock_service_with_execution)
+ assert_exception_raised(
+ self.invoke('services delete test_s'),
+ expected_exception=DependentActiveExecutionsError,
+ expected_msg="Can't delete service {name} - there is an active execution "
+ "for this service. Active execution id: 1".format(
+ name=mock_models.SERVICE_NAME))
+
+ def test_delete_available_nodes_error(self, monkeypatch, mock_storage):
+ monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+ assert_exception_raised(
+ self.invoke('services delete test_s'),
+ expected_exception=DependentAvailableNodesError,
+ expected_msg="Can't delete service {name} - there are available nodes "
+ "for this service. Available node ids: 1".format(
+ name=mock_models.SERVICE_NAME))
+
+ def test_delete_available_nodes_error_with_force(self, monkeypatch, mock_storage):
+ monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+ self.invoke('services delete service_with_available_nodes --force')
+
+ assert mock_storage.service.delete.call_count == 1
+ assert 'Service service_with_available_nodes deleted' in self.logger_output_string
+
+
+class TestServicesOutputs(TestCliBase):
+ pass
+
+
+class TestServicesInputs(TestCliBase):
+
+ def test_header_string(self, monkeypatch, mock_storage):
+ monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+ self.invoke('services inputs test_s')
+ assert 'Showing inputs for service test_s...' in self.logger_output_string
+
+ def test_inputs_no_inputs(self, monkeypatch, mock_storage):
+ monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+ self.invoke('services inputs service_with_no_inputs')
+
+ assert 'No inputs' in self.logger_output_string
+ assert 'input1' not in self.logger_output_string
+ assert 'value1' not in self.logger_output_string
+
+ def test_inputs_one_input(self, monkeypatch, mock_storage):
+
+ monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+ s = mock_models.create_service_with_dependencies(include_input=True)
+ monkeypatch.setattr(mock_storage.service, 'get_by_name', mock.MagicMock(return_value=s))
+
+ self.invoke('services inputs test_s')
+
+ assert 'input1' in self.logger_output_string
+ assert 'value1' in self.logger_output_string
+ assert 'No inputs' not in self.logger_output_string
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8e5a1ec2/tests/cli/utils.py
----------------------------------------------------------------------
diff --git a/tests/cli/utils.py b/tests/cli/utils.py
new file mode 100644
index 0000000..a1e0c9a
--- /dev/null
+++ b/tests/cli/utils.py
@@ -0,0 +1,101 @@
+# 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
+
+from mock import MagicMock
+
+from ..mock import models as mock_models
+
+
+def setup_logger(logger_name,
+ level=logging.INFO,
+ handlers=None,
+ remove_existing_handlers=True,
+ logger_format=None,
+ propagate=True):
+ """
+ :param logger_name: Name of the logger.
+ :param level: Level for the logger (not for specific handler).
+ :param handlers: An optional list of handlers (formatter will be
+ overridden); If None, only a StreamHandler for
+ sys.stdout will be used.
+ :param remove_existing_handlers: Determines whether to remove existing
+ handlers before adding new ones
+ :param logger_format: the format this logger will have.
+ :param propagate: propagate the message the parent logger.
+ :return: A logger instance.
+ :rtype: logging.Logger
+ """
+
+ logger = logging.getLogger(logger_name)
+
+ if remove_existing_handlers:
+ for handler in logger.handlers:
+ logger.removeHandler(handler)
+
+ for handler in handlers:
+ if logger_format:
+ formatter = logging.Formatter(fmt=logger_format)
+ handler.setFormatter(formatter)
+ logger.addHandler(handler)
+
+ logger.setLevel(level)
+ if not propagate:
+ logger.propagate = False
+
+ return logger
+
+
+class MockStorage(object):
+
+ def __init__(self):
+ self.service_template = MockServiceTemplateStorage()
+ self.service = MockServiceStorage()
+ self.node_template = MockNodeTemplateStorage()
+ self.node = MockNodeStorage()
+
+
+class MockServiceTemplateStorage(object):
+
+ def __init__(self):
+ self.list = MagicMock(return_value=[mock_models.create_service_template()])
+ self.get_by_name = MagicMock(return_value=mock_models.create_service_template())
+
+
+class MockServiceStorage(object):
+
+ def __init__(self):
+
+ self.s = mock_models.create_service_with_dependencies()
+
+ self.list = MagicMock(return_value=[self.s])
+ self.create = MagicMock(return_value=self.s)
+ self.get = MagicMock(
+ return_value=mock_models.create_service_with_dependencies(include_node=True))
+ self.get_by_name = MagicMock(return_value=self.s)
+ self.delete = MagicMock()
+
+
+class MockNodeTemplateStorage(object):
+ def __init__(self):
+ self.get = MagicMock(return_value=mock_models.create_node_template_with_dependencies())
+ self.list = MagicMock(return_value=[mock_models.create_node_template_with_dependencies()])
+
+
+class MockNodeStorage(object):
+ def __init__(self):
+ self.get = MagicMock(return_value=mock_models.create_node_with_dependencies())
+ self.list = MagicMock(return_value=[mock_models.create_node_with_dependencies()])
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8e5a1ec2/tests/conftest.py
----------------------------------------------------------------------
diff --git a/tests/conftest.py b/tests/conftest.py
index c501eeb..8f2c273 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -18,6 +18,7 @@ import logging
import pytest
import aria
+from aria import logger
@pytest.fixture(scope='session', autouse=True)
@@ -37,11 +38,10 @@ def logging_handler_cleanup(request):
:return:
"""
def clear_logging_handlers():
- logged_ctx_names = [
- aria.orchestrator.context.workflow.WorkflowContext.__name__,
- aria.orchestrator.context.operation.NodeOperationContext.__name__,
- aria.orchestrator.context.operation.RelationshipOperationContext.__name__
- ]
- for logger_name in logged_ctx_names:
- logging.getLogger(logger_name).handlers = []
+ logging.getLogger(logger.TASK_LOGGER_NAME).handlers = []
request.addfinalizer(clear_logging_handlers)
+
+
+@pytest.fixture
+def mock_object(mocker):
+ return mocker.MagicMock()
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8e5a1ec2/tests/end2end/test_orchestrator.py
----------------------------------------------------------------------
diff --git a/tests/end2end/test_orchestrator.py b/tests/end2end/test_orchestrator.py
deleted file mode 100644
index 4dfca44..0000000
--- a/tests/end2end/test_orchestrator.py
+++ /dev/null
@@ -1,63 +0,0 @@
-# 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 sys
-import os
-
-from aria.orchestrator.runner import Runner
-from aria.orchestrator.workflows.builtin import BUILTIN_WORKFLOWS
-from aria.utils.imports import import_fullname
-from aria.utils.collections import OrderedDict
-from aria.cli.dry import convert_to_dry
-
-from tests.parser.service_templates import consume_node_cellar
-
-
-WORKFLOW_POLICY_INTERNAL_PROPERTIES = ('implementation', 'dependencies')
-
-
-def test_install():
- _workflow('install')
-
-
-def test_custom():
- _workflow('maintenance_on')
-
-
-def _workflow(workflow_name):
- context, _ = consume_node_cellar()
-
- convert_to_dry(context.modeling.instance)
-
- # TODO: this logic will eventually stabilize and be part of the ARIA API,
- # likely somewhere in aria.orchestrator.workflows
- if workflow_name in BUILTIN_WORKFLOWS:
- workflow_fn = import_fullname('aria.orchestrator.workflows.builtin.' + workflow_name)
- inputs = {}
- else:
- workflow = context.modeling.instance.policies[workflow_name]
- sys.path.append(os.path.dirname(str(context.presentation.location)))
- workflow_fn = import_fullname(workflow.properties['implementation'].value)
- inputs = OrderedDict([
- (k, v.value) for k, v in workflow.properties.iteritems()
- if k not in WORKFLOW_POLICY_INTERNAL_PROPERTIES
- ])
-
- def _initialize_storage(model_storage):
- context.modeling.store(model_storage)
-
- runner = Runner(workflow_name, workflow_fn, inputs, _initialize_storage,
- lambda: context.modeling.instance.id)
- runner.run()
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8e5a1ec2/tests/end2end/test_tosca_simple_v1_0.py
----------------------------------------------------------------------
diff --git a/tests/end2end/test_tosca_simple_v1_0.py b/tests/end2end/test_tosca_simple_v1_0.py
deleted file mode 100644
index 4658fc3..0000000
--- a/tests/end2end/test_tosca_simple_v1_0.py
+++ /dev/null
@@ -1,112 +0,0 @@
-# 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 tests.parser.service_templates import (consume_use_case, consume_node_cellar)
-
-
-# Use Cases
-
-def test_use_case_compute_1():
- consume_use_case('compute-1', 'instance')
-
-
-def test_use_case_software_component_1():
- consume_use_case('software-component-1', 'instance')
-
-
-def test_use_case_block_storage_1():
- consume_use_case('block-storage-1', 'instance')
-
-
-def test_use_case_block_storage_2():
- consume_use_case('block-storage-2', 'instance')
-
-
-def test_use_case_block_storage_3():
- consume_use_case('block-storage-3', 'instance')
-
-
-def test_use_case_block_storage_4():
- consume_use_case('block-storage-4', 'instance')
-
-
-def test_use_case_block_storage_5():
- consume_use_case('block-storage-5', 'instance')
-
-
-def test_use_case_block_storage_6():
- consume_use_case('block-storage-6', 'instance')
-
-
-def test_use_case_object_storage_1():
- consume_use_case('object-storage-1', 'instance')
-
-
-def test_use_case_network_1():
- consume_use_case('network-1', 'instance')
-
-
-def test_use_case_network_2():
- consume_use_case('network-2', 'instance')
-
-
-def test_use_case_network_3():
- consume_use_case('network-3', 'instance')
-
-
-def test_use_case_network_4():
- consume_use_case('network-4', 'instance')
-
-
-def test_use_case_webserver_dbms_1():
- consume_use_case('webserver-dbms-1', 'template')
-
-
-def test_use_case_webserver_dbms_2():
- consume_use_case('webserver-dbms-2', 'instance')
-
-
-def test_use_case_multi_tier_1():
- consume_use_case('multi-tier-1', 'instance')
-
-
-def test_use_case_container_1():
- consume_use_case('container-1', 'template')
-
-
-# NodeCellar
-
-def test_node_cellar_validation():
- consume_node_cellar('validate')
-
-
-def test_node_cellar_validation_no_cache():
- consume_node_cellar('validate', False)
-
-
-def test_node_cellar_presentation():
- consume_node_cellar('presentation')
-
-
-def test_node_cellar_model():
- consume_node_cellar('template')
-
-
-def test_node_cellar_types():
- consume_node_cellar('types')
-
-
-def test_node_cellar_instance():
- consume_node_cellar('instance')
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8e5a1ec2/tests/fixtures.py
----------------------------------------------------------------------
diff --git a/tests/fixtures.py b/tests/fixtures.py
new file mode 100644
index 0000000..3b1b9b5
--- /dev/null
+++ b/tests/fixtures.py
@@ -0,0 +1,70 @@
+# 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 shutil
+
+import pytest
+
+from aria import (
+ application_model_storage,
+ application_resource_storage
+)
+from aria.orchestrator import plugin
+from aria.storage import (
+ sql_mapi,
+ filesystem_rapi
+)
+
+from . import storage
+
+
+@pytest.fixture
+def inmemory_model():
+ model = application_model_storage(sql_mapi.SQLAlchemyModelAPI,
+ initiator=storage.init_inmemory_model_storage)
+ yield model
+ storage.release_sqlite_storage(model)
+
+
+@pytest.fixture
+def fs_model(tmpdir):
+ result = application_model_storage(sql_mapi.SQLAlchemyModelAPI,
+ initiator_kwargs=dict(base_dir=str(tmpdir)),
+ initiator=sql_mapi.init_storage)
+ yield result
+ storage.release_sqlite_storage(result)
+
+
+@pytest.fixture
+def resource_storage(tmpdir):
+ result = tmpdir.join('resources')
+ result.mkdir()
+ resource_storage = application_resource_storage(
+ filesystem_rapi.FileSystemResourceAPI,
+ api_kwargs=dict(directory=str(result)))
+ yield resource_storage
+ shutil.rmtree(str(result))
+
+
+@pytest.fixture
+def plugins_dir(tmpdir):
+ result = tmpdir.join('plugins')
+ result.mkdir()
+ return str(result)
+
+
+@pytest.fixture
+def plugin_manager(model, plugins_dir):
+ return plugin.PluginManager(model=model, plugins_dir=plugins_dir)
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8e5a1ec2/tests/mock/context.py
----------------------------------------------------------------------
diff --git a/tests/mock/context.py b/tests/mock/context.py
index f943d7e..ac0a8a7 100644
--- a/tests/mock/context.py
+++ b/tests/mock/context.py
@@ -39,12 +39,17 @@ def simple(tmpdir, inmemory=False, context_kwargs=None, topology=None):
api_kwargs=dict(directory=os.path.join(tmpdir, 'resources'))
)
+ service_id = topology(model_storage)
+ execution = models.create_execution(model_storage.service.get(service_id))
+ model_storage.execution.put(execution)
+
final_kwargs = dict(
name='simple_context',
model_storage=model_storage,
resource_storage=resource_storage,
- service_id=topology(model_storage),
+ service_id=service_id,
workflow_name=models.WORKFLOW_NAME,
+ execution_id=execution.id,
task_max_attempts=models.TASK_MAX_ATTEMPTS,
task_retry_interval=models.TASK_RETRY_INTERVAL
)
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8e5a1ec2/tests/mock/models.py
----------------------------------------------------------------------
diff --git a/tests/mock/models.py b/tests/mock/models.py
index 1d29e2d..cdedea9 100644
--- a/tests/mock/models.py
+++ b/tests/mock/models.py
@@ -37,10 +37,11 @@ from aria.orchestrator.workflows.builtin.workflows import (
NORMATIVE_REMOVE_SOURCE
)
-SERVICE_NAME = 'test_service_name'
-SERVICE_TEMPLATE_NAME = 'test_service_template_name'
-WORKFLOW_NAME = 'test_workflow_name'
-EXECUTION_NAME = 'test_execution_name'
+SERVICE_TEMPLATE_NAME = 'test_service_template'
+SERVICE_NAME = 'test_service1'
+NODE_TEMPLATE_NAME = 'test_node_template'
+NODE_NAME = 'test_node1'
+WORKFLOW_NAME = 'test_workflow'
TASK_RETRY_INTERVAL = 1
TASK_MAX_ATTEMPTS = 1
@@ -50,11 +51,13 @@ DEPENDENT_NODE_TEMPLATE_NAME = 'dependent_node_template'
DEPENDENT_NODE_NAME = 'dependent_node'
-def create_service_template(name=SERVICE_TEMPLATE_NAME):
+def create_service_template(name=SERVICE_TEMPLATE_NAME, description=None, inputs=None):
now = datetime.now()
+ inputs = inputs or {}
return models.ServiceTemplate(
name=name,
- description=None,
+ description=description,
+ inputs=inputs,
created_at=now,
updated_at=now,
main_file_name='main_file_name',
@@ -68,10 +71,12 @@ def create_service_template(name=SERVICE_TEMPLATE_NAME):
)
-def create_service(service_template, name=SERVICE_NAME):
+def create_service(service_template, name=SERVICE_NAME, inputs=None):
now = datetime.utcnow()
+ inputs = inputs or {}
return models.Service(
name=name,
+ inputs=inputs,
service_template=service_template,
description='',
created_at=now,
@@ -81,6 +86,73 @@ def create_service(service_template, name=SERVICE_NAME):
)
+def create_service_with_dependencies(include_execution=False,
+ include_input=False,
+ include_node=False):
+ service_template = create_service_template()
+ service = create_service(service_template=service_template)
+ if include_execution:
+ execution = create_execution(service=service, status=models.Execution.STARTED)
+ service.executions = [execution]
+ execution.id = '1'
+ if include_input:
+ input = create_parameter(name='input1', value='value1')
+ service.inputs = {'input1': input}
+ if include_node:
+ node_template = create_node_template(service_template=service_template)
+ node = create_node(node_template, service, state=models.Node.STARTED)
+ node.id = '1'
+ return service
+
+
+def create_node_template_with_dependencies(include_node=False, include_property=False):
+ service_template = create_service_template()
+ node_template = create_node_template(service_template=service_template)
+ if include_node:
+ service = create_service(service_template=service_template)
+ create_node(dependency_node_template=node_template, service=service)
+ if include_property:
+ node_template.properties = {'prop1': create_parameter(name='prop1', value='value1')}
+ return node_template
+
+
+def create_node_with_dependencies(include_attribute=False):
+
+ node_template = create_node_template_with_dependencies()
+ node_template.service_template.services[0] = create_service(node_template.service_template)
+ node = create_node(node_template, node_template.service_template.services[0])
+ if include_attribute:
+ node.runtime_properties = {'attribute1': 'value1'}
+ return node
+
+
+def create_node_template(service_template,
+ name=NODE_TEMPLATE_NAME,
+ type=models.Type(variant='node', name='test_node_type'),
+ capability_templates=None,
+ requirement_templates=None,
+ interface_templates=None,
+ default_instances=1,
+ min_instances=1,
+ max_instances=1):
+ capability_templates = capability_templates or {}
+ requirement_templates = requirement_templates or []
+ interface_templates = interface_templates or {}
+ node_template = models.NodeTemplate(
+ name=name,
+ type=type,
+ capability_templates=capability_templates,
+ requirement_templates=requirement_templates,
+ interface_templates=interface_templates,
+ default_instances=default_instances,
+ min_instances=min_instances,
+ max_instances=max_instances,
+ service_template=service_template)
+
+ service_template.node_templates[node_template.name] = node_template
+ return node_template
+
+
def create_dependency_node_template(service_template, name=DEPENDENCY_NODE_TEMPLATE_NAME):
node_type = service_template.node_types.get_descendant('test_node_type')
capability_type = service_template.capability_types.get_descendant('test_capability_type')
@@ -89,18 +161,12 @@ def create_dependency_node_template(service_template, name=DEPENDENCY_NODE_TEMPL
name='capability',
type=capability_type
)
-
- node_template = models.NodeTemplate(
+ return create_node_template(
+ service_template=service_template,
name=name,
type=node_type,
- capability_templates=_dictify(capability_template),
- default_instances=1,
- min_instances=1,
- max_instances=1,
- service_template=service_template
+ capability_templates=_dictify(capability_template)
)
- service_template.node_templates[node_template.name] = node_template
- return node_template
def create_dependent_node_template(
@@ -111,29 +177,25 @@ def create_dependent_node_template(
name='requirement',
target_node_template=dependency_node_template
)
-
- node_template = models.NodeTemplate(
+ return create_node_template(
+ service_template=service_template,
name=name,
type=the_type,
- default_instances=1,
- min_instances=1,
- max_instances=1,
interface_templates=_dictify(get_standard_interface_template(service_template)),
requirement_templates=[requirement_template],
- service_template=service_template
)
- service_template.node_templates[node_template.name] = node_template
- return node_template
-def create_node(name, dependency_node_template, service):
+def create_node(dependency_node_template, service, name=NODE_NAME, state=models.Node.INITIAL,
+ runtime_properties=None):
+ runtime_properties = runtime_properties or {}
node = models.Node(
name=name,
type=dependency_node_template.type,
- runtime_properties={'ip': '1.1.1.1'},
+ runtime_properties=runtime_properties,
version=None,
node_template=dependency_node_template,
- state=models.Node.INITIAL,
+ state=state,
scaling_groups=[],
service=service,
interfaces=get_standard_interface(service),
@@ -168,6 +230,13 @@ def create_interface_template(service_template, interface_name, operation_name,
def create_interface(service, interface_name, operation_name, operation_kwargs=None,
interface_kwargs=None):
the_type = service.service_template.interface_types.get_descendant('test_interface_type')
+
+ if operation_kwargs and operation_kwargs.get('inputs'):
+ operation_kwargs['inputs'] = dict(
+ (input_name, models.Parameter.wrap(input_name, input_value))
+ for input_name, input_value in operation_kwargs['inputs'].iteritems()
+ if input_value is not None)
+
operation = models.Operation(
name=operation_name,
**(operation_kwargs or {})
@@ -180,13 +249,14 @@ def create_interface(service, interface_name, operation_name, operation_kwargs=N
)
-def create_execution(service):
+def create_execution(service, status=models.Execution.PENDING):
return models.Execution(
service=service,
- status=models.Execution.STARTED,
+ status=status,
workflow_name=WORKFLOW_NAME,
+ created_at=datetime.utcnow(),
started_at=datetime.utcnow(),
- parameters=None
+ inputs={}
)
@@ -214,6 +284,11 @@ def create_plugin_specification(name='test_plugin', version='0.1'):
)
+def create_parameter(name, value):
+ p = models.Parameter()
+ return p.wrap(name, value)
+
+
def _dictify(item):
return dict(((item.name, item),))
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8e5a1ec2/tests/mock/topology.py
----------------------------------------------------------------------
diff --git a/tests/mock/topology.py b/tests/mock/topology.py
index e5b4e01..bfb7b4e 100644
--- a/tests/mock/topology.py
+++ b/tests/mock/topology.py
@@ -33,7 +33,7 @@ def create_simple_topology_single_node(model_storage, create_operation):
)
node_template.interface_templates[interface_template.name] = interface_template # pylint: disable=unsubscriptable-object
- node = models.create_node(models.DEPENDENCY_NODE_NAME, node_template, service)
+ node = models.create_node(node_template, service, name=models.DEPENDENCY_NODE_NAME)
interface = models.create_interface(
service,
'Standard', 'create',
@@ -59,9 +59,9 @@ def create_simple_topology_two_nodes(model_storage):
dependency_node_template)
dependency_node = models.create_node(
- models.DEPENDENCY_NODE_NAME, dependency_node_template, service)
+ dependency_node_template, service, models.DEPENDENCY_NODE_NAME)
dependent_node = models.create_node(
- models.DEPENDENT_NODE_NAME, dependent_node_template, service)
+ dependent_node_template, service, models.DEPENDENT_NODE_NAME)
dependent_node.outbound_relationships.append(models.create_relationship( # pylint: disable=no-member
source=dependent_node,
@@ -86,7 +86,7 @@ def create_simple_topology_three_nodes(model_storage):
service = model_storage.service.get(service_id)
third_node_template = models.create_dependency_node_template(
service.service_template, name='another_dependency_node_template')
- third_node = models.create_node('another_dependency_node', third_node_template, service)
+ third_node = models.create_node(third_node_template, service, 'another_dependency_node')
new_relationship = models.create_relationship(
source=model_storage.node.get_by_name(models.DEPENDENT_NODE_NAME),
target=third_node,
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8e5a1ec2/tests/mock/workflow.py
----------------------------------------------------------------------
diff --git a/tests/mock/workflow.py b/tests/mock/workflow.py
new file mode 100644
index 0000000..b12b9fa
--- /dev/null
+++ b/tests/mock/workflow.py
@@ -0,0 +1,26 @@
+# 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 json
+
+from aria.orchestrator.decorators import workflow
+
+
+@workflow
+def mock_workflow(graph, ctx, output_path=None, **kwargs): # pylint: disable=unused-argument
+ if output_path:
+ # writes call arguments to the specified output file
+ with open(output_path, 'w') as f:
+ json.dump(kwargs, f)