summaryrefslogtreecommitdiffstats
path: root/azure/aria/aria-extension-cloudify/src/aria/tests/cli
diff options
context:
space:
mode:
Diffstat (limited to 'azure/aria/aria-extension-cloudify/src/aria/tests/cli')
-rw-r--r--azure/aria/aria-extension-cloudify/src/aria/tests/cli/__init__.py14
-rw-r--r--azure/aria/aria-extension-cloudify/src/aria/tests/cli/base_test.py77
-rw-r--r--azure/aria/aria-extension-cloudify/src/aria/tests/cli/runner.py27
-rw-r--r--azure/aria/aria-extension-cloudify/src/aria/tests/cli/test_node_templates.py133
-rw-r--r--azure/aria/aria-extension-cloudify/src/aria/tests/cli/test_nodes.py101
-rw-r--r--azure/aria/aria-extension-cloudify/src/aria/tests/cli/test_service_templates.py273
-rw-r--r--azure/aria/aria-extension-cloudify/src/aria/tests/cli/test_services.py227
-rw-r--r--azure/aria/aria-extension-cloudify/src/aria/tests/cli/utils.py101
8 files changed, 953 insertions, 0 deletions
diff --git a/azure/aria/aria-extension-cloudify/src/aria/tests/cli/__init__.py b/azure/aria/aria-extension-cloudify/src/aria/tests/cli/__init__.py
new file mode 100644
index 0000000..ae1e83e
--- /dev/null
+++ b/azure/aria/aria-extension-cloudify/src/aria/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.
diff --git a/azure/aria/aria-extension-cloudify/src/aria/tests/cli/base_test.py b/azure/aria/aria-extension-cloudify/src/aria/tests/cli/base_test.py
new file mode 100644
index 0000000..da9d72c
--- /dev/null
+++ b/azure/aria/aria-extension-cloudify/src/aria/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()
diff --git a/azure/aria/aria-extension-cloudify/src/aria/tests/cli/runner.py b/azure/aria/aria-extension-cloudify/src/aria/tests/cli/runner.py
new file mode 100644
index 0000000..7e4243b
--- /dev/null
+++ b/azure/aria/aria-extension-cloudify/src/aria/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
diff --git a/azure/aria/aria-extension-cloudify/src/aria/tests/cli/test_node_templates.py b/azure/aria/aria-extension-cloudify/src/aria/tests/cli/test_node_templates.py
new file mode 100644
index 0000000..ff7ff28
--- /dev/null
+++ b/azure/aria/aria-extension-cloudify/src/aria/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
diff --git a/azure/aria/aria-extension-cloudify/src/aria/tests/cli/test_nodes.py b/azure/aria/aria-extension-cloudify/src/aria/tests/cli/test_nodes.py
new file mode 100644
index 0000000..0233989
--- /dev/null
+++ b/azure/aria/aria-extension-cloudify/src/aria/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
diff --git a/azure/aria/aria-extension-cloudify/src/aria/tests/cli/test_service_templates.py b/azure/aria/aria-extension-cloudify/src/aria/tests/cli/test_service_templates.py
new file mode 100644
index 0000000..cc0150e
--- /dev/null
+++ b/azure/aria/aria-extension-cloudify/src/aria/tests/cli/test_service_templates.py
@@ -0,0 +1,273 @@
+# 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 zipfile
+
+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()
+ s = mock_models.create_service(st)
+ st.services = {s.name: s}
+ 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')
+ s = mock_models.create_service(st)
+ st.services = {s.name: s}
+ 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)
+ monkeypatch.setattr(os.path, 'dirname', 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_relative_path_single_yaml_file(self, monkeypatch, mock_object):
+ monkeypatch.setattr(Core, 'create_service_template', mock_object)
+ monkeypatch.setattr(os.path, 'isfile', lambda x: True)
+ monkeypatch.setattr(service_template_utils, '_is_archive', lambda x: False)
+
+ self.invoke('service_templates store service_template.yaml {name}'.format(
+ name=mock_models.SERVICE_TEMPLATE_NAME))
+
+ mock_object.assert_called_with(os.path.join(os.getcwd(), 'service_template.yaml'),
+ mock.ANY,
+ mock.ANY)
+
+ 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'))
+ monkeypatch.setattr(os.path, 'dirname', mock_object)
+
+ 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))
+ monkeypatch.setattr(os.path, 'dirname', mock_object)
+
+ 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_input(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
+
+ def test_create_archive_from_relative_path(self, monkeypatch, mock_object):
+
+ monkeypatch.setattr(os.path, 'isfile', mock_object)
+ monkeypatch.setattr(zipfile, 'ZipFile', mock.MagicMock)
+
+ self.invoke('service_templates create_archive archive stubdest')
+ mock_object.assert_called_with(os.path.join(os.getcwd(), 'archive'))
diff --git a/azure/aria/aria-extension-cloudify/src/aria/tests/cli/test_services.py b/azure/aria/aria-extension-cloudify/src/aria/tests/cli/test_services.py
new file mode 100644
index 0000000..7dc84bc
--- /dev/null
+++ b/azure/aria/aria-extension-cloudify/src/aria/tests/cli/test_services.py
@@ -0,0 +1,227 @@
+# 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 ParameterException
+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(ParameterException))
+
+ assert_exception_raised(
+ self.invoke('services create -t with_inputs test_s'),
+ expected_exception=ParameterException)
+
+ 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):
+
+ def test_header_string(self, monkeypatch, mock_storage):
+ monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+ self.invoke('services outputs test_s')
+ assert 'Showing outputs for service test_s...' in self.logger_output_string
+
+ def test_outputs_no_outputs(self, monkeypatch, mock_storage):
+ monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+ self.invoke('services outputs service_with_no_outputs')
+
+ assert 'No outputs' in self.logger_output_string
+ assert 'output1' not in self.logger_output_string
+ assert 'value1' not in self.logger_output_string
+
+ def test_outputs_one_output(self, monkeypatch, mock_storage):
+ monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+ s = mock_models.create_service_with_dependencies(include_output=True)
+ monkeypatch.setattr(mock_storage.service, 'get_by_name', mock.MagicMock(return_value=s))
+
+ self.invoke('services outputs test_s')
+
+ assert 'output1' in self.logger_output_string
+ assert 'value1' in self.logger_output_string
+ assert 'No outputs' not in self.logger_output_string
+
+
+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
diff --git a/azure/aria/aria-extension-cloudify/src/aria/tests/cli/utils.py b/azure/aria/aria-extension-cloudify/src/aria/tests/cli/utils.py
new file mode 100644
index 0000000..a1e0c9a
--- /dev/null
+++ b/azure/aria/aria-extension-cloudify/src/aria/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()])