murano-dashboard/muranodashboard/tests/unit/packages/test_views.py

1297 lines
54 KiB
Python

# Copyright (c) 2016 AT&T Corp
#
# Licensed 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 django.core.files import storage
from django import http
from django.utils.translation import ugettext_lazy as _
import mock
from horizon import exceptions as horizon_exceptions
from muranoclient.common import exceptions as exc
from muranodashboard.packages import consts as packages_consts
from muranodashboard.packages import forms
from muranodashboard.packages import tables
from muranodashboard.packages import views
from openstack_dashboard.test import helpers
class TestPackageView(helpers.APITestCase):
def setUp(self):
super(TestPackageView, self).setUp()
fake_response = {'status_code': 200}
self.mock_request = mock.Mock(return_value=fake_response)
self.addCleanup(mock.patch.stopall)
@mock.patch('muranodashboard.packages.views.api.muranoclient')
def test_download_package(self, mock_client):
mock_client().packages.download.return_value = {}
response =\
views.download_packge(self.mock_request, 'test_app_name', None)
expected_response = {
'Content-Type': 'application/octet-stream',
'Content-Disposition': 'filename=test_app_name.zip'
}
self.assertIsInstance(response, http.HttpResponse)
for key, val in expected_response.items():
self.assertIn(key.lower(), response._headers)
self.assertEqual((key, val), response._headers[key.lower()])
@mock.patch.object(views, 'exceptions')
@mock.patch.object(views, 'reverse')
@mock.patch.object(views, 'LOG')
@mock.patch('muranodashboard.packages.views.api.muranoclient')
def test_download_package_except_http_exception(self, mock_client,
mock_log, mock_reverse,
mock_exc):
mock_client().packages.download.side_effect = exc.HTTPException
mock_reverse.return_value = 'test_redirect'
views.download_packge(self.mock_request, 'test_app_name', None)
mock_log.exception.assert_called_once_with(
'Something went wrong during package downloading')
mock_reverse.assert_called_once_with(
'horizon:app-catalog:packages:index')
mock_exc.handle.assert_called_once_with(
self.mock_request, 'Unable to download package.',
redirect='test_redirect')
def test_is_app(self):
mock_wizard = mock.Mock()
mock_step_data = mock.MagicMock()
mock_step_data.__getitem__().type = 'Application'
mock_wizard.storage.get_step_data.return_value = mock_step_data
self.assertTrue(views.is_app(mock_wizard))
mock_step_data.__getitem__().type = 'Non-Application'
mock_wizard.storage.get_step_data.return_value = mock_step_data
self.assertFalse(views.is_app(mock_wizard))
class TestDetailView(helpers.APITestCase):
def setUp(self):
super(TestDetailView, self).setUp()
self.detail_view = views.DetailView()
fake_response = {'status_code': 200}
self.mock_request = mock.Mock(return_value=fake_response)
self.detail_view.request = self.mock_request
self.detail_view.kwargs = {'app_id': 'foo'}
self.assertEqual('packages/detail.html',
self.detail_view.template_name)
self.assertEqual('{{ app.name }}', self.detail_view.page_title)
self.addCleanup(mock.patch.stopall)
@mock.patch('muranodashboard.packages.views.api.muranoclient')
def test_get_context_data(self, mock_client):
mock_client().packages.get.return_value = 'test_app'
context = self.detail_view.get_context_data()
self.assertIn('app', context)
self.assertIn('view', context)
self.assertIsInstance(context['view'], views.DetailView)
self.assertEqual('test_app', context['app'])
@mock.patch.object(views, 'exceptions')
@mock.patch.object(views, 'reverse')
@mock.patch('muranodashboard.packages.views.api.muranoclient')
def test_get_context_data_except_exception(self, mock_client, mock_reverse,
mock_exc):
mock_client().packages.get.side_effect = Exception
mock_reverse.return_value = 'test_redirect'
self.detail_view.get_context_data()
mock_exc.handle.assert_called_once_with(
self.mock_request, 'Unable to retrieve package details.',
redirect='test_redirect')
class TestModifyPackageView(helpers.APITestCase):
def setUp(self):
super(TestModifyPackageView, self).setUp()
self.modify_pkg_view = views.ModifyPackageView()
fake_response = {'status_code': 200}
self.mock_request = mock.Mock(return_value=fake_response, META=[])
self.modify_pkg_view.request = self.mock_request
self.modify_pkg_view.kwargs = {'app_id': 'foo'}
self.assertEqual(forms.ModifyPackageForm,
self.modify_pkg_view.form_class)
self.assertEqual('packages/modify_package.html',
self.modify_pkg_view.template_name)
self.assertEqual('Modify Package', self.modify_pkg_view.page_title)
self.addCleanup(mock.patch.stopall)
@mock.patch('muranodashboard.packages.views.api.muranoclient')
def test_get_initial(self, mock_client):
mock_package = mock.Mock()
mock_client().packages.get.return_value = mock_package
expected_result = {
'package': mock_package,
'app_id': 'foo'
}
result = self.modify_pkg_view.get_initial()
for key, val in expected_result.items():
self.assertEqual(val, result[key])
def test_get_context_data(self):
mock_form = mock.Mock(return_value=type(
'FakeForm', (object, ), {'initial': {
'package': type(
'FakeFormInner', (object, ), {'type': 'test_type'}
)
}}
))
self.modify_pkg_view.get_form = mock_form
expected_context = {
'app_id': 'foo',
'type': 'test_type',
'form': mock_form
}
context = self.modify_pkg_view.get_context_data(form=mock_form)
self.assertIn('view', context)
self.assertIsInstance(context['view'], views.ModifyPackageView)
for key, val in expected_context.items():
self.assertIn(key, context)
self.assertEqual(val, context[key])
self.modify_pkg_view.get_form.assert_called_once_with()
class TestImportPackageWizard(helpers.APITestCase):
def setUp(self):
super(TestImportPackageWizard, self).setUp()
fake_response = {'status_code': 200}
self.mock_request = mock.MagicMock(return_value=fake_response, META=[])
self.import_pkg_wizard = views.ImportPackageWizard()
self.import_pkg_wizard.request = self.mock_request
all_cleaned_data = {
'enabled': False,
'is_public': True,
'package': 'test_package',
'import_type': 'test_import_type',
'url': 'test_url',
'repo_version': 'test_repo_version',
'repo_name': 'test_repo_name',
'tags': 'foo,bar,baz,qux'
}
self.import_pkg_wizard.get_all_cleaned_data = lambda: all_cleaned_data
self.import_pkg_wizard.steps = mock.Mock(current='upload')
self.assertIsInstance(self.import_pkg_wizard.file_storage,
storage.FileSystemStorage)
self.assertEqual('packages/upload.html',
self.import_pkg_wizard.template_name)
self.assertEqual({'add_category': views.is_app},
self.import_pkg_wizard.condition_dict)
self.assertEqual('Import Package',
self.import_pkg_wizard.page_title)
self.addCleanup(mock.patch.stopall)
def test_get_form_initial(self):
self.mock_request.GET = {
'url': 'test_url',
'repo_name': 'test_repo_name',
'repo_version': 'test_repo_version',
'import_type': 'test_import_type'
}
expected_dict = {
'foo': 'bar',
'url': 'test_url',
'repo_name': 'test_repo_name',
'repo_version': 'test_repo_version',
'import_type': 'test_import_type'
}
self.import_pkg_wizard.initial_dict = {'upload': {'foo': 'bar'}}
initial_dict = self.import_pkg_wizard.get_form_initial('upload')
for key, val in expected_dict.items():
self.assertIn(key, initial_dict)
self.assertEqual(val, initial_dict[key])
def test_get_context_data(self):
mock_form = mock.Mock()
self.import_pkg_wizard.storage = mock.Mock(
extra_data={'extra': 'data'})
self.import_pkg_wizard.prefix = 'test_prefix'
expected_result = {
'form': mock_form,
'modal_backdrop': 'static',
'extra': 'data',
'murano_repo_url': 'http://apps.openstack.org',
'wizard': {
'steps': self.import_pkg_wizard.steps,
'form': mock_form
}
}
result = self.import_pkg_wizard.get_context_data(form=mock_form)
self.assertIn('view', result)
self.assertIsInstance(result['view'], views.ImportPackageWizard)
for key, val in expected_result.items():
if isinstance(val, dict):
for key_, val_ in val.items():
self.assertEqual(val_, val[key_])
else:
self.assertEqual(val, result[key])
@mock.patch.object(views, 'exceptions')
@mock.patch.object(views, 'reverse')
@mock.patch.object(views, 'glance')
@mock.patch.object(views, 'api')
def test_done(self, mock_api, mock_glance, mock_reverse, mock_exc):
mock_storage = mock.MagicMock()
mock_storage.get_step_data().__getitem__.return_value =\
mock.Mock(id='test_package_id')
mock_storage.get_step_data().get.side_effect = [
[mock.Mock(id='test_dep_pkg_id', fully_qualified_name='fqn')],
[{'id': 'test_image_id'}]
]
self.import_pkg_wizard.storage = mock_storage
self.import_pkg_wizard.form_list = {}
self.import_pkg_wizard.done({})
expected_api_mock_calls = [
mock.call('test_dep_pkg_id',
{'enabled': False, 'is_public': True}),
mock.call('test_package_id',
{'enabled': False, 'is_public': True,
'tags': ['foo', 'bar', 'baz', 'qux']}),
]
mock_api.muranoclient().packages.update.assert_has_calls(
expected_api_mock_calls)
mock_reverse.assert_called_once_with(
'horizon:app-catalog:packages:index')
mock_glance.glanceclient().images.update.assert_called_once_with(
mock.ANY, is_public=True)
mock_storage.get_step_data.assert_any_call('upload')
mock_storage.get_step_data().get.assert_any_call('dependencies', [])
mock_storage.get_step_data().get.assert_any_call('images', [])
mock_exc.handle.assert_not_called()
@mock.patch.object(views, 'reverse')
@mock.patch.object(views, 'glance')
@mock.patch.object(views, 'LOG')
@mock.patch.object(views, 'messages')
@mock.patch.object(views, 'api')
def test_done_except_murano_client_exception(self, mock_api, mock_messages,
mock_log, *args):
mock_storage = mock.MagicMock()
mock_storage.get_step_data().__getitem__.return_value =\
mock.Mock(id='test_package_id')
mock_storage.get_step_data().get.side_effect = [
[mock.Mock(id='test_dep_pkg_id', fully_qualified_name='fqn')],
[{'id': 'test_image_id'}]
]
mock_api.muranoclient().packages.update.side_effect = [
Exception("murano client error message."), None
]
self.import_pkg_wizard.storage = mock_storage
self.import_pkg_wizard.form_list = {}
self.import_pkg_wizard.done({})
expected_msg = "Couldn't update package {0} parameters. Error: {1}"\
.format('fqn', 'murano client error message.')
mock_log.warning.assert_called_once_with(expected_msg)
mock_messages.warning.assert_called_once_with(
self.mock_request, expected_msg)
@mock.patch.object(views, 'api')
@mock.patch.object(views, 'reverse')
@mock.patch.object(views, 'glance')
@mock.patch.object(views, 'LOG')
@mock.patch.object(views, 'messages')
def test_done_except_glance_init_exception(self, mock_messages, mock_log,
mock_glance, *args):
"""Test null glance client with installed images throws exception."""
mock_storage = mock.MagicMock()
mock_storage.get_step_data().__getitem__.return_value =\
mock.Mock(id='test_package_id')
mock_storage.get_step_data().get.side_effect = [
[mock.Mock(id='test_dep_pkg_id', fully_qualified_name='fqn')],
[{'id': 'foo_image_id', 'name': 'foo_image_name'},
{'id': 'bar_image_id', 'name': 'bar_image_name'}]
]
mock_glance.glanceclient.return_value = None
self.import_pkg_wizard.storage = mock_storage
self.import_pkg_wizard.form_list = {}
self.import_pkg_wizard.done({})
expected_msg = "Couldn't initialise glance v1 client, therefore "\
"could not make the following images public: {0}"\
.format('foo_image_name bar_image_name')
mock_log.warning.assert_called_once_with(expected_msg)
mock_messages.warning.assert_called_once_with(
self.mock_request, expected_msg)
@mock.patch.object(views, 'api')
@mock.patch.object(views, 'reverse')
@mock.patch.object(views, 'glance')
@mock.patch.object(views, 'LOG')
@mock.patch.object(views, 'messages')
def test_done_except_glance_update_exception(self, mock_messages, mock_log,
mock_glance, *args):
mock_storage = mock.MagicMock()
mock_storage.get_step_data().__getitem__.return_value =\
mock.Mock(id='test_package_id')
mock_storage.get_step_data().get.side_effect = [
[mock.Mock(id='test_dep_pkg_id', fully_qualified_name='fqn')],
[{'id': 'test_image_id', 'name': 'test_image_name'}]
]
glance_exception = Exception("glance client error message")
mock_glance.glanceclient().images.update.side_effect =\
glance_exception
self.import_pkg_wizard.storage = mock_storage
self.import_pkg_wizard.form_list = {}
self.import_pkg_wizard.done({})
expected_msg = "Error {0} occurred while setting image {1}, {2} "\
"public".format(glance_exception, "test_image_name",
"test_image_id")
mock_log.exception.assert_called_once_with(expected_msg)
mock_messages.error.assert_called_once_with(
self.mock_request, expected_msg)
@mock.patch.object(views, 'glance')
@mock.patch.object(views, 'reverse')
@mock.patch.object(views, 'LOG')
@mock.patch.object(views, 'exceptions')
@mock.patch.object(views, 'api')
def test_done_except_http_forbidden(self, mock_api, mock_exc, mock_log,
mock_reverse, _):
mock_storage = mock.MagicMock()
mock_storage.get_step_data().__getitem__.return_value =\
mock.Mock(id='test_package_id')
mock_storage.get_step_data().get.side_effect = [
[mock.Mock(id='test_dep_pkg_id', fully_qualified_name='fqn')],
[{'id': 'test_image_id', 'name': 'test_image_name'}]
]
mock_api.muranoclient().packages.update.side_effect = [
None, exc.HTTPForbidden
]
mock_reverse.return_value = 'test_redirect'
self.import_pkg_wizard.storage = mock_storage
self.import_pkg_wizard.form_list = {}
self.import_pkg_wizard.done({})
expected_msg = "You are not allowed to change this properties of the "\
"package"
mock_log.exception.assert_called_once_with(expected_msg)
mock_exc.handle.assert_called_once_with(
self.mock_request, expected_msg, redirect='test_redirect')
@mock.patch.object(views, 'glance')
@mock.patch.object(views, 'reverse')
@mock.patch.object(views, 'LOG')
@mock.patch.object(views, 'exceptions')
@mock.patch.object(views, 'api')
def test_done_except_http_exception(self, mock_api, mock_exc, mock_log,
mock_reverse, _):
mock_storage = mock.MagicMock()
mock_storage.get_step_data().__getitem__.return_value =\
mock.Mock(id='test_package_id')
mock_storage.get_step_data().get.side_effect = [
[mock.Mock(id='test_dep_pkg_id', fully_qualified_name='fqn')],
[{'id': 'test_image_id', 'name': 'test_image_name'}]
]
mock_api.muranoclient().packages.update.side_effect = [
None, exc.HTTPException
]
mock_reverse.return_value = 'test_redirect'
self.import_pkg_wizard.storage = mock_storage
self.import_pkg_wizard.form_list = {}
self.import_pkg_wizard.done({})
expected_msg = 'Modifying package failed'
mock_log.exception.assert_called_once_with(expected_msg)
mock_exc.handle.assert_called_once_with(
self.mock_request, 'Unable to modify package',
redirect='test_redirect')
@mock.patch.object(views, 'reverse')
@mock.patch.object(views, 'exceptions')
@mock.patch.object(views, 'LOG')
def test_handle_exception(self, mock_log, mock_exc, mock_reverse):
mock_exception = mock.Mock()
mock_exception.details = '{"error": {"message": "test_error_message"}}'
mock_reverse.return_value = 'test_redirect'
self.import_pkg_wizard.request = self.mock_request
self.import_pkg_wizard._handle_exception(mock_exception)
expected_msg = 'Uploading package failed. {0}'\
.format('test_error_message')
mock_log.exception.assert_called_once_with(expected_msg)
mock_exc.handle.assert_called_once_with(
self.mock_request, expected_msg, redirect='test_redirect')
mock_reverse.assert_called_once_with(
'horizon:app-catalog:packages:index')
@mock.patch.object(views, 'json')
def test_handle_exception_except_value_error(self, mock_json):
mock_json.loads.side_effect = ValueError('test_error_message')
original_e = ValueError('original_error_message')
setattr(original_e, 'details', 'error_details')
with self.assertRaisesRegex(ValueError, 'original_error_message'):
self.import_pkg_wizard._handle_exception(original_e)
@mock.patch.object(views, 'glance')
@mock.patch.object(views, 'messages')
@mock.patch.object(views, 'api')
@mock.patch.object(views, 'muranoclient_utils')
def test_process_step(self, mock_murano_utils, mock_api, mock_messages, _):
mock_package = mock.Mock()
mock_package.manifest = {'FullName': 'foo'}
mock_original_package = mock.Mock()
mock_original_package.file.return_value = 'foo_file'
mock_package.requirements.return_value =\
{'foo': mock_original_package, 'bar': mock.Mock()}
mock_murano_utils.ensure_images.return_value = [
{'id': 1, 'name': 'foo'}, {'id': 2, 'name': 'bar'}
]
mock_murano_utils.Package.from_file.return_value = mock_package
mock_dependency_package = mock.Mock()
mock_result_package = mock.Mock(id='result_package_id')
mock_api.muranoclient().packages.create.side_effect = [
mock_dependency_package,
mock_result_package
]
mock_form = mock.Mock()
mock_form.cleaned_data = {
'import_type': 'upload',
'package': mock.Mock(file='test_package_file')
}
mock_form.data = {
'dependencies': ['dep1', 'dep2'],
'images': ['img1', 'img2']
}
step_data = self.import_pkg_wizard.process_step(mock_form)
for expected_key in ('images', 'dependencies', 'package'):
self.assertIn(expected_key, step_data)
self.assertIn({'id': 1, 'name': 'foo'}, step_data['images'])
self.assertIn({'id': 2, 'name': 'bar'}, step_data['images'])
self.assertEqual([mock_dependency_package], step_data['dependencies'])
self.assertEqual(mock_result_package, step_data['package'])
self.assertEqual(2, mock_murano_utils.ensure_images.call_count)
mock_murano_utils.Package.from_file.assert_called_once_with(
'test_package_file')
mock_api.muranoclient().packages.create.assert_any_call(
mock.ANY, {'foo': 'foo_file'})
mock_package.requirements.assert_called_once_with(
base_url=packages_consts.MURANO_REPO_URL)
mock_messages.success.assert_any_call(
self.mock_request, 'Package bar uploaded')
mock_messages.success.assert_any_call(
self.mock_request, 'Package foo uploaded')
@mock.patch.object(views, 'reverse')
@mock.patch.object(views, 'LOG')
@mock.patch.object(views, 'muranoclient_utils')
def test_process_step_except_from_file_exception(
self, mock_murano_utils, mock_log, mock_reverse):
mock_reverse.return_value = 'test_redirect'
mock_form = mock.Mock()
mock_form.cleaned_data = {
'import_type': 'upload',
'package': mock.Mock(file='test_package_file')
}
errors = (('(404) test_404_error', "Package creation failed."
"Reason: Can't find Package name "
"from repository."),
('random error message', "Package creation failed.Reason: "
"random error message"))
for error_message, expected_error_message in errors:
exception = Exception(error_message)
exception.message = error_message
mock_murano_utils.Package.from_file.side_effect = exception
with self.assertRaisesRegex(horizon_exceptions.Http302,
None):
self.import_pkg_wizard.process_step(mock_form)
mock_log.exception.assert_called_once_with(expected_error_message)
mock_reverse.assert_called_once_with(
'horizon:app-catalog:packages:index')
mock_log.exception.reset_mock()
mock_reverse.reset_mock()
@mock.patch.object(views, 'exceptions')
@mock.patch.object(views, 'messages')
@mock.patch.object(views, 'reverse')
@mock.patch.object(views, 'LOG')
@mock.patch.object(views, 'api')
@mock.patch.object(views, 'muranoclient_utils')
@mock.patch.object(views, 'glance')
def test_process_step_except_package_create_exception(
self, mock_glance, mock_murano_utils, mock_api, mock_log,
mock_reverse, mock_messages, mock_exc):
mock_murano_utils.Package.from_file.side_effect = None
mock_reverse.return_value = 'test_redirect'
mock_package = mock.Mock()
mock_package.manifest = {'FullName': 'foo'}
mock_murano_utils.Package.from_file.return_value = mock_package
mock_form = mock.Mock()
mock_form.cleaned_data = {
'import_type': 'upload',
'package': mock.Mock(file='test_package_file')
}
mock_form.data = {
'dependencies': [],
'images': []
}
# Test that first occurrence of exception is handled.
mock_package.requirements.return_value =\
{'foo': mock.Mock(), 'bar': mock.Mock()}
expected_error_message = _(
"Error test_error_message occurred while installing package bar")
mock_api.muranoclient().packages.create.side_effect = [
Exception('test_error_message'), mock.Mock(id='test_package_id')
]
self.import_pkg_wizard.process_step(mock_form)
mock_messages.error.assert_any_call(
self.mock_request, expected_error_message)
mock_messages.success.assert_any_call(
self.mock_request, _('Package foo uploaded'))
mock_log.exception.assert_called_once_with(expected_error_message)
mock_log.exception.reset_mock()
mock_messages.reset_mock()
# Test that second occurrence of exception is handled.
mock_package.requirements.return_value =\
{'foo': mock.Mock(), 'bar': mock.Mock()}
expected_error_message = 'Uploading package failed. {0}'.format('')
mock_api.muranoclient().packages.create.side_effect = [
mock.Mock(id='test_package_id'), Exception
]
self.import_pkg_wizard.process_step(mock_form)
mock_log.exception.assert_called_once_with(expected_error_message)
mock_exc.handle.assert_called_once_with(
self.mock_request, expected_error_message,
redirect='test_redirect')
mock_reverse.assert_called_once_with(
'horizon:app-catalog:packages:index')
@mock.patch.object(views, 'exceptions')
@mock.patch.object(views, 'messages')
@mock.patch.object(views, 'reverse')
@mock.patch.object(views, 'LOG')
@mock.patch.object(views, 'api')
@mock.patch.object(views, 'muranoclient_utils')
@mock.patch.object(views, 'glance')
def test_process_step_except_http_conflict(
self, mock_glance, mock_murano_utils, mock_api, mock_log,
mock_reverse, mock_messages, mock_exc):
mock_murano_utils.Package.from_file.side_effect = None
mock_reverse.return_value = 'test_redirect'
mock_form = mock.Mock()
mock_form.cleaned_data = {
'import_type': 'upload',
'package': mock.Mock(file='test_package_file')
}
mock_form.data = {
'dependencies': [],
'images': []
}
# Test that first occurrence of HTTPConflict is caught.
mock_package = mock.Mock()
mock_package.manifest = {'FullName': 'foo'}
mock_package.requirements.return_value =\
{'foo': mock.Mock(), 'bar': mock.Mock()}
mock_murano_utils.Package.from_file.return_value = mock_package
expected_error_message = "Package bar already registered."
mock_api.muranoclient().packages.create.side_effect = [
exc.HTTPConflict, None
]
self.import_pkg_wizard.process_step(mock_form)
mock_log.exception.assert_any_call(expected_error_message)
mock_messages.warning.assert_called_once_with(
self.mock_request, expected_error_message)
mock_log.exception.reset_mock()
mock_messages.warning.reset_mock()
# Test that second occurrence of HTTPConflict is caught.
mock_package.requirements.return_value =\
{'foo': mock.Mock(), 'bar': mock.Mock()}
mock_murano_utils.Package.from_file.return_value = mock_package
expected_error_message = _(
"Package with specified name already exists")
mock_api.muranoclient().packages.create.side_effect = [
None, exc.HTTPConflict
]
self.import_pkg_wizard.process_step(mock_form)
mock_log.exception.assert_any_call(expected_error_message)
mock_exc.handle.assert_any_call(
self.mock_request, expected_error_message,
redirect='test_redirect')
@mock.patch.object(views, 'exceptions')
@mock.patch.object(views, 'reverse')
@mock.patch.object(views, 'LOG')
@mock.patch.object(views, 'api')
@mock.patch.object(views, 'muranoclient_utils')
@mock.patch.object(views, 'glance')
def test_process_step_except_http_internal_server_error(
self, mock_glance, mock_murano_utils, mock_api, mock_log,
mock_reverse, mock_exc):
mock_murano_utils.Package.from_file.side_effect = None
mock_reverse.return_value = 'test_redirect'
mock_package = mock.Mock()
mock_package.manifest = {'FullName': 'foo'}
mock_package.requirements.return_value =\
{'foo': mock.Mock(), 'bar': mock.Mock()}
mock_murano_utils.Package.from_file.return_value = mock_package
mock_form = mock.Mock()
mock_form.cleaned_data = {
'import_type': 'upload',
'package': mock.Mock(file='test_package_file')
}
mock_form.data = {
'dependencies': [],
'images': []
}
expected_error_message = "Uploading package failed. {0}"\
.format('test_500_error_message')
exception = exc.HTTPInternalServerError(
details='{"error": {"message": "test_500_error_message"}}')
mock_api.muranoclient().packages.create.side_effect = [
mock.Mock(id='test_package_id'), exception
]
self.import_pkg_wizard.process_step(mock_form)
mock_log.exception.assert_called_once_with(expected_error_message)
mock_exc.handle.assert_called_once_with(
self.mock_request, expected_error_message,
redirect='test_redirect')
mock_reverse.assert_called_once_with(
'horizon:app-catalog:packages:index')
@mock.patch.object(views, 'exceptions')
@mock.patch.object(views, 'reverse')
@mock.patch.object(views, 'muranodashboard_utils')
@mock.patch.object(views, 'LOG')
@mock.patch.object(views, 'api')
@mock.patch.object(views, 'muranoclient_utils')
@mock.patch.object(views, 'glance')
def test_process_step_except_http_exception(
self, mock_glance, mock_murano_utils, mock_api, mock_log,
mock_dashboard_utils, mock_reverse, mock_exc):
mock_murano_utils.Package.from_file.side_effect = None
mock_reverse.return_value = 'test_redirect'
mock_package = mock.Mock()
mock_package.manifest = {'FullName': 'foo'}
mock_package.requirements.return_value =\
{'foo': mock.Mock(), 'bar': mock.Mock()}
mock_murano_utils.Package.from_file.return_value = mock_package
mock_dashboard_utils.parse_api_error.return_value = 'test_reason'
mock_form = mock.Mock()
mock_form.cleaned_data = {
'import_type': 'upload',
'package': mock.Mock(file='test_package_file')
}
mock_form.data = {
'dependencies': [],
'images': []
}
exception = exc.HTTPException(
details='{"error": {"message": "test_error_message"}}')
mock_api.muranoclient().packages.create.side_effect = [
mock.Mock(id='test_package_id'), exception
]
self.import_pkg_wizard.process_step(mock_form)
mock_log.exception.assert_any_call('test_reason')
mock_exc.handle.assert_called_once_with(
self.mock_request, 'test_reason', redirect='test_redirect')
mock_reverse.assert_called_once_with(
'horizon:app-catalog:packages:index')
def test_get_form_kwargs(self):
kwargs = self.import_pkg_wizard.get_form_kwargs('add_category')
self.assertEqual({'request': self.mock_request}, kwargs)
mock_storage = mock.Mock()
mock_storage.get_step_data().get.return_value = 'test_package'
self.import_pkg_wizard.storage = mock_storage
kwargs = self.import_pkg_wizard.get_form_kwargs('modify')
self.assertEqual({'request': self.mock_request,
'package': 'test_package'}, kwargs)
class TestImportBundleWizard(helpers.APITestCase):
def setUp(self):
super(TestImportBundleWizard, self).setUp()
fake_response = {'status_code': 200}
self.mock_request = mock.MagicMock(
name='mock_request', return_value=fake_response, META=[])
self.import_bundle_wizard = views.ImportBundleWizard()
self.import_bundle_wizard.request = self.mock_request
self.import_bundle_wizard.storage = mock.Mock(
name='mock_storage', extra_data={'foo': 'bar'})
self.import_bundle_wizard.steps = mock.Mock(name='mock_steps')
self.import_bundle_wizard.steps.current = 'upload'
self.import_bundle_wizard.prefix = 'test_prefix'
self.import_bundle_wizard.initial_dict = {'upload': {'foo': 'bar'}}
self.import_bundle_wizard.get_form_step_data =\
lambda f: 'test_step_form_data'
self.assertEqual('packages/import_bundle.html',
self.import_bundle_wizard.template_name)
self.assertEqual('Import Bundle',
self.import_bundle_wizard.page_title)
self.addCleanup(mock.patch.stopall)
def test_get_context_data(self):
mock_form = mock.Mock(initial={'package': mock.Mock(type='test_type')})
context = self.import_bundle_wizard.get_context_data(form=mock_form)
expected_instances = {
'view': views.ImportBundleWizard,
'wizard': dict
}
expected_context = {
'foo': 'bar',
'form': mock.ANY,
'hide': True,
'modal_backdrop': 'static',
'murano_repo_url': 'http://apps.openstack.org',
'view': mock.ANY,
'wizard': mock.ANY
}
for key, val in expected_context.items():
self.assertIn(key, context)
self.assertEqual(val, context[key])
for key, val in expected_instances.items():
self.assertIsInstance(context[key], val)
def test_get_form_initial(self):
self.import_bundle_wizard.request.GET = {
'url': 'test_url', 'name': 'test_name',
'import_type': 'test_import_type'
}
initial_dict = self.import_bundle_wizard.get_form_initial('upload')
expected_dict = {
'foo': 'bar',
'url': 'test_url',
'name': 'test_name',
'import_type': 'test_import_type'
}
for key, val in expected_dict.items():
self.assertIn(key, initial_dict)
self.assertEqual(val, initial_dict[key])
@mock.patch.object(views, 'api')
@mock.patch.object(views, 'muranoclient_utils')
@mock.patch.object(views, 'glance')
def test_process_step(self, mock_glance, mock_murano_utils, mock_api):
mock_bundle = mock.Mock()
mock_bundle.package_specs.return_value = [
{'Name': 'foo_spec', 'Version': '1.0.0', 'Url': 'www.foo.com'},
{'Name': 'bar_spec', 'Version': '2.0.0', 'Url': 'www.bar.com'}
]
mock_package = mock.Mock()
mock_foo_dependency = mock.Mock(name='foo_package')
mock_bar_dependency = mock.Mock(name='bar_package')
mock_package.requirements.return_value = {
'foo_package': mock_foo_dependency,
'bar_package': mock_bar_dependency
}
mock_murano_utils.to_url.return_value = 'test_url'
mock_form = mock.Mock()
for import_type in ('by_url', 'by_name'):
mock_form.cleaned_data = {
'import_type': import_type,
'url': 'test_url',
'name': 'test_form_name'
}
mock_murano_utils.Bundle.from_file.return_value = mock_bundle
mock_murano_utils.Package.from_location.return_value = mock_package
step_data = self.import_bundle_wizard.process_step(mock_form)
self.assertEqual('test_step_form_data', step_data)
mock_murano_utils.Bundle.from_file.assert_called_once_with(
'test_url')
mock_murano_utils.Package.from_location.assert_any_call(
'foo_spec', version='1.0.0', url='www.foo.com',
base_url=packages_consts.MURANO_REPO_URL, path=None
)
mock_murano_utils.Package.from_location.assert_any_call(
'bar_spec', version='2.0.0', url='www.bar.com',
base_url=packages_consts.MURANO_REPO_URL, path=None
)
mock_api.muranoclient().packages.create.assert_any_call(
{}, {'foo_package': mock_foo_dependency.file()})
mock_api.muranoclient().packages.create.assert_any_call(
{}, {'bar_package': mock_bar_dependency.file()})
mock_murano_utils.reset_mock()
mock_api.reset_mock()
@mock.patch.object(views, 'reverse')
@mock.patch.object(views, 'messages')
@mock.patch.object(views, 'LOG')
@mock.patch.object(views, 'muranoclient_utils')
def test_process_step_except_from_file_exception(
self, mock_murano_utils, mock_log, mock_messages, mock_reverse):
mock_reverse.return_value = 'test_redirect'
mock_form = mock.Mock(
cleaned_data={'import_type': 'by_url', 'url': 'foo_url'})
e_404 = Exception('(404)')
e_404.message = '(404)'
e = Exception('foo')
e.message = 'foo'
errors = ((e_404, "Bundle creation failed.Reason: Can't find Bundle "
"name from repository."),
(e, "Bundle creation failed.Reason: foo"))
for exception, expected_error_message in errors:
mock_murano_utils.Bundle.from_file.side_effect = exception
with self.assertRaisesRegex(horizon_exceptions.Http302, None):
self.import_bundle_wizard.process_step(mock_form)
mock_log.exception.assert_called_once_with(expected_error_message)
mock_messages.error.assert_called_once_with(
self.mock_request, expected_error_message)
mock_reverse.assert_called_once_with(
'horizon:app-catalog:packages:index')
for mock_ in (mock_log, mock_messages, mock_reverse):
mock_.reset_mock()
@mock.patch.object(views, 'messages')
@mock.patch.object(views, 'LOG')
@mock.patch.object(views, 'muranoclient_utils')
def test_process_step_except_from_location_exception(
self, mock_murano_utils, mock_log, mock_messages):
mock_form = mock.Mock(
cleaned_data={'import_type': 'by_url', 'url': 'foo_url'})
mock_bundle = mock.Mock()
mock_bundle.package_specs.return_value = [
{'Name': 'foo_spec', 'Version': '1.0.0', 'Url': 'www.foo.com'},
{'Name': 'bar_spec', 'Version': '2.0.0', 'Url': 'www.bar.com'}
]
mock_murano_utils.Bundle.from_file.return_value = mock_bundle
mock_murano_utils.Package.from_location.side_effect = Exception('foo')
self.import_bundle_wizard.process_step(mock_form)
for spec in ('foo_spec', 'bar_spec'):
expected_error_message = 'Error foo occurred while parsing '\
'package {0}'.format(spec)
mock_log.exception.assert_any_call(expected_error_message)
mock_messages.error.assert_any_call(
self.mock_request, expected_error_message)
@mock.patch.object(views, 'messages')
@mock.patch.object(views, 'LOG')
@mock.patch.object(views, 'api')
@mock.patch.object(views, 'muranoclient_utils')
@mock.patch.object(views, 'glance')
def test_process_step_except_http_conflict(
self, mock_glance, mock_murano_utils, mock_api, mock_log,
mock_messages):
mock_form = mock.Mock(
cleaned_data={'import_type': 'by_url', 'url': 'foo_url'})
mock_bundle = mock.Mock()
mock_bundle.package_specs.return_value = [
{'Name': 'foo_spec', 'Version': '1.0.0', 'Url': 'www.foo.com'},
{'Name': 'bar_spec', 'Version': '2.0.0', 'Url': 'www.bar.com'}
]
mock_foo_dependency = mock.Mock(name='foo_package')
mock_bar_dependency = mock.Mock(name='bar_package')
mock_package = mock.Mock()
mock_package.requirements.return_value = {
'foo_package': mock_foo_dependency,
'bar_package': mock_bar_dependency
}
mock_murano_utils.Bundle.from_file.return_value = mock_bundle
mock_murano_utils.Package.from_location.return_value = mock_package
mock_api.muranoclient().packages.create.side_effect = exc.HTTPConflict
self.import_bundle_wizard.process_step(mock_form)
for dep in ('foo_package', 'bar_package'):
expected_error_message = 'Package {0} already registered.'\
.format(dep)
mock_log.exception.assert_any_call(expected_error_message)
mock_messages.warning.assert_any_call(
self.mock_request, expected_error_message)
@mock.patch.object(views, 'messages')
@mock.patch.object(views, 'LOG')
@mock.patch.object(views, 'api')
@mock.patch.object(views, 'muranodashboard_utils')
@mock.patch.object(views, 'muranoclient_utils')
@mock.patch.object(views, 'glance')
def test_process_step_except_http_exception(
self, mock_glance, mock_murano_utils, mock_dashboard_utils,
mock_api, mock_log, mock_messages):
mock_form = mock.Mock(
cleaned_data={'import_type': 'by_url', 'url': 'foo_url'})
mock_bundle = mock.Mock()
mock_bundle.package_specs.return_value = [
{'Name': 'foo_spec', 'Version': '1.0.0', 'Url': 'www.foo.com'},
{'Name': 'bar_spec', 'Version': '2.0.0', 'Url': 'www.bar.com'}
]
mock_foo_dependency = mock.Mock(name='foo_package')
mock_bar_dependency = mock.Mock(name='bar_package')
mock_package = mock.Mock()
mock_package.requirements.return_value = {
'foo_package': mock_foo_dependency,
'bar_package': mock_bar_dependency
}
mock_murano_utils.Bundle.from_file.return_value = mock_bundle
mock_murano_utils.Package.from_location.return_value = mock_package
mock_api.muranoclient().packages.create.side_effect =\
exc.HTTPException('foo')
mock_dashboard_utils.parse_api_error.return_value = 'foo'
self.import_bundle_wizard.process_step(mock_form)
for dep in ('foo_package', 'bar_package'):
expected_error_message = 'Package {0} upload failed. foo'\
.format(dep)
mock_log.exception.assert_any_call(expected_error_message)
mock_messages.warning.assert_any_call(
self.mock_request, expected_error_message)
@mock.patch.object(views, 'messages')
@mock.patch.object(views, 'LOG')
@mock.patch.object(views, 'api')
@mock.patch.object(views, 'muranoclient_utils')
@mock.patch.object(views, 'glance')
def test_process_step_except_package_create_exception(
self, mock_glance, mock_murano_utils, mock_api, mock_log,
mock_messages):
mock_form = mock.Mock(
cleaned_data={'import_type': 'by_url', 'url': 'foo_url'})
mock_bundle = mock.Mock()
mock_bundle.package_specs.return_value = [
{'Name': 'foo_spec', 'Version': '1.0.0', 'Url': 'www.foo.com'},
{'Name': 'bar_spec', 'Version': '2.0.0', 'Url': 'www.bar.com'}
]
mock_foo_dependency = mock.Mock(name='foo_package')
mock_bar_dependency = mock.Mock(name='bar_package')
mock_package = mock.Mock()
mock_package.requirements.return_value = {
'foo_package': mock_foo_dependency,
'bar_package': mock_bar_dependency
}
mock_murano_utils.Bundle.from_file.return_value = mock_bundle
mock_murano_utils.Package.from_location.return_value = mock_package
mock_api.muranoclient().packages.create.side_effect =\
Exception('foo')
self.import_bundle_wizard.process_step(mock_form)
for dep in ('foo_package', 'bar_package'):
expected_error_message = 'Importing package {0} failed. '\
'Reason: foo'.format(dep)
mock_log.exception.assert_any_call(expected_error_message)
mock_messages.warning.assert_any_call(
self.mock_request, expected_error_message)
@mock.patch.object(views, 'messages')
@mock.patch.object(views, 'LOG')
@mock.patch.object(views, 'reverse')
def test_done(self, mock_reverse, mock_log, mock_messages):
mock_reverse.redirect = 'test_redirect'
result = self.import_bundle_wizard.done([])
self.assertIsInstance(result, http.response.HttpResponseRedirect)
expected_message = 'Bundle successfully imported.'
mock_log.info.assert_any_call(expected_message)
mock_messages.success.assert_called_once_with(
self.mock_request, expected_message)
mock_reverse.assert_called_once_with(
'horizon:app-catalog:packages:index')
class TestPackageDefinitionsView(helpers.APITestCase):
def setUp(self):
super(TestPackageDefinitionsView, self).setUp()
self.pkg_definitions_view = views.PackageDefinitionsView()
mock_token = mock.MagicMock()
mock_token.__getitem__.return_value = 'foo_token_id'
self.mock_request = mock.MagicMock(
name='mock_request', GET={'sort_dir': 'asc'},
session={'token': mock_token})
self.pkg_definitions_view.request = self.mock_request
self.original_get_filters = self.pkg_definitions_view.get_filters
self.pkg_definitions_view.get_filters = lambda opts: opts
self.assertEqual(self.pkg_definitions_view.table_class,
tables.PackageDefinitionsTable)
self.assertEqual(self.pkg_definitions_view.template_name,
'packages/index.html')
self.assertEqual(self.pkg_definitions_view.page_title, 'Packages')
self.assertFalse(self.pkg_definitions_view.has_more_data(None))
self.assertFalse(self.pkg_definitions_view.has_prev_data(None))
mock_horizon_utils = mock.patch.object(views, 'utils').start()
mock_horizon_utils.get_page_size.return_value = 123
self.addCleanup(mock.patch.stopall)
@mock.patch.object(views, 'pkg_api')
def test_get_data_with_same_tenants(self, mock_pkg_api):
mock_package = mock.Mock(
id='foo_package', owner_id='test_tenant', tenant_name=None)
mock_pkg_api.package_list.return_value =\
([mock_package], True)
mock_tenant = mock.MagicMock()
mock_tenant.__getitem__.side_effect = [
'test_tenant', 'foo_tenant_name'
]
self.pkg_definitions_view.request.user.is_superuser = False
self.pkg_definitions_view.request.session['token'] =\
mock.Mock(tenant=mock_tenant)
packages = self.pkg_definitions_view.get_data()
self.assertEqual([mock_package], packages)
self.assertEqual('foo_tenant_name', mock_package.tenant_name)
self.assertTrue(self.pkg_definitions_view.has_prev_data)
mock_pkg_api.package_list.assert_any_call(
self.mock_request, marker=None,
filters={'include_disabled': True, 'sort_dir': 'desc'},
paginate=True, page_size=123)
mock_pkg_api.package_list.assert_any_call(
self.mock_request, marker='foo_package',
filters={'include_disabled': True, 'sort_dir': 'desc'},
paginate=True, page_size=0)
@mock.patch.object(views, 'pkg_api')
def test_get_data_with_different_tenants(self, mock_pkg_api):
mock_package = mock.Mock(id='foo_package', tenant_name='test_tenant')
mock_pkg_api.package_list.return_value =\
([mock_package], True)
self.pkg_definitions_view.request.user.is_superuser = False
self.pkg_definitions_view.request.session['token'] =\
mock.MagicMock(__getitem__='alt_test_tenant')
packages = self.pkg_definitions_view.get_data()
self.assertEqual([mock_package], packages)
self.assertEqual('UNKNOWN', mock_package.tenant_name)
self.assertTrue(self.pkg_definitions_view.has_prev_data)
mock_pkg_api.package_list.assert_any_call(
self.mock_request, marker=None,
filters={'include_disabled': True, 'sort_dir': 'desc'},
paginate=True, page_size=123)
mock_pkg_api.package_list.assert_any_call(
self.mock_request, marker='foo_package',
filters={'include_disabled': True, 'sort_dir': 'desc'},
paginate=True, page_size=0)
@mock.patch.object(views, 'keystone')
@mock.patch.object(views, 'pkg_api')
def test_get_data_as_superuser(self, mock_pkg_api, mock_keystone):
mock_keystone.tenant_list.side_effect = None
super_user_tenant = mock.Mock(id='super_tenant_id')
super_user_tenant.configure_mock(name='super_tenant_name')
mock_keystone.tenant_list.return_value = ([super_user_tenant], False)
mock_package = mock.Mock(
id='foo_package', owner_id='super_tenant_id', tenant_name=None)
mock_pkg_api.package_list.return_value =\
([mock_package], True)
mock_tenant = mock.MagicMock()
mock_tenant.__getitem__.side_effect = [
'test_tenant', 'foo_tenant_name'
]
self.pkg_definitions_view.request.user.is_superuser = True
self.pkg_definitions_view.request.session['token'] =\
mock.Mock(tenant=mock_tenant)
packages = self.pkg_definitions_view.get_data()
self.assertEqual([mock_package], packages)
self.assertEqual('super_tenant_name', mock_package.tenant_name)
self.assertTrue(self.pkg_definitions_view.has_more_data)
@mock.patch.object(views, 'exceptions')
@mock.patch.object(views, 'keystone')
@mock.patch.object(views, 'pkg_api')
def test_get_data_except_keystone_exception(self, mock_pkg_api,
mock_keystone, mock_exc):
mock_keystone.tenant_list.side_effect = Exception
super_user_tenant = mock.Mock(id='super_tenant_id')
super_user_tenant.configure_mock(name='super_tenant_name')
mock_keystone.tenant_list.return_value = ([super_user_tenant], False)
mock_package = mock.Mock(
id='foo_package', owner_id='super_tenant_id', tenant_name=None)
mock_pkg_api.package_list.return_value =\
([mock_package], True)
mock_tenant = mock.MagicMock()
mock_tenant.__getitem__.side_effect = [
'test_tenant', 'foo_tenant_name'
]
self.pkg_definitions_view.request.user.is_superuser = True
self.pkg_definitions_view.request.session['token'] =\
mock.Mock(tenant=mock_tenant)
packages = self.pkg_definitions_view.get_data()
self.assertEqual([mock_package], packages)
self.assertIsNone(mock_package.tenant_name)
self.assertTrue(self.pkg_definitions_view.has_more_data)
mock_exc.handle.assert_called_once_with(
self.mock_request, "Unable to retrieve project list.")
@mock.patch.object(views, 'pkg_api')
def test_get_data_desc_order(self, mock_pkg_api):
mock_package = mock.Mock(
id='foo_package', owner_id='test_tenant', tenant_name=None)
mock_pkg_api.package_list.return_value =\
([mock_package], True)
mock_tenant = mock.MagicMock()
mock_tenant.__getitem__.side_effect = [
'test_tenant', 'foo_tenant_name'
]
self.pkg_definitions_view.request.GET = {'sort_dir': 'desc'}
self.pkg_definitions_view.request.user.is_superuser = False
self.pkg_definitions_view.request.session['token'] =\
mock.Mock(tenant=mock_tenant)
packages = self.pkg_definitions_view.get_data()
self.assertEqual([mock_package], packages)
self.assertEqual('foo_tenant_name', mock_package.tenant_name)
self.assertTrue(self.pkg_definitions_view.has_more_data)
mock_pkg_api.package_list.assert_any_call(
self.mock_request, marker=None,
filters={'include_disabled': True, 'sort_dir': 'asc'},
paginate=True, page_size=123)
mock_pkg_api.package_list.assert_any_call(
self.mock_request, marker='foo_package',
filters={'include_disabled': True, 'sort_dir': 'asc'},
paginate=True, page_size=0)
def test_get_context_data(self):
mock_form = mock.Mock(initial={'package': mock.Mock(type='test_type')})
self.pkg_definitions_view.table = 'foo_table'
context = self.pkg_definitions_view.get_context_data(form=mock_form)
expected_context = {
'table': 'foo_table',
'tenant_id': mock.ANY,
'packages_table': 'foo_table',
'form': mock.ANY,
'view': mock.ANY
}
for key, val in expected_context.items():
self.assertEqual(val, context[key])
self.assertIsInstance(context['view'], views.PackageDefinitionsView)
def test_get_filters(self):
mock_filter_action = mock.Mock()
mock_filter_action.is_api_filter.return_value = True
self.pkg_definitions_view.table = mock.Mock()
self.pkg_definitions_view.table._meta_._filter_action =\
mock_filter_action
self.pkg_definitions_view.table.get_filter_field.return_value =\
'test_filter_field'
self.pkg_definitions_view.table.get_filter_string.return_value =\
'test_filter_string'
self.pkg_definitions_view.get_filters = self.original_get_filters
test_filters = {'foo': 'bar'}
filters = self.pkg_definitions_view.get_filters(test_filters)
expected_filters = {
'test_filter_field': 'test_filter_string',
'foo': 'bar'
}
for key, val in expected_filters.items():
self.assertEqual(val, filters[key])