Show More
@@ -0,0 +1,42 b'' | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | ||||
|
3 | # Copyright (C) 2010-2016 RhodeCode GmbH | |||
|
4 | # | |||
|
5 | # This program is free software: you can redistribute it and/or modify | |||
|
6 | # it under the terms of the GNU Affero General Public License, version 3 | |||
|
7 | # (only), as published by the Free Software Foundation. | |||
|
8 | # | |||
|
9 | # This program is distributed in the hope that it will be useful, | |||
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
|
12 | # GNU General Public License for more details. | |||
|
13 | # | |||
|
14 | # You should have received a copy of the GNU Affero General Public License | |||
|
15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
|
16 | # | |||
|
17 | # This program is dual-licensed. If you wish to learn more about the | |||
|
18 | # RhodeCode Enterprise Edition, including its added features, Support services, | |||
|
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |||
|
20 | ||||
|
21 | import mock | |||
|
22 | import pytest | |||
|
23 | import rhodecode.lib.vcs.client as client | |||
|
24 | ||||
|
25 | @pytest.mark.usefixtures('autologin_user', 'app') | |||
|
26 | def test_vcs_available_returns_summary_page(app, backend): | |||
|
27 | url = '/{repo_name}'.format(repo_name=backend.repo.repo_name) | |||
|
28 | response = app.get(url) | |||
|
29 | assert response.status_code == 200 | |||
|
30 | assert 'Summary' in response.body | |||
|
31 | ||||
|
32 | ||||
|
33 | @pytest.mark.usefixtures('autologin_user', 'app') | |||
|
34 | def test_vcs_unavailable_returns_vcs_error_page(app, backend): | |||
|
35 | url = '/{repo_name}'.format(repo_name=backend.repo.repo_name) | |||
|
36 | ||||
|
37 | with mock.patch.object(client, '_get_proxy_method') as p: | |||
|
38 | p.side_effect = client.exceptions.PyroVCSCommunicationError() | |||
|
39 | response = app.get(url, expect_errors=True) | |||
|
40 | ||||
|
41 | assert response.status_code == 502 | |||
|
42 | assert 'Could not connect to VCS Server' in response.body |
@@ -43,9 +43,10 b' from rhodecode.config import patches' | |||||
43 | from rhodecode.config.routing import STATIC_FILE_PREFIX |
|
43 | from rhodecode.config.routing import STATIC_FILE_PREFIX | |
44 | from rhodecode.config.environment import ( |
|
44 | from rhodecode.config.environment import ( | |
45 | load_environment, load_pyramid_environment) |
|
45 | load_environment, load_pyramid_environment) | |
|
46 | from rhodecode.lib.exceptions import VCSServerUnavailable | |||
|
47 | from rhodecode.lib.vcs.exceptions import VCSCommunicationError | |||
46 | from rhodecode.lib.middleware import csrf |
|
48 | from rhodecode.lib.middleware import csrf | |
47 | from rhodecode.lib.middleware.appenlight import wrap_in_appenlight_if_enabled |
|
49 | from rhodecode.lib.middleware.appenlight import wrap_in_appenlight_if_enabled | |
48 | from rhodecode.lib.middleware.disable_vcs import DisableVCSPagesWrapper |
|
|||
49 | from rhodecode.lib.middleware.https_fixup import HttpsFixup |
|
50 | from rhodecode.lib.middleware.https_fixup import HttpsFixup | |
50 | from rhodecode.lib.middleware.vcs import VCSMiddleware |
|
51 | from rhodecode.lib.middleware.vcs import VCSMiddleware | |
51 | from rhodecode.lib.plugins.utils import register_rhodecode_plugin |
|
52 | from rhodecode.lib.plugins.utils import register_rhodecode_plugin | |
@@ -188,10 +189,6 b' def make_not_found_view(config):' | |||||
188 |
|
189 | |||
189 | pylons_app_as_view = wsgiapp(pylons_app) |
|
190 | pylons_app_as_view = wsgiapp(pylons_app) | |
190 |
|
191 | |||
191 | # Protect from VCS Server error related pages when server is not available |
|
|||
192 | if not vcs_server_enabled: |
|
|||
193 | pylons_app_as_view = DisableVCSPagesWrapper(pylons_app_as_view) |
|
|||
194 |
|
||||
195 | def pylons_app_with_error_handler(context, request): |
|
192 | def pylons_app_with_error_handler(context, request): | |
196 | """ |
|
193 | """ | |
197 | Handle exceptions from rc pylons app: |
|
194 | Handle exceptions from rc pylons app: | |
@@ -216,10 +213,17 b' def make_not_found_view(config):' | |||||
216 | return error_handler(response, request) |
|
213 | return error_handler(response, request) | |
217 | except HTTPError as e: # pyramid type exceptions |
|
214 | except HTTPError as e: # pyramid type exceptions | |
218 | return error_handler(e, request) |
|
215 | return error_handler(e, request) | |
219 | except Exception: |
|
216 | except Exception as e: | |
|
217 | log.exception(e) | |||
|
218 | ||||
220 | if settings.get('debugtoolbar.enabled', False): |
|
219 | if settings.get('debugtoolbar.enabled', False): | |
221 | raise |
|
220 | raise | |
|
221 | ||||
|
222 | if isinstance(e, VCSCommunicationError): | |||
|
223 | return error_handler(VCSServerUnavailable(), request) | |||
|
224 | ||||
222 | return error_handler(HTTPInternalServerError(), request) |
|
225 | return error_handler(HTTPInternalServerError(), request) | |
|
226 | ||||
223 | return response |
|
227 | return response | |
224 |
|
228 | |||
225 | return pylons_app_with_error_handler |
|
229 | return pylons_app_with_error_handler |
@@ -23,6 +23,7 b' Set of custom exceptions used in RhodeCo' | |||||
23 | """ |
|
23 | """ | |
24 |
|
24 | |||
25 | from webob.exc import HTTPClientError |
|
25 | from webob.exc import HTTPClientError | |
|
26 | from pyramid.httpexceptions import HTTPBadGateway | |||
26 |
|
27 | |||
27 |
|
28 | |||
28 | class LdapUsernameError(Exception): |
|
29 | class LdapUsernameError(Exception): | |
@@ -120,3 +121,14 b' class NotAllowedToCreateUserError(Except' | |||||
120 |
|
121 | |||
121 | class RepositoryCreationError(Exception): |
|
122 | class RepositoryCreationError(Exception): | |
122 | pass |
|
123 | pass | |
|
124 | ||||
|
125 | ||||
|
126 | class VCSServerUnavailable(HTTPBadGateway): | |||
|
127 | """ HTTP Exception class for VCS Server errors """ | |||
|
128 | code = 502 | |||
|
129 | title = 'VCS Server Error' | |||
|
130 | def __init__(self, message=''): | |||
|
131 | self.explanation = 'Could not connect to VCS Server' | |||
|
132 | if message: | |||
|
133 | self.explanation += ': ' + message | |||
|
134 | super(VCSServerUnavailable, self).__init__() |
@@ -305,7 +305,7 b' def _get_proxy_method(proxy, name):' | |||||
305 | try: |
|
305 | try: | |
306 | return getattr(proxy, name) |
|
306 | return getattr(proxy, name) | |
307 | except CommunicationError: |
|
307 | except CommunicationError: | |
308 | raise CommunicationError( |
|
308 | raise exceptions.PyroVCSCommunicationError( | |
309 | 'Unable to connect to remote pyro server %s' % proxy) |
|
309 | 'Unable to connect to remote pyro server %s' % proxy) | |
310 |
|
310 | |||
311 |
|
311 |
@@ -36,6 +36,7 b' import urllib2' | |||||
36 | import urlparse |
|
36 | import urlparse | |
37 | import uuid |
|
37 | import uuid | |
38 |
|
38 | |||
|
39 | import pycurl | |||
39 | import msgpack |
|
40 | import msgpack | |
40 | import requests |
|
41 | import requests | |
41 |
|
42 | |||
@@ -172,7 +173,11 b' class RemoteObject(object):' | |||||
172 |
|
173 | |||
173 |
|
174 | |||
174 | def _remote_call(url, payload, exceptions_map, session): |
|
175 | def _remote_call(url, payload, exceptions_map, session): | |
|
176 | try: | |||
175 | response = session.post(url, data=msgpack.packb(payload)) |
|
177 | response = session.post(url, data=msgpack.packb(payload)) | |
|
178 | except pycurl.error as e: | |||
|
179 | raise exceptions.HttpVCSCommunicationError(e) | |||
|
180 | ||||
176 | response = msgpack.unpackb(response.content) |
|
181 | response = msgpack.unpackb(response.content) | |
177 | error = response.get('error') |
|
182 | error = response.get('error') | |
178 | if error: |
|
183 | if error: |
@@ -24,6 +24,19 b' Custom vcs exceptions module.' | |||||
24 |
|
24 | |||
25 | import functools |
|
25 | import functools | |
26 | import urllib2 |
|
26 | import urllib2 | |
|
27 | import pycurl | |||
|
28 | from Pyro4.errors import CommunicationError | |||
|
29 | ||||
|
30 | class VCSCommunicationError(Exception): | |||
|
31 | pass | |||
|
32 | ||||
|
33 | ||||
|
34 | class PyroVCSCommunicationError(VCSCommunicationError): | |||
|
35 | pass | |||
|
36 | ||||
|
37 | ||||
|
38 | class HttpVCSCommunicationError(VCSCommunicationError): | |||
|
39 | pass | |||
27 |
|
40 | |||
28 |
|
41 | |||
29 | class VCSError(Exception): |
|
42 | class VCSError(Exception): | |
@@ -161,7 +174,6 b' def map_vcs_exceptions(func):' | |||||
161 | try: |
|
174 | try: | |
162 | return func(*args, **kwargs) |
|
175 | return func(*args, **kwargs) | |
163 | except Exception as e: |
|
176 | except Exception as e: | |
164 |
|
||||
165 | # The error middleware adds information if it finds |
|
177 | # The error middleware adds information if it finds | |
166 | # __traceback_info__ in a frame object. This way the remote |
|
178 | # __traceback_info__ in a frame object. This way the remote | |
167 | # traceback information is made available in error reports. |
|
179 | # traceback information is made available in error reports. | |
@@ -182,5 +194,4 b' def map_vcs_exceptions(func):' | |||||
182 | raise _EXCEPTION_MAP[kind](*e.args) |
|
194 | raise _EXCEPTION_MAP[kind](*e.args) | |
183 | else: |
|
195 | else: | |
184 | raise |
|
196 | raise | |
185 |
|
||||
186 | return wrapper |
|
197 | return wrapper |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
General Comments 0
You need to be logged in to leave comments.
Login now