diff --git a/nova/api/validation/parameter_types.py b/nova/api/validation/parameter_types.py index e17443fd2f58..9362aaf4ce4a 100644 --- a/nova/api/validation/parameter_types.py +++ b/nova/api/validation/parameter_types.py @@ -21,14 +21,6 @@ import unicodedata import six -from nova.i18n import _ - - -class ValidationRegex(object): - def __init__(self, regex, reason): - self.regex = regex - self.reason = reason - def _is_printable(char): """determine if a unicode code point is printable. @@ -118,12 +110,10 @@ def _build_regex_range(ws=True, invert=False, exclude=None): valid_name_regex_base = '^(?![%s])[%s]*(? 0: - # NOTE: For whole OpenStack message consistency, this error - # message has been written as the similar format of WSME. + # NOTE: For whole OpenStack message consistency, this error + # message has been written as the similar format of WSME. + if len(ex.path) > 0: detail = _("Invalid input for field/attribute %(path)s." " Value: %(value)s. %(message)s") % { 'path': ex.path.pop(), 'value': ex.instance, diff --git a/nova/exception.py b/nova/exception.py index cc59cf8d2d7b..f16769de0ad5 100644 --- a/nova/exception.py +++ b/nova/exception.py @@ -420,11 +420,6 @@ class InvalidStrTime(Invalid): msg_fmt = _("Invalid datetime string: %(reason)s") -class InvalidName(Invalid): - msg_fmt = _("An invalid 'name' value was provided. " - "The name must be: %(reason)s") - - class InstanceInvalidState(Invalid): msg_fmt = _("Instance %(instance_uuid)s in %(attr)s %(state)s. Cannot " "%(method)s while the instance is in this state.") diff --git a/nova/tests/unit/test_api_validation.py b/nova/tests/unit/test_api_validation.py index f9a34cff0195..69c89bea44d5 100644 --- a/nova/tests/unit/test_api_validation.py +++ b/nova/tests/unit/test_api_validation.py @@ -21,7 +21,6 @@ import six from nova.api.openstack import api_version_request as api_version from nova.api import validation from nova.api.validation import parameter_types -from nova.api.validation import validators from nova import exception from nova import test @@ -37,7 +36,7 @@ class FakeRequest(object): class ValidationRegex(test.NoDBTestCase): def test_cell_names(self): - cellre = re.compile(parameter_types.valid_cell_name_regex.regex) + cellre = re.compile(parameter_types.valid_cell_name_regex) self.assertTrue(cellre.search('foo')) self.assertFalse(cellre.search('foo.bar')) self.assertFalse(cellre.search('foo@bar')) @@ -109,18 +108,6 @@ class APIValidationTestCase(test.NoDBTestCase): self.fail('Any exception does not happen.') -class FormatCheckerTestCase(test.NoDBTestCase): - - def test_format_checker_failed(self): - format_checker = validators.FormatChecker() - exc = self.assertRaises(exception.InvalidName, - format_checker.check, " ", "name") - self.assertEqual("An invalid 'name' value was provided. The name must " - "be: printable characters. " - "Can not start or end with whitespace.", - exc.format_message()) - - class MicroversionsSchemaTestCase(APIValidationTestCase): def setUp(self): @@ -681,122 +668,6 @@ class HostnameIPaddressTestCase(APIValidationTestCase): expected_detail=detail) -class CellNameTestCase(APIValidationTestCase): - - def setUp(self): - super(CellNameTestCase, self).setUp() - schema = { - 'type': 'object', - 'properties': { - 'foo': parameter_types.cell_name, - }, - } - - @validation.schema(request_body_schema=schema) - def post(req, body): - return 'Validation succeeded.' - - self.post = post - - def test_validate_name(self): - self.assertEqual('Validation succeeded.', - self.post(body={'foo': 'abc'}, - req=FakeRequest())) - self.assertEqual('Validation succeeded.', - self.post(body={'foo': 'my server'}, - req=FakeRequest())) - self.assertEqual('Validation succeeded.', - self.post(body={'foo': u'\u0434'}, req=FakeRequest())) - self.assertEqual('Validation succeeded.', - self.post(body={'foo': u'\u0434\u2006\ufffd'}, - req=FakeRequest())) - - def test_validate_name_fails(self): - error = ("An invalid 'name' value was provided. The name must be: " - "printable characters except !, ., @. " - "Can not start or end with whitespace.") - - should_fail = (' ', - ' server', - 'server ', - u'a\xa0', # trailing unicode space - u'\uffff', # non-printable unicode - 'abc!def', - 'abc.def', - 'abc@def') - - for item in should_fail: - self.check_validation_error(self.post, body={'foo': item}, - expected_detail=error) - - # four-byte unicode, if supported by this python build - try: - self.check_validation_error(self.post, body={'foo': u'\U00010000'}, - expected_detail=error) - except ValueError: - pass - - -class CellNameLeadingTrailingSpacesTestCase(APIValidationTestCase): - - def setUp(self): - super(CellNameLeadingTrailingSpacesTestCase, self).setUp() - schema = { - 'type': 'object', - 'properties': { - 'foo': parameter_types.cell_name_leading_trailing_spaces, - }, - } - - @validation.schema(request_body_schema=schema) - def post(req, body): - return 'Validation succeeded.' - - self.post = post - - def test_validate_name(self): - self.assertEqual('Validation succeeded.', - self.post(body={'foo': 'abc'}, - req=FakeRequest())) - self.assertEqual('Validation succeeded.', - self.post(body={'foo': 'my server'}, - req=FakeRequest())) - self.assertEqual('Validation succeeded.', - self.post(body={'foo': u'\u0434'}, req=FakeRequest())) - self.assertEqual('Validation succeeded.', - self.post(body={'foo': u'\u0434\u2006\ufffd'}, - req=FakeRequest())) - self.assertEqual('Validation succeeded.', - self.post(body={'foo': ' my server'}, - req=FakeRequest())) - self.assertEqual('Validation succeeded.', - self.post(body={'foo': 'my server '}, - req=FakeRequest())) - - def test_validate_name_fails(self): - error = ("An invalid 'name' value was provided. The name must be: " - "printable characters except !, ., @, " - "with at least one non space character") - - should_fail = ( - ' ', - u'\uffff', # non-printable unicode - 'abc!def', - 'abc.def', - 'abc@def') - - for item in should_fail: - self.check_validation_error(self.post, body={'foo': item}, - expected_detail=error) - - # four-byte unicode, if supported by this python build - try: - self.check_validation_error(self.post, body={'foo': u'\U00010000'}, - expected_detail=error) - except ValueError: - pass - - class NameTestCase(APIValidationTestCase): def setUp(self): @@ -830,25 +701,54 @@ class NameTestCase(APIValidationTestCase): req=FakeRequest())) def test_validate_name_fails(self): - error = ("An invalid 'name' value was provided. The name must be: " - "printable characters. " - "Can not start or end with whitespace.") + detail = (u"Invalid input for field/attribute foo. Value: ." + " ' ' does not match .*") + self.check_validation_error(self.post, body={'foo': ' '}, + expected_detail=detail) - should_fail = (' ', - ' server', - 'server ', - u'a\xa0', # trailing unicode space - u'\uffff', # non-printable unicode - ) + detail = ("Invalid input for field/attribute foo. Value: server." + " ' server' does not match .*") + self.check_validation_error(self.post, body={'foo': ' server'}, + expected_detail=detail) - for item in should_fail: - self.check_validation_error(self.post, body={'foo': item}, - expected_detail=error) + detail = ("Invalid input for field/attribute foo. Value: server ." + " 'server ' does not match .*") + self.check_validation_error(self.post, body={'foo': 'server '}, + expected_detail=detail) + + detail = ("Invalid input for field/attribute foo. Value: a." + " ' a' does not match .*") + self.check_validation_error(self.post, body={'foo': ' a'}, + expected_detail=detail) + + detail = ("Invalid input for field/attribute foo. Value: a ." + " 'a ' does not match .*") + self.check_validation_error(self.post, body={'foo': 'a '}, + expected_detail=detail) + + # NOTE(stpierre): Quoting for the unicode values in the error + # messages below gets *really* messy, so we just wildcard it + # out. (e.g., '.* does not match'). In practice, we don't + # particularly care about that part of the error message. + + # trailing unicode space + detail = (u"Invalid input for field/attribute foo. Value: a\xa0." + u' .* does not match .*') + self.check_validation_error(self.post, body={'foo': u'a\xa0'}, + expected_detail=detail) + + # non-printable unicode + detail = (u"Invalid input for field/attribute foo. Value: \uffff." + u" .* does not match .*") + self.check_validation_error(self.post, body={'foo': u'\uffff'}, + expected_detail=detail) # four-byte unicode, if supported by this python build try: + detail = (u"Invalid input for field/attribute foo. Value: " + u"\U00010000. .* does not match .*") self.check_validation_error(self.post, body={'foo': u'\U00010000'}, - expected_detail=error) + expected_detail=detail) except ValueError: pass @@ -899,23 +799,34 @@ class NameWithLeadingTrailingSpacesTestCase(APIValidationTestCase): req=FakeRequest())) def test_validate_name_fails(self): - error = ("An invalid 'name' value was provided. The name must be: " - "printable characters with at least one non space character") + detail = (u"Invalid input for field/attribute foo. Value: ." + u" ' ' does not match .*") + self.check_validation_error(self.post, body={'foo': ' '}, + expected_detail=detail) - should_fail = ( - ' ', - u'\xa0', # unicode space - u'\uffff', # non-printable unicode - ) + # NOTE(stpierre): Quoting for the unicode values in the error + # messages below gets *really* messy, so we just wildcard it + # out. (e.g., '.* does not match'). In practice, we don't + # particularly care about that part of the error message. - for item in should_fail: - self.check_validation_error(self.post, body={'foo': item}, - expected_detail=error) + # unicode space + detail = (u"Invalid input for field/attribute foo. Value: \xa0." + u' .* does not match .*') + self.check_validation_error(self.post, body={'foo': u'\xa0'}, + expected_detail=detail) + + # non-printable unicode + detail = (u"Invalid input for field/attribute foo. Value: \uffff." + u" .* does not match .*") + self.check_validation_error(self.post, body={'foo': u'\uffff'}, + expected_detail=detail) # four-byte unicode, if supported by this python build try: + detail = (u"Invalid input for field/attribute foo. Value: " + u"\U00010000. .* does not match .*") self.check_validation_error(self.post, body={'foo': u'\U00010000'}, - expected_detail=error) + expected_detail=detail) except ValueError: pass @@ -1282,7 +1193,7 @@ class Ipv6TestCase(APIValidationTestCase): detail = ("Invalid input for field/attribute foo. Value: localhost." " 'localhost' is not a 'ipv6'") self.check_validation_error(self.post, body={'foo': 'localhost'}, - expected_detail=detail) + expected_detail=detail) detail = ("Invalid input for field/attribute foo." " Value: 192.168.0.100. '192.168.0.100' is not a 'ipv6'")