This adds a validator to check if a value is an IP address, an IP subnet, or none. This was originally part of the neutron-fwaas API definition migration to neutron-lib[1], but it was suggested that this should be pulled into a separate change. [1] https://review.openstack.org/389388 Change-Id: I8dcf49adc7754d0c9aa0479ede2de481325bb3e3
		
			
				
	
	
		
			1076 lines
		
	
	
		
			43 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			1076 lines
		
	
	
		
			43 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
#
 | 
						|
#    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 string
 | 
						|
 | 
						|
import mock
 | 
						|
import netaddr
 | 
						|
 | 
						|
from neutron_lib._i18n import _
 | 
						|
from neutron_lib.api import converters
 | 
						|
from neutron_lib.api import validators
 | 
						|
from neutron_lib import constants
 | 
						|
from neutron_lib import exceptions as n_exc
 | 
						|
from neutron_lib.tests import _base as base
 | 
						|
 | 
						|
 | 
						|
def dummy_validator(data, valid_values=None):
 | 
						|
    pass
 | 
						|
 | 
						|
 | 
						|
class TestAttributeValidation(base.BaseTestCase):
 | 
						|
 | 
						|
    def _construct_dict_and_constraints(self):
 | 
						|
        """Constructs a test dictionary and a definition of constraints.
 | 
						|
 | 
						|
        :return: A (dictionary, constraint) tuple
 | 
						|
        """
 | 
						|
 | 
						|
        constraints = {'key1': {'type:values': ['val1', 'val2'],
 | 
						|
                                'required': True},
 | 
						|
                       'key2': {'type:string': None,
 | 
						|
                                'required': False},
 | 
						|
                       'key3': {'type:dict': {'k4': {'type:string': None,
 | 
						|
                                                     'required': True}},
 | 
						|
                                'required': True}}
 | 
						|
 | 
						|
        dictionary = {'key1': 'val1',
 | 
						|
                      'key2': 'a string value',
 | 
						|
                      'key3': {'k4': 'a string value'}}
 | 
						|
 | 
						|
        return dictionary, constraints
 | 
						|
 | 
						|
    def test_type_prefixing(self):
 | 
						|
        validators.add_validator('type:prefixed_type', dummy_validator)
 | 
						|
        validators.add_validator('unprefixed_type', dummy_validator)
 | 
						|
        self.assertEqual(dummy_validator,
 | 
						|
                         validators.get_validator('type:prefixed_type'))
 | 
						|
        self.assertEqual(dummy_validator,
 | 
						|
                         validators.get_validator('prefixed_type'))
 | 
						|
        self.assertEqual(dummy_validator,
 | 
						|
                         validators.get_validator('type:unprefixed_type'))
 | 
						|
        self.assertEqual(dummy_validator,
 | 
						|
                         validators.get_validator('unprefixed_type'))
 | 
						|
 | 
						|
    def test_adding_validator(self):
 | 
						|
        validators.add_validator('new_type', dummy_validator)
 | 
						|
        self.assertIn('type:new_type', validators.validators)
 | 
						|
        self.assertEqual(dummy_validator,
 | 
						|
                         validators.validators['type:new_type'])
 | 
						|
 | 
						|
    def test_get_validator_default(self):
 | 
						|
        self.assertEqual(dummy_validator,
 | 
						|
                         validators.get_validator('nope',
 | 
						|
                                                  default=dummy_validator))
 | 
						|
 | 
						|
    def test_fail_adding_duplicate_validator(self):
 | 
						|
        self.assertRaises(KeyError,
 | 
						|
                          validators.add_validator,
 | 
						|
                          'dict', lambda x: x)
 | 
						|
 | 
						|
    def test_success_adding_duplicate_validator(self):
 | 
						|
        validators.add_validator('dummy', dummy_validator)
 | 
						|
        validators.add_validator('dummy', dummy_validator)
 | 
						|
        self.assertEqual(dummy_validator, validators.get_validator('dummy'))
 | 
						|
 | 
						|
    def test_is_attr_set(self):
 | 
						|
        data = constants.ATTR_NOT_SPECIFIED
 | 
						|
        self.assertIs(validators.is_attr_set(data), False)
 | 
						|
 | 
						|
        data = None
 | 
						|
        self.assertIs(validators.is_attr_set(data), False)
 | 
						|
 | 
						|
        data = "I'm set"
 | 
						|
        self.assertIs(validators.is_attr_set(data), True)
 | 
						|
 | 
						|
    def test_validate_values(self):
 | 
						|
        # Check that validation is not performed if valid_values is not set
 | 
						|
        msg = validators.validate_values(4)
 | 
						|
        self.assertIsNone(msg)
 | 
						|
 | 
						|
        # Check that value is within valid_values
 | 
						|
        msg = validators.validate_values(4, [4, 6])
 | 
						|
        self.assertIsNone(msg)
 | 
						|
 | 
						|
        # Check that value is within valid_values
 | 
						|
        msg = validators.validate_values(4, (4, 6))
 | 
						|
        self.assertIsNone(msg)
 | 
						|
 | 
						|
        # Check that value is within valid_values with strings
 | 
						|
        msg = validators.validate_values("1", ["2", "1", "4", "5"])
 | 
						|
        self.assertIsNone(msg)
 | 
						|
 | 
						|
        # Check that value is not compatible for comparison
 | 
						|
        response = "'valid_values' does not support membership operations"
 | 
						|
        self.assertRaisesRegex(TypeError, response,
 | 
						|
                               validators.validate_values, data=None,
 | 
						|
                               valid_values=True)
 | 
						|
 | 
						|
    def test_validate_values_display(self):
 | 
						|
        # Check that value is NOT within valid_values and report values
 | 
						|
        msg = validators.validate_values(7, [4, 6],
 | 
						|
                                         valid_values_display="[4, 6]")
 | 
						|
        self.assertEqual("7 is not in [4, 6]", msg)
 | 
						|
 | 
						|
        # Check that value is NOT within valid_values and report values
 | 
						|
        msg = validators.validate_values(7, (4, 6),
 | 
						|
                                         valid_values_display="(4, 6)")
 | 
						|
        self.assertEqual("7 is not in (4, 6)", msg)
 | 
						|
 | 
						|
        # Check values with a range function showing a custom string
 | 
						|
        msg = validators.validate_values(8, range(8),
 | 
						|
                                         valid_values_display="[0..7]")
 | 
						|
        self.assertEqual("8 is not in [0..7]", msg)
 | 
						|
 | 
						|
        # Check that value is not within valid_values and custom string
 | 
						|
        msg = validators.validate_values(1, [2, 3, 4, 5],
 | 
						|
                                         valid_values_display="[2, 3, 4, 5]")
 | 
						|
        self.assertEqual("1 is not in [2, 3, 4, 5]", msg)
 | 
						|
 | 
						|
        # Check that value is not within valid_values and custom string
 | 
						|
        msg = validators.validate_values("1", ["2", "3", "4", "5"],
 | 
						|
                                         valid_values_display="'valid_values"
 | 
						|
                                         "_to_show'")
 | 
						|
        self.assertEqual("1 is not in 'valid_values_to_show'", msg)
 | 
						|
 | 
						|
        # Check that value is not comparable to valid_values and got Exception
 | 
						|
        data = 1
 | 
						|
        valid_values = '[2, 3, 4, 5]'
 | 
						|
        response = "'data' of type '%s' and 'valid_values'of type" \
 | 
						|
                   " '%s' are not compatible for comparison" % (
 | 
						|
                       type(data), type(valid_values))
 | 
						|
        self.assertRaisesRegex(TypeError, response,
 | 
						|
                               validators.validate_values, data,
 | 
						|
                               valid_values,
 | 
						|
                               valid_values_display="[2, 3, 4, 5]")
 | 
						|
 | 
						|
    def test_validate_not_empty_string(self):
 | 
						|
        msg = validators.validate_not_empty_string('    ', None)
 | 
						|
        self.assertEqual(u"'    ' Blank strings are not permitted", msg)
 | 
						|
        msg = validators.validate_not_empty_string(123, None)
 | 
						|
        self.assertEqual(u"'123' is not a valid string", msg)
 | 
						|
 | 
						|
    def test_validate_not_empty_string_or_none(self):
 | 
						|
        msg = validators.validate_not_empty_string_or_none('    ', None)
 | 
						|
        self.assertEqual(u"'    ' Blank strings are not permitted", msg)
 | 
						|
 | 
						|
        msg = validators.validate_not_empty_string_or_none(None, None)
 | 
						|
        self.assertIsNone(msg)
 | 
						|
 | 
						|
    def test_validate_string_or_none(self):
 | 
						|
        msg = validators.validate_string_or_none('test', None)
 | 
						|
        self.assertIsNone(msg)
 | 
						|
 | 
						|
        msg = validators.validate_string_or_none(None, None)
 | 
						|
        self.assertIsNone(msg)
 | 
						|
 | 
						|
    def test_validate_string(self):
 | 
						|
        msg = validators.validate_string(None, None)
 | 
						|
        self.assertEqual("'None' is not a valid string", msg)
 | 
						|
 | 
						|
        # 0 == len(data) == max_len
 | 
						|
        msg = validators.validate_string("", 0)
 | 
						|
        self.assertIsNone(msg)
 | 
						|
 | 
						|
        # 0 == len(data) < max_len
 | 
						|
        msg = validators.validate_string("", 9)
 | 
						|
        self.assertIsNone(msg)
 | 
						|
 | 
						|
        # 0 < len(data) < max_len
 | 
						|
        msg = validators.validate_string("123456789", 10)
 | 
						|
        self.assertIsNone(msg)
 | 
						|
 | 
						|
        # 0 < len(data) == max_len
 | 
						|
        msg = validators.validate_string("123456789", 9)
 | 
						|
        self.assertIsNone(msg)
 | 
						|
 | 
						|
        # 0 < max_len < len(data)
 | 
						|
        msg = validators.validate_string("1234567890", 9)
 | 
						|
        self.assertEqual("'1234567890' exceeds maximum length of 9", msg)
 | 
						|
 | 
						|
        msg = validators.validate_string("123456789", None)
 | 
						|
        self.assertIsNone(msg)
 | 
						|
 | 
						|
    def test_validate_list_of_unique_strings(self):
 | 
						|
        data = "TEST"
 | 
						|
        msg = validators.validate_list_of_unique_strings(data, None)
 | 
						|
        self.assertEqual("'TEST' is not a list", msg)
 | 
						|
 | 
						|
        data = ["TEST01", "TEST02", "TEST01"]
 | 
						|
        msg = validators.validate_list_of_unique_strings(data, None)
 | 
						|
        self.assertEqual(
 | 
						|
            "Duplicate items in the list: 'TEST01, TEST02, TEST01'", msg)
 | 
						|
 | 
						|
        data = ["12345678", "123456789"]
 | 
						|
        msg = validators.validate_list_of_unique_strings(data, 8)
 | 
						|
        self.assertEqual("'123456789' exceeds maximum length of 8", msg)
 | 
						|
 | 
						|
        data = ["TEST01", "TEST02", "TEST03"]
 | 
						|
        msg = validators.validate_list_of_unique_strings(data, None)
 | 
						|
        self.assertIsNone(msg)
 | 
						|
 | 
						|
    def test_validate_boolean(self):
 | 
						|
        msg = validators.validate_boolean(True)
 | 
						|
        self.assertIsNone(msg)
 | 
						|
        msg = validators.validate_boolean(0)
 | 
						|
        self.assertIsNone(msg)
 | 
						|
        msg = validators.validate_boolean("false")
 | 
						|
        self.assertIsNone(msg)
 | 
						|
        msg = validators.validate_boolean("fasle")
 | 
						|
        self.assertEqual("'fasle' is not a valid boolean value", msg)
 | 
						|
 | 
						|
    def test_validate_integer(self):
 | 
						|
        msg = validators.validate_integer(1)
 | 
						|
        self.assertIsNone(msg)
 | 
						|
        msg = validators.validate_integer(0.1)
 | 
						|
        self.assertEqual("'0.1' is not an integer", msg)
 | 
						|
        msg = validators.validate_integer("1")
 | 
						|
        self.assertIsNone(msg)
 | 
						|
        msg = validators.validate_integer("0.1")
 | 
						|
        self.assertEqual("'0.1' is not an integer", msg)
 | 
						|
        msg = validators.validate_integer(True)
 | 
						|
        self.assertEqual("'True' is not an integer:boolean", msg)
 | 
						|
        msg = validators.validate_integer(False)
 | 
						|
        self.assertEqual("'False' is not an integer:boolean", msg)
 | 
						|
        msg = validators.validate_integer(float('Inf'))
 | 
						|
        self.assertEqual("'inf' is not an integer", msg)
 | 
						|
        msg = validators.validate_integer(None)
 | 
						|
        self.assertEqual("'None' is not an integer", msg)
 | 
						|
 | 
						|
    def test_validate_integer_values(self):
 | 
						|
        msg = validators.validate_integer(2, [2, 3, 4, 5])
 | 
						|
        self.assertIsNone(msg)
 | 
						|
        msg = validators.validate_integer(1, [2, 3, 4, 5])
 | 
						|
        self.assertEqual("1 is not in valid_values", msg)
 | 
						|
 | 
						|
    def test_validate_no_whitespace(self):
 | 
						|
        data = 'no_white_space'
 | 
						|
        result = validators.validate_no_whitespace(data)
 | 
						|
        self.assertEqual(data, result)
 | 
						|
 | 
						|
        self.assertRaises(n_exc.InvalidInput,
 | 
						|
                          validators.validate_no_whitespace,
 | 
						|
                          'i have whitespace')
 | 
						|
 | 
						|
        self.assertRaises(n_exc.InvalidInput,
 | 
						|
                          validators.validate_no_whitespace,
 | 
						|
                          'i\thave\twhitespace')
 | 
						|
 | 
						|
        for ws in string.whitespace:
 | 
						|
            self.assertRaises(n_exc.InvalidInput,
 | 
						|
                              validators.validate_no_whitespace,
 | 
						|
                              '%swhitespace-at-head' % ws)
 | 
						|
            self.assertRaises(n_exc.InvalidInput,
 | 
						|
                              validators.validate_no_whitespace,
 | 
						|
                              'whitespace-at-tail%s' % ws)
 | 
						|
 | 
						|
    def test_validate_range(self):
 | 
						|
        msg = validators.validate_range(1, [1, 9])
 | 
						|
        self.assertIsNone(msg)
 | 
						|
 | 
						|
        msg = validators.validate_range(5, [1, 9])
 | 
						|
        self.assertIsNone(msg)
 | 
						|
 | 
						|
        msg = validators.validate_range(9, [1, 9])
 | 
						|
        self.assertIsNone(msg)
 | 
						|
 | 
						|
        msg = validators.validate_range(1, (1, 9))
 | 
						|
        self.assertIsNone(msg)
 | 
						|
 | 
						|
        msg = validators.validate_range(5, (1, 9))
 | 
						|
        self.assertIsNone(msg)
 | 
						|
 | 
						|
        msg = validators.validate_range(9, (1, 9))
 | 
						|
        self.assertIsNone(msg)
 | 
						|
 | 
						|
        msg = validators.validate_range(0, [1, 9])
 | 
						|
        self.assertEqual("'0' is too small - must be at least '1'", msg)
 | 
						|
 | 
						|
        msg = validators.validate_range(10, (1, 9))
 | 
						|
        self.assertEqual("'10' is too large - must be no larger than '9'", msg)
 | 
						|
 | 
						|
        msg = validators.validate_range("bogus", (1, 9))
 | 
						|
        self.assertEqual("'bogus' is not an integer", msg)
 | 
						|
 | 
						|
        msg = validators.validate_range(10, (validators.UNLIMITED,
 | 
						|
                                             validators.UNLIMITED))
 | 
						|
        self.assertIsNone(msg)
 | 
						|
 | 
						|
        msg = validators.validate_range(10, (1, validators.UNLIMITED))
 | 
						|
        self.assertIsNone(msg)
 | 
						|
 | 
						|
        msg = validators.validate_range(1, (validators.UNLIMITED, 9))
 | 
						|
        self.assertIsNone(msg)
 | 
						|
 | 
						|
        msg = validators.validate_range(-1, (0, validators.UNLIMITED))
 | 
						|
        self.assertEqual("'-1' is too small - must be at least '0'", msg)
 | 
						|
 | 
						|
        msg = validators.validate_range(10, (validators.UNLIMITED, 9))
 | 
						|
        self.assertEqual("'10' is too large - must be no larger than '9'", msg)
 | 
						|
 | 
						|
    def _test_validate_mac_address(self, validator, allow_none=False):
 | 
						|
        mac_addr = "ff:16:3e:4f:00:00"
 | 
						|
        msg = validator(mac_addr)
 | 
						|
        self.assertIsNone(msg)
 | 
						|
 | 
						|
        mac_addr = "ffa:16:3e:4f:00:00"
 | 
						|
        msg = validator(mac_addr)
 | 
						|
        err_msg = "'%s' is not a valid MAC address"
 | 
						|
        self.assertEqual(err_msg % mac_addr, msg)
 | 
						|
 | 
						|
        for invalid_mac_addr in constants.INVALID_MAC_ADDRESSES:
 | 
						|
            msg = validator(invalid_mac_addr)
 | 
						|
            self.assertEqual(err_msg % invalid_mac_addr, msg)
 | 
						|
 | 
						|
        mac_addr = "123"
 | 
						|
        msg = validator(mac_addr)
 | 
						|
        self.assertEqual(err_msg % mac_addr, msg)
 | 
						|
 | 
						|
        mac_addr = None
 | 
						|
        msg = validator(mac_addr)
 | 
						|
        if allow_none:
 | 
						|
            self.assertIsNone(msg)
 | 
						|
        else:
 | 
						|
            self.assertEqual(err_msg % mac_addr, msg)
 | 
						|
 | 
						|
        mac_addr = "ff:16:3e:4f:00:00\r"
 | 
						|
        msg = validator(mac_addr)
 | 
						|
        self.assertEqual(err_msg % mac_addr, msg)
 | 
						|
 | 
						|
    def test_validate_mac_address(self):
 | 
						|
        self._test_validate_mac_address(validators.validate_mac_address)
 | 
						|
 | 
						|
    def test_validate_mac_address_or_none(self):
 | 
						|
        self._test_validate_mac_address(
 | 
						|
            validators.validate_mac_address_or_none, allow_none=True)
 | 
						|
 | 
						|
    def test_validate_ip_address(self):
 | 
						|
        ip_addr = '1.1.1.1'
 | 
						|
        msg = validators.validate_ip_address(ip_addr)
 | 
						|
        self.assertIsNone(msg)
 | 
						|
 | 
						|
        ip_addr = '1111.1.1.1'
 | 
						|
        msg = validators.validate_ip_address(ip_addr)
 | 
						|
        self.assertEqual("'%s' is not a valid IP address" % ip_addr, msg)
 | 
						|
 | 
						|
        # Depending on platform to run UTs, this case might or might not be
 | 
						|
        # an equivalent to test_validate_ip_address_bsd.
 | 
						|
        ip_addr = '1' * 59
 | 
						|
        msg = validators.validate_ip_address(ip_addr)
 | 
						|
        self.assertEqual("'%s' is not a valid IP address" % ip_addr, msg)
 | 
						|
 | 
						|
        ip_addr = '1.1.1.1 has whitespace'
 | 
						|
        msg = validators.validate_ip_address(ip_addr)
 | 
						|
        self.assertEqual("'%s' is not a valid IP address" % ip_addr, msg)
 | 
						|
 | 
						|
        ip_addr = '111.1.1.1\twhitespace'
 | 
						|
        msg = validators.validate_ip_address(ip_addr)
 | 
						|
        self.assertEqual("'%s' is not a valid IP address" % ip_addr, msg)
 | 
						|
 | 
						|
        ip_addr = '111.1.1.1\nwhitespace'
 | 
						|
        msg = validators.validate_ip_address(ip_addr)
 | 
						|
        self.assertEqual("'%s' is not a valid IP address" % ip_addr, msg)
 | 
						|
 | 
						|
        for ws in string.whitespace:
 | 
						|
            ip_addr = '%s111.1.1.1' % ws
 | 
						|
            msg = validators.validate_ip_address(ip_addr)
 | 
						|
            self.assertEqual("'%s' is not a valid IP address" % ip_addr, msg)
 | 
						|
 | 
						|
        for ws in string.whitespace:
 | 
						|
            ip_addr = '111.1.1.1%s' % ws
 | 
						|
            msg = validators.validate_ip_address(ip_addr)
 | 
						|
            self.assertEqual("'%s' is not a valid IP address" % ip_addr, msg)
 | 
						|
 | 
						|
    def test_validate_ip_address_with_leading_zero(self):
 | 
						|
        ip_addr = '1.1.1.01'
 | 
						|
        expected_msg = ("'%(data)s' is not an accepted IP address, "
 | 
						|
                        "'%(ip)s' is recommended")
 | 
						|
        msg = validators.validate_ip_address(ip_addr)
 | 
						|
        self.assertEqual(expected_msg % {"data": ip_addr, "ip": '1.1.1.1'},
 | 
						|
                         msg)
 | 
						|
 | 
						|
        ip_addr = '1.1.1.011'
 | 
						|
        msg = validators.validate_ip_address(ip_addr)
 | 
						|
        self.assertEqual(expected_msg % {"data": ip_addr, "ip": '1.1.1.11'},
 | 
						|
                         msg)
 | 
						|
 | 
						|
        ip_addr = '1.1.1.09'
 | 
						|
        msg = validators.validate_ip_address(ip_addr)
 | 
						|
        self.assertEqual(expected_msg % {"data": ip_addr, "ip": '1.1.1.9'},
 | 
						|
                         msg)
 | 
						|
 | 
						|
        ip_addr = "fe80:0:0:0:0:0:0:0001"
 | 
						|
        msg = validators.validate_ip_address(ip_addr)
 | 
						|
        self.assertIsNone(msg)
 | 
						|
 | 
						|
    def test_validate_ip_address_bsd(self):
 | 
						|
        # NOTE(yamamoto):  On NetBSD and OS X, netaddr.IPAddress() accepts
 | 
						|
        # '1' * 59 as a valid address.  The behaviour is inherited from
 | 
						|
        # libc behaviour there.  This test ensures that our validator reject
 | 
						|
        # such addresses on such platforms by mocking netaddr to emulate
 | 
						|
        # the behaviour.
 | 
						|
        ip_addr = '1' * 59
 | 
						|
        with mock.patch('netaddr.IPAddress') as ip_address_cls:
 | 
						|
            msg = validators.validate_ip_address(ip_addr)
 | 
						|
        ip_address_cls.assert_called_once_with(ip_addr,
 | 
						|
                                               flags=netaddr.core.ZEROFILL)
 | 
						|
        self.assertEqual("'%s' is not a valid IP address" % ip_addr, msg)
 | 
						|
 | 
						|
    def test_validate_ip_pools(self):
 | 
						|
        pools = [[{'end': '10.0.0.254'}],
 | 
						|
                 [{'start': '10.0.0.254'}],
 | 
						|
                 [{'start': '1000.0.0.254',
 | 
						|
                   'end': '1.1.1.1'}],
 | 
						|
                 [{'start': '10.0.0.2', 'end': '10.0.0.254',
 | 
						|
                   'forza': 'juve'}],
 | 
						|
                 [{'start': '10.0.0.2', 'end': '10.0.0.254'},
 | 
						|
                  {'end': '10.0.0.254'}],
 | 
						|
                 [None],
 | 
						|
                 None]
 | 
						|
        for pool in pools:
 | 
						|
            msg = validators.validate_ip_pools(pool)
 | 
						|
            self.assertIsNotNone(msg)
 | 
						|
 | 
						|
        pools = [[{'end': '10.0.0.254', 'start': '10.0.0.2'},
 | 
						|
                  {'start': '11.0.0.2', 'end': '11.1.1.1'}],
 | 
						|
                 [{'start': '11.0.0.2', 'end': '11.0.0.100'}]]
 | 
						|
        for pool in pools:
 | 
						|
            msg = validators.validate_ip_pools(pool)
 | 
						|
            self.assertIsNone(msg)
 | 
						|
 | 
						|
        invalid_ip = '10.0.0.2\r'
 | 
						|
        pools = [[{'end': '10.0.0.254', 'start': invalid_ip}]]
 | 
						|
        for pool in pools:
 | 
						|
            msg = validators.validate_ip_pools(pool)
 | 
						|
            self.assertEqual("'%s' is not a valid IP address" % invalid_ip,
 | 
						|
                             msg)
 | 
						|
 | 
						|
    def test_validate_fixed_ips(self):
 | 
						|
        fixed_ips = [
 | 
						|
            {'data': [{'subnet_id': '00000000-ffff-ffff-ffff-000000000000',
 | 
						|
                       'ip_address': '1111.1.1.1'}],
 | 
						|
             'error_msg': "'1111.1.1.1' is not a valid IP address"},
 | 
						|
            {'data': [{'subnet_id': 'invalid',
 | 
						|
                       'ip_address': '1.1.1.1'}],
 | 
						|
             'error_msg': "'invalid' is not a valid UUID"},
 | 
						|
            {'data': None,
 | 
						|
             'error_msg': "Invalid data format for fixed IP: 'None'"},
 | 
						|
            {'data': "1.1.1.1",
 | 
						|
             'error_msg': "Invalid data format for fixed IP: '1.1.1.1'"},
 | 
						|
            {'data': ['00000000-ffff-ffff-ffff-000000000000', '1.1.1.1'],
 | 
						|
             'error_msg': "Invalid data format for fixed IP: "
 | 
						|
                          "'00000000-ffff-ffff-ffff-000000000000'"},
 | 
						|
            {'data': [['00000000-ffff-ffff-ffff-000000000000', '1.1.1.1']],
 | 
						|
             'error_msg': "Invalid data format for fixed IP: "
 | 
						|
                          "'['00000000-ffff-ffff-ffff-000000000000', "
 | 
						|
                          "'1.1.1.1']'"},
 | 
						|
            {'data': [{'subnet_id': '00000000-0fff-ffff-ffff-000000000000',
 | 
						|
                       'ip_address': '1.1.1.1'},
 | 
						|
                      {'subnet_id': '00000000-ffff-ffff-ffff-000000000000',
 | 
						|
                       'ip_address': '1.1.1.1'}],
 | 
						|
             'error_msg': "Duplicate IP address '1.1.1.1'"}]
 | 
						|
        for fixed in fixed_ips:
 | 
						|
            msg = validators.validate_fixed_ips(fixed['data'])
 | 
						|
            self.assertEqual(fixed['error_msg'], msg)
 | 
						|
 | 
						|
        fixed_ips = [[{'subnet_id': '00000000-ffff-ffff-ffff-000000000000',
 | 
						|
                       'ip_address': '1.1.1.1'}],
 | 
						|
                     [{'subnet_id': '00000000-0fff-ffff-ffff-000000000000',
 | 
						|
                       'ip_address': '1.1.1.1'},
 | 
						|
                      {'subnet_id': '00000000-ffff-ffff-ffff-000000000000',
 | 
						|
                       'ip_address': '1.1.1.2'}]]
 | 
						|
        for fixed in fixed_ips:
 | 
						|
            msg = validators.validate_fixed_ips(fixed)
 | 
						|
            self.assertIsNone(msg)
 | 
						|
 | 
						|
    def test_validate_nameservers(self):
 | 
						|
        ns_pools = [['1.1.1.2', '1.1.1.2'],
 | 
						|
                    ['www.hostname.com', 'www.hostname.com'],
 | 
						|
                    ['1000.0.0.1'],
 | 
						|
                    ['www.hostname.com'],
 | 
						|
                    ['www.great.marathons.to.travel'],
 | 
						|
                    ['valid'],
 | 
						|
                    ['77.hostname.com'],
 | 
						|
                    ['1' * 59],
 | 
						|
                    ['www.internal.hostname.com'],
 | 
						|
                    None]
 | 
						|
 | 
						|
        for ns in ns_pools:
 | 
						|
            msg = validators.validate_nameservers(ns, None)
 | 
						|
            self.assertIsNotNone(msg)
 | 
						|
 | 
						|
        ns_pools = [['100.0.0.2'],
 | 
						|
                    ['1.1.1.1', '1.1.1.2']]
 | 
						|
 | 
						|
        for ns in ns_pools:
 | 
						|
            msg = validators.validate_nameservers(ns, None)
 | 
						|
            self.assertIsNone(msg)
 | 
						|
 | 
						|
    def test_validate_hostroutes(self):
 | 
						|
        hostroute_pools = [[{'destination': '100.0.0.0/24'}],
 | 
						|
                           [{'nexthop': '10.0.2.20'}],
 | 
						|
                           [{'nexthop': '10.0.2.20',
 | 
						|
                             'forza': 'juve',
 | 
						|
                             'destination': '100.0.0.0/8'}],
 | 
						|
                           [{'nexthop': '1110.0.2.20',
 | 
						|
                             'destination': '100.0.0.0/8'}],
 | 
						|
                           [{'nexthop': '10.0.2.20',
 | 
						|
                             'destination': '100.0.0.0'}],
 | 
						|
                           [{'nexthop': '10.0.2.20',
 | 
						|
                             'destination': '100.0.0.0/8'},
 | 
						|
                            {'nexthop': '10.0.2.20',
 | 
						|
                             'destination': '100.0.0.0/8'}],
 | 
						|
                           [None],
 | 
						|
                           None]
 | 
						|
        for host_routes in hostroute_pools:
 | 
						|
            msg = validators.validate_hostroutes(host_routes, None)
 | 
						|
            self.assertIsNotNone(msg)
 | 
						|
 | 
						|
        hostroute_pools = [[{'destination': '100.0.0.0/24',
 | 
						|
                             'nexthop': '10.0.2.20'}],
 | 
						|
                           [{'nexthop': '10.0.2.20',
 | 
						|
                             'destination': '100.0.0.0/8'},
 | 
						|
                            {'nexthop': '10.0.2.20',
 | 
						|
                             'destination': '101.0.0.0/8'}]]
 | 
						|
        for host_routes in hostroute_pools:
 | 
						|
            msg = validators.validate_hostroutes(host_routes, None)
 | 
						|
            self.assertIsNone(msg)
 | 
						|
 | 
						|
    def test_validate_ip_address_or_none(self):
 | 
						|
        ip_addr = None
 | 
						|
        msg = validators.validate_ip_address_or_none(ip_addr)
 | 
						|
        self.assertIsNone(msg)
 | 
						|
 | 
						|
        ip_addr = '1.1.1.1'
 | 
						|
        msg = validators.validate_ip_address_or_none(ip_addr)
 | 
						|
        self.assertIsNone(msg)
 | 
						|
 | 
						|
        ip_addr = '1111.1.1.1'
 | 
						|
        msg = validators.validate_ip_address_or_none(ip_addr)
 | 
						|
        self.assertEqual("'%s' is not a valid IP address" % ip_addr, msg)
 | 
						|
 | 
						|
    def test_uuid_pattern(self):
 | 
						|
        data = 'garbage'
 | 
						|
        msg = validators.validate_regex(data, constants.UUID_PATTERN)
 | 
						|
        self.assertIsNotNone(msg)
 | 
						|
 | 
						|
        data = '00000000-ffff-ffff-ffff-000000000000'
 | 
						|
        msg = validators.validate_regex(data, constants.UUID_PATTERN)
 | 
						|
        self.assertIsNone(msg)
 | 
						|
 | 
						|
    def test_mac_pattern(self):
 | 
						|
        # Valid - 3 octets
 | 
						|
        base_mac = "fa:16:3e:00:00:00"
 | 
						|
        msg = validators.validate_regex(base_mac, validators.MAC_PATTERN)
 | 
						|
        self.assertIsNone(msg)
 | 
						|
 | 
						|
        # Valid - 4 octets
 | 
						|
        base_mac = "fa:16:3e:4f:00:00"
 | 
						|
        msg = validators.validate_regex(base_mac, validators.MAC_PATTERN)
 | 
						|
        self.assertIsNone(msg)
 | 
						|
 | 
						|
        # Invalid - not unicast
 | 
						|
        base_mac = "01:16:3e:4f:00:00"
 | 
						|
        msg = validators.validate_regex(base_mac, validators.MAC_PATTERN)
 | 
						|
        self.assertIsNotNone(msg)
 | 
						|
 | 
						|
        # Invalid - invalid format
 | 
						|
        base_mac = "a:16:3e:4f:00:00"
 | 
						|
        msg = validators.validate_regex(base_mac, validators.MAC_PATTERN)
 | 
						|
        self.assertIsNotNone(msg)
 | 
						|
 | 
						|
        # Invalid - invalid format
 | 
						|
        base_mac = "ffa:16:3e:4f:00:00"
 | 
						|
        msg = validators.validate_regex(base_mac, validators.MAC_PATTERN)
 | 
						|
        self.assertIsNotNone(msg)
 | 
						|
 | 
						|
        # Invalid - invalid format
 | 
						|
        base_mac = "01163e4f0000"
 | 
						|
        msg = validators.validate_regex(base_mac, validators.MAC_PATTERN)
 | 
						|
        self.assertIsNotNone(msg)
 | 
						|
 | 
						|
        # Invalid - invalid format
 | 
						|
        base_mac = "01-16-3e-4f-00-00"
 | 
						|
        msg = validators.validate_regex(base_mac, validators.MAC_PATTERN)
 | 
						|
        self.assertIsNotNone(msg)
 | 
						|
 | 
						|
        # Invalid - invalid format
 | 
						|
        base_mac = "00:16:3:f:00:00"
 | 
						|
        msg = validators.validate_regex(base_mac, validators.MAC_PATTERN)
 | 
						|
        self.assertIsNotNone(msg)
 | 
						|
 | 
						|
        # Invalid - invalid format
 | 
						|
        base_mac = "12:3:4:5:67:89ab"
 | 
						|
        msg = validators.validate_regex(base_mac, validators.MAC_PATTERN)
 | 
						|
        self.assertIsNotNone(msg)
 | 
						|
 | 
						|
    def _test_validate_subnet(self, validator, allow_none=False):
 | 
						|
        # Valid - IPv4
 | 
						|
        cidr = "10.0.2.0/24"
 | 
						|
        msg = validator(cidr, None)
 | 
						|
        self.assertIsNone(msg)
 | 
						|
 | 
						|
        # Valid - IPv6 without final octets
 | 
						|
        cidr = "fe80::/24"
 | 
						|
        msg = validator(cidr, None)
 | 
						|
        self.assertIsNone(msg)
 | 
						|
 | 
						|
        # Valid - IPv6 with final octets
 | 
						|
        cidr = "fe80::/24"
 | 
						|
        msg = validator(cidr, None)
 | 
						|
        self.assertIsNone(msg)
 | 
						|
 | 
						|
        # Valid - uncompressed ipv6 address
 | 
						|
        cidr = "fe80:0:0:0:0:0:0:0/128"
 | 
						|
        msg = validator(cidr, None)
 | 
						|
        self.assertIsNone(msg)
 | 
						|
 | 
						|
        # Valid - ipv6 address with multiple consecutive zero
 | 
						|
        cidr = "2001:0db8:0:0:1::1/128"
 | 
						|
        msg = validator(cidr, None)
 | 
						|
        self.assertIsNone(msg)
 | 
						|
 | 
						|
        # Valid - ipv6 address with multiple consecutive zero
 | 
						|
        cidr = "2001:0db8::1:0:0:1/128"
 | 
						|
        msg = validator(cidr, None)
 | 
						|
        self.assertIsNone(msg)
 | 
						|
 | 
						|
        # Valid - ipv6 address with multiple consecutive zero
 | 
						|
        cidr = "2001::0:1:0:0:1100/120"
 | 
						|
        msg = validator(cidr, None)
 | 
						|
        self.assertIsNone(msg)
 | 
						|
 | 
						|
        # Invalid - abbreviated ipv4 address
 | 
						|
        cidr = "10/24"
 | 
						|
        msg = validator(cidr, None)
 | 
						|
        error = _("'%(data)s' isn't a recognized IP subnet cidr,"
 | 
						|
                  " '%(cidr)s' is recommended") % {"data": cidr,
 | 
						|
                                                   "cidr": "10.0.0.0/24"}
 | 
						|
        self.assertEqual(error, msg)
 | 
						|
 | 
						|
        # Invalid - IPv4 missing mask
 | 
						|
        cidr = "10.0.2.0"
 | 
						|
        msg = validator(cidr, None)
 | 
						|
        error = _("'%(data)s' isn't a recognized IP subnet cidr,"
 | 
						|
                  " '%(cidr)s' is recommended") % {"data": cidr,
 | 
						|
                                                   "cidr": "10.0.2.0/32"}
 | 
						|
        self.assertEqual(error, msg)
 | 
						|
 | 
						|
        # Valid - IPv4 with non-zero masked bits is ok
 | 
						|
        for i in range(1, 255):
 | 
						|
            cidr = "192.168.1.%s/24" % i
 | 
						|
            msg = validator(cidr, None)
 | 
						|
            self.assertIsNone(msg)
 | 
						|
 | 
						|
        # Invalid - IPv6 without final octets, missing mask
 | 
						|
        cidr = "fe80::"
 | 
						|
        msg = validator(cidr, None)
 | 
						|
        error = _("'%(data)s' isn't a recognized IP subnet cidr,"
 | 
						|
                  " '%(cidr)s' is recommended") % {"data": cidr,
 | 
						|
                                                   "cidr": "fe80::/128"}
 | 
						|
        self.assertEqual(error, msg)
 | 
						|
 | 
						|
        # Invalid - IPv6 with final octets, missing mask
 | 
						|
        cidr = "fe80::0"
 | 
						|
        msg = validator(cidr, None)
 | 
						|
        error = _("'%(data)s' isn't a recognized IP subnet cidr,"
 | 
						|
                  " '%(cidr)s' is recommended") % {"data": cidr,
 | 
						|
                                                   "cidr": "fe80::/128"}
 | 
						|
        self.assertEqual(error, msg)
 | 
						|
 | 
						|
        # Invalid - Address format error
 | 
						|
        cidr = 'invalid'
 | 
						|
        msg = validator(cidr, None)
 | 
						|
        error = "'%s' is not a valid IP subnet" % cidr
 | 
						|
        self.assertEqual(error, msg)
 | 
						|
 | 
						|
        cidr = None
 | 
						|
        msg = validator(cidr, None)
 | 
						|
        if allow_none:
 | 
						|
            self.assertIsNone(msg)
 | 
						|
        else:
 | 
						|
            error = "'%s' is not a valid IP subnet" % cidr
 | 
						|
            self.assertEqual(error, msg)
 | 
						|
 | 
						|
        # Invalid - IPv4 with trailing CR
 | 
						|
        cidr = "10.0.2.0/24\r"
 | 
						|
        msg = validator(cidr, None)
 | 
						|
        error = "'%s' is not a valid IP subnet" % cidr
 | 
						|
        self.assertEqual(error, msg)
 | 
						|
 | 
						|
    def test_validate_subnet(self):
 | 
						|
        self._test_validate_subnet(validators.validate_subnet)
 | 
						|
 | 
						|
    def test_validate_subnet_or_none(self):
 | 
						|
        self._test_validate_subnet(validators.validate_subnet_or_none,
 | 
						|
                                   allow_none=True)
 | 
						|
 | 
						|
    def test_validate_subnet_list(self):
 | 
						|
        msg = validators.validate_subnet_list('abc')
 | 
						|
        self.assertEqual(u"'abc' is not a list", msg)
 | 
						|
        msg = validators.validate_subnet_list(['10.1.0.0/24',
 | 
						|
                                               '10.2.0.0/24',
 | 
						|
                                               '10.1.0.0/24'])
 | 
						|
        self.assertEqual(u"Duplicate items in the list: '10.1.0.0/24, "
 | 
						|
                         u"10.2.0.0/24, 10.1.0.0/24'", msg)
 | 
						|
        msg = validators.validate_subnet_list(['10.1.0.0/24', '10.2.0.0'])
 | 
						|
        self.assertEqual(u"'10.2.0.0' isn't a recognized IP subnet cidr, "
 | 
						|
                         u"'10.2.0.0/32' is recommended", msg)
 | 
						|
 | 
						|
    def _test_validate_regex(self, validator, allow_none=False):
 | 
						|
        pattern = '[hc]at'
 | 
						|
 | 
						|
        data = None
 | 
						|
        msg = validator(data, pattern)
 | 
						|
        if allow_none:
 | 
						|
            self.assertIsNone(msg)
 | 
						|
        else:
 | 
						|
            self.assertEqual("'None' is not a valid input", msg)
 | 
						|
 | 
						|
        data = 'bat'
 | 
						|
        msg = validator(data, pattern)
 | 
						|
        self.assertEqual("'%s' is not a valid input" % data, msg)
 | 
						|
 | 
						|
        data = 'hat'
 | 
						|
        msg = validator(data, pattern)
 | 
						|
        self.assertIsNone(msg)
 | 
						|
 | 
						|
        data = 'cat'
 | 
						|
        msg = validator(data, pattern)
 | 
						|
        self.assertIsNone(msg)
 | 
						|
 | 
						|
    def test_validate_regex(self):
 | 
						|
        self._test_validate_regex(validators.validate_regex)
 | 
						|
 | 
						|
    def test_validate_regex_or_none(self):
 | 
						|
        self._test_validate_regex(validators.validate_regex_or_none,
 | 
						|
                                  allow_none=True)
 | 
						|
 | 
						|
    def test_validate_subnetpool_id(self):
 | 
						|
        msg = validators.validate_subnetpool_id(constants.IPV6_PD_POOL_ID)
 | 
						|
        self.assertIsNone(msg)
 | 
						|
 | 
						|
        msg = validators.validate_subnetpool_id(
 | 
						|
            '00000000-ffff-ffff-ffff-000000000000')
 | 
						|
        self.assertIsNone(msg)
 | 
						|
 | 
						|
    def test_validate_subnetpool_id_or_none(self):
 | 
						|
        msg = validators.validate_subnetpool_id_or_none(None)
 | 
						|
        self.assertIsNone(msg)
 | 
						|
 | 
						|
        msg = validators.validate_subnetpool_id_or_none(
 | 
						|
            '00000000-ffff-ffff-ffff-000000000000')
 | 
						|
        self.assertIsNone(msg)
 | 
						|
 | 
						|
    def test_validate_uuid(self):
 | 
						|
        invalid_uuids = [None,
 | 
						|
                         123,
 | 
						|
                         '123',
 | 
						|
                         't5069610-744b-42a7-8bd8-ceac1a229cd4',
 | 
						|
                         'e5069610-744bb-42a7-8bd8-ceac1a229cd4']
 | 
						|
        for uuid in invalid_uuids:
 | 
						|
            msg = validators.validate_uuid(uuid)
 | 
						|
            error = "'%s' is not a valid UUID" % uuid
 | 
						|
            self.assertEqual(error, msg)
 | 
						|
 | 
						|
        msg = validators.validate_uuid('00000000-ffff-ffff-ffff-000000000000')
 | 
						|
        self.assertIsNone(msg)
 | 
						|
 | 
						|
    def test_validate_uuid_list(self):
 | 
						|
        bad_uuid_list = ['00000000-ffff-ffff-ffff-000000000000',
 | 
						|
                         '00000000-ffff-ffff-ffff-000000000001',
 | 
						|
                         '123']
 | 
						|
        msg = validators.validate_uuid_list(bad_uuid_list,
 | 
						|
                                            valid_values='parameter not used')
 | 
						|
        error = "'%s' is not a valid UUID" % bad_uuid_list[2]
 | 
						|
        self.assertEqual(error, msg)
 | 
						|
 | 
						|
        good_uuid_list = ['00000000-ffff-ffff-ffff-000000000000',
 | 
						|
                          '00000000-ffff-ffff-ffff-000000000001']
 | 
						|
        msg = validators.validate_uuid_list(good_uuid_list,
 | 
						|
                                            valid_values='parameter not used')
 | 
						|
        self.assertIsNone(msg)
 | 
						|
 | 
						|
    def test__validate_list_of_items(self):
 | 
						|
        # check not a list
 | 
						|
        items = [None,
 | 
						|
                 123,
 | 
						|
                 'e5069610-744b-42a7-8bd8-ceac1a229cd4',
 | 
						|
                 '12345678123456781234567812345678',
 | 
						|
                 {'uuid': 'e5069610-744b-42a7-8bd8-ceac1a229cd4'}]
 | 
						|
        for item in items:
 | 
						|
            msg = validators._validate_list_of_items(mock.Mock(), item)
 | 
						|
            error = "'%s' is not a list" % item
 | 
						|
            self.assertEqual(error, msg)
 | 
						|
 | 
						|
        # check duplicate items in a list
 | 
						|
        duplicate_items = ['e5069610-744b-42a7-8bd8-ceac1a229cd4',
 | 
						|
                           'f3eeab00-8367-4524-b662-55e64d4cacb5',
 | 
						|
                           'e5069610-744b-42a7-8bd8-ceac1a229cd4']
 | 
						|
        msg = validators._validate_list_of_items(mock.Mock(), duplicate_items)
 | 
						|
        error = ("Duplicate items in the list: "
 | 
						|
                 "'%s'" % ', '.join(duplicate_items))
 | 
						|
        self.assertEqual(error, msg)
 | 
						|
 | 
						|
        # check valid lists
 | 
						|
        valid_lists = [[],
 | 
						|
                       [1, 2, 3],
 | 
						|
                       ['a', 'b', 'c']]
 | 
						|
        for list_obj in valid_lists:
 | 
						|
            msg = validators._validate_list_of_items(
 | 
						|
                mock.Mock(return_value=None), list_obj)
 | 
						|
            self.assertIsNone(msg)
 | 
						|
 | 
						|
    def test_validate_dict_type(self):
 | 
						|
        for value in (None, True, '1', []):
 | 
						|
            self.assertEqual("'%s' is not a dictionary" % value,
 | 
						|
                             validators.validate_dict(value))
 | 
						|
 | 
						|
    def test_validate_dict_without_constraints(self):
 | 
						|
        msg = validators.validate_dict({})
 | 
						|
        self.assertIsNone(msg)
 | 
						|
 | 
						|
        # Validate a dictionary without constraints.
 | 
						|
        msg = validators.validate_dict({'key': 'value'})
 | 
						|
        self.assertIsNone(msg)
 | 
						|
 | 
						|
    def test_validate_a_valid_dict_with_constraints(self):
 | 
						|
        dictionary, constraints = self._construct_dict_and_constraints()
 | 
						|
 | 
						|
        msg = validators.validate_dict(dictionary, constraints)
 | 
						|
        self.assertIsNone(msg, 'Validation of a valid dictionary failed.')
 | 
						|
 | 
						|
    def test_validate_dict_with_invalid_validator(self):
 | 
						|
        dictionary, constraints = self._construct_dict_and_constraints()
 | 
						|
 | 
						|
        constraints['key1'] = {'type:unsupported': None, 'required': True}
 | 
						|
        msg = validators.validate_dict(dictionary, constraints)
 | 
						|
        self.assertEqual("Validator 'type:unsupported' does not exist.", msg)
 | 
						|
 | 
						|
    def test_validate_dict_not_required_keys(self):
 | 
						|
        dictionary, constraints = self._construct_dict_and_constraints()
 | 
						|
 | 
						|
        del dictionary['key2']
 | 
						|
        msg = validators.validate_dict(dictionary, constraints)
 | 
						|
        self.assertIsNone(msg, 'Field that was not required by the specs was'
 | 
						|
                               'required by the validator.')
 | 
						|
 | 
						|
    def test_validate_dict_required_keys(self):
 | 
						|
        dictionary, constraints = self._construct_dict_and_constraints()
 | 
						|
 | 
						|
        del dictionary['key1']
 | 
						|
        msg = validators.validate_dict(dictionary, constraints)
 | 
						|
        self.assertIn('Expected keys:', msg)
 | 
						|
 | 
						|
    def test_validate_dict_wrong_values(self):
 | 
						|
        dictionary, constraints = self._construct_dict_and_constraints()
 | 
						|
 | 
						|
        dictionary['key1'] = 'UNSUPPORTED'
 | 
						|
        msg = validators.validate_dict(dictionary, constraints)
 | 
						|
        self.assertIsNotNone(msg)
 | 
						|
 | 
						|
    def test_validate_dict_unexpected_keys(self):
 | 
						|
        dictionary, constraints = self._construct_dict_and_constraints()
 | 
						|
 | 
						|
        dictionary['unexpected_key'] = 'val'
 | 
						|
        msg = validators.validate_dict(dictionary, constraints)
 | 
						|
        self.assertIn('Unexpected keys supplied:', msg)
 | 
						|
 | 
						|
    def test_validate_dict_convert_boolean(self):
 | 
						|
        dictionary, constraints = self._construct_dict_and_constraints()
 | 
						|
 | 
						|
        constraints['key_bool'] = {
 | 
						|
            'type:boolean': None,
 | 
						|
            'required': False,
 | 
						|
            'convert_to': converters.convert_to_boolean}
 | 
						|
        dictionary['key_bool'] = 'true'
 | 
						|
        msg = validators.validate_dict(dictionary, constraints)
 | 
						|
        self.assertIsNone(msg)
 | 
						|
        # Explicitly comparing with literal 'True' as assertTrue
 | 
						|
        # succeeds also for 'true'
 | 
						|
        self.assertIs(True, dictionary['key_bool'])
 | 
						|
 | 
						|
    def test_subdictionary(self):
 | 
						|
        dictionary, constraints = self._construct_dict_and_constraints()
 | 
						|
 | 
						|
        del dictionary['key3']['k4']
 | 
						|
        dictionary['key3']['k5'] = 'a string value'
 | 
						|
        msg = validators.validate_dict(dictionary, constraints)
 | 
						|
        self.assertIn('Expected keys:', msg)
 | 
						|
 | 
						|
    def test_validate_dict_or_none(self):
 | 
						|
        dictionary, constraints = self._construct_dict_and_constraints()
 | 
						|
 | 
						|
        # Check whether None is a valid value.
 | 
						|
        msg = validators.validate_dict_or_none(None, constraints)
 | 
						|
        self.assertIsNone(msg, 'Validation of a None dictionary failed.')
 | 
						|
 | 
						|
        # Check validation of a regular dictionary.
 | 
						|
        msg = validators.validate_dict_or_none(dictionary, constraints)
 | 
						|
        self.assertIsNone(msg, 'Validation of a valid dictionary failed.')
 | 
						|
 | 
						|
    def test_validate_dict_or_empty(self):
 | 
						|
        dictionary, constraints = self._construct_dict_and_constraints()
 | 
						|
 | 
						|
        # Check whether an empty dictionary is valid.
 | 
						|
        msg = validators.validate_dict_or_empty({}, constraints)
 | 
						|
        self.assertIsNone(msg, 'Validation of a None dictionary failed.')
 | 
						|
 | 
						|
        # Check validation of a regular dictionary.
 | 
						|
        msg = validators.validate_dict_or_empty(dictionary, constraints)
 | 
						|
        self.assertIsNone(msg, 'Validation of a valid dictionary failed.')
 | 
						|
 | 
						|
    def test_validate_dict_or_nodata(self):
 | 
						|
        dictionary, constraints = self._construct_dict_and_constraints()
 | 
						|
 | 
						|
        # Check whether no data is a valid value.
 | 
						|
        msg = validators.validate_dict_or_nodata(None, constraints)
 | 
						|
        self.assertIsNone(msg, 'Validation of None for no-data failed.')
 | 
						|
        msg = validators.validate_dict_or_nodata({}, constraints)
 | 
						|
        self.assertIsNone(msg, 'Validation of empty dict for no-data failed.')
 | 
						|
 | 
						|
        # Check validation of a regular dictionary.
 | 
						|
        msg = validators.validate_dict_or_nodata(dictionary, constraints)
 | 
						|
        self.assertIsNone(msg, 'Validation of a valid dictionary failed.')
 | 
						|
 | 
						|
    def test_validate_non_negative(self):
 | 
						|
        msg = validators.validate_non_negative('abc')
 | 
						|
        self.assertEqual("'abc' is not an integer", msg)
 | 
						|
 | 
						|
        for value in (-1, '-2'):
 | 
						|
            self.assertEqual("'%s' should be non-negative" % value,
 | 
						|
                             validators.validate_non_negative(value))
 | 
						|
 | 
						|
        for value in (0, 1, '2', True, False):
 | 
						|
            msg = validators.validate_non_negative(value)
 | 
						|
            self.assertIsNone(msg)
 | 
						|
 | 
						|
    def test_validate_subports_invalid_body(self):
 | 
						|
        self.assertIsNotNone(validators.validate_subports(None))
 | 
						|
 | 
						|
    def test_validate_subports_invalid_subport_object(self):
 | 
						|
        self.assertIsNotNone(validators.validate_subports(['foo_port']))
 | 
						|
 | 
						|
    def test_validate_subports_invalid_port_uuid(self):
 | 
						|
        body = [{'port_id': 'foo_port'}]
 | 
						|
        self.assertIsNotNone(validators.validate_subports(body))
 | 
						|
 | 
						|
    def test_validate_subports_invalid_missing_port_id(self):
 | 
						|
        body = [{'poort_id': 'foo_port'}]
 | 
						|
        self.assertIsNotNone(validators.validate_subports(body))
 | 
						|
 | 
						|
    def test_validate_subports_invalid_duplicate_port_ids(self):
 | 
						|
        body = [
 | 
						|
            {'port_id': '00000000-ffff-ffff-ffff-000000000000'},
 | 
						|
            {'port_id': '00000000-ffff-ffff-ffff-000000000000'}
 | 
						|
        ]
 | 
						|
        self.assertIsNotNone(validators.validate_subports(body))
 | 
						|
 | 
						|
    def test_validate_subports_invalid_incomplete_segmentation_details(self):
 | 
						|
        body = [
 | 
						|
            {'port_id': '00000000-ffff-ffff-ffff-000000000000',
 | 
						|
             'segmentation_id': '3'}
 | 
						|
        ]
 | 
						|
        self.assertIsNotNone(validators.validate_subports(body))
 | 
						|
 | 
						|
    def test_validate_subports_invalid_unknown_paramenter(self):
 | 
						|
        body = [
 | 
						|
            {'port_id': '00000000-ffff-ffff-ffff-000000000000',
 | 
						|
             'segmentation_id': '3', 'segmeNAtion_type': 'vlan'}
 | 
						|
        ]
 | 
						|
        self.assertIsNotNone(validators.validate_subports(body))
 | 
						|
 | 
						|
    def test_validate_subports_invalid_duplicate_segmentation_id(self):
 | 
						|
        body = [
 | 
						|
            {'port_id': '00000000-ffff-ffff-ffff-000000000000',
 | 
						|
             'segmentation_id': '3', 'segmentation_type': 'vlan'},
 | 
						|
            {'port_id': '11111111-ffff-ffff-ffff-000000000000',
 | 
						|
             'segmentation_id': '3', 'segmentation_type': 'vlan'}
 | 
						|
        ]
 | 
						|
        self.assertIsNotNone(validators.validate_subports(body))
 | 
						|
 | 
						|
    def test_validate_subports_valid_unique_segmentation_id(self):
 | 
						|
        body = [
 | 
						|
            {'port_id': '00000000-ffff-ffff-ffff-000000000000',
 | 
						|
             'segmentation_id': '3', 'segmentation_type': 'vlan'},
 | 
						|
            {'port_id': '11111111-ffff-ffff-ffff-000000000000',
 | 
						|
             'segmentation_id': '3', 'segmentation_type': 'vxlan'}
 | 
						|
        ]
 | 
						|
        self.assertIsNone(validators.validate_subports(body))
 | 
						|
 | 
						|
    def test_validate_subports_valid_empty_body(self):
 | 
						|
        self.assertIsNone(validators.validate_subports([]))
 | 
						|
 | 
						|
    def test_validate_subports_valid_suports_with_segmentation_details(self):
 | 
						|
        body = [
 | 
						|
            {'port_id': '00000000-ffff-ffff-ffff-000000000000',
 | 
						|
             'segmentation_id': '3', 'segmentation_type': 'vlan'},
 | 
						|
            {'port_id': '11111111-ffff-ffff-ffff-000000000000',
 | 
						|
             'segmentation_id': '5', 'segmentation_type': 'vlan'}
 | 
						|
        ]
 | 
						|
        self.assertIsNone(validators.validate_subports(body))
 | 
						|
 | 
						|
    def test_validate_subports_valid_subports(self):
 | 
						|
        body = [
 | 
						|
            {'port_id': '00000000-ffff-ffff-ffff-000000000000'},
 | 
						|
            {'port_id': '11111111-ffff-ffff-ffff-000000000000'},
 | 
						|
        ]
 | 
						|
        self.assertIsNone(validators.validate_subports(body))
 | 
						|
 | 
						|
 | 
						|
class TestValidateIPSubnetNone(base.BaseTestCase):
 | 
						|
 | 
						|
    def test_validate_none(self):
 | 
						|
        self.assertIsNone(validators.validate_ip_or_subnet_or_none(None))
 | 
						|
 | 
						|
    def test_validate_ipv4(self):
 | 
						|
        testdata = "172.0.0.1"
 | 
						|
        self.assertIsNone(validators.validate_ip_or_subnet_or_none(testdata))
 | 
						|
 | 
						|
    def test_validate_ipv4_subnet(self):
 | 
						|
        testdata = "172.0.0.1/24"
 | 
						|
        self.assertIsNone(validators.validate_ip_or_subnet_or_none(testdata))
 | 
						|
 | 
						|
    def test_validate_ipv6(self):
 | 
						|
        testdata = "2001:0db8:0a0b:12f0:0000:0000:0000:0001"
 | 
						|
        self.assertIsNone(validators.validate_ip_or_subnet_or_none(testdata))
 | 
						|
 | 
						|
    def test_validate_ipv6_subnet(self):
 | 
						|
        testdata = "::1/128"
 | 
						|
        self.assertIsNone(validators.validate_ip_or_subnet_or_none(testdata))
 | 
						|
 | 
						|
    def test_validate_ipv4_invalid(self):
 | 
						|
        testdata = "300.0.0.1"
 | 
						|
        self.assertEqual(("'300.0.0.1' is neither a valid IP address, nor is "
 | 
						|
                          "it a valid IP subnet"),
 | 
						|
                         validators.validate_ip_or_subnet_or_none(testdata))
 | 
						|
 | 
						|
    def test_validate_ipv4_subnet_invalid(self):
 | 
						|
        testdata = "172.0.0.1/45"
 | 
						|
        self.assertEqual(("'172.0.0.1/45' is neither a valid IP address, nor "
 | 
						|
                          "is it a valid IP subnet"),
 | 
						|
                         validators.validate_ip_or_subnet_or_none(testdata))
 | 
						|
 | 
						|
    def test_validate_ipv6_invalid(self):
 | 
						|
        testdata = "xxxx:0db8:0a0b:12f0:0000:0000:0000:0001"
 | 
						|
        self.assertEqual(("'xxxx:0db8:0a0b:12f0:0000:0000:0000:0001' is "
 | 
						|
                          "neither a valid IP address, nor is it a valid IP "
 | 
						|
                          "subnet"),
 | 
						|
                         validators.validate_ip_or_subnet_or_none(testdata))
 | 
						|
 | 
						|
    def test_validate_ipv6_subnet_invalid(self):
 | 
						|
        testdata = "::1/2048"
 | 
						|
        self.assertEqual(("'::1/2048' is neither a valid IP address, nor is "
 | 
						|
                          "it a valid IP subnet"),
 | 
						|
                         validators.validate_ip_or_subnet_or_none(testdata))
 |