##// END OF EJS Templates
settings: fixed found problem on new admin pyramid views, and made all test pass for them.
marcink -
r1313:8df63e5b default
parent child Browse files
Show More
@@ -1,101 +1,101 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2016-2017 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 collections
22 22 import logging
23 23
24 24 from pylons import tmpl_context as c
25 25 from pyramid.view import view_config
26 26 from pyramid.httpexceptions import HTTPFound
27 27
28 28 from rhodecode.translation import _
29 29
30 30 from rhodecode.admin.views.base import AdminSettingsView
31 31 from rhodecode.lib.auth import (
32 32 LoginRequired, HasPermissionAllDecorator, CSRFRequired)
33 33 from rhodecode.lib.utils2 import safe_int
34 34 from rhodecode.lib import system_info
35 35 from rhodecode.lib import user_sessions
36 36
37 37
38 38 from rhodecode.admin.navigation import navigation_list
39 39
40 40
41 41 log = logging.getLogger(__name__)
42 42
43 43
44 44 class AdminSessionSettingsView(AdminSettingsView):
45 45
46 46 @LoginRequired()
47 47 @HasPermissionAllDecorator('hg.admin')
48 48 @view_config(
49 49 route_name='admin_settings_sessions', request_method='GET',
50 50 renderer='rhodecode:templates/admin/settings/settings.mako')
51 51 def settings_sessions(self):
52 52 c.active = 'sessions'
53 53 c.navlist = navigation_list(self.request)
54 54
55 55 c.cleanup_older_days = 60
56 56 older_than_seconds = 24 * 60 * 60 * 24 * c.cleanup_older_days
57 57
58 58 config = system_info.rhodecode_config().get_value()['value']['config']
59 59 c.session_model = user_sessions.get_session_handler(
60 60 config.get('beaker.session.type', 'memory'))(config)
61 61
62 62 c.session_conf = c.session_model.config
63 63 c.session_count = c.session_model.get_count()
64 64 c.session_expired_count = c.session_model.get_expired_count(
65 65 older_than_seconds)
66 66
67 67 return {}
68 68
69 69 @LoginRequired()
70 70 @CSRFRequired()
71 71 @HasPermissionAllDecorator('hg.admin')
72 72 @view_config(
73 73 route_name='admin_settings_sessions_cleanup', request_method='POST')
74 74 def settings_sessions_cleanup(self):
75 75
76 76 expire_days = safe_int(self.request.params.get('expire_days'))
77 77
78 78 if expire_days is None:
79 79 expire_days = 60
80 80
81 81 older_than_seconds = 24 * 60 * 60 * 24 * expire_days
82 82
83 83 config = system_info.rhodecode_config().get_value()['value']['config']
84 84 session_model = user_sessions.get_session_handler(
85 85 config.get('beaker.session.type', 'memory'))(config)
86 86
87 87 try:
88 88 session_model.clean_sessions(
89 89 older_than_seconds=older_than_seconds)
90 90 self.request.session.flash(
91 91 _('Cleaned up old sessions'), queue='success')
92 92 except user_sessions.CleanupCommand as msg:
93 self.request.session.flash(msg, category='warning')
93 self.request.session.flash(msg.message, queue='warning')
94 94 except Exception as e:
95 95 log.exception('Failed session cleanup')
96 96 self.request.session.flash(
97 97 _('Failed to cleanup up old sessions'), queue='error')
98 98
99 99 redirect_to = self.request.resource_path(
100 100 self.context, route_name='admin_settings_sessions')
101 101 return HTTPFound(redirect_to)
@@ -1,200 +1,202 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2016-2017 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 logging
22 22 import urllib2
23 23 import packaging.version
24 24
25 25 from pylons import tmpl_context as c
26 26 from pyramid.view import view_config
27 27
28 28 import rhodecode
29 29 from rhodecode.lib import helpers as h
30 30 from rhodecode.lib.auth import (LoginRequired, HasPermissionAllDecorator)
31 31 from rhodecode.lib.utils2 import str2bool
32 32 from rhodecode.lib import system_info
33 33 from rhodecode.lib.ext_json import json
34 34
35 35 from rhodecode.admin.views.base import AdminSettingsView
36 36 from rhodecode.admin.navigation import navigation_list
37 37 from rhodecode.model.settings import SettingsModel
38 38
39 39 log = logging.getLogger(__name__)
40 40
41 41
42 42 class AdminSystemInfoSettingsView(AdminSettingsView):
43 43
44 44 @staticmethod
45 45 def get_update_data(update_url):
46 46 """Return the JSON update data."""
47 47 ver = rhodecode.__version__
48 48 log.debug('Checking for upgrade on `%s` server', update_url)
49 49 opener = urllib2.build_opener()
50 50 opener.addheaders = [('User-agent', 'RhodeCode-SCM/%s' % ver)]
51 51 response = opener.open(update_url)
52 52 response_data = response.read()
53 53 data = json.loads(response_data)
54 54
55 55 return data
56 56
57 57 def get_update_url(self):
58 58 settings = SettingsModel().get_all_settings()
59 59 return settings.get('rhodecode_update_url')
60 60
61 61 @LoginRequired()
62 62 @HasPermissionAllDecorator('hg.admin')
63 63 @view_config(
64 64 route_name='admin_settings_system', request_method='GET',
65 65 renderer='rhodecode:templates/admin/settings/settings.mako')
66 def settings_sessions(self):
66 def settings_system_info(self):
67 67 _ = self.request.translate
68 68
69 69 c.active = 'system'
70 70 c.navlist = navigation_list(self.request)
71 71
72 72 # TODO(marcink), figure out how to allow only selected users to do this
73 73 c.allowed_to_snapshot = self._rhodecode_user.admin
74 74
75 75 snapshot = str2bool(self.request.params.get('snapshot'))
76 76
77 77 c.rhodecode_update_url = self.get_update_url()
78 78 server_info = system_info.get_system_info(self.request.environ)
79 79
80 80 for key, val in server_info.items():
81 81 setattr(c, key, val)
82 82
83 83 def val(name, subkey='human_value'):
84 84 return server_info[name][subkey]
85 85
86 86 def state(name):
87 87 return server_info[name]['state']
88 88
89 89 def val2(name):
90 90 val = server_info[name]['human_value']
91 91 state = server_info[name]['state']
92 92 return val, state
93 93
94 94 update_info_msg = _('Note: please make sure this server can '
95 95 'access `${url}` for the update link to work',
96 96 mapping=dict(url=c.rhodecode_update_url))
97 97 c.data_items = [
98 98 # update info
99 99 (_('Update info'), h.literal(
100 100 '<span class="link" id="check_for_update" >%s.</span>' % (
101 101 _('Check for updates')) +
102 102 '<br/> <span >%s.</span>' % (update_info_msg)
103 103 ), ''),
104 104
105 105 # RhodeCode specific
106 106 (_('RhodeCode Version'), val('rhodecode_app')['text'], state('rhodecode_app')),
107 107 (_('RhodeCode Server IP'), val('server')['server_ip'], state('server')),
108 108 (_('RhodeCode Server ID'), val('server')['server_id'], state('server')),
109 109 (_('RhodeCode Configuration'), val('rhodecode_config')['path'], state('rhodecode_config')),
110 110 ('', '', ''), # spacer
111 111
112 112 # Database
113 113 (_('Database'), val('database')['url'], state('database')),
114 114 (_('Database version'), val('database')['version'], state('database')),
115 115 ('', '', ''), # spacer
116 116
117 117 # Platform/Python
118 118 (_('Platform'), val('platform')['name'], state('platform')),
119 119 (_('Platform UUID'), val('platform')['uuid'], state('platform')),
120 120 (_('Python version'), val('python')['version'], state('python')),
121 121 (_('Python path'), val('python')['executable'], state('python')),
122 122 ('', '', ''), # spacer
123 123
124 124 # Systems stats
125 125 (_('CPU'), val('cpu'), state('cpu')),
126 126 (_('Load'), val('load')['text'], state('load')),
127 127 (_('Memory'), val('memory')['text'], state('memory')),
128 128 (_('Uptime'), val('uptime')['text'], state('uptime')),
129 129 ('', '', ''), # spacer
130 130
131 131 # Repo storage
132 132 (_('Storage location'), val('storage')['path'], state('storage')),
133 133 (_('Storage info'), val('storage')['text'], state('storage')),
134 134 (_('Storage inodes'), val('storage_inodes')['text'], state('storage_inodes')),
135 135
136 136 (_('Gist storage location'), val('storage_gist')['path'], state('storage_gist')),
137 137 (_('Gist storage info'), val('storage_gist')['text'], state('storage_gist')),
138 138
139 139 (_('Archive cache storage location'), val('storage_archive')['path'], state('storage_archive')),
140 140 (_('Archive cache info'), val('storage_archive')['text'], state('storage_archive')),
141 141
142 142 (_('Temp storage location'), val('storage_temp')['path'], state('storage_temp')),
143 143 (_('Temp storage info'), val('storage_temp')['text'], state('storage_temp')),
144 144
145 145 (_('Search info'), val('search')['text'], state('search')),
146 146 (_('Search location'), val('search')['location'], state('search')),
147 147 ('', '', ''), # spacer
148 148
149 149 # VCS specific
150 150 (_('VCS Backends'), val('vcs_backends'), state('vcs_backends')),
151 151 (_('VCS Server'), val('vcs_server')['text'], state('vcs_server')),
152 152 (_('GIT'), val('git'), state('git')),
153 153 (_('HG'), val('hg'), state('hg')),
154 154 (_('SVN'), val('svn'), state('svn')),
155 155
156 156 ]
157 157
158 158 if snapshot:
159 159 if c.allowed_to_snapshot:
160 160 c.data_items.pop(0) # remove server info
161 161 self.request.override_renderer = 'admin/settings/settings_system_snapshot.mako'
162 162 else:
163 163 self.request.session.flash(
164 164 'You are not allowed to do this', queue='warning')
165 165 return {}
166 166
167 167 @LoginRequired()
168 168 @HasPermissionAllDecorator('hg.admin')
169 169 @view_config(
170 170 route_name='admin_settings_system_update', request_method='GET',
171 171 renderer='rhodecode:templates/admin/settings/settings_system_update.mako')
172 def settings_sessions_cleanup(self):
172 def settings_system_info_check_update(self):
173 173 _ = self.request.translate
174 174
175 175 update_url = self.get_update_url()
176 176
177 177 _err = lambda s: '<div style="color:#ff8888; padding:4px 0px">{}</div>'.format(s)
178 178 try:
179 179 data = self.get_update_data(update_url)
180 180 except urllib2.URLError as e:
181 181 log.exception("Exception contacting upgrade server")
182 self.request.override_renderer = 'string'
182 183 return _err('Failed to contact upgrade server: %r' % e)
183 184 except ValueError as e:
184 185 log.exception("Bad data sent from update server")
186 self.request.override_renderer = 'string'
185 187 return _err('Bad data sent from update server')
186 188
187 189 latest = data['versions'][0]
188 190
189 191 c.update_url = update_url
190 192 c.latest_data = latest
191 193 c.latest_ver = latest['version']
192 194 c.cur_ver = rhodecode.__version__
193 195 c.should_upgrade = False
194 196
195 197 if (packaging.version.Version(c.latest_ver) >
196 198 packaging.version.Version(c.cur_ver)):
197 199 c.should_upgrade = True
198 200 c.important_notices = latest['general']
199 201
200 202 return {}
@@ -1,621 +1,665 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2017 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 23
24 24 import rhodecode
25 25 from rhodecode.config.routing import ADMIN_PREFIX
26 26 from rhodecode.lib.utils2 import md5
27 27 from rhodecode.model.db import RhodeCodeUi
28 28 from rhodecode.model.meta import Session
29 29 from rhodecode.model.settings import SettingsModel, IssueTrackerSettingsModel
30 30 from rhodecode.tests import url, assert_session_flash
31 31 from rhodecode.tests.utils import AssertResponse
32 32
33 33
34 34 UPDATE_DATA_QUALNAME = (
35 'rhodecode.controllers.admin.settings.SettingsController.get_update_data')
35 'rhodecode.admin.views.system_info.AdminSystemInfoSettingsView.get_update_data')
36 36
37 37
38 38 @pytest.mark.usefixtures('autologin_user', 'app')
39 class TestAdminSettingsController:
39 class TestAdminSettingsController(object):
40 40
41 41 @pytest.mark.parametrize('urlname', [
42 42 'admin_settings_vcs',
43 43 'admin_settings_mapping',
44 44 'admin_settings_global',
45 45 'admin_settings_visual',
46 46 'admin_settings_email',
47 47 'admin_settings_hooks',
48 48 'admin_settings_search',
49 'admin_settings_system',
50 49 ])
51 50 def test_simple_get(self, urlname, app):
52 51 app.get(url(urlname))
53 52
54 53 def test_create_custom_hook(self, csrf_token):
55 54 response = self.app.post(
56 55 url('admin_settings_hooks'),
57 56 params={
58 57 'new_hook_ui_key': 'test_hooks_1',
59 58 'new_hook_ui_value': 'cd /tmp',
60 59 'csrf_token': csrf_token})
61 60
62 61 response = response.follow()
63 62 response.mustcontain('test_hooks_1')
64 63 response.mustcontain('cd /tmp')
65 64
66 65 def test_create_custom_hook_delete(self, csrf_token):
67 66 response = self.app.post(
68 67 url('admin_settings_hooks'),
69 68 params={
70 69 'new_hook_ui_key': 'test_hooks_2',
71 70 'new_hook_ui_value': 'cd /tmp2',
72 71 'csrf_token': csrf_token})
73 72
74 73 response = response.follow()
75 74 response.mustcontain('test_hooks_2')
76 75 response.mustcontain('cd /tmp2')
77 76
78 77 hook_id = SettingsModel().get_ui_by_key('test_hooks_2').ui_id
79 78
80 79 # delete
81 80 self.app.post(
82 81 url('admin_settings_hooks'),
83 82 params={'hook_id': hook_id, 'csrf_token': csrf_token})
84 83 response = self.app.get(url('admin_settings_hooks'))
85 84 response.mustcontain(no=['test_hooks_2'])
86 85 response.mustcontain(no=['cd /tmp2'])
87 86
88 def test_system_update_new_version(self):
89 update_data = {
90 'versions': [
91 {
92 'version': '100.3.1415926535',
93 'general': 'The latest version we are ever going to ship'
94 },
95 {
96 'version': '0.0.0',
97 'general': 'The first version we ever shipped'
98 }
99 ]
100 }
101 with mock.patch(UPDATE_DATA_QUALNAME, return_value=update_data):
102 response = self.app.get(url('admin_settings_system_update'))
103 response.mustcontain('A <b>new version</b> is available')
104
105 def test_system_update_nothing_new(self):
106 update_data = {
107 'versions': [
108 {
109 'version': '0.0.0',
110 'general': 'The first version we ever shipped'
111 }
112 ]
113 }
114 with mock.patch(UPDATE_DATA_QUALNAME, return_value=update_data):
115 response = self.app.get(url('admin_settings_system_update'))
116 response.mustcontain(
117 'You already have the <b>latest</b> stable version.')
118
119 def test_system_update_bad_response(self):
120 with mock.patch(UPDATE_DATA_QUALNAME, side_effect=ValueError('foo')):
121 response = self.app.get(url('admin_settings_system_update'))
122 response.mustcontain(
123 'Bad data sent from update server')
124
125 87
126 88 @pytest.mark.usefixtures('autologin_user', 'app')
127 class TestAdminSettingsGlobal:
89 class TestAdminSettingsGlobal(object):
128 90
129 91 def test_pre_post_code_code_active(self, csrf_token):
130 92 pre_code = 'rc-pre-code-187652122'
131 93 post_code = 'rc-postcode-98165231'
132 94
133 95 response = self.post_and_verify_settings({
134 96 'rhodecode_pre_code': pre_code,
135 97 'rhodecode_post_code': post_code,
136 98 'csrf_token': csrf_token,
137 99 })
138 100
139 101 response = response.follow()
140 102 response.mustcontain(pre_code, post_code)
141 103
142 104 def test_pre_post_code_code_inactive(self, csrf_token):
143 105 pre_code = 'rc-pre-code-187652122'
144 106 post_code = 'rc-postcode-98165231'
145 107 response = self.post_and_verify_settings({
146 108 'rhodecode_pre_code': '',
147 109 'rhodecode_post_code': '',
148 110 'csrf_token': csrf_token,
149 111 })
150 112
151 113 response = response.follow()
152 114 response.mustcontain(no=[pre_code, post_code])
153 115
154 116 def test_captcha_activate(self, csrf_token):
155 117 self.post_and_verify_settings({
156 118 'rhodecode_captcha_private_key': '1234567890',
157 119 'rhodecode_captcha_public_key': '1234567890',
158 120 'csrf_token': csrf_token,
159 121 })
160 122
161 123 response = self.app.get(ADMIN_PREFIX + '/register')
162 124 response.mustcontain('captcha')
163 125
164 126 def test_captcha_deactivate(self, csrf_token):
165 127 self.post_and_verify_settings({
166 128 'rhodecode_captcha_private_key': '',
167 129 'rhodecode_captcha_public_key': '1234567890',
168 130 'csrf_token': csrf_token,
169 131 })
170 132
171 133 response = self.app.get(ADMIN_PREFIX + '/register')
172 134 response.mustcontain(no=['captcha'])
173 135
174 136 def test_title_change(self, csrf_token):
175 137 old_title = 'RhodeCode'
176 138 new_title = old_title + '_changed'
177 139
178 140 for new_title in ['Changed', 'Ε»Γ³Ε‚wik', old_title]:
179 141 response = self.post_and_verify_settings({
180 142 'rhodecode_title': new_title,
181 143 'csrf_token': csrf_token,
182 144 })
183 145
184 146 response = response.follow()
185 147 response.mustcontain(
186 148 """<div class="branding">- %s</div>""" % new_title)
187 149
188 150 def post_and_verify_settings(self, settings):
189 151 old_title = 'RhodeCode'
190 152 old_realm = 'RhodeCode authentication'
191 153 params = {
192 154 'rhodecode_title': old_title,
193 155 'rhodecode_realm': old_realm,
194 156 'rhodecode_pre_code': '',
195 157 'rhodecode_post_code': '',
196 158 'rhodecode_captcha_private_key': '',
197 159 'rhodecode_captcha_public_key': '',
198 160 'rhodecode_create_personal_repo_group': False,
199 161 'rhodecode_personal_repo_group_pattern': '${username}',
200 162 }
201 163 params.update(settings)
202 164 response = self.app.post(url('admin_settings_global'), params=params)
203 165
204 166 assert_session_flash(response, 'Updated application settings')
205 167 app_settings = SettingsModel().get_all_settings()
206 168 del settings['csrf_token']
207 169 for key, value in settings.iteritems():
208 170 assert app_settings[key] == value.decode('utf-8')
209 171
210 172 return response
211 173
212 174
213 175 @pytest.mark.usefixtures('autologin_user', 'app')
214 class TestAdminSettingsVcs:
176 class TestAdminSettingsVcs(object):
215 177
216 178 def test_contains_svn_default_patterns(self, app):
217 179 response = app.get(url('admin_settings_vcs'))
218 180 expected_patterns = [
219 181 '/trunk',
220 182 '/branches/*',
221 183 '/tags/*',
222 184 ]
223 185 for pattern in expected_patterns:
224 186 response.mustcontain(pattern)
225 187
226 188 def test_add_new_svn_branch_and_tag_pattern(
227 189 self, app, backend_svn, form_defaults, disable_sql_cache,
228 190 csrf_token):
229 191 form_defaults.update({
230 192 'new_svn_branch': '/exp/branches/*',
231 193 'new_svn_tag': '/important_tags/*',
232 194 'csrf_token': csrf_token,
233 195 })
234 196
235 197 response = app.post(
236 198 url('admin_settings_vcs'), params=form_defaults, status=302)
237 199 response = response.follow()
238 200
239 201 # Expect to find the new values on the page
240 202 response.mustcontain('/exp/branches/*')
241 203 response.mustcontain('/important_tags/*')
242 204
243 205 # Expect that those patterns are used to match branches and tags now
244 206 repo = backend_svn['svn-simple-layout'].scm_instance()
245 207 assert 'exp/branches/exp-sphinx-docs' in repo.branches
246 208 assert 'important_tags/v0.5' in repo.tags
247 209
248 210 def test_add_same_svn_value_twice_shows_an_error_message(
249 211 self, app, form_defaults, csrf_token, settings_util):
250 212 settings_util.create_rhodecode_ui('vcs_svn_branch', '/test')
251 213 settings_util.create_rhodecode_ui('vcs_svn_tag', '/test')
252 214
253 215 response = app.post(
254 216 url('admin_settings_vcs'),
255 217 params={
256 218 'paths_root_path': form_defaults['paths_root_path'],
257 219 'new_svn_branch': '/test',
258 220 'new_svn_tag': '/test',
259 221 'csrf_token': csrf_token,
260 222 },
261 223 status=200)
262 224
263 225 response.mustcontain("Pattern already exists")
264 226 response.mustcontain("Some form inputs contain invalid data.")
265 227
266 228 @pytest.mark.parametrize('section', [
267 229 'vcs_svn_branch',
268 230 'vcs_svn_tag',
269 231 ])
270 232 def test_delete_svn_patterns(
271 233 self, section, app, csrf_token, settings_util):
272 234 setting = settings_util.create_rhodecode_ui(
273 235 section, '/test_delete', cleanup=False)
274 236
275 237 app.post(
276 238 url('admin_settings_vcs'),
277 239 params={
278 240 '_method': 'delete',
279 241 'delete_svn_pattern': setting.ui_id,
280 242 'csrf_token': csrf_token},
281 243 headers={'X-REQUESTED-WITH': 'XMLHttpRequest'})
282 244
283 245 @pytest.mark.parametrize('section', [
284 246 'vcs_svn_branch',
285 247 'vcs_svn_tag',
286 248 ])
287 249 def test_delete_svn_patterns_raises_400_when_no_xhr(
288 250 self, section, app, csrf_token, settings_util):
289 251 setting = settings_util.create_rhodecode_ui(section, '/test_delete')
290 252
291 253 app.post(
292 254 url('admin_settings_vcs'),
293 255 params={
294 256 '_method': 'delete',
295 257 'delete_svn_pattern': setting.ui_id,
296 258 'csrf_token': csrf_token},
297 259 status=400)
298 260
299 261 def test_extensions_hgsubversion(self, app, form_defaults, csrf_token):
300 262 form_defaults.update({
301 263 'csrf_token': csrf_token,
302 264 'extensions_hgsubversion': 'True',
303 265 })
304 266 response = app.post(
305 267 url('admin_settings_vcs'),
306 268 params=form_defaults,
307 269 status=302)
308 270
309 271 response = response.follow()
310 272 extensions_input = (
311 273 '<input id="extensions_hgsubversion" '
312 274 'name="extensions_hgsubversion" type="checkbox" '
313 275 'value="True" checked="checked" />')
314 276 response.mustcontain(extensions_input)
315 277
316 278 def test_has_a_section_for_pull_request_settings(self, app):
317 279 response = app.get(url('admin_settings_vcs'))
318 280 response.mustcontain('Pull Request Settings')
319 281
320 282 def test_has_an_input_for_invalidation_of_inline_comments(
321 283 self, app):
322 284 response = app.get(url('admin_settings_vcs'))
323 285 assert_response = AssertResponse(response)
324 286 assert_response.one_element_exists(
325 287 '[name=rhodecode_use_outdated_comments]')
326 288
327 289 @pytest.mark.parametrize('new_value', [True, False])
328 290 def test_allows_to_change_invalidation_of_inline_comments(
329 291 self, app, form_defaults, csrf_token, new_value):
330 292 setting_key = 'use_outdated_comments'
331 293 setting = SettingsModel().create_or_update_setting(
332 294 setting_key, not new_value, 'bool')
333 295 Session().add(setting)
334 296 Session().commit()
335 297
336 298 form_defaults.update({
337 299 'csrf_token': csrf_token,
338 300 'rhodecode_use_outdated_comments': str(new_value),
339 301 })
340 302 response = app.post(
341 303 url('admin_settings_vcs'),
342 304 params=form_defaults,
343 305 status=302)
344 306 response = response.follow()
345 307 setting = SettingsModel().get_setting_by_name(setting_key)
346 308 assert setting.app_settings_value is new_value
347 309
348 310 def test_has_a_section_for_labs_settings_if_enabled(self, app):
349 311 with mock.patch.dict(
350 312 rhodecode.CONFIG, {'labs_settings_active': 'true'}):
351 313 response = self.app.get(url('admin_settings_vcs'))
352 314 response.mustcontain('Labs Settings')
353 315
354 316 def test_has_not_a_section_for_labs_settings_if_disables(self, app):
355 317 with mock.patch.dict(
356 318 rhodecode.CONFIG, {'labs_settings_active': 'false'}):
357 319 response = self.app.get(url('admin_settings_vcs'))
358 320 response.mustcontain(no='Labs Settings')
359 321
360 322 @pytest.mark.parametrize('new_value', [True, False])
361 323 def test_allows_to_change_hg_rebase_merge_strategy(
362 324 self, app, form_defaults, csrf_token, new_value):
363 325 setting_key = 'hg_use_rebase_for_merging'
364 326
365 327 form_defaults.update({
366 328 'csrf_token': csrf_token,
367 329 'rhodecode_' + setting_key: str(new_value),
368 330 })
369 331
370 332 with mock.patch.dict(
371 333 rhodecode.CONFIG, {'labs_settings_active': 'true'}):
372 334 app.post(
373 335 url('admin_settings_vcs'),
374 336 params=form_defaults,
375 337 status=302)
376 338
377 339 setting = SettingsModel().get_setting_by_name(setting_key)
378 340 assert setting.app_settings_value is new_value
379 341
380 342 @pytest.fixture
381 343 def disable_sql_cache(self, request):
382 344 patcher = mock.patch(
383 345 'rhodecode.lib.caching_query.FromCache.process_query')
384 346 request.addfinalizer(patcher.stop)
385 347 patcher.start()
386 348
387 349 @pytest.fixture
388 350 def form_defaults(self):
389 351 from rhodecode.controllers.admin.settings import SettingsController
390 352 controller = SettingsController()
391 353 return controller._form_defaults()
392 354
393 355 # TODO: johbo: What we really want is to checkpoint before a test run and
394 356 # reset the session afterwards.
395 357 @pytest.fixture(scope='class', autouse=True)
396 358 def cleanup_settings(self, request, pylonsapp):
397 359 ui_id = RhodeCodeUi.ui_id
398 360 original_ids = list(
399 361 r.ui_id for r in RhodeCodeUi.query().values(ui_id))
400 362
401 363 @request.addfinalizer
402 364 def cleanup():
403 365 RhodeCodeUi.query().filter(
404 366 ui_id.notin_(original_ids)).delete(False)
405 367
406 368
407 369 @pytest.mark.usefixtures('autologin_user', 'app')
408 370 class TestLabsSettings(object):
409 371 def test_get_settings_page_disabled(self):
410 372 with mock.patch.dict(rhodecode.CONFIG,
411 373 {'labs_settings_active': 'false'}):
412 374 response = self.app.get(url('admin_settings_labs'), status=302)
413 375
414 376 assert response.location.endswith(url('admin_settings'))
415 377
416 378 def test_get_settings_page_enabled(self):
417 379 from rhodecode.controllers.admin import settings
418 380 lab_settings = [
419 381 settings.LabSetting(
420 382 key='rhodecode_bool',
421 383 type='bool',
422 384 group='bool group',
423 385 label='bool label',
424 386 help='bool help'
425 387 ),
426 388 settings.LabSetting(
427 389 key='rhodecode_text',
428 390 type='unicode',
429 391 group='text group',
430 392 label='text label',
431 393 help='text help'
432 394 ),
433 395 ]
434 396 with mock.patch.dict(rhodecode.CONFIG,
435 397 {'labs_settings_active': 'true'}):
436 398 with mock.patch.object(settings, '_LAB_SETTINGS', lab_settings):
437 399 response = self.app.get(url('admin_settings_labs'))
438 400
439 401 assert '<label>bool group:</label>' in response
440 402 assert '<label for="rhodecode_bool">bool label</label>' in response
441 403 assert '<p class="help-block">bool help</p>' in response
442 404 assert 'name="rhodecode_bool" type="checkbox"' in response
443 405
444 406 assert '<label>text group:</label>' in response
445 407 assert '<label for="rhodecode_text">text label</label>' in response
446 408 assert '<p class="help-block">text help</p>' in response
447 409 assert 'name="rhodecode_text" size="60" type="text"' in response
448 410
449 411
450 412 @pytest.mark.usefixtures('app')
451 413 class TestOpenSourceLicenses(object):
452 414
453 415 def _get_url(self):
454 416 return ADMIN_PREFIX + '/settings/open_source'
455 417
456 418 def test_records_are_displayed(self, autologin_user):
457 419 sample_licenses = {
458 420 "python2.7-pytest-2.7.1": {
459 421 "UNKNOWN": None
460 422 },
461 423 "python2.7-Markdown-2.6.2": {
462 424 "BSD-3-Clause": "http://spdx.org/licenses/BSD-3-Clause"
463 425 }
464 426 }
465 427 read_licenses_patch = mock.patch(
466 'rhodecode.admin.views.read_opensource_licenses',
428 'rhodecode.admin.views.open_source_licenses.read_opensource_licenses',
467 429 return_value=sample_licenses)
468 430 with read_licenses_patch:
469 431 response = self.app.get(self._get_url(), status=200)
470 432
471 433 assert_response = AssertResponse(response)
472 434 assert_response.element_contains(
473 435 '.panel-heading', 'Licenses of Third Party Packages')
474 436 for name in sample_licenses:
475 437 response.mustcontain(name)
476 438 for license in sample_licenses[name]:
477 439 assert_response.element_contains('.panel-body', license)
478 440
479 441 def test_records_can_be_read(self, autologin_user):
480 442 response = self.app.get(self._get_url(), status=200)
481 443 assert_response = AssertResponse(response)
482 444 assert_response.element_contains(
483 445 '.panel-heading', 'Licenses of Third Party Packages')
484 446
485 447 def test_forbidden_when_normal_user(self, autologin_regular_user):
486 448 self.app.get(self._get_url(), status=403)
487 449
488 450
451 @pytest.mark.usefixtures('app')
452 class TestUserSessions(object):
453
454 def _get_url(self, name='admin_settings_sessions'):
455 return {
456 'admin_settings_sessions': ADMIN_PREFIX + '/settings/sessions',
457 'admin_settings_sessions_cleanup': ADMIN_PREFIX + '/settings/sessions/cleanup'
458 }[name]
459
460 def test_forbidden_when_normal_user(self, autologin_regular_user):
461 self.app.get(self._get_url(), status=403)
462
463 def test_show_sessions_page(self, autologin_user):
464 response = self.app.get(self._get_url(), status=200)
465 response.mustcontain('file')
466
467 def test_cleanup_old_sessions(self, autologin_user, csrf_token):
468
469 post_data = {
470 'csrf_token': csrf_token,
471 'expire_days': '60'
472 }
473 response = self.app.post(
474 self._get_url('admin_settings_sessions_cleanup'), params=post_data,
475 status=302)
476 assert_session_flash(response, 'Please execute this command')
477
478
479 @pytest.mark.usefixtures('app')
480 class TestAdminSystemInfo(object):
481 def _get_url(self, name='admin_settings_system'):
482 return {
483 'admin_settings_system': ADMIN_PREFIX + '/settings/system',
484 'admin_settings_system_update': ADMIN_PREFIX + '/settings/system/updates',
485 }[name]
486
487 def test_forbidden_when_normal_user(self, autologin_regular_user):
488 self.app.get(self._get_url(), status=403)
489
490 def test_system_info_page(self, autologin_user):
491 response = self.app.get(self._get_url())
492 response.mustcontain('RhodeCode Community Edition, version {}'.format(
493 rhodecode.__version__))
494
495 def test_system_update_new_version(self, autologin_user):
496 update_data = {
497 'versions': [
498 {
499 'version': '100.3.1415926535',
500 'general': 'The latest version we are ever going to ship'
501 },
502 {
503 'version': '0.0.0',
504 'general': 'The first version we ever shipped'
505 }
506 ]
507 }
508 with mock.patch(UPDATE_DATA_QUALNAME, return_value=update_data):
509 response = self.app.get(self._get_url('admin_settings_system_update'))
510 response.mustcontain('A <b>new version</b> is available')
511
512 def test_system_update_nothing_new(self, autologin_user):
513 update_data = {
514 'versions': [
515 {
516 'version': '0.0.0',
517 'general': 'The first version we ever shipped'
518 }
519 ]
520 }
521 with mock.patch(UPDATE_DATA_QUALNAME, return_value=update_data):
522 response = self.app.get(self._get_url('admin_settings_system_update'))
523 response.mustcontain(
524 'You already have the <b>latest</b> stable version.')
525
526 def test_system_update_bad_response(self, autologin_user):
527 with mock.patch(UPDATE_DATA_QUALNAME, side_effect=ValueError('foo')):
528 response = self.app.get(self._get_url('admin_settings_system_update'))
529 response.mustcontain(
530 'Bad data sent from update server')
531
532
489 533 @pytest.mark.usefixtures("app")
490 class TestAdminSettingsIssueTracker:
534 class TestAdminSettingsIssueTracker(object):
491 535 RC_PREFIX = 'rhodecode_'
492 536 SHORT_PATTERN_KEY = 'issuetracker_pat_'
493 537 PATTERN_KEY = RC_PREFIX + SHORT_PATTERN_KEY
494 538
495 539 def test_issuetracker_index(self, autologin_user):
496 540 response = self.app.get(url('admin_settings_issuetracker'))
497 541 assert response.status_code == 200
498 542
499 543 def test_add_empty_issuetracker_pattern(
500 544 self, request, autologin_user, csrf_token):
501 545 post_url = url('admin_settings_issuetracker_save')
502 546 post_data = {
503 547 'csrf_token': csrf_token
504 548 }
505 549 self.app.post(post_url, post_data, status=302)
506 550
507 551 def test_add_issuetracker_pattern(
508 552 self, request, autologin_user, csrf_token):
509 553 pattern = 'issuetracker_pat'
510 554 another_pattern = pattern+'1'
511 555 post_url = url('admin_settings_issuetracker_save')
512 556 post_data = {
513 557 'new_pattern_pattern_0': pattern,
514 558 'new_pattern_url_0': 'url',
515 559 'new_pattern_prefix_0': 'prefix',
516 560 'new_pattern_description_0': 'description',
517 561 'new_pattern_pattern_1': another_pattern,
518 562 'new_pattern_url_1': 'url1',
519 563 'new_pattern_prefix_1': 'prefix1',
520 564 'new_pattern_description_1': 'description1',
521 565 'csrf_token': csrf_token
522 566 }
523 567 self.app.post(post_url, post_data, status=302)
524 568 settings = SettingsModel().get_all_settings()
525 569 self.uid = md5(pattern)
526 570 assert settings[self.PATTERN_KEY+self.uid] == pattern
527 571 self.another_uid = md5(another_pattern)
528 572 assert settings[self.PATTERN_KEY+self.another_uid] == another_pattern
529 573
530 574 @request.addfinalizer
531 575 def cleanup():
532 576 defaults = SettingsModel().get_all_settings()
533 577
534 578 entries = [name for name in defaults if (
535 579 (self.uid in name) or (self.another_uid) in name)]
536 580 start = len(self.RC_PREFIX)
537 581 for del_key in entries:
538 582 # TODO: anderson: get_by_name needs name without prefix
539 583 entry = SettingsModel().get_setting_by_name(del_key[start:])
540 584 Session().delete(entry)
541 585
542 586 Session().commit()
543 587
544 588 def test_edit_issuetracker_pattern(
545 589 self, autologin_user, backend, csrf_token, request):
546 590 old_pattern = 'issuetracker_pat'
547 591 old_uid = md5(old_pattern)
548 592 pattern = 'issuetracker_pat_new'
549 593 self.new_uid = md5(pattern)
550 594
551 595 SettingsModel().create_or_update_setting(
552 596 self.SHORT_PATTERN_KEY+old_uid, old_pattern, 'unicode')
553 597
554 598 post_url = url('admin_settings_issuetracker_save')
555 599 post_data = {
556 600 'new_pattern_pattern_0': pattern,
557 601 'new_pattern_url_0': 'url',
558 602 'new_pattern_prefix_0': 'prefix',
559 603 'new_pattern_description_0': 'description',
560 604 'uid': old_uid,
561 605 'csrf_token': csrf_token
562 606 }
563 607 self.app.post(post_url, post_data, status=302)
564 608 settings = SettingsModel().get_all_settings()
565 609 assert settings[self.PATTERN_KEY+self.new_uid] == pattern
566 610 assert self.PATTERN_KEY+old_uid not in settings
567 611
568 612 @request.addfinalizer
569 613 def cleanup():
570 614 IssueTrackerSettingsModel().delete_entries(self.new_uid)
571 615
572 616 def test_replace_issuetracker_pattern_description(
573 617 self, autologin_user, csrf_token, request, settings_util):
574 618 prefix = 'issuetracker'
575 619 pattern = 'issuetracker_pat'
576 620 self.uid = md5(pattern)
577 621 pattern_key = '_'.join([prefix, 'pat', self.uid])
578 622 rc_pattern_key = '_'.join(['rhodecode', pattern_key])
579 623 desc_key = '_'.join([prefix, 'desc', self.uid])
580 624 rc_desc_key = '_'.join(['rhodecode', desc_key])
581 625 new_description = 'new_description'
582 626
583 627 settings_util.create_rhodecode_setting(
584 628 pattern_key, pattern, 'unicode', cleanup=False)
585 629 settings_util.create_rhodecode_setting(
586 630 desc_key, 'old description', 'unicode', cleanup=False)
587 631
588 632 post_url = url('admin_settings_issuetracker_save')
589 633 post_data = {
590 634 'new_pattern_pattern_0': pattern,
591 635 'new_pattern_url_0': 'url',
592 636 'new_pattern_prefix_0': 'prefix',
593 637 'new_pattern_description_0': new_description,
594 638 'uid': self.uid,
595 639 'csrf_token': csrf_token
596 640 }
597 641 self.app.post(post_url, post_data, status=302)
598 642 settings = SettingsModel().get_all_settings()
599 643 assert settings[rc_pattern_key] == pattern
600 644 assert settings[rc_desc_key] == new_description
601 645
602 646 @request.addfinalizer
603 647 def cleanup():
604 648 IssueTrackerSettingsModel().delete_entries(self.uid)
605 649
606 650 def test_delete_issuetracker_pattern(
607 651 self, autologin_user, backend, csrf_token, settings_util):
608 652 pattern = 'issuetracker_pat'
609 653 uid = md5(pattern)
610 654 settings_util.create_rhodecode_setting(
611 655 self.SHORT_PATTERN_KEY+uid, pattern, 'unicode', cleanup=False)
612 656
613 657 post_url = url('admin_issuetracker_delete')
614 658 post_data = {
615 659 '_method': 'delete',
616 660 'uid': uid,
617 661 'csrf_token': csrf_token
618 662 }
619 663 self.app.post(post_url, post_data, status=302)
620 664 settings = SettingsModel().get_all_settings()
621 665 assert 'rhodecode_%s%s' % (self.SHORT_PATTERN_KEY, uid) not in settings
General Comments 0
You need to be logged in to leave comments. Login now