##// END OF EJS Templates
tests: Add a way to deactivate exception re-raising in tests.
Martin Bornhold -
r947:eb8b2333 default
parent child Browse files
Show More
@@ -1,104 +1,106 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2016-2016 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21
22 22 import logging
23
24 23 from pyramid import httpexceptions
25 24 from pyramid.httpexceptions import HTTPError, HTTPInternalServerError
26 25 from pyramid.threadlocal import get_current_request
27 26
28 27 from rhodecode.lib.exceptions import VCSServerUnavailable
29 28 from rhodecode.lib.vcs.exceptions import VCSCommunicationError
30 29
31 30
32 31 log = logging.getLogger(__name__)
33 32
34 33
35 34 class PylonsErrorHandlingMiddleware(object):
36 35 """
37 36 This middleware is wrapped around the old pylons application to catch
38 37 errors and invoke our error handling view to return a proper error page.
39 38 """
40 39 def __init__(self, app, error_view, reraise=False):
41 40 self.app = app
42 41 self.error_view = error_view
43 self.reraise = reraise
42 self._reraise = reraise
44 43
45 44 def __call__(self, environ, start_response):
46 45 # We need to use the pyramid request here instead of creating a custom
47 46 # instance from the environ because this request maybe passed to the
48 47 # error handler view which is a pyramid view and expects a pyramid
49 48 # request which has been processed by the pyramid router.
50 49 request = get_current_request()
51 50
52 51 response = self.handle_request(request)
53 52 return response(environ, start_response)
54 53
55 54 def is_vcs_response(self, response):
56 55 return 'X-RhodeCode-Backend' in response.headers
57 56
58 57 def is_http_error(self, response):
59 58 # webob type error responses
60 59 return (400 <= response.status_int <= 599)
61 60
62 61 def is_error_handling_needed(self, response):
63 62 return (self.is_http_error(response) and not
64 63 self.is_vcs_response(response))
65 64
65 def reraise(self):
66 return self._reraise
67
66 68 def handle_request(self, request):
67 69 """
68 70 Calls the underlying WSGI app (typically the old RhodeCode pylons app)
69 71 and returns the response if no error happened. In case of an error it
70 72 invokes the error handling view to return a proper error page as
71 73 response.
72 74
73 75 - old webob type exceptions get converted to pyramid exceptions
74 76 - pyramid exceptions are passed to the error handler view
75 77 """
76 78 try:
77 79 response = request.get_response(self.app)
78 80 if self.is_error_handling_needed(response):
79 81 response = webob_to_pyramid_http_response(response)
80 82 return self.error_view(response, request)
81 83 except HTTPError as e: # pyramid type exceptions
82 84 return self.error_view(e, request)
83 85 except Exception as e:
84 86 log.exception(e)
85 87
86 if self.reraise:
88 if self.reraise():
87 89 raise
88 90
89 91 if isinstance(e, VCSCommunicationError):
90 92 return self.error_view(VCSServerUnavailable(), request)
91 93
92 94 return self.error_view(HTTPInternalServerError(), request)
93 95
94 96 return response
95 97
96 98
97 99 def webob_to_pyramid_http_response(webob_response):
98 100 ResponseClass = httpexceptions.status_map[webob_response.status_int]
99 101 pyramid_response = ResponseClass(webob_response.status)
100 102 pyramid_response.status = webob_response.status
101 103 pyramid_response.headers.update(webob_response.headers)
102 104 if pyramid_response.headers['content-type'] == 'text/html':
103 105 pyramid_response.headers['content-type'] = 'text/html; charset=UTF-8'
104 106 return pyramid_response
@@ -1,47 +1,50 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2016 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 import mock
22 22 import pytest
23 import rhodecode
24 23 import rhodecode.lib.vcs.client as client
24 from rhodecode.lib.middleware.error_handling import (
25 PylonsErrorHandlingMiddleware)
26
25 27
26 28 @pytest.mark.usefixtures('autologin_user', 'app')
27 29 def test_vcs_available_returns_summary_page(app, backend):
28 30 url = '/{repo_name}'.format(repo_name=backend.repo.repo_name)
29 31 response = app.get(url)
30 32 assert response.status_code == 200
31 33 assert 'Summary' in response.body
32 34
33 35
34 36 @pytest.mark.usefixtures('autologin_user', 'app')
35 37 def test_vcs_unavailable_returns_vcs_error_page(app, backend):
36 38 url = '/{repo_name}'.format(repo_name=backend.repo.repo_name)
37 39
38 try:
39 rhodecode.disable_error_handler = False
40 with mock.patch.object(client, '_get_proxy_method') as p:
41 p.side_effect = client.exceptions.PyroVCSCommunicationError()
40 # Path the get proxy method to raise an exception instead of making a RPC
41 # call to the vcsserver.
42 with mock.patch.object(client, '_get_proxy_method') as p:
43 p.side_effect = client.exceptions.PyroVCSCommunicationError()
44 # Patch pylons error handling middleware to not re-raise exceptions.
45 with mock.patch.object(PylonsErrorHandlingMiddleware, 'reraise') as r:
46 r.return_value = False
42 47 response = app.get(url, expect_errors=True)
43 finally:
44 rhodecode.disable_error_handler = True
45 48
46 49 assert response.status_code == 502
47 50 assert 'Could not connect to VCS Server' in response.body
General Comments 0
You need to be logged in to leave comments. Login now