209 lines
7.9 KiB
Python
209 lines
7.9 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.
|
|
|
|
import collections
|
|
import mock
|
|
import testtools
|
|
from yaql.language import contexts as yaql_contexts
|
|
|
|
from django import forms as django_forms
|
|
|
|
from muranodashboard.dynamic_ui import fields
|
|
from muranodashboard.dynamic_ui import forms
|
|
from muranodashboard.dynamic_ui import yaql_expression
|
|
|
|
|
|
class TestAnyFieldDict(testtools.TestCase):
|
|
|
|
def test_missing(self):
|
|
any_field_dict = forms.AnyFieldDict()
|
|
result = any_field_dict.__missing__(['foo', 'bar'])
|
|
self.assertEqual('DynamicSelect', result.__name__)
|
|
|
|
|
|
class TestDynamicUiForm(testtools.TestCase):
|
|
|
|
def test_collect_fields_process_widget(self):
|
|
test_spec = {
|
|
'type': 'text',
|
|
'name': 'foo_spec',
|
|
'widget_media': {
|
|
'js': 'foo.js',
|
|
'css': 'foo.css'
|
|
},
|
|
'widget_attrs': {'foo': 'bar'}
|
|
}
|
|
|
|
result = forms._collect_fields([test_spec], 'foo_form', None)
|
|
|
|
self.assertIsInstance(result, list)
|
|
self.assertEqual(1, len(result))
|
|
self.assertEqual('foo_spec', result[0][0])
|
|
self.assertIsInstance(result[0][1], fields.CharField)
|
|
|
|
field = result[0][1]
|
|
|
|
self.assertTrue(hasattr(field, 'widget'))
|
|
self.assertTrue(hasattr(field.widget, 'Media'))
|
|
self.assertEqual('foo.js', field.widget.Media.js)
|
|
self.assertEqual('foo.css', field.widget.Media.css)
|
|
self.assertIn('foo', field.widget.__dict__['attrs'])
|
|
self.assertEqual('bar', field.widget.__dict__['attrs']['foo'])
|
|
|
|
def test_collect_fields_parse_spec_with_yaql_expression(self):
|
|
mock_yaql = mock.Mock(spec=yaql_expression.YaqlExpression)
|
|
test_spec = {
|
|
'type': 'choice',
|
|
'name': 'foo_spec',
|
|
'validators': [{'expr': mock_yaql}]
|
|
}
|
|
|
|
result = forms._collect_fields([test_spec], 'foo_form', None)
|
|
|
|
self.assertIsInstance(result, list)
|
|
self.assertEqual(1, len(result))
|
|
self.assertEqual('foo_spec', result[0][0])
|
|
self.assertIsInstance(result[0][1], fields.ChoiceField)
|
|
|
|
field = result[0][1]
|
|
|
|
self.assertTrue(hasattr(field, 'validators'))
|
|
self.assertIn('expr', field.validators[0])
|
|
self.assertIsInstance(field.validators[0]['expr'], fields.RawProperty)
|
|
self.assertEqual(mock_yaql, field.validators[0]['expr'].spec)
|
|
|
|
|
|
class TestDynamicFormMetaclass(testtools.TestCase):
|
|
|
|
def test_new(self):
|
|
test_dict = {
|
|
'name': 'foo_form',
|
|
'field_specs': [{'type': 'text', 'name': 'foo_spec'}],
|
|
'service': 'foo_service',
|
|
}
|
|
|
|
form = forms.DynamicFormMetaclass('foo_form', (), test_dict)
|
|
self.assertEqual('foo_form', form.__name__)
|
|
self.assertEqual('foo_service', form.service)
|
|
self.assertIsInstance(form.declared_fields, collections.OrderedDict)
|
|
self.assertIn('foo_spec', form.declared_fields)
|
|
self.assertIsInstance(form.declared_fields['foo_spec'],
|
|
fields.CharField)
|
|
|
|
|
|
class TestUpdatableFieldsForm(testtools.TestCase):
|
|
|
|
def setUp(self):
|
|
super(TestUpdatableFieldsForm, self).setUp()
|
|
|
|
self.form = forms.UpdatableFieldsForm(None)
|
|
self.assertEqual('required', self.form.required_css_class)
|
|
|
|
def test_update_fields(self):
|
|
mock_password_field = mock.Mock(spec=fields.PasswordField)
|
|
mock_password_field.confirm_input = True
|
|
mock_password_field.has_clone = False
|
|
mock_password_field.original = True
|
|
mock_password_field.required = True
|
|
mock_password_field.update = mock.Mock()
|
|
mock_password_field.initial = 'foo_initial'
|
|
mock_password_field.get_clone_name.return_value = 'bar_password_field'
|
|
mock_clone_password_field = mock.Mock(
|
|
spec=fields.PasswordField, required=True)
|
|
mock_password_field.clone_field.return_value = \
|
|
mock_clone_password_field
|
|
|
|
self.form.fields = collections.OrderedDict({
|
|
'foo_password_field': mock_password_field})
|
|
self.form.update_fields()
|
|
|
|
self.assertEqual(2, len(self.form.fields))
|
|
self.assertIn('foo_password_field', self.form.fields)
|
|
self.assertIn('bar_password_field', self.form.fields)
|
|
self.assertEqual(mock_password_field,
|
|
self.form.fields['foo_password_field'])
|
|
self.assertEqual(mock_clone_password_field,
|
|
self.form.fields['bar_password_field'])
|
|
mock_password_field.get_clone_name.assert_called_once_with(
|
|
'foo_password_field')
|
|
self.assertTrue(mock_password_field.get_clone_name.called)
|
|
self.assertTrue(mock_password_field.update.called)
|
|
|
|
|
|
class TestServiceConfigurationForm(testtools.TestCase):
|
|
|
|
def setUp(self):
|
|
super(TestServiceConfigurationForm, self).setUp()
|
|
|
|
mock_service = mock.Mock()
|
|
mock_service.update_cleaned_data.return_value = \
|
|
{'foo': 'bar', 'baz': 'qux'}
|
|
|
|
self.form = forms.ServiceConfigurationForm(
|
|
initial={'app_id': 'foo_app'})
|
|
self.form._errors = []
|
|
self.form.validators = []
|
|
self.form.cleaned_data = {'foo': 'bar', 'baz': 'qux'}
|
|
self.form.service = mock_service
|
|
|
|
self.assertEqual('foo_app_%s', self.form.auto_id)
|
|
self.assertIsInstance(self.form.context, yaql_contexts.Context)
|
|
|
|
@mock.patch.object(forms, 'LOG', autospec=True)
|
|
def test_clean(self, mock_log):
|
|
password_field = mock.Mock(spec=fields.PasswordField)
|
|
password_field.enabled = True
|
|
password_field.confirm_input = True
|
|
|
|
foo_field = mock.Mock()
|
|
foo_field.enabled = False
|
|
foo_field.postclean.return_value = 'post_foo'
|
|
|
|
self.form.fields = {'foo': foo_field, 'password': password_field}
|
|
result = self.form.clean()
|
|
expected_cleaned_data = {'foo': 'post_foo', 'baz': 'qux'}
|
|
|
|
for key, val in expected_cleaned_data.items():
|
|
self.assertEqual(val, result[key])
|
|
|
|
# NOTE(felipemonteiro): mock.ANY is being used in the assertions
|
|
# below, rather than `{'foo': 'bar', 'baz': 'qux'}` because
|
|
# `cleaned_data[name] = value` in clean() appears to also change the
|
|
# dict that was passed in to mock objects in previous lines of code.
|
|
foo_field.postclean.assert_called_once_with(self.form, 'foo', mock.ANY)
|
|
password_field.compare.assert_called_once_with('password', mock.ANY)
|
|
mock_log.debug.assert_called_once_with(
|
|
"Update 'foo' data in postclean method")
|
|
self.form.service.update_cleaned_data.assert_called_with(
|
|
mock.ANY, form=self.form)
|
|
|
|
def test_clean_except_validation_error(self):
|
|
mock_expr = mock.Mock()
|
|
mock_expr.evaluate.return_value = False
|
|
test_validator = {'expr': mock_expr, 'message': 'Foo Error'}
|
|
|
|
self.form.validators = [test_validator]
|
|
with self.assertRaisesRegex(django_forms.ValidationError,
|
|
'Foo Error'):
|
|
self.form.clean()
|
|
|
|
self.form.service.update_cleaned_data.assert_called_once_with(
|
|
{'foo': 'bar', 'baz': 'qux'}, form=self.form)
|
|
mock_expr.evaluate.assert_called_once_with(
|
|
data={'foo': 'bar', 'baz': 'qux'}, context=self.form.context)
|
|
|
|
def test_clean_with_errors(self):
|
|
self.form._errors = ['foo_error']
|
|
self.assertEqual({'foo': 'bar', 'baz': 'qux'}, self.form.clean())
|