##// END OF EJS Templates
tests: disable pretty error page handler for tests, with option to...
dan -
r735:eaa85268 default
parent child Browse files
Show More
@@ -1,188 +1,190 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 """
22 22 Pylons environment configuration
23 23 """
24 24
25 25 import os
26 26 import logging
27 27 import rhodecode
28 28 import platform
29 29 import re
30 30 import io
31 31
32 32 from mako.lookup import TemplateLookup
33 33 from pylons.configuration import PylonsConfig
34 34 from pylons.error import handle_mako_error
35 35 from pyramid.settings import asbool
36 36
37 37 # ------------------------------------------------------------------------------
38 38 # CELERY magic until refactor - issue #4163 - import order matters here:
39 39 from rhodecode.lib import celerypylons # this must be first, celerypylons
40 40 # sets config settings upon import
41 41
42 42 import rhodecode.integrations # any modules using celery task
43 43 # decorators should be added afterwards:
44 44 # ------------------------------------------------------------------------------
45 45
46 46 from rhodecode.lib import app_globals
47 47 from rhodecode.config import utils
48 48 from rhodecode.config.routing import make_map
49 49 from rhodecode.config.jsroutes import generate_jsroutes_content
50 50
51 51 from rhodecode.lib import helpers
52 52 from rhodecode.lib.auth import set_available_permissions
53 53 from rhodecode.lib.utils import (
54 54 repo2db_mapper, make_db_config, set_rhodecode_config,
55 55 load_rcextensions)
56 56 from rhodecode.lib.utils2 import str2bool, aslist
57 57 from rhodecode.lib.vcs import connect_vcs, start_vcs_server
58 58 from rhodecode.model.scm import ScmModel
59 59
60 60 log = logging.getLogger(__name__)
61 61
62 62 def load_environment(global_conf, app_conf, initial=False,
63 63 test_env=None, test_index=None):
64 64 """
65 65 Configure the Pylons environment via the ``pylons.config``
66 66 object
67 67 """
68 68 config = PylonsConfig()
69 69
70 70
71 71 # Pylons paths
72 72 root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
73 73 paths = {
74 74 'root': root,
75 75 'controllers': os.path.join(root, 'controllers'),
76 76 'static_files': os.path.join(root, 'public'),
77 77 'templates': [os.path.join(root, 'templates')],
78 78 }
79 79
80 80 # Initialize config with the basic options
81 81 config.init_app(global_conf, app_conf, package='rhodecode', paths=paths)
82 82
83 83 # store some globals into rhodecode
84 84 rhodecode.CELERY_ENABLED = str2bool(config['app_conf'].get('use_celery'))
85 85 rhodecode.CELERY_EAGER = str2bool(
86 86 config['app_conf'].get('celery.always.eager'))
87 87
88 88 config['routes.map'] = make_map(config)
89 89
90 90 if asbool(config.get('generate_js_files', 'false')):
91 91 jsroutes = config['routes.map'].jsroutes()
92 92 jsroutes_file_content = generate_jsroutes_content(jsroutes)
93 93 jsroutes_file_path = os.path.join(
94 94 paths['static_files'], 'js', 'rhodecode', 'routes.js')
95 95
96 96 with io.open(jsroutes_file_path, 'w', encoding='utf-8') as f:
97 97 f.write(jsroutes_file_content)
98 98
99 99 config['pylons.app_globals'] = app_globals.Globals(config)
100 100 config['pylons.h'] = helpers
101 101 rhodecode.CONFIG = config
102 102
103 103 load_rcextensions(root_path=config['here'])
104 104
105 105 # Setup cache object as early as possible
106 106 import pylons
107 107 pylons.cache._push_object(config['pylons.app_globals'].cache)
108 108
109 109 # Create the Mako TemplateLookup, with the default auto-escaping
110 110 config['pylons.app_globals'].mako_lookup = TemplateLookup(
111 111 directories=paths['templates'],
112 112 error_handler=handle_mako_error,
113 113 module_directory=os.path.join(app_conf['cache_dir'], 'templates'),
114 114 input_encoding='utf-8', default_filters=['escape'],
115 115 imports=['from webhelpers.html import escape'])
116 116
117 117 # sets the c attribute access when don't existing attribute are accessed
118 118 config['pylons.strict_tmpl_context'] = True
119 119
120 120 # configure channelstream
121 121 config['channelstream_config'] = {
122 122 'enabled': asbool(config.get('channelstream.enabled', False)),
123 123 'server': config.get('channelstream.server'),
124 124 'secret': config.get('channelstream.secret')
125 125 }
126 126
127 127 set_available_permissions(config)
128 128 db_cfg = make_db_config(clear_session=True)
129 129
130 130 repos_path = list(db_cfg.items('paths'))[0][1]
131 131 config['base_path'] = repos_path
132 132
133 133 # store db config also in main global CONFIG
134 134 set_rhodecode_config(config)
135 135
136 136 # configure instance id
137 137 utils.set_instance_id(config)
138 138
139 139 # CONFIGURATION OPTIONS HERE (note: all config options will override
140 140 # any Pylons config options)
141 141
142 142 # store config reference into our module to skip import magic of pylons
143 143 rhodecode.CONFIG.update(config)
144 144
145 145 return config
146 146
147 147
148 148 def load_pyramid_environment(global_config, settings):
149 149 # Some parts of the code expect a merge of global and app settings.
150 150 settings_merged = global_config.copy()
151 151 settings_merged.update(settings)
152 152
153 153 # Store the settings to make them available to other modules.
154 154 rhodecode.PYRAMID_SETTINGS = settings_merged
155 155
156 156 # If this is a test run we prepare the test environment like
157 157 # creating a test database, test search index and test repositories.
158 158 # This has to be done before the database connection is initialized.
159 159 if settings['is_test']:
160 160 rhodecode.is_test = True
161 rhodecode.disable_error_handler = True
162
161 163 utils.initialize_test_environment(settings_merged)
162 164
163 165 # Initialize the database connection.
164 166 utils.initialize_database(settings_merged)
165 167
166 168 # Limit backends to `vcs.backends` from configuration
167 169 for alias in rhodecode.BACKENDS.keys():
168 170 if alias not in settings['vcs.backends']:
169 171 del rhodecode.BACKENDS[alias]
170 172 log.info('Enabled VCS backends: %s', rhodecode.BACKENDS.keys())
171 173
172 174 # initialize vcs client and optionally run the server if enabled
173 175 vcs_server_uri = settings['vcs.server']
174 176 vcs_server_enabled = settings['vcs.server.enable']
175 177 start_server = (
176 178 settings['vcs.start_server'] and
177 179 not int(os.environ.get('RC_VCSSERVER_TEST_DISABLE', '0')))
178 180
179 181 if vcs_server_enabled and start_server:
180 182 log.info("Starting vcsserver")
181 183 start_vcs_server(server_and_port=vcs_server_uri,
182 184 protocol=utils.get_vcs_server_protocol(settings),
183 185 log_level=settings['vcs.server.log_level'])
184 186
185 187 utils.configure_pyro4(settings)
186 188 utils.configure_vcs(settings)
187 189 if vcs_server_enabled:
188 190 connect_vcs(vcs_server_uri, utils.get_vcs_server_protocol(settings))
@@ -1,504 +1,505 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 """
22 22 Pylons middleware initialization
23 23 """
24 24 import logging
25 25 from collections import OrderedDict
26 26
27 27 from paste.registry import RegistryManager
28 28 from paste.gzipper import make_gzip_middleware
29 29 from pylons.wsgiapp import PylonsApp
30 30 from pyramid.authorization import ACLAuthorizationPolicy
31 31 from pyramid.config import Configurator
32 32 from pyramid.settings import asbool, aslist
33 33 from pyramid.wsgi import wsgiapp
34 34 from pyramid.httpexceptions import HTTPError, HTTPInternalServerError, HTTPFound
35 35 from pyramid.events import ApplicationCreated
36 36 import pyramid.httpexceptions as httpexceptions
37 37 from pyramid.renderers import render_to_response
38 38 from routes.middleware import RoutesMiddleware
39 39 import routes.util
40 40
41 41 import rhodecode
42 42 from rhodecode.model import meta
43 43 from rhodecode.config import patches
44 44 from rhodecode.config.routing import STATIC_FILE_PREFIX
45 45 from rhodecode.config.environment import (
46 46 load_environment, load_pyramid_environment)
47 47 from rhodecode.lib.exceptions import VCSServerUnavailable
48 48 from rhodecode.lib.vcs.exceptions import VCSCommunicationError
49 49 from rhodecode.lib.middleware import csrf
50 50 from rhodecode.lib.middleware.appenlight import wrap_in_appenlight_if_enabled
51 51 from rhodecode.lib.middleware.https_fixup import HttpsFixup
52 52 from rhodecode.lib.middleware.vcs import VCSMiddleware
53 53 from rhodecode.lib.plugins.utils import register_rhodecode_plugin
54 54 from rhodecode.lib.utils2 import aslist as rhodecode_aslist
55 55 from rhodecode.subscribers import scan_repositories_if_enabled
56 56
57 57
58 58 log = logging.getLogger(__name__)
59 59
60 60
61 61 # this is used to avoid avoid the route lookup overhead in routesmiddleware
62 62 # for certain routes which won't go to pylons to - eg. static files, debugger
63 63 # it is only needed for the pylons migration and can be removed once complete
64 64 class SkippableRoutesMiddleware(RoutesMiddleware):
65 65 """ Routes middleware that allows you to skip prefixes """
66 66
67 67 def __init__(self, *args, **kw):
68 68 self.skip_prefixes = kw.pop('skip_prefixes', [])
69 69 super(SkippableRoutesMiddleware, self).__init__(*args, **kw)
70 70
71 71 def __call__(self, environ, start_response):
72 72 for prefix in self.skip_prefixes:
73 73 if environ['PATH_INFO'].startswith(prefix):
74 74 # added to avoid the case when a missing /_static route falls
75 75 # through to pylons and causes an exception as pylons is
76 76 # expecting wsgiorg.routingargs to be set in the environ
77 77 # by RoutesMiddleware.
78 78 if 'wsgiorg.routing_args' not in environ:
79 79 environ['wsgiorg.routing_args'] = (None, {})
80 80 return self.app(environ, start_response)
81 81
82 82 return super(SkippableRoutesMiddleware, self).__call__(
83 83 environ, start_response)
84 84
85 85
86 86 def make_app(global_conf, static_files=True, **app_conf):
87 87 """Create a Pylons WSGI application and return it
88 88
89 89 ``global_conf``
90 90 The inherited configuration for this application. Normally from
91 91 the [DEFAULT] section of the Paste ini file.
92 92
93 93 ``app_conf``
94 94 The application's local configuration. Normally specified in
95 95 the [app:<name>] section of the Paste ini file (where <name>
96 96 defaults to main).
97 97
98 98 """
99 99 # Apply compatibility patches
100 100 patches.kombu_1_5_1_python_2_7_11()
101 101 patches.inspect_getargspec()
102 102
103 103 # Configure the Pylons environment
104 104 config = load_environment(global_conf, app_conf)
105 105
106 106 # The Pylons WSGI app
107 107 app = PylonsApp(config=config)
108 108 if rhodecode.is_test:
109 109 app = csrf.CSRFDetector(app)
110 110
111 111 expected_origin = config.get('expected_origin')
112 112 if expected_origin:
113 113 # The API can be accessed from other Origins.
114 114 app = csrf.OriginChecker(app, expected_origin,
115 115 skip_urls=[routes.util.url_for('api')])
116 116
117 117 # Establish the Registry for this application
118 118 app = RegistryManager(app)
119 119
120 120 app.config = config
121 121
122 122 return app
123 123
124 124
125 125 def make_pyramid_app(global_config, **settings):
126 126 """
127 127 Constructs the WSGI application based on Pyramid and wraps the Pylons based
128 128 application.
129 129
130 130 Specials:
131 131
132 132 * We migrate from Pylons to Pyramid. While doing this, we keep both
133 133 frameworks functional. This involves moving some WSGI middlewares around
134 134 and providing access to some data internals, so that the old code is
135 135 still functional.
136 136
137 137 * The application can also be integrated like a plugin via the call to
138 138 `includeme`. This is accompanied with the other utility functions which
139 139 are called. Changing this should be done with great care to not break
140 140 cases when these fragments are assembled from another place.
141 141
142 142 """
143 143 # The edition string should be available in pylons too, so we add it here
144 144 # before copying the settings.
145 145 settings.setdefault('rhodecode.edition', 'Community Edition')
146 146
147 147 # As long as our Pylons application does expect "unprepared" settings, make
148 148 # sure that we keep an unmodified copy. This avoids unintentional change of
149 149 # behavior in the old application.
150 150 settings_pylons = settings.copy()
151 151
152 152 sanitize_settings_and_apply_defaults(settings)
153 153 config = Configurator(settings=settings)
154 154 add_pylons_compat_data(config.registry, global_config, settings_pylons)
155 155
156 156 load_pyramid_environment(global_config, settings)
157 157
158 158 includeme_first(config)
159 159 includeme(config)
160 160 pyramid_app = config.make_wsgi_app()
161 161 pyramid_app = wrap_app_in_wsgi_middlewares(pyramid_app, config)
162 162 pyramid_app.config = config
163 163
164 164 # creating the app uses a connection - return it after we are done
165 165 meta.Session.remove()
166 166
167 167 return pyramid_app
168 168
169 169
170 170 def make_not_found_view(config):
171 171 """
172 172 This creates the view which should be registered as not-found-view to
173 173 pyramid. Basically it contains of the old pylons app, converted to a view.
174 174 Additionally it is wrapped by some other middlewares.
175 175 """
176 176 settings = config.registry.settings
177 177 vcs_server_enabled = settings['vcs.server.enable']
178 178
179 179 # Make pylons app from unprepared settings.
180 180 pylons_app = make_app(
181 181 config.registry._pylons_compat_global_config,
182 182 **config.registry._pylons_compat_settings)
183 183 config.registry._pylons_compat_config = pylons_app.config
184 184
185 185 # Appenlight monitoring.
186 186 pylons_app, appenlight_client = wrap_in_appenlight_if_enabled(
187 187 pylons_app, settings)
188 188
189 189 # The VCSMiddleware shall operate like a fallback if pyramid doesn't find
190 190 # a view to handle the request. Therefore we wrap it around the pylons app.
191 191 if vcs_server_enabled:
192 192 pylons_app = VCSMiddleware(
193 193 pylons_app, settings, appenlight_client, registry=config.registry)
194 194
195 195 pylons_app_as_view = wsgiapp(pylons_app)
196 196
197 197 def pylons_app_with_error_handler(context, request):
198 198 """
199 199 Handle exceptions from rc pylons app:
200 200
201 201 - old webob type exceptions get converted to pyramid exceptions
202 202 - pyramid exceptions are passed to the error handler view
203 203 """
204 204 def is_vcs_response(response):
205 205 return 'X-RhodeCode-Backend' in response.headers
206 206
207 207 def is_http_error(response):
208 208 # webob type error responses
209 209 return (400 <= response.status_int <= 599)
210 210
211 211 def is_error_handling_needed(response):
212 212 return is_http_error(response) and not is_vcs_response(response)
213 213
214 214 try:
215 215 response = pylons_app_as_view(context, request)
216 216 if is_error_handling_needed(response):
217 217 response = webob_to_pyramid_http_response(response)
218 218 return error_handler(response, request)
219 219 except HTTPError as e: # pyramid type exceptions
220 220 return error_handler(e, request)
221 221 except Exception as e:
222 222 log.exception(e)
223 223
224 if settings.get('debugtoolbar.enabled', False):
224 if (settings.get('debugtoolbar.enabled', False) or
225 rhodecode.disable_error_handler):
225 226 raise
226 227
227 228 if isinstance(e, VCSCommunicationError):
228 229 return error_handler(VCSServerUnavailable(), request)
229 230
230 231 return error_handler(HTTPInternalServerError(), request)
231 232
232 233 return response
233 234
234 235 return pylons_app_with_error_handler
235 236
236 237
237 238 def add_pylons_compat_data(registry, global_config, settings):
238 239 """
239 240 Attach data to the registry to support the Pylons integration.
240 241 """
241 242 registry._pylons_compat_global_config = global_config
242 243 registry._pylons_compat_settings = settings
243 244
244 245
245 246 def webob_to_pyramid_http_response(webob_response):
246 247 ResponseClass = httpexceptions.status_map[webob_response.status_int]
247 248 pyramid_response = ResponseClass(webob_response.status)
248 249 pyramid_response.status = webob_response.status
249 250 pyramid_response.headers.update(webob_response.headers)
250 251 if pyramid_response.headers['content-type'] == 'text/html':
251 252 pyramid_response.headers['content-type'] = 'text/html; charset=UTF-8'
252 253 return pyramid_response
253 254
254 255
255 256 def error_handler(exception, request):
256 257 from rhodecode.model.settings import SettingsModel
257 258 from rhodecode.lib.utils2 import AttributeDict
258 259
259 260 try:
260 261 rc_config = SettingsModel().get_all_settings()
261 262 except Exception:
262 263 log.exception('failed to fetch settings')
263 264 rc_config = {}
264 265
265 266 base_response = HTTPInternalServerError()
266 267 # prefer original exception for the response since it may have headers set
267 268 if isinstance(exception, HTTPError):
268 269 base_response = exception
269 270
270 271 c = AttributeDict()
271 272 c.error_message = base_response.status
272 273 c.error_explanation = base_response.explanation or str(base_response)
273 274 c.visual = AttributeDict()
274 275
275 276 c.visual.rhodecode_support_url = (
276 277 request.registry.settings.get('rhodecode_support_url') or
277 278 request.route_url('rhodecode_support')
278 279 )
279 280 c.redirect_time = 0
280 281 c.rhodecode_name = rc_config.get('rhodecode_title', '')
281 282 if not c.rhodecode_name:
282 283 c.rhodecode_name = 'Rhodecode'
283 284
284 285 c.causes = []
285 286 if hasattr(base_response, 'causes'):
286 287 c.causes = base_response.causes
287 288
288 289 response = render_to_response(
289 290 '/errors/error_document.html', {'c': c}, request=request,
290 291 response=base_response)
291 292
292 293 return response
293 294
294 295
295 296 def includeme(config):
296 297 settings = config.registry.settings
297 298
298 299 # plugin information
299 300 config.registry.rhodecode_plugins = OrderedDict()
300 301
301 302 config.add_directive(
302 303 'register_rhodecode_plugin', register_rhodecode_plugin)
303 304
304 305 if asbool(settings.get('appenlight', 'false')):
305 306 config.include('appenlight_client.ext.pyramid_tween')
306 307
307 308 # Includes which are required. The application would fail without them.
308 309 config.include('pyramid_mako')
309 310 config.include('pyramid_beaker')
310 311 config.include('rhodecode.channelstream')
311 312 config.include('rhodecode.admin')
312 313 config.include('rhodecode.authentication')
313 314 config.include('rhodecode.integrations')
314 315 config.include('rhodecode.login')
315 316 config.include('rhodecode.tweens')
316 317 config.include('rhodecode.api')
317 318 config.include('rhodecode.svn_support')
318 319 config.add_route(
319 320 'rhodecode_support', 'https://rhodecode.com/help/', static=True)
320 321
321 322 # Add subscribers.
322 323 config.add_subscriber(scan_repositories_if_enabled, ApplicationCreated)
323 324
324 325 # Set the authorization policy.
325 326 authz_policy = ACLAuthorizationPolicy()
326 327 config.set_authorization_policy(authz_policy)
327 328
328 329 # Set the default renderer for HTML templates to mako.
329 330 config.add_mako_renderer('.html')
330 331
331 332 # include RhodeCode plugins
332 333 includes = aslist(settings.get('rhodecode.includes', []))
333 334 for inc in includes:
334 335 config.include(inc)
335 336
336 337 # This is the glue which allows us to migrate in chunks. By registering the
337 338 # pylons based application as the "Not Found" view in Pyramid, we will
338 339 # fallback to the old application each time the new one does not yet know
339 340 # how to handle a request.
340 341 config.add_notfound_view(make_not_found_view(config))
341 342
342 343 if not settings.get('debugtoolbar.enabled', False):
343 344 # if no toolbar, then any exception gets caught and rendered
344 345 config.add_view(error_handler, context=Exception)
345 346
346 347 config.add_view(error_handler, context=HTTPError)
347 348
348 349
349 350 def includeme_first(config):
350 351 # redirect automatic browser favicon.ico requests to correct place
351 352 def favicon_redirect(context, request):
352 353 return HTTPFound(
353 354 request.static_path('rhodecode:public/images/favicon.ico'))
354 355
355 356 config.add_view(favicon_redirect, route_name='favicon')
356 357 config.add_route('favicon', '/favicon.ico')
357 358
358 359 config.add_static_view(
359 360 '_static/deform', 'deform:static')
360 361 config.add_static_view(
361 362 '_static/rhodecode', path='rhodecode:public', cache_max_age=3600 * 24)
362 363
363 364
364 365 def wrap_app_in_wsgi_middlewares(pyramid_app, config):
365 366 """
366 367 Apply outer WSGI middlewares around the application.
367 368
368 369 Part of this has been moved up from the Pylons layer, so that the
369 370 data is also available if old Pylons code is hit through an already ported
370 371 view.
371 372 """
372 373 settings = config.registry.settings
373 374
374 375 # enable https redirects based on HTTP_X_URL_SCHEME set by proxy
375 376 pyramid_app = HttpsFixup(pyramid_app, settings)
376 377
377 378 # Add RoutesMiddleware to support the pylons compatibility tween during
378 379 # migration to pyramid.
379 380 pyramid_app = SkippableRoutesMiddleware(
380 381 pyramid_app, config.registry._pylons_compat_config['routes.map'],
381 382 skip_prefixes=(STATIC_FILE_PREFIX, '/_debug_toolbar'))
382 383
383 384 pyramid_app, _ = wrap_in_appenlight_if_enabled(pyramid_app, settings)
384 385
385 386 if settings['gzip_responses']:
386 387 pyramid_app = make_gzip_middleware(
387 388 pyramid_app, settings, compress_level=1)
388 389
389 390
390 391 # this should be the outer most middleware in the wsgi stack since
391 392 # middleware like Routes make database calls
392 393 def pyramid_app_with_cleanup(environ, start_response):
393 394 try:
394 395 return pyramid_app(environ, start_response)
395 396 finally:
396 397 # Dispose current database session and rollback uncommitted
397 398 # transactions.
398 399 meta.Session.remove()
399 400
400 401 # In a single threaded mode server, on non sqlite db we should have
401 402 # '0 Current Checked out connections' at the end of a request,
402 403 # if not, then something, somewhere is leaving a connection open
403 404 pool = meta.Base.metadata.bind.engine.pool
404 405 log.debug('sa pool status: %s', pool.status())
405 406
406 407
407 408 return pyramid_app_with_cleanup
408 409
409 410
410 411 def sanitize_settings_and_apply_defaults(settings):
411 412 """
412 413 Applies settings defaults and does all type conversion.
413 414
414 415 We would move all settings parsing and preparation into this place, so that
415 416 we have only one place left which deals with this part. The remaining parts
416 417 of the application would start to rely fully on well prepared settings.
417 418
418 419 This piece would later be split up per topic to avoid a big fat monster
419 420 function.
420 421 """
421 422
422 423 # Pyramid's mako renderer has to search in the templates folder so that the
423 424 # old templates still work. Ported and new templates are expected to use
424 425 # real asset specifications for the includes.
425 426 mako_directories = settings.setdefault('mako.directories', [
426 427 # Base templates of the original Pylons application
427 428 'rhodecode:templates',
428 429 ])
429 430 log.debug(
430 431 "Using the following Mako template directories: %s",
431 432 mako_directories)
432 433
433 434 # Default includes, possible to change as a user
434 435 pyramid_includes = settings.setdefault('pyramid.includes', [
435 436 'rhodecode.lib.middleware.request_wrapper',
436 437 ])
437 438 log.debug(
438 439 "Using the following pyramid.includes: %s",
439 440 pyramid_includes)
440 441
441 442 # TODO: johbo: Re-think this, usually the call to config.include
442 443 # should allow to pass in a prefix.
443 444 settings.setdefault('rhodecode.api.url', '/_admin/api')
444 445
445 446 # Sanitize generic settings.
446 447 _list_setting(settings, 'default_encoding', 'UTF-8')
447 448 _bool_setting(settings, 'is_test', 'false')
448 449 _bool_setting(settings, 'gzip_responses', 'false')
449 450
450 451 # Call split out functions that sanitize settings for each topic.
451 452 _sanitize_appenlight_settings(settings)
452 453 _sanitize_vcs_settings(settings)
453 454
454 455 return settings
455 456
456 457
457 458 def _sanitize_appenlight_settings(settings):
458 459 _bool_setting(settings, 'appenlight', 'false')
459 460
460 461
461 462 def _sanitize_vcs_settings(settings):
462 463 """
463 464 Applies settings defaults and does type conversion for all VCS related
464 465 settings.
465 466 """
466 467 _string_setting(settings, 'vcs.svn.compatible_version', '')
467 468 _string_setting(settings, 'git_rev_filter', '--all')
468 469 _string_setting(settings, 'vcs.hooks.protocol', 'pyro4')
469 470 _string_setting(settings, 'vcs.server', '')
470 471 _string_setting(settings, 'vcs.server.log_level', 'debug')
471 472 _string_setting(settings, 'vcs.server.protocol', 'pyro4')
472 473 _bool_setting(settings, 'startup.import_repos', 'false')
473 474 _bool_setting(settings, 'vcs.hooks.direct_calls', 'false')
474 475 _bool_setting(settings, 'vcs.server.enable', 'true')
475 476 _bool_setting(settings, 'vcs.start_server', 'false')
476 477 _list_setting(settings, 'vcs.backends', 'hg, git, svn')
477 478 _int_setting(settings, 'vcs.connection_timeout', 3600)
478 479
479 480
480 481 def _int_setting(settings, name, default):
481 482 settings[name] = int(settings.get(name, default))
482 483
483 484
484 485 def _bool_setting(settings, name, default):
485 486 input = settings.get(name, default)
486 487 if isinstance(input, unicode):
487 488 input = input.encode('utf8')
488 489 settings[name] = asbool(input)
489 490
490 491
491 492 def _list_setting(settings, name, default):
492 493 raw_value = settings.get(name, default)
493 494
494 495 old_separator = ','
495 496 if old_separator in raw_value:
496 497 # If we get a comma separated list, pass it to our own function.
497 498 settings[name] = rhodecode_aslist(raw_value, sep=old_separator)
498 499 else:
499 500 # Otherwise we assume it uses pyramids space/newline separation.
500 501 settings[name] = aslist(raw_value)
501 502
502 503
503 504 def _string_setting(settings, name, default):
504 505 settings[name] = settings.get(name, default).lower()
@@ -1,42 +1,47 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
23 24 import rhodecode.lib.vcs.client as client
24 25
25 26 @pytest.mark.usefixtures('autologin_user', 'app')
26 27 def test_vcs_available_returns_summary_page(app, backend):
27 28 url = '/{repo_name}'.format(repo_name=backend.repo.repo_name)
28 29 response = app.get(url)
29 30 assert response.status_code == 200
30 31 assert 'Summary' in response.body
31 32
32 33
33 34 @pytest.mark.usefixtures('autologin_user', 'app')
34 35 def test_vcs_unavailable_returns_vcs_error_page(app, backend):
35 36 url = '/{repo_name}'.format(repo_name=backend.repo.repo_name)
36 37
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)
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()
42 response = app.get(url, expect_errors=True)
43 finally:
44 rhodecode.disable_error_handler = True
40 45
41 46 assert response.status_code == 502
42 47 assert 'Could not connect to VCS Server' in response.body
General Comments 0
You need to be logged in to leave comments. Login now