|
|
|
|
|
# Copyright (C) 2010-2023 RhodeCode GmbH
|
|
|
#
|
|
|
# This program is free software: you can redistribute it and/or modify
|
|
|
# it under the terms of the GNU Affero General Public License, version 3
|
|
|
# (only), as published by the Free Software Foundation.
|
|
|
#
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
# GNU General Public License for more details.
|
|
|
#
|
|
|
# You should have received a copy of the GNU Affero General Public License
|
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
#
|
|
|
# This program is dual-licensed. If you wish to learn more about the
|
|
|
# RhodeCode Enterprise Edition, including its added features, Support services,
|
|
|
# and proprietary license terms, please see https://rhodecode.com/licenses/
|
|
|
|
|
|
import mock
|
|
|
import pytest
|
|
|
|
|
|
import rhodecode
|
|
|
from rhodecode.apps._base import ADMIN_PREFIX
|
|
|
from rhodecode.lib.hash_utils import md5_safe
|
|
|
from rhodecode.model.db import RhodeCodeUi
|
|
|
from rhodecode.model.meta import Session
|
|
|
from rhodecode.model.settings import SettingsModel, IssueTrackerSettingsModel
|
|
|
from rhodecode.tests import assert_session_flash
|
|
|
|
|
|
|
|
|
UPDATE_DATA_QUALNAME = 'rhodecode.model.update.UpdateModel.get_update_data'
|
|
|
|
|
|
|
|
|
def route_path(name, params=None, **kwargs):
|
|
|
import urllib.request
|
|
|
import urllib.parse
|
|
|
import urllib.error
|
|
|
from rhodecode.apps._base import ADMIN_PREFIX
|
|
|
|
|
|
base_url = {
|
|
|
|
|
|
'admin_settings':
|
|
|
ADMIN_PREFIX +'/settings',
|
|
|
'admin_settings_update':
|
|
|
ADMIN_PREFIX + '/settings/update',
|
|
|
'admin_settings_global':
|
|
|
ADMIN_PREFIX + '/settings/global',
|
|
|
'admin_settings_global_update':
|
|
|
ADMIN_PREFIX + '/settings/global/update',
|
|
|
'admin_settings_vcs':
|
|
|
ADMIN_PREFIX + '/settings/vcs',
|
|
|
'admin_settings_vcs_update':
|
|
|
ADMIN_PREFIX + '/settings/vcs/update',
|
|
|
'admin_settings_vcs_svn_pattern_delete':
|
|
|
ADMIN_PREFIX + '/settings/vcs/svn_pattern_delete',
|
|
|
'admin_settings_mapping':
|
|
|
ADMIN_PREFIX + '/settings/mapping',
|
|
|
'admin_settings_mapping_update':
|
|
|
ADMIN_PREFIX + '/settings/mapping/update',
|
|
|
'admin_settings_visual':
|
|
|
ADMIN_PREFIX + '/settings/visual',
|
|
|
'admin_settings_visual_update':
|
|
|
ADMIN_PREFIX + '/settings/visual/update',
|
|
|
'admin_settings_issuetracker':
|
|
|
ADMIN_PREFIX + '/settings/issue-tracker',
|
|
|
'admin_settings_issuetracker_update':
|
|
|
ADMIN_PREFIX + '/settings/issue-tracker/update',
|
|
|
'admin_settings_issuetracker_test':
|
|
|
ADMIN_PREFIX + '/settings/issue-tracker/test',
|
|
|
'admin_settings_issuetracker_delete':
|
|
|
ADMIN_PREFIX + '/settings/issue-tracker/delete',
|
|
|
'admin_settings_email':
|
|
|
ADMIN_PREFIX + '/settings/email',
|
|
|
'admin_settings_email_update':
|
|
|
ADMIN_PREFIX + '/settings/email/update',
|
|
|
'admin_settings_hooks':
|
|
|
ADMIN_PREFIX + '/settings/hooks',
|
|
|
'admin_settings_hooks_update':
|
|
|
ADMIN_PREFIX + '/settings/hooks/update',
|
|
|
'admin_settings_hooks_delete':
|
|
|
ADMIN_PREFIX + '/settings/hooks/delete',
|
|
|
'admin_settings_search':
|
|
|
ADMIN_PREFIX + '/settings/search',
|
|
|
'admin_settings_labs':
|
|
|
ADMIN_PREFIX + '/settings/labs',
|
|
|
'admin_settings_labs_update':
|
|
|
ADMIN_PREFIX + '/settings/labs/update',
|
|
|
|
|
|
'admin_settings_sessions':
|
|
|
ADMIN_PREFIX + '/settings/sessions',
|
|
|
'admin_settings_sessions_cleanup':
|
|
|
ADMIN_PREFIX + '/settings/sessions/cleanup',
|
|
|
'admin_settings_system':
|
|
|
ADMIN_PREFIX + '/settings/system',
|
|
|
'admin_settings_system_update':
|
|
|
ADMIN_PREFIX + '/settings/system/updates',
|
|
|
'admin_settings_open_source':
|
|
|
ADMIN_PREFIX + '/settings/open_source',
|
|
|
|
|
|
|
|
|
}[name].format(**kwargs)
|
|
|
|
|
|
if params:
|
|
|
base_url = '{}?{}'.format(base_url, urllib.parse.urlencode(params))
|
|
|
return base_url
|
|
|
|
|
|
|
|
|
@pytest.mark.usefixtures('autologin_user', 'app')
|
|
|
class TestAdminSettingsController(object):
|
|
|
|
|
|
@pytest.mark.parametrize('urlname', [
|
|
|
'admin_settings_vcs',
|
|
|
'admin_settings_mapping',
|
|
|
'admin_settings_global',
|
|
|
'admin_settings_visual',
|
|
|
'admin_settings_email',
|
|
|
'admin_settings_hooks',
|
|
|
'admin_settings_search',
|
|
|
])
|
|
|
def test_simple_get(self, urlname):
|
|
|
self.app.get(route_path(urlname))
|
|
|
|
|
|
def test_create_custom_hook(self, csrf_token):
|
|
|
response = self.app.post(
|
|
|
route_path('admin_settings_hooks_update'),
|
|
|
params={
|
|
|
'new_hook_ui_key': 'test_hooks_1',
|
|
|
'new_hook_ui_value': 'cd /tmp',
|
|
|
'csrf_token': csrf_token})
|
|
|
|
|
|
response = response.follow()
|
|
|
response.mustcontain('test_hooks_1')
|
|
|
response.mustcontain('cd /tmp')
|
|
|
|
|
|
def test_create_custom_hook_delete(self, csrf_token):
|
|
|
response = self.app.post(
|
|
|
route_path('admin_settings_hooks_update'),
|
|
|
params={
|
|
|
'new_hook_ui_key': 'test_hooks_2',
|
|
|
'new_hook_ui_value': 'cd /tmp2',
|
|
|
'csrf_token': csrf_token})
|
|
|
|
|
|
response = response.follow()
|
|
|
response.mustcontain('test_hooks_2')
|
|
|
response.mustcontain('cd /tmp2')
|
|
|
|
|
|
hook_id = SettingsModel().get_ui_by_key('test_hooks_2').ui_id
|
|
|
|
|
|
# delete
|
|
|
self.app.post(
|
|
|
route_path('admin_settings_hooks_delete'),
|
|
|
params={'hook_id': hook_id, 'csrf_token': csrf_token})
|
|
|
response = self.app.get(route_path('admin_settings_hooks'))
|
|
|
response.mustcontain(no=['test_hooks_2'])
|
|
|
response.mustcontain(no=['cd /tmp2'])
|
|
|
|
|
|
|
|
|
@pytest.mark.usefixtures('autologin_user', 'app')
|
|
|
class TestAdminSettingsGlobal(object):
|
|
|
|
|
|
def test_pre_post_code_code_active(self, csrf_token):
|
|
|
pre_code = 'rc-pre-code-187652122'
|
|
|
post_code = 'rc-postcode-98165231'
|
|
|
|
|
|
response = self.post_and_verify_settings({
|
|
|
'rhodecode_pre_code': pre_code,
|
|
|
'rhodecode_post_code': post_code,
|
|
|
'csrf_token': csrf_token,
|
|
|
})
|
|
|
|
|
|
response = response.follow()
|
|
|
response.mustcontain(pre_code, post_code)
|
|
|
|
|
|
def test_pre_post_code_code_inactive(self, csrf_token):
|
|
|
pre_code = 'rc-pre-code-187652122'
|
|
|
post_code = 'rc-postcode-98165231'
|
|
|
response = self.post_and_verify_settings({
|
|
|
'rhodecode_pre_code': '',
|
|
|
'rhodecode_post_code': '',
|
|
|
'csrf_token': csrf_token,
|
|
|
})
|
|
|
|
|
|
response = response.follow()
|
|
|
response.mustcontain(no=[pre_code, post_code])
|
|
|
|
|
|
def test_captcha_activate(self, csrf_token):
|
|
|
self.post_and_verify_settings({
|
|
|
'rhodecode_captcha_private_key': '1234567890',
|
|
|
'rhodecode_captcha_public_key': '1234567890',
|
|
|
'csrf_token': csrf_token,
|
|
|
})
|
|
|
|
|
|
response = self.app.get(ADMIN_PREFIX + '/register')
|
|
|
response.mustcontain('captcha')
|
|
|
|
|
|
def test_captcha_deactivate(self, csrf_token):
|
|
|
self.post_and_verify_settings({
|
|
|
'rhodecode_captcha_private_key': '',
|
|
|
'rhodecode_captcha_public_key': '1234567890',
|
|
|
'csrf_token': csrf_token,
|
|
|
})
|
|
|
|
|
|
response = self.app.get(ADMIN_PREFIX + '/register')
|
|
|
response.mustcontain(no=['captcha'])
|
|
|
|
|
|
def test_title_change(self, csrf_token):
|
|
|
old_title = 'RhodeCode'
|
|
|
|
|
|
for new_title in ['Changed', 'Żółwik', old_title]:
|
|
|
response = self.post_and_verify_settings({
|
|
|
'rhodecode_title': new_title,
|
|
|
'csrf_token': csrf_token,
|
|
|
})
|
|
|
|
|
|
response = response.follow()
|
|
|
response.mustcontain(new_title)
|
|
|
|
|
|
def post_and_verify_settings(self, settings):
|
|
|
old_title = 'RhodeCode'
|
|
|
old_realm = 'RhodeCode authentication'
|
|
|
params = {
|
|
|
'rhodecode_title': old_title,
|
|
|
'rhodecode_realm': old_realm,
|
|
|
'rhodecode_pre_code': '',
|
|
|
'rhodecode_post_code': '',
|
|
|
'rhodecode_captcha_private_key': '',
|
|
|
'rhodecode_captcha_public_key': '',
|
|
|
'rhodecode_create_personal_repo_group': False,
|
|
|
'rhodecode_personal_repo_group_pattern': '${username}',
|
|
|
}
|
|
|
params.update(settings)
|
|
|
response = self.app.post(
|
|
|
route_path('admin_settings_global_update'), params=params)
|
|
|
|
|
|
assert_session_flash(response, 'Updated application settings')
|
|
|
|
|
|
app_settings = SettingsModel().get_all_settings()
|
|
|
del settings['csrf_token']
|
|
|
for key, value in settings.items():
|
|
|
assert app_settings[key] == value
|
|
|
|
|
|
return response
|
|
|
|
|
|
|
|
|
@pytest.mark.usefixtures('autologin_user', 'app')
|
|
|
class TestAdminSettingsVcs(object):
|
|
|
|
|
|
def test_contains_svn_default_patterns(self):
|
|
|
response = self.app.get(route_path('admin_settings_vcs'))
|
|
|
expected_patterns = [
|
|
|
'/trunk',
|
|
|
'/branches/*',
|
|
|
'/tags/*',
|
|
|
]
|
|
|
for pattern in expected_patterns:
|
|
|
response.mustcontain(pattern)
|
|
|
|
|
|
def test_add_new_svn_branch_and_tag_pattern(
|
|
|
self, backend_svn, form_defaults, disable_sql_cache,
|
|
|
csrf_token):
|
|
|
form_defaults.update({
|
|
|
'new_svn_branch': '/exp/branches/*',
|
|
|
'new_svn_tag': '/important_tags/*',
|
|
|
'csrf_token': csrf_token,
|
|
|
})
|
|
|
|
|
|
response = self.app.post(
|
|
|
route_path('admin_settings_vcs_update'),
|
|
|
params=form_defaults, status=302)
|
|
|
response = response.follow()
|
|
|
|
|
|
# Expect to find the new values on the page
|
|
|
response.mustcontain('/exp/branches/*')
|
|
|
response.mustcontain('/important_tags/*')
|
|
|
|
|
|
# Expect that those patterns are used to match branches and tags now
|
|
|
repo = backend_svn['svn-simple-layout'].scm_instance()
|
|
|
assert 'exp/branches/exp-sphinx-docs' in repo.branches
|
|
|
assert 'important_tags/v0.5' in repo.tags
|
|
|
|
|
|
def test_add_same_svn_value_twice_shows_an_error_message(
|
|
|
self, form_defaults, csrf_token, settings_util):
|
|
|
settings_util.create_rhodecode_ui('vcs_svn_branch', '/test')
|
|
|
settings_util.create_rhodecode_ui('vcs_svn_tag', '/test')
|
|
|
|
|
|
response = self.app.post(
|
|
|
route_path('admin_settings_vcs_update'),
|
|
|
params={
|
|
|
'paths_root_path': form_defaults['paths_root_path'],
|
|
|
'new_svn_branch': '/test',
|
|
|
'new_svn_tag': '/test',
|
|
|
'csrf_token': csrf_token,
|
|
|
},
|
|
|
status=200)
|
|
|
|
|
|
response.mustcontain("Pattern already exists")
|
|
|
response.mustcontain("Some form inputs contain invalid data.")
|
|
|
|
|
|
@pytest.mark.parametrize('section', [
|
|
|
'vcs_svn_branch',
|
|
|
'vcs_svn_tag',
|
|
|
])
|
|
|
def test_delete_svn_patterns(
|
|
|
self, section, csrf_token, settings_util):
|
|
|
setting = settings_util.create_rhodecode_ui(
|
|
|
section, '/test_delete', cleanup=False)
|
|
|
|
|
|
self.app.post(
|
|
|
route_path('admin_settings_vcs_svn_pattern_delete'),
|
|
|
params={
|
|
|
'delete_svn_pattern': setting.ui_id,
|
|
|
'csrf_token': csrf_token},
|
|
|
headers={'X-REQUESTED-WITH': 'XMLHttpRequest'})
|
|
|
|
|
|
@pytest.mark.parametrize('section', [
|
|
|
'vcs_svn_branch',
|
|
|
'vcs_svn_tag',
|
|
|
])
|
|
|
def test_delete_svn_patterns_raises_404_when_no_xhr(
|
|
|
self, section, csrf_token, settings_util):
|
|
|
setting = settings_util.create_rhodecode_ui(section, '/test_delete')
|
|
|
|
|
|
self.app.post(
|
|
|
route_path('admin_settings_vcs_svn_pattern_delete'),
|
|
|
params={
|
|
|
'delete_svn_pattern': setting.ui_id,
|
|
|
'csrf_token': csrf_token},
|
|
|
status=404)
|
|
|
|
|
|
def test_extensions_hgsubversion(self, form_defaults, csrf_token):
|
|
|
form_defaults.update({
|
|
|
'csrf_token': csrf_token,
|
|
|
'extensions_hgsubversion': 'True',
|
|
|
})
|
|
|
response = self.app.post(
|
|
|
route_path('admin_settings_vcs_update'),
|
|
|
params=form_defaults,
|
|
|
status=302)
|
|
|
|
|
|
response = response.follow()
|
|
|
extensions_input = (
|
|
|
'<input id="extensions_hgsubversion" '
|
|
|
'name="extensions_hgsubversion" type="checkbox" '
|
|
|
'value="True" checked="checked" />')
|
|
|
response.mustcontain(extensions_input)
|
|
|
|
|
|
def test_extensions_hgevolve(self, form_defaults, csrf_token):
|
|
|
form_defaults.update({
|
|
|
'csrf_token': csrf_token,
|
|
|
'extensions_evolve': 'True',
|
|
|
})
|
|
|
response = self.app.post(
|
|
|
route_path('admin_settings_vcs_update'),
|
|
|
params=form_defaults,
|
|
|
status=302)
|
|
|
|
|
|
response = response.follow()
|
|
|
extensions_input = (
|
|
|
'<input id="extensions_evolve" '
|
|
|
'name="extensions_evolve" type="checkbox" '
|
|
|
'value="True" checked="checked" />')
|
|
|
response.mustcontain(extensions_input)
|
|
|
|
|
|
def test_has_a_section_for_pull_request_settings(self):
|
|
|
response = self.app.get(route_path('admin_settings_vcs'))
|
|
|
response.mustcontain('Pull Request Settings')
|
|
|
|
|
|
def test_has_an_input_for_invalidation_of_inline_comments(self):
|
|
|
response = self.app.get(route_path('admin_settings_vcs'))
|
|
|
assert_response = response.assert_response()
|
|
|
assert_response.one_element_exists(
|
|
|
'[name=rhodecode_use_outdated_comments]')
|
|
|
|
|
|
@pytest.mark.parametrize('new_value', [True, False])
|
|
|
def test_allows_to_change_invalidation_of_inline_comments(
|
|
|
self, form_defaults, csrf_token, new_value):
|
|
|
setting_key = 'use_outdated_comments'
|
|
|
setting = SettingsModel().create_or_update_setting(
|
|
|
setting_key, not new_value, 'bool')
|
|
|
Session().add(setting)
|
|
|
Session().commit()
|
|
|
|
|
|
form_defaults.update({
|
|
|
'csrf_token': csrf_token,
|
|
|
'rhodecode_use_outdated_comments': str(new_value),
|
|
|
})
|
|
|
response = self.app.post(
|
|
|
route_path('admin_settings_vcs_update'),
|
|
|
params=form_defaults,
|
|
|
status=302)
|
|
|
response = response.follow()
|
|
|
setting = SettingsModel().get_setting_by_name(setting_key)
|
|
|
assert setting.app_settings_value is new_value
|
|
|
|
|
|
@pytest.mark.parametrize('new_value', [True, False])
|
|
|
def test_allows_to_change_hg_rebase_merge_strategy(
|
|
|
self, form_defaults, csrf_token, new_value):
|
|
|
setting_key = 'hg_use_rebase_for_merging'
|
|
|
|
|
|
form_defaults.update({
|
|
|
'csrf_token': csrf_token,
|
|
|
'rhodecode_' + setting_key: str(new_value),
|
|
|
})
|
|
|
|
|
|
with mock.patch.dict(
|
|
|
rhodecode.CONFIG, {'labs_settings_active': 'true'}):
|
|
|
self.app.post(
|
|
|
route_path('admin_settings_vcs_update'),
|
|
|
params=form_defaults,
|
|
|
status=302)
|
|
|
|
|
|
setting = SettingsModel().get_setting_by_name(setting_key)
|
|
|
assert setting.app_settings_value is new_value
|
|
|
|
|
|
@pytest.fixture()
|
|
|
def disable_sql_cache(self, request):
|
|
|
# patch _do_orm_execute so it returns None similar like if we don't use a cached query
|
|
|
patcher = mock.patch(
|
|
|
'rhodecode.lib.caching_query.ORMCache._do_orm_execute', return_value=None)
|
|
|
request.addfinalizer(patcher.stop)
|
|
|
patcher.start()
|
|
|
|
|
|
@pytest.fixture()
|
|
|
def form_defaults(self):
|
|
|
from rhodecode.apps.admin.views.settings import AdminSettingsView
|
|
|
return AdminSettingsView._form_defaults()
|
|
|
|
|
|
# TODO: johbo: What we really want is to checkpoint before a test run and
|
|
|
# reset the session afterwards.
|
|
|
@pytest.fixture(scope='class', autouse=True)
|
|
|
def cleanup_settings(self, request, baseapp):
|
|
|
ui_id = RhodeCodeUi.ui_id
|
|
|
original_ids = [r.ui_id for r in RhodeCodeUi.query().with_entities(ui_id)]
|
|
|
|
|
|
@request.addfinalizer
|
|
|
def cleanup():
|
|
|
RhodeCodeUi.query().filter(
|
|
|
ui_id.notin_(original_ids)).delete(False)
|
|
|
|
|
|
|
|
|
@pytest.mark.usefixtures('autologin_user', 'app')
|
|
|
class TestLabsSettings(object):
|
|
|
def test_get_settings_page_disabled(self):
|
|
|
with mock.patch.dict(
|
|
|
rhodecode.CONFIG, {'labs_settings_active': 'false'}):
|
|
|
|
|
|
response = self.app.get(
|
|
|
route_path('admin_settings_labs'), status=302)
|
|
|
|
|
|
assert response.location.endswith(route_path('admin_settings'))
|
|
|
|
|
|
def test_get_settings_page_enabled(self):
|
|
|
from rhodecode.apps.admin.views import settings
|
|
|
lab_settings = [
|
|
|
settings.LabSetting(
|
|
|
key='rhodecode_bool',
|
|
|
type='bool',
|
|
|
group='bool group',
|
|
|
label='bool label',
|
|
|
help='bool help'
|
|
|
),
|
|
|
settings.LabSetting(
|
|
|
key='rhodecode_text',
|
|
|
type='unicode',
|
|
|
group='text group',
|
|
|
label='text label',
|
|
|
help='text help'
|
|
|
),
|
|
|
]
|
|
|
with mock.patch.dict(rhodecode.CONFIG,
|
|
|
{'labs_settings_active': 'true'}):
|
|
|
with mock.patch.object(settings, '_LAB_SETTINGS', lab_settings):
|
|
|
response = self.app.get(route_path('admin_settings_labs'))
|
|
|
|
|
|
assert '<label>bool group:</label>' in response
|
|
|
assert '<label for="rhodecode_bool">bool label</label>' in response
|
|
|
assert '<p class="help-block">bool help</p>' in response
|
|
|
assert 'name="rhodecode_bool" type="checkbox"' in response
|
|
|
|
|
|
assert '<label>text group:</label>' in response
|
|
|
assert '<label for="rhodecode_text">text label</label>' in response
|
|
|
assert '<p class="help-block">text help</p>' in response
|
|
|
assert 'name="rhodecode_text" size="60" type="text"' in response
|
|
|
|
|
|
|
|
|
@pytest.mark.usefixtures('app')
|
|
|
class TestOpenSourceLicenses(object):
|
|
|
|
|
|
def test_records_are_displayed(self, autologin_user):
|
|
|
sample_licenses = [
|
|
|
{
|
|
|
"license": [
|
|
|
{
|
|
|
"fullName": "BSD 4-clause \"Original\" or \"Old\" License",
|
|
|
"shortName": "bsdOriginal",
|
|
|
"spdxId": "BSD-4-Clause",
|
|
|
"url": "http://spdx.org/licenses/BSD-4-Clause.html"
|
|
|
}
|
|
|
],
|
|
|
"name": "python2.7-coverage-3.7.1"
|
|
|
},
|
|
|
{
|
|
|
"license": [
|
|
|
{
|
|
|
"fullName": "MIT License",
|
|
|
"shortName": "mit",
|
|
|
"spdxId": "MIT",
|
|
|
"url": "http://spdx.org/licenses/MIT.html"
|
|
|
}
|
|
|
],
|
|
|
"name": "python2.7-bootstrapped-pip-9.0.1"
|
|
|
},
|
|
|
]
|
|
|
read_licenses_patch = mock.patch(
|
|
|
'rhodecode.apps.admin.views.open_source_licenses.read_opensource_licenses',
|
|
|
return_value=sample_licenses)
|
|
|
with read_licenses_patch:
|
|
|
response = self.app.get(
|
|
|
route_path('admin_settings_open_source'), status=200)
|
|
|
|
|
|
assert_response = response.assert_response()
|
|
|
assert_response.element_contains(
|
|
|
'.panel-heading', 'Licenses of Third Party Packages')
|
|
|
for license_data in sample_licenses:
|
|
|
response.mustcontain(license_data["license"][0]["spdxId"])
|
|
|
assert_response.element_contains('.panel-body', license_data["name"])
|
|
|
|
|
|
def test_records_can_be_read(self, autologin_user):
|
|
|
response = self.app.get(
|
|
|
route_path('admin_settings_open_source'), status=200)
|
|
|
assert_response = response.assert_response()
|
|
|
assert_response.element_contains(
|
|
|
'.panel-heading', 'Licenses of Third Party Packages')
|
|
|
|
|
|
def test_forbidden_when_normal_user(self, autologin_regular_user):
|
|
|
self.app.get(
|
|
|
route_path('admin_settings_open_source'), status=404)
|
|
|
|
|
|
|
|
|
@pytest.mark.usefixtures('app')
|
|
|
class TestUserSessions(object):
|
|
|
|
|
|
def test_forbidden_when_normal_user(self, autologin_regular_user):
|
|
|
self.app.get(route_path('admin_settings_sessions'), status=404)
|
|
|
|
|
|
def test_show_sessions_page(self, autologin_user):
|
|
|
response = self.app.get(route_path('admin_settings_sessions'), status=200)
|
|
|
response.mustcontain('file')
|
|
|
|
|
|
def test_cleanup_old_sessions(self, autologin_user, csrf_token):
|
|
|
|
|
|
post_data = {
|
|
|
'csrf_token': csrf_token,
|
|
|
'expire_days': '60'
|
|
|
}
|
|
|
response = self.app.post(
|
|
|
route_path('admin_settings_sessions_cleanup'), params=post_data,
|
|
|
status=302)
|
|
|
assert_session_flash(response, 'Cleaned up old sessions')
|
|
|
|
|
|
|
|
|
@pytest.mark.usefixtures('app')
|
|
|
class TestAdminSystemInfo(object):
|
|
|
|
|
|
def test_forbidden_when_normal_user(self, autologin_regular_user):
|
|
|
self.app.get(route_path('admin_settings_system'), status=404)
|
|
|
|
|
|
def test_system_info_page(self, autologin_user):
|
|
|
response = self.app.get(route_path('admin_settings_system'))
|
|
|
response.mustcontain('RhodeCode Community Edition, version {}'.format(
|
|
|
rhodecode.__version__))
|
|
|
|
|
|
def test_system_update_new_version(self, autologin_user):
|
|
|
update_data = {
|
|
|
'versions': [
|
|
|
{
|
|
|
'version': '100.3.1415926535',
|
|
|
'general': 'The latest version we are ever going to ship'
|
|
|
},
|
|
|
{
|
|
|
'version': '0.0.0',
|
|
|
'general': 'The first version we ever shipped'
|
|
|
}
|
|
|
]
|
|
|
}
|
|
|
with mock.patch(UPDATE_DATA_QUALNAME, return_value=update_data):
|
|
|
response = self.app.get(route_path('admin_settings_system_update'))
|
|
|
response.mustcontain('A <b>new version</b> is available')
|
|
|
|
|
|
def test_system_update_nothing_new(self, autologin_user):
|
|
|
update_data = {
|
|
|
'versions': [
|
|
|
{
|
|
|
'version': '0.0.0',
|
|
|
'general': 'The first version we ever shipped'
|
|
|
}
|
|
|
]
|
|
|
}
|
|
|
with mock.patch(UPDATE_DATA_QUALNAME, return_value=update_data):
|
|
|
response = self.app.get(route_path('admin_settings_system_update'))
|
|
|
response.mustcontain(
|
|
|
'This instance is already running the <b>latest</b> stable version')
|
|
|
|
|
|
def test_system_update_bad_response(self, autologin_user):
|
|
|
with mock.patch(UPDATE_DATA_QUALNAME, side_effect=ValueError('foo')):
|
|
|
response = self.app.get(route_path('admin_settings_system_update'))
|
|
|
response.mustcontain(
|
|
|
'Bad data sent from update server')
|
|
|
|
|
|
|
|
|
@pytest.mark.usefixtures("app")
|
|
|
class TestAdminSettingsIssueTracker(object):
|
|
|
RC_PREFIX = 'rhodecode_'
|
|
|
SHORT_PATTERN_KEY = 'issuetracker_pat_'
|
|
|
PATTERN_KEY = RC_PREFIX + SHORT_PATTERN_KEY
|
|
|
DESC_KEY = RC_PREFIX + 'issuetracker_desc_'
|
|
|
|
|
|
def test_issuetracker_index(self, autologin_user):
|
|
|
response = self.app.get(route_path('admin_settings_issuetracker'))
|
|
|
assert response.status_code == 200
|
|
|
|
|
|
def test_add_empty_issuetracker_pattern(
|
|
|
self, request, autologin_user, csrf_token):
|
|
|
post_url = route_path('admin_settings_issuetracker_update')
|
|
|
post_data = {
|
|
|
'csrf_token': csrf_token
|
|
|
}
|
|
|
self.app.post(post_url, post_data, status=302)
|
|
|
|
|
|
def test_add_issuetracker_pattern(
|
|
|
self, request, autologin_user, csrf_token):
|
|
|
pattern = 'issuetracker_pat'
|
|
|
another_pattern = pattern+'1'
|
|
|
post_url = route_path('admin_settings_issuetracker_update')
|
|
|
post_data = {
|
|
|
'new_pattern_pattern_0': pattern,
|
|
|
'new_pattern_url_0': 'http://url',
|
|
|
'new_pattern_prefix_0': 'prefix',
|
|
|
'new_pattern_description_0': 'description',
|
|
|
'new_pattern_pattern_1': another_pattern,
|
|
|
'new_pattern_url_1': 'https://url1',
|
|
|
'new_pattern_prefix_1': 'prefix1',
|
|
|
'new_pattern_description_1': 'description1',
|
|
|
'csrf_token': csrf_token
|
|
|
}
|
|
|
self.app.post(post_url, post_data, status=302)
|
|
|
settings = SettingsModel().get_all_settings()
|
|
|
self.uid = md5_safe(pattern)
|
|
|
assert settings[self.PATTERN_KEY+self.uid] == pattern
|
|
|
self.another_uid = md5_safe(another_pattern)
|
|
|
assert settings[self.PATTERN_KEY+self.another_uid] == another_pattern
|
|
|
|
|
|
@request.addfinalizer
|
|
|
def cleanup():
|
|
|
defaults = SettingsModel().get_all_settings()
|
|
|
|
|
|
entries = [name for name in defaults if (
|
|
|
(self.uid in name) or (self.another_uid in name))]
|
|
|
start = len(self.RC_PREFIX)
|
|
|
for del_key in entries:
|
|
|
# TODO: anderson: get_by_name needs name without prefix
|
|
|
entry = SettingsModel().get_setting_by_name(del_key[start:])
|
|
|
Session().delete(entry)
|
|
|
|
|
|
Session().commit()
|
|
|
|
|
|
def test_edit_issuetracker_pattern(
|
|
|
self, autologin_user, backend, csrf_token, request):
|
|
|
|
|
|
old_pattern = 'issuetracker_pat1'
|
|
|
old_uid = md5_safe(old_pattern)
|
|
|
|
|
|
post_url = route_path('admin_settings_issuetracker_update')
|
|
|
post_data = {
|
|
|
'new_pattern_pattern_0': old_pattern,
|
|
|
'new_pattern_url_0': 'http://url',
|
|
|
'new_pattern_prefix_0': 'prefix',
|
|
|
'new_pattern_description_0': 'description',
|
|
|
|
|
|
'csrf_token': csrf_token
|
|
|
}
|
|
|
self.app.post(post_url, post_data, status=302)
|
|
|
|
|
|
new_pattern = 'issuetracker_pat1_edited'
|
|
|
self.new_uid = md5_safe(new_pattern)
|
|
|
|
|
|
post_url = route_path('admin_settings_issuetracker_update')
|
|
|
post_data = {
|
|
|
'new_pattern_pattern_{}'.format(old_uid): new_pattern,
|
|
|
'new_pattern_url_{}'.format(old_uid): 'https://url_edited',
|
|
|
'new_pattern_prefix_{}'.format(old_uid): 'prefix_edited',
|
|
|
'new_pattern_description_{}'.format(old_uid): 'description_edited',
|
|
|
'uid': old_uid,
|
|
|
'csrf_token': csrf_token
|
|
|
}
|
|
|
self.app.post(post_url, post_data, status=302)
|
|
|
|
|
|
settings = SettingsModel().get_all_settings()
|
|
|
assert settings[self.PATTERN_KEY+self.new_uid] == new_pattern
|
|
|
assert settings[self.DESC_KEY + self.new_uid] == 'description_edited'
|
|
|
assert self.PATTERN_KEY+old_uid not in settings
|
|
|
|
|
|
@request.addfinalizer
|
|
|
def cleanup():
|
|
|
IssueTrackerSettingsModel().delete_entries(old_uid)
|
|
|
IssueTrackerSettingsModel().delete_entries(self.new_uid)
|
|
|
|
|
|
def test_replace_issuetracker_pattern_description(
|
|
|
self, autologin_user, csrf_token, request, settings_util):
|
|
|
prefix = 'issuetracker'
|
|
|
pattern = 'issuetracker_pat'
|
|
|
self.uid = md5_safe(pattern)
|
|
|
pattern_key = '_'.join([prefix, 'pat', self.uid])
|
|
|
rc_pattern_key = '_'.join(['rhodecode', pattern_key])
|
|
|
desc_key = '_'.join([prefix, 'desc', self.uid])
|
|
|
rc_desc_key = '_'.join(['rhodecode', desc_key])
|
|
|
new_description = 'new_description'
|
|
|
|
|
|
settings_util.create_rhodecode_setting(
|
|
|
pattern_key, pattern, 'unicode', cleanup=False)
|
|
|
settings_util.create_rhodecode_setting(
|
|
|
desc_key, 'old description', 'unicode', cleanup=False)
|
|
|
|
|
|
post_url = route_path('admin_settings_issuetracker_update')
|
|
|
post_data = {
|
|
|
'new_pattern_pattern_0': pattern,
|
|
|
'new_pattern_url_0': 'https://url',
|
|
|
'new_pattern_prefix_0': 'prefix',
|
|
|
'new_pattern_description_0': new_description,
|
|
|
'uid': self.uid,
|
|
|
'csrf_token': csrf_token
|
|
|
}
|
|
|
self.app.post(post_url, post_data, status=302)
|
|
|
settings = SettingsModel().get_all_settings()
|
|
|
assert settings[rc_pattern_key] == pattern
|
|
|
assert settings[rc_desc_key] == new_description
|
|
|
|
|
|
@request.addfinalizer
|
|
|
def cleanup():
|
|
|
IssueTrackerSettingsModel().delete_entries(self.uid)
|
|
|
|
|
|
def test_delete_issuetracker_pattern(
|
|
|
self, autologin_user, backend, csrf_token, settings_util, xhr_header):
|
|
|
|
|
|
old_pattern = 'issuetracker_pat_deleted'
|
|
|
old_uid = md5_safe(old_pattern)
|
|
|
|
|
|
post_url = route_path('admin_settings_issuetracker_update')
|
|
|
post_data = {
|
|
|
'new_pattern_pattern_0': old_pattern,
|
|
|
'new_pattern_url_0': 'http://url',
|
|
|
'new_pattern_prefix_0': 'prefix',
|
|
|
'new_pattern_description_0': 'description',
|
|
|
|
|
|
'csrf_token': csrf_token
|
|
|
}
|
|
|
self.app.post(post_url, post_data, status=302)
|
|
|
|
|
|
post_url = route_path('admin_settings_issuetracker_delete')
|
|
|
post_data = {
|
|
|
'uid': old_uid,
|
|
|
'csrf_token': csrf_token
|
|
|
}
|
|
|
self.app.post(post_url, post_data, extra_environ=xhr_header, status=200)
|
|
|
settings = SettingsModel().get_all_settings()
|
|
|
assert self.PATTERN_KEY+old_uid not in settings
|
|
|
assert self.DESC_KEY + old_uid not in settings
|
|
|
|