Merge "Make `is_valid` more flexible with uuid validation"
This commit is contained in:
commit
e813a4de5a
|
@ -12,6 +12,7 @@
|
||||||
# License for the specific language governing permissions and limitations under
|
# License for the specific language governing permissions and limitations under
|
||||||
# the License.
|
# the License.
|
||||||
import hashlib
|
import hashlib
|
||||||
|
import re
|
||||||
import uuid
|
import uuid
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
|
@ -33,6 +34,8 @@ if CONF.audit.namespace:
|
||||||
md5_hash = hashlib.md5(CONF.audit.namespace.encode('utf-8'))
|
md5_hash = hashlib.md5(CONF.audit.namespace.encode('utf-8'))
|
||||||
AUDIT_NS = uuid.UUID(md5_hash.hexdigest())
|
AUDIT_NS = uuid.UUID(md5_hash.hexdigest())
|
||||||
|
|
||||||
|
VALID_EXCEPTIONS = ['default', 'initiator', 'observer', 'target']
|
||||||
|
|
||||||
|
|
||||||
def generate_uuid():
|
def generate_uuid():
|
||||||
"""Generate a CADF identifier."""
|
"""Generate a CADF identifier."""
|
||||||
|
@ -48,15 +51,31 @@ def norm_ns(str_id):
|
||||||
return prefix + str_id
|
return prefix + str_id
|
||||||
|
|
||||||
|
|
||||||
|
def _check_valid_uuid(value):
|
||||||
|
"""Checks a value for one or multiple valid uuids joined together."""
|
||||||
|
|
||||||
|
if not value:
|
||||||
|
raise ValueError
|
||||||
|
|
||||||
|
value = re.sub('[{}-]|urn:uuid:', '', value)
|
||||||
|
for val in [value[i:i + 32] for i in range(0, len(value), 32)]:
|
||||||
|
uuid.UUID(val)
|
||||||
|
|
||||||
|
|
||||||
def is_valid(value):
|
def is_valid(value):
|
||||||
"""Validation to ensure Identifier is correct."""
|
"""Validation to ensure Identifier is correct.
|
||||||
if value in ['target', 'initiator', 'observer']:
|
|
||||||
|
If the Identifier value is a string type but not a valid UUID string,
|
||||||
|
warn against interoperability issues and return True. This relaxes
|
||||||
|
the requirement of having strict UUID checking.
|
||||||
|
"""
|
||||||
|
if value in VALID_EXCEPTIONS:
|
||||||
return True
|
return True
|
||||||
try:
|
try:
|
||||||
uuid.UUID(value)
|
_check_valid_uuid(value)
|
||||||
except (ValueError, TypeError):
|
except (ValueError, TypeError):
|
||||||
if not isinstance(value, six.string_types) or not value:
|
if not isinstance(value, six.string_types) or not value:
|
||||||
return False
|
return False
|
||||||
warnings.warn('Invalid uuid. To ensure interoperability, identifiers '
|
warnings.warn(('Invalid uuid: %s. To ensure interoperability, '
|
||||||
'should be a valid uuid.')
|
'identifiers should be a valid uuid.' % (value)))
|
||||||
return True
|
return True
|
||||||
|
|
|
@ -38,16 +38,72 @@ from pycadf import timestamp
|
||||||
class TestCADFSpec(base.TestCase):
|
class TestCADFSpec(base.TestCase):
|
||||||
|
|
||||||
@mock.patch('pycadf.identifier.warnings.warn')
|
@mock.patch('pycadf.identifier.warnings.warn')
|
||||||
def test_identifier(self, warning_mock):
|
def test_identifier_generated_uuid(self, warning_mock):
|
||||||
# empty string
|
|
||||||
self.assertFalse(identifier.is_valid(''))
|
|
||||||
# generated uuid
|
# generated uuid
|
||||||
self.assertTrue(identifier.is_valid(identifier.generate_uuid()))
|
self.assertTrue(identifier.is_valid(identifier.generate_uuid()))
|
||||||
self.assertFalse(warning_mock.called)
|
self.assertFalse(warning_mock.called)
|
||||||
|
|
||||||
|
@mock.patch('pycadf.identifier.warnings.warn')
|
||||||
|
def test_identifier_empty_string_is_invalid(self, warning_mock):
|
||||||
|
# empty string
|
||||||
|
self.assertFalse(identifier.is_valid(''))
|
||||||
|
self.assertFalse(warning_mock.called)
|
||||||
|
|
||||||
|
@mock.patch('pycadf.identifier.warnings.warn')
|
||||||
|
def test_identifier_any_string_is_invalid(self, warning_mock):
|
||||||
# any string
|
# any string
|
||||||
self.assertTrue(identifier.is_valid('blah'))
|
self.assertTrue(identifier.is_valid('blah'))
|
||||||
self.assertTrue(warning_mock.called)
|
self.assertTrue(warning_mock.called)
|
||||||
|
|
||||||
|
@mock.patch('pycadf.identifier.warnings.warn')
|
||||||
|
def test_identifier_joined_uuids_are_valid(self, warning_mock):
|
||||||
|
# multiple uuids joined together
|
||||||
|
long_128_uuids = [
|
||||||
|
('3adce28e67e44544a5a9d5f1ab54f578a86d310aac3a465e9d'
|
||||||
|
'd2693a78b45c0e42dce28e67e44544a5a9d5f1ab54f578a86d'
|
||||||
|
'310aac3a465e9dd2693a78b45c0e'),
|
||||||
|
('{3adce28e67e44544a5a9d5f1ab54f578a86d310aac3a465e9d'
|
||||||
|
'd2693a78b45c0e42dce28e67e44544a5a9d5f1ab54f578a86d'
|
||||||
|
'310aac3a465e9dd2693a78b45c0e}'),
|
||||||
|
('{12345678-1234-5678-1234-567812345678'
|
||||||
|
'12345678-1234-5678-1234-567812345678'
|
||||||
|
'12345678-1234-5678-1234-567812345678'
|
||||||
|
'12345678-1234-5678-1234-567812345678}'),
|
||||||
|
('urn:uuid:3adce28e67e44544a5a9d5f1ab54f578a86d310aac3a465e9d'
|
||||||
|
'd2693a78b45c0e42dce28e67e44544a5a9d5f1ab54f578a86d'
|
||||||
|
'310aac3a465e9dd2693a78b45c0e')]
|
||||||
|
|
||||||
|
for value in long_128_uuids:
|
||||||
|
self.assertTrue(identifier.is_valid(value))
|
||||||
|
self.assertFalse(warning_mock.called)
|
||||||
|
|
||||||
|
@mock.patch('pycadf.identifier.warnings.warn')
|
||||||
|
def test_identifier_long_nonjoined_uuid_is_invalid(self, warning_mock):
|
||||||
|
# long uuid not of size % 32
|
||||||
|
char_42_id = '3adce28e67e44544a5a9d5f1ab54f578a86d310aac'
|
||||||
|
self.assertTrue(identifier.is_valid(char_42_id))
|
||||||
|
self.assertTrue(warning_mock.called)
|
||||||
|
|
||||||
|
@mock.patch('pycadf.identifier.warnings.warn')
|
||||||
|
def test_identifier_specific_exceptions_are_valid(self, warning_mock):
|
||||||
|
# uuid exceptions
|
||||||
|
for value in identifier.VALID_EXCEPTIONS:
|
||||||
|
self.assertTrue(identifier.is_valid(value))
|
||||||
|
self.assertFalse(warning_mock.called)
|
||||||
|
|
||||||
|
@mock.patch('pycadf.identifier.warnings.warn')
|
||||||
|
def test_identifier_valid_id_extra_chars_is_valid(self, warning_mock):
|
||||||
|
# valid uuid with additional characters according to:
|
||||||
|
# https://docs.python.org/2/library/uuid.html
|
||||||
|
valid_ids = [
|
||||||
|
'{1234567890abcdef1234567890abcdef}',
|
||||||
|
'{12345678-1234-5678-1234-567812345678}',
|
||||||
|
'urn:uuid:12345678-1234-5678-1234-567812345678']
|
||||||
|
|
||||||
|
for value in valid_ids:
|
||||||
|
self.assertTrue(identifier.is_valid(value))
|
||||||
|
self.assertFalse(warning_mock.called)
|
||||||
|
|
||||||
def test_endpoint(self):
|
def test_endpoint(self):
|
||||||
endp = endpoint.Endpoint(url='http://192.168.0.1',
|
endp = endpoint.Endpoint(url='http://192.168.0.1',
|
||||||
name='endpoint name',
|
name='endpoint name',
|
||||||
|
|
Loading…
Reference in New Issue