906 lines
35 KiB
Python
906 lines
35 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 import exceptions
|
|
from django.core import validators as django_validator
|
|
from django import forms
|
|
from django.utils.translation import ugettext_lazy as _
|
|
|
|
import mock
|
|
import testtools
|
|
|
|
from muranodashboard.dynamic_ui import fields
|
|
|
|
|
|
class TestFields(testtools.TestCase):
|
|
|
|
def setUp(self):
|
|
super(TestFields, self).setUp()
|
|
self.request = {'request': mock.Mock()}
|
|
self.addCleanup(mock.patch.stopall)
|
|
|
|
@mock.patch.object(fields, 'LOG')
|
|
def test_fields_with_initial_request(self, mock_log):
|
|
test_initial = {
|
|
'request': 'foo_request',
|
|
'foo': 'bar'
|
|
}
|
|
self._test_fields_decorator_with_initial_request(test_initial)
|
|
mock_log.debug.assert_called_once_with(
|
|
"Using 'request' value from initial dictionary")
|
|
|
|
@fields.with_request
|
|
def _test_fields_decorator_with_initial_request(self, request, **kwargs):
|
|
self.assertEqual('foo_request', request)
|
|
self.assertEqual({'foo': 'bar'}, kwargs)
|
|
|
|
@mock.patch.object(fields, 'LOG')
|
|
def test_fields_with_request(self, mock_log):
|
|
test_request = {
|
|
'foo': 'bar'
|
|
}
|
|
self._test_fields_decorator_with_request({}, request=test_request)
|
|
mock_log.debug.assert_called_once_with("Using direct 'request' value")
|
|
|
|
@fields.with_request
|
|
def _test_fields_decorator_with_request(self, request, **kwargs):
|
|
self.assertEqual({'foo': 'bar'}, request)
|
|
self.assertEqual({}, kwargs)
|
|
|
|
@mock.patch.object(fields, 'LOG')
|
|
def test_fields_except_validation_error(self, mock_log):
|
|
with self.assertRaisesRegexp(forms.ValidationError,
|
|
"Can't get a request information"):
|
|
self._test_fields_decorator_with_validation_error({}, request=None)
|
|
mock_log.error.assert_called_once_with(
|
|
"No 'request' value passed neither via initial dictionary, nor "
|
|
"directly")
|
|
|
|
@fields.with_request
|
|
def _test_fields_decorator_with_validation_error(self, request, **kwargs):
|
|
pass
|
|
|
|
def test_make_yaql_validator(self):
|
|
mock_validator_property = mock.MagicMock()
|
|
mock_validator_property.__getitem__().spec.evaluate.return_value = True
|
|
mock_validator_property.get.return_value = 'foo_message'
|
|
|
|
validator_func = fields.make_yaql_validator(mock_validator_property)
|
|
self.assertTrue(hasattr(validator_func, '__call__'))
|
|
validator_func('bar')
|
|
mock_validator_property.__getitem__().spec.evaluate.\
|
|
assert_called_once_with(context=mock.ANY)
|
|
|
|
def test_make_yaql_validator_except_validation_error(self):
|
|
mock_validator_property = mock.MagicMock()
|
|
mock_validator_property.__getitem__().spec.evaluate.return_value =\
|
|
False
|
|
mock_validator_property.get.return_value = 'foo_message'
|
|
|
|
validator_func = fields.make_yaql_validator(mock_validator_property)
|
|
self.assertTrue(hasattr(validator_func, '__call__'))
|
|
e = self.assertRaises(forms.ValidationError, validator_func, 'bar')
|
|
self.assertEqual('foo_message', e.message)
|
|
|
|
def test_get_regex_validator(self):
|
|
validator = django_validator.RegexValidator()
|
|
test_expr = {
|
|
'validators': [
|
|
validator
|
|
]
|
|
}
|
|
result = fields.get_regex_validator(test_expr)
|
|
self.assertEqual(validator, result)
|
|
|
|
def test_get_regex_validator_except_error(self):
|
|
for error in (TypeError, KeyError, IndexError):
|
|
mock_expr = mock.MagicMock()
|
|
mock_expr.__getitem__.side_effect = error
|
|
result = fields.get_regex_validator(mock_expr)
|
|
self.assertIsNone(result)
|
|
|
|
def test_wrap_regex_validator(self):
|
|
def _validator(value):
|
|
pass
|
|
|
|
func = fields.wrap_regex_validator(_validator, None)
|
|
func(None)
|
|
self.assertTrue(hasattr(func, '__call__'))
|
|
|
|
def test_wrap_regex_validator_except_validation_error(self):
|
|
def _validator(value):
|
|
raise forms.ValidationError(None)
|
|
|
|
with self.assertRaisesRegexp(forms.ValidationError, 'foo'):
|
|
func = fields.wrap_regex_validator(_validator, 'foo')
|
|
func(None)
|
|
|
|
@mock.patch.object(fields, 'glance')
|
|
def test_get_murano_images(self, mock_glance):
|
|
foo_image = mock.Mock(murano_property=None)
|
|
foo_image.murano_image_info = '{"foo": "foo_val"}'
|
|
bar_image = mock.Mock(murano_property=None)
|
|
bar_image.murano_image_info = '{"bar": "bar_val"}'
|
|
mock_glance.image_list_detailed.return_value = [
|
|
[foo_image, bar_image], None
|
|
]
|
|
|
|
murano_images = fields.get_murano_images(self.request)
|
|
mock_glance.image_list_detailed.assert_called_once_with(self.request)
|
|
self.assertEqual({"foo": "foo_val"}, foo_image.murano_property)
|
|
self.assertEqual({"bar": "bar_val"}, bar_image.murano_property)
|
|
|
|
expected_images = []
|
|
foo_image.murano_property = {"foo": "foo_val"}
|
|
bar_image.murano_property = {"bar": "bar_val"}
|
|
expected_images.extend([foo_image, bar_image])
|
|
|
|
self.assertEqual(expected_images, murano_images)
|
|
|
|
@mock.patch.object(fields, 'exceptions')
|
|
@mock.patch.object(fields, 'LOG')
|
|
@mock.patch.object(fields, 'glance')
|
|
def test_murano_images_except_exception(self, mock_glance, mock_log,
|
|
mock_exceptions):
|
|
mock_glance.image_list_detailed.side_effect = Exception
|
|
|
|
murano_images = fields.get_murano_images(self.request)
|
|
|
|
self.assertEqual([], murano_images)
|
|
self.assertTrue(mock_log.error.called)
|
|
mock_exceptions.handle.assert_called_once_with(
|
|
self.request, _("Unable to retrieve public images."))
|
|
|
|
@mock.patch.object(fields, 'messages')
|
|
@mock.patch.object(fields, 'LOG')
|
|
@mock.patch.object(fields, 'glance')
|
|
def test_murano_images_except_value_error(self, mock_glance, mock_log,
|
|
mock_messages):
|
|
foo_image = mock.Mock(murano_property=None)
|
|
foo_image.murano_image_info = "{'foo': 'foo_val'}"
|
|
mock_glance.image_list_detailed.return_value = [
|
|
[foo_image], None
|
|
]
|
|
|
|
murano_images = fields.get_murano_images(self.request)
|
|
|
|
self.assertEqual([], murano_images)
|
|
mock_log.warning.assert_called_once_with(
|
|
"JSON in image metadata is not valid. Check it in glance.")
|
|
mock_messages.error.assert_called_once_with(
|
|
self.request, _("Invalid murano image metadata"))
|
|
|
|
def test_choice_get_title(self):
|
|
choice = fields.Choice('test_title', True)
|
|
self.assertEqual('test_title', fields._get_title(choice))
|
|
self.assertIsNone(fields._get_title(None))
|
|
|
|
def test_choice_disable_non_ready(self):
|
|
choice = fields.Choice('test_title', True)
|
|
self.assertEqual({}, fields._disable_non_ready(choice))
|
|
choice = fields.Choice('test_title', False)
|
|
self.assertEqual({'disabled': 'disabled'},
|
|
fields._disable_non_ready(choice))
|
|
|
|
@mock.patch.object(fields, 'env_api')
|
|
@mock.patch.object(fields, 'pkg_api')
|
|
def test_make_select_cls_update(self, mock_pkg_api, mock_env_api):
|
|
mock_pkg_api.app_by_fqn.return_value =\
|
|
mock.Mock(fully_qualified_name='foo_class_fqn')
|
|
mock_pkg_api.apps_that_inherit.return_value = [
|
|
mock.Mock(fully_qualified_name='foo_class_fqn'),
|
|
mock.Mock(fully_qualified_name='bar_class_fqn')
|
|
]
|
|
expected_choices = [
|
|
('', 'Foo'), ('foo_app_id', 'foo_app_name'),
|
|
('bar_app_id', 'bar_app_name')
|
|
]
|
|
|
|
foo_app = mock.MagicMock()
|
|
foo_app.__getitem__.return_value = {'id': 'foo_app_id'}
|
|
foo_app.configure_mock(name='foo_app_name')
|
|
bar_app = mock.MagicMock()
|
|
bar_app.__getitem__.return_value = {'id': 'bar_app_id'}
|
|
bar_app.configure_mock(name='bar_app_name')
|
|
mock_env_api.service_list_by_fqns.return_value = [foo_app, bar_app]
|
|
|
|
dynamic_select_cls = fields.make_select_cls('foo_class_fqn')
|
|
self.assertIsNotNone(dynamic_select_cls)
|
|
self.assertEqual('DynamicSelect', dynamic_select_cls.__name__)
|
|
|
|
dynamic_select = dynamic_select_cls(empty_value_message='Foo')
|
|
dynamic_select.update(self.request, environment_id='foo_env_id')
|
|
|
|
self.assertTrue(
|
|
hasattr(dynamic_select.widget.add_item_link, '__call__'))
|
|
self.assertEqual(expected_choices, dynamic_select.choices)
|
|
self.assertIsNone(dynamic_select.initial)
|
|
|
|
mock_pkg_api.app_by_fqn.assert_called_once_with(
|
|
self.request['request'], 'foo_class_fqn')
|
|
mock_env_api.service_list_by_fqns.assert_called_once_with(
|
|
self.request['request'], 'foo_env_id',
|
|
['foo_class_fqn', 'bar_class_fqn']
|
|
)
|
|
|
|
@mock.patch.object(fields, 'env_api')
|
|
@mock.patch.object(fields, 'pkg_api')
|
|
def test_make_select_cls_update_2_choices(self, mock_pkg_api,
|
|
mock_env_api):
|
|
mock_pkg_api.app_by_fqn.return_value =\
|
|
mock.Mock(fully_qualified_name='foo_class_fqn')
|
|
mock_pkg_api.apps_that_inherit.return_value = []
|
|
expected_choices = [
|
|
('', 'Foo'), ('foo_app_id', 'foo_app_name')
|
|
]
|
|
|
|
foo_app = mock.MagicMock()
|
|
foo_app.__getitem__.return_value = {'id': 'foo_app_id'}
|
|
foo_app.configure_mock(name='foo_app_name')
|
|
mock_env_api.service_list_by_fqns.return_value = [foo_app]
|
|
|
|
dynamic_select_cls = fields.make_select_cls('foo_class_fqn')
|
|
dynamic_select = dynamic_select_cls(empty_value_message='Foo')
|
|
dynamic_select.update(self.request, environment_id='foo_env_id')
|
|
|
|
self.assertEqual(expected_choices, dynamic_select.choices)
|
|
self.assertEqual('foo_app_id', dynamic_select.initial)
|
|
|
|
mock_pkg_api.app_by_fqn.assert_called_once_with(
|
|
self.request['request'], 'foo_class_fqn')
|
|
mock_env_api.service_list_by_fqns.assert_called_once_with(
|
|
self.request['request'], 'foo_env_id', ['foo_class_fqn']
|
|
)
|
|
|
|
@mock.patch.object(fields, 'env_api')
|
|
@mock.patch.object(fields, 'pkg_api')
|
|
def test_make_select_cls_update_no_matching_classes(self, mock_pkg_api,
|
|
mock_env_api):
|
|
mock_pkg_api.app_by_fqn.return_value = None
|
|
mock_pkg_api.apps_that_inherit.return_value = []
|
|
mock_env_api.service_list_by_fqns.return_value = []
|
|
expected_choices = [('', 'Foo')]
|
|
|
|
dynamic_select_cls = fields.make_select_cls('foo_class_fqn')
|
|
dynamic_select = dynamic_select_cls(empty_value_message='Foo')
|
|
dynamic_select.update(self.request, environment_id='foo_env_id')
|
|
|
|
self.assertEqual(expected_choices, dynamic_select.choices)
|
|
self.assertIsNone(dynamic_select.initial)
|
|
|
|
mock_pkg_api.app_by_fqn.assert_called_once_with(
|
|
self.request['request'], 'foo_class_fqn')
|
|
mock_env_api.service_list_by_fqns.assert_called_once_with(
|
|
self.request['request'], 'foo_env_id', [])
|
|
|
|
@mock.patch.object(fields, 'reverse')
|
|
@mock.patch.object(fields, 'env_api')
|
|
@mock.patch.object(fields, 'pkg_api')
|
|
def test_make_select_cls_update_make_link(self, mock_pkg_api, mock_env_api,
|
|
mock_reverse):
|
|
mock_pkg_api.app_by_fqn.return_value = None
|
|
mock_pkg_api.apps_that_inherit.return_value = []
|
|
mock_env_api.service_list_by_fqns.return_value = []
|
|
mock_reverse.return_value = 'foo_url'
|
|
|
|
dynamic_select_cls = fields.make_select_cls('foo_class_fqn')
|
|
dynamic_select = dynamic_select_cls(empty_value_message='Foo')
|
|
dynamic_select.update(self.request, environment_id='foo_env_id')
|
|
|
|
result = dynamic_select.widget.add_item_link()
|
|
self.assertEqual('', result)
|
|
|
|
mock_pkg = mock.Mock(fully_qualified_name='foo_class_fqn')
|
|
mock_pkg.configure_mock(name='foo_class_name')
|
|
mock_pkg_api.app_by_fqn.return_value = mock_pkg
|
|
dynamic_select.update(self.request, environment_id='foo_env_id')
|
|
|
|
result = dynamic_select.widget.add_item_link()
|
|
expected = '[["foo_class_name", "foo_url"]]'
|
|
self.assertEqual(expected, result)
|
|
|
|
@mock.patch.object(fields, 'env_api')
|
|
@mock.patch.object(fields, 'pkg_api')
|
|
def test_update_clean(self, mock_pkg_api, mock_env_api):
|
|
mock_pkg_api.app_by_fqn.return_value = None
|
|
mock_pkg_api.apps_that_inherit.return_value = []
|
|
mock_env_api.service_list_by_fqns.return_value = []
|
|
|
|
dynamic_select_cls = fields.make_select_cls('foo_class_fqn')
|
|
dynamic_select = dynamic_select_cls(empty_value_message='Foo')
|
|
dynamic_select.form = mock.Mock()
|
|
dynamic_select.required = False
|
|
dynamic_select.choices = [('value', '')]
|
|
|
|
self.assertEqual('value', dynamic_select.clean('value'))
|
|
|
|
|
|
class TestRawProperty(testtools.TestCase):
|
|
|
|
def test_finalize(self):
|
|
class Control(object):
|
|
def __init__(self):
|
|
self.value = None
|
|
|
|
@property
|
|
def prop(self):
|
|
return self.value
|
|
|
|
@prop.setter
|
|
def prop(self, value):
|
|
self.value = value
|
|
|
|
@prop.deleter
|
|
def prop(self):
|
|
delattr(self, 'value')
|
|
|
|
mock_service = mock.Mock()
|
|
mock_service.get_data.side_effect = ['foo_value']
|
|
|
|
raw_property = fields.RawProperty('prop', 'foo_spec')
|
|
props = raw_property.finalize(
|
|
'foo_form_name', mock_service, Control)
|
|
|
|
ctl = Control()
|
|
|
|
result = props.fget(ctl)
|
|
self.assertEqual('foo_value', result)
|
|
|
|
props.fset(ctl, 'bar_value')
|
|
self.assertEqual('bar_value', ctl.prop)
|
|
|
|
props.fdel(ctl)
|
|
self.assertNotIn('prop', ctl.__dict__)
|
|
|
|
|
|
class TestCustomPropertiesField(testtools.TestCase):
|
|
|
|
def setUp(self):
|
|
super(TestCustomPropertiesField, self).setUp()
|
|
|
|
test_validator_1 = mock.MagicMock(__call__=lambda: None)
|
|
test_validator_2 = {
|
|
'expr': {
|
|
'validators': [django_validator.RegexValidator()]
|
|
}
|
|
}
|
|
test_validator_3 = {
|
|
'expr': fields.RawProperty(None, None)
|
|
}
|
|
kwargs = {
|
|
'validators': [
|
|
test_validator_1, test_validator_2, test_validator_3
|
|
]
|
|
}
|
|
for arg in fields.FIELD_ARGS_TO_ESCAPE:
|
|
kwargs[arg] = 'foo_' + arg
|
|
|
|
custom_props_field = fields.CustomPropertiesField(**kwargs)
|
|
|
|
for arg in fields.FIELD_ARGS_TO_ESCAPE:
|
|
self.assertTrue(hasattr(custom_props_field, arg))
|
|
self.assertEqual('foo_{0}'.format(arg),
|
|
getattr(custom_props_field, arg))
|
|
self.assertEqual(3, len(custom_props_field.validators))
|
|
|
|
def test_clean(self):
|
|
mock_form = mock.Mock()
|
|
mock_form.cleaned_data = 'test_cleaned_data'
|
|
custom_props_field = fields.CustomPropertiesField()
|
|
custom_props_field.form = mock_form
|
|
|
|
custom_props_field.enabled = True
|
|
self.assertEqual('foo', custom_props_field.clean('foo'))
|
|
|
|
custom_props_field.enabled = False
|
|
self.assertEqual('foo', custom_props_field.clean('foo'))
|
|
|
|
def test_finalize_properties(self):
|
|
finalize_properties = fields.CustomPropertiesField.finalize_properties
|
|
kwargs = {
|
|
'foo_raw_property': fields.RawProperty('foo_key', 'foo_spec')
|
|
}
|
|
mock_service = mock.Mock()
|
|
|
|
result = finalize_properties(kwargs, 'foo_form_name', mock_service)
|
|
self.assertIsNotNone(result)
|
|
result = finalize_properties({}, 'foo_form_name', mock_service)
|
|
self.assertIsNotNone(result)
|
|
|
|
|
|
class TestPasswordField(testtools.TestCase):
|
|
|
|
def setUp(self):
|
|
super(TestPasswordField, self).setUp()
|
|
self.password_field = fields.PasswordField(None)
|
|
self.password_field.original = True
|
|
self.password_field.required = True
|
|
self.addCleanup(mock.patch.stopall)
|
|
|
|
def test_get_clone_name(self):
|
|
self.assertEqual('foo-clone',
|
|
fields.PasswordField.get_clone_name('foo'))
|
|
|
|
def test_compare(self):
|
|
test_form_data = {'name': 'foo', 'name-clone': 'foo'}
|
|
result = self.password_field.compare('name', test_form_data)
|
|
self.assertIsNone(result)
|
|
|
|
def test_compare_except_validation_error(self):
|
|
test_form_data = {'name': 'foo', 'name-clone': 'bar'}
|
|
self.assertRaises(forms.ValidationError, self.password_field.compare,
|
|
'name', test_form_data)
|
|
|
|
def test_deepcopy(self):
|
|
self.password_field.error_messages = None
|
|
test_memo = {}
|
|
result = self.password_field.__deepcopy__(test_memo)
|
|
self.assertIsInstance(result, fields.PasswordField)
|
|
self.assertGreater(len(test_memo.keys()), 0)
|
|
|
|
self.password_field.error_messages = ['foo_error', 'bar_error']
|
|
test_memo = {}
|
|
result = self.password_field.__deepcopy__(test_memo)
|
|
self.assertIsInstance(result, fields.PasswordField)
|
|
self.assertGreater(len(test_memo.keys()), 0)
|
|
self.assertEqual(['foo_error', 'bar_error'], result.error_messages)
|
|
|
|
def test_clone_field(self):
|
|
self.assertFalse(self.password_field.has_clone)
|
|
|
|
result = self.password_field.clone_field()
|
|
self.assertIsInstance(result, fields.PasswordField)
|
|
self.assertFalse(result.original)
|
|
self.assertEqual('Confirm password', result.label)
|
|
self.assertEqual('Please confirm your password',
|
|
result.error_messages['required'])
|
|
self.assertEqual('Retype your password', result.help_text)
|
|
|
|
|
|
class TestFlavorChoiceField(testtools.TestCase):
|
|
|
|
def setUp(self):
|
|
super(TestFlavorChoiceField, self).setUp()
|
|
|
|
self.requirements = {
|
|
'min_vcpus': 1,
|
|
'min_disk': 100,
|
|
'min_memory_mb': 500,
|
|
'max_vcpus': 5,
|
|
'max_disk': 5000,
|
|
'max_memory_mb': 16000
|
|
}
|
|
kwargs = {
|
|
'requirements': self.requirements
|
|
}
|
|
self.flavor_choice_field = fields.FlavorChoiceField(**kwargs)
|
|
self.flavor_choice_field.choices = []
|
|
self.flavor_choice_field.initial = None
|
|
self.assertEqual(kwargs['requirements'],
|
|
self.flavor_choice_field.requirements)
|
|
|
|
self.request = {'request': mock.Mock()}
|
|
self.tiny_flavor = mock.Mock()
|
|
self.tiny_flavor.configure_mock(name='m1.tiny')
|
|
self.small_flavor = mock.Mock()
|
|
self.small_flavor.configure_mock(name='m1.small')
|
|
self.medium_flavor = mock.Mock()
|
|
self.medium_flavor.configure_mock(name='m1.medium')
|
|
|
|
self.addCleanup(mock.patch.stopall)
|
|
|
|
@mock.patch.object(fields, 'nova')
|
|
def test_update(self, mock_nova):
|
|
""""Test if flavor with any invalid requirement is excluded."""
|
|
mock_nova.novaclient().flavors.list.return_value = [
|
|
self.tiny_flavor, self.small_flavor, self.medium_flavor
|
|
]
|
|
expected_choices = [
|
|
('m1.medium', 'm1.medium'), ('m1.small', 'm1.small')
|
|
]
|
|
valid_requirements = [
|
|
('vcpus', 2), ('disk', 101), ('ram', 501)
|
|
]
|
|
invalid_requirements = [
|
|
('vcpus', 0), ('vcpus', 6), ('disk', 99), ('disk', 5001),
|
|
('ram', 499), ('ram', 16001)
|
|
]
|
|
|
|
for req in valid_requirements:
|
|
for flavor in (self.small_flavor, self.medium_flavor):
|
|
setattr(flavor, req[0], req[1])
|
|
|
|
for invalid_req in invalid_requirements:
|
|
for valid_req in valid_requirements:
|
|
if invalid_req[0] != valid_req[0]:
|
|
setattr(self.tiny_flavor, valid_req[0], valid_req[1])
|
|
setattr(self.tiny_flavor, invalid_req[0], invalid_req[1])
|
|
self.flavor_choice_field.update(self.request)
|
|
self.assertEqual(expected_choices,
|
|
self.flavor_choice_field.choices)
|
|
self.assertEqual('m1.medium', self.flavor_choice_field.initial)
|
|
|
|
@mock.patch.object(fields, 'nova')
|
|
def test_update_without_requirements(self, mock_nova):
|
|
mock_nova.novaclient().flavors.list.return_value = [
|
|
self.tiny_flavor, self.small_flavor, self.medium_flavor
|
|
]
|
|
del self.flavor_choice_field.requirements
|
|
|
|
expected_choices = [
|
|
('m1.medium', 'm1.medium'),
|
|
('m1.small', 'm1.small'),
|
|
('m1.tiny', 'm1.tiny')
|
|
]
|
|
|
|
self.flavor_choice_field.update(self.request)
|
|
self.assertEqual(expected_choices, self.flavor_choice_field.choices)
|
|
self.assertEqual('m1.medium', self.flavor_choice_field.initial)
|
|
|
|
|
|
class TestKeyPairChoiceField(testtools.TestCase):
|
|
|
|
def setUp(self):
|
|
super(TestKeyPairChoiceField, self).setUp()
|
|
self.request = {'request': mock.Mock()}
|
|
self.addCleanup(mock.patch.stopall)
|
|
|
|
@mock.patch.object(fields, 'nova')
|
|
def test_update(self, mock_nova):
|
|
foo_keypair = mock.Mock()
|
|
bar_keypair = mock.Mock()
|
|
foo_keypair.configure_mock(name='foo')
|
|
bar_keypair.configure_mock(name='bar')
|
|
mock_nova.novaclient().keypairs.list.return_value = [
|
|
foo_keypair, bar_keypair
|
|
]
|
|
key_pair_choice_field = fields.KeyPairChoiceField()
|
|
key_pair_choice_field.choices = []
|
|
key_pair_choice_field.update(self.request)
|
|
|
|
expected_choices = [
|
|
('', _('No keypair')), ('foo', 'foo'), ('bar', 'bar')
|
|
]
|
|
self.assertEqual(sorted(expected_choices),
|
|
sorted(key_pair_choice_field.choices))
|
|
|
|
|
|
class TestSecurityGroupChoiceField(testtools.TestCase):
|
|
|
|
def setUp(self):
|
|
super(TestSecurityGroupChoiceField, self).setUp()
|
|
self.request = {'request': mock.Mock()}
|
|
self.addCleanup(mock.patch.stopall)
|
|
|
|
@mock.patch.object(fields, 'neutron')
|
|
def test_update(self, mock_neutron):
|
|
mock_neutron.security_group_list.return_value = [
|
|
mock.Mock(name_or_id='foo'),
|
|
mock.Mock(name_or_id='bar')
|
|
]
|
|
security_group_choice_field = fields.SecurityGroupChoiceField()
|
|
security_group_choice_field.choices = []
|
|
security_group_choice_field.update(self.request)
|
|
|
|
expected_choices = [
|
|
('', _('Application default security group')),
|
|
('foo', 'foo'), ('bar', 'bar')
|
|
]
|
|
self.assertEqual(sorted(expected_choices),
|
|
sorted(security_group_choice_field.choices))
|
|
|
|
|
|
class TestImageChoiceField(testtools.TestCase):
|
|
|
|
def setUp(self):
|
|
super(TestImageChoiceField, self).setUp()
|
|
self.request = {'request': mock.Mock()}
|
|
self.addCleanup(mock.patch.stopall)
|
|
|
|
@mock.patch.object(fields, 'get_murano_images')
|
|
def test_update(self, mock_get_murano_images):
|
|
mock_get_murano_images.return_value = [
|
|
# Test successful control flow.
|
|
mock.Mock(id='foo_image_id', murano_property={
|
|
'title': 'foo_image_title', 'type': 'png'},
|
|
status='active'),
|
|
# Test whether second continue statement works.
|
|
mock.Mock(id='bar_image_id', murano_property={
|
|
'title': 'foo_image_title', 'type': 'jpg'},
|
|
status='active')
|
|
]
|
|
image_choice_field = fields.ImageChoiceField()
|
|
image_choice_field.image_type = 'png'
|
|
image_choice_field.choices = []
|
|
image_choice_field.update(self.request)
|
|
|
|
self.assertEqual(("", _("Select Image")),
|
|
image_choice_field.choices[0])
|
|
self.assertEqual("foo_image_id", image_choice_field.choices[1][0])
|
|
self.assertIsInstance(image_choice_field.choices[1][1], fields.Choice)
|
|
|
|
# Test whether first continue statement works.
|
|
mock_get_murano_images.return_value = [
|
|
mock.Mock(murano_property={
|
|
'title': 'bar_image_title', 'type': None},
|
|
status=None)
|
|
]
|
|
image_choice_field.image_type = ''
|
|
image_choice_field.choices = []
|
|
image_choice_field.update(self.request)
|
|
expected_choices = [("", _("No images available"))]
|
|
self.assertEqual(expected_choices, image_choice_field.choices)
|
|
|
|
|
|
class TestNetworkChoiceField(testtools.TestCase):
|
|
|
|
def setUp(self):
|
|
super(TestNetworkChoiceField, self).setUp()
|
|
self.network_choice_field = fields.NetworkChoiceField(
|
|
filter=None,
|
|
murano_networks='exclude',
|
|
allow_auto=True)
|
|
self.request = {'request': mock.Mock()}
|
|
self.addCleanup(mock.patch.stopall)
|
|
|
|
@mock.patch.object(fields, 'net')
|
|
def test_update(self, mock_net):
|
|
mock_net.get_available_networks.return_value = [
|
|
(('foo', 'foo'), _('Foo'))
|
|
]
|
|
expected_choices = [
|
|
((None, None), _('Auto')), (('foo', 'foo'), _('Foo'))
|
|
]
|
|
|
|
self.network_choice_field.update(self.request)
|
|
self.assertEqual(expected_choices, self.network_choice_field.choices)
|
|
mock_net.get_available_networks.assert_called_once_with(
|
|
self.request['request'], None, 'exclude')
|
|
|
|
def test_to_python(self):
|
|
self.assertEqual({'foo': 'bar'},
|
|
self.network_choice_field.to_python('{"foo": "bar"}'))
|
|
self.assertEqual((None, None),
|
|
self.network_choice_field.to_python(None))
|
|
|
|
|
|
class TestVolumeChoiceField(testtools.TestCase):
|
|
|
|
def setUp(self):
|
|
super(TestVolumeChoiceField, self).setUp()
|
|
self.request = {'request': mock.Mock()}
|
|
self.addCleanup(mock.patch.stopall)
|
|
|
|
@mock.patch.object(fields, 'cinder')
|
|
def test_update(self, mock_cinder):
|
|
foo_vol = mock.Mock()
|
|
bar_snap = mock.Mock()
|
|
baz_snap = mock.Mock()
|
|
foo_vol.configure_mock(name='foo_vol', id='foo_id', status='available')
|
|
bar_snap.configure_mock(name='bar_snap', id='bar_id',
|
|
status='available')
|
|
baz_snap.configure_mock(name='baz_snap', id='baz_id', status='error')
|
|
mock_cinder.volume_list.return_value = [foo_vol]
|
|
mock_cinder.volume_snapshot_list.return_value = [bar_snap]
|
|
volume_choice_field = fields.VolumeChoiceField()
|
|
volume_choice_field.choices = []
|
|
volume_choice_field.update(self.request)
|
|
|
|
expected_choices = [
|
|
('', _('Select volume')), ('foo_id', 'foo_vol'),
|
|
('bar_id', 'bar_snap')
|
|
]
|
|
|
|
self.assertEqual(sorted(expected_choices),
|
|
sorted(volume_choice_field.choices))
|
|
|
|
@mock.patch.object(fields, 'cinder')
|
|
def test_update_withoutsnapshot(self, mock_cinder):
|
|
foo_vol = mock.Mock()
|
|
bar_vol = mock.Mock()
|
|
baz_snap = mock.Mock()
|
|
foo_vol.configure_mock(name='foo_vol', id='foo_id', status='available')
|
|
bar_vol.configure_mock(name='bar_vol', id='bar_id', status='error')
|
|
baz_snap.configure_mock(name='baz_snap', id='baz_id',
|
|
status='available')
|
|
mock_cinder.volume_list.return_value = [foo_vol]
|
|
mock_cinder.volume_snapshot_list.return_value = [baz_snap]
|
|
volume_choice_field = fields.VolumeChoiceField(include_snapshots=False)
|
|
volume_choice_field.choices = []
|
|
volume_choice_field.update(self.request)
|
|
|
|
expected_choices = [
|
|
('', _('Select volume')), ('foo_id', 'foo_vol')
|
|
]
|
|
|
|
self.assertEqual(sorted(expected_choices),
|
|
sorted(volume_choice_field.choices))
|
|
|
|
@mock.patch.object(fields, 'cinder')
|
|
def test_update_withoutvolume(self, mock_cinder):
|
|
foo_vol = mock.Mock()
|
|
baz_snap = mock.Mock()
|
|
foo_vol.configure_mock(name='foo_vol', id='foo_id', status='available')
|
|
baz_snap.configure_mock(name='baz_snap', id='baz_id',
|
|
status='available')
|
|
mock_cinder.volume_list.return_value = [foo_vol]
|
|
mock_cinder.volume_snapshot_list.return_value = [baz_snap]
|
|
volume_choice_field = fields.VolumeChoiceField(include_volumes=False)
|
|
volume_choice_field.choices = []
|
|
volume_choice_field.update(self.request)
|
|
|
|
expected_choices = [
|
|
('', _('Select volume')), ('baz_id', 'baz_snap')
|
|
]
|
|
|
|
self.assertEqual(sorted(expected_choices),
|
|
sorted(volume_choice_field.choices))
|
|
|
|
@mock.patch.object(fields, 'exceptions')
|
|
@mock.patch.object(fields, 'cinder')
|
|
def test_update_except_snapshot_list_exception(self, mock_cinder,
|
|
mock_exceptions):
|
|
foo_vol = mock.Mock()
|
|
bar_vol = mock.Mock()
|
|
foo_vol.configure_mock(name='foo_vol', id='foo_id', status='available')
|
|
bar_vol.configure_mock(name='bar_vol', id='bar_id', status='error')
|
|
mock_cinder.volume_list.return_value = [foo_vol]
|
|
mock_cinder.volume_snapshot_list.side_effect = Exception
|
|
volume_choice_field = fields.VolumeChoiceField(include_volumes=True,
|
|
include_snapshots=True)
|
|
volume_choice_field.choices = []
|
|
volume_choice_field.update(self.request)
|
|
|
|
expected_choices = [
|
|
('', _('Select volume')), ('foo_id', 'foo_vol')
|
|
]
|
|
|
|
self.assertEqual(sorted(expected_choices),
|
|
sorted(volume_choice_field.choices))
|
|
mock_exceptions.handle.assert_called_once_with(
|
|
self.request['request'], _('Unable to retrieve snapshot list.'))
|
|
|
|
@mock.patch.object(fields, 'exceptions')
|
|
@mock.patch.object(fields, 'cinder')
|
|
def test_update_except_volume_list_exception(self, mock_cinder,
|
|
mock_exceptions):
|
|
bar_snap = mock.Mock()
|
|
bar_snap.configure_mock(name='bar_snap', id='bar_id',
|
|
status='available')
|
|
mock_cinder.volume_list.side_effect = Exception
|
|
mock_cinder.volume_snapshot_list.return_value = [bar_snap]
|
|
volume_choice_field = fields.VolumeChoiceField(include_volumes=True,
|
|
include_snapshots=True)
|
|
volume_choice_field.choices = []
|
|
volume_choice_field.update(self.request)
|
|
|
|
expected_choices = [
|
|
('', _('Select volume')), ('bar_id', 'bar_snap')
|
|
]
|
|
|
|
self.assertEqual(expected_choices, volume_choice_field.choices)
|
|
mock_exceptions.handle.assert_called_once_with(
|
|
self.request['request'], _('Unable to retrieve volume list.'))
|
|
|
|
@mock.patch.object(fields, 'exceptions')
|
|
@mock.patch.object(fields, 'cinder')
|
|
def test_update_except_exception(self, mock_cinder, mock_exceptions):
|
|
mock_cinder.volume_list.side_effect = Exception
|
|
mock_cinder.volume_snapshot_list.side_effect = Exception
|
|
volume_choice_field = fields.VolumeChoiceField(include_volumes=True,
|
|
include_snapshots=True)
|
|
volume_choice_field.choices = []
|
|
volume_choice_field.update(self.request)
|
|
|
|
expected_choices = [
|
|
('', _('No volumes available'))
|
|
]
|
|
expected_calls = [
|
|
mock.call(self.request['request'],
|
|
_('Unable to retrieve volume list.')),
|
|
mock.call(self.request['request'],
|
|
_('Unable to retrieve snapshot list.'))
|
|
]
|
|
self.assertEqual(expected_choices, volume_choice_field.choices)
|
|
mock_exceptions.handle.assert_has_calls(expected_calls)
|
|
|
|
|
|
class TestAZoneChoiceField(testtools.TestCase):
|
|
|
|
@mock.patch.object(fields, 'nova')
|
|
def test_update(self, mock_nova):
|
|
mock_nova.novaclient().availability_zones.list.return_value = [
|
|
mock.Mock(zoneName='foo_zone', zoneState='foo_state'),
|
|
mock.Mock(zoneName='bar_zone', zoneState='bar_state')
|
|
]
|
|
request = {'request': mock.Mock()}
|
|
a_zone_choice_field = fields.AZoneChoiceField()
|
|
a_zone_choice_field.choices = []
|
|
|
|
expected_choices = [
|
|
("bar_zone", "bar_zone"), ("foo_zone", "foo_zone")
|
|
]
|
|
a_zone_choice_field.update(request)
|
|
self.assertEqual(expected_choices, a_zone_choice_field.choices)
|
|
|
|
@mock.patch.object(fields, 'exceptions')
|
|
@mock.patch.object(fields, 'nova')
|
|
def test_update_except_exception(self, mock_nova, mock_exc):
|
|
mock_nova.novaclient().availability_zones.list.side_effect = Exception
|
|
request = {'request': mock.Mock()}
|
|
a_zone_choice_field = fields.AZoneChoiceField()
|
|
a_zone_choice_field.choices = []
|
|
|
|
expected_choices = [
|
|
("", _("No availability zones available"))
|
|
]
|
|
a_zone_choice_field.update(request)
|
|
self.assertEqual(expected_choices, a_zone_choice_field.choices)
|
|
mock_exc.handle.assert_called_once_with(request['request'], mock.ANY)
|
|
|
|
|
|
class TestBooleanField(testtools.TestCase):
|
|
|
|
def test_boolean_field(self):
|
|
class Widget(object):
|
|
def __init__(self, attrs):
|
|
self.attrs = attrs
|
|
|
|
boolean_field = fields.BooleanField(widget=Widget)
|
|
self.assertIsInstance(boolean_field.widget, Widget)
|
|
self.assertEqual({'class': 'checkbox'}, boolean_field.widget.attrs)
|
|
self.assertFalse(boolean_field.required)
|
|
|
|
boolean_field = fields.BooleanField()
|
|
self.assertIsInstance(boolean_field.widget, forms.CheckboxInput)
|
|
self.assertEqual({'class': 'checkbox'}, boolean_field.widget.attrs)
|
|
self.assertFalse(boolean_field.required)
|
|
|
|
|
|
class TestDatabaseListField(testtools.TestCase):
|
|
|
|
def setUp(self):
|
|
super(TestDatabaseListField, self).setUp()
|
|
self.database_list_field = fields.DatabaseListField()
|
|
self.addCleanup(mock.patch.stopall)
|
|
|
|
def test_to_python(self):
|
|
self.assertEqual([], self.database_list_field.to_python(None))
|
|
self.assertEqual(['foo', 'bar'],
|
|
self.database_list_field.to_python('foo ,bar '))
|
|
|
|
def test_validate(self):
|
|
valid_value = ['a123', '_123', 'a123_$#@']
|
|
result = self.database_list_field.validate(valid_value)
|
|
self.assertIsNone(result)
|
|
|
|
def test_validate_except_validation_error(self):
|
|
invalid_value = ['123abc']
|
|
|
|
expected_error = "First symbol should be latin letter or underscore. "\
|
|
"Subsequent symbols can be latin letter, numeric, "\
|
|
"underscore, at sign, number sign or dollar sign"
|
|
e = self.assertRaises(exceptions.ValidationError,
|
|
self.database_list_field.validate, invalid_value)
|
|
self.assertEqual(expected_error, e.message)
|
|
|
|
|
|
class TestErrorWidget(testtools.TestCase):
|
|
|
|
def test_render(self):
|
|
error_widget = fields.ErrorWidget()
|
|
error_widget.message = 'foo_message'
|
|
result = error_widget.render("'foo_name'", None)
|
|
self.assertEqual("<div name='foo_name'>foo_message</div>", result)
|