b82e6e5aff
Partial-Bug: #1643599 Change-Id: I8cd2b972c4be053ebbcb0cc788c1ee0384120374
590 lines
18 KiB
Python
590 lines
18 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Copyright 2013 Mirantis, Inc.
|
|
#
|
|
# 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 json
|
|
import mock
|
|
|
|
from nailgun.api.v1.validators import base
|
|
from nailgun.api.v1.validators import cluster
|
|
from nailgun import errors
|
|
from nailgun.test import base as base_test
|
|
|
|
|
|
class TestClusterAttributesValidator(base_test.BaseTestCase):
|
|
def test_generated_attributes_validation(self):
|
|
self.assertRaises(
|
|
errors.InvalidData,
|
|
cluster.ClusterAttributesValidator.validate,
|
|
'{"generated": {"name": "test"}}')
|
|
|
|
def test_editable_attributes_validation(self):
|
|
self.assertRaises(
|
|
errors.InvalidData,
|
|
cluster.ClusterAttributesValidator.validate,
|
|
'{"editable": "name"}')
|
|
|
|
@mock.patch('nailgun.objects.Cluster.get_updated_editable_attributes')
|
|
def test_invalid_provisioning_method(self, mock_cluster_attrs):
|
|
attrs = {'editable': {'provision': {'method':
|
|
{'value': 'not_image', 'type': 'text'}}}}
|
|
mock_cluster_attrs.return_value = attrs
|
|
cluster_mock = mock.Mock(release=mock.Mock(environment_version='7.0'))
|
|
self.assertRaises(
|
|
errors.InvalidData,
|
|
cluster.ClusterAttributesValidator.validate,
|
|
json.dumps(attrs), cluster_mock)
|
|
|
|
@mock.patch('nailgun.objects.Cluster.get_updated_editable_attributes')
|
|
def test_provision_method_missing(self, mock_cluster_attrs):
|
|
attrs = {'editable': {'method':
|
|
{'value': 'not_image', 'type': 'text'}}}
|
|
mock_cluster_attrs.return_value = attrs
|
|
cluster_mock = mock.Mock(release=mock.Mock(environment_version='7.0'))
|
|
self.assertRaises(
|
|
errors.InvalidData,
|
|
cluster.ClusterAttributesValidator.validate,
|
|
json.dumps(attrs), cluster_mock)
|
|
|
|
@mock.patch('nailgun.objects.Cluster.get_updated_editable_attributes')
|
|
def test_provision_method_passed(self, mock_cluster_attrs):
|
|
attrs = {'editable': {'provision': {'method':
|
|
{'value': 'image', 'type': 'text'}}}}
|
|
mock_cluster_attrs.return_value = attrs
|
|
cluster_mock = mock.Mock(
|
|
is_locked=False, release=mock.Mock(environment_version='7.0')
|
|
)
|
|
self.assertNotRaises(
|
|
errors.InvalidData,
|
|
cluster.ClusterAttributesValidator.validate,
|
|
json.dumps(attrs), cluster_mock)
|
|
|
|
@mock.patch('nailgun.objects.Cluster.get_updated_editable_attributes')
|
|
def test_provision_method_passed_old(self, mock_cluster_attrs):
|
|
attrs = {'editable': {'provision': {'method':
|
|
{'value': 'image', 'type': 'text'}}}}
|
|
mock_cluster_attrs.return_value = attrs
|
|
cluster_mock = mock.Mock(
|
|
is_locked=False, release=mock.Mock(environment_version='6.0')
|
|
)
|
|
self.assertNotRaises(
|
|
errors.InvalidData,
|
|
cluster.ClusterAttributesValidator.validate,
|
|
json.dumps(attrs), cluster_mock)
|
|
|
|
def test_valid_attributes(self):
|
|
valid_attibutes = [
|
|
'{"group": {"name": "test"}}',
|
|
'{"name": "test"}',
|
|
]
|
|
for attributes in valid_attibutes:
|
|
self.assertNotRaises(
|
|
errors.InvalidData,
|
|
cluster.ClusterAttributesValidator.validate,
|
|
attributes)
|
|
attribute_dict = json.loads(attributes)
|
|
self.assertNotRaises(
|
|
errors.InvalidData,
|
|
cluster.ClusterAttributesValidator.validate_attributes,
|
|
attribute_dict)
|
|
|
|
|
|
class TestBasicAttributesValidator(base_test.BaseTestCase):
|
|
def test_missing_type(self):
|
|
attrs = {
|
|
'storage': {
|
|
'osd_pool_size': {
|
|
'description': 'desc',
|
|
'label': 'OSD Pool Size',
|
|
'value': 'x',
|
|
'weight': 80
|
|
}
|
|
}
|
|
}
|
|
self.assertRaises(
|
|
errors.InvalidData,
|
|
base.BasicAttributesValidator.validate_attributes,
|
|
attrs)
|
|
|
|
def test_missing_value(self):
|
|
attrs = {
|
|
'storage': {
|
|
'osd_pool_size': {
|
|
'description': 'desc',
|
|
'label': 'OSD Pool Size',
|
|
'type': 'checkbox',
|
|
'weight': 80
|
|
}
|
|
}
|
|
}
|
|
self.assertRaises(
|
|
errors.InvalidData,
|
|
base.BasicAttributesValidator.validate_attributes,
|
|
attrs)
|
|
|
|
def test_invalid_regexp(self):
|
|
attrs = {
|
|
'storage': {
|
|
'osd_pool_size': {
|
|
'description': 'desc',
|
|
'label': 'OSD Pool Size',
|
|
'type': 'text',
|
|
'value': '212a',
|
|
'regex': {
|
|
'error': 'Invalid',
|
|
'source': '^\d+$'
|
|
},
|
|
'weight': 80
|
|
}
|
|
}
|
|
}
|
|
self.assertRaises(
|
|
errors.InvalidData,
|
|
base.BasicAttributesValidator.validate_attributes,
|
|
attrs)
|
|
|
|
def test_checkbox_value(self):
|
|
attrs = {
|
|
'storage': {
|
|
'osd_pool_size': {
|
|
'description': 'desc',
|
|
'label': 'OSD Pool Size',
|
|
'type': 'checkbox',
|
|
'value': True,
|
|
'weight': 80
|
|
}
|
|
}
|
|
}
|
|
self.assertNotRaises(
|
|
errors.InvalidData,
|
|
base.BasicAttributesValidator.validate_attributes,
|
|
attrs)
|
|
attrs = {
|
|
'storage': {
|
|
'osd_pool_size': {
|
|
'description': 'desc',
|
|
'label': 'OSD Pool Size',
|
|
'type': 'checkbox',
|
|
'value': 'x',
|
|
'weight': 80
|
|
}
|
|
}
|
|
}
|
|
self.assertRaises(
|
|
errors.InvalidData,
|
|
base.BasicAttributesValidator.validate_attributes,
|
|
attrs)
|
|
|
|
def test_custom_repo_configuration_value(self):
|
|
attrs = {
|
|
'storage': {
|
|
'repos': {
|
|
'description': 'desc',
|
|
'type': 'custom_repo_configuration',
|
|
'value': [{
|
|
'name': 'ubuntu',
|
|
'priority': None,
|
|
'section': 'main universe multiverse',
|
|
'suite': 'trusty',
|
|
'type': 'deb',
|
|
'uri': 'http://archive.ubuntu.com/ubuntu/'
|
|
}, {
|
|
'name': 'ubuntu-updates',
|
|
'priority': None,
|
|
'section': 'main universe multiverse',
|
|
'suite': 'trusty-updates',
|
|
'type': 'deb',
|
|
'uri': 'http://archive.ubuntu.com/ubuntu/'
|
|
}]
|
|
}
|
|
}
|
|
}
|
|
self.assertNotRaises(
|
|
errors.InvalidData,
|
|
base.BasicAttributesValidator.validate_attributes,
|
|
attrs)
|
|
|
|
def test_password_value(self):
|
|
attrs = {
|
|
'storage': {
|
|
'osd_pool_size': {
|
|
'description': 'desc',
|
|
'label': 'OSD Pool Size',
|
|
'type': 'password',
|
|
'value': '2',
|
|
'weight': 80
|
|
}
|
|
}
|
|
}
|
|
self.assertNotRaises(
|
|
errors.InvalidData,
|
|
base.BasicAttributesValidator.validate_attributes,
|
|
attrs)
|
|
|
|
attrs = {
|
|
'storage': {
|
|
'osd_pool_size': {
|
|
'description': 'desc',
|
|
'label': 'OSD Pool Size',
|
|
'type': 'password',
|
|
'value': 2,
|
|
'weight': 80
|
|
}
|
|
}
|
|
}
|
|
self.assertRaises(
|
|
errors.InvalidData,
|
|
base.BasicAttributesValidator.validate_attributes,
|
|
attrs)
|
|
|
|
def test_radio_value(self):
|
|
attrs = {
|
|
'storage': {
|
|
'syslog_transport': {
|
|
'label': 'Syslog transport protocol',
|
|
'type': 'radio',
|
|
'value': 'tcp',
|
|
'values': [{
|
|
'data': 'udp',
|
|
'description': '',
|
|
'label': 'UDP'
|
|
}, {
|
|
'data': 'tcp',
|
|
'description': '',
|
|
'label': 'TCP'
|
|
}, {
|
|
'data': 'missing-description',
|
|
'label': 'Missing Description'
|
|
}],
|
|
'weight': 3
|
|
}
|
|
}
|
|
}
|
|
|
|
self.assertNotRaises(
|
|
errors.InvalidData,
|
|
base.BasicAttributesValidator.validate_attributes,
|
|
attrs)
|
|
|
|
def test_select_value(self):
|
|
attrs = {
|
|
'common': {
|
|
'libvirt_type': {
|
|
'label': 'Hypervisor type',
|
|
'type': 'select',
|
|
'value': 'qemu',
|
|
'values': [{
|
|
'data': 'kvm',
|
|
'label': 'KVM',
|
|
'description': 'KVM description'
|
|
}, {
|
|
'data': 'qemu',
|
|
'label': 'QEMU',
|
|
'description': 'QEMU description'
|
|
}]
|
|
}
|
|
}
|
|
}
|
|
|
|
self.assertNotRaises(
|
|
errors.InvalidData,
|
|
base.BasicAttributesValidator.validate_attributes,
|
|
attrs)
|
|
|
|
def test_text_value(self):
|
|
attrs = {
|
|
'storage': {
|
|
'osd_pool_size': {
|
|
'description': 'desc',
|
|
'label': 'OSD Pool Size',
|
|
'type': 'text',
|
|
'value': '2',
|
|
'weight': 80
|
|
}
|
|
}
|
|
}
|
|
self.assertNotRaises(
|
|
errors.InvalidData,
|
|
base.BasicAttributesValidator.validate_attributes,
|
|
attrs)
|
|
|
|
attrs = {
|
|
'storage': {
|
|
'osd_pool_size': {
|
|
'description': 'desc',
|
|
'label': 'OSD Pool Size',
|
|
'type': 'text',
|
|
'value': 2,
|
|
'weight': 80
|
|
}
|
|
}
|
|
}
|
|
self.assertRaises(
|
|
errors.InvalidData,
|
|
base.BasicAttributesValidator.validate_attributes,
|
|
attrs)
|
|
|
|
attrs = {
|
|
'storage': {
|
|
'osd_pool_size': {
|
|
'description': 'desc',
|
|
'label': 'OSD Pool Size',
|
|
'type': 'text',
|
|
'nullable': True,
|
|
'value': '2',
|
|
'weight': 80
|
|
}
|
|
}
|
|
}
|
|
self.assertNotRaises(
|
|
errors.InvalidData,
|
|
base.BasicAttributesValidator.validate_attributes,
|
|
attrs)
|
|
|
|
attrs = {
|
|
'storage': {
|
|
'osd_pool_size': {
|
|
'description': 'desc',
|
|
'label': 'OSD Pool Size',
|
|
'type': 'text',
|
|
'nullable': True,
|
|
'value': None,
|
|
'weight': 80
|
|
}
|
|
}
|
|
}
|
|
self.assertNotRaises(
|
|
errors.InvalidData,
|
|
base.BasicAttributesValidator.validate_attributes,
|
|
attrs)
|
|
|
|
def test_textarea_value(self):
|
|
attrs = {
|
|
'storage': {
|
|
'osd_pool_size': {
|
|
'description': 'desc',
|
|
'label': 'OSD Pool Size',
|
|
'type': 'textarea',
|
|
'value': '2',
|
|
'weight': 80
|
|
}
|
|
}
|
|
}
|
|
self.assertNotRaises(
|
|
errors.InvalidData,
|
|
base.BasicAttributesValidator.validate_attributes,
|
|
attrs)
|
|
|
|
attrs = {
|
|
'storage': {
|
|
'osd_pool_size': {
|
|
'description': 'desc',
|
|
'label': 'OSD Pool Size',
|
|
'type': 'textarea',
|
|
'value': 2,
|
|
'weight': 80
|
|
}
|
|
}
|
|
}
|
|
self.assertRaises(
|
|
errors.InvalidData,
|
|
base.BasicAttributesValidator.validate_attributes,
|
|
attrs)
|
|
|
|
def test_text_list_value(self):
|
|
attrs = {
|
|
'storage': {
|
|
'osd_pool_size': {
|
|
'description': 'desc',
|
|
'label': 'OSD Pool Size',
|
|
'type': 'text_list',
|
|
'value': ['2'],
|
|
'weight': 80
|
|
}
|
|
}
|
|
}
|
|
# check that text_list value is a list
|
|
self.assertNotRaises(
|
|
errors.InvalidData,
|
|
base.BasicAttributesValidator.validate_attributes,
|
|
attrs)
|
|
|
|
attrs = {
|
|
'storage': {
|
|
'osd_pool_size': {
|
|
'description': 'desc',
|
|
'label': 'OSD Pool Size',
|
|
'type': 'text_list',
|
|
'value': 2,
|
|
'weight': 80
|
|
}
|
|
}
|
|
}
|
|
self.assertRaises(
|
|
errors.InvalidData,
|
|
base.BasicAttributesValidator.validate_attributes,
|
|
attrs)
|
|
|
|
def test_valid_attributes(self):
|
|
valid_attibutes = [
|
|
'{"group": {"name": "test"}}',
|
|
'{"name": "test"}',
|
|
]
|
|
|
|
for attributes in valid_attibutes:
|
|
self.assertNotRaises(
|
|
errors.InvalidData,
|
|
base.BasicAttributesValidator.validate,
|
|
attributes)
|
|
attribute_dict = json.loads(attributes)
|
|
self.assertNotRaises(
|
|
errors.InvalidData,
|
|
base.BasicAttributesValidator.validate_attributes,
|
|
attribute_dict)
|
|
|
|
def test_custom_hugepages_value(self):
|
|
attrs = {
|
|
'hugepages': {
|
|
'nova': {
|
|
'description': 'desc',
|
|
'label': 'Label',
|
|
'type': 'custom_hugepages',
|
|
'value': {
|
|
'2048': 4,
|
|
'1048576': 2
|
|
},
|
|
'weight': 10
|
|
}
|
|
}
|
|
}
|
|
self.assertNotRaises(
|
|
errors.InvalidData,
|
|
base.BasicAttributesValidator.validate_attributes,
|
|
attrs)
|
|
|
|
attrs = {
|
|
'storage': {
|
|
'osd_pool_size': {
|
|
'description': 'desc',
|
|
'label': 'OSD Pool Size',
|
|
'type': 'custrom_hugepages',
|
|
'value': {
|
|
'2048': '1'
|
|
},
|
|
'weight': 10
|
|
}
|
|
}
|
|
}
|
|
self.assertRaises(
|
|
errors.InvalidData,
|
|
base.BasicAttributesValidator.validate_attributes,
|
|
attrs)
|
|
|
|
def test_number_value(self):
|
|
attrs = {
|
|
'cpu_pinning': {
|
|
'nova': {
|
|
'description': 'desc',
|
|
'label': 'Label',
|
|
'type': 'number',
|
|
'value': 1,
|
|
'min': 0,
|
|
'weight': 10
|
|
}
|
|
}
|
|
}
|
|
self.assertNotRaises(
|
|
errors.InvalidData,
|
|
base.BasicAttributesValidator.validate_attributes,
|
|
attrs)
|
|
|
|
attrs = {
|
|
'cpu_pinning': {
|
|
'nova': {
|
|
'description': 'desc',
|
|
'label': 'Label',
|
|
'type': 'number',
|
|
'value': -1,
|
|
'min': 0,
|
|
'weight': 10
|
|
}
|
|
}
|
|
}
|
|
self.assertRaises(
|
|
errors.InvalidData,
|
|
base.BasicAttributesValidator.validate_attributes,
|
|
attrs)
|
|
|
|
attrs = {
|
|
'cpu_pinning': {
|
|
'nova': {
|
|
'description': 'desc',
|
|
'label': 'Label',
|
|
'type': 'number',
|
|
'nullable': True,
|
|
'value': 1,
|
|
'min': 0,
|
|
'weight': 10
|
|
}
|
|
}
|
|
}
|
|
self.assertNotRaises(
|
|
errors.InvalidData,
|
|
base.BasicAttributesValidator.validate_attributes,
|
|
attrs)
|
|
|
|
attrs = {
|
|
'cpu_pinning': {
|
|
'nova': {
|
|
'description': 'desc',
|
|
'label': 'Label',
|
|
'type': 'number',
|
|
'nullable': True,
|
|
'value': None,
|
|
'min': 0,
|
|
'weight': 10
|
|
}
|
|
}
|
|
}
|
|
self.assertNotRaises(
|
|
errors.InvalidData,
|
|
base.BasicAttributesValidator.validate_attributes,
|
|
attrs)
|
|
|
|
def test_restriction_strict(self):
|
|
context = {'context': {'existing': {'value': 13}}}
|
|
|
|
for strict in (False, True):
|
|
attrs = {
|
|
'section': {
|
|
'subsection': {
|
|
'restrictions': [{
|
|
'condition': 'context:nonexisting.value == 42',
|
|
'strict': strict,
|
|
}],
|
|
},
|
|
},
|
|
}
|
|
|
|
if strict:
|
|
assert_fn = self.assertRaises
|
|
else:
|
|
assert_fn = self.assertNotRaises
|
|
|
|
assert_fn(
|
|
TypeError,
|
|
base.BasicAttributesValidator.validate_attributes,
|
|
attrs,
|
|
models=context)
|