From 651ad18bdde92e550eee68aa7522288a5de94cdd Mon Sep 17 00:00:00 2001 From: 119Vik Date: Wed, 21 Aug 2013 11:59:39 +0300 Subject: [PATCH] Fix for returned status code and .gitignore For this purposes I added addiitional processing of original exceptions at wsme/wsmeext/pecan.py. For exception's validation special validator was added to wsme/wsmeext/utils.py. Also functionality was reworked to be compatible with python3.3 Fixes bug#1214073 Change-Id: Ib1cd0b274bda11f62298848ebcd55b3f6641757c --- .gitignore | 2 + tests/pecantest/test/controllers/ws.py | 24 +++++++++ tests/pecantest/test/tests/test_ws.py | 70 +++++++++++++++++++++++--- wsmeext/pecan.py | 20 ++++++-- wsmeext/tests/test_utils.py | 16 ++++++ wsmeext/utils.py | 11 ++++ 6 files changed, 133 insertions(+), 10 deletions(-) create mode 100644 wsmeext/tests/test_utils.py create mode 100644 wsmeext/utils.py diff --git a/.gitignore b/.gitignore index 96b9edf..ba5f335 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,5 @@ dist doc/_build d2to1-*.egg + +WSME.egg-info/ diff --git a/tests/pecantest/test/controllers/ws.py b/tests/pecantest/test/controllers/ws.py index cddaec0..f0dcba4 100644 --- a/tests/pecantest/test/controllers/ws.py +++ b/tests/pecantest/test/controllers/ws.py @@ -19,6 +19,24 @@ class Book(Base): author = wsattr('Author') +class BookNotFound(Exception): + message = "Book with ID={id} Not Found" + code = 404 + + def __init__(self, id): + message = self.message.format(id=id) + super(BookNotFound, self).__init__(message) + + +class NonHttpException(Exception): + message = "Internal Exception for Book ID={id}" + code = 684 + + def __init__(self, id): + message = self.message.format(id=id) + super(NonHttpException, self).__init__(message) + + class BooksController(RestController): @wsmeext.pecan.wsexpose(Book, int, int) @@ -71,6 +89,12 @@ def get(self, id): if id == 999: raise wsme.exc.ClientSideError('Wrong ID') + if id == 998: + raise BookNotFound(id) + + if id == 997: + raise NonHttpException(id) + if id == 911: return wsme.api.Response(Author(), status_code=401) diff --git a/tests/pecantest/test/tests/test_ws.py b/tests/pecantest/test/tests/test_ws.py index bd5c704..3c22042 100644 --- a/tests/pecantest/test/tests/test_ws.py +++ b/tests/pecantest/test/tests/test_ws.py @@ -1,7 +1,15 @@ +from six.moves import http_client from test.tests import FunctionalTest import json import pecan +used_status_codes = [400, 401, 404, 500] +http_response_messages = { + code: '{} {}'.format(code, status) + for code, status in http_client.responses.iteritems() + if code in used_status_codes +} + class TestWS(FunctionalTest): @@ -70,12 +78,14 @@ def test_post_body_parameter(self): assert a['firstname'] == 'test' def test_clientsideerror(self): + expected_status_code = 400 + expected_status = http_response_messages[expected_status_code] res = self.app.get( '/authors/999.json', expect_errors=True ) print res - self.assertEqual(res.status, '400 Bad Request') + self.assertEqual(res.status, expected_status) a = json.loads(res.body) print a assert a['faultcode'] == 'Client' @@ -85,29 +95,77 @@ def test_clientsideerror(self): expect_errors=True ) print res - self.assertEqual(res.status, '400 Bad Request') + self.assertEqual(res.status, expected_status) assert 'Client' in res.body + def test_custom_clientside_error(self): + expected_status_code = 404 + expected_status = http_response_messages[expected_status_code] + res = self.app.get( + '/authors/998.json', + expect_errors=True + ) + print res + self.assertEqual(res.status, expected_status) + a = json.loads(res.body) + print a + assert a['faultcode'] == 'Server' + + res = self.app.get( + '/authors/998.xml', + expect_errors=True + ) + print res + self.assertEqual(res.status, expected_status) + assert 'Server' in res.body + + def test_custom_non_http_clientside_error(self): + expected_status_code = 500 + expected_status = http_response_messages[expected_status_code] + res = self.app.get( + '/authors/997.json', + expect_errors=True + ) + print res + self.assertEqual(res.status, expected_status) + a = json.loads(res.body) + print a + assert a['faultcode'] == 'Server' + + res = self.app.get( + '/authors/997.xml', + expect_errors=True + ) + print res + self.assertEqual(res.status, expected_status) + assert 'Server' in res.body + def test_non_default_response(self): + expected_status_code = 401 + expected_status = http_response_messages[expected_status_code] res = self.app.get( '/authors/911.json', expect_errors=True ) - self.assertEqual(res.status_int, 401) - self.assertEqual(res.status, '401 Unauthorized') + self.assertEqual(res.status_int, expected_status_code) + self.assertEqual(res.status, expected_status) def test_serversideerror(self): + expected_status_code = 500 + expected_status = http_response_messages[expected_status_code] res = self.app.get('/divide_by_zero.json', expect_errors=True) - self.assertEqual(res.status, '500 Internal Server Error') + self.assertEqual(res.status, expected_status) a = json.loads(res.body) print a assert a['faultcode'] == 'Server' assert a['debuginfo'] is None def test_serversideerror_with_debug(self): + expected_status_code = 500 + expected_status = http_response_messages[expected_status_code] pecan.set_config({'wsme': {'debug': True}}) res = self.app.get('/divide_by_zero.json', expect_errors=True) - self.assertEqual(res.status, '500 Internal Server Error') + self.assertEqual(res.status, expected_status) a = json.loads(res.body) print a assert a['faultcode'] == 'Server' diff --git a/wsmeext/pecan.py b/wsmeext/pecan.py index f8390b0..268c76c 100644 --- a/wsmeext/pecan.py +++ b/wsmeext/pecan.py @@ -11,6 +11,8 @@ import pecan +from wsmeext.utils import is_valid_code + class JSonRenderer(object): def __init__(self, path, extra_vars): @@ -76,14 +78,24 @@ def callfunction(self, *args, **kwargs): result = result.obj except: - data = wsme.api.format_exception( - sys.exc_info(), - pecan.conf.get('wsme', {}).get('debug', False) - ) + try: + exception_info = sys.exc_info() + orig_exception = exception_info[1] + orig_code = getattr(orig_exception, 'code', None) + data = wsme.api.format_exception( + exception_info, + pecan.conf.get('wsme', {}).get('debug', False) + ) + finally: + del exception_info + if data['faultcode'] == 'Client': pecan.response.status = 400 + elif orig_code and is_valid_code(orig_code): + pecan.response.status = orig_code else: pecan.response.status = 500 + return data if funcdef.return_type is None: diff --git a/wsmeext/tests/test_utils.py b/wsmeext/tests/test_utils.py new file mode 100644 index 0000000..383a394 --- /dev/null +++ b/wsmeext/tests/test_utils.py @@ -0,0 +1,16 @@ +from wsmeext.utils import is_valid_code + + +class TestUtils(): + + def test_validator_with_valid_code(self): + valid_code = 404 + assert is_valid_code(valid_code), "Valid status code not detected" + + def test_validator_with_invalid_int_code(self): + invalid_int_code = 648 + assert not is_valid_code(invalid_int_code), "Invalid status code not detected" + + def test_validator_with_invalid_str_code(self): + invalid_str_code = '404' + assert not is_valid_code(invalid_str_code), "Invalid status code not detected" \ No newline at end of file diff --git a/wsmeext/utils.py b/wsmeext/utils.py new file mode 100644 index 0000000..58b4013 --- /dev/null +++ b/wsmeext/utils.py @@ -0,0 +1,11 @@ +""" +This File consists of utils functions used in wsmeext module. +""" +from six.moves import http_client + + +def is_valid_code(code_value): + """ + This function checks if incoming value in http response codes range. + """ + return code_value in http_client.responses