Fixed _error_checker in rest client

Restclient's method '_error_checker' for response codes 500 and 501 gets key
error exception when 'resp_body' is a string and passes conditions for
containing of keys.
Also added fix to rarely raised Exceptions after separation main and base
exceptions for two modules.

Closes-Bug: #1280767
Closes-Bug: #1289190
Partially-implements: bp unit-tests
Change-Id: I4b909d008940f8a96efc922daac64a086819c78a
This commit is contained in:
vponomaryov 2014-03-07 09:39:05 +02:00
parent be392f2d7c
commit 6cb6d190f4
3 changed files with 136 additions and 16 deletions

View File

@ -409,7 +409,7 @@ class RestClient(object):
elif ctype.lower() in TXT_ENC:
parse_resp = False
else:
raise exceptions.RestClientException(str(resp.status))
raise exceptions.InvalidContentType(str(resp.status))
if resp.status == 401 or resp.status == 403:
raise exceptions.Unauthorized()
@ -451,25 +451,26 @@ class RestClient(object):
# exception.
raise exceptions.InvalidHTTPResponseBody(message)
else:
# I'm seeing both computeFault
# and cloudServersFault come back.
# Will file a bug to fix, but leave as is for now.
if 'cloudServersFault' in resp_body:
message = resp_body['cloudServersFault']['message']
elif 'computeFault' in resp_body:
message = resp_body['computeFault']['message']
elif 'error' in resp_body: # Keystone errors
message = resp_body['error']['message']
raise exceptions.IdentityError(message)
elif 'message' in resp_body:
message = resp_body['message']
if isinstance(resp_body, dict):
# I'm seeing both computeFault
# and cloudServersFault come back.
# Will file a bug to fix, but leave as is for now.
if 'cloudServersFault' in resp_body:
message = resp_body['cloudServersFault']['message']
elif 'computeFault' in resp_body:
message = resp_body['computeFault']['message']
elif 'error' in resp_body: # Keystone errors
message = resp_body['error']['message']
raise exceptions.IdentityError(message)
elif 'message' in resp_body:
message = resp_body['message']
else:
message = resp_body
raise exceptions.ServerFault(message)
if resp.status >= 400:
if parse_resp:
resp_body = self._parse_resp(resp_body)
raise exceptions.RestClientException(str(resp.status))
raise exceptions.UnexpectedResponseCode(str(resp.status))
def is_absolute_limit(self, resp, resp_body):
if (not isinstance(resp_body, collections.Mapping) or

View File

@ -146,3 +146,11 @@ class ResponseWithEntity(base.RFCViolation):
class InvalidHTTPResponseBody(base.RestClientException):
message = "HTTP response body is invalid json or xml"
class InvalidContentType(base.RestClientException):
message = "Invalid content type provided"
class UnexpectedResponseCode(base.RestClientException):
message = "Unexpected response code received"

View File

@ -230,3 +230,114 @@ class TestRestClientParseRespJSON(TestRestClientParseRespXML):
data = {"one_top_key": "not_list_or_dict_value"}
body = self.rest_client._parse_resp(json.dumps(data))
self.assertEqual(data, body)
class TestRestClientErrorCheckerJSON(base.TestCase):
c_type = "application/json"
def set_data(self, r_code, enc=None, r_body=None):
if enc is None:
enc = self.c_type
resp_dict = {'status': r_code, 'content-type': enc}
resp = httplib2.Response(resp_dict)
data = {
"method": "fake_method",
"url": "fake_url",
"headers": "fake_headers",
"body": "fake_body",
"resp": resp,
"resp_body": '{"resp_body": "fake_resp_body"}',
}
if r_body is not None:
data.update({"resp_body": r_body})
return data
def setUp(self):
super(TestRestClientErrorCheckerJSON, self).setUp()
self.stubs.Set(config, 'TempestConfigPrivate', fake_config.FakeConfig)
self.rest_client = rest_client.RestClient(
fake_auth_provider.FakeAuthProvider())
def test_response_less_than_400(self):
self.rest_client._error_checker(**self.set_data("399"))
def test_response_400(self):
self.assertRaises(exceptions.BadRequest,
self.rest_client._error_checker,
**self.set_data("400"))
def test_response_401(self):
self.assertRaises(exceptions.Unauthorized,
self.rest_client._error_checker,
**self.set_data("401"))
def test_response_403(self):
self.assertRaises(exceptions.Unauthorized,
self.rest_client._error_checker,
**self.set_data("403"))
def test_response_404(self):
self.assertRaises(exceptions.NotFound,
self.rest_client._error_checker,
**self.set_data("404"))
def test_response_409(self):
self.assertRaises(exceptions.Conflict,
self.rest_client._error_checker,
**self.set_data("409"))
def test_response_413(self):
self.assertRaises(exceptions.OverLimit,
self.rest_client._error_checker,
**self.set_data("413"))
def test_response_422(self):
self.assertRaises(exceptions.UnprocessableEntity,
self.rest_client._error_checker,
**self.set_data("422"))
def test_response_500_with_text(self):
# _parse_resp is expected to return 'str'
self.assertRaises(exceptions.ServerFault,
self.rest_client._error_checker,
**self.set_data("500"))
def test_response_501_with_text(self):
self.assertRaises(exceptions.ServerFault,
self.rest_client._error_checker,
**self.set_data("501"))
def test_response_500_with_dict(self):
r_body = '{"resp_body": {"err": "fake_resp_body"}}'
self.assertRaises(exceptions.ServerFault,
self.rest_client._error_checker,
**self.set_data("500", r_body=r_body))
def test_response_501_with_dict(self):
r_body = '{"resp_body": {"err": "fake_resp_body"}}'
self.assertRaises(exceptions.ServerFault,
self.rest_client._error_checker,
**self.set_data("501", r_body=r_body))
def test_response_bigger_than_400(self):
# Any response code, that bigger than 400, and not in
# (401, 403, 404, 409, 413, 422, 500, 501)
self.assertRaises(exceptions.UnexpectedResponseCode,
self.rest_client._error_checker,
**self.set_data("402"))
class TestRestClientErrorCheckerXML(TestRestClientErrorCheckerJSON):
c_type = "application/xml"
class TestRestClientErrorCheckerTEXT(TestRestClientErrorCheckerJSON):
c_type = "text/plain"
def test_fake_content_type(self):
# This test is required only in one exemplar
# Any response code, that bigger than 400, and not in
# (401, 403, 404, 409, 413, 422, 500, 501)
self.assertRaises(exceptions.InvalidContentType,
self.rest_client._error_checker,
**self.set_data("405", enc="fake_enc"))