Add JSON schema validation for project tags

This change adds json schema for project tags validation, with
the limits for number of characters per tag as well as the
limit for the number of tags a project can have per update.

Co-Authored-By: Jaewoo Park <jp655p@att.com>
Co-Authored-By: Nicolas <nh202b@att.com>

Change-Id: I5f8e4a53089b9fcc38084bb958d09f63ccc59d2a
Partially-Implements: bp project-tags
This commit is contained in:
Gage Hugo 2017-07-17 15:37:44 -05:00
parent 7c91276290
commit 5329071174
2 changed files with 153 additions and 2 deletions

View File

@ -20,6 +20,25 @@ _name_properties = {
'pattern': '[\S]+'
}
_project_tag_name_properties = {
'type': 'string',
'minLength': 1,
'maxLength': 255,
# NOTE(gagehugo) This pattern is for tags which follows the
# guidelines as set by the API-WG, which matches anything that
# does not contain a '/' or ','.
# https://specs.openstack.org/openstack/api-wg/guidelines/tags.html
'pattern': '^[^,/]*$'
}
_project_tags_list_properties = {
'type': 'array',
'items': _project_tag_name_properties,
'required': [],
'maxItems': 80,
'uniqueItems': True
}
_project_properties = {
'description': validation.nullable(parameter_types.description),
# NOTE(htruta): domain_id is nullable for projects acting as a domain.
@ -27,9 +46,16 @@ _project_properties = {
'enabled': parameter_types.boolean,
'is_domain': parameter_types.boolean,
'parent_id': validation.nullable(parameter_types.id_string),
'name': _name_properties
'name': _name_properties,
'tags': _project_tags_list_properties
}
# This is for updating a single project tag via the URL
project_tag_create = _project_tag_name_properties
# This is for updaing a project with a list of tags
project_tags_update = _project_tags_list_properties
project_create = {
'type': 'object',
'properties': _project_properties,
@ -51,7 +77,8 @@ project_update = {
_domain_properties = {
'description': validation.nullable(parameter_types.description),
'enabled': parameter_types.boolean,
'name': _name_properties
'name': _name_properties,
'tags': project_tags_update
}
domain_create = {

View File

@ -381,6 +381,37 @@ class ProjectValidationTestCase(unit.BaseTestCase):
self.create_project_validator.validate,
request_to_validate)
def test_validate_project_create_with_tags(self):
request_to_validate = {'name': uuid.uuid4().hex,
'tags': ['foo', 'bar']}
self.create_project_validator.validate(request_to_validate)
def test_validate_project_create_with_tags_invalid_char(self):
invalid_chars = [',', '/', ',foo', 'foo/bar']
for char in invalid_chars:
tag = uuid.uuid4().hex + char
request_to_validate = {'name': uuid.uuid4().hex,
'tags': ['foo', tag]}
self.assertRaises(exception.SchemaValidationError,
self.create_project_validator.validate,
request_to_validate)
def test_validate_project_create_with_tag_name_too_long(self):
invalid_name = 'a' * 256
request_to_validate = {'name': uuid.uuid4().hex,
'tags': ['foo', invalid_name]}
self.assertRaises(exception.SchemaValidationError,
self.create_project_validator.validate,
request_to_validate)
def test_validate_project_create_with_too_many_tags(self):
tags = [uuid.uuid4().hex for _ in range(81)]
request_to_validate = {'name': uuid.uuid4().hex,
'tags': tags}
self.assertRaises(exception.SchemaValidationError,
self.create_project_validator.validate,
request_to_validate)
def test_validate_project_request_with_valid_parent_id(self):
"""Test that we validate `parent_id` in create project requests."""
# parent_id is nullable
@ -432,6 +463,37 @@ class ProjectValidationTestCase(unit.BaseTestCase):
self.update_project_validator.validate,
request_to_validate)
def test_validate_project_update_with_tags(self):
request_to_validate = {'name': uuid.uuid4().hex,
'tags': ['foo', 'bar']}
self.update_project_validator.validate(request_to_validate)
def test_validate_project_update_with_tags_invalid_char(self):
invalid_chars = [',', '/']
for char in invalid_chars:
tag = uuid.uuid4().hex + char
request_to_validate = {'name': uuid.uuid4().hex,
'tags': ['foo', tag]}
self.assertRaises(exception.SchemaValidationError,
self.update_project_validator.validate,
request_to_validate)
def test_validate_project_update_with_tag_name_too_long(self):
invalid_name = 'a' * 256
request_to_validate = {'name': uuid.uuid4().hex,
'tags': ['foo', invalid_name]}
self.assertRaises(exception.SchemaValidationError,
self.update_project_validator.validate,
request_to_validate)
def test_validate_project_update_with_too_many_tags(self):
tags = [uuid.uuid4().hex for _ in range(81)]
request_to_validate = {'name': uuid.uuid4().hex,
'tags': tags}
self.assertRaises(exception.SchemaValidationError,
self.update_project_validator.validate,
request_to_validate)
def test_validate_project_create_request_with_valid_domain_id(self):
"""Test that we validate `domain_id` in create project requests."""
# domain_id is nullable
@ -521,6 +583,37 @@ class DomainValidationTestCase(unit.BaseTestCase):
self.create_domain_validator.validate,
request_to_validate)
def test_validate_domain_create_with_tags(self):
request_to_validate = {'name': uuid.uuid4().hex,
'tags': ['foo', 'bar']}
self.create_domain_validator.validate(request_to_validate)
def test_validate_domain_create_with_tags_invalid_char(self):
invalid_chars = [',', '/']
for char in invalid_chars:
tag = uuid.uuid4().hex + char
request_to_validate = {'name': uuid.uuid4().hex,
'tags': ['foo', tag]}
self.assertRaises(exception.SchemaValidationError,
self.create_domain_validator.validate,
request_to_validate)
def test_validate_domain_create_with_tag_name_too_long(self):
invalid_name = 'a' * 256
request_to_validate = {'name': uuid.uuid4().hex,
'tags': ['foo', invalid_name]}
self.assertRaises(exception.SchemaValidationError,
self.create_domain_validator.validate,
request_to_validate)
def test_validate_domain_create_with_too_many_tags(self):
tags = [uuid.uuid4().hex for _ in range(81)]
request_to_validate = {'name': uuid.uuid4().hex,
'tags': tags}
self.assertRaises(exception.SchemaValidationError,
self.create_domain_validator.validate,
request_to_validate)
def test_validate_domain_update_request(self):
"""Test that we validate a domain update request."""
request_to_validate = {'domain_id': uuid.uuid4().hex}
@ -549,6 +642,37 @@ class DomainValidationTestCase(unit.BaseTestCase):
self.update_domain_validator.validate,
request_to_validate)
def test_validate_domain_update_with_tags(self):
request_to_validate = {'name': uuid.uuid4().hex,
'tags': ['foo', 'bar']}
self.update_domain_validator.validate(request_to_validate)
def test_validate_domain_update_with_tags_invalid_char(self):
invalid_chars = [',', '/']
for char in invalid_chars:
tag = uuid.uuid4().hex + char
request_to_validate = {'name': uuid.uuid4().hex,
'tags': ['foo', tag]}
self.assertRaises(exception.SchemaValidationError,
self.update_domain_validator.validate,
request_to_validate)
def test_validate_domain_update_with_tag_name_too_long(self):
invalid_name = 'a' * 256
request_to_validate = {'name': uuid.uuid4().hex,
'tags': ['foo', invalid_name]}
self.assertRaises(exception.SchemaValidationError,
self.update_domain_validator.validate,
request_to_validate)
def test_validate_domain_update_with_too_many_tags(self):
tags = [uuid.uuid4().hex for _ in range(81)]
request_to_validate = {'name': uuid.uuid4().hex,
'tags': tags}
self.assertRaises(exception.SchemaValidationError,
self.update_domain_validator.validate,
request_to_validate)
class RoleValidationTestCase(unit.BaseTestCase):
"""Test for V3 Role API validation."""