From 038171962198c787512f7a1a1dc0208038a5aaf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20HUBSCHER?= Date: Fri, 2 Oct 2015 16:04:33 +0200 Subject: [PATCH] Handle RequestException as Service Unavailable errors. --- syncto/tests/test_functional.py | 16 +++++++++++++++- syncto/views/errors.py | 22 +++++++++++++++++++--- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/syncto/tests/test_functional.py b/syncto/tests/test_functional.py index 094f255..ef8e95c 100644 --- a/syncto/tests/test_functional.py +++ b/syncto/tests/test_functional.py @@ -4,7 +4,7 @@ from cliquet.errors import ERRORS from cliquet.tests.support import FormattedErrorMixin -from requests.exceptions import HTTPError +from requests.exceptions import HTTPError, ConnectionError from syncto import AUTHORIZATION_HEADER, CLIENT_STATE_HEADER from syncto import main as testapp @@ -114,6 +114,20 @@ def test_error_with_syncclient_server_raise_a_503(self): self.assertFormattedError( resp, 503, ERRORS.BACKEND, "Service Unavailable", "retry later") + def test_error_with_syncclient_server_request(self): + headers = self.headers.copy() + headers['Authorization'] = "BrowserID valid-browser-id-assertion" + headers['X-Client-State'] = "ValidClientState" + with mock.patch("syncto.authentication.TokenserverClient", + side_effect=ConnectionError): + resp = self.app.get(COLLECTION_URL, headers=headers, status=503) + + error_msg = ("Unable to reach the service. Check your " + "internet connection or firewall configuration.") + + self.assertFormattedError( + resp, 503, ERRORS.BACKEND, "Service Unavailable", error_msg) + class BaseViewTest(BaseWebTest, unittest.TestCase): patch_authent_for = 'record' diff --git a/syncto/views/errors.py b/syncto/views/errors.py index 6c73ebf..a974f82 100644 --- a/syncto/views/errors.py +++ b/syncto/views/errors.py @@ -1,7 +1,7 @@ from pyramid import httpexceptions from pyramid.security import NO_PERMISSION_REQUIRED, forget from pyramid.view import view_config -from requests.exceptions import HTTPError +from requests.exceptions import HTTPError, RequestException from cliquet import logger from cliquet.errors import http_error, ERRORS @@ -12,7 +12,7 @@ @view_config(context=HTTPError, permission=NO_PERMISSION_REQUIRED) -def error(context, request): +def response_error(context, request): """Catch server errors and trace them.""" message = '%s %s: %s' % (context.response.status_code, context.response.reason, @@ -42,9 +42,25 @@ def error(context, request): errno=ERRORS.INVALID_RESOURCE_ID, message=message) else: - response = service_unavailable(context, request) + response = service_unavailable( + httpexceptions.HTTPServiceUnavailable(), + request) request.response = response export_headers(context.response, request) return reapply_cors(request, response) + + +@view_config(context=RequestException, permission=NO_PERMISSION_REQUIRED) +def request_error(context, request): + """Catch requests errors when issuing a request.""" + logger.error(context, exc_info=True) + + error_msg = ("Unable to reach the service. " + "Check your internet connection or firewall configuration.") + response = http_error(httpexceptions.HTTPServiceUnavailable(), + errno=ERRORS.BACKEND, + message=error_msg) + + return service_unavailable(response, request)