# Copyright (C) 2010-2024 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 . # # 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 from rhodecode.lib.utils2 import str2bool from rhodecode.model.meta import Session from rhodecode.model.settings import VcsSettingsModel, UiSetting HOOKS_FORM_DATA = { "hooks_changegroup_repo_size": True, "hooks_changegroup_push_logger": True, "hooks_outgoing_pull_logger": True, } SVN_FORM_DATA = {"new_svn_branch": "test-branch", "new_svn_tag": "test-tag"} GENERAL_FORM_DATA = { "rhodecode_pr_merge_enabled": True, "rhodecode_auto_merge_enabled": True, "rhodecode_use_outdated_comments": True, "rhodecode_pr_security_scan_enabled": True, "rhodecode_ai_default_code_review": True, "rhodecode_hg_use_rebase_for_merging": True, "rhodecode_hg_close_branch_before_merging": True, "rhodecode_hg_merge_strategy_selector": True, "rhodecode_git_use_rebase_for_merging": True, "rhodecode_git_close_branch_before_merging": True, "rhodecode_git_merge_strategy_selector": True, "rhodecode_diff_cache": True, "rhodecode_pr_target_branch_prepopulate": True, } class TestInheritGlobalSettingsProperty(object): def test_get_raises_exception_when_repository_not_specified(self): model = VcsSettingsModel() with pytest.raises(Exception) as exc_info: model.inherit_global_settings assert str(exc_info.value) == "Repository is not specified" def test_true_is_returned_when_value_is_not_found(self, repo_stub): model = VcsSettingsModel(repo=repo_stub.repo_name) assert model.inherit_global_settings is True def test_value_is_returned(self, repo_stub, settings_util): model = VcsSettingsModel(repo=repo_stub.repo_name) settings_util.create_repo_rhodecode_setting(repo_stub, VcsSettingsModel.INHERIT_SETTINGS, False, "bool") assert model.inherit_global_settings is False def test_value_is_set(self, repo_stub): model = VcsSettingsModel(repo=repo_stub.repo_name) model.inherit_global_settings = False setting = model.repo_settings.get_setting_by_name(VcsSettingsModel.INHERIT_SETTINGS) try: assert setting.app_settings_type == "bool" assert setting.app_settings_value is False finally: Session().delete(setting) Session().commit() def test_set_raises_exception_when_repository_not_specified(self): model = VcsSettingsModel() with pytest.raises(Exception) as exc_info: model.inherit_global_settings = False assert str(exc_info.value) == "Repository is not specified" class TestVcsSettingsModel(object): def test_global_svn_branch_patterns(self): model = VcsSettingsModel() expected_result = {"test": "test"} with mock.patch.object(model, "global_settings") as settings_mock: get_settings = settings_mock.get_ui_by_section get_settings.return_value = expected_result settings_mock.return_value = expected_result result = model.get_global_svn_branch_patterns() get_settings.assert_called_once_with(model.SVN_BRANCH_SECTION) assert expected_result == result def test_repo_svn_branch_patterns(self): model = VcsSettingsModel() expected_result = {"test": "test"} with mock.patch.object(model, "repo_settings") as settings_mock: get_settings = settings_mock.get_ui_by_section get_settings.return_value = expected_result settings_mock.return_value = expected_result result = model.get_repo_svn_branch_patterns() get_settings.assert_called_once_with(model.SVN_BRANCH_SECTION) assert expected_result == result def test_repo_svn_branch_patterns_raises_exception_when_repo_is_not_set(self): model = VcsSettingsModel() with pytest.raises(Exception) as exc_info: model.get_repo_svn_branch_patterns() assert str(exc_info.value) == "Repository is not specified" def test_global_svn_tag_patterns(self): model = VcsSettingsModel() expected_result = {"test": "test"} with mock.patch.object(model, "global_settings") as settings_mock: get_settings = settings_mock.get_ui_by_section get_settings.return_value = expected_result settings_mock.return_value = expected_result result = model.get_global_svn_tag_patterns() get_settings.assert_called_once_with(model.SVN_TAG_SECTION) assert expected_result == result def test_repo_svn_tag_patterns(self): model = VcsSettingsModel() expected_result = {"test": "test"} with mock.patch.object(model, "repo_settings") as settings_mock: get_settings = settings_mock.get_ui_by_section get_settings.return_value = expected_result settings_mock.return_value = expected_result result = model.get_repo_svn_tag_patterns() get_settings.assert_called_once_with(model.SVN_TAG_SECTION) assert expected_result == result def test_repo_svn_tag_patterns_raises_exception_when_repo_is_not_set(self): model = VcsSettingsModel() with pytest.raises(Exception) as exc_info: model.get_repo_svn_tag_patterns() assert str(exc_info.value) == "Repository is not specified" def test_get_global_settings(self): expected_result = {"test": "test"} model = VcsSettingsModel() with mock.patch.object(model, "_collect_all_settings") as collect_mock: collect_mock.return_value = expected_result result = model.get_global_settings() collect_mock.assert_called_once_with(global_=True) assert result == expected_result def test_get_repo_settings(self, repo_stub): model = VcsSettingsModel(repo=repo_stub.repo_name) expected_result = {"test": "test"} with mock.patch.object(model, "_collect_all_settings") as collect_mock: collect_mock.return_value = expected_result result = model.get_repo_settings() collect_mock.assert_called_once_with(global_=False) assert result == expected_result @pytest.mark.parametrize("settings, global_", [("global_settings", True), ("repo_settings", False)]) def test_collect_all_settings(self, settings, global_): model = VcsSettingsModel() result_mock = self._mock_result() settings_patch = mock.patch.object(model, settings) with settings_patch as settings_mock: settings_mock.get_ui_by_section_and_key.return_value = result_mock settings_mock.get_setting_by_name.return_value = result_mock result = model._collect_all_settings(global_=global_) ui_settings = model.HG_SETTINGS + model.GIT_SETTINGS + model.HOOKS_SETTINGS self._assert_get_settings_calls(settings_mock, ui_settings, model.GENERAL_SETTINGS) self._assert_collect_all_settings_result(ui_settings, model.GENERAL_SETTINGS, result) @pytest.mark.parametrize("settings, global_", [("global_settings", True), ("repo_settings", False)]) def test_collect_all_settings_without_empty_value(self, settings, global_): model = VcsSettingsModel() settings_patch = mock.patch.object(model, settings) with settings_patch as settings_mock: settings_mock.get_ui_by_section_and_key.return_value = None settings_mock.get_setting_by_name.return_value = None result = model._collect_all_settings(global_=global_) assert result == {} def _mock_result(self): result_mock = mock.Mock() result_mock.ui_value = "ui_value" result_mock.ui_active = True result_mock.app_settings_value = "setting_value" return result_mock def _assert_get_settings_calls(self, settings_mock, ui_settings, general_settings): assert settings_mock.get_ui_by_section_and_key.call_count == len(ui_settings) assert settings_mock.get_setting_by_name.call_count == len(general_settings) for section, key in ui_settings: expected_call = mock.call(section, key) assert expected_call in settings_mock.get_ui_by_section_and_key.call_args_list for name in general_settings: expected_call = mock.call(name) assert expected_call in settings_mock.get_setting_by_name.call_args_list def _assert_collect_all_settings_result(self, ui_settings, general_settings, result): expected_result = {} for section, key in ui_settings: key = "{}_{}".format(section, key.replace(".", "_")) if section in ("extensions", "hooks"): value = True elif key in ["vcs_git_lfs_enabled"]: value = True else: value = "ui_value" expected_result[key] = value for name in general_settings: key = "rhodecode_" + name expected_result[key] = "setting_value" assert expected_result == result class TestCreateOrUpdateRepoHookSettings(object): def test_create_when_no_repo_object_found(self, repo_stub): model = VcsSettingsModel(repo=repo_stub.repo_name) self._create_settings(model, HOOKS_FORM_DATA) cleanup = [] try: for section, key in model.HOOKS_SETTINGS: ui = model.repo_settings.get_ui_by_section_and_key(section, key) assert ui.ui_active is True cleanup.append(ui) finally: for ui in cleanup: Session().delete(ui) Session().commit() def test_create_raises_exception_when_data_incomplete(self, repo_stub): model = VcsSettingsModel(repo=repo_stub.repo_name) deleted_key = "hooks_changegroup_repo_size" data = HOOKS_FORM_DATA.copy() data.pop(deleted_key) with pytest.raises(ValueError) as exc_info: model.create_or_update_repo_hook_settings(data) Session().commit() msg = "The given data does not contain {} key".format(deleted_key) assert str(exc_info.value) == msg def test_update_when_repo_object_found(self, repo_stub, settings_util): model = VcsSettingsModel(repo=repo_stub.repo_name) for section, key in model.HOOKS_SETTINGS: settings_util.create_repo_rhodecode_ui(repo_stub, section, None, key=key, active=False) model.create_or_update_repo_hook_settings(HOOKS_FORM_DATA) Session().commit() for section, key in model.HOOKS_SETTINGS: ui = model.repo_settings.get_ui_by_section_and_key(section, key) assert ui.ui_active is True def _create_settings(self, model, data): global_patch = mock.patch.object(model, "global_settings") global_setting = mock.Mock() global_setting.ui_value = "Test value" with global_patch as global_mock: global_mock.get_ui_by_section_and_key.return_value = global_setting model.create_or_update_repo_hook_settings(HOOKS_FORM_DATA) Session().commit() class TestUpdateGlobalHookSettings(object): def test_update_raises_exception_when_data_incomplete(self): model = VcsSettingsModel() deleted_key = "hooks_changegroup_repo_size" data = HOOKS_FORM_DATA.copy() data.pop(deleted_key) with pytest.raises(ValueError) as exc_info: model.update_global_hook_settings(data) Session().commit() msg = "The given data does not contain {} key".format(deleted_key) assert str(exc_info.value) == msg def test_update_global_hook_settings(self, settings_util): model = VcsSettingsModel() setting_mock = mock.MagicMock() setting_mock.ui_active = False get_settings_patcher = mock.patch.object( model.global_settings, "get_ui_by_section_and_key", return_value=setting_mock ) session_patcher = mock.patch("rhodecode.model.settings.Session") with get_settings_patcher as get_settings_mock, session_patcher: model.update_global_hook_settings(HOOKS_FORM_DATA) Session().commit() assert setting_mock.ui_active is True assert get_settings_mock.call_count == 3 class TestCreateOrUpdateRepoGeneralSettings(object): def test_calls_create_or_update_general_settings(self, repo_stub): model = VcsSettingsModel(repo=repo_stub.repo_name) create_patch = mock.patch.object(model, "_create_or_update_general_settings") with create_patch as create_mock: model.create_or_update_repo_pr_settings(GENERAL_FORM_DATA) Session().commit() create_mock.assert_called_once_with(model.repo_settings, GENERAL_FORM_DATA) def test_raises_exception_when_repository_is_not_specified(self): model = VcsSettingsModel() with pytest.raises(Exception) as exc_info: model.create_or_update_repo_pr_settings(GENERAL_FORM_DATA) assert str(exc_info.value) == "Repository is not specified" class TestCreateOrUpdatGlobalGeneralSettings(object): def test_calls_create_or_update_general_settings(self): model = VcsSettingsModel() create_patch = mock.patch.object(model, "_create_or_update_general_settings") with create_patch as create_mock: model.create_or_update_global_pr_settings(GENERAL_FORM_DATA) create_mock.assert_called_once_with(model.global_settings, GENERAL_FORM_DATA) class TestCreateOrUpdateGeneralSettings(object): def test_create_when_no_repo_settings_found(self, repo_stub): model = VcsSettingsModel(repo=repo_stub.repo_name) model._create_or_update_general_settings(model.repo_settings, GENERAL_FORM_DATA) cleanup = [] try: for name in model.GENERAL_SETTINGS: setting = model.repo_settings.get_setting_by_name(name) assert setting.app_settings_value is True cleanup.append(setting) finally: for setting in cleanup: Session().delete(setting) Session().commit() def test_create_raises_exception_when_data_incomplete(self, repo_stub): model = VcsSettingsModel(repo=repo_stub.repo_name) deleted_key = "rhodecode_pr_merge_enabled" data = GENERAL_FORM_DATA.copy() data.pop(deleted_key) with pytest.raises(ValueError) as exc_info: model._create_or_update_general_settings(model.repo_settings, data) Session().commit() msg = "The given data does not contain {} key".format(deleted_key) assert str(exc_info.value) == msg def test_update_when_repo_setting_found(self, repo_stub, settings_util): model = VcsSettingsModel(repo=repo_stub.repo_name) for name in model.GENERAL_SETTINGS: settings_util.create_repo_rhodecode_setting(repo_stub, name, False, "bool") model._create_or_update_general_settings(model.repo_settings, GENERAL_FORM_DATA) Session().commit() for name in model.GENERAL_SETTINGS: setting = model.repo_settings.get_setting_by_name(name) assert setting.app_settings_value is True class TestCreateRepoSvnSettings(object): def test_calls_create_svn_settings(self, repo_stub): model = VcsSettingsModel(repo=repo_stub.repo_name) with mock.patch.object(model, "_create_svn_settings") as create_mock: model.create_repo_svn_settings(SVN_FORM_DATA) Session().commit() create_mock.assert_called_once_with(model.repo_settings, SVN_FORM_DATA) def test_raises_exception_when_repository_is_not_specified(self): model = VcsSettingsModel() with pytest.raises(Exception) as exc_info: model.create_repo_svn_settings(SVN_FORM_DATA) Session().commit() assert str(exc_info.value) == "Repository is not specified" class TestCreateSvnSettings(object): def test_create(self, repo_stub): model = VcsSettingsModel(repo=repo_stub.repo_name) model._create_svn_settings(model.repo_settings, SVN_FORM_DATA) Session().commit() branch_ui = model.repo_settings.get_ui_by_section(model.SVN_BRANCH_SECTION) tag_ui = model.repo_settings.get_ui_by_section(model.SVN_TAG_SECTION) try: assert len(branch_ui) == 1 assert len(tag_ui) == 1 finally: Session().delete(branch_ui[0]) Session().delete(tag_ui[0]) Session().commit() def test_create_tag(self, repo_stub): model = VcsSettingsModel(repo=repo_stub.repo_name) data = SVN_FORM_DATA.copy() data.pop("new_svn_branch") model._create_svn_settings(model.repo_settings, data) Session().commit() branch_ui = model.repo_settings.get_ui_by_section(model.SVN_BRANCH_SECTION) tag_ui = model.repo_settings.get_ui_by_section(model.SVN_TAG_SECTION) try: assert len(branch_ui) == 0 assert len(tag_ui) == 1 finally: Session().delete(tag_ui[0]) Session().commit() def test_create_nothing_when_no_svn_settings_specified(self, repo_stub): model = VcsSettingsModel(repo=repo_stub.repo_name) model._create_svn_settings(model.repo_settings, {}) Session().commit() branch_ui = model.repo_settings.get_ui_by_section(model.SVN_BRANCH_SECTION) tag_ui = model.repo_settings.get_ui_by_section(model.SVN_TAG_SECTION) assert len(branch_ui) == 0 assert len(tag_ui) == 0 def test_create_nothing_when_empty_settings_specified(self, repo_stub): model = VcsSettingsModel(repo=repo_stub.repo_name) data = {"new_svn_branch": "", "new_svn_tag": ""} model._create_svn_settings(model.repo_settings, data) Session().commit() branch_ui = model.repo_settings.get_ui_by_section(model.SVN_BRANCH_SECTION) tag_ui = model.repo_settings.get_ui_by_section(model.SVN_TAG_SECTION) assert len(branch_ui) == 0 assert len(tag_ui) == 0 class TestCreateOrUpdateUi(object): def test_create(self, repo_stub): model = VcsSettingsModel(repo=repo_stub.repo_name) model._create_or_update_ui(model.repo_settings, "test-section", "test-key", active=False, value="False") Session().commit() created_ui = model.repo_settings.get_ui_by_section_and_key("test-section", "test-key") try: assert created_ui.ui_active is False assert str2bool(created_ui.ui_value) is False finally: Session().delete(created_ui) Session().commit() def test_update(self, repo_stub, settings_util): model = VcsSettingsModel(repo=repo_stub.repo_name) # care about only 3 first settings largefiles, phases, evolve = model.HG_SETTINGS[:3] section = "test-section" key = "test-key" settings_util.create_repo_rhodecode_ui(repo_stub, section, "True", key=key, active=True) model._create_or_update_ui(model.repo_settings, section, key, active=False, value="False") Session().commit() created_ui = model.repo_settings.get_ui_by_section_and_key(section, key) assert created_ui.ui_active is False assert str2bool(created_ui.ui_value) is False class TestCreateOrUpdateRepoHgSettings(object): FORM_DATA = {"extensions_largefiles": False, "extensions_evolve": False, "phases_publish": False} def test_creates_repo_hg_settings_when_data_is_correct(self, repo_stub): model = VcsSettingsModel(repo=repo_stub.repo_name) with mock.patch.object(model, "_create_or_update_ui") as create_mock: model.create_or_update_repo_hg_settings(self.FORM_DATA) expected_calls = [ mock.call(model.repo_settings, "extensions", "largefiles", active=False, value=""), mock.call(model.repo_settings, "extensions", "evolve", active=False, value=""), mock.call(model.repo_settings, "experimental", "evolution", active=False, value=""), mock.call(model.repo_settings, "experimental", "evolution.exchange", active=False, value="no"), mock.call(model.repo_settings, "extensions", "topic", active=False, value=""), mock.call(model.repo_settings, "phases", "publish", value="False"), ] assert expected_calls == create_mock.call_args_list @pytest.mark.parametrize("field_to_remove", FORM_DATA.keys()) def test_key_is_not_found(self, repo_stub, field_to_remove): model = VcsSettingsModel(repo=repo_stub.repo_name) data = self.FORM_DATA.copy() data.pop(field_to_remove) with pytest.raises(ValueError) as exc_info: model.create_or_update_repo_hg_settings(data) Session().commit() expected_message = "The given data does not contain {} key".format(field_to_remove) assert str(exc_info.value) == expected_message def test_create_raises_exception_when_repository_not_specified(self): model = VcsSettingsModel() with pytest.raises(Exception) as exc_info: model.create_or_update_repo_hg_settings(self.FORM_DATA) Session().commit() assert str(exc_info.value) == "Repository is not specified" class TestCreateOrUpdateGlobalHgSettings(object): FORM_DATA = {"extensions_largefiles": False, "phases_publish": False, "extensions_evolve": False} def test_creates_repo_hg_settings_when_data_is_correct(self): model = VcsSettingsModel() with mock.patch.object(model, "_create_or_update_ui") as create_mock: model.create_or_update_global_hg_settings(self.FORM_DATA) Session().commit() expected_calls = [ mock.call(model.global_settings, "extensions", "largefiles", active=False, value=""), mock.call(model.global_settings, "phases", "publish", value="False"), mock.call(model.global_settings, "extensions", "evolve", active=False, value=""), mock.call(model.global_settings, "experimental", "evolution", active=False, value=""), mock.call(model.global_settings, "experimental", "evolution.exchange", active=False, value="no"), mock.call(model.global_settings, "extensions", "topic", active=False, value=""), ] assert expected_calls == create_mock.call_args_list @pytest.mark.parametrize("field_to_remove", FORM_DATA.keys()) def test_key_is_not_found(self, repo_stub, field_to_remove): model = VcsSettingsModel(repo=repo_stub.repo_name) data = self.FORM_DATA.copy() data.pop(field_to_remove) with pytest.raises(Exception) as exc_info: model.create_or_update_global_hg_settings(data) Session().commit() expected_message = "The given data does not contain {} key".format(field_to_remove) assert str(exc_info.value) == expected_message class TestCreateOrUpdateGlobalGitSettings(object): FORM_DATA = { "vcs_git_lfs_enabled": False, "vcs_git_default_branch": "main", } def test_creates_repo_hg_settings_when_data_is_correct(self): model = VcsSettingsModel() with mock.patch.object(model, "_create_or_update_ui") as create_mock: model.create_or_update_global_git_settings(self.FORM_DATA) Session().commit() expected_calls = [ mock.call(model.global_settings, "vcs_git_lfs", "enabled", active=False, value=False), mock.call(model.global_settings, "vcs_git", "default_branch", active=True, value="main"), ] assert expected_calls == create_mock.call_args_list def test_default_branch_falls_back_to_master_when_empty(self): model = VcsSettingsModel() form_data = { "vcs_git_lfs_enabled": False, "vcs_git_default_branch": "", } with mock.patch.object(model, "_create_or_update_ui") as create_mock: model.create_or_update_global_git_settings(form_data) Session().commit() expected_calls = [ mock.call(model.global_settings, "vcs_git_lfs", "enabled", active=False, value=False), mock.call(model.global_settings, "vcs_git", "default_branch", active=True, value="master"), ] assert expected_calls == create_mock.call_args_list def test_valid_branch_names_are_accepted(self): """Test that valid Git branch names pass validation""" import formencode from rhodecode.model.forms import v valid_names = ["main", "develop", "feature/my-feature", "release-1.0", "hotfix_urgent"] validator = v.Regex( r"^(?!\.)(?!.*\.\.)(?!.*[~^:?*\[\\\s])(?!.*//)(?!.*/$)(?!.*\.lock$).+$", not_empty=False, if_missing="master", ) for branch_name in valid_names: result = validator.to_python(branch_name) assert result == branch_name def test_invalid_branch_names_are_rejected(self): """Test that invalid Git branch names fail validation""" import formencode from rhodecode.model.forms import v invalid_names = [ ".hidden", # starts with dot "feature..bug", # contains double dots "feature~1", # contains tilde "branch:name", # contains colon "what?", # contains question mark "wild*card", # contains asterisk "feature[test]", # contains brackets "trailing/", # ends with slash "double//slash", # contains double slash "feature.lock", # ends with .lock ] validator = v.Regex( r"^(?!\.)(?!.*\.\.)(?!.*[~^:?*\[\\\s])(?!.*//)(?!.*/$)(?!.*\.lock$).+$", not_empty=False, if_missing="master", ) for branch_name in invalid_names: try: validator.to_python(branch_name) assert False, f"Expected validation error for branch name: {branch_name}" except formencode.Invalid: pass # Expected class TestDeleteRepoSvnPattern(object): def test_success_when_repo_is_set(self, backend_svn, settings_util): repo = backend_svn.create_repo() repo_name = repo.repo_name model = VcsSettingsModel(repo=repo_name) entry = settings_util.create_repo_rhodecode_ui(repo, VcsSettingsModel.SVN_BRANCH_SECTION, "svn-branch") Session().commit() model.delete_repo_svn_pattern(entry.ui_id) def test_fail_when_delete_id_from_other_repo(self, backend_svn): repo_name = backend_svn.repo_name model = VcsSettingsModel(repo=repo_name) delete_ui_patch = mock.patch.object(model.repo_settings, "delete_ui") with delete_ui_patch as delete_ui_mock: model.delete_repo_svn_pattern(123) Session().commit() delete_ui_mock.assert_called_once_with(-1) def test_raises_exception_when_repository_is_not_specified(self): model = VcsSettingsModel() with pytest.raises(Exception) as exc_info: model.delete_repo_svn_pattern(123) assert str(exc_info.value) == "Repository is not specified" class TestDeleteGlobalSvnPattern(object): def test_delete_global_svn_pattern_calls_delete_ui(self): model = VcsSettingsModel() delete_ui_patch = mock.patch.object(model.global_settings, "delete_ui") with delete_ui_patch as delete_ui_mock: model.delete_global_svn_pattern(123) delete_ui_mock.assert_called_once_with(123) class TestFilterUiSettings(object): def test_settings_are_filtered(self): model = VcsSettingsModel() repo_settings = [ UiSetting("extensions", "largefiles", "", True), UiSetting("phases", "publish", "True", True), UiSetting("hooks", "changegroup.repo_size", "hook", True), UiSetting("hooks", "changegroup.push_logger", "hook", True), UiSetting("hooks", "outgoing.pull_logger", "hook", True), UiSetting("vcs_svn_branch", "84223c972204fa545ca1b22dac7bef5b68d7442d", "test_branch", True), UiSetting("vcs_svn_tag", "84229c972204fa545ca1b22dac7bef5b68d7442d", "test_tag", True), ] non_repo_settings = [ UiSetting("largefiles", "usercache", "/example/largefiles-store", True), UiSetting("test", "outgoing.pull_logger", "hook", True), UiSetting("hooks", "test2", "hook", True), UiSetting("vcs_svn_repo", "84229c972204fa545ca1b22dac7bef5b68d7442d", "test_tag", True), ] settings = repo_settings + non_repo_settings filtered_settings = model._filter_ui_settings(settings) assert sorted(filtered_settings) == sorted(repo_settings) class TestFilterGeneralSettings(object): def test_settings_are_filtered(self): model = VcsSettingsModel() settings = { "rhodecode_abcde": "value1", "rhodecode_vwxyz": "value2", } general_settings = {"rhodecode_{}".format(key): "value" for key in VcsSettingsModel.GENERAL_SETTINGS} settings.update(general_settings) filtered_settings = model._filter_general_settings(general_settings) assert sorted(filtered_settings) == sorted(general_settings) class TestGetRepoUiSettings(object): def test_global_uis_are_returned_when_no_repo_uis_found(self, repo_stub): model = VcsSettingsModel(repo=repo_stub.repo_name) result = model.get_repo_ui_settings() svn_sections = (VcsSettingsModel.SVN_TAG_SECTION, VcsSettingsModel.SVN_BRANCH_SECTION) expected_result = [s for s in model.global_settings.get_ui() if s.section not in svn_sections] assert sorted(result) == sorted(expected_result) def test_repo_uis_are_overriding_global_uis(self, repo_stub, settings_util): for section, key in VcsSettingsModel.HOOKS_SETTINGS: settings_util.create_repo_rhodecode_ui(repo_stub, section, "repo", key=key, active=False) model = VcsSettingsModel(repo=repo_stub.repo_name) result = model.get_repo_ui_settings() for setting in result: locator = (setting.section, setting.key) if locator in VcsSettingsModel.HOOKS_SETTINGS: assert setting.value == "repo" assert setting.active is False def test_global_svn_patterns_are_not_in_list(self, repo_stub, settings_util): svn_sections = (VcsSettingsModel.SVN_TAG_SECTION, VcsSettingsModel.SVN_BRANCH_SECTION) for section in svn_sections: settings_util.create_rhodecode_ui(section, "repo", key="deadbeef" + section, active=False) Session().commit() model = VcsSettingsModel(repo=repo_stub.repo_name) result = model.get_repo_ui_settings() for setting in result: assert setting.section not in svn_sections def test_repo_uis_filtered_by_section_are_returned(self, repo_stub, settings_util): for section, key in VcsSettingsModel.HOOKS_SETTINGS: settings_util.create_repo_rhodecode_ui(repo_stub, section, "repo", key=key, active=False) model = VcsSettingsModel(repo=repo_stub.repo_name) section, key = VcsSettingsModel.HOOKS_SETTINGS[0] result = model.get_repo_ui_settings(section=section) for setting in result: assert setting.section == section def test_repo_uis_filtered_by_key_are_returned(self, repo_stub, settings_util): for section, key in VcsSettingsModel.HOOKS_SETTINGS: settings_util.create_repo_rhodecode_ui(repo_stub, section, "repo", key=key, active=False) model = VcsSettingsModel(repo=repo_stub.repo_name) section, key = VcsSettingsModel.HOOKS_SETTINGS[0] result = model.get_repo_ui_settings(key=key) for setting in result: assert setting.key == key def test_raises_exception_when_repository_is_not_specified(self): model = VcsSettingsModel() with pytest.raises(Exception) as exc_info: model.get_repo_ui_settings() assert str(exc_info.value) == "Repository is not specified" class TestGetRepoGeneralSettings(object): def test_global_settings_are_returned_when_no_repo_settings_found(self, repo_stub): model = VcsSettingsModel(repo=repo_stub.repo_name) result = model.get_repo_general_settings() expected_result = model.global_settings.get_all_settings() assert sorted(result) == sorted(expected_result) def test_repo_uis_are_overriding_global_uis(self, repo_stub, settings_util): for key in VcsSettingsModel.GENERAL_SETTINGS: settings_util.create_repo_rhodecode_setting(repo_stub, key, "abcde", type_="unicode") Session().commit() model = VcsSettingsModel(repo=repo_stub.repo_name) result = model.get_repo_ui_settings() for key in result: if key in VcsSettingsModel.GENERAL_SETTINGS: assert result[key] == "abcde" def test_raises_exception_when_repository_is_not_specified(self): model = VcsSettingsModel() with pytest.raises(Exception) as exc_info: model.get_repo_general_settings() assert str(exc_info.value) == "Repository is not specified" class TestGetGlobalGeneralSettings(object): def test_global_settings_are_returned(self, repo_stub): model = VcsSettingsModel() result = model.get_global_general_settings() expected_result = model.global_settings.get_all_settings() assert sorted(result) == sorted(expected_result) def test_repo_uis_are_not_overriding_global_uis(self, repo_stub, settings_util): for key in VcsSettingsModel.GENERAL_SETTINGS: settings_util.create_repo_rhodecode_setting(repo_stub, key, "abcde", type_="unicode") Session().commit() model = VcsSettingsModel(repo=repo_stub.repo_name) result = model.get_global_general_settings() expected_result = model.global_settings.get_all_settings() assert sorted(result) == sorted(expected_result) class TestGetGlobalUiSettings(object): def test_global_uis_are_returned(self, repo_stub): model = VcsSettingsModel() result = model.get_global_ui_settings() expected_result = model.global_settings.get_ui() assert sorted(result) == sorted(expected_result) def test_repo_uis_are_not_overriding_global_uis(self, repo_stub, settings_util): for section, key in VcsSettingsModel.HOOKS_SETTINGS: settings_util.create_repo_rhodecode_ui(repo_stub, section, "repo", key=key, active=False) Session().commit() model = VcsSettingsModel(repo=repo_stub.repo_name) result = model.get_global_ui_settings() expected_result = model.global_settings.get_ui() assert sorted(result) == sorted(expected_result) def test_ui_settings_filtered_by_section(self, repo_stub, settings_util): model = VcsSettingsModel(repo=repo_stub.repo_name) section, key = VcsSettingsModel.HOOKS_SETTINGS[0] result = model.get_global_ui_settings(section=section) expected_result = model.global_settings.get_ui(section=section) assert sorted(result) == sorted(expected_result) def test_ui_settings_filtered_by_key(self, repo_stub, settings_util): model = VcsSettingsModel(repo=repo_stub.repo_name) section, key = VcsSettingsModel.HOOKS_SETTINGS[0] result = model.get_global_ui_settings(key=key) expected_result = model.global_settings.get_ui(key=key) assert sorted(result) == sorted(expected_result) class TestGetGeneralSettings(object): def test_global_settings_are_returned_when_inherited_is_true(self, repo_stub, settings_util): model = VcsSettingsModel(repo=repo_stub.repo_name) model.inherit_global_settings = True for key in VcsSettingsModel.GENERAL_SETTINGS: settings_util.create_repo_rhodecode_setting(repo_stub, key, "abcde", type_="unicode") Session().commit() result = model.get_general_settings() expected_result = model.get_global_general_settings() assert sorted(result) == sorted(expected_result) def test_repo_settings_are_returned_when_inherited_is_false(self, repo_stub, settings_util): model = VcsSettingsModel(repo=repo_stub.repo_name) model.inherit_global_settings = False for key in VcsSettingsModel.GENERAL_SETTINGS: settings_util.create_repo_rhodecode_setting(repo_stub, key, "abcde", type_="unicode") Session().commit() result = model.get_general_settings() expected_result = model.get_repo_general_settings() assert sorted(result) == sorted(expected_result) def test_global_settings_are_returned_when_no_repository_specified(self): model = VcsSettingsModel() result = model.get_general_settings() expected_result = model.get_global_general_settings() assert sorted(result) == sorted(expected_result) class TestGetUiSettings(object): def test_global_settings_are_returned_when_inherited_is_true(self, repo_stub, settings_util): model = VcsSettingsModel(repo=repo_stub.repo_name) model.inherit_global_settings = True for section, key in VcsSettingsModel.HOOKS_SETTINGS: settings_util.create_repo_rhodecode_ui(repo_stub, section, "repo", key=key, active=True) Session().commit() result = model.get_ui_settings() expected_result = model.get_global_ui_settings() assert sorted(result) == sorted(expected_result) def test_repo_settings_are_returned_when_inherited_is_false(self, repo_stub, settings_util): model = VcsSettingsModel(repo=repo_stub.repo_name) model.inherit_global_settings = False for section, key in VcsSettingsModel.HOOKS_SETTINGS: settings_util.create_repo_rhodecode_ui(repo_stub, section, "repo", key=key, active=True) Session().commit() result = model.get_ui_settings() expected_result = model.get_repo_ui_settings() assert sorted(result) == sorted(expected_result) def test_repo_settings_filtered_by_section_and_key(self, repo_stub): model = VcsSettingsModel(repo=repo_stub.repo_name) model.inherit_global_settings = False args = ("section", "key") with mock.patch.object(model, "get_repo_ui_settings") as settings_mock: model.get_ui_settings(*args) Session().commit() settings_mock.assert_called_once_with(*args) def test_global_settings_filtered_by_section_and_key(self): model = VcsSettingsModel() args = ("section", "key") with mock.patch.object(model, "get_global_ui_settings") as (settings_mock): model.get_ui_settings(*args) settings_mock.assert_called_once_with(*args) def test_global_settings_are_returned_when_no_repository_specified(self): model = VcsSettingsModel() result = model.get_ui_settings() expected_result = model.get_global_ui_settings() assert sorted(result) == sorted(expected_result) class TestGetSvnPatterns(object): def test_repo_settings_filtered_by_section_and_key(self, repo_stub): model = VcsSettingsModel(repo=repo_stub.repo_name) args = ("section",) with mock.patch.object(model, "get_repo_ui_settings") as settings_mock: model.get_svn_patterns(*args) Session().commit() settings_mock.assert_called_once_with(*args) def test_global_settings_filtered_by_section_and_key(self): model = VcsSettingsModel() args = ("section",) with mock.patch.object(model, "get_global_ui_settings") as (settings_mock): model.get_svn_patterns(*args) settings_mock.assert_called_once_with(*args) class TestCreateOrUpdateRepoSettings(object): FORM_DATA = { "inherit_global_settings": False, "hooks_changegroup_repo_size": False, "hooks_changegroup_push_logger": False, "hooks_outgoing_pull_logger": False, "extensions_largefiles": False, "extensions_evolve": False, "vcs_git_lfs_enabled": False, "vcs_git_default_branch": "main", "phases_publish": "False", "rhodecode_pr_merge_enabled": False, "rhodecode_auto_merge_enabled": False, "rhodecode_use_outdated_comments": False, "rhodecode_hg_use_rebase_for_merging": False, "rhodecode_hg_close_branch_before_merging": False, "rhodecode_hg_merge_strategy_selector": False, "rhodecode_git_use_rebase_for_merging": False, "rhodecode_git_close_branch_before_merging": False, "rhodecode_git_merge_strategy_selector": False, "rhodecode_diff_cache": False, "rhodecode_pr_target_branch_prepopulate": False, "new_svn_branch": "", "new_svn_tag": "", } def test_get_raises_exception_when_repository_not_specified(self): model = VcsSettingsModel() with pytest.raises(Exception) as exc_info: model.create_or_update_repo_settings(data=self.FORM_DATA) Session().commit() assert str(exc_info.value) == "Repository is not specified" def test_only_svn_settings_are_updated_when_type_is_svn(self, backend_svn): repo = backend_svn.create_repo() model = VcsSettingsModel(repo=repo) with self._patch_model(model) as mocks: model.create_or_update_repo_settings(data=self.FORM_DATA, inherit_global_settings=False) Session().commit() mocks["create_repo_svn_settings"].assert_called_once_with(self.FORM_DATA) non_called_methods = ( "create_or_update_repo_hook_settings", "create_or_update_repo_pr_settings", "create_or_update_repo_hg_settings", ) for method in non_called_methods: assert mocks[method].call_count == 0 def test_non_svn_settings_are_updated_when_type_is_hg(self, backend_hg): repo = backend_hg.create_repo() model = VcsSettingsModel(repo=repo) with self._patch_model(model) as mocks: model.create_or_update_repo_settings(data=self.FORM_DATA, inherit_global_settings=False) Session().commit() assert mocks["create_repo_svn_settings"].call_count == 0 called_methods = ( "create_or_update_repo_hook_settings", "create_or_update_repo_pr_settings", "create_or_update_repo_hg_settings", ) for method in called_methods: mocks[method].assert_called_once_with(self.FORM_DATA) def test_non_svn_and_hg_settings_are_updated_when_type_is_git(self, backend_git): repo = backend_git.create_repo() model = VcsSettingsModel(repo=repo) with self._patch_model(model) as mocks: model.create_or_update_repo_settings(data=self.FORM_DATA, inherit_global_settings=False) assert mocks["create_repo_svn_settings"].call_count == 0 called_methods = ("create_or_update_repo_hook_settings", "create_or_update_repo_pr_settings") non_called_methods = ("create_repo_svn_settings", "create_or_update_repo_hg_settings") for method in called_methods: mocks[method].assert_called_once_with(self.FORM_DATA) for method in non_called_methods: assert mocks[method].call_count == 0 def test_no_methods_are_called_when_settings_are_inherited(self, backend): repo = backend.create_repo() model = VcsSettingsModel(repo=repo) with self._patch_model(model) as mocks: model.create_or_update_repo_settings(data=self.FORM_DATA, inherit_global_settings=True) for method_name in mocks: assert mocks[method_name].call_count == 0 def test_cache_is_marked_for_invalidation(self, repo_stub): model = VcsSettingsModel(repo=repo_stub) invalidation_patcher = mock.patch("rhodecode.model.scm.ScmModel.mark_for_invalidation") with invalidation_patcher as invalidation_mock: model.create_or_update_repo_settings(data=self.FORM_DATA, inherit_global_settings=True) Session().commit() invalidation_mock.assert_called_once_with(repo_stub.repo_name, delete=True) def test_inherit_flag_is_saved(self, repo_stub): model = VcsSettingsModel(repo=repo_stub) model.inherit_global_settings = True with self._patch_model(model): model.create_or_update_repo_settings(data=self.FORM_DATA, inherit_global_settings=False) Session().commit() assert model.inherit_global_settings is False def _patch_model(self, model): return mock.patch.multiple( model, create_repo_svn_settings=mock.DEFAULT, create_or_update_repo_hook_settings=mock.DEFAULT, create_or_update_repo_pr_settings=mock.DEFAULT, create_or_update_repo_hg_settings=mock.DEFAULT, )