diff --git a/conftest.py b/conftest.py
index f731dbc6..0ac472d3 100644
--- a/conftest.py
+++ b/conftest.py
@@ -27,8 +27,11 @@ from rhodecode.tests.conftest_common import ( # noqa
pytest_plugins = [
- "rhodecode.tests.fixture_mods.fixture_pyramid",
- "rhodecode.tests.fixture_mods.fixture_utils",
+ "rhodecode.tests.fixtures.fixture_pyramid",
+ "rhodecode.tests.fixtures.fixture_utils",
+ "rhodecode.tests.fixtures.function_scoped_baseapp",
+ "rhodecode.tests.fixtures.module_scoped_baseapp",
+ "rhodecode.tests.fixtures.rcextensions_fixtures",
]
diff --git a/pyproject.toml b/pyproject.toml
index 84e5acbd..599ef4f8 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -65,8 +65,7 @@ dependencies = {file = ["requirements.txt"]}
optional-dependencies.tests = {file = ["requirements_test.txt"]}
[tool.ruff]
-
-select = [
+lint.select = [
# Pyflakes
"F",
# Pycodestyle
@@ -75,16 +74,13 @@ select = [
# isort
"I001"
]
-
-ignore = [
+lint.ignore = [
"E501", # line too long, handled by black
]
-
# Same as Black.
line-length = 120
-[tool.ruff.isort]
-
+[tool.ruff.lint.isort]
known-first-party = ["rhodecode"]
[tool.ruff.format]
diff --git a/pytest.ini b/pytest.ini
index e1bd2486..6afc1d2f 100644
--- a/pytest.ini
+++ b/pytest.ini
@@ -4,8 +4,10 @@ norecursedirs = rhodecode/public rhodecode/templates tests/scripts
cache_dir = /tmp/.pytest_cache
pyramid_config = rhodecode/tests/rhodecode.ini
-vcsserver_protocol = http
-vcsserver_config_http = rhodecode/tests/vcsserver_http.ini
+
+vcsserver_config = rhodecode/tests/vcsserver_http.ini
+rhodecode_config = rhodecode/tests/rhodecode.ini
+celery_config = rhodecode/tests/rhodecode.ini
addopts =
--pdbcls=IPython.terminal.debugger:TerminalPdb
diff --git a/rhodecode/api/tests/test_add_field_to_repo.py b/rhodecode/api/tests/test_add_field_to_repo.py
index c12ae440..3b9f1fc8 100644
--- a/rhodecode/api/tests/test_add_field_to_repo.py
+++ b/rhodecode/api/tests/test_add_field_to_repo.py
@@ -1,5 +1,4 @@
-
-# Copyright (C) 2010-2023 RhodeCode GmbH
+# 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
diff --git a/rhodecode/api/tests/test_create_gist.py b/rhodecode/api/tests/test_create_gist.py
index 41b4bf77..c440fb9e 100644
--- a/rhodecode/api/tests/test_create_gist.py
+++ b/rhodecode/api/tests/test_create_gist.py
@@ -24,7 +24,7 @@ from rhodecode.model.db import Gist
from rhodecode.model.gist import GistModel
from rhodecode.api.tests.utils import (
build_data, api_call, assert_error, assert_ok, crash)
-from rhodecode.tests.fixture import Fixture
+from rhodecode.tests.fixtures.rc_fixture import Fixture
@pytest.mark.usefixtures("testuser_api", "app")
diff --git a/rhodecode/api/tests/test_create_repo.py b/rhodecode/api/tests/test_create_repo.py
index be373a42..872d62e7 100644
--- a/rhodecode/api/tests/test_create_repo.py
+++ b/rhodecode/api/tests/test_create_repo.py
@@ -27,7 +27,7 @@ from rhodecode.model.user import UserModel
from rhodecode.tests import TEST_USER_ADMIN_LOGIN
from rhodecode.api.tests.utils import (
build_data, api_call, assert_ok, assert_error, crash)
-from rhodecode.tests.fixture import Fixture
+from rhodecode.tests.fixtures.rc_fixture import Fixture
from rhodecode.lib.ext_json import json
from rhodecode.lib.str_utils import safe_str
diff --git a/rhodecode/api/tests/test_create_repo_group.py b/rhodecode/api/tests/test_create_repo_group.py
index 72e7ee56..a72b2180 100644
--- a/rhodecode/api/tests/test_create_repo_group.py
+++ b/rhodecode/api/tests/test_create_repo_group.py
@@ -26,7 +26,7 @@ from rhodecode.model.user import UserModel
from rhodecode.tests import TEST_USER_ADMIN_LOGIN
from rhodecode.api.tests.utils import (
build_data, api_call, assert_ok, assert_error, crash)
-from rhodecode.tests.fixture import Fixture
+from rhodecode.tests.fixtures.rc_fixture import Fixture
fixture = Fixture()
diff --git a/rhodecode/api/tests/test_create_user.py b/rhodecode/api/tests/test_create_user.py
index 9b1e6797..6b612232 100644
--- a/rhodecode/api/tests/test_create_user.py
+++ b/rhodecode/api/tests/test_create_user.py
@@ -26,7 +26,7 @@ from rhodecode.tests import (
TEST_USER_ADMIN_LOGIN, TEST_USER_REGULAR_EMAIL)
from rhodecode.api.tests.utils import (
build_data, api_call, assert_ok, assert_error, jsonify, crash)
-from rhodecode.tests.fixture import Fixture
+from rhodecode.tests.fixtures.rc_fixture import Fixture
from rhodecode.model.db import RepoGroup
diff --git a/rhodecode/api/tests/test_create_user_group.py b/rhodecode/api/tests/test_create_user_group.py
index 14035458..fb101f0d 100644
--- a/rhodecode/api/tests/test_create_user_group.py
+++ b/rhodecode/api/tests/test_create_user_group.py
@@ -25,7 +25,7 @@ from rhodecode.model.user import UserModel
from rhodecode.model.user_group import UserGroupModel
from rhodecode.api.tests.utils import (
build_data, api_call, assert_error, assert_ok, crash, jsonify)
-from rhodecode.tests.fixture import Fixture
+from rhodecode.tests.fixtures.rc_fixture import Fixture
@pytest.mark.usefixtures("testuser_api", "app")
diff --git a/rhodecode/api/tests/test_fork_repo.py b/rhodecode/api/tests/test_fork_repo.py
index f24b1a90..bb4cb554 100644
--- a/rhodecode/api/tests/test_fork_repo.py
+++ b/rhodecode/api/tests/test_fork_repo.py
@@ -28,7 +28,7 @@ from rhodecode.model.user import UserModel
from rhodecode.tests import TEST_USER_ADMIN_LOGIN
from rhodecode.api.tests.utils import (
build_data, api_call, assert_error, assert_ok, crash)
-from rhodecode.tests.fixture import Fixture
+from rhodecode.tests.fixtures.rc_fixture import Fixture
fixture = Fixture()
diff --git a/rhodecode/api/tests/test_update_repo.py b/rhodecode/api/tests/test_update_repo.py
index f978b9aa..64f98f7c 100644
--- a/rhodecode/api/tests/test_update_repo.py
+++ b/rhodecode/api/tests/test_update_repo.py
@@ -25,8 +25,8 @@ from rhodecode.model.scm import ScmModel
from rhodecode.tests import TEST_USER_ADMIN_LOGIN, TEST_USER_REGULAR_LOGIN
from rhodecode.api.tests.utils import (
build_data, api_call, assert_error, assert_ok, crash, jsonify)
-from rhodecode.tests.fixture import Fixture
-from rhodecode.tests.fixture_mods.fixture_utils import plain_http_host_only_stub
+from rhodecode.tests.fixtures.rc_fixture import Fixture
+from rhodecode.tests.fixtures.fixture_utils import plain_http_host_only_stub
fixture = Fixture()
diff --git a/rhodecode/apps/admin/tests/test_admin_audit_logs.py b/rhodecode/apps/admin/tests/test_admin_audit_logs.py
index da127e3d..fe1475c3 100644
--- a/rhodecode/apps/admin/tests/test_admin_audit_logs.py
+++ b/rhodecode/apps/admin/tests/test_admin_audit_logs.py
@@ -26,7 +26,7 @@ import pytest
from rhodecode.lib.str_utils import safe_str
from rhodecode.tests import *
from rhodecode.tests.routes import route_path
-from rhodecode.tests.fixture import FIXTURES
+from rhodecode.tests.fixtures.rc_fixture import FIXTURES
from rhodecode.model.db import UserLog
from rhodecode.model.meta import Session
diff --git a/rhodecode/apps/admin/tests/test_admin_main_views.py b/rhodecode/apps/admin/tests/test_admin_main_views.py
index b0b75eab..1520cc51 100644
--- a/rhodecode/apps/admin/tests/test_admin_main_views.py
+++ b/rhodecode/apps/admin/tests/test_admin_main_views.py
@@ -20,7 +20,7 @@
import pytest
from rhodecode.tests import TestController
-from rhodecode.tests.fixture import Fixture
+from rhodecode.tests.fixtures.rc_fixture import Fixture
from rhodecode.tests.routes import route_path
fixture = Fixture()
diff --git a/rhodecode/apps/admin/tests/test_admin_repos.py b/rhodecode/apps/admin/tests/test_admin_repos.py
index 014a79b7..ab09b219 100644
--- a/rhodecode/apps/admin/tests/test_admin_repos.py
+++ b/rhodecode/apps/admin/tests/test_admin_repos.py
@@ -37,7 +37,7 @@ from rhodecode.model.user import UserModel
from rhodecode.tests import (
login_user_session, assert_session_flash, TEST_USER_ADMIN_LOGIN,
TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS)
-from rhodecode.tests.fixture import Fixture, error_function
+from rhodecode.tests.fixtures.rc_fixture import Fixture, error_function
from rhodecode.tests.utils import repo_on_filesystem
from rhodecode.tests.routes import route_path
diff --git a/rhodecode/apps/admin/tests/test_admin_repository_groups.py b/rhodecode/apps/admin/tests/test_admin_repository_groups.py
index 1f94bce2..9d168f39 100644
--- a/rhodecode/apps/admin/tests/test_admin_repository_groups.py
+++ b/rhodecode/apps/admin/tests/test_admin_repository_groups.py
@@ -27,7 +27,7 @@ from rhodecode.model.meta import Session
from rhodecode.model.repo_group import RepoGroupModel
from rhodecode.tests import (
assert_session_flash, TEST_USER_REGULAR_LOGIN, TESTS_TMP_PATH)
-from rhodecode.tests.fixture import Fixture
+from rhodecode.tests.fixtures.rc_fixture import Fixture
from rhodecode.tests.routes import route_path
diff --git a/rhodecode/apps/admin/tests/test_admin_user_groups.py b/rhodecode/apps/admin/tests/test_admin_user_groups.py
index c6dbe1d0..61d37d10 100644
--- a/rhodecode/apps/admin/tests/test_admin_user_groups.py
+++ b/rhodecode/apps/admin/tests/test_admin_user_groups.py
@@ -24,7 +24,7 @@ from rhodecode.model.meta import Session
from rhodecode.tests import (
TestController, assert_session_flash)
-from rhodecode.tests.fixture import Fixture
+from rhodecode.tests.fixtures.rc_fixture import Fixture
from rhodecode.tests.routes import route_path
fixture = Fixture()
diff --git a/rhodecode/apps/admin/tests/test_admin_users.py b/rhodecode/apps/admin/tests/test_admin_users.py
index 39b83e21..095d84a0 100644
--- a/rhodecode/apps/admin/tests/test_admin_users.py
+++ b/rhodecode/apps/admin/tests/test_admin_users.py
@@ -28,7 +28,7 @@ from rhodecode.model.user import UserModel
from rhodecode.tests import (
TestController, TEST_USER_REGULAR_LOGIN, assert_session_flash)
-from rhodecode.tests.fixture import Fixture
+from rhodecode.tests.fixtures.rc_fixture import Fixture
from rhodecode.tests.routes import route_path
fixture = Fixture()
diff --git a/rhodecode/apps/admin/tests/test_admin_users_ssh_keys.py b/rhodecode/apps/admin/tests/test_admin_users_ssh_keys.py
index 1d1e09b3..33518b74 100644
--- a/rhodecode/apps/admin/tests/test_admin_users_ssh_keys.py
+++ b/rhodecode/apps/admin/tests/test_admin_users_ssh_keys.py
@@ -22,7 +22,7 @@ import pytest
from rhodecode.model.db import User, UserSshKeys
from rhodecode.tests import TestController, assert_session_flash
-from rhodecode.tests.fixture import Fixture
+from rhodecode.tests.fixtures.rc_fixture import Fixture
from rhodecode.tests.routes import route_path
fixture = Fixture()
diff --git a/rhodecode/apps/home/tests/test_get_goto_switched_data.py b/rhodecode/apps/home/tests/test_get_goto_switched_data.py
index b7d6e269..551fcbe9 100644
--- a/rhodecode/apps/home/tests/test_get_goto_switched_data.py
+++ b/rhodecode/apps/home/tests/test_get_goto_switched_data.py
@@ -27,7 +27,7 @@ from rhodecode.model.repo_group import RepoGroupModel
from rhodecode.model.db import Session, Repository, RepoGroup
from rhodecode.tests import TestController, TEST_USER_ADMIN_LOGIN
-from rhodecode.tests.fixture import Fixture
+from rhodecode.tests.fixtures.rc_fixture import Fixture
from rhodecode.tests.routes import route_path
fixture = Fixture()
diff --git a/rhodecode/apps/home/tests/test_get_repo_list_data.py b/rhodecode/apps/home/tests/test_get_repo_list_data.py
index 52139aed..bf6b7d31 100644
--- a/rhodecode/apps/home/tests/test_get_repo_list_data.py
+++ b/rhodecode/apps/home/tests/test_get_repo_list_data.py
@@ -22,7 +22,7 @@ from rhodecode.model.db import Repository
from rhodecode.lib.ext_json import json
from rhodecode.tests import TestController
-from rhodecode.tests.fixture import Fixture
+from rhodecode.tests.fixtures.rc_fixture import Fixture
from rhodecode.tests.routes import route_path
fixture = Fixture()
diff --git a/rhodecode/apps/home/tests/test_get_user_data.py b/rhodecode/apps/home/tests/test_get_user_data.py
index d1128c5c..2113b360 100644
--- a/rhodecode/apps/home/tests/test_get_user_data.py
+++ b/rhodecode/apps/home/tests/test_get_user_data.py
@@ -20,7 +20,7 @@ import pytest
from rhodecode.lib.ext_json import json
from rhodecode.tests import TestController
-from rhodecode.tests.fixture import Fixture
+from rhodecode.tests.fixtures.rc_fixture import Fixture
from rhodecode.tests.routes import route_path
fixture = Fixture()
diff --git a/rhodecode/apps/home/tests/test_get_user_group_data.py b/rhodecode/apps/home/tests/test_get_user_group_data.py
index dea6573f..9fdb613c 100644
--- a/rhodecode/apps/home/tests/test_get_user_group_data.py
+++ b/rhodecode/apps/home/tests/test_get_user_group_data.py
@@ -40,7 +40,7 @@ import pytest
from rhodecode.lib.ext_json import json
from rhodecode.tests import TestController
-from rhodecode.tests.fixture import Fixture
+from rhodecode.tests.fixtures.rc_fixture import Fixture
from rhodecode.tests.routes import route_path
fixture = Fixture()
diff --git a/rhodecode/apps/home/tests/test_home.py b/rhodecode/apps/home/tests/test_home.py
index 9b855285..fdcfb634 100644
--- a/rhodecode/apps/home/tests/test_home.py
+++ b/rhodecode/apps/home/tests/test_home.py
@@ -24,7 +24,7 @@ from rhodecode.model.db import Repository, RepoGroup, User
from rhodecode.model.meta import Session
from rhodecode.model.settings import SettingsModel
from rhodecode.tests import TestController
-from rhodecode.tests.fixture import Fixture
+from rhodecode.tests.fixtures.rc_fixture import Fixture
from rhodecode.tests.routes import route_path
diff --git a/rhodecode/apps/login/tests/test_2fa.py b/rhodecode/apps/login/tests/test_2fa.py
index 3c3ec102..0e193253 100644
--- a/rhodecode/apps/login/tests/test_2fa.py
+++ b/rhodecode/apps/login/tests/test_2fa.py
@@ -3,7 +3,7 @@ import mock
from rhodecode.lib.type_utils import AttributeDict
from rhodecode.model.meta import Session
-from rhodecode.tests.fixture import Fixture
+from rhodecode.tests.fixtures.rc_fixture import Fixture
from rhodecode.tests.routes import route_path
from rhodecode.model.settings import SettingsModel
diff --git a/rhodecode/apps/login/tests/test_login.py b/rhodecode/apps/login/tests/test_login.py
index 424cfabf..22c9ac8e 100644
--- a/rhodecode/apps/login/tests/test_login.py
+++ b/rhodecode/apps/login/tests/test_login.py
@@ -31,7 +31,7 @@ from rhodecode.model.meta import Session
from rhodecode.tests import (
assert_session_flash, HG_REPO, TEST_USER_ADMIN_LOGIN,
no_newline_id_generator)
-from rhodecode.tests.fixture import Fixture
+from rhodecode.tests.fixtures.rc_fixture import Fixture
from rhodecode.tests.routes import route_path
fixture = Fixture()
diff --git a/rhodecode/apps/login/tests/test_password_reset.py b/rhodecode/apps/login/tests/test_password_reset.py
index 3d95cc2d..d4d26b4f 100644
--- a/rhodecode/apps/login/tests/test_password_reset.py
+++ b/rhodecode/apps/login/tests/test_password_reset.py
@@ -22,7 +22,7 @@ from rhodecode.lib import helpers as h
from rhodecode.tests import (
TestController, clear_cache_regions,
TEST_USER_ADMIN_LOGIN, TEST_USER_ADMIN_PASS)
-from rhodecode.tests.fixture import Fixture
+from rhodecode.tests.fixtures.rc_fixture import Fixture
from rhodecode.tests.utils import AssertResponse
from rhodecode.tests.routes import route_path
diff --git a/rhodecode/apps/my_account/tests/test_my_account_auth_tokens.py b/rhodecode/apps/my_account/tests/test_my_account_auth_tokens.py
index 5923c751..162221dc 100644
--- a/rhodecode/apps/my_account/tests/test_my_account_auth_tokens.py
+++ b/rhodecode/apps/my_account/tests/test_my_account_auth_tokens.py
@@ -22,7 +22,7 @@ from rhodecode.apps._base import ADMIN_PREFIX
from rhodecode.model.db import User
from rhodecode.tests import (
TestController, assert_session_flash)
-from rhodecode.tests.fixture import Fixture
+from rhodecode.tests.fixtures.rc_fixture import Fixture
from rhodecode.tests.routes import route_path
diff --git a/rhodecode/apps/my_account/tests/test_my_account_emails.py b/rhodecode/apps/my_account/tests/test_my_account_emails.py
index ba4f542b..4ca87b60 100644
--- a/rhodecode/apps/my_account/tests/test_my_account_emails.py
+++ b/rhodecode/apps/my_account/tests/test_my_account_emails.py
@@ -23,7 +23,7 @@ from rhodecode.model.db import User, UserEmailMap
from rhodecode.tests import (
TestController, TEST_USER_ADMIN_LOGIN, TEST_USER_REGULAR_EMAIL,
assert_session_flash, TEST_USER_REGULAR_PASS)
-from rhodecode.tests.fixture import Fixture
+from rhodecode.tests.fixtures.rc_fixture import Fixture
from rhodecode.tests.routes import route_path
diff --git a/rhodecode/apps/my_account/tests/test_my_account_notifications.py b/rhodecode/apps/my_account/tests/test_my_account_notifications.py
index f6746159..a8259dd7 100644
--- a/rhodecode/apps/my_account/tests/test_my_account_notifications.py
+++ b/rhodecode/apps/my_account/tests/test_my_account_notifications.py
@@ -21,7 +21,7 @@ import pytest
from rhodecode.tests import (
TestController, TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS,
TEST_USER_ADMIN_LOGIN, TEST_USER_ADMIN_PASS)
-from rhodecode.tests.fixture import Fixture
+from rhodecode.tests.fixtures.rc_fixture import Fixture
from rhodecode.tests.routes import route_path
from rhodecode.model.db import Notification, User
diff --git a/rhodecode/apps/my_account/tests/test_my_account_password.py b/rhodecode/apps/my_account/tests/test_my_account_password.py
index a1841e1b..23f5bdfa 100644
--- a/rhodecode/apps/my_account/tests/test_my_account_password.py
+++ b/rhodecode/apps/my_account/tests/test_my_account_password.py
@@ -24,7 +24,7 @@ from rhodecode.lib.auth import check_password
from rhodecode.model.meta import Session
from rhodecode.model.user import UserModel
from rhodecode.tests import assert_session_flash, TestController
-from rhodecode.tests.fixture import Fixture, error_function
+from rhodecode.tests.fixtures.rc_fixture import Fixture, error_function
from rhodecode.tests.routes import route_path
fixture = Fixture()
diff --git a/rhodecode/apps/my_account/tests/test_my_account_profile.py b/rhodecode/apps/my_account/tests/test_my_account_profile.py
index 79117835..fe8d9ac8 100644
--- a/rhodecode/apps/my_account/tests/test_my_account_profile.py
+++ b/rhodecode/apps/my_account/tests/test_my_account_profile.py
@@ -20,7 +20,7 @@
from rhodecode.tests import (
TestController, TEST_USER_ADMIN_LOGIN,
TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS)
-from rhodecode.tests.fixture import Fixture
+from rhodecode.tests.fixtures.rc_fixture import Fixture
from rhodecode.tests.routes import route_path
fixture = Fixture()
diff --git a/rhodecode/apps/my_account/tests/test_my_account_simple_views.py b/rhodecode/apps/my_account/tests/test_my_account_simple_views.py
index 154f4768..1fb74f8c 100644
--- a/rhodecode/apps/my_account/tests/test_my_account_simple_views.py
+++ b/rhodecode/apps/my_account/tests/test_my_account_simple_views.py
@@ -19,7 +19,7 @@
from rhodecode.model.db import User, Repository, UserFollowing
from rhodecode.tests import TestController, TEST_USER_ADMIN_LOGIN
-from rhodecode.tests.fixture import Fixture
+from rhodecode.tests.fixtures.rc_fixture import Fixture
from rhodecode.tests.routes import route_path
fixture = Fixture()
diff --git a/rhodecode/apps/my_account/tests/test_my_account_ssh_keys.py b/rhodecode/apps/my_account/tests/test_my_account_ssh_keys.py
index 7e769eda..cf853330 100644
--- a/rhodecode/apps/my_account/tests/test_my_account_ssh_keys.py
+++ b/rhodecode/apps/my_account/tests/test_my_account_ssh_keys.py
@@ -21,7 +21,7 @@
from rhodecode.model.db import User, UserSshKeys
from rhodecode.tests import TestController, assert_session_flash
-from rhodecode.tests.fixture import Fixture
+from rhodecode.tests.fixtures.rc_fixture import Fixture
from rhodecode.tests.routes import route_path
fixture = Fixture()
diff --git a/rhodecode/apps/repository/tests/test_repo_compare_on_single_file.py b/rhodecode/apps/repository/tests/test_repo_compare_on_single_file.py
index 8ba459eb..2d81aaad 100644
--- a/rhodecode/apps/repository/tests/test_repo_compare_on_single_file.py
+++ b/rhodecode/apps/repository/tests/test_repo_compare_on_single_file.py
@@ -22,7 +22,7 @@ import pytest
from rhodecode.apps.repository.tests.test_repo_compare import ComparePage
from rhodecode.lib.vcs import nodes
from rhodecode.lib.vcs.backends.base import EmptyCommit
-from rhodecode.tests.fixture import Fixture
+from rhodecode.tests.fixtures.rc_fixture import Fixture
from rhodecode.tests.utils import commit_change
from rhodecode.tests.routes import route_path
@@ -166,14 +166,15 @@ class TestSideBySideDiff(object):
response.mustcontain('Collapse 2 commits')
response.mustcontain('123 file changed')
- response.mustcontain(
- 'r%s:%s...r%s:%s' % (
- commit1.idx, commit1.short_id, commit2.idx, commit2.short_id))
+ response.mustcontain(f'r{commit1.idx}:{commit1.short_id}...r{commit2.idx}:{commit2.short_id}')
response.mustcontain(f_path)
- @pytest.mark.xfail(reason='GIT does not handle empty commit compare correct (missing 1 commit)')
+ #@pytest.mark.xfail(reason='GIT does not handle empty commit compare correct (missing 1 commit)')
def test_diff_side_by_side_from_0_commit_with_file_filter(self, app, backend, backend_stub):
+ if backend.alias == 'git':
+ pytest.skip('GIT does not handle empty commit compare correct (missing 1 commit)')
+
f_path = b'test_sidebyside_file.py'
commit1_content = b'content-25d7e49c18b159446c\n'
commit2_content = b'content-603d6c72c46d953420\n'
@@ -200,9 +201,7 @@ class TestSideBySideDiff(object):
response.mustcontain('Collapse 2 commits')
response.mustcontain('1 file changed')
- response.mustcontain(
- 'r%s:%s...r%s:%s' % (
- commit1.idx, commit1.short_id, commit2.idx, commit2.short_id))
+ response.mustcontain(f'r{commit1.idx}:{commit1.short_id}...r{commit2.idx}:{commit2.short_id}')
response.mustcontain(f_path)
diff --git a/rhodecode/apps/repository/tests/test_repo_files.py b/rhodecode/apps/repository/tests/test_repo_files.py
index 01301c8f..c59aed27 100644
--- a/rhodecode/apps/repository/tests/test_repo_files.py
+++ b/rhodecode/apps/repository/tests/test_repo_files.py
@@ -33,7 +33,7 @@ from rhodecode.lib.vcs.conf import settings
from rhodecode.model.db import Session, Repository
from rhodecode.tests import assert_session_flash
-from rhodecode.tests.fixture import Fixture
+from rhodecode.tests.fixtures.rc_fixture import Fixture
from rhodecode.tests.routes import route_path
diff --git a/rhodecode/apps/repository/tests/test_repo_forks.py b/rhodecode/apps/repository/tests/test_repo_forks.py
index 978b86ff..e52dc880 100644
--- a/rhodecode/apps/repository/tests/test_repo_forks.py
+++ b/rhodecode/apps/repository/tests/test_repo_forks.py
@@ -21,7 +21,7 @@ import pytest
from rhodecode.tests import TestController, assert_session_flash, HG_FORK, GIT_FORK
-from rhodecode.tests.fixture import Fixture
+from rhodecode.tests.fixtures.rc_fixture import Fixture
from rhodecode.lib import helpers as h
from rhodecode.model.db import Repository
diff --git a/rhodecode/apps/repository/tests/test_repo_maintainance.py b/rhodecode/apps/repository/tests/test_repo_maintainance.py
index 8b812084..86e0ad49 100644
--- a/rhodecode/apps/repository/tests/test_repo_maintainance.py
+++ b/rhodecode/apps/repository/tests/test_repo_maintainance.py
@@ -21,7 +21,7 @@ import pytest
from rhodecode.model.db import Repository, UserRepoToPerm, Permission, User
-from rhodecode.tests.fixture import Fixture
+from rhodecode.tests.fixtures.rc_fixture import Fixture
from rhodecode.tests.routes import route_path
fixture = Fixture()
diff --git a/rhodecode/apps/repository/tests/test_repo_pullrequests.py b/rhodecode/apps/repository/tests/test_repo_pullrequests.py
index 1df532a3..ad41a2cb 100644
--- a/rhodecode/apps/repository/tests/test_repo_pullrequests.py
+++ b/rhodecode/apps/repository/tests/test_repo_pullrequests.py
@@ -15,6 +15,9 @@
# 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 logging
+import os
+
import mock
import pytest
@@ -41,7 +44,7 @@ from rhodecode.tests import (
TEST_USER_ADMIN_LOGIN,
TEST_USER_REGULAR_LOGIN,
)
-from rhodecode.tests.fixture_mods.fixture_utils import PRTestUtility
+from rhodecode.tests.fixtures.fixture_utils import PRTestUtility
from rhodecode.tests.routes import route_path
@@ -1050,7 +1053,6 @@ class TestPullrequestsView(object):
)
assert len(notifications.all()) == 2
- @pytest.mark.xfail(reason="unable to fix this test after python3 migration")
def test_create_pull_request_stores_ancestor_commit_id(self, backend, csrf_token):
commits = [
{
@@ -1125,20 +1127,38 @@ class TestPullrequestsView(object):
response.mustcontain(no=["content_of_ancestor-child"])
response.mustcontain("content_of_change")
- def test_merge_pull_request_enabled(self, pr_util, csrf_token):
- # Clear any previous calls to rcextensions
- rhodecode.EXTENSIONS.calls.clear()
+ def test_merge_pull_request_enabled(self, pr_util, csrf_token, rcextensions_modification):
pull_request = pr_util.create_pull_request(approved=True, mergeable=True)
pull_request_id = pull_request.pull_request_id
- repo_name = (pull_request.target_repo.scm_instance().name,)
+ repo_name = pull_request.target_repo.scm_instance().name
url = route_path(
"pullrequest_merge",
- repo_name=str(repo_name[0]),
+ repo_name=repo_name,
pull_request_id=pull_request_id,
)
- response = self.app.post(url, params={"csrf_token": csrf_token}).follow()
+
+ rcstack_location = os.path.dirname(self.app._pyramid_registry.settings['__file__'])
+ rc_ext_location = os.path.join(rcstack_location, 'rcextension-output.txt')
+
+
+ mods = [
+ ('_push_hook',
+ f"""
+ import os
+ action = kwargs['action']
+ commit_ids = kwargs['commit_ids']
+ with open('{rc_ext_location}', 'w') as f:
+ f.write('test-execution'+os.linesep)
+ f.write(f'{{action}}'+os.linesep)
+ f.write(f'{{commit_ids}}'+os.linesep)
+ return HookResponse(0, 'HOOK_TEST')
+ """)
+ ]
+ # Add the hook
+ with rcextensions_modification(rcstack_location, mods, create_if_missing=True, force_create=True):
+ response = self.app.post(url, params={"csrf_token": csrf_token}).follow()
pull_request = PullRequest.get(pull_request_id)
@@ -1162,12 +1182,39 @@ class TestPullrequestsView(object):
assert actions[-1].action == "user.push"
assert actions[-1].action_data["commit_ids"] == pr_commit_ids
- # Check post_push rcextension was really executed
- push_calls = rhodecode.EXTENSIONS.calls["_push_hook"]
- assert len(push_calls) == 1
- unused_last_call_args, last_call_kwargs = push_calls[0]
- assert last_call_kwargs["action"] == "push"
- assert last_call_kwargs["commit_ids"] == pr_commit_ids
+ with open(rc_ext_location) as f:
+ f_data = f.read()
+ assert 'test-execution' in f_data
+ for commit_id in pr_commit_ids:
+ assert f'{commit_id}' in f_data
+
+ def test_merge_pull_request_forbidden_by_pre_push_hook(self, pr_util, csrf_token, rcextensions_modification, caplog):
+ caplog.set_level(logging.WARNING, logger="rhodecode.model.pull_request")
+
+ pull_request = pr_util.create_pull_request(approved=True, mergeable=True)
+ pull_request_id = pull_request.pull_request_id
+ repo_name = pull_request.target_repo.scm_instance().name
+
+ url = route_path(
+ "pullrequest_merge",
+ repo_name=repo_name,
+ pull_request_id=pull_request_id,
+ )
+
+ rcstack_location = os.path.dirname(self.app._pyramid_registry.settings['__file__'])
+
+ mods = [
+ ('_pre_push_hook',
+ f"""
+ return HookResponse(1, 'HOOK_TEST_FORBIDDEN')
+ """)
+ ]
+ # Add the hook
+ with rcextensions_modification(rcstack_location, mods, create_if_missing=True, force_create=True):
+ self.app.post(url, params={"csrf_token": csrf_token})
+
+ assert 'Merge failed, not updating the pull request.' in [r[2] for r in caplog.record_tuples]
+
def test_merge_pull_request_disabled(self, pr_util, csrf_token):
pull_request = pr_util.create_pull_request(mergeable=False)
@@ -1523,7 +1570,6 @@ class TestPullrequestsView(object):
assert pull_request.revisions == [commit_ids["change-rebased"]]
-
def test_remove_pull_request_branch(self, backend_git, csrf_token):
branch_name = "development"
commits = [
diff --git a/rhodecode/apps/repository/tests/test_repo_settings.py b/rhodecode/apps/repository/tests/test_repo_settings.py
index 14b7281c..d20fe3cb 100644
--- a/rhodecode/apps/repository/tests/test_repo_settings.py
+++ b/rhodecode/apps/repository/tests/test_repo_settings.py
@@ -26,7 +26,7 @@ from rhodecode.model.db import Repository, UserRepoToPerm, Permission, User
from rhodecode.model.meta import Session
from rhodecode.tests import (
TEST_USER_ADMIN_LOGIN, TEST_USER_REGULAR_LOGIN, assert_session_flash)
-from rhodecode.tests.fixture import Fixture
+from rhodecode.tests.fixtures.rc_fixture import Fixture
from rhodecode.tests.routes import route_path
fixture = Fixture()
diff --git a/rhodecode/apps/repository/tests/test_repo_settings_advanced.py b/rhodecode/apps/repository/tests/test_repo_settings_advanced.py
index 1d3cdc80..dc8e8c6a 100644
--- a/rhodecode/apps/repository/tests/test_repo_settings_advanced.py
+++ b/rhodecode/apps/repository/tests/test_repo_settings_advanced.py
@@ -24,7 +24,7 @@ from rhodecode.model.db import Repository
from rhodecode.model.repo import RepoModel
from rhodecode.tests import (
HG_REPO, GIT_REPO, assert_session_flash, no_newline_id_generator)
-from rhodecode.tests.fixture import Fixture
+from rhodecode.tests.fixtures.rc_fixture import Fixture
from rhodecode.tests.utils import repo_on_filesystem
from rhodecode.tests.routes import route_path
diff --git a/rhodecode/apps/repository/tests/test_repo_summary.py b/rhodecode/apps/repository/tests/test_repo_summary.py
index 8fb75b34..a2a3ab92 100644
--- a/rhodecode/apps/repository/tests/test_repo_summary.py
+++ b/rhodecode/apps/repository/tests/test_repo_summary.py
@@ -31,7 +31,7 @@ from rhodecode.model.meta import Session
from rhodecode.model.repo import RepoModel
from rhodecode.model.scm import ScmModel
from rhodecode.tests import assert_session_flash
-from rhodecode.tests.fixture import Fixture
+from rhodecode.tests.fixtures.rc_fixture import Fixture
from rhodecode.tests.utils import AssertResponse, repo_on_filesystem
from rhodecode.tests.routes import route_path
diff --git a/rhodecode/apps/repository/tests/test_repo_vcs_settings.py b/rhodecode/apps/repository/tests/test_repo_vcs_settings.py
index cd41d528..63accea0 100644
--- a/rhodecode/apps/repository/tests/test_repo_vcs_settings.py
+++ b/rhodecode/apps/repository/tests/test_repo_vcs_settings.py
@@ -30,7 +30,7 @@ from rhodecode.model.user import UserModel
from rhodecode.tests import (
login_user_session, logout_user_session,
TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS)
-from rhodecode.tests.fixture import Fixture
+from rhodecode.tests.fixtures.rc_fixture import Fixture
from rhodecode.tests.utils import AssertResponse
from rhodecode.tests.routes import route_path
diff --git a/rhodecode/apps/repository/tests/test_vcs_settings.py b/rhodecode/apps/repository/tests/test_vcs_settings.py
index 72d9a07c..0b05c64a 100644
--- a/rhodecode/apps/repository/tests/test_vcs_settings.py
+++ b/rhodecode/apps/repository/tests/test_vcs_settings.py
@@ -32,16 +32,13 @@ class TestAdminRepoVcsSettings(object):
@pytest.mark.parametrize('setting_name, setting_backends', [
('hg_use_rebase_for_merging', ['hg']),
])
- def test_labs_settings_visible_if_enabled(
- self, setting_name, setting_backends, backend):
+ def test_labs_settings_visible_if_enabled(self, setting_name, setting_backends, backend):
if backend.alias not in setting_backends:
pytest.skip('Setting not available for backend {}'.format(backend))
- vcs_settings_url = route_path(
- 'edit_repo_vcs', repo_name=backend.repo.repo_name)
+ vcs_settings_url = route_path('edit_repo_vcs', repo_name=backend.repo.repo_name)
- with mock.patch.dict(
- rhodecode.CONFIG, {'labs_settings_active': 'true'}):
+ with mock.patch.dict(rhodecode.CONFIG, {'labs_settings_active': 'true'}):
response = self.app.get(vcs_settings_url)
assertr = response.assert_response()
diff --git a/rhodecode/apps/ssh_support/lib/backends/base.py b/rhodecode/apps/ssh_support/lib/backends/base.py
index ede5ad3a..639a810e 100644
--- a/rhodecode/apps/ssh_support/lib/backends/base.py
+++ b/rhodecode/apps/ssh_support/lib/backends/base.py
@@ -20,7 +20,7 @@ import os
import sys
import logging
-from rhodecode.lib.hook_daemon.base import prepare_callback_daemon
+from rhodecode.lib.hook_daemon.utils import prepare_callback_daemon
from rhodecode.lib.ext_json import sjson as json
from rhodecode.lib.vcs.conf import settings as vcs_settings
from rhodecode.lib.api_utils import call_service_api
@@ -162,9 +162,7 @@ class SshVcsServer(object):
extras = {}
extras.update(tunnel_extras)
- callback_daemon, extras = prepare_callback_daemon(
- extras, protocol=self.hooks_protocol,
- host=vcs_settings.HOOKS_HOST)
+ callback_daemon, extras = prepare_callback_daemon(extras, protocol=self.hooks_protocol)
with callback_daemon:
try:
diff --git a/rhodecode/apps/ssh_support/tests/test_server_git.py b/rhodecode/apps/ssh_support/tests/test_server_git.py
index 843bec16..fc721340 100644
--- a/rhodecode/apps/ssh_support/tests/test_server_git.py
+++ b/rhodecode/apps/ssh_support/tests/test_server_git.py
@@ -33,19 +33,24 @@ class GitServerCreator(object):
'app:main': {
'ssh.executable.git': git_path,
'vcs.hooks.protocol.v2': 'celery',
+ 'app.service_api.host': 'http://localhost',
+ 'app.service_api.token': 'secret4',
+ 'rhodecode.api.url': '/_admin/api',
}
}
repo_name = 'test_git'
repo_mode = 'receive-pack'
user = plain_dummy_user()
- def __init__(self):
- pass
+ def __init__(self, service_api_url, ini_file):
+ self.service_api_url = service_api_url
+ self.ini_file = ini_file
def create(self, **kwargs):
+ self.config_data['app:main']['app.service_api.host'] = self.service_api_url
parameters = {
'store': self.root,
- 'ini_path': '',
+ 'ini_path': self.ini_file,
'user': self.user,
'repo_name': self.repo_name,
'repo_mode': self.repo_mode,
@@ -60,12 +65,30 @@ class GitServerCreator(object):
return server
-@pytest.fixture()
-def git_server(app):
- return GitServerCreator()
+@pytest.fixture(scope='module')
+def git_server(request, module_app, rhodecode_factory, available_port_factory):
+ ini_file = module_app._pyramid_settings['__file__']
+ vcsserver_host = module_app._pyramid_settings['vcs.server']
+
+ store_dir = os.path.dirname(ini_file)
+
+ # start rhodecode for service API
+ rc = rhodecode_factory(
+ request,
+ store_dir=store_dir,
+ port=available_port_factory(),
+ overrides=(
+ {'handler_console': {'level': 'DEBUG'}},
+ {'app:main': {'vcs.server': vcsserver_host}},
+ {'app:main': {'repo_store.path': store_dir}}
+ ))
+
+ service_api_url = f'http://{rc.bind_addr}'
+
+ return GitServerCreator(service_api_url, ini_file)
-class TestGitServer(object):
+class TestGitServer:
def test_command(self, git_server):
server = git_server.create()
@@ -102,14 +125,14 @@ class TestGitServer(object):
assert result is value
def test_run_returns_executes_command(self, git_server):
- server = git_server.create()
from rhodecode.apps.ssh_support.lib.backends.git import GitTunnelWrapper
+ server = git_server.create()
os.environ['SSH_CLIENT'] = '127.0.0.1'
with mock.patch.object(GitTunnelWrapper, 'create_hooks_env') as _patch:
_patch.return_value = 0
with mock.patch.object(GitTunnelWrapper, 'command', return_value='date'):
- exit_code = server.run()
+ exit_code = server.run(tunnel_extras={'config': server.ini_path})
assert exit_code == (0, False)
@@ -135,7 +158,7 @@ class TestGitServer(object):
'action': action,
'ip': '10.10.10.10',
'locked_by': [None, None],
- 'config': '',
+ 'config': git_server.ini_file,
'repo_store': store,
'server_url': None,
'hooks': ['push', 'pull'],
diff --git a/rhodecode/apps/ssh_support/tests/test_server_hg.py b/rhodecode/apps/ssh_support/tests/test_server_hg.py
index 9765eb52..e9585eb5 100644
--- a/rhodecode/apps/ssh_support/tests/test_server_hg.py
+++ b/rhodecode/apps/ssh_support/tests/test_server_hg.py
@@ -17,6 +17,7 @@
# and proprietary license terms, please see https://rhodecode.com/licenses/
import os
+
import mock
import pytest
@@ -32,22 +33,27 @@ class MercurialServerCreator(object):
'app:main': {
'ssh.executable.hg': hg_path,
'vcs.hooks.protocol.v2': 'celery',
+ 'app.service_api.host': 'http://localhost',
+ 'app.service_api.token': 'secret4',
+ 'rhodecode.api.url': '/_admin/api',
}
}
repo_name = 'test_hg'
user = plain_dummy_user()
- def __init__(self):
- pass
+ def __init__(self, service_api_url, ini_file):
+ self.service_api_url = service_api_url
+ self.ini_file = ini_file
def create(self, **kwargs):
+ self.config_data['app:main']['app.service_api.host'] = self.service_api_url
parameters = {
'store': self.root,
- 'ini_path': '',
+ 'ini_path': self.ini_file,
'user': self.user,
'repo_name': self.repo_name,
'user_permissions': {
- 'test_hg': 'repository.admin'
+ self.repo_name: 'repository.admin'
},
'settings': self.config_data['app:main'],
'env': plain_dummy_env()
@@ -57,12 +63,30 @@ class MercurialServerCreator(object):
return server
-@pytest.fixture()
-def hg_server(app):
- return MercurialServerCreator()
+@pytest.fixture(scope='module')
+def hg_server(request, module_app, rhodecode_factory, available_port_factory):
+ ini_file = module_app._pyramid_settings['__file__']
+ vcsserver_host = module_app._pyramid_settings['vcs.server']
+
+ store_dir = os.path.dirname(ini_file)
+
+ # start rhodecode for service API
+ rc = rhodecode_factory(
+ request,
+ store_dir=store_dir,
+ port=available_port_factory(),
+ overrides=(
+ {'handler_console': {'level': 'DEBUG'}},
+ {'app:main': {'vcs.server': vcsserver_host}},
+ {'app:main': {'repo_store.path': store_dir}}
+ ))
+
+ service_api_url = f'http://{rc.bind_addr}'
+
+ return MercurialServerCreator(service_api_url, ini_file)
-class TestMercurialServer(object):
+class TestMercurialServer:
def test_command(self, hg_server, tmpdir):
server = hg_server.create()
@@ -107,7 +131,7 @@ class TestMercurialServer(object):
with mock.patch.object(MercurialTunnelWrapper, 'create_hooks_env') as _patch:
_patch.return_value = 0
with mock.patch.object(MercurialTunnelWrapper, 'command', return_value='date'):
- exit_code = server.run()
+ exit_code = server.run(tunnel_extras={'config': server.ini_path})
assert exit_code == (0, False)
diff --git a/rhodecode/apps/ssh_support/tests/test_server_svn.py b/rhodecode/apps/ssh_support/tests/test_server_svn.py
index d8e1d1f0..e78d3149 100644
--- a/rhodecode/apps/ssh_support/tests/test_server_svn.py
+++ b/rhodecode/apps/ssh_support/tests/test_server_svn.py
@@ -15,7 +15,9 @@
# 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 os
+
import mock
import pytest
@@ -26,39 +28,62 @@ from rhodecode.apps.ssh_support.tests.conftest import plain_dummy_env, plain_dum
class SubversionServerCreator(object):
root = '/tmp/repo/path/'
svn_path = '/usr/local/bin/svnserve'
+
config_data = {
'app:main': {
'ssh.executable.svn': svn_path,
'vcs.hooks.protocol.v2': 'celery',
+ 'app.service_api.host': 'http://localhost',
+ 'app.service_api.token': 'secret4',
+ 'rhodecode.api.url': '/_admin/api',
}
}
repo_name = 'test-svn'
user = plain_dummy_user()
- def __init__(self):
- pass
+ def __init__(self, service_api_url, ini_file):
+ self.service_api_url = service_api_url
+ self.ini_file = ini_file
def create(self, **kwargs):
+ self.config_data['app:main']['app.service_api.host'] = self.service_api_url
parameters = {
'store': self.root,
- 'repo_name': self.repo_name,
- 'ini_path': '',
+ 'ini_path': self.ini_file,
'user': self.user,
+ 'repo_name': self.repo_name,
'user_permissions': {
self.repo_name: 'repository.admin'
},
'settings': self.config_data['app:main'],
'env': plain_dummy_env()
}
-
parameters.update(kwargs)
server = SubversionServer(**parameters)
return server
-@pytest.fixture()
-def svn_server(app):
- return SubversionServerCreator()
+@pytest.fixture(scope='module')
+def svn_server(request, module_app, rhodecode_factory, available_port_factory):
+ ini_file = module_app._pyramid_settings['__file__']
+ vcsserver_host = module_app._pyramid_settings['vcs.server']
+
+ store_dir = os.path.dirname(ini_file)
+
+ # start rhodecode for service API
+ rc = rhodecode_factory(
+ request,
+ store_dir=store_dir,
+ port=available_port_factory(),
+ overrides=(
+ {'handler_console': {'level': 'DEBUG'}},
+ {'app:main': {'vcs.server': vcsserver_host}},
+ {'app:main': {'repo_store.path': store_dir}}
+ ))
+
+ service_api_url = f'http://{rc.bind_addr}'
+
+ return SubversionServerCreator(service_api_url, ini_file)
class TestSubversionServer(object):
@@ -168,8 +193,9 @@ class TestSubversionServer(object):
assert repo_name == expected_match
def test_run_returns_executes_command(self, svn_server):
- server = svn_server.create()
from rhodecode.apps.ssh_support.lib.backends.svn import SubversionTunnelWrapper
+
+ server = svn_server.create()
os.environ['SSH_CLIENT'] = '127.0.0.1'
with mock.patch.object(
SubversionTunnelWrapper, 'get_first_client_response',
@@ -184,20 +210,18 @@ class TestSubversionServer(object):
SubversionTunnelWrapper, 'command',
return_value=['date']):
- exit_code = server.run()
+ exit_code = server.run(tunnel_extras={'config': server.ini_path})
# SVN has this differently configured, and we get in our mock env
# None as return code
assert exit_code == (None, False)
def test_run_returns_executes_command_that_cannot_extract_repo_name(self, svn_server):
- server = svn_server.create()
from rhodecode.apps.ssh_support.lib.backends.svn import SubversionTunnelWrapper
- with mock.patch.object(
- SubversionTunnelWrapper, 'command',
- return_value=['date']):
- with mock.patch.object(
- SubversionTunnelWrapper, 'get_first_client_response',
+
+ server = svn_server.create()
+ with mock.patch.object(SubversionTunnelWrapper, 'command', return_value=['date']):
+ with mock.patch.object(SubversionTunnelWrapper, 'get_first_client_response',
return_value=None):
- exit_code = server.run()
+ exit_code = server.run(tunnel_extras={'config': server.ini_path})
assert exit_code == (1, False)
diff --git a/rhodecode/apps/user_group/tests/test_user_groups.py b/rhodecode/apps/user_group/tests/test_user_groups.py
index b2b5cae4..5d5fd018 100644
--- a/rhodecode/apps/user_group/tests/test_user_groups.py
+++ b/rhodecode/apps/user_group/tests/test_user_groups.py
@@ -22,7 +22,7 @@ from rhodecode.tests import (
TestController, assert_session_flash, TEST_USER_ADMIN_LOGIN)
from rhodecode.model.db import UserGroup
from rhodecode.model.meta import Session
-from rhodecode.tests.fixture import Fixture
+from rhodecode.tests.fixtures.rc_fixture import Fixture
from rhodecode.tests.routes import route_path
fixture = Fixture()
diff --git a/rhodecode/apps/user_group_profile/tests/test_user_group.py b/rhodecode/apps/user_group_profile/tests/test_user_group.py
index 51096e70..4740375f 100644
--- a/rhodecode/apps/user_group_profile/tests/test_user_group.py
+++ b/rhodecode/apps/user_group_profile/tests/test_user_group.py
@@ -18,7 +18,7 @@
from rhodecode.model.user_group import UserGroupModel
from rhodecode.tests import (
TestController, TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS)
-from rhodecode.tests.fixture import Fixture
+from rhodecode.tests.fixtures.rc_fixture import Fixture
from rhodecode.tests.routes import route_path
fixture = Fixture()
diff --git a/rhodecode/apps/user_profile/tests/test_users.py b/rhodecode/apps/user_profile/tests/test_users.py
index c471adef..79b348c7 100644
--- a/rhodecode/apps/user_profile/tests/test_users.py
+++ b/rhodecode/apps/user_profile/tests/test_users.py
@@ -22,7 +22,7 @@ from rhodecode.model.db import User
from rhodecode.tests import (
TestController, TEST_USER_ADMIN_LOGIN, TEST_USER_ADMIN_PASS,
TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS)
-from rhodecode.tests.fixture import Fixture
+from rhodecode.tests.fixtures.rc_fixture import Fixture
from rhodecode.tests.utils import AssertResponse
from rhodecode.tests.routes import route_path
diff --git a/rhodecode/config/environment.py b/rhodecode/config/environment.py
index 1c699e65..acc2a76f 100644
--- a/rhodecode/config/environment.py
+++ b/rhodecode/config/environment.py
@@ -30,7 +30,7 @@ from rhodecode.lib.vcs import connect_vcs
log = logging.getLogger(__name__)
-def propagate_rhodecode_config(global_config, settings, config):
+def propagate_rhodecode_config(global_config, settings, config, full=True):
# Store the settings to make them available to other modules.
settings_merged = global_config.copy()
settings_merged.update(settings)
@@ -40,7 +40,7 @@ def propagate_rhodecode_config(global_config, settings, config):
rhodecode.PYRAMID_SETTINGS = settings_merged
rhodecode.CONFIG = settings_merged
- if 'default_user_id' not in rhodecode.CONFIG:
+ if full and 'default_user_id' not in rhodecode.CONFIG:
rhodecode.CONFIG['default_user_id'] = utils.get_default_user_id()
log.debug('set rhodecode.CONFIG data')
@@ -93,6 +93,7 @@ def load_pyramid_environment(global_config, settings):
# first run, to store data...
propagate_rhodecode_config(global_config, settings, {})
+
if vcs_server_enabled:
connect_vcs(vcs_server_uri, utils.get_vcs_server_protocol(settings))
else:
diff --git a/rhodecode/config/middleware.py b/rhodecode/config/middleware.py
index c82395cd..8e34137c 100644
--- a/rhodecode/config/middleware.py
+++ b/rhodecode/config/middleware.py
@@ -101,6 +101,9 @@ def make_pyramid_app(global_config, **settings):
patches.inspect_getargspec()
patches.repoze_sendmail_lf_fix()
+ # first init, so load_pyramid_enviroment, can access some critical data, like __file__
+ propagate_rhodecode_config(global_config, {}, {}, full=False)
+
load_pyramid_environment(global_config, settings)
# Static file view comes first
diff --git a/rhodecode/config/rcextensions/__init__.py b/rhodecode/config/rcextensions/__init__.py
index a4b661c4..ddb69559 100644
--- a/rhodecode/config/rcextensions/__init__.py
+++ b/rhodecode/config/rcextensions/__init__.py
@@ -17,7 +17,7 @@
# and proprietary license terms, please see https://rhodecode.com/licenses/
"""
-rcextensions module, please edit `hooks.py` to over write hooks logic
+rcextensions module, please edit `hooks.py` to over-write hooks logic
"""
from .hooks import (
diff --git a/rhodecode/config/rcextensions/examples/validate_pushed_files_name_and_size.py b/rhodecode/config/rcextensions/examples/validate_pushed_files_name_and_size.py
index 1631291c..fbf1d72e 100644
--- a/rhodecode/config/rcextensions/examples/validate_pushed_files_name_and_size.py
+++ b/rhodecode/config/rcextensions/examples/validate_pushed_files_name_and_size.py
@@ -85,7 +85,7 @@ def _pre_push_hook(*args, **kwargs):
# check files names
if forbidden_files:
- reason = 'File {} is forbidden to be pushed'.format(file_name)
+ reason = f'File {file_name} is forbidden to be pushed'
for forbidden_pattern in forbid_files:
# here we can also filter for operation, e.g if check for only ADDED files
# if operation == 'A':
diff --git a/rhodecode/config/rcextensions/helpers/extra_fields.py b/rhodecode/config/rcextensions/helpers/extra_fields.py
index 093de20d..3bf746d2 100644
--- a/rhodecode/config/rcextensions/helpers/extra_fields.py
+++ b/rhodecode/config/rcextensions/helpers/extra_fields.py
@@ -1,4 +1,3 @@
-
# Copyright (C) 2016-2023 RhodeCode GmbH
#
# This program is free software: you can redistribute it and/or modify
@@ -55,7 +54,7 @@ def run(*args, **kwargs):
return fields
-class _Undefined(object):
+class _Undefined:
pass
@@ -67,7 +66,7 @@ def get_field(extra_fields_data, key, default=_Undefined(), convert_type=True):
if key not in extra_fields_data:
if isinstance(default, _Undefined):
- raise ValueError('key {} not present in extra_fields'.format(key))
+ raise ValueError(f'key {key} not present in extra_fields')
return default
# NOTE(dan): from metadata we get field_label, field_value, field_desc, field_type
diff --git a/rhodecode/config/rcextensions/helpers/extract_post_commits.py b/rhodecode/config/rcextensions/helpers/extract_post_commits.py
index 84ca7e69..9b2d0d9f 100644
--- a/rhodecode/config/rcextensions/helpers/extract_post_commits.py
+++ b/rhodecode/config/rcextensions/helpers/extract_post_commits.py
@@ -1,4 +1,3 @@
-
# Copyright (C) 2016-2023 RhodeCode GmbH
#
# This program is free software: you can redistribute it and/or modify
diff --git a/rhodecode/config/rcextensions/helpers/extract_pre_commits.py b/rhodecode/config/rcextensions/helpers/extract_pre_commits.py
index b2c1df2b..40702027 100644
--- a/rhodecode/config/rcextensions/helpers/extract_pre_commits.py
+++ b/rhodecode/config/rcextensions/helpers/extract_pre_commits.py
@@ -1,4 +1,3 @@
-
# Copyright (C) 2016-2023 RhodeCode GmbH
#
# This program is free software: you can redistribute it and/or modify
@@ -52,7 +51,7 @@ def get_git_commits(repo, refs):
cmd = [
'log',
'--pretty=format:{"commit_id": "%H", "author": "%aN <%aE>", "date": "%ad", "message": "%s"}',
- '{}...{}'.format(old_rev, new_rev)
+ f'{old_rev}...{new_rev}'
]
stdout, stderr = repo.run_git_command(cmd, extra_env=git_env)
@@ -80,12 +79,12 @@ def run(*args, **kwargs):
if vcs_type == 'git':
for rev_data in kwargs['commit_ids']:
- new_environ = dict((k, v) for k, v in rev_data['git_env'])
+ new_environ = {k: v for k, v in rev_data['git_env']}
commits = get_git_commits(vcs_repo, kwargs['commit_ids'])
if vcs_type == 'hg':
for rev_data in kwargs['commit_ids']:
- new_environ = dict((k, v) for k, v in rev_data['hg_env'])
+ new_environ = {k: v for k, v in rev_data['hg_env']}
commits = get_hg_commits(vcs_repo, kwargs['commit_ids'])
return commits
diff --git a/rhodecode/config/rcextensions/helpers/extract_pre_files.py b/rhodecode/config/rcextensions/helpers/extract_pre_files.py
index 3d517165..9eb625c8 100644
--- a/rhodecode/config/rcextensions/helpers/extract_pre_files.py
+++ b/rhodecode/config/rcextensions/helpers/extract_pre_files.py
@@ -1,4 +1,3 @@
-
# Copyright (C) 2016-2023 RhodeCode GmbH
#
# This program is free software: you can redistribute it and/or modify
@@ -133,12 +132,12 @@ def run(*args, **kwargs):
if vcs_type == 'git':
for rev_data in kwargs['commit_ids']:
- new_environ = dict((k, v) for k, v in rev_data['git_env'])
+ new_environ = {k: v for k, v in rev_data['git_env']}
files = get_git_files(repo, vcs_repo, kwargs['commit_ids'])
if vcs_type == 'hg':
for rev_data in kwargs['commit_ids']:
- new_environ = dict((k, v) for k, v in rev_data['hg_env'])
+ new_environ = {k: v for k, v in rev_data['hg_env']}
files = get_hg_files(repo, vcs_repo, kwargs['commit_ids'])
if vcs_type == 'svn':
diff --git a/rhodecode/config/rcextensions/helpers/http_call.py b/rhodecode/config/rcextensions/helpers/http_call.py
index 0bbe2434..b06dd9a0 100644
--- a/rhodecode/config/rcextensions/helpers/http_call.py
+++ b/rhodecode/config/rcextensions/helpers/http_call.py
@@ -1,4 +1,3 @@
-
# Copyright (C) 2016-2023 RhodeCode GmbH
#
# This program is free software: you can redistribute it and/or modify
diff --git a/rhodecode/config/rcextensions/utils.py b/rhodecode/config/rcextensions/utils.py
index 2f31a873..d7f4b48d 100644
--- a/rhodecode/config/rcextensions/utils.py
+++ b/rhodecode/config/rcextensions/utils.py
@@ -28,7 +28,7 @@ import urllib.error
log = logging.getLogger('rhodecode.' + __name__)
-class HookResponse(object):
+class HookResponse:
def __init__(self, status, output):
self.status = status
self.output = output
@@ -44,6 +44,11 @@ class HookResponse(object):
def __bool__(self):
return self.status == 0
+ def to_json(self):
+ return {'status': self.status, 'output': self.output}
+
+ def __repr__(self):
+ return self.to_json().__repr__()
class DotDict(dict):
@@ -91,8 +96,8 @@ class DotDict(dict):
def __repr__(self):
keys = list(self.keys())
keys.sort()
- args = ', '.join(['%s=%r' % (key, self[key]) for key in keys])
- return '%s(%s)' % (self.__class__.__name__, args)
+ args = ', '.join(['{}={!r}'.format(key, self[key]) for key in keys])
+ return '{}({})'.format(self.__class__.__name__, args)
@staticmethod
def fromDict(d):
@@ -110,7 +115,7 @@ def serialize(x):
def unserialize(x):
if isinstance(x, dict):
- return dict((k, unserialize(v)) for k, v in x.items())
+ return {k: unserialize(v) for k, v in x.items()}
elif isinstance(x, (list, tuple)):
return type(x)(unserialize(v) for v in x)
else:
@@ -161,7 +166,8 @@ def str2bool(_str) -> bool:
string into boolean
:param _str: string value to translate into boolean
- :returns: bool from given string
+ :rtype: boolean
+ :returns: boolean from given string
"""
if _str is None:
return False
diff --git a/rhodecode/config/routing_links.py b/rhodecode/config/routing_links.py
index 4a782b15..6a569383 100644
--- a/rhodecode/config/routing_links.py
+++ b/rhodecode/config/routing_links.py
@@ -49,22 +49,22 @@ link_config = [
{
"name": "enterprise_docs",
"target": "https://rhodecode.com/r1/enterprise/docs/",
- "external_target": "https://docs.rhodecode.com/RhodeCode-Enterprise/",
+ "external_target": "https://docs.rhodecode.com/4.x/rce/index.html",
},
{
"name": "enterprise_log_file_locations",
"target": "https://rhodecode.com/r1/enterprise/docs/admin-system-overview/",
- "external_target": "https://docs.rhodecode.com/RhodeCode-Enterprise/admin/system-overview.html#log-files",
+ "external_target": "https://docs.rhodecode.com/4.x/rce/admin/system-overview.html#log-files",
},
{
"name": "enterprise_issue_tracker_settings",
"target": "https://rhodecode.com/r1/enterprise/docs/issue-trackers-overview/",
- "external_target": "https://docs.rhodecode.com/RhodeCode-Enterprise/issue-trackers/issue-trackers.html",
+ "external_target": "https://docs.rhodecode.com/4.x/rce/issue-trackers/issue-trackers.html",
},
{
"name": "enterprise_svn_setup",
"target": "https://rhodecode.com/r1/enterprise/docs/svn-setup/",
- "external_target": "https://docs.rhodecode.com/RhodeCode-Enterprise/admin/svn-http.html",
+ "external_target": "https://docs.rhodecode.com/4.x/rce/admin/svn-http.html",
},
{
"name": "enterprise_license_convert_from_old",
diff --git a/rhodecode/config/utils.py b/rhodecode/config/utils.py
index 17236b25..e3d48d1c 100644
--- a/rhodecode/config/utils.py
+++ b/rhodecode/config/utils.py
@@ -19,6 +19,8 @@
import os
import platform
+from rhodecode.lib.type_utils import str2bool
+
DEFAULT_USER = 'default'
@@ -48,28 +50,23 @@ def initialize_database(config):
engine = engine_from_config(config, 'sqlalchemy.db1.')
init_model(engine, encryption_key=get_encryption_key(config))
+def initialize_test_environment(settings):
+ skip_test_env = str2bool(os.environ.get('RC_NO_TEST_ENV'))
+ if skip_test_env:
+ return
-def initialize_test_environment(settings, test_env=None):
- if test_env is None:
- test_env = not int(os.environ.get('RC_NO_TMP_PATH', 0))
+ repo_store_path = os.environ.get('RC_TEST_ENV_REPO_STORE') or settings['repo_store.path']
from rhodecode.lib.utils import (
create_test_directory, create_test_database, create_test_repositories,
create_test_index)
- from rhodecode.tests import TESTS_TMP_PATH
- from rhodecode.lib.vcs.backends.hg import largefiles_store
- from rhodecode.lib.vcs.backends.git import lfs_store
+ create_test_directory(repo_store_path)
+
+ create_test_database(repo_store_path, settings)
# test repos
- if test_env:
- create_test_directory(TESTS_TMP_PATH)
- # large object stores
- create_test_directory(largefiles_store(TESTS_TMP_PATH))
- create_test_directory(lfs_store(TESTS_TMP_PATH))
-
- create_test_database(TESTS_TMP_PATH, settings)
- create_test_repositories(TESTS_TMP_PATH, settings)
- create_test_index(TESTS_TMP_PATH, settings)
+ create_test_repositories(repo_store_path, settings)
+ create_test_index(repo_store_path, settings)
def get_vcs_server_protocol(config):
diff --git a/rhodecode/lib/exceptions.py b/rhodecode/lib/exceptions.py
index d4cd6c17..301e629f 100644
--- a/rhodecode/lib/exceptions.py
+++ b/rhodecode/lib/exceptions.py
@@ -20,8 +20,7 @@
Set of custom exceptions used in RhodeCode
"""
-from webob.exc import HTTPClientError
-from pyramid.httpexceptions import HTTPBadGateway
+from pyramid.httpexceptions import HTTPBadGateway, HTTPClientError
class LdapUsernameError(Exception):
@@ -102,12 +101,7 @@ class HTTPRequirementError(HTTPClientError):
self.args = (message, )
-class ClientNotSupportedError(HTTPRequirementError):
- title = explanation = 'Client Not Supported'
- reason = None
-
-
-class HTTPLockedRC(HTTPClientError):
+class HTTPLockedRepo(HTTPClientError):
"""
Special Exception For locked Repos in RhodeCode, the return code can
be overwritten by _code keyword argument passed into constructors
@@ -131,14 +125,13 @@ class HTTPBranchProtected(HTTPClientError):
Special Exception For Indicating that branch is protected in RhodeCode, the
return code can be overwritten by _code keyword argument passed into constructors
"""
- code = 403
title = explanation = 'Branch Protected'
reason = None
- def __init__(self, message, *args, **kwargs):
- self.title = self.explanation = message
- super().__init__(*args, **kwargs)
- self.args = (message, )
+
+class ClientNotSupported(HTTPRequirementError):
+ title = explanation = 'Client Not Supported'
+ reason = None
class IMCCommitError(Exception):
diff --git a/rhodecode/lib/hook_daemon/base.py b/rhodecode/lib/hook_daemon/base.py
index 705926f4..d0629edb 100644
--- a/rhodecode/lib/hook_daemon/base.py
+++ b/rhodecode/lib/hook_daemon/base.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2010-2023 RhodeCode GmbH
+# 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
@@ -16,13 +16,14 @@
# RhodeCode Enterprise Edition, including its added features, Support services,
# and proprietary license terms, please see https://rhodecode.com/licenses/
-import os
-import time
import logging
+import traceback
-from rhodecode.lib.config_utils import get_app_config_lightweight
+from rhodecode.model import meta
+from rhodecode.lib import hooks_base
+from rhodecode.lib.utils2 import AttributeDict
+from rhodecode.lib.exceptions import HTTPLockedRepo, HTTPBranchProtected
-from rhodecode.lib.svn_txn_utils import get_txn_id_from_store
log = logging.getLogger(__name__)
@@ -42,53 +43,82 @@ class BaseHooksCallbackDaemon:
log.debug('Exiting `%s` callback daemon', self.__class__.__name__)
-class HooksModuleCallbackDaemon(BaseHooksCallbackDaemon):
+class Hooks(object):
+ """
+ Exposes the hooks module for calling them using the local HooksModuleCallbackDaemon
+ """
+ def __init__(self, request=None, log_prefix=''):
+ self.log_prefix = log_prefix
+ self.request = request
- def __init__(self, module):
- super().__init__()
- self.hooks_module = module
+ def repo_size(self, extras):
+ log.debug("%sCalled repo_size of %s object", self.log_prefix, self)
+ return self._call_hook(hooks_base.repo_size, extras)
- def __repr__(self):
- return f'HooksModuleCallbackDaemon(hooks_module={self.hooks_module})'
+ def pre_pull(self, extras):
+ log.debug("%sCalled pre_pull of %s object", self.log_prefix, self)
+ return self._call_hook(hooks_base.pre_pull, extras)
+ def post_pull(self, extras):
+ log.debug("%sCalled post_pull of %s object", self.log_prefix, self)
+ return self._call_hook(hooks_base.post_pull, extras)
-def prepare_callback_daemon(extras, protocol, host, txn_id=None):
+ def pre_push(self, extras):
+ log.debug("%sCalled pre_push of %s object", self.log_prefix, self)
+ return self._call_hook(hooks_base.pre_push, extras)
- match protocol:
- case 'http':
- from rhodecode.lib.hook_daemon.http_hooks_deamon import HttpHooksCallbackDaemon
- port = 0
- if txn_id:
- # read txn-id to re-use the PORT for callback daemon
- repo_path = os.path.join(extras['repo_store'], extras['repository'])
- txn_details = get_txn_id_from_store(repo_path, txn_id)
- port = txn_details.get('port', 0)
+ def post_push(self, extras):
+ log.debug("%sCalled post_push of %s object", self.log_prefix, self)
+ return self._call_hook(hooks_base.post_push, extras)
- callback_daemon = HttpHooksCallbackDaemon(
- txn_id=txn_id, host=host, port=port)
- case 'celery':
- from rhodecode.lib.hook_daemon.celery_hooks_deamon import CeleryHooksCallbackDaemon
+ def _call_hook(self, hook, extras):
+ extras = AttributeDict(extras)
+ _server_url = extras['server_url']
- config = get_app_config_lightweight(extras['config'])
- task_queue = config.get('celery.broker_url')
- task_backend = config.get('celery.result_backend')
+ extras.request = self.request
+ try:
+ result = hook(extras)
+ if result is None:
+ raise Exception(f'Failed to obtain hook result from func: {hook}')
+ except HTTPBranchProtected as error:
+ # Those special cases don't need error reporting. It's a case of
+ # locked repo or protected branch
+ result = AttributeDict({
+ 'status': error.code,
+ 'output': error.explanation
+ })
+ except HTTPLockedRepo as error:
+ # Those special cases don't need error reporting. It's a case of
+ # locked repo or protected branch
+ result = AttributeDict({
+ 'status': error.code,
+ 'output': error.explanation
+ })
+ except Exception as error:
+ # locked needs different handling since we need to also
+ # handle PULL operations
+ log.exception('%sException when handling hook %s', self.log_prefix, hook)
+ exc_tb = traceback.format_exc()
+ error_args = error.args
+ return {
+ 'status': 128,
+ 'output': '',
+ 'exception': type(error).__name__,
+ 'exception_traceback': exc_tb,
+ 'exception_args': error_args,
+ }
+ finally:
+ meta.Session.remove()
- callback_daemon = CeleryHooksCallbackDaemon(task_queue, task_backend)
- case 'local':
- from rhodecode.lib.hook_daemon.hook_module import Hooks
- callback_daemon = HooksModuleCallbackDaemon(Hooks.__module__)
- case _:
- log.error('Unsupported callback daemon protocol "%s"', protocol)
- raise Exception('Unsupported callback daemon protocol.')
+ log.debug('%sGot hook call response %s', self.log_prefix, result)
+ return {
+ 'status': result.status,
+ 'output': result.output,
+ }
- extras['hooks_uri'] = getattr(callback_daemon, 'hooks_uri', '')
- extras['task_queue'] = getattr(callback_daemon, 'task_queue', '')
- extras['task_backend'] = getattr(callback_daemon, 'task_backend', '')
- extras['hooks_protocol'] = protocol
- extras['time'] = time.time()
+ def __enter__(self):
+ return self
+
+ def __exit__(self, exc_type, exc_val, exc_tb):
+ pass
- # register txn_id
- extras['txn_id'] = txn_id
- log.debug('Prepared a callback daemon: %s',
- callback_daemon.__class__.__name__)
- return callback_daemon, extras
diff --git a/rhodecode/lib/hook_daemon/celery_hooks_deamon.py b/rhodecode/lib/hook_daemon/celery_hooks_deamon.py
index 245a6bf3..fc67b3cb 100644
--- a/rhodecode/lib/hook_daemon/celery_hooks_deamon.py
+++ b/rhodecode/lib/hook_daemon/celery_hooks_deamon.py
@@ -22,14 +22,16 @@ from rhodecode.lib.hook_daemon.base import BaseHooksCallbackDaemon
class CeleryHooksCallbackDaemon(BaseHooksCallbackDaemon):
"""
Context manger for achieving a compatibility with celery backend
+ It is calling a call to vcsserver, where it uses HooksCeleryClient to actually call a task from
+
+ f'rhodecode.lib.celerylib.tasks.{method}'
+
"""
- def __init__(self, task_queue, task_backend):
- self.task_queue = task_queue
- self.task_backend = task_backend
+ def __init__(self, broker_url, result_backend):
+ super().__init__()
+ self.broker_url = broker_url
+ self.result_backend = result_backend
def __repr__(self):
- return f'CeleryHooksCallbackDaemon(task_queue={self.task_queue}, task_backend={self.task_backend})'
-
- def __repr__(self):
- return f'CeleryHooksCallbackDaemon(task_queue={self.task_queue}, task_backend={self.task_backend})'
+ return f'CeleryHooksCallbackDaemon(broker_url={self.broker_url}, result_backend={self.result_backend})'
diff --git a/rhodecode/lib/hook_daemon/hook_module.py b/rhodecode/lib/hook_daemon/hook_module.py
index c6e88c0b..1a7e90e0 100644
--- a/rhodecode/lib/hook_daemon/hook_module.py
+++ b/rhodecode/lib/hook_daemon/hook_module.py
@@ -17,88 +17,18 @@
# and proprietary license terms, please see https://rhodecode.com/licenses/
import logging
-import traceback
-from rhodecode.model import meta
-
-from rhodecode.lib import hooks_base
-from rhodecode.lib.exceptions import HTTPLockedRC, HTTPBranchProtected
-from rhodecode.lib.utils2 import AttributeDict
+from rhodecode.lib.hook_daemon.base import BaseHooksCallbackDaemon
log = logging.getLogger(__name__)
-class Hooks(object):
- """
- Exposes the hooks for remote callbacks
- """
- def __init__(self, request=None, log_prefix=''):
- self.log_prefix = log_prefix
- self.request = request
+class HooksModuleCallbackDaemon(BaseHooksCallbackDaemon):
- def repo_size(self, extras):
- log.debug("%sCalled repo_size of %s object", self.log_prefix, self)
- return self._call_hook(hooks_base.repo_size, extras)
+ def __init__(self, module):
+ super().__init__()
+ self.hooks_module = module
- def pre_pull(self, extras):
- log.debug("%sCalled pre_pull of %s object", self.log_prefix, self)
- return self._call_hook(hooks_base.pre_pull, extras)
+ def __repr__(self):
+ return f'HooksModuleCallbackDaemon(hooks_module={self.hooks_module})'
- def post_pull(self, extras):
- log.debug("%sCalled post_pull of %s object", self.log_prefix, self)
- return self._call_hook(hooks_base.post_pull, extras)
-
- def pre_push(self, extras):
- log.debug("%sCalled pre_push of %s object", self.log_prefix, self)
- return self._call_hook(hooks_base.pre_push, extras)
-
- def post_push(self, extras):
- log.debug("%sCalled post_push of %s object", self.log_prefix, self)
- return self._call_hook(hooks_base.post_push, extras)
-
- def _call_hook(self, hook, extras):
- extras = AttributeDict(extras)
- _server_url = extras['server_url']
-
- extras.request = self.request
-
- try:
- result = hook(extras)
- if result is None:
- raise Exception(f'Failed to obtain hook result from func: {hook}')
- except HTTPBranchProtected as error:
- # Those special cases don't need error reporting. It's a case of
- # locked repo or protected branch
- result = AttributeDict({
- 'status': error.code,
- 'output': error.explanation
- })
- except (HTTPLockedRC, Exception) as error:
- # locked needs different handling since we need to also
- # handle PULL operations
- exc_tb = ''
- if not isinstance(error, HTTPLockedRC):
- exc_tb = traceback.format_exc()
- log.exception('%sException when handling hook %s', self.log_prefix, hook)
- error_args = error.args
- return {
- 'status': 128,
- 'output': '',
- 'exception': type(error).__name__,
- 'exception_traceback': exc_tb,
- 'exception_args': error_args,
- }
- finally:
- meta.Session.remove()
-
- log.debug('%sGot hook call response %s', self.log_prefix, result)
- return {
- 'status': result.status,
- 'output': result.output,
- }
-
- def __enter__(self):
- return self
-
- def __exit__(self, exc_type, exc_val, exc_tb):
- pass
diff --git a/rhodecode/lib/hook_daemon/http_hooks_deamon.py b/rhodecode/lib/hook_daemon/http_hooks_deamon.py
deleted file mode 100644
index bc86d0cb..00000000
--- a/rhodecode/lib/hook_daemon/http_hooks_deamon.py
+++ /dev/null
@@ -1,287 +0,0 @@
-# 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 .
-#
-# 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 os
-import logging
-import traceback
-import threading
-import socket
-import msgpack
-import gevent
-
-from http.server import BaseHTTPRequestHandler
-from socketserver import TCPServer
-
-from rhodecode.model import meta
-from rhodecode.lib.ext_json import json
-from rhodecode.lib import rc_cache
-from rhodecode.lib.svn_txn_utils import get_txn_id_data_key
-from rhodecode.lib.hook_daemon.hook_module import Hooks
-
-log = logging.getLogger(__name__)
-
-
-class HooksHttpHandler(BaseHTTPRequestHandler):
-
- JSON_HOOKS_PROTO = 'json.v1'
- MSGPACK_HOOKS_PROTO = 'msgpack.v1'
- # starting with RhodeCode 5.0.0 MsgPack is the default, prior it used json
- DEFAULT_HOOKS_PROTO = MSGPACK_HOOKS_PROTO
-
- @classmethod
- def serialize_data(cls, data, proto=DEFAULT_HOOKS_PROTO):
- if proto == cls.MSGPACK_HOOKS_PROTO:
- return msgpack.packb(data)
- return json.dumps(data)
-
- @classmethod
- def deserialize_data(cls, data, proto=DEFAULT_HOOKS_PROTO):
- if proto == cls.MSGPACK_HOOKS_PROTO:
- return msgpack.unpackb(data)
- return json.loads(data)
-
- def do_POST(self):
- hooks_proto, method, extras = self._read_request()
- log.debug('Handling HooksHttpHandler %s with %s proto', method, hooks_proto)
-
- txn_id = getattr(self.server, 'txn_id', None)
- if txn_id:
- log.debug('Computing TXN_ID based on `%s`:`%s`',
- extras['repository'], extras['txn_id'])
- computed_txn_id = rc_cache.utils.compute_key_from_params(
- extras['repository'], extras['txn_id'])
- if txn_id != computed_txn_id:
- raise Exception(
- 'TXN ID fail: expected {} got {} instead'.format(
- txn_id, computed_txn_id))
-
- request = getattr(self.server, 'request', None)
- try:
- hooks = Hooks(request=request, log_prefix='HOOKS: {} '.format(self.server.server_address))
- result = self._call_hook_method(hooks, method, extras)
-
- except Exception as e:
- exc_tb = traceback.format_exc()
- result = {
- 'exception': e.__class__.__name__,
- 'exception_traceback': exc_tb,
- 'exception_args': e.args
- }
- self._write_response(hooks_proto, result)
-
- def _read_request(self):
- length = int(self.headers['Content-Length'])
- # respect sent headers, fallback to OLD proto for compatability
- hooks_proto = self.headers.get('rc-hooks-protocol') or self.JSON_HOOKS_PROTO
- if hooks_proto == self.MSGPACK_HOOKS_PROTO:
- # support for new vcsserver msgpack based protocol hooks
- body = self.rfile.read(length)
- data = self.deserialize_data(body)
- else:
- body = self.rfile.read(length)
- data = self.deserialize_data(body)
-
- return hooks_proto, data['method'], data['extras']
-
- def _write_response(self, hooks_proto, result):
- self.send_response(200)
- if hooks_proto == self.MSGPACK_HOOKS_PROTO:
- self.send_header("Content-type", "application/msgpack")
- self.end_headers()
- data = self.serialize_data(result)
- self.wfile.write(data)
- else:
- self.send_header("Content-type", "text/json")
- self.end_headers()
- data = self.serialize_data(result)
- self.wfile.write(data)
-
- def _call_hook_method(self, hooks, method, extras):
- try:
- result = getattr(hooks, method)(extras)
- finally:
- meta.Session.remove()
- return result
-
- def log_message(self, format, *args):
- """
- This is an overridden method of BaseHTTPRequestHandler which logs using
- a logging library instead of writing directly to stderr.
- """
-
- message = format % args
-
- log.debug(
- "HOOKS: client=%s - - [%s] %s", self.client_address,
- self.log_date_time_string(), message)
-
-
-class ThreadedHookCallbackDaemon(object):
-
- _callback_thread = None
- _daemon = None
- _done = False
- use_gevent = False
-
- def __init__(self, txn_id=None, host=None, port=None):
- self._prepare(txn_id=txn_id, host=host, port=port)
- if self.use_gevent:
- self._run_func = self._run_gevent
- self._stop_func = self._stop_gevent
- else:
- self._run_func = self._run
- self._stop_func = self._stop
-
- def __enter__(self):
- log.debug('Running `%s` callback daemon', self.__class__.__name__)
- self._run_func()
- return self
-
- def __exit__(self, exc_type, exc_val, exc_tb):
- log.debug('Exiting `%s` callback daemon', self.__class__.__name__)
- self._stop_func()
-
- def _prepare(self, txn_id=None, host=None, port=None):
- raise NotImplementedError()
-
- def _run(self):
- raise NotImplementedError()
-
- def _stop(self):
- raise NotImplementedError()
-
- def _run_gevent(self):
- raise NotImplementedError()
-
- def _stop_gevent(self):
- raise NotImplementedError()
-
-
-class HttpHooksCallbackDaemon(ThreadedHookCallbackDaemon):
- """
- Context manager which will run a callback daemon in a background thread.
- """
-
- hooks_uri = None
-
- # From Python docs: Polling reduces our responsiveness to a shutdown
- # request and wastes cpu at all other times.
- POLL_INTERVAL = 0.01
-
- use_gevent = False
-
- def __repr__(self):
- return f'HttpHooksCallbackDaemon(hooks_uri={self.hooks_uri})'
-
- @property
- def _hook_prefix(self):
- return f'HOOKS: {self.hooks_uri} '
-
- def get_hostname(self):
- return socket.gethostname() or '127.0.0.1'
-
- def get_available_port(self, min_port=20000, max_port=65535):
- from rhodecode.lib.utils2 import get_available_port as _get_port
- return _get_port(min_port, max_port)
-
- def _prepare(self, txn_id=None, host=None, port=None):
- from pyramid.threadlocal import get_current_request
-
- if not host or host == "*":
- host = self.get_hostname()
- if not port:
- port = self.get_available_port()
-
- server_address = (host, port)
- self.hooks_uri = f'{host}:{port}'
- self.txn_id = txn_id
- self._done = False
-
- log.debug(
- "%s Preparing HTTP callback daemon registering hook object: %s",
- self._hook_prefix, HooksHttpHandler)
-
- self._daemon = TCPServer(server_address, HooksHttpHandler)
- # inject transaction_id for later verification
- self._daemon.txn_id = self.txn_id
-
- # pass the WEB app request into daemon
- self._daemon.request = get_current_request()
-
- def _run(self):
- log.debug("Running thread-based loop of callback daemon in background")
- callback_thread = threading.Thread(
- target=self._daemon.serve_forever,
- kwargs={'poll_interval': self.POLL_INTERVAL})
- callback_thread.daemon = True
- callback_thread.start()
- self._callback_thread = callback_thread
-
- def _run_gevent(self):
- log.debug("Running gevent-based loop of callback daemon in background")
- # create a new greenlet for the daemon's serve_forever method
- callback_greenlet = gevent.spawn(
- self._daemon.serve_forever,
- poll_interval=self.POLL_INTERVAL)
-
- # store reference to greenlet
- self._callback_greenlet = callback_greenlet
-
- # switch to this greenlet
- gevent.sleep(0.01)
-
- def _stop(self):
- log.debug("Waiting for background thread to finish.")
- self._daemon.shutdown()
- self._callback_thread.join()
- self._daemon = None
- self._callback_thread = None
- if self.txn_id:
- #TODO: figure out the repo_path...
- repo_path = ''
- txn_id_file = get_txn_id_data_key(repo_path, self.txn_id)
- log.debug('Cleaning up TXN ID %s', txn_id_file)
- if os.path.isfile(txn_id_file):
- os.remove(txn_id_file)
-
- log.debug("Background thread done.")
-
- def _stop_gevent(self):
- log.debug("Waiting for background greenlet to finish.")
-
- # if greenlet exists and is running
- if self._callback_greenlet and not self._callback_greenlet.dead:
- # shutdown daemon if it exists
- if self._daemon:
- self._daemon.shutdown()
-
- # kill the greenlet
- self._callback_greenlet.kill()
-
- self._daemon = None
- self._callback_greenlet = None
-
- if self.txn_id:
- #TODO: figure out the repo_path...
- repo_path = ''
- txn_id_file = get_txn_id_data_key(repo_path, self.txn_id)
- log.debug('Cleaning up TXN ID %s', txn_id_file)
- if os.path.isfile(txn_id_file):
- os.remove(txn_id_file)
-
- log.debug("Background greenlet done.")
diff --git a/rhodecode/lib/hook_daemon/utils.py b/rhodecode/lib/hook_daemon/utils.py
new file mode 100644
index 00000000..b2938e21
--- /dev/null
+++ b/rhodecode/lib/hook_daemon/utils.py
@@ -0,0 +1,61 @@
+# 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 time
+import logging
+
+from rhodecode.lib.config_utils import get_app_config_lightweight
+
+from rhodecode.lib.hook_daemon.base import Hooks
+from rhodecode.lib.hook_daemon.hook_module import HooksModuleCallbackDaemon
+from rhodecode.lib.hook_daemon.celery_hooks_deamon import CeleryHooksCallbackDaemon
+from rhodecode.lib.type_utils import str2bool
+
+log = logging.getLogger(__name__)
+
+
+
+def prepare_callback_daemon(extras, protocol: str, txn_id=None):
+ hooks_config = {}
+ match protocol:
+ case 'celery':
+ config = get_app_config_lightweight(extras['config'])
+
+ broker_url = config.get('celery.broker_url')
+ result_backend = config.get('celery.result_backend')
+
+ hooks_config = {
+ 'broker_url': broker_url,
+ 'result_backend': result_backend,
+ }
+
+ callback_daemon = CeleryHooksCallbackDaemon(broker_url, result_backend)
+ case 'local':
+ callback_daemon = HooksModuleCallbackDaemon(Hooks.__module__)
+ case _:
+ log.error('Unsupported callback daemon protocol "%s"', protocol)
+ raise Exception('Unsupported callback daemon protocol.')
+
+ extras['hooks_config'] = hooks_config
+ extras['hooks_protocol'] = protocol
+ extras['time'] = time.time()
+
+ # register txn_id
+ extras['txn_id'] = txn_id
+ log.debug('Prepared a callback daemon: %s', callback_daemon.__class__.__name__)
+ return callback_daemon, extras
diff --git a/rhodecode/lib/hooks_base.py b/rhodecode/lib/hooks_base.py
index 795987cc..c44d5368 100644
--- a/rhodecode/lib/hooks_base.py
+++ b/rhodecode/lib/hooks_base.py
@@ -30,14 +30,14 @@ from rhodecode.lib import helpers as h
from rhodecode.lib import audit_logger
from rhodecode.lib.utils2 import safe_str, user_agent_normalizer
from rhodecode.lib.exceptions import (
- HTTPLockedRC, HTTPBranchProtected, UserCreationError, ClientNotSupportedError)
+ HTTPLockedRepo, HTTPBranchProtected, UserCreationError, ClientNotSupported)
from rhodecode.model.db import Repository, User
from rhodecode.lib.statsd_client import StatsdClient
log = logging.getLogger(__name__)
-class HookResponse(object):
+class HookResponse:
def __init__(self, status, output):
self.status = status
self.output = output
@@ -56,6 +56,8 @@ class HookResponse(object):
def to_json(self):
return {'status': self.status, 'output': self.output}
+ def __repr__(self):
+ return self.to_json().__repr__()
def is_shadow_repo(extras):
"""
@@ -73,8 +75,69 @@ def check_vcs_client(extras):
except ModuleNotFoundError:
is_vcs_client_whitelisted = lambda *x: True
backend = extras.get('scm')
- if not is_vcs_client_whitelisted(extras.get('user_agent'), backend):
- raise ClientNotSupportedError(f"Your {backend} client is forbidden")
+ user_agent = extras.get('user_agent')
+ if not is_vcs_client_whitelisted(user_agent, backend):
+ raise ClientNotSupported(f"Your {backend} client (version={user_agent}) is forbidden by security rules")
+
+
+def check_locked_repo(extras, check_same_user=True):
+ user = User.get_by_username(extras.username)
+ output = ''
+ if extras.locked_by[0] and (not check_same_user or user.user_id != extras.locked_by[0]):
+
+ locked_by = User.get(extras.locked_by[0]).username
+ reason = extras.locked_by[2]
+ # this exception is interpreted in git/hg middlewares and based
+ # on that proper return code is server to client
+ _http_ret = HTTPLockedRepo(_locked_by_explanation(extras.repository, locked_by, reason))
+ if str(_http_ret.code).startswith('2'):
+ # 2xx Codes don't raise exceptions
+ output = _http_ret.title
+ else:
+ raise _http_ret
+
+ return output
+
+
+def check_branch_protected(extras):
+ if extras.commit_ids and extras.check_branch_perms:
+ user = User.get_by_username(extras.username)
+ auth_user = user.AuthUser()
+ repo = Repository.get_by_repo_name(extras.repository)
+ if not repo:
+ raise ValueError(f'Repo for {extras.repository} not found')
+ affected_branches = []
+ if repo.repo_type == 'hg':
+ for entry in extras.commit_ids:
+ if entry['type'] == 'branch':
+ is_forced = bool(entry['multiple_heads'])
+ affected_branches.append([entry['name'], is_forced])
+ elif repo.repo_type == 'git':
+ for entry in extras.commit_ids:
+ if entry['type'] == 'heads':
+ is_forced = bool(entry['pruned_sha'])
+ affected_branches.append([entry['name'], is_forced])
+
+ for branch_name, is_forced in affected_branches:
+
+ rule, branch_perm = auth_user.get_rule_and_branch_permission(extras.repository, branch_name)
+ if not branch_perm:
+ # no branch permission found for this branch, just keep checking
+ continue
+
+ if branch_perm == 'branch.push_force':
+ continue
+ elif branch_perm == 'branch.push' and is_forced is False:
+ continue
+ elif branch_perm == 'branch.push' and is_forced is True:
+ halt_message = f'Branch `{branch_name}` changes rejected by rule {rule}. ' \
+ f'FORCE PUSH FORBIDDEN.'
+ else:
+ halt_message = f'Branch `{branch_name}` changes rejected by rule {rule}.'
+
+ if halt_message:
+ _http_ret = HTTPBranchProtected(halt_message)
+ raise _http_ret
def _get_scm_size(alias, root_path):
@@ -109,116 +172,30 @@ def repo_size(extras):
repo = Repository.get_by_repo_name(extras.repository)
vcs_part = f'.{repo.repo_type}'
size_vcs, size_root, size_total = _get_scm_size(vcs_part, repo.repo_full_path)
- msg = (f'RhodeCode: `{repo.repo_name}` size summary {vcs_part}:{size_vcs} repo:{size_root} total:{size_total}\n')
+ msg = f'RhodeCode: `{repo.repo_name}` size summary {vcs_part}:{size_vcs} repo:{size_root} total:{size_total}\n'
return HookResponse(0, msg)
-def pre_push(extras):
- """
- Hook executed before pushing code.
-
- It bans pushing when the repository is locked.
- """
-
- check_vcs_client(extras)
- user = User.get_by_username(extras.username)
- output = ''
- if extras.locked_by[0] and user.user_id != int(extras.locked_by[0]):
- locked_by = User.get(extras.locked_by[0]).username
- reason = extras.locked_by[2]
- # this exception is interpreted in git/hg middlewares and based
- # on that proper return code is server to client
- _http_ret = HTTPLockedRC(
- _locked_by_explanation(extras.repository, locked_by, reason))
- if str(_http_ret.code).startswith('2'):
- # 2xx Codes don't raise exceptions
- output = _http_ret.title
- else:
- raise _http_ret
-
- hook_response = ''
- if not is_shadow_repo(extras):
-
- if extras.commit_ids and extras.check_branch_perms:
- auth_user = user.AuthUser()
- repo = Repository.get_by_repo_name(extras.repository)
- if not repo:
- raise ValueError(f'Repo for {extras.repository} not found')
- affected_branches = []
- if repo.repo_type == 'hg':
- for entry in extras.commit_ids:
- if entry['type'] == 'branch':
- is_forced = bool(entry['multiple_heads'])
- affected_branches.append([entry['name'], is_forced])
- elif repo.repo_type == 'git':
- for entry in extras.commit_ids:
- if entry['type'] == 'heads':
- is_forced = bool(entry['pruned_sha'])
- affected_branches.append([entry['name'], is_forced])
-
- for branch_name, is_forced in affected_branches:
-
- rule, branch_perm = auth_user.get_rule_and_branch_permission(
- extras.repository, branch_name)
- if not branch_perm:
- # no branch permission found for this branch, just keep checking
- continue
-
- if branch_perm == 'branch.push_force':
- continue
- elif branch_perm == 'branch.push' and is_forced is False:
- continue
- elif branch_perm == 'branch.push' and is_forced is True:
- halt_message = f'Branch `{branch_name}` changes rejected by rule {rule}. ' \
- f'FORCE PUSH FORBIDDEN.'
- else:
- halt_message = f'Branch `{branch_name}` changes rejected by rule {rule}.'
-
- if halt_message:
- _http_ret = HTTPBranchProtected(halt_message)
- raise _http_ret
-
- # Propagate to external components. This is done after checking the
- # lock, for consistent behavior.
- hook_response = pre_push_extension(
- repo_store_path=Repository.base_path(), **extras)
- events.trigger(events.RepoPrePushEvent(
- repo_name=extras.repository, extras=extras))
-
- return HookResponse(0, output) + hook_response
-
-
def pre_pull(extras):
"""
Hook executed before pulling the code.
It bans pulling when the repository is locked.
+ It bans pulling when incorrect client is used.
"""
-
- check_vcs_client(extras)
output = ''
- if extras.locked_by[0]:
- locked_by = User.get(extras.locked_by[0]).username
- reason = extras.locked_by[2]
- # this exception is interpreted in git/hg middlewares and based
- # on that proper return code is server to client
- _http_ret = HTTPLockedRC(
- _locked_by_explanation(extras.repository, locked_by, reason))
- if str(_http_ret.code).startswith('2'):
- # 2xx Codes don't raise exceptions
- output = _http_ret.title
- else:
- raise _http_ret
+ check_vcs_client(extras)
+
+ # locking repo can, but not have to stop the operation it can also just produce output
+ output += check_locked_repo(extras, check_same_user=False)
# Propagate to external components. This is done after checking the
# lock, for consistent behavior.
hook_response = ''
if not is_shadow_repo(extras):
extras.hook_type = extras.hook_type or 'pre_pull'
- hook_response = pre_pull_extension(
- repo_store_path=Repository.base_path(), **extras)
- events.trigger(events.RepoPrePullEvent(
- repo_name=extras.repository, extras=extras))
+ hook_response = pre_pull_extension(repo_store_path=Repository.base_path(), **extras)
+ events.trigger(events.RepoPrePullEvent(repo_name=extras.repository, extras=extras))
return HookResponse(0, output) + hook_response
@@ -239,6 +216,7 @@ def post_pull(extras):
statsd.incr('rhodecode_pull_total', tags=[
f'user-agent:{user_agent_normalizer(extras.user_agent)}',
])
+
output = ''
# make lock is a tri state False, True, None. We only make lock on True
if extras.make_lock is True and not is_shadow_repo(extras):
@@ -246,18 +224,9 @@ def post_pull(extras):
Repository.lock(Repository.get_by_repo_name(extras.repository),
user.user_id,
lock_reason=Repository.LOCK_PULL)
- msg = 'Made lock on repo `{}`'.format(extras.repository)
+ msg = f'Made lock on repo `{extras.repository}`'
output += msg
- if extras.locked_by[0]:
- locked_by = User.get(extras.locked_by[0]).username
- reason = extras.locked_by[2]
- _http_ret = HTTPLockedRC(
- _locked_by_explanation(extras.repository, locked_by, reason))
- if str(_http_ret.code).startswith('2'):
- # 2xx Codes don't raise exceptions
- output += _http_ret.title
-
# Propagate to external components.
hook_response = ''
if not is_shadow_repo(extras):
@@ -270,6 +239,33 @@ def post_pull(extras):
return HookResponse(0, output) + hook_response
+def pre_push(extras):
+ """
+ Hook executed before pushing code.
+
+ It bans pushing when the repository is locked.
+ It banks pushing when incorrect client is used.
+ It also checks for Branch protection
+ """
+ output = ''
+ check_vcs_client(extras)
+
+ # locking repo can, but not have to stop the operation it can also just produce output
+ output += check_locked_repo(extras)
+
+ hook_response = ''
+ if not is_shadow_repo(extras):
+
+ check_branch_protected(extras)
+
+ # Propagate to external components. This is done after checking the
+ # lock, for consistent behavior.
+ hook_response = pre_push_extension(repo_store_path=Repository.base_path(), **extras)
+ events.trigger(events.RepoPrePushEvent(repo_name=extras.repository, extras=extras))
+
+ return HookResponse(0, output) + hook_response
+
+
def post_push(extras):
"""Hook executed after user pushes to the repository."""
commit_ids = extras.commit_ids
@@ -292,22 +288,13 @@ def post_push(extras):
# Propagate to external components.
output = ''
+
# make lock is a tri state False, True, None. We only release lock on False
if extras.make_lock is False and not is_shadow_repo(extras):
Repository.unlock(Repository.get_by_repo_name(extras.repository))
msg = f'Released lock on repo `{extras.repository}`\n'
output += msg
- if extras.locked_by[0]:
- locked_by = User.get(extras.locked_by[0]).username
- reason = extras.locked_by[2]
- _http_ret = HTTPLockedRC(
- _locked_by_explanation(extras.repository, locked_by, reason))
- # TODO: johbo: if not?
- if str(_http_ret.code).startswith('2'):
- # 2xx Codes don't raise exceptions
- output += _http_ret.title
-
if extras.new_refs:
tmpl = '{}/{}/pull-request/new?{{ref_type}}={{ref_name}}'.format(
safe_str(extras.server_url), safe_str(extras.repository))
@@ -322,11 +309,8 @@ def post_push(extras):
hook_response = ''
if not is_shadow_repo(extras):
- hook_response = post_push_extension(
- repo_store_path=Repository.base_path(),
- **extras)
- events.trigger(events.RepoPushEvent(
- repo_name=extras.repository, pushed_commit_ids=commit_ids, extras=extras))
+ hook_response = post_push_extension(repo_store_path=Repository.base_path(), **extras)
+ events.trigger(events.RepoPushEvent(repo_name=extras.repository, pushed_commit_ids=commit_ids, extras=extras))
output += 'RhodeCode: push completed\n'
return HookResponse(0, output) + hook_response
@@ -380,12 +364,20 @@ class ExtensionCallback(object):
# with older rcextensions that require api_key present
if self._hook_name in ['CREATE_USER_HOOK', 'DELETE_USER_HOOK']:
kwargs_to_pass['api_key'] = '_DEPRECATED_'
- return callback(**kwargs_to_pass)
+ result = callback(**kwargs_to_pass)
+ log.debug('got rcextensions result: %s', result)
+ return result
def is_active(self):
return hasattr(rhodecode.EXTENSIONS, self._hook_name)
def _get_callback(self):
+ if rhodecode.is_test:
+ log.debug('In test mode, reloading rcextensions...')
+ # NOTE: for test re-load rcextensions always so we can dynamically change them for testing purposes
+ from rhodecode.lib.utils import load_rcextensions
+ load_rcextensions(root_path=os.path.dirname(rhodecode.CONFIG['__file__']))
+ return getattr(rhodecode.EXTENSIONS, self._hook_name, None)
return getattr(rhodecode.EXTENSIONS, self._hook_name, None)
diff --git a/rhodecode/lib/middleware/simplegit.py b/rhodecode/lib/middleware/simplegit.py
index f709a646..9580f827 100644
--- a/rhodecode/lib/middleware/simplegit.py
+++ b/rhodecode/lib/middleware/simplegit.py
@@ -40,16 +40,6 @@ GIT_PROTO_PAT = re.compile(
GIT_LFS_PROTO_PAT = re.compile(r'^/(.+)/(info/lfs/(.+))')
-def default_lfs_store():
- """
- Default lfs store location, it's consistent with Mercurials large file
- store which is in .cache/largefiles
- """
- from rhodecode.lib.vcs.backends.git import lfs_store
- user_home = os.path.expanduser("~")
- return lfs_store(user_home)
-
-
class SimpleGit(simplevcs.SimpleVCS):
SCM = 'git'
@@ -151,6 +141,6 @@ class SimpleGit(simplevcs.SimpleVCS):
extras['git_lfs_enabled'] = utils2.str2bool(
config.get('vcs_git_lfs', 'enabled'))
- extras['git_lfs_store_path'] = custom_store or default_lfs_store()
+ extras['git_lfs_store_path'] = custom_store
extras['git_lfs_http_scheme'] = scheme
return extras
diff --git a/rhodecode/lib/middleware/simplevcs.py b/rhodecode/lib/middleware/simplevcs.py
index b3f7c230..bd6d8c16 100644
--- a/rhodecode/lib/middleware/simplevcs.py
+++ b/rhodecode/lib/middleware/simplevcs.py
@@ -1,5 +1,3 @@
-
-
# Copyright (C) 2014-2023 RhodeCode GmbH
#
# This program is free software: you can redistribute it and/or modify
@@ -32,8 +30,7 @@ from functools import wraps
import time
from paste.httpheaders import REMOTE_USER, AUTH_TYPE
-from pyramid.httpexceptions import (
- HTTPNotFound, HTTPForbidden, HTTPNotAcceptable, HTTPInternalServerError)
+from pyramid.httpexceptions import HTTPNotFound, HTTPForbidden, HTTPNotAcceptable, HTTPInternalServerError
from zope.cachedescriptors.property import Lazy as LazyProperty
import rhodecode
@@ -41,10 +38,9 @@ from rhodecode.authentication.base import authenticate, VCS_TYPE, loadplugin
from rhodecode.lib import rc_cache
from rhodecode.lib.svn_txn_utils import store_txn_id_data
from rhodecode.lib.auth import AuthUser, HasPermissionAnyMiddleware
-from rhodecode.lib.base import (
- BasicAuth, get_ip_addr, get_user_agent, vcs_operation_context)
-from rhodecode.lib.exceptions import (UserCreationError, NotAllowedToCreateUserError)
-from rhodecode.lib.hook_daemon.base import prepare_callback_daemon
+from rhodecode.lib.base import BasicAuth, get_ip_addr, get_user_agent, vcs_operation_context
+from rhodecode.lib.exceptions import UserCreationError, NotAllowedToCreateUserError
+from rhodecode.lib.hook_daemon.utils import prepare_callback_daemon
from rhodecode.lib.middleware import appenlight
from rhodecode.lib.middleware.utils import scm_app_http
from rhodecode.lib.str_utils import safe_bytes, safe_int
@@ -78,17 +74,18 @@ def initialize_generator(factory):
try:
init = next(gen)
except StopIteration:
- raise ValueError('Generator must yield at least one element.')
+ raise ValueError("Generator must yield at least one element.")
if init != "__init__":
raise ValueError('First yielded element must be "__init__".')
return gen
+
return wrapper
class SimpleVCS(object):
"""Common functionality for SCM HTTP handlers."""
- SCM = 'unknown'
+ SCM = "unknown"
acl_repo_name = None
url_repo_name = None
@@ -100,11 +97,11 @@ class SimpleVCS(object):
# we use this regex which will match only on URLs pointing to shadow
# repositories.
shadow_repo_re = re.compile(
- '(?P(?:{slug_pat}/)*)' # repo groups
- '(?P{slug_pat})/' # target repo
- 'pull-request/(?P\\d+)/' # pull request
- 'repository$' # shadow repo
- .format(slug_pat=SLUG_RE.pattern))
+ "(?P(?:{slug_pat}/)*)" # repo groups
+ "(?P{slug_pat})/" # target repo
+ "pull-request/(?P\\d+)/" # pull request
+ "repository$".format(slug_pat=SLUG_RE.pattern) # shadow repo
+ )
def __init__(self, config, registry):
self.registry = registry
@@ -113,15 +110,14 @@ class SimpleVCS(object):
self.repo_vcs_config = base.Config()
rc_settings = SettingsModel().get_all_settings(cache=True, from_request=False)
- realm = rc_settings.get('rhodecode_realm') or 'RhodeCode AUTH'
+ realm = rc_settings.get("rhodecode_realm") or "RhodeCode AUTH"
# authenticate this VCS request using authfunc
- auth_ret_code_detection = \
- str2bool(self.config.get('auth_ret_code_detection', False))
+ auth_ret_code_detection = str2bool(self.config.get("auth_ret_code_detection", False))
self.authenticate = BasicAuth(
- '', authenticate, registry, config.get('auth_ret_code'),
- auth_ret_code_detection, rc_realm=realm)
- self.ip_addr = '0.0.0.0'
+ "", authenticate, registry, config.get("auth_ret_code"), auth_ret_code_detection, rc_realm=realm
+ )
+ self.ip_addr = "0.0.0.0"
@LazyProperty
def global_vcs_config(self):
@@ -132,10 +128,10 @@ class SimpleVCS(object):
@property
def base_path(self):
- settings_path = self.config.get('repo_store.path')
+ settings_path = self.config.get("repo_store.path")
if not settings_path:
- raise ValueError('FATAL: repo_store.path is empty')
+ raise ValueError("FATAL: repo_store.path is empty")
return settings_path
def set_repo_names(self, environ):
@@ -164,17 +160,16 @@ class SimpleVCS(object):
match_dict = match.groupdict()
# Build acl repo name from regex match.
- acl_repo_name = safe_str('{groups}{target}'.format(
- groups=match_dict['groups'] or '',
- target=match_dict['target']))
+ acl_repo_name = safe_str(
+ "{groups}{target}".format(groups=match_dict["groups"] or "", target=match_dict["target"])
+ )
# Retrieve pull request instance by ID from regex match.
- pull_request = PullRequest.get(match_dict['pr_id'])
+ pull_request = PullRequest.get(match_dict["pr_id"])
# Only proceed if we got a pull request and if acl repo name from
# URL equals the target repo name of the pull request.
if pull_request and (acl_repo_name == pull_request.target_repo.repo_name):
-
# Get file system path to shadow repository.
workspace_id = PullRequestModel()._workspace_id(pull_request)
vcs_repo_name = pull_request.target_repo.get_shadow_repository_path(workspace_id)
@@ -184,21 +179,23 @@ class SimpleVCS(object):
self.acl_repo_name = acl_repo_name
self.is_shadow_repo = True
- log.debug('Setting all VCS repository names: %s', {
- 'acl_repo_name': self.acl_repo_name,
- 'url_repo_name': self.url_repo_name,
- 'vcs_repo_name': self.vcs_repo_name,
- })
+ log.debug(
+ "Setting all VCS repository names: %s",
+ {
+ "acl_repo_name": self.acl_repo_name,
+ "url_repo_name": self.url_repo_name,
+ "vcs_repo_name": self.vcs_repo_name,
+ },
+ )
@property
def scm_app(self):
- custom_implementation = self.config['vcs.scm_app_implementation']
- if custom_implementation == 'http':
- log.debug('Using HTTP implementation of scm app.')
+ custom_implementation = self.config["vcs.scm_app_implementation"]
+ if custom_implementation == "http":
+ log.debug("Using HTTP implementation of scm app.")
scm_app_impl = scm_app_http
else:
- log.debug('Using custom implementation of scm_app: "{}"'.format(
- custom_implementation))
+ log.debug('Using custom implementation of scm_app: "{}"'.format(custom_implementation))
scm_app_impl = importlib.import_module(custom_implementation)
return scm_app_impl
@@ -208,17 +205,18 @@ class SimpleVCS(object):
with a repository_name for support of _ non changeable urls
"""
- data = repo_name.split('/')
+ data = repo_name.split("/")
if len(data) >= 2:
from rhodecode.model.repo import RepoModel
+
by_id_match = RepoModel().get_repo_by_id(repo_name)
if by_id_match:
data[1] = by_id_match.repo_name
# Because PEP-3333-WSGI uses bytes-tunneled-in-latin-1 as PATH_INFO
# and we use this data
- maybe_new_path = '/'.join(data)
- return safe_bytes(maybe_new_path).decode('latin1')
+ maybe_new_path = "/".join(data)
+ return safe_bytes(maybe_new_path).decode("latin1")
def _invalidate_cache(self, repo_name):
"""
@@ -231,21 +229,18 @@ class SimpleVCS(object):
def is_valid_and_existing_repo(self, repo_name, base_path, scm_type):
db_repo = Repository.get_by_repo_name(repo_name)
if not db_repo:
- log.debug('Repository `%s` not found inside the database.',
- repo_name)
+ log.debug("Repository `%s` not found inside the database.", repo_name)
return False
if db_repo.repo_type != scm_type:
log.warning(
- 'Repository `%s` have incorrect scm_type, expected %s got %s',
- repo_name, db_repo.repo_type, scm_type)
+ "Repository `%s` have incorrect scm_type, expected %s got %s", repo_name, db_repo.repo_type, scm_type
+ )
return False
config = db_repo._config
- config.set('extensions', 'largefiles', '')
- return is_valid_repo(
- repo_name, base_path,
- explicit_scm=scm_type, expect_scm=scm_type, config=config)
+ config.set("extensions", "largefiles", "")
+ return is_valid_repo(repo_name, base_path, explicit_scm=scm_type, expect_scm=scm_type, config=config)
def valid_and_active_user(self, user):
"""
@@ -267,8 +262,9 @@ class SimpleVCS(object):
def is_shadow_repo_dir(self):
return os.path.isdir(self.vcs_repo_name)
- def _check_permission(self, action, user, auth_user, repo_name, ip_addr=None,
- plugin_id='', plugin_cache_active=False, cache_ttl=0):
+ def _check_permission(
+ self, action, user, auth_user, repo_name, ip_addr=None, plugin_id="", plugin_cache_active=False, cache_ttl=0
+ ):
"""
Checks permissions using action (push/pull) user and repository
name. If plugin_cache and ttl is set it will use the plugin which
@@ -280,71 +276,67 @@ class SimpleVCS(object):
:param repo_name: repository name
"""
- log.debug('AUTH_CACHE_TTL for permissions `%s` active: %s (TTL: %s)',
- plugin_id, plugin_cache_active, cache_ttl)
+ log.debug("AUTH_CACHE_TTL for permissions `%s` active: %s (TTL: %s)", plugin_id, plugin_cache_active, cache_ttl)
user_id = user.user_id
- cache_namespace_uid = f'cache_user_auth.{rc_cache.PERMISSIONS_CACHE_VER}.{user_id}'
- region = rc_cache.get_or_create_region('cache_perms', cache_namespace_uid)
+ cache_namespace_uid = f"cache_user_auth.{rc_cache.PERMISSIONS_CACHE_VER}.{user_id}"
+ region = rc_cache.get_or_create_region("cache_perms", cache_namespace_uid)
- @region.conditional_cache_on_arguments(namespace=cache_namespace_uid,
- expiration_time=cache_ttl,
- condition=plugin_cache_active)
- def compute_perm_vcs(
- cache_name, plugin_id, action, user_id, repo_name, ip_addr):
-
- log.debug('auth: calculating permission access now for vcs operation: %s', action)
+ @region.conditional_cache_on_arguments(
+ namespace=cache_namespace_uid, expiration_time=cache_ttl, condition=plugin_cache_active
+ )
+ def compute_perm_vcs(cache_name, plugin_id, action, user_id, repo_name, ip_addr):
+ log.debug("auth: calculating permission access now for vcs operation: %s", action)
# check IP
inherit = user.inherit_default_permissions
- ip_allowed = AuthUser.check_ip_allowed(
- user_id, ip_addr, inherit_from_default=inherit)
+ ip_allowed = AuthUser.check_ip_allowed(user_id, ip_addr, inherit_from_default=inherit)
if ip_allowed:
- log.info('Access for IP:%s allowed', ip_addr)
+ log.info("Access for IP:%s allowed", ip_addr)
else:
return False
- if action == 'push':
- perms = ('repository.write', 'repository.admin')
+ if action == "push":
+ perms = ("repository.write", "repository.admin")
if not HasPermissionAnyMiddleware(*perms)(auth_user, repo_name):
return False
else:
# any other action need at least read permission
- perms = (
- 'repository.read', 'repository.write', 'repository.admin')
+ perms = ("repository.read", "repository.write", "repository.admin")
if not HasPermissionAnyMiddleware(*perms)(auth_user, repo_name):
return False
return True
start = time.time()
- log.debug('Running plugin `%s` permissions check', plugin_id)
+ log.debug("Running plugin `%s` permissions check", plugin_id)
# for environ based auth, password can be empty, but then the validation is
# on the server that fills in the env data needed for authentication
- perm_result = compute_perm_vcs(
- 'vcs_permissions', plugin_id, action, user.user_id, repo_name, ip_addr)
+ perm_result = compute_perm_vcs("vcs_permissions", plugin_id, action, user.user_id, repo_name, ip_addr)
auth_time = time.time() - start
- log.debug('Permissions for plugin `%s` completed in %.4fs, '
- 'expiration time of fetched cache %.1fs.',
- plugin_id, auth_time, cache_ttl)
+ log.debug(
+ "Permissions for plugin `%s` completed in %.4fs, " "expiration time of fetched cache %.1fs.",
+ plugin_id,
+ auth_time,
+ cache_ttl,
+ )
return perm_result
def _get_http_scheme(self, environ):
try:
- return environ['wsgi.url_scheme']
+ return environ["wsgi.url_scheme"]
except Exception:
- log.exception('Failed to read http scheme')
- return 'http'
+ log.exception("Failed to read http scheme")
+ return "http"
def _get_default_cache_ttl(self):
# take AUTH_CACHE_TTL from the `rhodecode` auth plugin
- plugin = loadplugin('egg:rhodecode-enterprise-ce#rhodecode')
+ plugin = loadplugin("egg:rhodecode-enterprise-ce#rhodecode")
plugin_settings = plugin.get_settings()
- plugin_cache_active, cache_ttl = plugin.get_ttl_cache(
- plugin_settings) or (False, 0)
+ plugin_cache_active, cache_ttl = plugin.get_ttl_cache(plugin_settings) or (False, 0)
return plugin_cache_active, cache_ttl
def __call__(self, environ, start_response):
@@ -359,17 +351,17 @@ class SimpleVCS(object):
def _handle_request(self, environ, start_response):
if not self.url_repo_name:
- log.warning('Repository name is empty: %s', self.url_repo_name)
+ log.warning("Repository name is empty: %s", self.url_repo_name)
# failed to get repo name, we fail now
return HTTPNotFound()(environ, start_response)
- log.debug('Extracted repo name is %s', self.url_repo_name)
+ log.debug("Extracted repo name is %s", self.url_repo_name)
ip_addr = get_ip_addr(environ)
user_agent = get_user_agent(environ)
username = None
# skip passing error to error controller
- environ['pylons.status_code_redirect'] = True
+ environ["pylons.status_code_redirect"] = True
# ======================================================================
# GET ACTION PULL or PUSH
@@ -380,17 +372,15 @@ class SimpleVCS(object):
# Check if this is a request to a shadow repository of a pull request.
# In this case only pull action is allowed.
# ======================================================================
- if self.is_shadow_repo and action != 'pull':
- reason = 'Only pull action is allowed for shadow repositories.'
- log.debug('User not allowed to proceed, %s', reason)
+ if self.is_shadow_repo and action != "pull":
+ reason = "Only pull action is allowed for shadow repositories."
+ log.debug("User not allowed to proceed, %s", reason)
return HTTPNotAcceptable(reason)(environ, start_response)
# Check if the shadow repo actually exists, in case someone refers
# to it, and it has been deleted because of successful merge.
if self.is_shadow_repo and not self.is_shadow_repo_dir:
- log.debug(
- 'Shadow repo detected, and shadow repo dir `%s` is missing',
- self.is_shadow_repo_dir)
+ log.debug("Shadow repo detected, and shadow repo dir `%s` is missing", self.is_shadow_repo_dir)
return HTTPNotFound()(environ, start_response)
# ======================================================================
@@ -398,7 +388,7 @@ class SimpleVCS(object):
# ======================================================================
detect_force_push = False
check_branch_perms = False
- if action in ['pull', 'push']:
+ if action in ["pull", "push"]:
user_obj = anonymous_user = User.get_default_user()
auth_user = user_obj.AuthUser()
username = anonymous_user.username
@@ -406,8 +396,12 @@ class SimpleVCS(object):
plugin_cache_active, cache_ttl = self._get_default_cache_ttl()
# ONLY check permissions if the user is activated
anonymous_perm = self._check_permission(
- action, anonymous_user, auth_user, self.acl_repo_name, ip_addr,
- plugin_id='anonymous_access',
+ action,
+ anonymous_user,
+ auth_user,
+ self.acl_repo_name,
+ ip_addr,
+ plugin_id="anonymous_access",
plugin_cache_active=plugin_cache_active,
cache_ttl=cache_ttl,
)
@@ -416,12 +410,13 @@ class SimpleVCS(object):
if not anonymous_user.active or not anonymous_perm:
if not anonymous_user.active:
- log.debug('Anonymous access is disabled, running '
- 'authentication')
+ log.debug("Anonymous access is disabled, running " "authentication")
if not anonymous_perm:
- log.debug('Not enough credentials to access repo: `%s` '
- 'repository as anonymous user', self.acl_repo_name)
+ log.debug(
+ "Not enough credentials to access repo: `%s` " "repository as anonymous user",
+ self.acl_repo_name,
+ )
username = None
# ==============================================================
@@ -430,19 +425,18 @@ class SimpleVCS(object):
# ==============================================================
# try to auth based on environ, container auth methods
- log.debug('Running PRE-AUTH for container|headers based authentication')
+ log.debug("Running PRE-AUTH for container|headers based authentication")
# headers auth, by just reading special headers and bypass the auth with user/passwd
pre_auth = authenticate(
- '', '', environ, VCS_TYPE, registry=self.registry,
- acl_repo_name=self.acl_repo_name)
+ "", "", environ, VCS_TYPE, registry=self.registry, acl_repo_name=self.acl_repo_name
+ )
- if pre_auth and pre_auth.get('username'):
- username = pre_auth['username']
- log.debug('PRE-AUTH got `%s` as username', username)
+ if pre_auth and pre_auth.get("username"):
+ username = pre_auth["username"]
+ log.debug("PRE-AUTH got `%s` as username", username)
if pre_auth:
- log.debug('PRE-AUTH successful from %s',
- pre_auth.get('auth_data', {}).get('_plugin'))
+ log.debug("PRE-AUTH successful from %s", pre_auth.get("auth_data", {}).get("_plugin"))
# If not authenticated by the container, running basic auth
# before inject the calling repo_name for special scope checks
@@ -463,16 +457,16 @@ class SimpleVCS(object):
return HTTPNotAcceptable(reason)(environ, start_response)
if isinstance(auth_result, dict):
- AUTH_TYPE.update(environ, 'basic')
- REMOTE_USER.update(environ, auth_result['username'])
- username = auth_result['username']
- plugin = auth_result.get('auth_data', {}).get('_plugin')
- log.info(
- 'MAIN-AUTH successful for user `%s` from %s plugin',
- username, plugin)
+ AUTH_TYPE.update(environ, "basic")
+ REMOTE_USER.update(environ, auth_result["username"])
+ username = auth_result["username"]
+ plugin = auth_result.get("auth_data", {}).get("_plugin")
+ log.info("MAIN-AUTH successful for user `%s` from %s plugin", username, plugin)
- plugin_cache_active, cache_ttl = auth_result.get(
- 'auth_data', {}).get('_ttl_cache') or (False, 0)
+ plugin_cache_active, cache_ttl = auth_result.get("auth_data", {}).get("_ttl_cache") or (
+ False,
+ 0,
+ )
else:
return auth_result.wsgi_application(environ, start_response)
@@ -488,21 +482,24 @@ class SimpleVCS(object):
# check user attributes for password change flag
user_obj = user
auth_user = user_obj.AuthUser()
- if user_obj and user_obj.username != User.DEFAULT_USER and \
- user_obj.user_data.get('force_password_change'):
- reason = 'password change required'
- log.debug('User not allowed to authenticate, %s', reason)
+ if (
+ user_obj
+ and user_obj.username != User.DEFAULT_USER
+ and user_obj.user_data.get("force_password_change")
+ ):
+ reason = "password change required"
+ log.debug("User not allowed to authenticate, %s", reason)
return HTTPNotAcceptable(reason)(environ, start_response)
# check permissions for this repository
perm = self._check_permission(
- action, user, auth_user, self.acl_repo_name, ip_addr,
- plugin, plugin_cache_active, cache_ttl)
+ action, user, auth_user, self.acl_repo_name, ip_addr, plugin, plugin_cache_active, cache_ttl
+ )
if not perm:
return HTTPForbidden()(environ, start_response)
- environ['rc_auth_user_id'] = str(user_id)
+ environ["rc_auth_user_id"] = str(user_id)
- if action == 'push':
+ if action == "push":
perms = auth_user.get_branch_permissions(self.acl_repo_name)
if perms:
check_branch_perms = True
@@ -510,41 +507,48 @@ class SimpleVCS(object):
# extras are injected into UI object and later available
# in hooks executed by RhodeCode
- check_locking = _should_check_locking(environ.get('QUERY_STRING'))
+ check_locking = _should_check_locking(environ.get("QUERY_STRING"))
extras = vcs_operation_context(
- environ, repo_name=self.acl_repo_name, username=username,
- action=action, scm=self.SCM, check_locking=check_locking,
- is_shadow_repo=self.is_shadow_repo, check_branch_perms=check_branch_perms,
- detect_force_push=detect_force_push
+ environ,
+ repo_name=self.acl_repo_name,
+ username=username,
+ action=action,
+ scm=self.SCM,
+ check_locking=check_locking,
+ is_shadow_repo=self.is_shadow_repo,
+ check_branch_perms=check_branch_perms,
+ detect_force_push=detect_force_push,
)
# ======================================================================
# REQUEST HANDLING
# ======================================================================
- repo_path = os.path.join(
- safe_str(self.base_path), safe_str(self.vcs_repo_name))
- log.debug('Repository path is %s', repo_path)
+ repo_path = os.path.join(safe_str(self.base_path), safe_str(self.vcs_repo_name))
+ log.debug("Repository path is %s", repo_path)
fix_PATH()
log.info(
'%s action on %s repo "%s" by "%s" from %s %s',
- action, self.SCM, safe_str(self.url_repo_name),
- safe_str(username), ip_addr, user_agent)
+ action,
+ self.SCM,
+ safe_str(self.url_repo_name),
+ safe_str(username),
+ ip_addr,
+ user_agent,
+ )
- return self._generate_vcs_response(
- environ, start_response, repo_path, extras, action)
+ return self._generate_vcs_response(environ, start_response, repo_path, extras, action)
def _get_txn_id(self, environ):
-
- for k in ['RAW_URI', 'HTTP_DESTINATION']:
+ for k in ["RAW_URI", "HTTP_DESTINATION"]:
url = environ.get(k)
if not url:
continue
# regex to search for svn-txn-id
- pattern = r'/!svn/txr/([^/]+)/'
+ pattern = r"/!svn/txr/([^/]+)/"
# Search for the pattern in the URL
match = re.search(pattern, url)
@@ -555,8 +559,7 @@ class SimpleVCS(object):
return txn_id
@initialize_generator
- def _generate_vcs_response(
- self, environ, start_response, repo_path, extras, action):
+ def _generate_vcs_response(self, environ, start_response, repo_path, extras, action):
"""
Returns a generator for the response content.
@@ -565,24 +568,20 @@ class SimpleVCS(object):
also handles the locking exceptions which will be triggered when
the first chunk is produced by the underlying WSGI application.
"""
- svn_txn_id = ''
- if action == 'push':
+ svn_txn_id = ""
+ if action == "push":
svn_txn_id = self._get_txn_id(environ)
- callback_daemon, extras = self._prepare_callback_daemon(
- extras, environ, action, txn_id=svn_txn_id)
+ callback_daemon, extras = self._prepare_callback_daemon(extras, environ, action, txn_id=svn_txn_id)
if svn_txn_id:
-
- port = safe_int(extras['hooks_uri'].split(':')[-1])
txn_id_data = extras.copy()
- txn_id_data.update({'port': port})
- txn_id_data.update({'req_method': environ['REQUEST_METHOD']})
+ txn_id_data.update({"req_method": environ["REQUEST_METHOD"]})
full_repo_path = repo_path
store_txn_id_data(full_repo_path, svn_txn_id, txn_id_data)
- log.debug('HOOKS extras is %s', extras)
+ log.debug("HOOKS extras is %s", extras)
http_scheme = self._get_http_scheme(environ)
@@ -609,7 +608,7 @@ class SimpleVCS(object):
try:
# invalidate cache on push
- if action == 'push':
+ if action == "push":
self._invalidate_cache(self.url_repo_name)
finally:
meta.Session.remove()
@@ -632,12 +631,12 @@ class SimpleVCS(object):
"""Return the WSGI app that will finally handle the request."""
raise NotImplementedError()
- def _create_config(self, extras, repo_name, scheme='http'):
+ def _create_config(self, extras, repo_name, scheme="http"):
"""Create a safe config representation."""
raise NotImplementedError()
def _should_use_callback_daemon(self, extras, environ, action):
- if extras.get('is_shadow_repo'):
+ if extras.get("is_shadow_repo"):
# we don't want to execute hooks, and callback daemon for shadow repos
return False
return True
@@ -647,11 +646,9 @@ class SimpleVCS(object):
if not self._should_use_callback_daemon(extras, environ, action):
# disable callback daemon for actions that don't require it
- protocol = 'local'
+ protocol = "local"
- return prepare_callback_daemon(
- extras, protocol=protocol,
- host=vcs_settings.HOOKS_HOST, txn_id=txn_id)
+ return prepare_callback_daemon(extras, protocol=protocol, txn_id=txn_id)
def _should_check_locking(query_string):
@@ -659,4 +656,4 @@ def _should_check_locking(query_string):
# server see all operation on commit; bookmarks, phases and
# obsolescence marker in different transaction, we don't want to check
# locking on those
- return query_string not in ['cmd=listkeys']
+ return query_string not in ["cmd=listkeys"]
diff --git a/rhodecode/lib/utils.py b/rhodecode/lib/utils.py
index 11331c06..ea5ada46 100644
--- a/rhodecode/lib/utils.py
+++ b/rhodecode/lib/utils.py
@@ -21,6 +21,7 @@ Utilities library for RhodeCode
"""
import datetime
+import importlib
import decorator
import logging
@@ -42,8 +43,9 @@ from webhelpers2.text import collapse, strip_tags, convert_accented_entities, co
from mako import exceptions
+import rhodecode
from rhodecode import ConfigGet
-from rhodecode.lib.exceptions import HTTPBranchProtected, HTTPLockedRC
+from rhodecode.lib.exceptions import HTTPBranchProtected, HTTPLockedRepo, ClientNotSupported
from rhodecode.lib.hash_utils import sha256_safe, md5, sha1
from rhodecode.lib.type_utils import AttributeDict
from rhodecode.lib.str_utils import safe_bytes, safe_str
@@ -86,6 +88,7 @@ def adopt_for_celery(func):
@wraps(func)
def wrapper(extras):
extras = AttributeDict(extras)
+
try:
# HooksResponse implements to_json method which must be used there.
return func(extras).to_json()
@@ -100,7 +103,18 @@ def adopt_for_celery(func):
'exception_args': error_args,
'exception_traceback': '',
}
- except HTTPLockedRC as error:
+ except ClientNotSupported as error:
+ # Those special cases don't need error reporting. It's a case of
+ # locked repo or protected branch
+ error_args = error.args
+ return {
+ 'status': error.code,
+ 'output': error.explanation,
+ 'exception': type(error).__name__,
+ 'exception_args': error_args,
+ 'exception_traceback': '',
+ }
+ except HTTPLockedRepo as error:
# Those special cases don't need error reporting. It's a case of
# locked repo or protected branch
error_args = error.args
@@ -117,7 +131,7 @@ def adopt_for_celery(func):
'output': '',
'exception': type(e).__name__,
'exception_args': e.args,
- 'exception_traceback': '',
+ 'exception_traceback': traceback.format_exc(),
}
return wrapper
@@ -411,6 +425,10 @@ def prepare_config_data(clear_session=True, repo=None):
('web', 'push_ssl', 'false'),
]
for setting in ui_settings:
+ # skip certain deprecated keys that might be still in DB
+ if f"{setting.section}_{setting.key}" in ['extensions_hgsubversion']:
+ continue
+
# Todo: remove this section once transition to *.ini files will be completed
if setting.section in ('largefiles', 'vcs_git_lfs'):
if setting.key != 'enabled':
@@ -686,22 +704,41 @@ def repo2db_mapper(initial_repo_list, remove_obsolete=False, force_hooks_rebuild
return added, removed
+def deep_reload_package(package_name):
+ """
+ Deeply reload a package by removing it and its submodules from sys.modules,
+ then re-importing it.
+ """
+ # Remove the package and its submodules from sys.modules
+ to_reload = [name for name in sys.modules if name == package_name or name.startswith(package_name + ".")]
+ for module_name in to_reload:
+ del sys.modules[module_name]
+ log.debug(f"Removed module from cache: {module_name}")
+
+ # Re-import the package
+ package = importlib.import_module(package_name)
+ log.debug(f"Re-imported package: {package_name}")
+
+ return package
def load_rcextensions(root_path):
import rhodecode
from rhodecode.config import conf
path = os.path.join(root_path)
- sys.path.append(path)
+ deep_reload = path in sys.path
+ sys.path.insert(0, path)
try:
- rcextensions = __import__('rcextensions')
+ rcextensions = __import__('rcextensions', fromlist=[''])
except ImportError:
if os.path.isdir(os.path.join(path, 'rcextensions')):
log.warning('Unable to load rcextensions from %s', path)
rcextensions = None
if rcextensions:
+ if deep_reload:
+ rcextensions = deep_reload_package('rcextensions')
log.info('Loaded rcextensions from %s...', rcextensions)
rhodecode.EXTENSIONS = rcextensions
@@ -741,6 +778,7 @@ def create_test_index(repo_location, config):
except ImportError:
raise ImportError('Failed to import rc_testdata, '
'please make sure this package is installed from requirements_test.txt')
+
rc_testdata.extract_search_index(
'vcs_search_index', os.path.dirname(config['search.location']))
@@ -785,22 +823,15 @@ def create_test_repositories(test_path, config):
Creates test repositories in the temporary directory. Repositories are
extracted from archives within the rc_testdata package.
"""
- import rc_testdata
+ try:
+ import rc_testdata
+ except ImportError:
+ raise ImportError('Failed to import rc_testdata, '
+ 'please make sure this package is installed from requirements_test.txt')
+
from rhodecode.tests import HG_REPO, GIT_REPO, SVN_REPO
- log.debug('making test vcs repositories')
-
- idx_path = config['search.location']
- data_path = config['cache_dir']
-
- # clean index and data
- if idx_path and os.path.exists(idx_path):
- log.debug('remove %s', idx_path)
- shutil.rmtree(idx_path)
-
- if data_path and os.path.exists(data_path):
- log.debug('remove %s', data_path)
- shutil.rmtree(data_path)
+ log.debug('making test vcs repositories at %s', test_path)
rc_testdata.extract_hg_dump('vcs_test_hg', jn(test_path, HG_REPO))
rc_testdata.extract_git_dump('vcs_test_git', jn(test_path, GIT_REPO))
diff --git a/rhodecode/lib/vcs/__init__.py b/rhodecode/lib/vcs/__init__.py
index da7de79b..bce7c095 100644
--- a/rhodecode/lib/vcs/__init__.py
+++ b/rhodecode/lib/vcs/__init__.py
@@ -140,7 +140,7 @@ class CurlSession(object):
try:
curl.perform()
except pycurl.error as exc:
- log.error('Failed to call endpoint url: {} using pycurl'.format(url))
+ log.error('Failed to call endpoint url: %s using pycurl', url)
raise
status_code = curl.getinfo(pycurl.HTTP_CODE)
diff --git a/rhodecode/lib/vcs/backends/git/__init__.py b/rhodecode/lib/vcs/backends/git/__init__.py
index a2632c07..e08cd427 100644
--- a/rhodecode/lib/vcs/backends/git/__init__.py
+++ b/rhodecode/lib/vcs/backends/git/__init__.py
@@ -45,10 +45,3 @@ def discover_git_version(raise_on_exc=False):
if raise_on_exc:
raise
return ''
-
-
-def lfs_store(base_location):
- """
- Return a lfs store relative to base_location
- """
- return os.path.join(base_location, '.cache', 'lfs_store')
diff --git a/rhodecode/lib/vcs/backends/hg/__init__.py b/rhodecode/lib/vcs/backends/hg/__init__.py
index 60ebd19b..cefbe54a 100644
--- a/rhodecode/lib/vcs/backends/hg/__init__.py
+++ b/rhodecode/lib/vcs/backends/hg/__init__.py
@@ -45,10 +45,3 @@ def discover_hg_version(raise_on_exc=False):
if raise_on_exc:
raise
return ''
-
-
-def largefiles_store(base_location):
- """
- Return a largefile store relative to base_location
- """
- return os.path.join(base_location, '.cache', 'largefiles')
diff --git a/rhodecode/lib/vcs/client_http.py b/rhodecode/lib/vcs/client_http.py
index b331b167..498a0eb6 100644
--- a/rhodecode/lib/vcs/client_http.py
+++ b/rhodecode/lib/vcs/client_http.py
@@ -216,7 +216,7 @@ class RemoteRepo(object):
self._cache_region, self._cache_namespace = \
remote_maker.init_cache_region(cache_repo_id)
- with_wire = with_wire or {}
+ with_wire = with_wire or {"cache": False}
repo_state_uid = with_wire.get('repo_state_uid') or 'state'
diff --git a/rhodecode/model/comment.py b/rhodecode/model/comment.py
index 075c7efd..8b44a156 100644
--- a/rhodecode/model/comment.py
+++ b/rhodecode/model/comment.py
@@ -373,6 +373,7 @@ class CommentsModel(BaseModel):
Session().add(comment)
Session().flush()
+
kwargs = {
'user': user,
'renderer_type': renderer,
@@ -387,8 +388,7 @@ class CommentsModel(BaseModel):
}
if commit_obj:
- recipients = ChangesetComment.get_users(
- revision=commit_obj.raw_id)
+ recipients = ChangesetComment.get_users(revision=commit_obj.raw_id)
# add commit author if it's in RhodeCode system
cs_author = User.get_from_cs_author(commit_obj.author)
if not cs_author:
@@ -397,16 +397,13 @@ class CommentsModel(BaseModel):
recipients += [cs_author]
commit_comment_url = self.get_url(comment, request=request)
- commit_comment_reply_url = self.get_url(
- comment, request=request,
- anchor=f'comment-{comment.comment_id}/?/ReplyToComment')
+ commit_comment_reply_url = self.get_url(comment, request=request, anchor=f'comment-{comment.comment_id}/?/ReplyToComment')
target_repo_url = h.link_to(
repo.repo_name,
h.route_url('repo_summary', repo_name=repo.repo_name))
- commit_url = h.route_url('repo_commit', repo_name=repo.repo_name,
- commit_id=commit_id)
+ commit_url = h.route_url('repo_commit', repo_name=repo.repo_name, commit_id=commit_id)
# commit specifics
kwargs.update({
@@ -489,7 +486,6 @@ class CommentsModel(BaseModel):
if not is_draft:
comment_data = comment.get_api_data()
-
self._log_audit_action(
action, {'data': comment_data}, auth_user, comment)
diff --git a/rhodecode/model/pull_request.py b/rhodecode/model/pull_request.py
index 0848a826..e99fad38 100644
--- a/rhodecode/model/pull_request.py
+++ b/rhodecode/model/pull_request.py
@@ -38,7 +38,7 @@ from rhodecode.translation import lazy_ugettext
from rhodecode.lib import helpers as h, hooks_utils, diffs
from rhodecode.lib import audit_logger
from collections import OrderedDict
-from rhodecode.lib.hook_daemon.base import prepare_callback_daemon
+from rhodecode.lib.hook_daemon.utils import prepare_callback_daemon
from rhodecode.lib.ext_json import sjson as json
from rhodecode.lib.markup_renderer import (
DEFAULT_COMMENTS_RENDERER, RstTemplateRenderer)
@@ -980,9 +980,7 @@ class PullRequestModel(BaseModel):
target_ref = self._refresh_reference(
pull_request.target_ref_parts, target_vcs)
- callback_daemon, extras = prepare_callback_daemon(
- extras, protocol=vcs_settings.HOOKS_PROTOCOL,
- host=vcs_settings.HOOKS_HOST)
+ callback_daemon, extras = prepare_callback_daemon(extras, protocol=vcs_settings.HOOKS_PROTOCOL)
with callback_daemon:
# TODO: johbo: Implement a clean way to run a config_override
diff --git a/rhodecode/model/settings.py b/rhodecode/model/settings.py
index 275cd868..23433839 100644
--- a/rhodecode/model/settings.py
+++ b/rhodecode/model/settings.py
@@ -862,27 +862,3 @@ class VcsSettingsModel(object):
raise ValueError(
f'The given data does not contain {data_key} key')
return data_keys
-
- def create_largeobjects_dirs_if_needed(self, repo_store_path):
- """
- This is subscribed to the `pyramid.events.ApplicationCreated` event. It
- does a repository scan if enabled in the settings.
- """
-
- from rhodecode.lib.vcs.backends.hg import largefiles_store
- from rhodecode.lib.vcs.backends.git import lfs_store
-
- paths = [
- largefiles_store(repo_store_path),
- lfs_store(repo_store_path)]
-
- for path in paths:
- if os.path.isdir(path):
- continue
- if os.path.isfile(path):
- continue
- # not a file nor dir, we try to create it
- try:
- os.makedirs(path)
- except Exception:
- log.warning('Failed to create largefiles dir:%s', path)
diff --git a/rhodecode/tests/__init__.py b/rhodecode/tests/__init__.py
index 3d8d082d..f2f2a9a2 100644
--- a/rhodecode/tests/__init__.py
+++ b/rhodecode/tests/__init__.py
@@ -1,5 +1,4 @@
-
-# Copyright (C) 2010-2023 RhodeCode GmbH
+# 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
@@ -38,7 +37,7 @@ from rhodecode.lib.hash_utils import sha1_safe
log = logging.getLogger(__name__)
__all__ = [
- 'get_new_dir', 'TestController',
+ 'get_new_dir', 'TestController', 'console_printer',
'clear_cache_regions',
'assert_session_flash', 'login_user', 'no_newline_id_generator',
'TESTS_TMP_PATH', 'HG_REPO', 'GIT_REPO', 'SVN_REPO',
@@ -244,3 +243,11 @@ def no_newline_id_generator(test_name):
return test_name or 'test-with-empty-name'
+def console_printer(*msg):
+ print_func = print
+ try:
+ from rich import print as print_func
+ except ImportError:
+ pass
+
+ print_func(*msg)
diff --git a/rhodecode/tests/auth_external_test.py b/rhodecode/tests/auth_external_test.py
index 07010731..ab4ff946 100644
--- a/rhodecode/tests/auth_external_test.py
+++ b/rhodecode/tests/auth_external_test.py
@@ -1,5 +1,4 @@
-
-# Copyright (C) 2010-2023 RhodeCode GmbH
+# 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
@@ -90,7 +89,7 @@ class RhodeCodeAuthPlugin(RhodeCodeExternalAuthPlugin):
'firstname': firstname,
'lastname': lastname,
'groups': [],
- 'email': '%s@rhodecode.com' % username,
+ 'email': f'{username}@rhodecode.com',
'admin': admin,
'active': active,
"active_from_extern": None,
diff --git a/rhodecode/tests/config/test_routing_links.py b/rhodecode/tests/config/test_routing_links.py
index a8b7612a..bb9ada63 100644
--- a/rhodecode/tests/config/test_routing_links.py
+++ b/rhodecode/tests/config/test_routing_links.py
@@ -20,14 +20,14 @@
import pytest
import requests
from rhodecode.config import routing_links
-
+from rhodecode.tests import console_printer
def check_connection():
try:
response = requests.get('https://rhodecode.com')
return response.status_code == 200
except Exception as e:
- print(e)
+ console_printer(e)
return False
diff --git a/rhodecode/tests/conftest.py b/rhodecode/tests/conftest.py
index e6cdc829..da5ca2af 100644
--- a/rhodecode/tests/conftest.py
+++ b/rhodecode/tests/conftest.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2010-2023 RhodeCode GmbH
+# 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
@@ -16,23 +16,10 @@
# RhodeCode Enterprise Edition, including its added features, Support services,
# and proprietary license terms, please see https://rhodecode.com/licenses/
-"""
-py.test config for test suite for making push/pull operations.
-
-.. important::
-
- You must have git >= 1.8.5 for tests to work fine. With 68b939b git started
- to redirect things to stderr instead of stdout.
-"""
-
-import pytest
+import pytest # noqa
import logging
-
-from rhodecode.authentication import AuthenticationPluginRegistry
-from rhodecode.model.db import Permission, User
-from rhodecode.model.meta import Session
-from rhodecode.model.settings import SettingsModel
-from rhodecode.model.user import UserModel
+import collections
+import rhodecode
log = logging.getLogger(__name__)
@@ -40,99 +27,3 @@ log = logging.getLogger(__name__)
# Docker image running httpbin...
HTTPBIN_DOMAIN = 'http://httpbin'
HTTPBIN_POST = HTTPBIN_DOMAIN + '/post'
-
-
-@pytest.fixture()
-def enable_auth_plugins(request, baseapp, csrf_token):
- """
- Return a factory object that when called, allows to control which
- authentication plugins are enabled.
- """
-
- class AuthPluginManager(object):
-
- def cleanup(self):
- self._enable_plugins(['egg:rhodecode-enterprise-ce#rhodecode'])
-
- def enable(self, plugins_list, override=None):
- return self._enable_plugins(plugins_list, override)
-
- def _enable_plugins(self, plugins_list, override=None):
- override = override or {}
- params = {
- 'auth_plugins': ','.join(plugins_list),
- }
-
- # helper translate some names to others, to fix settings code
- name_map = {
- 'token': 'authtoken'
- }
- log.debug('enable_auth_plugins: enabling following auth-plugins: %s', plugins_list)
-
- for module in plugins_list:
- plugin_name = module.partition('#')[-1]
- if plugin_name in name_map:
- plugin_name = name_map[plugin_name]
- enabled_plugin = f'auth_{plugin_name}_enabled'
- cache_ttl = f'auth_{plugin_name}_cache_ttl'
-
- # default params that are needed for each plugin,
- # `enabled` and `cache_ttl`
- params.update({
- enabled_plugin: True,
- cache_ttl: 0
- })
- if override.get:
- params.update(override.get(module, {}))
-
- validated_params = params
-
- for k, v in validated_params.items():
- setting = SettingsModel().create_or_update_setting(k, v)
- Session().add(setting)
- Session().commit()
-
- AuthenticationPluginRegistry.invalidate_auth_plugins_cache(hard=True)
-
- enabled_plugins = SettingsModel().get_auth_plugins()
- assert plugins_list == enabled_plugins
-
- enabler = AuthPluginManager()
- request.addfinalizer(enabler.cleanup)
-
- return enabler
-
-
-@pytest.fixture()
-def test_user_factory(request, baseapp):
-
- def user_factory(username='test_user', password='qweqwe', first_name='John', last_name='Testing', **kwargs):
- usr = UserModel().create_or_update(
- username=username,
- password=password,
- email=f'{username}@rhodecode.org',
- firstname=first_name, lastname=last_name)
- Session().commit()
-
- for k, v in kwargs.items():
- setattr(usr, k, v)
- Session().add(usr)
-
- new_usr = User.get_by_username(username)
- new_usr_id = new_usr.user_id
- assert new_usr == usr
-
- @request.addfinalizer
- def cleanup():
- if User.get(new_usr_id) is None:
- return
-
- perm = Permission.query().all()
- for p in perm:
- UserModel().revoke_perm(usr, p)
-
- UserModel().delete(new_usr_id)
- Session().commit()
- return usr
-
- return user_factory
diff --git a/rhodecode/tests/conftest_common.py b/rhodecode/tests/conftest_common.py
index a773c0fb..20d044a5 100644
--- a/rhodecode/tests/conftest_common.py
+++ b/rhodecode/tests/conftest_common.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2010-2023 RhodeCode GmbH
+# 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
@@ -98,16 +98,16 @@ def pytest_addoption(parser):
'pyramid_config',
"Set up a Pyramid environment with the specified config file.")
+ parser.addini('rhodecode_config', 'rhodecode config ini for tests')
+ parser.addini('celery_config', 'celery config ini for tests')
+ parser.addini('vcsserver_config', 'vcsserver config ini for tests')
+
vcsgroup = parser.getgroup('vcs')
+
vcsgroup.addoption(
'--without-vcsserver', dest='with_vcsserver', action='store_false',
help="Do not start the VCSServer in a background process.")
- vcsgroup.addoption(
- '--with-vcsserver-http', dest='vcsserver_config_http',
- help="Start the HTTP VCSServer with the specified config file.")
- vcsgroup.addoption(
- '--vcsserver-protocol', dest='vcsserver_protocol',
- help="Start the VCSServer with HTTP protocol support.")
+
vcsgroup.addoption(
'--vcsserver-config-override', action='store', type=_parse_json,
default=None, dest='vcsserver_config_override', help=(
@@ -122,12 +122,6 @@ def pytest_addoption(parser):
"Allows to set the port of the vcsserver. Useful when testing "
"against an already running server and random ports cause "
"trouble."))
- parser.addini(
- 'vcsserver_config_http',
- "Start the HTTP VCSServer with the specified config file.")
- parser.addini(
- 'vcsserver_protocol',
- "Start the VCSServer with HTTP protocol support.")
@pytest.hookimpl(tryfirst=True, hookwrapper=True)
diff --git a/rhodecode/tests/database/__init__.py b/rhodecode/tests/database/__init__.py
new file mode 100644
index 00000000..c4d86aeb
--- /dev/null
+++ b/rhodecode/tests/database/__init__.py
@@ -0,0 +1,17 @@
+# 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 .
+#
+# 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/
diff --git a/rhodecode/tests/database/conftest.py b/rhodecode/tests/database/conftest.py
index 0bd2c0b3..528b1dbb 100644
--- a/rhodecode/tests/database/conftest.py
+++ b/rhodecode/tests/database/conftest.py
@@ -1,4 +1,3 @@
-
# Copyright (C) 2010-2023 RhodeCode GmbH
#
# This program is free software: you can redistribute it and/or modify
@@ -17,7 +16,7 @@
# RhodeCode Enterprise Edition, including its added features, Support services,
# and proprietary license terms, please see https://rhodecode.com/licenses/
-from subprocess import Popen, PIPE
+import subprocess
import os
import sys
import tempfile
@@ -26,87 +25,71 @@ import pytest
from sqlalchemy.engine import url
from rhodecode.lib.str_utils import safe_str, safe_bytes
-from rhodecode.tests.fixture import TestINI
+from rhodecode.tests.fixtures.rc_fixture import TestINI
def _get_dbs_from_metafunc(metafunc):
- dbs_mark = metafunc.definition.get_closest_marker('dbs')
+ dbs_mark = metafunc.definition.get_closest_marker("dbs")
if dbs_mark:
# Supported backends by this test function, created from pytest.mark.dbs
backends = dbs_mark.args
else:
- backends = metafunc.config.getoption('--dbs')
+ backends = metafunc.config.getoption("--dbs")
return backends
def pytest_generate_tests(metafunc):
# Support test generation based on --dbs parameter
- if 'db_backend' in metafunc.fixturenames:
- requested_backends = set(metafunc.config.getoption('--dbs'))
+ if "db_backend" in metafunc.fixturenames:
+ requested_backends = set(metafunc.config.getoption("--dbs"))
backends = _get_dbs_from_metafunc(metafunc)
backends = requested_backends.intersection(backends)
# TODO: johbo: Disabling a backend did not work out with
# parametrization, find better way to achieve this.
if not backends:
metafunc.function._skip = True
- metafunc.parametrize('db_backend_name', backends)
+ metafunc.parametrize("db_backend_name", backends)
def pytest_collection_modifyitems(session, config, items):
- remaining = [
- i for i in items if not getattr(i.obj, '_skip', False)]
+ remaining = [i for i in items if not getattr(i.obj, "_skip", False)]
items[:] = remaining
@pytest.fixture()
-def db_backend(
- request, db_backend_name, ini_config, tmpdir_factory):
+def db_backend(request, db_backend_name, ini_config, tmpdir_factory):
basetemp = tmpdir_factory.getbasetemp().strpath
klass = _get_backend(db_backend_name)
- option_name = '--{}-connection-string'.format(db_backend_name)
+ option_name = "--{}-connection-string".format(db_backend_name)
connection_string = request.config.getoption(option_name) or None
- return klass(
- config_file=ini_config, basetemp=basetemp,
- connection_string=connection_string)
+ return klass(config_file=ini_config, basetemp=basetemp, connection_string=connection_string)
def _get_backend(backend_type):
- return {
- 'sqlite': SQLiteDBBackend,
- 'postgres': PostgresDBBackend,
- 'mysql': MySQLDBBackend,
- '': EmptyDBBackend
- }[backend_type]
+ return {"sqlite": SQLiteDBBackend, "postgres": PostgresDBBackend, "mysql": MySQLDBBackend, "": EmptyDBBackend}[
+ backend_type
+ ]
class DBBackend(object):
_store = os.path.dirname(os.path.abspath(__file__))
_type = None
- _base_ini_config = [{'app:main': {'vcs.start_server': 'false',
- 'startup.import_repos': 'false'}}]
- _db_url = [{'app:main': {'sqlalchemy.db1.url': ''}}]
- _base_db_name = 'rhodecode_test_db_backend'
- std_env = {'RC_TEST': '0'}
-
- def __init__(
- self, config_file, db_name=None, basetemp=None,
- connection_string=None):
-
- from rhodecode.lib.vcs.backends.hg import largefiles_store
- from rhodecode.lib.vcs.backends.git import lfs_store
+ _base_ini_config = [{"app:main": {"vcs.start_server": "false", "startup.import_repos": "false"}}]
+ _db_url = [{"app:main": {"sqlalchemy.db1.url": ""}}]
+ _base_db_name = "rhodecode_test_db_backend"
+ std_env = {"RC_TEST": "0"}
+ def __init__(self, config_file, db_name=None, basetemp=None, connection_string=None):
self.fixture_store = os.path.join(self._store, self._type)
self.db_name = db_name or self._base_db_name
self._base_ini_file = config_file
- self.stderr = ''
- self.stdout = ''
+ self.stderr = ""
+ self.stdout = ""
self._basetemp = basetemp or tempfile.gettempdir()
- self._repos_location = os.path.join(self._basetemp, 'rc_test_repos')
- self._repos_hg_largefiles_store = largefiles_store(self._basetemp)
- self._repos_git_lfs_store = lfs_store(self._basetemp)
+ self._repos_location = os.path.join(self._basetemp, "rc_test_repos")
self.connection_string = connection_string
@property
@@ -118,8 +101,7 @@ class DBBackend(object):
if not new_connection_string:
new_connection_string = self.get_default_connection_string()
else:
- new_connection_string = new_connection_string.format(
- db_name=self.db_name)
+ new_connection_string = new_connection_string.format(db_name=self.db_name)
url_parts = url.make_url(new_connection_string)
self._connection_string = new_connection_string
self.user = url_parts.username
@@ -127,73 +109,67 @@ class DBBackend(object):
self.host = url_parts.host
def get_default_connection_string(self):
- raise NotImplementedError('default connection_string is required.')
+ raise NotImplementedError("default connection_string is required.")
def execute(self, cmd, env=None, *args):
"""
Runs command on the system with given ``args``.
"""
- command = cmd + ' ' + ' '.join(args)
- sys.stdout.write(f'CMD: {command}')
+ command = cmd + " " + " ".join(args)
+ sys.stdout.write(f"CMD: {command}")
# Tell Python to use UTF-8 encoding out stdout
_env = os.environ.copy()
- _env['PYTHONIOENCODING'] = 'UTF-8'
+ _env["PYTHONIOENCODING"] = "UTF-8"
_env.update(self.std_env)
if env:
_env.update(env)
- self.p = Popen(command, shell=True, stdout=PIPE, stderr=PIPE, env=_env)
+ self.p = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=_env)
self.stdout, self.stderr = self.p.communicate()
stdout_str = safe_str(self.stdout)
- sys.stdout.write(f'COMMAND:{command}\n')
+ sys.stdout.write(f"COMMAND:{command}\n")
sys.stdout.write(stdout_str)
return self.stdout, self.stderr
def assert_returncode_success(self):
from rich import print as pprint
+
if not self.p.returncode == 0:
pprint(safe_str(self.stderr))
- raise AssertionError(f'non 0 retcode:{self.p.returncode}')
+ raise AssertionError(f"non 0 retcode:{self.p.returncode}")
def assert_correct_output(self, stdout, version):
- assert b'UPGRADE FOR STEP %b COMPLETED' % safe_bytes(version) in stdout
+ assert b"UPGRADE FOR STEP %b COMPLETED" % safe_bytes(version) in stdout
def setup_rhodecode_db(self, ini_params=None, env=None):
if not ini_params:
ini_params = self._base_ini_config
ini_params.extend(self._db_url)
- with TestINI(self._base_ini_file, ini_params,
- self._type, destroy=True) as _ini_file:
-
+ with TestINI(self._base_ini_file, ini_params, self._type, destroy=True) as _ini_file:
if not os.path.isdir(self._repos_location):
os.makedirs(self._repos_location)
- if not os.path.isdir(self._repos_hg_largefiles_store):
- os.makedirs(self._repos_hg_largefiles_store)
- if not os.path.isdir(self._repos_git_lfs_store):
- os.makedirs(self._repos_git_lfs_store)
return self.execute(
"rc-setup-app {0} --user=marcink "
"--email=marcin@rhodeocode.com --password={1} "
- "--repos={2} --force-yes".format(
- _ini_file, 'qweqwe', self._repos_location), env=env)
+ "--repos={2} --force-yes".format(_ini_file, "qweqwe", self._repos_location),
+ env=env,
+ )
def upgrade_database(self, ini_params=None):
if not ini_params:
ini_params = self._base_ini_config
ini_params.extend(self._db_url)
- test_ini = TestINI(
- self._base_ini_file, ini_params, self._type, destroy=True)
+ test_ini = TestINI(self._base_ini_file, ini_params, self._type, destroy=True)
with test_ini as ini_file:
if not os.path.isdir(self._repos_location):
os.makedirs(self._repos_location)
- return self.execute(
- "rc-upgrade-db {0} --force-yes".format(ini_file))
+ return self.execute("rc-upgrade-db {0} --force-yes".format(ini_file))
def setup_db(self):
raise NotImplementedError
@@ -206,7 +182,7 @@ class DBBackend(object):
class EmptyDBBackend(DBBackend):
- _type = ''
+ _type = ""
def setup_db(self):
pass
@@ -222,21 +198,20 @@ class EmptyDBBackend(DBBackend):
class SQLiteDBBackend(DBBackend):
- _type = 'sqlite'
+ _type = "sqlite"
def get_default_connection_string(self):
- return 'sqlite:///{}/{}.sqlite'.format(self._basetemp, self.db_name)
+ return "sqlite:///{}/{}.sqlite".format(self._basetemp, self.db_name)
def setup_db(self):
# dump schema for tests
# cp -v $TEST_DB_NAME
- self._db_url = [{'app:main': {
- 'sqlalchemy.db1.url': self.connection_string}}]
+ self._db_url = [{"app:main": {"sqlalchemy.db1.url": self.connection_string}}]
def import_dump(self, dumpname):
dump = os.path.join(self.fixture_store, dumpname)
- target = os.path.join(self._basetemp, '{0.db_name}.sqlite'.format(self))
- return self.execute(f'cp -v {dump} {target}')
+ target = os.path.join(self._basetemp, "{0.db_name}.sqlite".format(self))
+ return self.execute(f"cp -v {dump} {target}")
def teardown_db(self):
target_db = os.path.join(self._basetemp, self.db_name)
@@ -244,39 +219,39 @@ class SQLiteDBBackend(DBBackend):
class MySQLDBBackend(DBBackend):
- _type = 'mysql'
+ _type = "mysql"
def get_default_connection_string(self):
- return 'mysql://root:qweqwe@127.0.0.1/{}'.format(self.db_name)
+ return "mysql://root:qweqwe@127.0.0.1/{}".format(self.db_name)
def setup_db(self):
# dump schema for tests
# mysqldump -uroot -pqweqwe $TEST_DB_NAME
- self._db_url = [{'app:main': {
- 'sqlalchemy.db1.url': self.connection_string}}]
- return self.execute("mysql -v -u{} -p{} -e 'create database '{}';'".format(
- self.user, self.password, self.db_name))
+ self._db_url = [{"app:main": {"sqlalchemy.db1.url": self.connection_string}}]
+ return self.execute(
+ "mysql -v -u{} -p{} -e 'create database '{}';'".format(self.user, self.password, self.db_name)
+ )
def import_dump(self, dumpname):
dump = os.path.join(self.fixture_store, dumpname)
- return self.execute("mysql -u{} -p{} {} < {}".format(
- self.user, self.password, self.db_name, dump))
+ return self.execute("mysql -u{} -p{} {} < {}".format(self.user, self.password, self.db_name, dump))
def teardown_db(self):
- return self.execute("mysql -v -u{} -p{} -e 'drop database '{}';'".format(
- self.user, self.password, self.db_name))
+ return self.execute(
+ "mysql -v -u{} -p{} -e 'drop database '{}';'".format(self.user, self.password, self.db_name)
+ )
class PostgresDBBackend(DBBackend):
- _type = 'postgres'
+ _type = "postgres"
def get_default_connection_string(self):
- return 'postgresql://postgres:qweqwe@localhost/{}'.format(self.db_name)
+ return "postgresql://postgres:qweqwe@localhost/{}".format(self.db_name)
def setup_db(self):
# dump schema for tests
# pg_dump -U postgres -h localhost $TEST_DB_NAME
- self._db_url = [{'app:main': {'sqlalchemy.db1.url': self.connection_string}}]
+ self._db_url = [{"app:main": {"sqlalchemy.db1.url": self.connection_string}}]
cmd = f"PGPASSWORD={self.password} psql -U {self.user} -h localhost -c 'create database '{self.db_name}';'"
return self.execute(cmd)
diff --git a/rhodecode/tests/database/test_creation.py b/rhodecode/tests/database/test_creation.py
index 23e13086..25ef7a98 100755
--- a/rhodecode/tests/database/test_creation.py
+++ b/rhodecode/tests/database/test_creation.py
@@ -1,4 +1,3 @@
-
# Copyright (C) 2010-2023 RhodeCode GmbH
#
# This program is free software: you can redistribute it and/or modify
diff --git a/rhodecode/tests/database/test_migration.py b/rhodecode/tests/database/test_migration.py
index f0d90748..9a199bdf 100644
--- a/rhodecode/tests/database/test_migration.py
+++ b/rhodecode/tests/database/test_migration.py
@@ -1,4 +1,3 @@
-
# Copyright (C) 2010-2023 RhodeCode GmbH
#
# This program is free software: you can redistribute it and/or modify
@@ -21,33 +20,42 @@ import pytest
@pytest.mark.dbs("postgres")
-@pytest.mark.parametrize("dumpname", [
- '1.4.4.sql',
- '1.5.0.sql',
- '1.6.0.sql',
- '1.6.0_no_repo_name_index.sql',
-])
+@pytest.mark.parametrize(
+ "dumpname",
+ [
+ "1.4.4.sql",
+ "1.5.0.sql",
+ "1.6.0.sql",
+ "1.6.0_no_repo_name_index.sql",
+ ],
+)
def test_migrate_postgres_db(db_backend, dumpname):
_run_migration_test(db_backend, dumpname)
@pytest.mark.dbs("sqlite")
-@pytest.mark.parametrize("dumpname", [
- 'rhodecode.1.4.4.sqlite',
- 'rhodecode.1.4.4_with_groups.sqlite',
- 'rhodecode.1.4.4_with_ldap_active.sqlite',
-])
+@pytest.mark.parametrize(
+ "dumpname",
+ [
+ "rhodecode.1.4.4.sqlite",
+ "rhodecode.1.4.4_with_groups.sqlite",
+ "rhodecode.1.4.4_with_ldap_active.sqlite",
+ ],
+)
def test_migrate_sqlite_db(db_backend, dumpname):
_run_migration_test(db_backend, dumpname)
@pytest.mark.dbs("mysql")
-@pytest.mark.parametrize("dumpname", [
- '1.4.4.sql',
- '1.5.0.sql',
- '1.6.0.sql',
- '1.6.0_no_repo_name_index.sql',
-])
+@pytest.mark.parametrize(
+ "dumpname",
+ [
+ "1.4.4.sql",
+ "1.5.0.sql",
+ "1.6.0.sql",
+ "1.6.0_no_repo_name_index.sql",
+ ],
+)
def test_migrate_mysql_db(db_backend, dumpname):
_run_migration_test(db_backend, dumpname)
@@ -60,5 +68,5 @@ def _run_migration_test(db_backend, dumpname):
db_backend.import_dump(dumpname)
stdout, stderr = db_backend.upgrade_database()
- db_backend.assert_correct_output(stdout+stderr, version='16')
+ db_backend.assert_correct_output(stdout + stderr, version="16")
db_backend.assert_returncode_success()
diff --git a/rhodecode/tests/fixture_mods/fixture_pyramid.py b/rhodecode/tests/fixture_mods/fixture_pyramid.py
deleted file mode 100644
index e90d7d5b..00000000
--- a/rhodecode/tests/fixture_mods/fixture_pyramid.py
+++ /dev/null
@@ -1,226 +0,0 @@
-
-# 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 .
-#
-# 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 pytest
-
-from rhodecode.lib.config_utils import get_app_config
-from rhodecode.tests.fixture import TestINI
-from rhodecode.tests import TESTS_TMP_PATH
-from rhodecode.tests.server_utils import RcVCSServer
-
-
-@pytest.fixture(scope='session')
-def vcsserver(request, vcsserver_port, vcsserver_factory):
- """
- Session scope VCSServer.
-
- Tests which need the VCSServer have to rely on this fixture in order
- to ensure it will be running.
-
- For specific needs, the fixture vcsserver_factory can be used. It allows to
- adjust the configuration file for the test run.
-
- Command line args:
-
- --without-vcsserver: Allows to switch this fixture off. You have to
- manually start the server.
-
- --vcsserver-port: Will expect the VCSServer to listen on this port.
- """
-
- if not request.config.getoption('with_vcsserver'):
- return None
-
- return vcsserver_factory(
- request, vcsserver_port=vcsserver_port)
-
-
-@pytest.fixture(scope='session')
-def vcsserver_factory(tmpdir_factory):
- """
- Use this if you need a running vcsserver with a special configuration.
- """
-
- def factory(request, overrides=(), vcsserver_port=None,
- log_file=None, workers='3'):
-
- if vcsserver_port is None:
- vcsserver_port = get_available_port()
-
- overrides = list(overrides)
- overrides.append({'server:main': {'port': vcsserver_port}})
-
- option_name = 'vcsserver_config_http'
- override_option_name = 'vcsserver_config_override'
- config_file = get_config(
- request.config, option_name=option_name,
- override_option_name=override_option_name, overrides=overrides,
- basetemp=tmpdir_factory.getbasetemp().strpath,
- prefix='test_vcs_')
-
- server = RcVCSServer(config_file, log_file, workers)
- server.start()
-
- @request.addfinalizer
- def cleanup():
- server.shutdown()
-
- server.wait_until_ready()
- return server
-
- return factory
-
-
-def _use_log_level(config):
- level = config.getoption('test_loglevel') or 'critical'
- return level.upper()
-
-
-@pytest.fixture(scope='session')
-def ini_config(request, tmpdir_factory, rcserver_port, vcsserver_port):
- option_name = 'pyramid_config'
- log_level = _use_log_level(request.config)
-
- overrides = [
- {'server:main': {'port': rcserver_port}},
- {'app:main': {
- 'cache_dir': '%(here)s/rc-tests/rc_data',
- 'vcs.server': f'localhost:{vcsserver_port}',
- # johbo: We will always start the VCSServer on our own based on the
- # fixtures of the test cases. For the test run it must always be
- # off in the INI file.
- 'vcs.start_server': 'false',
-
- 'vcs.server.protocol': 'http',
- 'vcs.scm_app_implementation': 'http',
- 'vcs.svn.proxy.enabled': 'true',
- 'vcs.hooks.protocol.v2': 'celery',
- 'vcs.hooks.host': '*',
- 'repo_store.path': TESTS_TMP_PATH,
- 'app.service_api.token': 'service_secret_token',
- }},
-
- {'handler_console': {
- 'class': 'StreamHandler',
- 'args': '(sys.stderr,)',
- 'level': log_level,
- }},
-
- ]
-
- filename = get_config(
- request.config, option_name=option_name,
- override_option_name='{}_override'.format(option_name),
- overrides=overrides,
- basetemp=tmpdir_factory.getbasetemp().strpath,
- prefix='test_rce_')
- return filename
-
-
-@pytest.fixture(scope='session')
-def ini_settings(ini_config):
- ini_path = ini_config
- return get_app_config(ini_path)
-
-
-def get_available_port(min_port=40000, max_port=55555):
- from rhodecode.lib.utils2 import get_available_port as _get_port
- return _get_port(min_port, max_port)
-
-
-@pytest.fixture(scope='session')
-def rcserver_port(request):
- port = get_available_port()
- print(f'Using rhodecode port {port}')
- return port
-
-
-@pytest.fixture(scope='session')
-def vcsserver_port(request):
- port = request.config.getoption('--vcsserver-port')
- if port is None:
- port = get_available_port()
- print(f'Using vcsserver port {port}')
- return port
-
-
-@pytest.fixture(scope='session')
-def available_port_factory() -> get_available_port:
- """
- Returns a callable which returns free port numbers.
- """
- return get_available_port
-
-
-@pytest.fixture()
-def available_port(available_port_factory):
- """
- Gives you one free port for the current test.
-
- Uses "available_port_factory" to retrieve the port.
- """
- return available_port_factory()
-
-
-@pytest.fixture(scope='session')
-def testini_factory(tmpdir_factory, ini_config):
- """
- Factory to create an INI file based on TestINI.
-
- It will make sure to place the INI file in the correct directory.
- """
- basetemp = tmpdir_factory.getbasetemp().strpath
- return TestIniFactory(basetemp, ini_config)
-
-
-class TestIniFactory(object):
-
- def __init__(self, basetemp, template_ini):
- self._basetemp = basetemp
- self._template_ini = template_ini
-
- def __call__(self, ini_params, new_file_prefix='test'):
- ini_file = TestINI(
- self._template_ini, ini_params=ini_params,
- new_file_prefix=new_file_prefix, dir=self._basetemp)
- result = ini_file.create()
- return result
-
-
-def get_config(
- config, option_name, override_option_name, overrides=None,
- basetemp=None, prefix='test'):
- """
- Find a configuration file and apply overrides for the given `prefix`.
- """
- config_file = (
- config.getoption(option_name) or config.getini(option_name))
- if not config_file:
- pytest.exit(
- "Configuration error, could not extract {}.".format(option_name))
-
- overrides = overrides or []
- config_override = config.getoption(override_option_name)
- if config_override:
- overrides.append(config_override)
- temp_ini_file = TestINI(
- config_file, ini_params=overrides, new_file_prefix=prefix,
- dir=basetemp)
-
- return temp_ini_file.create()
diff --git a/rhodecode/tests/fixture_mods/__init__.py b/rhodecode/tests/fixtures/__init__.py
similarity index 100%
rename from rhodecode/tests/fixture_mods/__init__.py
rename to rhodecode/tests/fixtures/__init__.py
diff --git a/rhodecode/tests/fixtures/diff_with_diff_data.diff b/rhodecode/tests/fixtures/diff_fixtures/diff_with_diff_data.diff
similarity index 100%
rename from rhodecode/tests/fixtures/diff_with_diff_data.diff
rename to rhodecode/tests/fixtures/diff_fixtures/diff_with_diff_data.diff
diff --git a/rhodecode/tests/fixtures/git_diff_binary_and_normal.diff b/rhodecode/tests/fixtures/diff_fixtures/git_diff_binary_and_normal.diff
similarity index 100%
rename from rhodecode/tests/fixtures/git_diff_binary_and_normal.diff
rename to rhodecode/tests/fixtures/diff_fixtures/git_diff_binary_and_normal.diff
diff --git a/rhodecode/tests/fixtures/git_diff_binary_special_files.diff b/rhodecode/tests/fixtures/diff_fixtures/git_diff_binary_special_files.diff
similarity index 100%
rename from rhodecode/tests/fixtures/git_diff_binary_special_files.diff
rename to rhodecode/tests/fixtures/diff_fixtures/git_diff_binary_special_files.diff
diff --git a/rhodecode/tests/fixtures/git_diff_binary_special_files_2.diff b/rhodecode/tests/fixtures/diff_fixtures/git_diff_binary_special_files_2.diff
similarity index 100%
rename from rhodecode/tests/fixtures/git_diff_binary_special_files_2.diff
rename to rhodecode/tests/fixtures/diff_fixtures/git_diff_binary_special_files_2.diff
diff --git a/rhodecode/tests/fixtures/git_diff_chmod.diff b/rhodecode/tests/fixtures/diff_fixtures/git_diff_chmod.diff
similarity index 100%
rename from rhodecode/tests/fixtures/git_diff_chmod.diff
rename to rhodecode/tests/fixtures/diff_fixtures/git_diff_chmod.diff
diff --git a/rhodecode/tests/fixtures/git_diff_js_chars.diff b/rhodecode/tests/fixtures/diff_fixtures/git_diff_js_chars.diff
similarity index 100%
rename from rhodecode/tests/fixtures/git_diff_js_chars.diff
rename to rhodecode/tests/fixtures/diff_fixtures/git_diff_js_chars.diff
diff --git a/rhodecode/tests/fixtures/git_diff_mod_single_binary_file.diff b/rhodecode/tests/fixtures/diff_fixtures/git_diff_mod_single_binary_file.diff
similarity index 100%
rename from rhodecode/tests/fixtures/git_diff_mod_single_binary_file.diff
rename to rhodecode/tests/fixtures/diff_fixtures/git_diff_mod_single_binary_file.diff
diff --git a/rhodecode/tests/fixtures/git_diff_rename_file.diff b/rhodecode/tests/fixtures/diff_fixtures/git_diff_rename_file.diff
similarity index 100%
rename from rhodecode/tests/fixtures/git_diff_rename_file.diff
rename to rhodecode/tests/fixtures/diff_fixtures/git_diff_rename_file.diff
diff --git a/rhodecode/tests/fixtures/git_diff_rename_file_with_spaces.diff b/rhodecode/tests/fixtures/diff_fixtures/git_diff_rename_file_with_spaces.diff
similarity index 100%
rename from rhodecode/tests/fixtures/git_diff_rename_file_with_spaces.diff
rename to rhodecode/tests/fixtures/diff_fixtures/git_diff_rename_file_with_spaces.diff
diff --git a/rhodecode/tests/fixtures/git_node_history_response.json b/rhodecode/tests/fixtures/diff_fixtures/git_node_history_response.json
similarity index 100%
rename from rhodecode/tests/fixtures/git_node_history_response.json
rename to rhodecode/tests/fixtures/diff_fixtures/git_node_history_response.json
diff --git a/rhodecode/tests/fixtures/hg_diff_add_single_binary_file.diff b/rhodecode/tests/fixtures/diff_fixtures/hg_diff_add_single_binary_file.diff
similarity index 100%
rename from rhodecode/tests/fixtures/hg_diff_add_single_binary_file.diff
rename to rhodecode/tests/fixtures/diff_fixtures/hg_diff_add_single_binary_file.diff
diff --git a/rhodecode/tests/fixtures/hg_diff_binary_and_normal.diff b/rhodecode/tests/fixtures/diff_fixtures/hg_diff_binary_and_normal.diff
similarity index 100%
rename from rhodecode/tests/fixtures/hg_diff_binary_and_normal.diff
rename to rhodecode/tests/fixtures/diff_fixtures/hg_diff_binary_and_normal.diff
diff --git a/rhodecode/tests/fixtures/hg_diff_chmod.diff b/rhodecode/tests/fixtures/diff_fixtures/hg_diff_chmod.diff
similarity index 100%
rename from rhodecode/tests/fixtures/hg_diff_chmod.diff
rename to rhodecode/tests/fixtures/diff_fixtures/hg_diff_chmod.diff
diff --git a/rhodecode/tests/fixtures/hg_diff_chmod_and_mod_single_binary_file.diff b/rhodecode/tests/fixtures/diff_fixtures/hg_diff_chmod_and_mod_single_binary_file.diff
similarity index 100%
rename from rhodecode/tests/fixtures/hg_diff_chmod_and_mod_single_binary_file.diff
rename to rhodecode/tests/fixtures/diff_fixtures/hg_diff_chmod_and_mod_single_binary_file.diff
diff --git a/rhodecode/tests/fixtures/hg_diff_copy_and_chmod_file.diff b/rhodecode/tests/fixtures/diff_fixtures/hg_diff_copy_and_chmod_file.diff
similarity index 100%
rename from rhodecode/tests/fixtures/hg_diff_copy_and_chmod_file.diff
rename to rhodecode/tests/fixtures/diff_fixtures/hg_diff_copy_and_chmod_file.diff
diff --git a/rhodecode/tests/fixtures/hg_diff_copy_and_modify_file.diff b/rhodecode/tests/fixtures/diff_fixtures/hg_diff_copy_and_modify_file.diff
similarity index 100%
rename from rhodecode/tests/fixtures/hg_diff_copy_and_modify_file.diff
rename to rhodecode/tests/fixtures/diff_fixtures/hg_diff_copy_and_modify_file.diff
diff --git a/rhodecode/tests/fixtures/hg_diff_copy_chmod_and_edit_file.diff b/rhodecode/tests/fixtures/diff_fixtures/hg_diff_copy_chmod_and_edit_file.diff
similarity index 100%
rename from rhodecode/tests/fixtures/hg_diff_copy_chmod_and_edit_file.diff
rename to rhodecode/tests/fixtures/diff_fixtures/hg_diff_copy_chmod_and_edit_file.diff
diff --git a/rhodecode/tests/fixtures/hg_diff_copy_file.diff b/rhodecode/tests/fixtures/diff_fixtures/hg_diff_copy_file.diff
similarity index 100%
rename from rhodecode/tests/fixtures/hg_diff_copy_file.diff
rename to rhodecode/tests/fixtures/diff_fixtures/hg_diff_copy_file.diff
diff --git a/rhodecode/tests/fixtures/hg_diff_copy_file_with_spaces.diff b/rhodecode/tests/fixtures/diff_fixtures/hg_diff_copy_file_with_spaces.diff
similarity index 100%
rename from rhodecode/tests/fixtures/hg_diff_copy_file_with_spaces.diff
rename to rhodecode/tests/fixtures/diff_fixtures/hg_diff_copy_file_with_spaces.diff
diff --git a/rhodecode/tests/fixtures/hg_diff_del_single_binary_file.diff b/rhodecode/tests/fixtures/diff_fixtures/hg_diff_del_single_binary_file.diff
similarity index 100%
rename from rhodecode/tests/fixtures/hg_diff_del_single_binary_file.diff
rename to rhodecode/tests/fixtures/diff_fixtures/hg_diff_del_single_binary_file.diff
diff --git a/rhodecode/tests/fixtures/hg_diff_double_file_change_double_newline.diff b/rhodecode/tests/fixtures/diff_fixtures/hg_diff_double_file_change_double_newline.diff
similarity index 100%
rename from rhodecode/tests/fixtures/hg_diff_double_file_change_double_newline.diff
rename to rhodecode/tests/fixtures/diff_fixtures/hg_diff_double_file_change_double_newline.diff
diff --git a/rhodecode/tests/fixtures/hg_diff_double_file_change_newline.diff b/rhodecode/tests/fixtures/diff_fixtures/hg_diff_double_file_change_newline.diff
similarity index 100%
rename from rhodecode/tests/fixtures/hg_diff_double_file_change_newline.diff
rename to rhodecode/tests/fixtures/diff_fixtures/hg_diff_double_file_change_newline.diff
diff --git a/rhodecode/tests/fixtures/hg_diff_four_file_change_newline.diff b/rhodecode/tests/fixtures/diff_fixtures/hg_diff_four_file_change_newline.diff
similarity index 100%
rename from rhodecode/tests/fixtures/hg_diff_four_file_change_newline.diff
rename to rhodecode/tests/fixtures/diff_fixtures/hg_diff_four_file_change_newline.diff
diff --git a/rhodecode/tests/fixtures/hg_diff_mixed_filename_encodings.diff b/rhodecode/tests/fixtures/diff_fixtures/hg_diff_mixed_filename_encodings.diff
similarity index 100%
rename from rhodecode/tests/fixtures/hg_diff_mixed_filename_encodings.diff
rename to rhodecode/tests/fixtures/diff_fixtures/hg_diff_mixed_filename_encodings.diff
diff --git a/rhodecode/tests/fixtures/hg_diff_mod_file_and_rename.diff b/rhodecode/tests/fixtures/diff_fixtures/hg_diff_mod_file_and_rename.diff
similarity index 100%
rename from rhodecode/tests/fixtures/hg_diff_mod_file_and_rename.diff
rename to rhodecode/tests/fixtures/diff_fixtures/hg_diff_mod_file_and_rename.diff
diff --git a/rhodecode/tests/fixtures/hg_diff_mod_single_binary_file.diff b/rhodecode/tests/fixtures/diff_fixtures/hg_diff_mod_single_binary_file.diff
similarity index 100%
rename from rhodecode/tests/fixtures/hg_diff_mod_single_binary_file.diff
rename to rhodecode/tests/fixtures/diff_fixtures/hg_diff_mod_single_binary_file.diff
diff --git a/rhodecode/tests/fixtures/hg_diff_mod_single_file_and_rename_and_chmod.diff b/rhodecode/tests/fixtures/diff_fixtures/hg_diff_mod_single_file_and_rename_and_chmod.diff
similarity index 100%
rename from rhodecode/tests/fixtures/hg_diff_mod_single_file_and_rename_and_chmod.diff
rename to rhodecode/tests/fixtures/diff_fixtures/hg_diff_mod_single_file_and_rename_and_chmod.diff
diff --git a/rhodecode/tests/fixtures/hg_diff_no_newline.diff b/rhodecode/tests/fixtures/diff_fixtures/hg_diff_no_newline.diff
similarity index 100%
rename from rhodecode/tests/fixtures/hg_diff_no_newline.diff
rename to rhodecode/tests/fixtures/diff_fixtures/hg_diff_no_newline.diff
diff --git a/rhodecode/tests/fixtures/hg_diff_rename_and_chmod_file.diff b/rhodecode/tests/fixtures/diff_fixtures/hg_diff_rename_and_chmod_file.diff
similarity index 100%
rename from rhodecode/tests/fixtures/hg_diff_rename_and_chmod_file.diff
rename to rhodecode/tests/fixtures/diff_fixtures/hg_diff_rename_and_chmod_file.diff
diff --git a/rhodecode/tests/fixtures/hg_diff_rename_file.diff b/rhodecode/tests/fixtures/diff_fixtures/hg_diff_rename_file.diff
similarity index 100%
rename from rhodecode/tests/fixtures/hg_diff_rename_file.diff
rename to rhodecode/tests/fixtures/diff_fixtures/hg_diff_rename_file.diff
diff --git a/rhodecode/tests/fixtures/hg_diff_rename_file_with_spaces.diff b/rhodecode/tests/fixtures/diff_fixtures/hg_diff_rename_file_with_spaces.diff
similarity index 100%
rename from rhodecode/tests/fixtures/hg_diff_rename_file_with_spaces.diff
rename to rhodecode/tests/fixtures/diff_fixtures/hg_diff_rename_file_with_spaces.diff
diff --git a/rhodecode/tests/fixtures/hg_diff_single_file_change_newline.diff b/rhodecode/tests/fixtures/diff_fixtures/hg_diff_single_file_change_newline.diff
similarity index 100%
rename from rhodecode/tests/fixtures/hg_diff_single_file_change_newline.diff
rename to rhodecode/tests/fixtures/diff_fixtures/hg_diff_single_file_change_newline.diff
diff --git a/rhodecode/tests/fixtures/hg_node_history_response.json b/rhodecode/tests/fixtures/diff_fixtures/hg_node_history_response.json
similarity index 100%
rename from rhodecode/tests/fixtures/hg_node_history_response.json
rename to rhodecode/tests/fixtures/diff_fixtures/hg_node_history_response.json
diff --git a/rhodecode/tests/fixtures/journal_dump.csv b/rhodecode/tests/fixtures/diff_fixtures/journal_dump.csv
similarity index 100%
rename from rhodecode/tests/fixtures/journal_dump.csv
rename to rhodecode/tests/fixtures/diff_fixtures/journal_dump.csv
diff --git a/rhodecode/tests/fixtures/large_diff.diff b/rhodecode/tests/fixtures/diff_fixtures/large_diff.diff
similarity index 100%
rename from rhodecode/tests/fixtures/large_diff.diff
rename to rhodecode/tests/fixtures/diff_fixtures/large_diff.diff
diff --git a/rhodecode/tests/fixtures/svn_diff_binary_add_file.diff b/rhodecode/tests/fixtures/diff_fixtures/svn_diff_binary_add_file.diff
similarity index 100%
rename from rhodecode/tests/fixtures/svn_diff_binary_add_file.diff
rename to rhodecode/tests/fixtures/diff_fixtures/svn_diff_binary_add_file.diff
diff --git a/rhodecode/tests/fixtures/svn_diff_multiple_changes.diff b/rhodecode/tests/fixtures/diff_fixtures/svn_diff_multiple_changes.diff
similarity index 100%
rename from rhodecode/tests/fixtures/svn_diff_multiple_changes.diff
rename to rhodecode/tests/fixtures/diff_fixtures/svn_diff_multiple_changes.diff
diff --git a/rhodecode/tests/fixtures/svn_node_history_branches.json b/rhodecode/tests/fixtures/diff_fixtures/svn_node_history_branches.json
similarity index 100%
rename from rhodecode/tests/fixtures/svn_node_history_branches.json
rename to rhodecode/tests/fixtures/diff_fixtures/svn_node_history_branches.json
diff --git a/rhodecode/tests/fixtures/svn_node_history_response.json b/rhodecode/tests/fixtures/diff_fixtures/svn_node_history_response.json
similarity index 100%
rename from rhodecode/tests/fixtures/svn_node_history_response.json
rename to rhodecode/tests/fixtures/diff_fixtures/svn_node_history_response.json
diff --git a/rhodecode/tests/fixtures/fixture_pyramid.py b/rhodecode/tests/fixtures/fixture_pyramid.py
new file mode 100644
index 00000000..26935325
--- /dev/null
+++ b/rhodecode/tests/fixtures/fixture_pyramid.py
@@ -0,0 +1,308 @@
+# 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 pytest
+
+from rhodecode.lib.config_utils import get_app_config
+from rhodecode.tests.fixtures.rc_fixture import TestINI
+from rhodecode.tests import TESTS_TMP_PATH
+from rhodecode.tests.server_utils import RcVCSServer
+from rhodecode.tests.server_utils import RcWebServer
+from rhodecode.tests.server_utils import CeleryServer
+
+
+@pytest.fixture(scope="session")
+def vcsserver_factory():
+ """
+ Use this if you need a running vcsserver with a special configuration.
+ """
+
+ def factory(request, store_dir, overrides=(), config_file=None, port=None, log_file=None, workers="3", env=None, info_prefix=""):
+ env = env or {"RC_NO_TEST_ENV": "1"}
+ vcsserver_port = port
+ if port is None:
+ vcsserver_port = get_available_port()
+
+ overrides = list(overrides)
+ overrides.append({"server:main": {"port": vcsserver_port}})
+
+ if getattr(request, 'param', None):
+ config_overrides = [request.param]
+ overrides.extend(config_overrides)
+
+ option_name = "vcsserver_config"
+ override_option_name = None
+ if not config_file:
+ config_file = get_config(
+ request.config,
+ option_name=option_name,
+ override_option_name=override_option_name,
+ overrides=overrides,
+ basetemp=store_dir,
+ prefix=f"{info_prefix}test_vcsserver_ini_",
+ )
+ server = RcVCSServer(config_file, log_file, workers, env=env, info_prefix=info_prefix)
+ server.start()
+
+ @request.addfinalizer
+ def cleanup():
+ server.shutdown()
+
+ server.wait_until_ready()
+ return server
+
+ return factory
+
+
+@pytest.fixture(scope="session")
+def rhodecode_factory():
+ def factory(request, store_dir, overrides=(), config_file=None, port=None, log_file=None, workers="3", env=None, info_prefix=""):
+ env = env or {"RC_NO_TEST_ENV": "1"}
+ rhodecode_port = port
+ if port is None:
+ rhodecode_port = get_available_port()
+
+ overrides = list(overrides)
+ overrides.append({"server:main": {"port": rhodecode_port}})
+ overrides.append({"app:main": {"use_celery": "true"}})
+ overrides.append({"app:main": {"celery.task_always_eager": "false"}})
+
+ if getattr(request, 'param', None):
+ config_overrides = [request.param]
+ overrides.extend(config_overrides)
+
+
+ option_name = "rhodecode_config"
+ override_option_name = None
+ if not config_file:
+ config_file = get_config(
+ request.config,
+ option_name=option_name,
+ override_option_name=override_option_name,
+ overrides=overrides,
+ basetemp=store_dir,
+ prefix=f"{info_prefix}test_rhodecode_ini",
+ )
+
+ server = RcWebServer(config_file, log_file, workers, env, info_prefix=info_prefix)
+ server.start()
+
+ @request.addfinalizer
+ def cleanup():
+ server.shutdown()
+
+ server.wait_until_ready()
+ return server
+
+ return factory
+
+
+@pytest.fixture(scope="session")
+def celery_factory():
+ def factory(request, store_dir, overrides=(), config_file=None, port=None, log_file=None, workers="3", env=None, info_prefix=""):
+ env = env or {"RC_NO_TEST_ENV": "1"}
+ rhodecode_port = port
+
+ overrides = list(overrides)
+ overrides.append({"app:main": {"use_celery": "true"}})
+ overrides.append({"app:main": {"celery.task_always_eager": "false"}})
+ config_overrides = None
+
+ if getattr(request, 'param', None):
+ config_overrides = [request.param]
+ overrides.extend(config_overrides)
+
+ option_name = "celery_config"
+ override_option_name = None
+
+ if not config_file:
+ config_file = get_config(
+ request.config,
+ option_name=option_name,
+ override_option_name=override_option_name,
+ overrides=overrides,
+ basetemp=store_dir,
+ prefix=f"{info_prefix}test_celery_ini_",
+ )
+
+ server = CeleryServer(config_file, log_file, workers, env, info_prefix=info_prefix)
+ server.start()
+
+ @request.addfinalizer
+ def cleanup():
+ server.shutdown()
+
+ server.wait_until_ready()
+ return server
+
+ return factory
+
+
+def _use_log_level(config):
+ level = config.getoption("test_loglevel") or "critical"
+ return level.upper()
+
+
+def _ini_config_factory(request, base_dir, rcserver_port, vcsserver_port):
+ option_name = "pyramid_config"
+ log_level = _use_log_level(request.config)
+
+ overrides = [
+ {"server:main": {"port": rcserver_port}},
+ {
+ "app:main": {
+ #'cache_dir': '%(here)s/rc-tests/rc_data',
+ "vcs.server": f"localhost:{vcsserver_port}",
+ # johbo: We will always start the VCSServer on our own based on the
+ # fixtures of the test cases. For the test run it must always be
+ # off in the INI file.
+ "vcs.start_server": "false",
+ "vcs.server.protocol": "http",
+ "vcs.scm_app_implementation": "http",
+ "vcs.svn.proxy.enabled": "true",
+ "vcs.hooks.protocol.v2": "celery",
+ "vcs.hooks.host": "*",
+ "repo_store.path": TESTS_TMP_PATH,
+ "app.service_api.token": "service_secret_token",
+ }
+ },
+ {
+ "handler_console": {
+ "class": "StreamHandler",
+ "args": "(sys.stderr,)",
+ "level": log_level,
+ }
+ },
+ ]
+
+ filename = get_config(
+ request.config,
+ option_name=option_name,
+ override_option_name=f"{option_name}_override",
+ overrides=overrides,
+ basetemp=base_dir,
+ prefix="test_rce_",
+ )
+ return filename
+
+
+@pytest.fixture(scope="session")
+def ini_config(request, tmpdir_factory, rcserver_port, vcsserver_port):
+ base_dir = tmpdir_factory.getbasetemp().strpath
+ return _ini_config_factory(request, base_dir, rcserver_port, vcsserver_port)
+
+
+@pytest.fixture(scope="session")
+def ini_config_factory(request, tmpdir_factory, rcserver_port, vcsserver_port):
+ def _factory(ini_config_basedir, overrides=()):
+ return _ini_config_factory(request, ini_config_basedir, rcserver_port, vcsserver_port)
+
+ return _factory
+
+
+@pytest.fixture(scope="session")
+def ini_settings(ini_config):
+ ini_path = ini_config
+ return get_app_config(ini_path)
+
+
+def get_available_port(min_port=40000, max_port=55555):
+ from rhodecode.lib.utils2 import get_available_port as _get_port
+
+ return _get_port(min_port, max_port)
+
+
+@pytest.fixture(scope="session")
+def rcserver_port(request):
+ port = get_available_port()
+ return port
+
+
+@pytest.fixture(scope="session")
+def vcsserver_port(request):
+ port = request.config.getoption("--vcsserver-port")
+ if port is None:
+ port = get_available_port()
+ return port
+
+
+@pytest.fixture(scope="session")
+def available_port_factory() -> get_available_port:
+ """
+ Returns a callable which returns free port numbers.
+ """
+ return get_available_port
+
+
+@pytest.fixture()
+def available_port(available_port_factory):
+ """
+ Gives you one free port for the current test.
+
+ Uses "available_port_factory" to retrieve the port.
+ """
+ return available_port_factory()
+
+
+@pytest.fixture(scope="session")
+def testini_factory(tmpdir_factory, ini_config):
+ """
+ Factory to create an INI file based on TestINI.
+
+ It will make sure to place the INI file in the correct directory.
+ """
+ basetemp = tmpdir_factory.getbasetemp().strpath
+ return TestIniFactory(basetemp, ini_config)
+
+
+class TestIniFactory(object):
+ def __init__(self, ini_store_dir, template_ini):
+ self._ini_store_dir = ini_store_dir
+ self._template_ini = template_ini
+
+ def __call__(self, ini_params, new_file_prefix="test"):
+ ini_file = TestINI(
+ self._template_ini, ini_params=ini_params, new_file_prefix=new_file_prefix, dir=self._ini_store_dir
+ )
+ result = ini_file.create()
+ return result
+
+
+def get_config(config, option_name, override_option_name, overrides=None, basetemp=None, prefix="test"):
+ """
+ Find a configuration file and apply overrides for the given `prefix`.
+ """
+ try:
+ config_file = config.getoption(option_name)
+ except ValueError:
+ config_file = None
+
+ if not config_file:
+ config_file = config.getini(option_name)
+
+ if not config_file:
+ pytest.exit(f"Configuration error, could not extract {option_name}.")
+
+ overrides = overrides or []
+ if override_option_name:
+ config_override = config.getoption(override_option_name)
+ if config_override:
+ overrides.append(config_override)
+ temp_ini_file = TestINI(config_file, ini_params=overrides, new_file_prefix=prefix, dir=basetemp)
+
+ return temp_ini_file.create()
diff --git a/rhodecode/tests/fixture_mods/fixture_utils.py b/rhodecode/tests/fixtures/fixture_utils.py
similarity index 69%
rename from rhodecode/tests/fixture_mods/fixture_utils.py
rename to rhodecode/tests/fixtures/fixture_utils.py
index 9b95ceeb..5caedd3f 100644
--- a/rhodecode/tests/fixture_mods/fixture_utils.py
+++ b/rhodecode/tests/fixtures/fixture_utils.py
@@ -1,5 +1,4 @@
-
-# Copyright (C) 2010-2023 RhodeCode GmbH
+# 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
@@ -30,6 +29,7 @@ import uuid
import dateutil.tz
import logging
import functools
+import textwrap
import mock
import pyramid.testing
@@ -43,8 +43,17 @@ import rhodecode.lib
from rhodecode.model.changeset_status import ChangesetStatusModel
from rhodecode.model.comment import CommentsModel
from rhodecode.model.db import (
- PullRequest, PullRequestReviewers, Repository, RhodeCodeSetting, ChangesetStatus,
- RepoGroup, UserGroup, RepoRhodeCodeUi, RepoRhodeCodeSetting, RhodeCodeUi)
+ PullRequest,
+ PullRequestReviewers,
+ Repository,
+ RhodeCodeSetting,
+ ChangesetStatus,
+ RepoGroup,
+ UserGroup,
+ RepoRhodeCodeUi,
+ RepoRhodeCodeSetting,
+ RhodeCodeUi,
+)
from rhodecode.model.meta import Session
from rhodecode.model.pull_request import PullRequestModel
from rhodecode.model.repo import RepoModel
@@ -60,12 +69,20 @@ from rhodecode.lib.str_utils import safe_bytes
from rhodecode.lib.hash_utils import sha1_safe
from rhodecode.lib.vcs.backends import get_backend
from rhodecode.lib.vcs.nodes import FileNode
+from rhodecode.lib.base import bootstrap_config
from rhodecode.tests import (
- login_user_session, get_new_dir, utils, TESTS_TMP_PATH,
- TEST_USER_ADMIN_LOGIN, TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR2_LOGIN,
- TEST_USER_REGULAR_PASS)
-from rhodecode.tests.utils import CustomTestApp, set_anonymous_access
-from rhodecode.tests.fixture import Fixture
+ login_user_session,
+ get_new_dir,
+ utils,
+ TESTS_TMP_PATH,
+ TEST_USER_ADMIN_LOGIN,
+ TEST_USER_REGULAR_LOGIN,
+ TEST_USER_REGULAR2_LOGIN,
+ TEST_USER_REGULAR_PASS,
+ console_printer,
+)
+from rhodecode.tests.utils import set_anonymous_access
+from rhodecode.tests.fixtures.rc_fixture import Fixture
from rhodecode.config import utils as config_utils
log = logging.getLogger(__name__)
@@ -76,36 +93,7 @@ def cmp(a, b):
return (a > b) - (a < b)
-@pytest.fixture(scope='session', autouse=True)
-def activate_example_rcextensions(request):
- """
- Patch in an example rcextensions module which verifies passed in kwargs.
- """
- from rhodecode.config import rcextensions
-
- old_extensions = rhodecode.EXTENSIONS
- rhodecode.EXTENSIONS = rcextensions
- rhodecode.EXTENSIONS.calls = collections.defaultdict(list)
-
- @request.addfinalizer
- def cleanup():
- rhodecode.EXTENSIONS = old_extensions
-
-
-@pytest.fixture()
-def capture_rcextensions():
- """
- Returns the recorded calls to entry points in rcextensions.
- """
- calls = rhodecode.EXTENSIONS.calls
- calls.clear()
- # Note: At this moment, it is still the empty dict, but that will
- # be filled during the test run and since it is a reference this
- # is enough to make it work.
- return calls
-
-
-@pytest.fixture(scope='session')
+@pytest.fixture(scope="session")
def http_environ_session():
"""
Allow to use "http_environ" in session scope.
@@ -117,7 +105,31 @@ def plain_http_host_stub():
"""
Value of HTTP_HOST in the test run.
"""
- return 'example.com:80'
+ return "example.com:80"
+
+
+def plain_config_stub(request, request_stub):
+ """
+ Set up pyramid.testing and return the Configurator.
+ """
+
+ config = bootstrap_config(request=request_stub)
+
+ @request.addfinalizer
+ def cleanup():
+ pyramid.testing.tearDown()
+
+ return config
+
+
+def plain_request_stub():
+ """
+ Stub request object.
+ """
+ from rhodecode.lib.base import bootstrap_request
+
+ _request = bootstrap_request(scheme="https")
+ return _request
@pytest.fixture()
@@ -132,7 +144,7 @@ def plain_http_host_only_stub():
"""
Value of HTTP_HOST in the test run.
"""
- return plain_http_host_stub().split(':')[0]
+ return plain_http_host_stub().split(":")[0]
@pytest.fixture()
@@ -147,33 +159,21 @@ def plain_http_environ():
"""
HTTP extra environ keys.
- User by the test application and as well for setting up the pylons
+ Used by the test application and as well for setting up the pylons
environment. In the case of the fixture "app" it should be possible
to override this for a specific test case.
"""
return {
- 'SERVER_NAME': plain_http_host_only_stub(),
- 'SERVER_PORT': plain_http_host_stub().split(':')[1],
- 'HTTP_HOST': plain_http_host_stub(),
- 'HTTP_USER_AGENT': 'rc-test-agent',
- 'REQUEST_METHOD': 'GET'
+ "SERVER_NAME": plain_http_host_only_stub(),
+ "SERVER_PORT": plain_http_host_stub().split(":")[1],
+ "HTTP_HOST": plain_http_host_stub(),
+ "HTTP_USER_AGENT": "rc-test-agent",
+ "REQUEST_METHOD": "GET",
}
-@pytest.fixture()
-def http_environ():
- """
- HTTP extra environ keys.
-
- User by the test application and as well for setting up the pylons
- environment. In the case of the fixture "app" it should be possible
- to override this for a specific test case.
- """
- return plain_http_environ()
-
-
-@pytest.fixture(scope='session')
-def baseapp(ini_config, vcsserver, http_environ_session):
+@pytest.fixture(scope="session")
+def baseapp(request, ini_config, http_environ_session, available_port_factory, vcsserver_factory, celery_factory):
from rhodecode.lib.config_utils import get_app_config
from rhodecode.config.middleware import make_pyramid_app
@@ -181,22 +181,41 @@ def baseapp(ini_config, vcsserver, http_environ_session):
pyramid.paster.setup_logging(ini_config)
settings = get_app_config(ini_config)
- app = make_pyramid_app({'__file__': ini_config}, **settings)
+ store_dir = os.path.dirname(ini_config)
- return app
+ # start vcsserver
+ _vcsserver_port = available_port_factory()
+ vcsserver_instance = vcsserver_factory(
+ request,
+ store_dir=store_dir,
+ port=_vcsserver_port,
+ info_prefix="base-app-"
+ )
+
+ settings["vcs.server"] = vcsserver_instance.bind_addr
+
+ # we skip setting store_dir for baseapp, it's internally set via testing rhodecode.ini
+ # settings['repo_store.path'] = str(store_dir)
+ console_printer(f' :warning: [green]pytest-setup[/green] Starting base pyramid-app: {ini_config}')
+ pyramid_baseapp = make_pyramid_app({"__file__": ini_config}, **settings)
+
+ # start celery
+ celery_factory(
+ request,
+ store_dir=store_dir,
+ port=None,
+ info_prefix="base-app-",
+ overrides=(
+ {'handler_console': {'level': 'DEBUG'}},
+ {'app:main': {'vcs.server': vcsserver_instance.bind_addr}},
+ {'app:main': {'repo_store.path': store_dir}}
+ )
+ )
+
+ return pyramid_baseapp
-@pytest.fixture(scope='function')
-def app(request, config_stub, baseapp, http_environ):
- app = CustomTestApp(
- baseapp,
- extra_environ=http_environ)
- if request.cls:
- request.cls.app = app
- return app
-
-
-@pytest.fixture(scope='session')
+@pytest.fixture(scope="session")
def app_settings(baseapp, ini_config):
"""
Settings dictionary used to create the app.
@@ -207,19 +226,19 @@ def app_settings(baseapp, ini_config):
return baseapp.config.get_settings()
-@pytest.fixture(scope='session')
+@pytest.fixture(scope="session")
def db_connection(ini_settings):
# Initialize the database connection.
config_utils.initialize_database(ini_settings)
-LoginData = collections.namedtuple('LoginData', ('csrf_token', 'user'))
+LoginData = collections.namedtuple("LoginData", ("csrf_token", "user"))
def _autologin_user(app, *args):
session = login_user_session(app, *args)
csrf_token = rhodecode.lib.auth.get_csrf_token(session)
- return LoginData(csrf_token, session['rhodecode_user'])
+ return LoginData(csrf_token, session["rhodecode_user"])
@pytest.fixture()
@@ -235,18 +254,17 @@ def autologin_regular_user(app):
"""
Utility fixture which makes sure that the regular user is logged in
"""
- return _autologin_user(
- app, TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS)
+ return _autologin_user(app, TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS)
-@pytest.fixture(scope='function')
+@pytest.fixture(scope="function")
def csrf_token(request, autologin_user):
return autologin_user.csrf_token
-@pytest.fixture(scope='function')
+@pytest.fixture(scope="function")
def xhr_header(request):
- return {'HTTP_X_REQUESTED_WITH': 'XMLHttpRequest'}
+ return {"HTTP_X_REQUESTED_WITH": "XMLHttpRequest"}
@pytest.fixture()
@@ -257,18 +275,18 @@ def real_crypto_backend(monkeypatch):
During the test run the crypto backend is replaced with a faster
implementation based on the MD5 algorithm.
"""
- monkeypatch.setattr(rhodecode, 'is_test', False)
+ monkeypatch.setattr(rhodecode, "is_test", False)
-@pytest.fixture(scope='class')
+@pytest.fixture(scope="class")
def index_location(request, baseapp):
- index_location = baseapp.config.get_settings()['search.location']
+ index_location = baseapp.config.get_settings()["search.location"]
if request.cls:
request.cls.index_location = index_location
return index_location
-@pytest.fixture(scope='session', autouse=True)
+@pytest.fixture(scope="session", autouse=True)
def tests_tmp_path(request):
"""
Create temporary directory to be used during the test session.
@@ -276,7 +294,8 @@ def tests_tmp_path(request):
if not os.path.exists(TESTS_TMP_PATH):
os.makedirs(TESTS_TMP_PATH)
- if not request.config.getoption('--keep-tmp-path'):
+ if not request.config.getoption("--keep-tmp-path"):
+
@request.addfinalizer
def remove_tmp_path():
shutil.rmtree(TESTS_TMP_PATH)
@@ -291,7 +310,7 @@ def test_repo_group(request):
usage automatically
"""
fixture = Fixture()
- repogroupid = 'test_repo_group_%s' % str(time.time()).replace('.', '')
+ repogroupid = "test_repo_group_%s" % str(time.time()).replace(".", "")
repo_group = fixture.create_repo_group(repogroupid)
def _cleanup():
@@ -308,7 +327,7 @@ def test_user_group(request):
usage automatically
"""
fixture = Fixture()
- usergroupid = 'test_user_group_%s' % str(time.time()).replace('.', '')
+ usergroupid = "test_user_group_%s" % str(time.time()).replace(".", "")
user_group = fixture.create_user_group(usergroupid)
def _cleanup():
@@ -318,7 +337,7 @@ def test_user_group(request):
return user_group
-@pytest.fixture(scope='session')
+@pytest.fixture(scope="session")
def test_repo(request):
container = TestRepoContainer()
request.addfinalizer(container._cleanup)
@@ -340,9 +359,9 @@ class TestRepoContainer(object):
"""
dump_extractors = {
- 'git': utils.extract_git_repo_from_dump,
- 'hg': utils.extract_hg_repo_from_dump,
- 'svn': utils.extract_svn_repo_from_dump,
+ "git": utils.extract_git_repo_from_dump,
+ "hg": utils.extract_hg_repo_from_dump,
+ "svn": utils.extract_svn_repo_from_dump,
}
def __init__(self):
@@ -358,7 +377,7 @@ class TestRepoContainer(object):
return Repository.get(self._repos[key])
def _create_repo(self, dump_name, backend_alias, config):
- repo_name = f'{backend_alias}-{dump_name}'
+ repo_name = f"{backend_alias}-{dump_name}"
backend = get_backend(backend_alias)
dump_extractor = self.dump_extractors[backend_alias]
repo_path = dump_extractor(dump_name, repo_name)
@@ -375,19 +394,17 @@ class TestRepoContainer(object):
self._fixture.destroy_repo(repo_name)
-def backend_base(request, backend_alias, baseapp, test_repo):
- if backend_alias not in request.config.getoption('--backends'):
- pytest.skip("Backend %s not selected." % (backend_alias, ))
+def backend_base(request, backend_alias, test_repo):
+ if backend_alias not in request.config.getoption("--backends"):
+ pytest.skip(f"Backend {backend_alias} not selected.")
utils.check_xfail_backends(request.node, backend_alias)
utils.check_skip_backends(request.node, backend_alias)
- repo_name = 'vcs_test_%s' % (backend_alias, )
+ repo_name = "vcs_test_%s" % (backend_alias,)
backend = Backend(
- alias=backend_alias,
- repo_name=repo_name,
- test_name=request.node.name,
- test_repo_container=test_repo)
+ alias=backend_alias, repo_name=repo_name, test_name=request.node.name, test_repo_container=test_repo
+ )
request.addfinalizer(backend.cleanup)
return backend
@@ -404,22 +421,22 @@ def backend(request, backend_alias, baseapp, test_repo):
for specific backends. This is intended as a utility for incremental
development of a new backend implementation.
"""
- return backend_base(request, backend_alias, baseapp, test_repo)
+ return backend_base(request, backend_alias, test_repo)
@pytest.fixture()
def backend_git(request, baseapp, test_repo):
- return backend_base(request, 'git', baseapp, test_repo)
+ return backend_base(request, "git", test_repo)
@pytest.fixture()
def backend_hg(request, baseapp, test_repo):
- return backend_base(request, 'hg', baseapp, test_repo)
+ return backend_base(request, "hg", test_repo)
@pytest.fixture()
def backend_svn(request, baseapp, test_repo):
- return backend_base(request, 'svn', baseapp, test_repo)
+ return backend_base(request, "svn", test_repo)
@pytest.fixture()
@@ -467,9 +484,9 @@ class Backend(object):
session.
"""
- invalid_repo_name = re.compile(r'[^0-9a-zA-Z]+')
+ invalid_repo_name = re.compile(r"[^0-9a-zA-Z]+")
_master_repo = None
- _master_repo_path = ''
+ _master_repo_path = ""
_commit_ids = {}
def __init__(self, alias, repo_name, test_name, test_repo_container):
@@ -500,6 +517,7 @@ class Backend(object):
last repo which has been created with `create_repo`.
"""
from rhodecode.model.db import Repository
+
return Repository.get_by_repo_name(self.repo_name)
@property
@@ -517,9 +535,7 @@ class Backend(object):
which can serve as the base to create a new commit on top of it.
"""
vcsrepo = self.repo.scm_instance()
- head_id = (
- vcsrepo.DEFAULT_BRANCH_NAME or
- vcsrepo.commit_ids[-1])
+ head_id = vcsrepo.DEFAULT_BRANCH_NAME or vcsrepo.commit_ids[-1]
return head_id
@property
@@ -543,9 +559,7 @@ class Backend(object):
return self._commit_ids
- def create_repo(
- self, commits=None, number_of_commits=0, heads=None,
- name_suffix='', bare=False, **kwargs):
+ def create_repo(self, commits=None, number_of_commits=0, heads=None, name_suffix="", bare=False, **kwargs):
"""
Create a repository and record it for later cleanup.
@@ -559,13 +573,10 @@ class Backend(object):
:param bare: set a repo as bare (no checkout)
"""
self.repo_name = self._next_repo_name() + name_suffix
- repo = self._fixture.create_repo(
- self.repo_name, repo_type=self.alias, bare=bare, **kwargs)
+ repo = self._fixture.create_repo(self.repo_name, repo_type=self.alias, bare=bare, **kwargs)
self._cleanup_repos.append(repo.repo_name)
- commits = commits or [
- {'message': f'Commit {x} of {self.repo_name}'}
- for x in range(number_of_commits)]
+ commits = commits or [{"message": f"Commit {x} of {self.repo_name}"} for x in range(number_of_commits)]
vcs_repo = repo.scm_instance()
vcs_repo.count()
self._add_commits_to_repo(vcs_repo, commits)
@@ -579,7 +590,7 @@ class Backend(object):
Make sure that repo contains all commits mentioned in `heads`
"""
vcsrepo = repo.scm_instance()
- vcsrepo.config.clear_section('hooks')
+ vcsrepo.config.clear_section("hooks")
commit_ids = [self._commit_ids[h] for h in heads]
if do_fetch:
vcsrepo.fetch(self._master_repo_path, commit_ids=commit_ids)
@@ -592,21 +603,22 @@ class Backend(object):
self._cleanup_repos.append(self.repo_name)
return repo
- def new_repo_name(self, suffix=''):
+ def new_repo_name(self, suffix=""):
self.repo_name = self._next_repo_name() + suffix
self._cleanup_repos.append(self.repo_name)
return self.repo_name
def _next_repo_name(self):
- return "%s_%s" % (
- self.invalid_repo_name.sub('_', self._test_name), len(self._cleanup_repos))
+ return "%s_%s" % (self.invalid_repo_name.sub("_", self._test_name), len(self._cleanup_repos))
- def ensure_file(self, filename, content=b'Test content\n'):
+ def ensure_file(self, filename, content=b"Test content\n"):
assert self._cleanup_repos, "Avoid writing into vcs_test repos"
commits = [
- {'added': [
- FileNode(filename, content=content),
- ]},
+ {
+ "added": [
+ FileNode(filename, content=content),
+ ]
+ },
]
self._add_commits_to_repo(self.repo.scm_instance(), commits)
@@ -627,11 +639,11 @@ class Backend(object):
self._commit_ids = commit_ids
# Creating refs for Git to allow fetching them from remote repository
- if self.alias == 'git':
+ if self.alias == "git":
refs = {}
for message in self._commit_ids:
- cleanup_message = message.replace(' ', '')
- ref_name = f'refs/test-refs/{cleanup_message}'
+ cleanup_message = message.replace(" ", "")
+ ref_name = f"refs/test-refs/{cleanup_message}"
refs[ref_name] = self._commit_ids[message]
self._create_refs(repo, refs)
@@ -645,7 +657,7 @@ class VcsBackend(object):
Represents the test configuration for one supported vcs backend.
"""
- invalid_repo_name = re.compile(r'[^0-9a-zA-Z]+')
+ invalid_repo_name = re.compile(r"[^0-9a-zA-Z]+")
def __init__(self, alias, repo_path, test_name, test_repo_container):
self.alias = alias
@@ -658,7 +670,7 @@ class VcsBackend(object):
return self._test_repo_container(key, self.alias).scm_instance()
def __repr__(self):
- return f'{self.__class__.__name__}(alias={self.alias}, repo={self._repo_path})'
+ return f"{self.__class__.__name__}(alias={self.alias}, repo={self._repo_path})"
@property
def repo(self):
@@ -676,8 +688,7 @@ class VcsBackend(object):
"""
return get_backend(self.alias)
- def create_repo(self, commits=None, number_of_commits=0, _clone_repo=None,
- bare=False):
+ def create_repo(self, commits=None, number_of_commits=0, _clone_repo=None, bare=False):
repo_name = self._next_repo_name()
self._repo_path = get_new_dir(repo_name)
repo_class = get_backend(self.alias)
@@ -687,9 +698,7 @@ class VcsBackend(object):
repo = repo_class(self._repo_path, create=True, src_url=src_url, bare=bare)
self._cleanup_repos.append(repo)
- commits = commits or [
- {'message': 'Commit %s of %s' % (x, repo_name)}
- for x in range(number_of_commits)]
+ commits = commits or [{"message": "Commit %s of %s" % (x, repo_name)} for x in range(number_of_commits)]
_add_commits_to_repo(repo, commits)
return repo
@@ -706,38 +715,30 @@ class VcsBackend(object):
return self._repo_path
def _next_repo_name(self):
+ return "{}_{}".format(self.invalid_repo_name.sub("_", self._test_name), len(self._cleanup_repos))
- return "{}_{}".format(
- self.invalid_repo_name.sub('_', self._test_name),
- len(self._cleanup_repos)
- )
-
- def add_file(self, repo, filename, content='Test content\n'):
+ def add_file(self, repo, filename, content="Test content\n"):
imc = repo.in_memory_commit
imc.add(FileNode(safe_bytes(filename), content=safe_bytes(content)))
- imc.commit(
- message='Automatic commit from vcsbackend fixture',
- author='Automatic ')
+ imc.commit(message="Automatic commit from vcsbackend fixture", author="Automatic ")
- def ensure_file(self, filename, content='Test content\n'):
+ def ensure_file(self, filename, content="Test content\n"):
assert self._cleanup_repos, "Avoid writing into vcs_test repos"
self.add_file(self.repo, filename, content)
def vcsbackend_base(request, backend_alias, tests_tmp_path, baseapp, test_repo) -> VcsBackend:
- if backend_alias not in request.config.getoption('--backends'):
- pytest.skip("Backend %s not selected." % (backend_alias, ))
+ if backend_alias not in request.config.getoption("--backends"):
+ pytest.skip("Backend %s not selected." % (backend_alias,))
utils.check_xfail_backends(request.node, backend_alias)
utils.check_skip_backends(request.node, backend_alias)
- repo_name = f'vcs_test_{backend_alias}'
+ repo_name = f"vcs_test_{backend_alias}"
repo_path = os.path.join(tests_tmp_path, repo_name)
backend = VcsBackend(
- alias=backend_alias,
- repo_path=repo_path,
- test_name=request.node.name,
- test_repo_container=test_repo)
+ alias=backend_alias, repo_path=repo_path, test_name=request.node.name, test_repo_container=test_repo
+ )
request.addfinalizer(backend.cleanup)
return backend
@@ -758,17 +759,17 @@ def vcsbackend(request, backend_alias, tests_tmp_path, baseapp, test_repo):
@pytest.fixture()
def vcsbackend_git(request, tests_tmp_path, baseapp, test_repo):
- return vcsbackend_base(request, 'git', tests_tmp_path, baseapp, test_repo)
+ return vcsbackend_base(request, "git", tests_tmp_path, baseapp, test_repo)
@pytest.fixture()
def vcsbackend_hg(request, tests_tmp_path, baseapp, test_repo):
- return vcsbackend_base(request, 'hg', tests_tmp_path, baseapp, test_repo)
+ return vcsbackend_base(request, "hg", tests_tmp_path, baseapp, test_repo)
@pytest.fixture()
def vcsbackend_svn(request, tests_tmp_path, baseapp, test_repo):
- return vcsbackend_base(request, 'svn', tests_tmp_path, baseapp, test_repo)
+ return vcsbackend_base(request, "svn", tests_tmp_path, baseapp, test_repo)
@pytest.fixture()
@@ -789,29 +790,28 @@ def _add_commits_to_repo(vcs_repo, commits):
imc = vcs_repo.in_memory_commit
for idx, commit in enumerate(commits):
- message = str(commit.get('message', f'Commit {idx}'))
+ message = str(commit.get("message", f"Commit {idx}"))
- for node in commit.get('added', []):
+ for node in commit.get("added", []):
imc.add(FileNode(safe_bytes(node.path), content=node.content))
- for node in commit.get('changed', []):
+ for node in commit.get("changed", []):
imc.change(FileNode(safe_bytes(node.path), content=node.content))
- for node in commit.get('removed', []):
+ for node in commit.get("removed", []):
imc.remove(FileNode(safe_bytes(node.path)))
- parents = [
- vcs_repo.get_commit(commit_id=commit_ids[p])
- for p in commit.get('parents', [])]
+ parents = [vcs_repo.get_commit(commit_id=commit_ids[p]) for p in commit.get("parents", [])]
- operations = ('added', 'changed', 'removed')
+ operations = ("added", "changed", "removed")
if not any((commit.get(o) for o in operations)):
- imc.add(FileNode(b'file_%b' % safe_bytes(str(idx)), content=safe_bytes(message)))
+ imc.add(FileNode(b"file_%b" % safe_bytes(str(idx)), content=safe_bytes(message)))
commit = imc.commit(
message=message,
- author=str(commit.get('author', 'Automatic ')),
- date=commit.get('date'),
- branch=commit.get('branch'),
- parents=parents)
+ author=str(commit.get("author", "Automatic ")),
+ date=commit.get("date"),
+ branch=commit.get("branch"),
+ parents=parents,
+ )
commit_ids[commit.message] = commit.raw_id
@@ -842,14 +842,14 @@ class RepoServer(object):
self._cleanup_servers = []
def serve(self, vcsrepo):
- if vcsrepo.alias != 'svn':
+ if vcsrepo.alias != "svn":
raise TypeError("Backend %s not supported" % vcsrepo.alias)
proc = subprocess.Popen(
- ['svnserve', '-d', '--foreground', '--listen-host', 'localhost',
- '--root', vcsrepo.path])
+ ["svnserve", "-d", "--foreground", "--listen-host", "localhost", "--root", vcsrepo.path]
+ )
self._cleanup_servers.append(proc)
- self.url = 'svn://localhost'
+ self.url = "svn://localhost"
def cleanup(self):
for proc in self._cleanup_servers:
@@ -874,7 +874,6 @@ def pr_util(backend, request, config_stub):
class PRTestUtility(object):
-
pull_request = None
pull_request_id = None
mergeable_patcher = None
@@ -886,48 +885,55 @@ class PRTestUtility(object):
self.backend = backend
def create_pull_request(
- self, commits=None, target_head=None, source_head=None,
- revisions=None, approved=False, author=None, mergeable=False,
- enable_notifications=True, name_suffix='', reviewers=None, observers=None,
- title="Test", description="Description"):
+ self,
+ commits=None,
+ target_head=None,
+ source_head=None,
+ revisions=None,
+ approved=False,
+ author=None,
+ mergeable=False,
+ enable_notifications=True,
+ name_suffix="",
+ reviewers=None,
+ observers=None,
+ title="Test",
+ description="Description",
+ ):
self.set_mergeable(mergeable)
if not enable_notifications:
# mock notification side effect
- self.notification_patcher = mock.patch(
- 'rhodecode.model.notification.NotificationModel.create')
+ self.notification_patcher = mock.patch("rhodecode.model.notification.NotificationModel.create")
self.notification_patcher.start()
if not self.pull_request:
if not commits:
commits = [
- {'message': 'c1'},
- {'message': 'c2'},
- {'message': 'c3'},
+ {"message": "c1"},
+ {"message": "c2"},
+ {"message": "c3"},
]
- target_head = 'c1'
- source_head = 'c2'
- revisions = ['c2']
+ target_head = "c1"
+ source_head = "c2"
+ revisions = ["c2"]
self.commit_ids = self.backend.create_master_repo(commits)
- self.target_repository = self.backend.create_repo(
- heads=[target_head], name_suffix=name_suffix)
- self.source_repository = self.backend.create_repo(
- heads=[source_head], name_suffix=name_suffix)
- self.author = author or UserModel().get_by_username(
- TEST_USER_ADMIN_LOGIN)
+ self.target_repository = self.backend.create_repo(heads=[target_head], name_suffix=name_suffix)
+ self.source_repository = self.backend.create_repo(heads=[source_head], name_suffix=name_suffix)
+ self.author = author or UserModel().get_by_username(TEST_USER_ADMIN_LOGIN)
model = PullRequestModel()
self.create_parameters = {
- 'created_by': self.author,
- 'source_repo': self.source_repository.repo_name,
- 'source_ref': self._default_branch_reference(source_head),
- 'target_repo': self.target_repository.repo_name,
- 'target_ref': self._default_branch_reference(target_head),
- 'revisions': [self.commit_ids[r] for r in revisions],
- 'reviewers': reviewers or self._get_reviewers(),
- 'observers': observers or self._get_observers(),
- 'title': title,
- 'description': description,
+ "created_by": self.author,
+ "source_repo": self.source_repository.repo_name,
+ "source_ref": self._default_branch_reference(source_head),
+ "target_repo": self.target_repository.repo_name,
+ "target_ref": self._default_branch_reference(target_head),
+ "revisions": [self.commit_ids[r] for r in revisions],
+ "reviewers": reviewers or self._get_reviewers(),
+ "observers": observers or self._get_observers(),
+ "title": title,
+ "description": description,
}
self.pull_request = model.create(**self.create_parameters)
assert model.get_versions(self.pull_request) == []
@@ -943,9 +949,7 @@ class PRTestUtility(object):
return self.pull_request
def approve(self):
- self.create_status_votes(
- ChangesetStatus.STATUS_APPROVED,
- *self.pull_request.reviewers)
+ self.create_status_votes(ChangesetStatus.STATUS_APPROVED, *self.pull_request.reviewers)
def close(self):
PullRequestModel().close_pull_request(self.pull_request, self.author)
@@ -953,28 +957,26 @@ class PRTestUtility(object):
def _default_branch_reference(self, commit_message, branch: str = None) -> str:
default_branch = branch or self.backend.default_branch_name
message = self.commit_ids[commit_message]
- reference = f'branch:{default_branch}:{message}'
+ reference = f"branch:{default_branch}:{message}"
return reference
def _get_reviewers(self):
role = PullRequestReviewers.ROLE_REVIEWER
return [
- (TEST_USER_REGULAR_LOGIN, ['default1'], False, role, []),
- (TEST_USER_REGULAR2_LOGIN, ['default2'], False, role, []),
+ (TEST_USER_REGULAR_LOGIN, ["default1"], False, role, []),
+ (TEST_USER_REGULAR2_LOGIN, ["default2"], False, role, []),
]
def _get_observers(self):
- return [
-
- ]
+ return []
def update_source_repository(self, head=None, do_fetch=False):
- heads = [head or 'c3']
+ heads = [head or "c3"]
self.backend.pull_heads(self.source_repository, heads=heads, do_fetch=do_fetch)
def update_target_repository(self, head=None, do_fetch=False):
- heads = [head or 'c3']
+ heads = [head or "c3"]
self.backend.pull_heads(self.target_repository, heads=heads, do_fetch=do_fetch)
def set_pr_target_ref(self, ref_type: str = "branch", ref_name: str = "branch", ref_commit_id: str = "") -> str:
@@ -1004,7 +1006,7 @@ class PRTestUtility(object):
# TODO: johbo: Git and Mercurial have an inconsistent vcs api here,
# remove the if once that's sorted out.
if self.backend.alias == "git":
- kwargs = {'branch_name': self.backend.default_branch_name}
+ kwargs = {"branch_name": self.backend.default_branch_name}
else:
kwargs = {}
source_vcs.strip(removed_commit_id, **kwargs)
@@ -1015,10 +1017,8 @@ class PRTestUtility(object):
def create_comment(self, linked_to=None):
comment = CommentsModel().create(
- text="Test comment",
- repo=self.target_repository.repo_name,
- user=self.author,
- pull_request=self.pull_request)
+ text="Test comment", repo=self.target_repository.repo_name, user=self.author, pull_request=self.pull_request
+ )
assert comment.pull_request_version_id is None
if linked_to:
@@ -1026,15 +1026,15 @@ class PRTestUtility(object):
return comment
- def create_inline_comment(
- self, linked_to=None, line_no='n1', file_path='file_1'):
+ def create_inline_comment(self, linked_to=None, line_no="n1", file_path="file_1"):
comment = CommentsModel().create(
text="Test comment",
repo=self.target_repository.repo_name,
user=self.author,
line_no=line_no,
f_path=file_path,
- pull_request=self.pull_request)
+ pull_request=self.pull_request,
+ )
assert comment.pull_request_version_id is None
if linked_to:
@@ -1044,25 +1044,20 @@ class PRTestUtility(object):
def create_version_of_pull_request(self):
pull_request = self.create_pull_request()
- version = PullRequestModel()._create_version_from_snapshot(
- pull_request)
+ version = PullRequestModel()._create_version_from_snapshot(pull_request)
return version
def create_status_votes(self, status, *reviewers):
for reviewer in reviewers:
ChangesetStatusModel().set_status(
- repo=self.pull_request.target_repo,
- status=status,
- user=reviewer.user_id,
- pull_request=self.pull_request)
+ repo=self.pull_request.target_repo, status=status, user=reviewer.user_id, pull_request=self.pull_request
+ )
def set_mergeable(self, value):
if not self.mergeable_patcher:
- self.mergeable_patcher = mock.patch.object(
- VcsSettingsModel, 'get_general_settings')
+ self.mergeable_patcher = mock.patch.object(VcsSettingsModel, "get_general_settings")
self.mergeable_mock = self.mergeable_patcher.start()
- self.mergeable_mock.return_value = {
- 'rhodecode_pr_merge_enabled': value}
+ self.mergeable_mock.return_value = {"rhodecode_pr_merge_enabled": value}
def cleanup(self):
# In case the source repository is already cleaned up, the pull
@@ -1109,7 +1104,6 @@ def user_util(request, db_connection):
# TODO: johbo: Split this up into utilities per domain or something similar
class UserUtility(object):
-
def __init__(self, test_name="test"):
self._test_name = self._sanitize_name(test_name)
self.fixture = Fixture()
@@ -1126,37 +1120,29 @@ class UserUtility(object):
self.user_permissions = []
def _sanitize_name(self, name):
- for char in ['[', ']']:
- name = name.replace(char, '_')
+ for char in ["[", "]"]:
+ name = name.replace(char, "_")
return name
- def create_repo_group(
- self, owner=TEST_USER_ADMIN_LOGIN, auto_cleanup=True):
- group_name = "{prefix}_repogroup_{count}".format(
- prefix=self._test_name,
- count=len(self.repo_group_ids))
- repo_group = self.fixture.create_repo_group(
- group_name, cur_user=owner)
+ def create_repo_group(self, owner=TEST_USER_ADMIN_LOGIN, auto_cleanup=True):
+ group_name = "{prefix}_repogroup_{count}".format(prefix=self._test_name, count=len(self.repo_group_ids))
+ repo_group = self.fixture.create_repo_group(group_name, cur_user=owner)
if auto_cleanup:
self.repo_group_ids.append(repo_group.group_id)
return repo_group
- def create_repo(self, owner=TEST_USER_ADMIN_LOGIN, parent=None,
- auto_cleanup=True, repo_type='hg', bare=False):
- repo_name = "{prefix}_repository_{count}".format(
- prefix=self._test_name,
- count=len(self.repos_ids))
+ def create_repo(self, owner=TEST_USER_ADMIN_LOGIN, parent=None, auto_cleanup=True, repo_type="hg", bare=False):
+ repo_name = "{prefix}_repository_{count}".format(prefix=self._test_name, count=len(self.repos_ids))
repository = self.fixture.create_repo(
- repo_name, cur_user=owner, repo_group=parent, repo_type=repo_type, bare=bare)
+ repo_name, cur_user=owner, repo_group=parent, repo_type=repo_type, bare=bare
+ )
if auto_cleanup:
self.repos_ids.append(repository.repo_id)
return repository
def create_user(self, auto_cleanup=True, **kwargs):
- user_name = "{prefix}_user_{count}".format(
- prefix=self._test_name,
- count=len(self.user_ids))
+ user_name = "{prefix}_user_{count}".format(prefix=self._test_name, count=len(self.user_ids))
user = self.fixture.create_user(user_name, **kwargs)
if auto_cleanup:
self.user_ids.append(user.user_id)
@@ -1171,13 +1157,9 @@ class UserUtility(object):
user_group = self.create_user_group(members=[user])
return user, user_group
- def create_user_group(self, owner=TEST_USER_ADMIN_LOGIN, members=None,
- auto_cleanup=True, **kwargs):
- group_name = "{prefix}_usergroup_{count}".format(
- prefix=self._test_name,
- count=len(self.user_group_ids))
- user_group = self.fixture.create_user_group(
- group_name, cur_user=owner, **kwargs)
+ def create_user_group(self, owner=TEST_USER_ADMIN_LOGIN, members=None, auto_cleanup=True, **kwargs):
+ group_name = "{prefix}_usergroup_{count}".format(prefix=self._test_name, count=len(self.user_group_ids))
+ user_group = self.fixture.create_user_group(group_name, cur_user=owner, **kwargs)
if auto_cleanup:
self.user_group_ids.append(user_group.users_group_id)
@@ -1190,52 +1172,34 @@ class UserUtility(object):
self.inherit_default_user_permissions(user_name, False)
self.user_permissions.append((user_name, permission_name))
- def grant_user_permission_to_repo_group(
- self, repo_group, user, permission_name):
- permission = RepoGroupModel().grant_user_permission(
- repo_group, user, permission_name)
- self.user_repo_group_permission_ids.append(
- (repo_group.group_id, user.user_id))
+ def grant_user_permission_to_repo_group(self, repo_group, user, permission_name):
+ permission = RepoGroupModel().grant_user_permission(repo_group, user, permission_name)
+ self.user_repo_group_permission_ids.append((repo_group.group_id, user.user_id))
return permission
- def grant_user_group_permission_to_repo_group(
- self, repo_group, user_group, permission_name):
- permission = RepoGroupModel().grant_user_group_permission(
- repo_group, user_group, permission_name)
- self.user_group_repo_group_permission_ids.append(
- (repo_group.group_id, user_group.users_group_id))
+ def grant_user_group_permission_to_repo_group(self, repo_group, user_group, permission_name):
+ permission = RepoGroupModel().grant_user_group_permission(repo_group, user_group, permission_name)
+ self.user_group_repo_group_permission_ids.append((repo_group.group_id, user_group.users_group_id))
return permission
- def grant_user_permission_to_repo(
- self, repo, user, permission_name):
- permission = RepoModel().grant_user_permission(
- repo, user, permission_name)
- self.user_repo_permission_ids.append(
- (repo.repo_id, user.user_id))
+ def grant_user_permission_to_repo(self, repo, user, permission_name):
+ permission = RepoModel().grant_user_permission(repo, user, permission_name)
+ self.user_repo_permission_ids.append((repo.repo_id, user.user_id))
return permission
- def grant_user_group_permission_to_repo(
- self, repo, user_group, permission_name):
- permission = RepoModel().grant_user_group_permission(
- repo, user_group, permission_name)
- self.user_group_repo_permission_ids.append(
- (repo.repo_id, user_group.users_group_id))
+ def grant_user_group_permission_to_repo(self, repo, user_group, permission_name):
+ permission = RepoModel().grant_user_group_permission(repo, user_group, permission_name)
+ self.user_group_repo_permission_ids.append((repo.repo_id, user_group.users_group_id))
return permission
- def grant_user_permission_to_user_group(
- self, target_user_group, user, permission_name):
- permission = UserGroupModel().grant_user_permission(
- target_user_group, user, permission_name)
- self.user_user_group_permission_ids.append(
- (target_user_group.users_group_id, user.user_id))
+ def grant_user_permission_to_user_group(self, target_user_group, user, permission_name):
+ permission = UserGroupModel().grant_user_permission(target_user_group, user, permission_name)
+ self.user_user_group_permission_ids.append((target_user_group.users_group_id, user.user_id))
return permission
- def grant_user_group_permission_to_user_group(
- self, target_user_group, user_group, permission_name):
- permission = UserGroupModel().grant_user_group_permission(
- target_user_group, user_group, permission_name)
- self.user_group_user_group_permission_ids.append(
- (target_user_group.users_group_id, user_group.users_group_id))
+ def grant_user_group_permission_to_user_group(self, target_user_group, user_group, permission_name):
+ permission = UserGroupModel().grant_user_group_permission(target_user_group, user_group, permission_name)
+ self.user_group_user_group_permission_ids.append((target_user_group.users_group_id, user_group.users_group_id))
return permission
def revoke_user_permission(self, user_name, permission_name):
@@ -1285,14 +1249,11 @@ class UserUtility(object):
"""
first_group = RepoGroup.get(first_group_id)
second_group = RepoGroup.get(second_group_id)
- first_group_parts = (
- len(first_group.group_name.split('/')) if first_group else 0)
- second_group_parts = (
- len(second_group.group_name.split('/')) if second_group else 0)
+ first_group_parts = len(first_group.group_name.split("/")) if first_group else 0
+ second_group_parts = len(second_group.group_name.split("/")) if second_group else 0
return cmp(second_group_parts, first_group_parts)
- sorted_repo_group_ids = sorted(
- self.repo_group_ids, key=functools.cmp_to_key(_repo_group_compare))
+ sorted_repo_group_ids = sorted(self.repo_group_ids, key=functools.cmp_to_key(_repo_group_compare))
for repo_group_id in sorted_repo_group_ids:
self.fixture.destroy_repo_group(repo_group_id)
@@ -1308,16 +1269,11 @@ class UserUtility(object):
"""
first_group = UserGroup.get(first_group_id)
second_group = UserGroup.get(second_group_id)
- first_group_parts = (
- len(first_group.users_group_name.split('/'))
- if first_group else 0)
- second_group_parts = (
- len(second_group.users_group_name.split('/'))
- if second_group else 0)
+ first_group_parts = len(first_group.users_group_name.split("/")) if first_group else 0
+ second_group_parts = len(second_group.users_group_name.split("/")) if second_group else 0
return cmp(second_group_parts, first_group_parts)
- sorted_user_group_ids = sorted(
- self.user_group_ids, key=functools.cmp_to_key(_user_group_compare))
+ sorted_user_group_ids = sorted(self.user_group_ids, key=functools.cmp_to_key(_user_group_compare))
for user_group_id in sorted_user_group_ids:
self.fixture.destroy_user_group(user_group_id)
@@ -1326,22 +1282,19 @@ class UserUtility(object):
self.fixture.destroy_user(user_id)
-@pytest.fixture(scope='session')
+@pytest.fixture(scope="session")
def testrun():
return {
- 'uuid': uuid.uuid4(),
- 'start': datetime.datetime.utcnow().isoformat(),
- 'timestamp': int(time.time()),
+ "uuid": uuid.uuid4(),
+ "start": datetime.datetime.utcnow().isoformat(),
+ "timestamp": int(time.time()),
}
class AppenlightClient(object):
+ url_template = "{url}?protocol_version=0.5"
- url_template = '{url}?protocol_version=0.5'
-
- def __init__(
- self, url, api_key, add_server=True, add_timestamp=True,
- namespace=None, request=None, testrun=None):
+ def __init__(self, url, api_key, add_server=True, add_timestamp=True, namespace=None, request=None, testrun=None):
self.url = self.url_template.format(url=url)
self.api_key = api_key
self.add_server = add_server
@@ -1362,40 +1315,41 @@ class AppenlightClient(object):
def collect(self, data):
if self.add_server:
- data.setdefault('server', self.server)
+ data.setdefault("server", self.server)
if self.add_timestamp:
- data.setdefault('date', datetime.datetime.utcnow().isoformat())
+ data.setdefault("date", datetime.datetime.utcnow().isoformat())
if self.namespace:
- data.setdefault('namespace', self.namespace)
+ data.setdefault("namespace", self.namespace)
if self.request:
- data.setdefault('request', self.request)
+ data.setdefault("request", self.request)
self.stats.append(data)
def send_stats(self):
tags = [
- ('testrun', self.request),
- ('testrun.start', self.testrun['start']),
- ('testrun.timestamp', self.testrun['timestamp']),
- ('test', self.namespace),
+ ("testrun", self.request),
+ ("testrun.start", self.testrun["start"]),
+ ("testrun.timestamp", self.testrun["timestamp"]),
+ ("test", self.namespace),
]
for key, value in self.tags_before.items():
- tags.append((key + '.before', value))
+ tags.append((key + ".before", value))
try:
delta = self.tags_after[key] - value
- tags.append((key + '.delta', delta))
+ tags.append((key + ".delta", delta))
except Exception:
pass
for key, value in self.tags_after.items():
- tags.append((key + '.after', value))
- self.collect({
- 'message': "Collected tags",
- 'tags': tags,
- })
+ tags.append((key + ".after", value))
+ self.collect(
+ {
+ "message": "Collected tags",
+ "tags": tags,
+ }
+ )
response = requests.post(
self.url,
- headers={
- 'X-appenlight-api-key': self.api_key},
+ headers={"X-appenlight-api-key": self.api_key},
json=self.stats,
)
@@ -1403,7 +1357,7 @@ class AppenlightClient(object):
pprint.pprint(self.stats)
print(response.headers)
print(response.text)
- raise Exception('Sending to appenlight failed')
+ raise Exception("Sending to appenlight failed")
@pytest.fixture()
@@ -1454,9 +1408,8 @@ class SettingsUtility(object):
self.repo_rhodecode_ui_ids = []
self.repo_rhodecode_setting_ids = []
- def create_repo_rhodecode_ui(
- self, repo, section, value, key=None, active=True, cleanup=True):
- key = key or sha1_safe(f'{section}{value}{repo.repo_id}')
+ def create_repo_rhodecode_ui(self, repo, section, value, key=None, active=True, cleanup=True):
+ key = key or sha1_safe(f"{section}{value}{repo.repo_id}")
setting = RepoRhodeCodeUi()
setting.repository_id = repo.repo_id
@@ -1471,9 +1424,8 @@ class SettingsUtility(object):
self.repo_rhodecode_ui_ids.append(setting.ui_id)
return setting
- def create_rhodecode_ui(
- self, section, value, key=None, active=True, cleanup=True):
- key = key or sha1_safe(f'{section}{value}')
+ def create_rhodecode_ui(self, section, value, key=None, active=True, cleanup=True):
+ key = key or sha1_safe(f"{section}{value}")
setting = RhodeCodeUi()
setting.ui_section = section
@@ -1487,10 +1439,8 @@ class SettingsUtility(object):
self.rhodecode_ui_ids.append(setting.ui_id)
return setting
- def create_repo_rhodecode_setting(
- self, repo, name, value, type_, cleanup=True):
- setting = RepoRhodeCodeSetting(
- repo.repo_id, key=name, val=value, type=type_)
+ def create_repo_rhodecode_setting(self, repo, name, value, type_, cleanup=True):
+ setting = RepoRhodeCodeSetting(repo.repo_id, key=name, val=value, type=type_)
Session().add(setting)
Session().commit()
@@ -1530,13 +1480,12 @@ class SettingsUtility(object):
@pytest.fixture()
def no_notifications(request):
- notification_patcher = mock.patch(
- 'rhodecode.model.notification.NotificationModel.create')
+ notification_patcher = mock.patch("rhodecode.model.notification.NotificationModel.create")
notification_patcher.start()
request.addfinalizer(notification_patcher.stop)
-@pytest.fixture(scope='session')
+@pytest.fixture(scope="session")
def repeat(request):
"""
The number of repetitions is based on this fixture.
@@ -1544,7 +1493,7 @@ def repeat(request):
Slower calls may divide it by 10 or 100. It is chosen in a way so that the
tests are not too slow in our default test suite.
"""
- return request.config.getoption('--repeat')
+ return request.config.getoption("--repeat")
@pytest.fixture()
@@ -1561,43 +1510,18 @@ def context_stub():
return context
-@pytest.fixture()
-def request_stub():
- """
- Stub request object.
- """
- from rhodecode.lib.base import bootstrap_request
- request = bootstrap_request(scheme='https')
- return request
-
-
-@pytest.fixture()
-def config_stub(request, request_stub):
- """
- Set up pyramid.testing and return the Configurator.
- """
- from rhodecode.lib.base import bootstrap_config
- config = bootstrap_config(request=request_stub)
-
- @request.addfinalizer
- def cleanup():
- pyramid.testing.tearDown()
-
- return config
-
-
@pytest.fixture()
def StubIntegrationType():
class _StubIntegrationType(IntegrationTypeBase):
- """ Test integration type class """
+ """Test integration type class"""
- key = 'test'
- display_name = 'Test integration type'
- description = 'A test integration type for testing'
+ key = "test"
+ display_name = "Test integration type"
+ description = "A test integration type for testing"
@classmethod
def icon(cls):
- return 'test_icon_html_image'
+ return "test_icon_html_image"
def __init__(self, settings):
super(_StubIntegrationType, self).__init__(settings)
@@ -1611,14 +1535,14 @@ def StubIntegrationType():
test_string_field = colander.SchemaNode(
colander.String(),
missing=colander.required,
- title='test string field',
+ title="test string field",
)
test_int_field = colander.SchemaNode(
colander.Int(),
- title='some integer setting',
+ title="some integer setting",
)
- return SettingsSchema()
+ return SettingsSchema()
integration_type_registry.register_integration_type(_StubIntegrationType)
return _StubIntegrationType
@@ -1627,18 +1551,22 @@ def StubIntegrationType():
@pytest.fixture()
def stub_integration_settings():
return {
- 'test_string_field': 'some data',
- 'test_int_field': 100,
+ "test_string_field": "some data",
+ "test_int_field": 100,
}
@pytest.fixture()
-def repo_integration_stub(request, repo_stub, StubIntegrationType,
- stub_integration_settings):
+def repo_integration_stub(request, repo_stub, StubIntegrationType, stub_integration_settings):
integration = IntegrationModel().create(
- StubIntegrationType, settings=stub_integration_settings, enabled=True,
- name='test repo integration',
- repo=repo_stub, repo_group=None, child_repos_only=None)
+ StubIntegrationType,
+ settings=stub_integration_settings,
+ enabled=True,
+ name="test repo integration",
+ repo=repo_stub,
+ repo_group=None,
+ child_repos_only=None,
+ )
@request.addfinalizer
def cleanup():
@@ -1648,12 +1576,16 @@ def repo_integration_stub(request, repo_stub, StubIntegrationType,
@pytest.fixture()
-def repogroup_integration_stub(request, test_repo_group, StubIntegrationType,
- stub_integration_settings):
+def repogroup_integration_stub(request, test_repo_group, StubIntegrationType, stub_integration_settings):
integration = IntegrationModel().create(
- StubIntegrationType, settings=stub_integration_settings, enabled=True,
- name='test repogroup integration',
- repo=None, repo_group=test_repo_group, child_repos_only=True)
+ StubIntegrationType,
+ settings=stub_integration_settings,
+ enabled=True,
+ name="test repogroup integration",
+ repo=None,
+ repo_group=test_repo_group,
+ child_repos_only=True,
+ )
@request.addfinalizer
def cleanup():
@@ -1663,12 +1595,16 @@ def repogroup_integration_stub(request, test_repo_group, StubIntegrationType,
@pytest.fixture()
-def repogroup_recursive_integration_stub(request, test_repo_group,
- StubIntegrationType, stub_integration_settings):
+def repogroup_recursive_integration_stub(request, test_repo_group, StubIntegrationType, stub_integration_settings):
integration = IntegrationModel().create(
- StubIntegrationType, settings=stub_integration_settings, enabled=True,
- name='test recursive repogroup integration',
- repo=None, repo_group=test_repo_group, child_repos_only=False)
+ StubIntegrationType,
+ settings=stub_integration_settings,
+ enabled=True,
+ name="test recursive repogroup integration",
+ repo=None,
+ repo_group=test_repo_group,
+ child_repos_only=False,
+ )
@request.addfinalizer
def cleanup():
@@ -1678,12 +1614,16 @@ def repogroup_recursive_integration_stub(request, test_repo_group,
@pytest.fixture()
-def global_integration_stub(request, StubIntegrationType,
- stub_integration_settings):
+def global_integration_stub(request, StubIntegrationType, stub_integration_settings):
integration = IntegrationModel().create(
- StubIntegrationType, settings=stub_integration_settings, enabled=True,
- name='test global integration',
- repo=None, repo_group=None, child_repos_only=None)
+ StubIntegrationType,
+ settings=stub_integration_settings,
+ enabled=True,
+ name="test global integration",
+ repo=None,
+ repo_group=None,
+ child_repos_only=None,
+ )
@request.addfinalizer
def cleanup():
@@ -1693,12 +1633,16 @@ def global_integration_stub(request, StubIntegrationType,
@pytest.fixture()
-def root_repos_integration_stub(request, StubIntegrationType,
- stub_integration_settings):
+def root_repos_integration_stub(request, StubIntegrationType, stub_integration_settings):
integration = IntegrationModel().create(
- StubIntegrationType, settings=stub_integration_settings, enabled=True,
- name='test global integration',
- repo=None, repo_group=None, child_repos_only=True)
+ StubIntegrationType,
+ settings=stub_integration_settings,
+ enabled=True,
+ name="test global integration",
+ repo=None,
+ repo_group=None,
+ child_repos_only=True,
+ )
@request.addfinalizer
def cleanup():
@@ -1710,8 +1654,8 @@ def root_repos_integration_stub(request, StubIntegrationType,
@pytest.fixture()
def local_dt_to_utc():
def _factory(dt):
- return dt.replace(tzinfo=dateutil.tz.tzlocal()).astimezone(
- dateutil.tz.tzutc()).replace(tzinfo=None)
+ return dt.replace(tzinfo=dateutil.tz.tzlocal()).astimezone(dateutil.tz.tzutc()).replace(tzinfo=None)
+
return _factory
@@ -1724,7 +1668,7 @@ def disable_anonymous_user(request, baseapp):
set_anonymous_access(True)
-@pytest.fixture(scope='module')
+@pytest.fixture(scope="module")
def rc_fixture(request):
return Fixture()
@@ -1734,9 +1678,9 @@ def repo_groups(request):
fixture = Fixture()
session = Session()
- zombie_group = fixture.create_repo_group('zombie')
- parent_group = fixture.create_repo_group('parent')
- child_group = fixture.create_repo_group('parent/child')
+ zombie_group = fixture.create_repo_group("zombie")
+ parent_group = fixture.create_repo_group("parent")
+ child_group = fixture.create_repo_group("parent/child")
groups_in_db = session.query(RepoGroup).all()
assert len(groups_in_db) == 3
assert child_group.group_parent_id == parent_group.group_id
@@ -1748,3 +1692,4 @@ def repo_groups(request):
fixture.destroy_repo_group(parent_group)
return zombie_group, parent_group, child_group
+
diff --git a/rhodecode/tests/fixtures/function_scoped_baseapp.py b/rhodecode/tests/fixtures/function_scoped_baseapp.py
new file mode 100644
index 00000000..b768258f
--- /dev/null
+++ b/rhodecode/tests/fixtures/function_scoped_baseapp.py
@@ -0,0 +1,52 @@
+# 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 pytest
+from rhodecode.tests.utils import CustomTestApp
+from rhodecode.tests.fixtures.fixture_utils import plain_http_environ, plain_config_stub, plain_request_stub
+
+
+@pytest.fixture(scope='function')
+def request_stub():
+ return plain_request_stub()
+
+
+@pytest.fixture(scope='function')
+def config_stub(request, request_stub):
+ return plain_config_stub(request, request_stub)
+
+
+@pytest.fixture(scope='function')
+def http_environ():
+ """
+ HTTP extra environ keys.
+
+ Used by the test application and as well for setting up the pylons
+ environment. In the case of the fixture "app" it should be possible
+ to override this for a specific test case.
+ """
+ return plain_http_environ()
+
+
+@pytest.fixture(scope='function')
+def app(request, config_stub, http_environ, baseapp):
+ app = CustomTestApp(baseapp, extra_environ=http_environ)
+ if request.cls:
+ # inject app into a class that uses this fixtures
+ request.cls.app = app
+ return app
diff --git a/rhodecode/tests/fixtures/module_scoped_baseapp.py b/rhodecode/tests/fixtures/module_scoped_baseapp.py
new file mode 100644
index 00000000..3478e714
--- /dev/null
+++ b/rhodecode/tests/fixtures/module_scoped_baseapp.py
@@ -0,0 +1,49 @@
+# 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 pytest
+from rhodecode.tests.utils import CustomTestApp
+from rhodecode.tests.fixtures.fixture_utils import plain_http_environ, plain_config_stub, plain_request_stub
+
+
+@pytest.fixture(scope='module')
+def module_request_stub():
+ return plain_request_stub()
+
+
+@pytest.fixture(scope='module')
+def module_config_stub(request, module_request_stub):
+ return plain_config_stub(request, module_request_stub)
+
+
+@pytest.fixture(scope='module')
+def module_http_environ():
+ """
+ HTTP extra environ keys.
+
+ Used by the test application and as well for setting up the pylons
+ environment. In the case of the fixture "app" it should be possible
+ to override this for a specific test case.
+ """
+ return plain_http_environ()
+
+
+@pytest.fixture(scope='module')
+def module_app(request, module_config_stub, module_http_environ, baseapp):
+ app = CustomTestApp(baseapp, extra_environ=module_http_environ)
+ return app
diff --git a/rhodecode/tests/fixture.py b/rhodecode/tests/fixtures/rc_fixture.py
similarity index 68%
rename from rhodecode/tests/fixture.py
rename to rhodecode/tests/fixtures/rc_fixture.py
index d7ca57bd..2fc5692a 100644
--- a/rhodecode/tests/fixture.py
+++ b/rhodecode/tests/fixtures/rc_fixture.py
@@ -1,4 +1,3 @@
-
# Copyright (C) 2010-2023 RhodeCode GmbH
#
# This program is free software: you can redistribute it and/or modify
@@ -37,17 +36,16 @@ from rhodecode.model.user_group import UserGroupModel
from rhodecode.model.gist import GistModel
from rhodecode.model.auth_token import AuthTokenModel
from rhodecode.model.scm import ScmModel
-from rhodecode.authentication.plugins.auth_rhodecode import \
- RhodeCodeAuthPlugin
+from rhodecode.authentication.plugins.auth_rhodecode import RhodeCodeAuthPlugin
from rhodecode.tests import TEST_USER_ADMIN_LOGIN
dn = os.path.dirname
-FIXTURES = os.path.join(dn(dn(os.path.abspath(__file__))), 'tests', 'fixtures')
+FIXTURES = os.path.join(dn(os.path.abspath(__file__)), "diff_fixtures")
def error_function(*args, **kwargs):
- raise Exception('Total Crash !')
+ raise Exception("Total Crash !")
class TestINI(object):
@@ -59,8 +57,7 @@ class TestINI(object):
print('paster server %s' % new_test_ini)
"""
- def __init__(self, ini_file_path, ini_params, new_file_prefix='DEFAULT',
- destroy=True, dir=None):
+ def __init__(self, ini_file_path, ini_params, new_file_prefix="DEFAULT", destroy=True, dir=None):
self.ini_file_path = ini_file_path
self.ini_params = ini_params
self.new_path = None
@@ -85,9 +82,8 @@ class TestINI(object):
parser[section][key] = str(val)
with tempfile.NamedTemporaryFile(
- mode='w',
- prefix=self.new_path_prefix, suffix='.ini', dir=self._dir,
- delete=False) as new_ini_file:
+ mode="w", prefix=self.new_path_prefix, suffix=".ini", dir=self._dir, delete=False
+ ) as new_ini_file:
parser.write(new_ini_file)
self.new_path = new_ini_file.name
@@ -99,7 +95,6 @@ class TestINI(object):
class Fixture(object):
-
def anon_access(self, status):
"""
Context process for disabling anonymous access. use like:
@@ -139,22 +134,19 @@ class Fixture(object):
class context(object):
def _get_plugin(self):
- plugin_id = 'egg:rhodecode-enterprise-ce#{}'.format(RhodeCodeAuthPlugin.uid)
+ plugin_id = "egg:rhodecode-enterprise-ce#{}".format(RhodeCodeAuthPlugin.uid)
plugin = RhodeCodeAuthPlugin(plugin_id)
return plugin
def __enter__(self):
-
plugin = self._get_plugin()
- plugin.create_or_update_setting('auth_restriction', auth_restriction)
+ plugin.create_or_update_setting("auth_restriction", auth_restriction)
Session().commit()
SettingsModel().invalidate_settings_cache(hard=True)
def __exit__(self, exc_type, exc_val, exc_tb):
-
plugin = self._get_plugin()
- plugin.create_or_update_setting(
- 'auth_restriction', RhodeCodeAuthPlugin.AUTH_RESTRICTION_NONE)
+ plugin.create_or_update_setting("auth_restriction", RhodeCodeAuthPlugin.AUTH_RESTRICTION_NONE)
Session().commit()
SettingsModel().invalidate_settings_cache(hard=True)
@@ -173,62 +165,61 @@ class Fixture(object):
class context(object):
def _get_plugin(self):
- plugin_id = 'egg:rhodecode-enterprise-ce#{}'.format(RhodeCodeAuthPlugin.uid)
+ plugin_id = "egg:rhodecode-enterprise-ce#{}".format(RhodeCodeAuthPlugin.uid)
plugin = RhodeCodeAuthPlugin(plugin_id)
return plugin
def __enter__(self):
plugin = self._get_plugin()
- plugin.create_or_update_setting('scope_restriction', scope_restriction)
+ plugin.create_or_update_setting("scope_restriction", scope_restriction)
Session().commit()
SettingsModel().invalidate_settings_cache(hard=True)
def __exit__(self, exc_type, exc_val, exc_tb):
plugin = self._get_plugin()
- plugin.create_or_update_setting(
- 'scope_restriction', RhodeCodeAuthPlugin.AUTH_RESTRICTION_SCOPE_ALL)
+ plugin.create_or_update_setting("scope_restriction", RhodeCodeAuthPlugin.AUTH_RESTRICTION_SCOPE_ALL)
Session().commit()
SettingsModel().invalidate_settings_cache(hard=True)
return context()
def _get_repo_create_params(self, **custom):
- repo_type = custom.get('repo_type') or 'hg'
+ repo_type = custom.get("repo_type") or "hg"
default_landing_ref, landing_ref_lbl = ScmModel.backend_landing_ref(repo_type)
defs = {
- 'repo_name': None,
- 'repo_type': repo_type,
- 'clone_uri': '',
- 'push_uri': '',
- 'repo_group': '-1',
- 'repo_description': 'DESC',
- 'repo_private': False,
- 'repo_landing_commit_ref': default_landing_ref,
- 'repo_copy_permissions': False,
- 'repo_state': Repository.STATE_CREATED,
+ "repo_name": None,
+ "repo_type": repo_type,
+ "clone_uri": "",
+ "push_uri": "",
+ "repo_group": "-1",
+ "repo_description": "DESC",
+ "repo_private": False,
+ "repo_landing_commit_ref": default_landing_ref,
+ "repo_copy_permissions": False,
+ "repo_state": Repository.STATE_CREATED,
}
defs.update(custom)
- if 'repo_name_full' not in custom:
- defs.update({'repo_name_full': defs['repo_name']})
+ if "repo_name_full" not in custom:
+ defs.update({"repo_name_full": defs["repo_name"]})
# fix the repo name if passed as repo_name_full
- if defs['repo_name']:
- defs['repo_name'] = defs['repo_name'].split('/')[-1]
+ if defs["repo_name"]:
+ defs["repo_name"] = defs["repo_name"].split("/")[-1]
return defs
def _get_group_create_params(self, **custom):
defs = {
- 'group_name': None,
- 'group_description': 'DESC',
- 'perm_updates': [],
- 'perm_additions': [],
- 'perm_deletions': [],
- 'group_parent_id': -1,
- 'enable_locking': False,
- 'recursive': False,
+ "group_name": None,
+ "group_description": "DESC",
+ "perm_updates": [],
+ "perm_additions": [],
+ "perm_deletions": [],
+ "group_parent_id": -1,
+ "enable_locking": False,
+ "recursive": False,
}
defs.update(custom)
@@ -236,16 +227,16 @@ class Fixture(object):
def _get_user_create_params(self, name, **custom):
defs = {
- 'username': name,
- 'password': 'qweqwe',
- 'email': '%s+test@rhodecode.org' % name,
- 'firstname': 'TestUser',
- 'lastname': 'Test',
- 'description': 'test description',
- 'active': True,
- 'admin': False,
- 'extern_type': 'rhodecode',
- 'extern_name': None,
+ "username": name,
+ "password": "qweqwe",
+ "email": "%s+test@rhodecode.org" % name,
+ "firstname": "TestUser",
+ "lastname": "Test",
+ "description": "test description",
+ "active": True,
+ "admin": False,
+ "extern_type": "rhodecode",
+ "extern_name": None,
}
defs.update(custom)
@@ -253,30 +244,30 @@ class Fixture(object):
def _get_user_group_create_params(self, name, **custom):
defs = {
- 'users_group_name': name,
- 'user_group_description': 'DESC',
- 'users_group_active': True,
- 'user_group_data': {},
+ "users_group_name": name,
+ "user_group_description": "DESC",
+ "users_group_active": True,
+ "user_group_data": {},
}
defs.update(custom)
return defs
def create_repo(self, name, **kwargs):
- repo_group = kwargs.get('repo_group')
+ repo_group = kwargs.get("repo_group")
if isinstance(repo_group, RepoGroup):
- kwargs['repo_group'] = repo_group.group_id
+ kwargs["repo_group"] = repo_group.group_id
name = name.split(Repository.NAME_SEP)[-1]
name = Repository.NAME_SEP.join((repo_group.group_name, name))
- if 'skip_if_exists' in kwargs:
- del kwargs['skip_if_exists']
+ if "skip_if_exists" in kwargs:
+ del kwargs["skip_if_exists"]
r = Repository.get_by_repo_name(name)
if r:
return r
form_data = self._get_repo_create_params(repo_name=name, **kwargs)
- cur_user = kwargs.get('cur_user', TEST_USER_ADMIN_LOGIN)
+ cur_user = kwargs.get("cur_user", TEST_USER_ADMIN_LOGIN)
RepoModel().create(form_data, cur_user)
Session().commit()
repo = Repository.get_by_repo_name(name)
@@ -287,17 +278,15 @@ class Fixture(object):
repo_to_fork = Repository.get_by_repo_name(repo_to_fork)
form_data = self._get_repo_create_params(
- repo_name=fork_name,
- fork_parent_id=repo_to_fork.repo_id,
- repo_type=repo_to_fork.repo_type,
- **kwargs)
+ repo_name=fork_name, fork_parent_id=repo_to_fork.repo_id, repo_type=repo_to_fork.repo_type, **kwargs
+ )
# TODO: fix it !!
- form_data['description'] = form_data['repo_description']
- form_data['private'] = form_data['repo_private']
- form_data['landing_rev'] = form_data['repo_landing_commit_ref']
+ form_data["description"] = form_data["repo_description"]
+ form_data["private"] = form_data["repo_private"]
+ form_data["landing_rev"] = form_data["repo_landing_commit_ref"]
- owner = kwargs.get('cur_user', TEST_USER_ADMIN_LOGIN)
+ owner = kwargs.get("cur_user", TEST_USER_ADMIN_LOGIN)
RepoModel().create_fork(form_data, cur_user=owner)
Session().commit()
r = Repository.get_by_repo_name(fork_name)
@@ -305,7 +294,7 @@ class Fixture(object):
return r
def destroy_repo(self, repo_name, **kwargs):
- RepoModel().delete(repo_name, pull_requests='delete', artifacts='delete', **kwargs)
+ RepoModel().delete(repo_name, pull_requests="delete", artifacts="delete", **kwargs)
Session().commit()
def destroy_repo_on_filesystem(self, repo_name):
@@ -314,17 +303,16 @@ class Fixture(object):
shutil.rmtree(rm_path)
def create_repo_group(self, name, **kwargs):
- if 'skip_if_exists' in kwargs:
- del kwargs['skip_if_exists']
+ if "skip_if_exists" in kwargs:
+ del kwargs["skip_if_exists"]
gr = RepoGroup.get_by_group_name(group_name=name)
if gr:
return gr
form_data = self._get_group_create_params(group_name=name, **kwargs)
- owner = kwargs.get('cur_user', TEST_USER_ADMIN_LOGIN)
+ owner = kwargs.get("cur_user", TEST_USER_ADMIN_LOGIN)
gr = RepoGroupModel().create(
- group_name=form_data['group_name'],
- group_description=form_data['group_name'],
- owner=owner)
+ group_name=form_data["group_name"], group_description=form_data["group_name"], owner=owner
+ )
Session().commit()
gr = RepoGroup.get_by_group_name(gr.group_name)
return gr
@@ -334,8 +322,8 @@ class Fixture(object):
Session().commit()
def create_user(self, name, **kwargs):
- if 'skip_if_exists' in kwargs:
- del kwargs['skip_if_exists']
+ if "skip_if_exists" in kwargs:
+ del kwargs["skip_if_exists"]
user = User.get_by_username(name)
if user:
return user
@@ -343,8 +331,7 @@ class Fixture(object):
user = UserModel().create(form_data)
# create token for user
- AuthTokenModel().create(
- user=user, description=u'TEST_USER_TOKEN')
+ AuthTokenModel().create(user=user, description="TEST_USER_TOKEN")
Session().commit()
user = User.get_by_username(user.username)
@@ -368,22 +355,24 @@ class Fixture(object):
Session().commit()
def create_user_group(self, name, **kwargs):
- if 'skip_if_exists' in kwargs:
- del kwargs['skip_if_exists']
+ if "skip_if_exists" in kwargs:
+ del kwargs["skip_if_exists"]
gr = UserGroup.get_by_group_name(group_name=name)
if gr:
return gr
# map active flag to the real attribute. For API consistency of fixtures
- if 'active' in kwargs:
- kwargs['users_group_active'] = kwargs['active']
- del kwargs['active']
+ if "active" in kwargs:
+ kwargs["users_group_active"] = kwargs["active"]
+ del kwargs["active"]
form_data = self._get_user_group_create_params(name, **kwargs)
- owner = kwargs.get('cur_user', TEST_USER_ADMIN_LOGIN)
+ owner = kwargs.get("cur_user", TEST_USER_ADMIN_LOGIN)
user_group = UserGroupModel().create(
- name=form_data['users_group_name'],
- description=form_data['user_group_description'],
- owner=owner, active=form_data['users_group_active'],
- group_data=form_data['user_group_data'])
+ name=form_data["users_group_name"],
+ description=form_data["user_group_description"],
+ owner=owner,
+ active=form_data["users_group_active"],
+ group_data=form_data["user_group_data"],
+ )
Session().commit()
user_group = UserGroup.get_by_group_name(user_group.users_group_name)
return user_group
@@ -394,18 +383,23 @@ class Fixture(object):
def create_gist(self, **kwargs):
form_data = {
- 'description': 'new-gist',
- 'owner': TEST_USER_ADMIN_LOGIN,
- 'gist_type': GistModel.cls.GIST_PUBLIC,
- 'lifetime': -1,
- 'acl_level': Gist.ACL_LEVEL_PUBLIC,
- 'gist_mapping': {b'filename1.txt': {'content': b'hello world'},}
+ "description": "new-gist",
+ "owner": TEST_USER_ADMIN_LOGIN,
+ "gist_type": GistModel.cls.GIST_PUBLIC,
+ "lifetime": -1,
+ "acl_level": Gist.ACL_LEVEL_PUBLIC,
+ "gist_mapping": {
+ b"filename1.txt": {"content": b"hello world"},
+ },
}
form_data.update(kwargs)
gist = GistModel().create(
- description=form_data['description'], owner=form_data['owner'],
- gist_mapping=form_data['gist_mapping'], gist_type=form_data['gist_type'],
- lifetime=form_data['lifetime'], gist_acl_level=form_data['acl_level']
+ description=form_data["description"],
+ owner=form_data["owner"],
+ gist_mapping=form_data["gist_mapping"],
+ gist_type=form_data["gist_type"],
+ lifetime=form_data["lifetime"],
+ gist_acl_level=form_data["acl_level"],
)
Session().commit()
return gist
@@ -420,7 +414,7 @@ class Fixture(object):
Session().commit()
def load_resource(self, resource_name, strip=False):
- with open(os.path.join(FIXTURES, resource_name), 'rb') as f:
+ with open(os.path.join(FIXTURES, resource_name), "rb") as f:
source = f.read()
if strip:
source = source.strip()
diff --git a/rhodecode/tests/fixtures/rcextensions_fixtures.py b/rhodecode/tests/fixtures/rcextensions_fixtures.py
new file mode 100644
index 00000000..c8879912
--- /dev/null
+++ b/rhodecode/tests/fixtures/rcextensions_fixtures.py
@@ -0,0 +1,157 @@
+# 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 os
+import shutil
+import logging
+import textwrap
+
+import pytest
+
+import rhodecode
+import rhodecode.lib
+
+from rhodecode.tests import console_printer
+
+log = logging.getLogger(__name__)
+
+
+def store_rcextensions(destination, force=False):
+ from rhodecode.config import rcextensions
+ package_path = rcextensions.__path__[0]
+
+ # Note: rcextensions are looked up based on the path of the ini file
+ rcextensions_path = os.path.join(destination, 'rcextensions')
+
+ if force:
+ shutil.rmtree(rcextensions_path, ignore_errors=True)
+ shutil.copytree(package_path, rcextensions_path)
+
+
+@pytest.fixture(scope="module")
+def rcextensions(request, tmp_storage_location):
+ """
+ Installs a testing rcextensions pack to ensure they work as expected.
+ """
+
+ # Note: rcextensions are looked up based on the path of the ini file
+ rcextensions_path = os.path.join(tmp_storage_location, 'rcextensions')
+
+ if os.path.exists(rcextensions_path):
+ pytest.fail(
+ f"Path for rcextensions already exists, please clean up before "
+ f"test run this path: {rcextensions_path}")
+ else:
+ store_rcextensions(tmp_storage_location)
+
+
+@pytest.fixture(scope='function')
+def rcextensions_present(request):
+
+ class RcExtensionsPresent:
+ def __init__(self, rcextensions_location):
+ self.rcextensions_location = rcextensions_location
+
+ def __enter__(self):
+ self.store()
+
+ def __exit__(self, exc_type, exc_val, exc_tb):
+ self.cleanup()
+
+ def store(self):
+ store_rcextensions(self.rcextensions_location)
+
+ def cleanup(self):
+ shutil.rmtree(os.path.join(self.rcextensions_location, 'rcextensions'))
+
+ return RcExtensionsPresent
+
+
+@pytest.fixture(scope='function')
+def rcextensions_modification(request):
+ """
+ example usage::
+
+ hook_name = '_pre_push_hook'
+ code = '''
+ raise OSError('failed')
+ return HookResponse(1, 'FAILED')
+ '''
+ mods = [
+ (hook_name, code),
+ ]
+ # rhodecode.ini file location, where rcextensions needs to live
+ rcstack_location = os.path.dirname(rcstack.config_file)
+ with rcextensions_modification(rcstack_location, mods):
+ # do some stuff
+ """
+
+ class RcextensionsModification:
+ def __init__(self, rcextensions_location, mods, create_if_missing=False, force_create=False):
+ self.force_create = force_create
+ self.create_if_missing = create_if_missing
+ self.rcextensions_location = rcextensions_location
+ self.mods = mods
+ if not isinstance(mods, list):
+ raise ValueError('mods must be a list of modifications')
+
+ def __enter__(self):
+ if self.create_if_missing:
+ store_rcextensions(self.rcextensions_location, force=self.force_create)
+
+ for hook_name, method_body in self.mods:
+ self.modification(hook_name, method_body)
+
+ def __exit__(self, exc_type, exc_val, exc_tb):
+ self.cleanup()
+
+ def cleanup(self):
+ # reset rcextensions to "bare" state from the package
+ store_rcextensions(self.rcextensions_location, force=True)
+
+ def modification(self, hook_name, method_body):
+ import ast
+
+ rcextensions_path = os.path.join(self.rcextensions_location, 'rcextensions')
+
+ # Load the code from hooks.py
+ hooks_filename = os.path.join(rcextensions_path, 'hooks.py')
+ with open(hooks_filename, "r") as file:
+ tree = ast.parse(file.read())
+
+ # Define new content for the function as a string
+ new_code = textwrap.dedent(method_body)
+
+ # Parse the new code to add it to the function
+ new_body = ast.parse(new_code).body
+
+ # Walk through the AST to find and modify the function
+ for node in tree.body:
+ if isinstance(node, ast.FunctionDef) and node.name == hook_name:
+ node.body = new_body # Replace the function body with the new body
+
+ # Compile the modified AST back to code
+ compile(tree, hooks_filename, "exec")
+
+ # Write the updated code back to hooks.py
+ with open(hooks_filename, "w") as file:
+ file.write(ast.unparse(tree)) # Requires Python 3.9+
+
+ console_printer(f" [green]rcextensions[/green] Updated the body of '{hooks_filename}' function '{hook_name}'")
+
+ return RcextensionsModification
diff --git a/rhodecode/tests/functional/test_delegated_admin.py b/rhodecode/tests/functional/test_delegated_admin.py
index 8e65348a..e48cf835 100644
--- a/rhodecode/tests/functional/test_delegated_admin.py
+++ b/rhodecode/tests/functional/test_delegated_admin.py
@@ -21,7 +21,7 @@
import pytest
from rhodecode.tests import TestController
-from rhodecode.tests.fixture import Fixture
+from rhodecode.tests.fixtures.rc_fixture import Fixture
from rhodecode.tests.routes import route_path
diff --git a/rhodecode/tests/integrations/__init__.py b/rhodecode/tests/integrations/__init__.py
new file mode 100644
index 00000000..ae06165a
--- /dev/null
+++ b/rhodecode/tests/integrations/__init__.py
@@ -0,0 +1,17 @@
+# 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/
diff --git a/rhodecode/tests/integrations/test_integration.py b/rhodecode/tests/integrations/test_integration.py
index 1e320b67..8c76dbc5 100644
--- a/rhodecode/tests/integrations/test_integration.py
+++ b/rhodecode/tests/integrations/test_integration.py
@@ -20,7 +20,7 @@ import time
import pytest
from rhodecode import events
-from rhodecode.tests.fixture import Fixture
+from rhodecode.tests.fixtures.rc_fixture import Fixture
from rhodecode.model.db import Session, Integration
from rhodecode.model.integration import IntegrationModel
diff --git a/rhodecode/tests/lib/auth_modules/__init__.py b/rhodecode/tests/lib/auth_modules/__init__.py
new file mode 100644
index 00000000..ae06165a
--- /dev/null
+++ b/rhodecode/tests/lib/auth_modules/__init__.py
@@ -0,0 +1,17 @@
+# 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/
diff --git a/rhodecode/tests/lib/middleware/test_simplehg.py b/rhodecode/tests/lib/middleware/test_simplehg.py
index 69bbf833..608a245d 100644
--- a/rhodecode/tests/lib/middleware/test_simplehg.py
+++ b/rhodecode/tests/lib/middleware/test_simplehg.py
@@ -123,10 +123,14 @@ def test_get_config(user_util, baseapp, request_stub):
('web', 'allow_push', '*'),
('web', 'allow_archive', 'gz zip bz2'),
('web', 'baseurl', '/'),
+
+ # largefiles data...
('vcs_git_lfs', 'store_location', hg_config_org.get('vcs_git_lfs', 'store_location')),
+ ('largefiles', 'usercache', hg_config_org.get('largefiles', 'usercache')),
+
('vcs_svn_branch', '9aac1a38c3b8a0cdc4ae0f960a5f83332bc4fa5e', '/branches/*'),
('vcs_svn_branch', 'c7e6a611c87da06529fd0dd733308481d67c71a8', '/trunk'),
- ('largefiles', 'usercache', hg_config_org.get('largefiles', 'usercache')),
+
('hooks', 'preoutgoing.pre_pull', 'python:vcsserver.hooks.pre_pull'),
('hooks', 'prechangegroup.pre_push', 'python:vcsserver.hooks.pre_push'),
('hooks', 'outgoing.pull_logger', 'python:vcsserver.hooks.log_pull_action'),
diff --git a/rhodecode/tests/lib/middleware/test_simplevcs.py b/rhodecode/tests/lib/middleware/test_simplevcs.py
index c8129d24..2ed7cfde 100644
--- a/rhodecode/tests/lib/middleware/test_simplevcs.py
+++ b/rhodecode/tests/lib/middleware/test_simplevcs.py
@@ -22,7 +22,8 @@ import pytest
from rhodecode.lib.str_utils import base64_to_str
from rhodecode.lib.utils2 import AttributeDict
-from rhodecode.tests.utils import CustomTestApp
+from rhodecode.tests.fixtures.fixture_pyramid import ini_config
+from rhodecode.tests.utils import CustomTestApp, AuthPluginManager
from rhodecode.lib.caching_query import FromCache
from rhodecode.lib.middleware import simplevcs
@@ -34,6 +35,57 @@ from rhodecode.tests import (
HG_REPO, TEST_USER_ADMIN_LOGIN, TEST_USER_ADMIN_PASS)
from rhodecode.tests.lib.middleware import mock_scm_app
+from rhodecode.model.db import Permission, User
+from rhodecode.model.meta import Session
+from rhodecode.model.user import UserModel
+
+
+@pytest.fixture()
+def enable_auth_plugins(request, app):
+ """
+ Return a factory object that when called, allows to control which
+ authentication plugins are enabled.
+ """
+
+ enabler = AuthPluginManager()
+ request.addfinalizer(enabler.cleanup)
+
+ return enabler
+
+
+@pytest.fixture()
+def test_user_factory(request, baseapp):
+
+ def user_factory(username='test_user', password='qweqwe', first_name='John', last_name='Testing', **kwargs):
+ usr = UserModel().create_or_update(
+ username=username,
+ password=password,
+ email=f'{username}@rhodecode.org',
+ firstname=first_name, lastname=last_name)
+ Session().commit()
+
+ for k, v in kwargs.items():
+ setattr(usr, k, v)
+ Session().add(usr)
+
+ new_usr = User.get_by_username(username)
+ new_usr_id = new_usr.user_id
+ assert new_usr == usr
+
+ @request.addfinalizer
+ def cleanup():
+ if User.get(new_usr_id) is None:
+ return
+
+ perm = Permission.query().all()
+ for p in perm:
+ UserModel().revoke_perm(usr, p)
+
+ UserModel().delete(new_usr_id)
+ Session().commit()
+ return usr
+
+ return user_factory
class StubVCSController(simplevcs.SimpleVCS):
@@ -107,8 +159,7 @@ def _remove_default_user_from_query_cache():
Session().expire(user)
-def test_handles_exceptions_during_permissions_checks(
- vcscontroller, disable_anonymous_user, enable_auth_plugins, test_user_factory):
+def test_handles_exceptions_during_permissions_checks(vcscontroller, disable_anonymous_user, enable_auth_plugins, test_user_factory):
test_password = 'qweqwe'
test_user = test_user_factory(password=test_password, extern_type='headers', extern_name='headers')
@@ -373,29 +424,30 @@ class TestShadowRepoExposure(object):
controller.vcs_repo_name)
-@pytest.mark.usefixtures('baseapp')
class TestGenerateVcsResponse(object):
- def test_ensures_that_start_response_is_called_early_enough(self):
- self.call_controller_with_response_body(iter(['a', 'b']))
+ def test_ensures_that_start_response_is_called_early_enough(self, baseapp):
+ app_ini_config = baseapp.config.registry.settings['__file__']
+ self.call_controller_with_response_body(app_ini_config, iter(['a', 'b']))
assert self.start_response.called
- def test_invalidates_cache_after_body_is_consumed(self):
- result = self.call_controller_with_response_body(iter(['a', 'b']))
+ def test_invalidates_cache_after_body_is_consumed(self, baseapp):
+ app_ini_config = baseapp.config.registry.settings['__file__']
+ result = self.call_controller_with_response_body(app_ini_config, iter(['a', 'b']))
assert not self.was_cache_invalidated()
# Consume the result
list(result)
assert self.was_cache_invalidated()
- def test_raises_unknown_exceptions(self):
- result = self.call_controller_with_response_body(
- self.raise_result_iter(vcs_kind='unknown'))
+ def test_raises_unknown_exceptions(self, baseapp):
+ app_ini_config = baseapp.config.registry.settings['__file__']
+ result = self.call_controller_with_response_body(app_ini_config, self.raise_result_iter(vcs_kind='unknown'))
with pytest.raises(Exception):
list(result)
- def call_controller_with_response_body(self, response_body):
+ def call_controller_with_response_body(self, ini_config, response_body):
+
settings = {
- 'base_path': 'fake_base_path',
'vcs.hooks.protocol.v2': 'celery',
'vcs.hooks.direct_calls': False,
}
@@ -407,7 +459,7 @@ class TestGenerateVcsResponse(object):
result = controller._generate_vcs_response(
environ={}, start_response=self.start_response,
repo_path='fake_repo_path',
- extras={}, action='push')
+ extras={'config': ini_config}, action='push')
self.controller = controller
return result
diff --git a/rhodecode/tests/lib/middleware/utils/test_scm_app_http.py b/rhodecode/tests/lib/middleware/utils/test_scm_app_http.py
index 3f9b7b75..6530618c 100644
--- a/rhodecode/tests/lib/middleware/utils/test_scm_app_http.py
+++ b/rhodecode/tests/lib/middleware/utils/test_scm_app_http.py
@@ -19,6 +19,7 @@
# and proprietary license terms, please see https://rhodecode.com/licenses/
import pytest
+import tempfile
from rhodecode.tests.utils import CustomTestApp
from rhodecode.lib.middleware.utils import scm_app_http, scm_app
@@ -41,10 +42,13 @@ def vcsserver_http_echo_app(request, vcsserver_factory):
"""
A running VCSServer with the EchoApp activated via HTTP.
"""
- vcsserver = vcsserver_factory(
+ store_dir = tempfile.gettempdir()
+
+ vcsserver_instance = vcsserver_factory(
request=request,
+ store_dir=store_dir,
overrides=[{'app:main': {'dev.use_echo_app': 'true'}}])
- return vcsserver
+ return vcsserver_instance
@pytest.fixture(scope='session')
diff --git a/rhodecode/tests/lib/test_auth.py b/rhodecode/tests/lib/test_auth.py
index 63955c53..1b8f98bc 100644
--- a/rhodecode/tests/lib/test_auth.py
+++ b/rhodecode/tests/lib/test_auth.py
@@ -1,5 +1,4 @@
-
-# Copyright (C) 2010-2023 RhodeCode GmbH
+# 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
diff --git a/rhodecode/tests/lib/test_diffs.py b/rhodecode/tests/lib/test_diffs.py
index e543d78f..c38c7bb7 100644
--- a/rhodecode/tests/lib/test_diffs.py
+++ b/rhodecode/tests/lib/test_diffs.py
@@ -30,7 +30,7 @@ from rhodecode.lib.diffs import (
from rhodecode.lib.utils2 import AttributeDict
from rhodecode.lib.vcs.backends.git import GitCommit
-from rhodecode.tests.fixture import Fixture
+from rhodecode.tests.fixtures.rc_fixture import Fixture
from rhodecode.tests import no_newline_id_generator
from rhodecode.lib.vcs.backends.git.repository import GitDiff
from rhodecode.lib.vcs.backends.hg.repository import MercurialDiff
diff --git a/rhodecode/tests/lib/test_hooks_daemon.py b/rhodecode/tests/lib/test_hooks_daemon.py
index cf6b6500..1e4e079e 100644
--- a/rhodecode/tests/lib/test_hooks_daemon.py
+++ b/rhodecode/tests/lib/test_hooks_daemon.py
@@ -1,5 +1,4 @@
-
-# Copyright (C) 2010-2023 RhodeCode GmbH
+# 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
@@ -18,305 +17,71 @@
# and proprietary license terms, please see https://rhodecode.com/licenses/
import logging
-import io
import mock
-import msgpack
import pytest
import tempfile
-from rhodecode.lib.hook_daemon import http_hooks_deamon
from rhodecode.lib.hook_daemon import celery_hooks_deamon
-from rhodecode.lib.hook_daemon import hook_module
+from rhodecode.lib.hook_daemon import utils as hooks_utils
from rhodecode.lib.hook_daemon import base as hook_base
-from rhodecode.lib.str_utils import safe_bytes
-from rhodecode.tests.utils import assert_message_in_log
-from rhodecode.lib.ext_json import json
-test_proto = http_hooks_deamon.HooksHttpHandler.MSGPACK_HOOKS_PROTO
+from rhodecode.tests.utils import assert_message_in_log
class TestHooks(object):
def test_hooks_can_be_used_as_a_context_processor(self):
- hooks = hook_module.Hooks()
+ hooks = hook_base.Hooks()
with hooks as return_value:
pass
assert hooks == return_value
-
-class TestHooksHttpHandler(object):
- def test_read_request_parses_method_name_and_arguments(self):
- data = {
- 'method': 'test',
- 'extras': {
- 'param1': 1,
- 'param2': 'a'
- }
- }
- request = self._generate_post_request(data)
- hooks_patcher = mock.patch.object(
- hook_module.Hooks, data['method'], create=True, return_value=1)
-
- with hooks_patcher as hooks_mock:
- handler = http_hooks_deamon.HooksHttpHandler
- handler.DEFAULT_HOOKS_PROTO = test_proto
- handler.wbufsize = 10240
- MockServer(handler, request)
-
- hooks_mock.assert_called_once_with(data['extras'])
-
- def test_hooks_serialized_result_is_returned(self):
- request = self._generate_post_request({})
- rpc_method = 'test'
- hook_result = {
- 'first': 'one',
- 'second': 2
- }
- extras = {}
-
- # patching our _read to return test method and proto used
- read_patcher = mock.patch.object(
- http_hooks_deamon.HooksHttpHandler, '_read_request',
- return_value=(test_proto, rpc_method, extras))
-
- # patch Hooks instance to return hook_result data on 'test' call
- hooks_patcher = mock.patch.object(
- hook_module.Hooks, rpc_method, create=True,
- return_value=hook_result)
-
- with read_patcher, hooks_patcher:
- handler = http_hooks_deamon.HooksHttpHandler
- handler.DEFAULT_HOOKS_PROTO = test_proto
- handler.wbufsize = 10240
- server = MockServer(handler, request)
-
- expected_result = http_hooks_deamon.HooksHttpHandler.serialize_data(hook_result)
-
- server.request.output_stream.seek(0)
- assert server.request.output_stream.readlines()[-1] == expected_result
-
- def test_exception_is_returned_in_response(self):
- request = self._generate_post_request({})
- rpc_method = 'test'
-
- read_patcher = mock.patch.object(
- http_hooks_deamon.HooksHttpHandler, '_read_request',
- return_value=(test_proto, rpc_method, {}))
-
- hooks_patcher = mock.patch.object(
- hook_module.Hooks, rpc_method, create=True,
- side_effect=Exception('Test exception'))
-
- with read_patcher, hooks_patcher:
- handler = http_hooks_deamon.HooksHttpHandler
- handler.DEFAULT_HOOKS_PROTO = test_proto
- handler.wbufsize = 10240
- server = MockServer(handler, request)
-
- server.request.output_stream.seek(0)
- data = server.request.output_stream.readlines()
- msgpack_data = b''.join(data[5:])
- org_exc = http_hooks_deamon.HooksHttpHandler.deserialize_data(msgpack_data)
- expected_result = {
- 'exception': 'Exception',
- 'exception_traceback': org_exc['exception_traceback'],
- 'exception_args': ['Test exception']
- }
- assert org_exc == expected_result
-
- def test_log_message_writes_to_debug_log(self, caplog):
- ip_port = ('0.0.0.0', 8888)
- handler = http_hooks_deamon.HooksHttpHandler(MockRequest('POST /'), ip_port, mock.Mock())
- fake_date = '1/Nov/2015 00:00:00'
- date_patcher = mock.patch.object(
- handler, 'log_date_time_string', return_value=fake_date)
-
- with date_patcher, caplog.at_level(logging.DEBUG):
- handler.log_message('Some message %d, %s', 123, 'string')
-
- expected_message = f"HOOKS: client={ip_port} - - [{fake_date}] Some message 123, string"
-
- assert_message_in_log(
- caplog.records, expected_message,
- levelno=logging.DEBUG, module='http_hooks_deamon')
-
- def _generate_post_request(self, data, proto=test_proto):
- if proto == http_hooks_deamon.HooksHttpHandler.MSGPACK_HOOKS_PROTO:
- payload = msgpack.packb(data)
- else:
- payload = json.dumps(data)
-
- return b'POST / HTTP/1.0\nContent-Length: %d\n\n%b' % (
- len(payload), payload)
-
-
-class ThreadedHookCallbackDaemon(object):
- def test_constructor_calls_prepare(self):
- prepare_daemon_patcher = mock.patch.object(
- http_hooks_deamon.ThreadedHookCallbackDaemon, '_prepare')
- with prepare_daemon_patcher as prepare_daemon_mock:
- http_hooks_deamon.ThreadedHookCallbackDaemon()
- prepare_daemon_mock.assert_called_once_with()
-
- def test_run_is_called_on_context_start(self):
- patchers = mock.patch.multiple(
- http_hooks_deamon.ThreadedHookCallbackDaemon,
- _run=mock.DEFAULT, _prepare=mock.DEFAULT, __exit__=mock.DEFAULT)
-
- with patchers as mocks:
- daemon = http_hooks_deamon.ThreadedHookCallbackDaemon()
- with daemon as daemon_context:
- pass
- mocks['_run'].assert_called_once_with()
- assert daemon_context == daemon
-
- def test_stop_is_called_on_context_exit(self):
- patchers = mock.patch.multiple(
- http_hooks_deamon.ThreadedHookCallbackDaemon,
- _run=mock.DEFAULT, _prepare=mock.DEFAULT, _stop=mock.DEFAULT)
-
- with patchers as mocks:
- daemon = http_hooks_deamon.ThreadedHookCallbackDaemon()
- with daemon as daemon_context:
- assert mocks['_stop'].call_count == 0
-
- mocks['_stop'].assert_called_once_with()
- assert daemon_context == daemon
-
-
-class TestHttpHooksCallbackDaemon(object):
- def test_hooks_callback_generates_new_port(self, caplog):
- with caplog.at_level(logging.DEBUG):
- daemon = http_hooks_deamon.HttpHooksCallbackDaemon(host='127.0.0.1', port=8881)
- assert daemon._daemon.server_address == ('127.0.0.1', 8881)
-
- with caplog.at_level(logging.DEBUG):
- daemon = http_hooks_deamon.HttpHooksCallbackDaemon(host=None, port=None)
- assert daemon._daemon.server_address[1] in range(0, 66000)
- assert daemon._daemon.server_address[0] != '127.0.0.1'
-
- def test_prepare_inits_daemon_variable(self, tcp_server, caplog):
- with self._tcp_patcher(tcp_server), caplog.at_level(logging.DEBUG):
- daemon = http_hooks_deamon.HttpHooksCallbackDaemon(host='127.0.0.1', port=8881)
- assert daemon._daemon == tcp_server
-
- _, port = tcp_server.server_address
-
- msg = f"HOOKS: 127.0.0.1:{port} Preparing HTTP callback daemon registering " \
- f"hook object: "
- assert_message_in_log(
- caplog.records, msg, levelno=logging.DEBUG, module='http_hooks_deamon')
-
- def test_prepare_inits_hooks_uri_and_logs_it(
- self, tcp_server, caplog):
- with self._tcp_patcher(tcp_server), caplog.at_level(logging.DEBUG):
- daemon = http_hooks_deamon.HttpHooksCallbackDaemon(host='127.0.0.1', port=8881)
-
- _, port = tcp_server.server_address
- expected_uri = '{}:{}'.format('127.0.0.1', port)
- assert daemon.hooks_uri == expected_uri
-
- msg = f"HOOKS: 127.0.0.1:{port} Preparing HTTP callback daemon registering " \
- f"hook object: "
-
- assert_message_in_log(
- caplog.records, msg,
- levelno=logging.DEBUG, module='http_hooks_deamon')
-
- def test_run_creates_a_thread(self, tcp_server):
- thread = mock.Mock()
-
- with self._tcp_patcher(tcp_server):
- daemon = http_hooks_deamon.HttpHooksCallbackDaemon()
-
- with self._thread_patcher(thread) as thread_mock:
- daemon._run()
-
- thread_mock.assert_called_once_with(
- target=tcp_server.serve_forever,
- kwargs={'poll_interval': daemon.POLL_INTERVAL})
- assert thread.daemon is True
- thread.start.assert_called_once_with()
-
- def test_run_logs(self, tcp_server, caplog):
-
- with self._tcp_patcher(tcp_server):
- daemon = http_hooks_deamon.HttpHooksCallbackDaemon()
-
- with self._thread_patcher(mock.Mock()), caplog.at_level(logging.DEBUG):
- daemon._run()
-
- assert_message_in_log(
- caplog.records,
- 'Running thread-based loop of callback daemon in background',
- levelno=logging.DEBUG, module='http_hooks_deamon')
-
- def test_stop_cleans_up_the_connection(self, tcp_server, caplog):
- thread = mock.Mock()
-
- with self._tcp_patcher(tcp_server):
- daemon = http_hooks_deamon.HttpHooksCallbackDaemon()
-
- with self._thread_patcher(thread), caplog.at_level(logging.DEBUG):
- with daemon:
- assert daemon._daemon == tcp_server
- assert daemon._callback_thread == thread
-
- assert daemon._daemon is None
- assert daemon._callback_thread is None
- tcp_server.shutdown.assert_called_with()
- thread.join.assert_called_once_with()
-
- assert_message_in_log(
- caplog.records, 'Waiting for background thread to finish.',
- levelno=logging.DEBUG, module='http_hooks_deamon')
-
- def _tcp_patcher(self, tcp_server):
- return mock.patch.object(
- http_hooks_deamon, 'TCPServer', return_value=tcp_server)
-
- def _thread_patcher(self, thread):
- return mock.patch.object(
- http_hooks_deamon.threading, 'Thread', return_value=thread)
-
-
class TestPrepareHooksDaemon(object):
@pytest.mark.parametrize('protocol', ('celery',))
- def test_returns_celery_hooks_callback_daemon_when_celery_protocol_specified(
- self, protocol):
+ def test_returns_celery_hooks_callback_daemon_when_celery_protocol_specified(self, protocol):
with tempfile.NamedTemporaryFile(mode='w') as temp_file:
- temp_file.write("[app:main]\ncelery.broker_url = redis://redis/0\n"
- "celery.result_backend = redis://redis/0")
+ temp_file.write(
+ "[app:main]\n"
+ "celery.broker_url = redis://redis/0\n"
+ "celery.result_backend = redis://redis/0\n"
+ )
temp_file.flush()
expected_extras = {'config': temp_file.name}
- callback, extras = hook_base.prepare_callback_daemon(
- expected_extras, protocol=protocol, host='')
+ callback, extras = hooks_utils.prepare_callback_daemon(expected_extras, protocol=protocol)
assert isinstance(callback, celery_hooks_deamon.CeleryHooksCallbackDaemon)
@pytest.mark.parametrize('protocol, expected_class', (
- ('http', http_hooks_deamon.HttpHooksCallbackDaemon),
+ ('celery', celery_hooks_deamon.CeleryHooksCallbackDaemon),
))
- def test_returns_real_hooks_callback_daemon_when_protocol_is_specified(
- self, protocol, expected_class):
- expected_extras = {
- 'extra1': 'value1',
- 'txn_id': 'txnid2',
- 'hooks_protocol': protocol.lower(),
- 'task_backend': '',
- 'task_queue': '',
- 'repo_store': '/var/opt/rhodecode_repo_store',
- 'repository': 'rhodecode',
- }
- from rhodecode import CONFIG
- CONFIG['vcs.svn.redis_conn'] = 'redis://redis:6379/0'
- callback, extras = hook_base.prepare_callback_daemon(
- expected_extras.copy(), protocol=protocol, host='127.0.0.1',
- txn_id='txnid2')
- assert isinstance(callback, expected_class)
- extras.pop('hooks_uri')
- expected_extras['time'] = extras['time']
- assert extras == expected_extras
+ def test_returns_real_hooks_callback_daemon_when_protocol_is_specified(self, protocol, expected_class):
+
+ with tempfile.NamedTemporaryFile(mode='w') as temp_file:
+ temp_file.write(
+ "[app:main]\n"
+ "celery.broker_url = redis://redis:6379/0\n"
+ "celery.result_backend = redis://redis:6379/0\n"
+ )
+ temp_file.flush()
+
+ expected_extras = {
+ 'extra1': 'value1',
+ 'txn_id': 'txnid2',
+ 'hooks_protocol': protocol.lower(),
+ 'hooks_config': {
+ 'broker_url': 'redis://redis:6379/0',
+ 'result_backend': 'redis://redis:6379/0',
+ },
+ 'repo_store': '/var/opt/rhodecode_repo_store',
+ 'repository': 'rhodecode',
+ 'config': temp_file.name
+ }
+ from rhodecode import CONFIG
+ CONFIG['vcs.svn.redis_conn'] = 'redis://redis:6379/0'
+ callback, extras = hooks_utils.prepare_callback_daemon(expected_extras.copy(), protocol=protocol,txn_id='txnid2')
+ assert isinstance(callback, expected_class)
+ expected_extras['time'] = extras['time']
+ assert extras == expected_extras
@pytest.mark.parametrize('protocol', (
'invalid',
@@ -330,35 +95,4 @@ class TestPrepareHooksDaemon(object):
'hooks_protocol': protocol.lower()
}
with pytest.raises(Exception):
- callback, extras = hook_base.prepare_callback_daemon(
- expected_extras.copy(),
- protocol=protocol, host='127.0.0.1')
-
-
-class MockRequest(object):
-
- def __init__(self, request):
- self.request = request
- self.input_stream = io.BytesIO(safe_bytes(self.request))
- self.output_stream = io.BytesIO() # make it un-closable for testing invesitagion
- self.output_stream.close = lambda: None
-
- def makefile(self, mode, *args, **kwargs):
- return self.output_stream if mode == 'wb' else self.input_stream
-
-
-class MockServer(object):
-
- def __init__(self, handler_cls, request):
- ip_port = ('0.0.0.0', 8888)
- self.request = MockRequest(request)
- self.server_address = ip_port
- self.handler = handler_cls(self.request, ip_port, self)
-
-
-@pytest.fixture()
-def tcp_server():
- server = mock.Mock()
- server.server_address = ('127.0.0.1', 8881)
- server.wbufsize = 1024
- return server
+ callback, extras = hooks_utils.prepare_callback_daemon(expected_extras.copy(), protocol=protocol)
diff --git a/rhodecode/tests/lib/test_utils.py b/rhodecode/tests/lib/test_utils.py
index 41a48c40..6f68b38e 100644
--- a/rhodecode/tests/lib/test_utils.py
+++ b/rhodecode/tests/lib/test_utils.py
@@ -33,7 +33,7 @@ from rhodecode.model import meta
from rhodecode.model.repo import RepoModel
from rhodecode.model.repo_group import RepoGroupModel
from rhodecode.model.settings import UiSetting, SettingsModel
-from rhodecode.tests.fixture import Fixture
+from rhodecode.tests.fixtures.rc_fixture import Fixture
from rhodecode_tools.lib.hash_utils import md5_safe
from rhodecode.lib.ext_json import json
@@ -403,12 +403,9 @@ class TestPrepareConfigData(object):
self._assert_repo_name_passed(model_mock, repo_name)
- expected_result = [
- ('section1', 'option1', 'value1'),
- ('section2', 'option2', 'value2'),
- ]
- # We have extra config items returned, so we're ignoring two last items
- assert result[:2] == expected_result
+ assert ('section1', 'option1', 'value1') in result
+ assert ('section2', 'option2', 'value2') in result
+ assert ('section3', 'option3', 'value3') not in result
def _assert_repo_name_passed(self, model_mock, repo_name):
assert model_mock.call_count == 1
diff --git a/rhodecode/tests/load/http_performance.py b/rhodecode/tests/load/http_performance.py
index 505e37d4..ce64121b 100644
--- a/rhodecode/tests/load/http_performance.py
+++ b/rhodecode/tests/load/http_performance.py
@@ -25,7 +25,7 @@ It works by replaying a group of commits to the repo.
import argparse
import collections
-import ConfigParser
+import configparser
import functools
import itertools
import os
@@ -294,7 +294,7 @@ class HgMixin(object):
def add_remote(self, repo, remote_url, remote_name='upstream'):
self.remove_remote(repo, remote_name)
os.chdir(repo)
- hgrc = ConfigParser.RawConfigParser()
+ hgrc = configparser.RawConfigParser()
hgrc.read('.hg/hgrc')
hgrc.set('paths', remote_name, remote_url)
with open('.hg/hgrc', 'w') as f:
@@ -303,7 +303,7 @@ class HgMixin(object):
@keep_cwd
def remove_remote(self, repo, remote_name='upstream'):
os.chdir(repo)
- hgrc = ConfigParser.RawConfigParser()
+ hgrc = configparser.RawConfigParser()
hgrc.read('.hg/hgrc')
hgrc.remove_option('paths', remote_name)
with open('.hg/hgrc', 'w') as f:
diff --git a/rhodecode/tests/load/profile-mem.py b/rhodecode/tests/load/profile-mem.py
index 087fc644..96778bd1 100644
--- a/rhodecode/tests/load/profile-mem.py
+++ b/rhodecode/tests/load/profile-mem.py
@@ -59,16 +59,6 @@ def parse_options():
parser.add_argument(
'--interval', '-i', type=float, default=5,
help="Interval in secods.")
- parser.add_argument(
- '--appenlight', '--ae', action='store_true')
- parser.add_argument(
- '--appenlight-url', '--ae-url',
- default='https://ae.rhodecode.com/api/logs',
- help='URL of the Appenlight API endpoint, defaults to "%(default)s".')
- parser.add_argument(
- '--appenlight-api-key', '--ae-key',
- help='API key to use when sending data to appenlight. This has to be '
- 'set if Appenlight is enabled.')
return parser.parse_args()
diff --git a/rhodecode/tests/load/profile.py b/rhodecode/tests/load/profile.py
index f45567af..5a6a1f5f 100644
--- a/rhodecode/tests/load/profile.py
+++ b/rhodecode/tests/load/profile.py
@@ -1,4 +1,3 @@
-
# Copyright (C) 2010-2023 RhodeCode GmbH
#
# This program is free software: you can redistribute it and/or modify
diff --git a/rhodecode/tests/load/vcs_performance.py b/rhodecode/tests/load/vcs_performance.py
index e5ab98a7..f4ca7294 100644
--- a/rhodecode/tests/load/vcs_performance.py
+++ b/rhodecode/tests/load/vcs_performance.py
@@ -1,5 +1,3 @@
-
-
# Copyright (C) 2016-2023 RhodeCode GmbH
#
# This program is free software: you can redistribute it and/or modify
diff --git a/rhodecode/tests/models/common.py b/rhodecode/tests/models/common.py
index f41c4aab..0c98304e 100644
--- a/rhodecode/tests/models/common.py
+++ b/rhodecode/tests/models/common.py
@@ -22,7 +22,7 @@ from rhodecode.model.meta import Session
from rhodecode.model.repo_group import RepoGroupModel
from rhodecode.model.repo import RepoModel
from rhodecode.model.user import UserModel
-from rhodecode.tests.fixture import Fixture
+from rhodecode.tests.fixtures.rc_fixture import Fixture
fixture = Fixture()
diff --git a/rhodecode/tests/models/test_notifications.py b/rhodecode/tests/models/test_notifications.py
index 3b5b8715..fee49a4f 100644
--- a/rhodecode/tests/models/test_notifications.py
+++ b/rhodecode/tests/models/test_notifications.py
@@ -19,7 +19,7 @@
import pytest
-from rhodecode.tests.fixture import Fixture
+from rhodecode.tests.fixtures.rc_fixture import Fixture
from rhodecode.model.db import User, Notification, UserNotification
from rhodecode.model.meta import Session
diff --git a/rhodecode/tests/models/test_permissions.py b/rhodecode/tests/models/test_permissions.py
index 2efb6475..8722a774 100644
--- a/rhodecode/tests/models/test_permissions.py
+++ b/rhodecode/tests/models/test_permissions.py
@@ -29,7 +29,7 @@ from rhodecode.model.repo import RepoModel
from rhodecode.model.repo_group import RepoGroupModel
from rhodecode.model.user import UserModel
from rhodecode.model.user_group import UserGroupModel
-from rhodecode.tests.fixture import Fixture
+from rhodecode.tests.fixtures.rc_fixture import Fixture
fixture = Fixture()
diff --git a/rhodecode/tests/models/test_pullrequest.py b/rhodecode/tests/models/test_pullrequest.py
index 0df90b8c..9a09c098 100644
--- a/rhodecode/tests/models/test_pullrequest.py
+++ b/rhodecode/tests/models/test_pullrequest.py
@@ -1,4 +1,3 @@
-
# Copyright (C) 2010-2023 RhodeCode GmbH
#
# This program is free software: you can redistribute it and/or modify
@@ -16,6 +15,7 @@
# 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 os
import mock
import pytest
@@ -23,8 +23,7 @@ import textwrap
import rhodecode
from rhodecode.lib.vcs.backends import get_backend
-from rhodecode.lib.vcs.backends.base import (
- MergeResponse, MergeFailureReason, Reference)
+from rhodecode.lib.vcs.backends.base import MergeResponse, MergeFailureReason, Reference
from rhodecode.lib.vcs.exceptions import RepositoryError
from rhodecode.lib.vcs.nodes import FileNode
from rhodecode.model.comment import CommentsModel
@@ -39,54 +38,42 @@ pytestmark = [
]
-@pytest.mark.usefixtures('config_stub')
+@pytest.mark.usefixtures("config_stub")
class TestPullRequestModel(object):
-
@pytest.fixture()
def pull_request(self, request, backend, pr_util):
"""
A pull request combined with multiples patches.
"""
BackendClass = get_backend(backend.alias)
- merge_resp = MergeResponse(
- False, False, None, MergeFailureReason.UNKNOWN,
- metadata={'exception': 'MockError'})
- self.merge_patcher = mock.patch.object(
- BackendClass, 'merge', return_value=merge_resp)
- self.workspace_remove_patcher = mock.patch.object(
- BackendClass, 'cleanup_merge_workspace')
+ merge_resp = MergeResponse(False, False, None, MergeFailureReason.UNKNOWN, metadata={"exception": "MockError"})
+ self.merge_patcher = mock.patch.object(BackendClass, "merge", return_value=merge_resp)
+ self.workspace_remove_patcher = mock.patch.object(BackendClass, "cleanup_merge_workspace")
self.workspace_remove_mock = self.workspace_remove_patcher.start()
self.merge_mock = self.merge_patcher.start()
- self.comment_patcher = mock.patch(
- 'rhodecode.model.changeset_status.ChangesetStatusModel.set_status')
+ self.comment_patcher = mock.patch("rhodecode.model.changeset_status.ChangesetStatusModel.set_status")
self.comment_patcher.start()
- self.notification_patcher = mock.patch(
- 'rhodecode.model.notification.NotificationModel.create')
+ self.notification_patcher = mock.patch("rhodecode.model.notification.NotificationModel.create")
self.notification_patcher.start()
- self.helper_patcher = mock.patch(
- 'rhodecode.lib.helpers.route_path')
+ self.helper_patcher = mock.patch("rhodecode.lib.helpers.route_path")
self.helper_patcher.start()
- self.hook_patcher = mock.patch.object(PullRequestModel,
- 'trigger_pull_request_hook')
+ self.hook_patcher = mock.patch.object(PullRequestModel, "trigger_pull_request_hook")
self.hook_mock = self.hook_patcher.start()
- self.invalidation_patcher = mock.patch(
- 'rhodecode.model.pull_request.ScmModel.mark_for_invalidation')
+ self.invalidation_patcher = mock.patch("rhodecode.model.pull_request.ScmModel.mark_for_invalidation")
self.invalidation_mock = self.invalidation_patcher.start()
- self.pull_request = pr_util.create_pull_request(
- mergeable=True, name_suffix=u'ąć')
+ self.pull_request = pr_util.create_pull_request(mergeable=True, name_suffix="ąć")
self.source_commit = self.pull_request.source_ref_parts.commit_id
self.target_commit = self.pull_request.target_ref_parts.commit_id
- self.workspace_id = 'pr-%s' % self.pull_request.pull_request_id
+ self.workspace_id = f"pr-{self.pull_request.pull_request_id}"
self.repo_id = self.pull_request.target_repo.repo_id
@request.addfinalizer
def cleanup_pull_request():
- calls = [mock.call(
- self.pull_request, self.pull_request.author, 'create')]
+ calls = [mock.call(self.pull_request, self.pull_request.author, "create")]
self.hook_mock.assert_has_calls(calls)
self.workspace_remove_patcher.stop()
@@ -114,29 +101,30 @@ class TestPullRequestModel(object):
assert len(prs) == 1
def test_count_awaiting_review(self, pull_request):
- pr_count = PullRequestModel().count_awaiting_review(
- pull_request.target_repo)
+ pr_count = PullRequestModel().count_awaiting_review(pull_request.target_repo)
assert pr_count == 1
def test_get_awaiting_my_review(self, pull_request):
PullRequestModel().update_reviewers(
- pull_request, [(pull_request.author, ['author'], False, 'reviewer', [])],
- pull_request.author)
+ pull_request, [(pull_request.author, ["author"], False, "reviewer", [])], pull_request.author
+ )
Session().commit()
prs = PullRequestModel().get_awaiting_my_review(
- pull_request.target_repo.repo_name, user_id=pull_request.author.user_id)
+ pull_request.target_repo.repo_name, user_id=pull_request.author.user_id
+ )
assert isinstance(prs, list)
assert len(prs) == 1
def test_count_awaiting_my_review(self, pull_request):
PullRequestModel().update_reviewers(
- pull_request, [(pull_request.author, ['author'], False, 'reviewer', [])],
- pull_request.author)
+ pull_request, [(pull_request.author, ["author"], False, "reviewer", [])], pull_request.author
+ )
Session().commit()
pr_count = PullRequestModel().count_awaiting_my_review(
- pull_request.target_repo.repo_name, user_id=pull_request.author.user_id)
+ pull_request.target_repo.repo_name, user_id=pull_request.author.user_id
+ )
assert pr_count == 1
def test_delete_calls_cleanup_merge(self, pull_request):
@@ -144,24 +132,19 @@ class TestPullRequestModel(object):
PullRequestModel().delete(pull_request, pull_request.author)
Session().commit()
- self.workspace_remove_mock.assert_called_once_with(
- repo_id, self.workspace_id)
+ self.workspace_remove_mock.assert_called_once_with(repo_id, self.workspace_id)
def test_close_calls_cleanup_and_hook(self, pull_request):
- PullRequestModel().close_pull_request(
- pull_request, pull_request.author)
+ PullRequestModel().close_pull_request(pull_request, pull_request.author)
Session().commit()
repo_id = pull_request.target_repo.repo_id
- self.workspace_remove_mock.assert_called_once_with(
- repo_id, self.workspace_id)
- self.hook_mock.assert_called_with(
- self.pull_request, self.pull_request.author, 'close')
+ self.workspace_remove_mock.assert_called_once_with(repo_id, self.workspace_id)
+ self.hook_mock.assert_called_with(self.pull_request, self.pull_request.author, "close")
def test_merge_status(self, pull_request):
- self.merge_mock.return_value = MergeResponse(
- True, False, None, MergeFailureReason.NONE)
+ self.merge_mock.return_value = MergeResponse(True, False, None, MergeFailureReason.NONE)
assert pull_request._last_merge_source_rev is None
assert pull_request._last_merge_target_rev is None
@@ -169,13 +152,17 @@ class TestPullRequestModel(object):
merge_response, status, msg = PullRequestModel().merge_status(pull_request)
assert status is True
- assert msg == 'This pull request can be automatically merged.'
+ assert msg == "This pull request can be automatically merged."
self.merge_mock.assert_called_with(
- self.repo_id, self.workspace_id,
+ self.repo_id,
+ self.workspace_id,
pull_request.target_ref_parts,
pull_request.source_repo.scm_instance(),
- pull_request.source_ref_parts, dry_run=True,
- use_rebase=False, close_branch=False)
+ pull_request.source_ref_parts,
+ dry_run=True,
+ use_rebase=False,
+ close_branch=False,
+ )
assert pull_request._last_merge_source_rev == self.source_commit
assert pull_request._last_merge_target_rev == self.target_commit
@@ -184,13 +171,13 @@ class TestPullRequestModel(object):
self.merge_mock.reset_mock()
merge_response, status, msg = PullRequestModel().merge_status(pull_request)
assert status is True
- assert msg == 'This pull request can be automatically merged.'
+ assert msg == "This pull request can be automatically merged."
assert self.merge_mock.called is False
def test_merge_status_known_failure(self, pull_request):
self.merge_mock.return_value = MergeResponse(
- False, False, None, MergeFailureReason.MERGE_FAILED,
- metadata={'unresolved_files': 'file1'})
+ False, False, None, MergeFailureReason.MERGE_FAILED, metadata={"unresolved_files": "file1"}
+ )
assert pull_request._last_merge_source_rev is None
assert pull_request._last_merge_target_rev is None
@@ -198,13 +185,17 @@ class TestPullRequestModel(object):
merge_response, status, msg = PullRequestModel().merge_status(pull_request)
assert status is False
- assert msg == 'This pull request cannot be merged because of merge conflicts. file1'
+ assert msg == "This pull request cannot be merged because of merge conflicts. file1"
self.merge_mock.assert_called_with(
- self.repo_id, self.workspace_id,
+ self.repo_id,
+ self.workspace_id,
pull_request.target_ref_parts,
pull_request.source_repo.scm_instance(),
- pull_request.source_ref_parts, dry_run=True,
- use_rebase=False, close_branch=False)
+ pull_request.source_ref_parts,
+ dry_run=True,
+ use_rebase=False,
+ close_branch=False,
+ )
assert pull_request._last_merge_source_rev == self.source_commit
assert pull_request._last_merge_target_rev == self.target_commit
@@ -213,13 +204,13 @@ class TestPullRequestModel(object):
self.merge_mock.reset_mock()
merge_response, status, msg = PullRequestModel().merge_status(pull_request)
assert status is False
- assert msg == 'This pull request cannot be merged because of merge conflicts. file1'
+ assert msg == "This pull request cannot be merged because of merge conflicts. file1"
assert self.merge_mock.called is False
def test_merge_status_unknown_failure(self, pull_request):
self.merge_mock.return_value = MergeResponse(
- False, False, None, MergeFailureReason.UNKNOWN,
- metadata={'exception': 'MockError'})
+ False, False, None, MergeFailureReason.UNKNOWN, metadata={"exception": "MockError"}
+ )
assert pull_request._last_merge_source_rev is None
assert pull_request._last_merge_target_rev is None
@@ -227,15 +218,17 @@ class TestPullRequestModel(object):
merge_response, status, msg = PullRequestModel().merge_status(pull_request)
assert status is False
- assert msg == (
- 'This pull request cannot be merged because of an unhandled exception. '
- 'MockError')
+ assert msg == "This pull request cannot be merged because of an unhandled exception. MockError"
self.merge_mock.assert_called_with(
- self.repo_id, self.workspace_id,
+ self.repo_id,
+ self.workspace_id,
pull_request.target_ref_parts,
pull_request.source_repo.scm_instance(),
- pull_request.source_ref_parts, dry_run=True,
- use_rebase=False, close_branch=False)
+ pull_request.source_ref_parts,
+ dry_run=True,
+ use_rebase=False,
+ close_branch=False,
+ )
assert pull_request._last_merge_source_rev is None
assert pull_request._last_merge_target_rev is None
@@ -244,155 +237,136 @@ class TestPullRequestModel(object):
self.merge_mock.reset_mock()
merge_response, status, msg = PullRequestModel().merge_status(pull_request)
assert status is False
- assert msg == (
- 'This pull request cannot be merged because of an unhandled exception. '
- 'MockError')
+ assert msg == "This pull request cannot be merged because of an unhandled exception. MockError"
assert self.merge_mock.called is True
def test_merge_status_when_target_is_locked(self, pull_request):
- pull_request.target_repo.locked = [1, u'12345.50', 'lock_web']
+ pull_request.target_repo.locked = [1, "12345.50", "lock_web"]
merge_response, status, msg = PullRequestModel().merge_status(pull_request)
assert status is False
- assert msg == (
- 'This pull request cannot be merged because the target repository '
- 'is locked by user:1.')
+ assert msg == "This pull request cannot be merged because the target repository is locked by user:1."
def test_merge_status_requirements_check_target(self, pull_request):
-
def has_largefiles(self, repo):
return repo == pull_request.source_repo
- patcher = mock.patch.object(PullRequestModel, '_has_largefiles', has_largefiles)
+ patcher = mock.patch.object(PullRequestModel, "_has_largefiles", has_largefiles)
with patcher:
merge_response, status, msg = PullRequestModel().merge_status(pull_request)
assert status is False
- assert msg == 'Target repository large files support is disabled.'
+ assert msg == "Target repository large files support is disabled."
def test_merge_status_requirements_check_source(self, pull_request):
-
def has_largefiles(self, repo):
return repo == pull_request.target_repo
- patcher = mock.patch.object(PullRequestModel, '_has_largefiles', has_largefiles)
+ patcher = mock.patch.object(PullRequestModel, "_has_largefiles", has_largefiles)
with patcher:
merge_response, status, msg = PullRequestModel().merge_status(pull_request)
assert status is False
- assert msg == 'Source repository large files support is disabled.'
+ assert msg == "Source repository large files support is disabled."
def test_merge(self, pull_request, merge_extras):
user = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN)
- merge_ref = Reference(
- 'type', 'name', '6126b7bfcc82ad2d3deaee22af926b082ce54cc6')
- self.merge_mock.return_value = MergeResponse(
- True, True, merge_ref, MergeFailureReason.NONE)
+ merge_ref = Reference("type", "name", "6126b7bfcc82ad2d3deaee22af926b082ce54cc6")
+ self.merge_mock.return_value = MergeResponse(True, True, merge_ref, MergeFailureReason.NONE)
- merge_extras['repository'] = pull_request.target_repo.repo_name
- PullRequestModel().merge_repo(
- pull_request, pull_request.author, extras=merge_extras)
+ merge_extras["repository"] = pull_request.target_repo.repo_name
+ PullRequestModel().merge_repo(pull_request, pull_request.author, extras=merge_extras)
Session().commit()
- message = (
- u'Merge pull request !{pr_id} from {source_repo} {source_ref_name}'
- u'\n\n {pr_title}'.format(
- pr_id=pull_request.pull_request_id,
- source_repo=safe_str(
- pull_request.source_repo.scm_instance().name),
- source_ref_name=pull_request.source_ref_parts.name,
- pr_title=safe_str(pull_request.title)
- )
+ message = "Merge pull request !{pr_id} from {source_repo} {source_ref_name}" "\n\n {pr_title}".format(
+ pr_id=pull_request.pull_request_id,
+ source_repo=safe_str(pull_request.source_repo.scm_instance().name),
+ source_ref_name=pull_request.source_ref_parts.name,
+ pr_title=safe_str(pull_request.title),
)
self.merge_mock.assert_called_with(
- self.repo_id, self.workspace_id,
+ self.repo_id,
+ self.workspace_id,
pull_request.target_ref_parts,
pull_request.source_repo.scm_instance(),
pull_request.source_ref_parts,
- user_name=user.short_contact, user_email=user.email, message=message,
- use_rebase=False, close_branch=False
+ user_name=user.short_contact,
+ user_email=user.email,
+ message=message,
+ use_rebase=False,
+ close_branch=False,
)
- self.invalidation_mock.assert_called_once_with(
- pull_request.target_repo.repo_name)
+ self.invalidation_mock.assert_called_once_with(pull_request.target_repo.repo_name)
- self.hook_mock.assert_called_with(
- self.pull_request, self.pull_request.author, 'merge')
+ self.hook_mock.assert_called_with(self.pull_request, self.pull_request.author, "merge")
pull_request = PullRequest.get(pull_request.pull_request_id)
- assert pull_request.merge_rev == '6126b7bfcc82ad2d3deaee22af926b082ce54cc6'
+ assert pull_request.merge_rev == "6126b7bfcc82ad2d3deaee22af926b082ce54cc6"
def test_merge_with_status_lock(self, pull_request, merge_extras):
user = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN)
- merge_ref = Reference(
- 'type', 'name', '6126b7bfcc82ad2d3deaee22af926b082ce54cc6')
- self.merge_mock.return_value = MergeResponse(
- True, True, merge_ref, MergeFailureReason.NONE)
+ merge_ref = Reference("type", "name", "6126b7bfcc82ad2d3deaee22af926b082ce54cc6")
+ self.merge_mock.return_value = MergeResponse(True, True, merge_ref, MergeFailureReason.NONE)
- merge_extras['repository'] = pull_request.target_repo.repo_name
+ merge_extras["repository"] = pull_request.target_repo.repo_name
with pull_request.set_state(PullRequest.STATE_UPDATING):
assert pull_request.pull_request_state == PullRequest.STATE_UPDATING
- PullRequestModel().merge_repo(
- pull_request, pull_request.author, extras=merge_extras)
+ PullRequestModel().merge_repo(pull_request, pull_request.author, extras=merge_extras)
Session().commit()
assert pull_request.pull_request_state == PullRequest.STATE_CREATED
- message = (
- u'Merge pull request !{pr_id} from {source_repo} {source_ref_name}'
- u'\n\n {pr_title}'.format(
- pr_id=pull_request.pull_request_id,
- source_repo=safe_str(
- pull_request.source_repo.scm_instance().name),
- source_ref_name=pull_request.source_ref_parts.name,
- pr_title=safe_str(pull_request.title)
- )
+ message = "Merge pull request !{pr_id} from {source_repo} {source_ref_name}" "\n\n {pr_title}".format(
+ pr_id=pull_request.pull_request_id,
+ source_repo=safe_str(pull_request.source_repo.scm_instance().name),
+ source_ref_name=pull_request.source_ref_parts.name,
+ pr_title=safe_str(pull_request.title),
)
self.merge_mock.assert_called_with(
- self.repo_id, self.workspace_id,
+ self.repo_id,
+ self.workspace_id,
pull_request.target_ref_parts,
pull_request.source_repo.scm_instance(),
pull_request.source_ref_parts,
- user_name=user.short_contact, user_email=user.email, message=message,
- use_rebase=False, close_branch=False
+ user_name=user.short_contact,
+ user_email=user.email,
+ message=message,
+ use_rebase=False,
+ close_branch=False,
)
- self.invalidation_mock.assert_called_once_with(
- pull_request.target_repo.repo_name)
+ self.invalidation_mock.assert_called_once_with(pull_request.target_repo.repo_name)
- self.hook_mock.assert_called_with(
- self.pull_request, self.pull_request.author, 'merge')
+ self.hook_mock.assert_called_with(self.pull_request, self.pull_request.author, "merge")
pull_request = PullRequest.get(pull_request.pull_request_id)
- assert pull_request.merge_rev == '6126b7bfcc82ad2d3deaee22af926b082ce54cc6'
+ assert pull_request.merge_rev == "6126b7bfcc82ad2d3deaee22af926b082ce54cc6"
def test_merge_failed(self, pull_request, merge_extras):
user = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN)
- merge_ref = Reference(
- 'type', 'name', '6126b7bfcc82ad2d3deaee22af926b082ce54cc6')
- self.merge_mock.return_value = MergeResponse(
- False, False, merge_ref, MergeFailureReason.MERGE_FAILED)
+ merge_ref = Reference("type", "name", "6126b7bfcc82ad2d3deaee22af926b082ce54cc6")
+ self.merge_mock.return_value = MergeResponse(False, False, merge_ref, MergeFailureReason.MERGE_FAILED)
- merge_extras['repository'] = pull_request.target_repo.repo_name
- PullRequestModel().merge_repo(
- pull_request, pull_request.author, extras=merge_extras)
+ merge_extras["repository"] = pull_request.target_repo.repo_name
+ PullRequestModel().merge_repo(pull_request, pull_request.author, extras=merge_extras)
Session().commit()
- message = (
- u'Merge pull request !{pr_id} from {source_repo} {source_ref_name}'
- u'\n\n {pr_title}'.format(
- pr_id=pull_request.pull_request_id,
- source_repo=safe_str(
- pull_request.source_repo.scm_instance().name),
- source_ref_name=pull_request.source_ref_parts.name,
- pr_title=safe_str(pull_request.title)
- )
+ message = "Merge pull request !{pr_id} from {source_repo} {source_ref_name}" "\n\n {pr_title}".format(
+ pr_id=pull_request.pull_request_id,
+ source_repo=safe_str(pull_request.source_repo.scm_instance().name),
+ source_ref_name=pull_request.source_ref_parts.name,
+ pr_title=safe_str(pull_request.title),
)
self.merge_mock.assert_called_with(
- self.repo_id, self.workspace_id,
+ self.repo_id,
+ self.workspace_id,
pull_request.target_ref_parts,
pull_request.source_repo.scm_instance(),
pull_request.source_ref_parts,
- user_name=user.short_contact, user_email=user.email, message=message,
- use_rebase=False, close_branch=False
+ user_name=user.short_contact,
+ user_email=user.email,
+ message=message,
+ use_rebase=False,
+ close_branch=False,
)
pull_request = PullRequest.get(pull_request.pull_request_id)
@@ -410,7 +384,7 @@ class TestPullRequestModel(object):
assert commit_ids == pull_request.revisions
# Merge revision is not in the revisions list
- pull_request.merge_rev = 'f000' * 10
+ pull_request.merge_rev = "f000" * 10
commit_ids = PullRequestModel()._get_commit_ids(pull_request)
assert commit_ids == pull_request.revisions + [pull_request.merge_rev]
@@ -419,147 +393,126 @@ class TestPullRequestModel(object):
source_ref_id = pull_request.source_ref_parts.commit_id
target_ref_id = pull_request.target_ref_parts.commit_id
diff = PullRequestModel()._get_diff_from_pr_or_version(
- source_repo, source_ref_id, target_ref_id,
- hide_whitespace_changes=False, diff_context=6)
- assert b'file_1' in diff.raw.tobytes()
+ source_repo, source_ref_id, target_ref_id, hide_whitespace_changes=False, diff_context=6
+ )
+ assert b"file_1" in diff.raw.tobytes()
def test_generate_title_returns_unicode(self):
title = PullRequestModel().generate_pullrequest_title(
- source='source-dummy',
- source_ref='source-ref-dummy',
- target='target-dummy',
+ source="source-dummy",
+ source_ref="source-ref-dummy",
+ target="target-dummy",
)
assert type(title) == str
- @pytest.mark.parametrize('title, has_wip', [
- ('hello', False),
- ('hello wip', False),
- ('hello wip: xxx', False),
- ('[wip] hello', True),
- ('[wip] hello', True),
- ('wip: hello', True),
- ('wip hello', True),
-
- ])
+ @pytest.mark.parametrize(
+ "title, has_wip",
+ [
+ ("hello", False),
+ ("hello wip", False),
+ ("hello wip: xxx", False),
+ ("[wip] hello", True),
+ ("[wip] hello", True),
+ ("wip: hello", True),
+ ("wip hello", True),
+ ],
+ )
def test_wip_title_marker(self, pull_request, title, has_wip):
pull_request.title = title
assert pull_request.work_in_progress == has_wip
-@pytest.mark.usefixtures('config_stub')
+@pytest.mark.usefixtures("config_stub")
class TestIntegrationMerge(object):
- @pytest.mark.parametrize('extra_config', (
- {'vcs.hooks.protocol.v2': 'celery', 'vcs.hooks.direct_calls': False},
- ))
- def test_merge_triggers_push_hooks(
- self, pr_util, user_admin, capture_rcextensions, merge_extras,
- extra_config):
- pull_request = pr_util.create_pull_request(
- approved=True, mergeable=True)
- # TODO: johbo: Needed for sqlite, try to find an automatic way for it
- merge_extras['repository'] = pull_request.target_repo.repo_name
- Session().commit()
-
- with mock.patch.dict(rhodecode.CONFIG, extra_config, clear=False):
- merge_state = PullRequestModel().merge_repo(
- pull_request, user_admin, extras=merge_extras)
- Session().commit()
-
- assert merge_state.executed
- assert '_pre_push_hook' in capture_rcextensions
- assert '_push_hook' in capture_rcextensions
-
- def test_merge_can_be_rejected_by_pre_push_hook(
- self, pr_util, user_admin, capture_rcextensions, merge_extras):
- pull_request = pr_util.create_pull_request(
- approved=True, mergeable=True)
- # TODO: johbo: Needed for sqlite, try to find an automatic way for it
- merge_extras['repository'] = pull_request.target_repo.repo_name
- Session().commit()
-
- with mock.patch('rhodecode.EXTENSIONS.PRE_PUSH_HOOK') as pre_pull:
- pre_pull.side_effect = RepositoryError("Disallow push!")
- merge_status = PullRequestModel().merge_repo(
- pull_request, user_admin, extras=merge_extras)
- Session().commit()
-
- assert not merge_status.executed
- assert 'pre_push' not in capture_rcextensions
- assert 'post_push' not in capture_rcextensions
-
- def test_merge_fails_if_target_is_locked(
- self, pr_util, user_regular, merge_extras):
- pull_request = pr_util.create_pull_request(
- approved=True, mergeable=True)
- locked_by = [user_regular.user_id + 1, 12345.50, 'lock_web']
+ def test_merge_fails_if_target_is_locked(self, pr_util, user_regular, merge_extras):
+ pull_request = pr_util.create_pull_request(approved=True, mergeable=True)
+ locked_by = [user_regular.user_id + 1, 12345.50, "lock_web"]
pull_request.target_repo.locked = locked_by
# TODO: johbo: Check if this can work based on the database, currently
# all data is pre-computed, that's why just updating the DB is not
# enough.
- merge_extras['locked_by'] = locked_by
- merge_extras['repository'] = pull_request.target_repo.repo_name
+ merge_extras["locked_by"] = locked_by
+ merge_extras["repository"] = pull_request.target_repo.repo_name
# TODO: johbo: Needed for sqlite, try to find an automatic way for it
Session().commit()
- merge_status = PullRequestModel().merge_repo(
- pull_request, user_regular, extras=merge_extras)
+ merge_status = PullRequestModel().merge_repo(pull_request, user_regular, extras=merge_extras)
Session().commit()
assert not merge_status.executed
-@pytest.mark.parametrize('use_outdated, inlines_count, outdated_count', [
- (False, 1, 0),
- (True, 0, 1),
-])
-def test_outdated_comments(
- pr_util, use_outdated, inlines_count, outdated_count, config_stub):
+@pytest.mark.parametrize(
+ "use_outdated, inlines_count, outdated_count",
+ [
+ (False, 1, 0),
+ (True, 0, 1),
+ ],
+)
+def test_outdated_comments(pr_util, use_outdated, inlines_count, outdated_count, config_stub):
pull_request = pr_util.create_pull_request()
- pr_util.create_inline_comment(file_path='not_in_updated_diff')
+ pr_util.create_inline_comment(file_path="not_in_updated_diff")
with outdated_comments_patcher(use_outdated) as outdated_comment_mock:
pr_util.add_one_commit()
- assert_inline_comments(
- pull_request, visible=inlines_count, outdated=outdated_count)
+ assert_inline_comments(pull_request, visible=inlines_count, outdated=outdated_count)
outdated_comment_mock.assert_called_with(pull_request)
-@pytest.mark.parametrize('mr_type, expected_msg', [
- (MergeFailureReason.NONE,
- 'This pull request can be automatically merged.'),
- (MergeFailureReason.UNKNOWN,
- 'This pull request cannot be merged because of an unhandled exception. CRASH'),
- (MergeFailureReason.MERGE_FAILED,
- 'This pull request cannot be merged because of merge conflicts. CONFLICT_FILE'),
- (MergeFailureReason.PUSH_FAILED,
- 'This pull request could not be merged because push to target:`some-repo@merge_commit` failed.'),
- (MergeFailureReason.TARGET_IS_NOT_HEAD,
- 'This pull request cannot be merged because the target `ref_name` is not a head.'),
- (MergeFailureReason.HG_SOURCE_HAS_MORE_BRANCHES,
- 'This pull request cannot be merged because the source contains more branches than the target.'),
- (MergeFailureReason.HG_TARGET_HAS_MULTIPLE_HEADS,
- 'This pull request cannot be merged because the target `ref_name` has multiple heads: `a,b,c`.'),
- (MergeFailureReason.TARGET_IS_LOCKED,
- 'This pull request cannot be merged because the target repository is locked by user:123.'),
- (MergeFailureReason.MISSING_TARGET_REF,
- 'This pull request cannot be merged because the target reference `ref_name` is missing.'),
- (MergeFailureReason.MISSING_SOURCE_REF,
- 'This pull request cannot be merged because the source reference `ref_name` is missing.'),
- (MergeFailureReason.SUBREPO_MERGE_FAILED,
- 'This pull request cannot be merged because of conflicts related to sub repositories.'),
-
-])
+@pytest.mark.parametrize(
+ "mr_type, expected_msg",
+ [
+ (MergeFailureReason.NONE, "This pull request can be automatically merged."),
+ (MergeFailureReason.UNKNOWN, "This pull request cannot be merged because of an unhandled exception. CRASH"),
+ (
+ MergeFailureReason.MERGE_FAILED,
+ "This pull request cannot be merged because of merge conflicts. CONFLICT_FILE",
+ ),
+ (
+ MergeFailureReason.PUSH_FAILED,
+ "This pull request could not be merged because push to target:`some-repo@merge_commit` failed.",
+ ),
+ (
+ MergeFailureReason.TARGET_IS_NOT_HEAD,
+ "This pull request cannot be merged because the target `ref_name` is not a head.",
+ ),
+ (
+ MergeFailureReason.HG_SOURCE_HAS_MORE_BRANCHES,
+ "This pull request cannot be merged because the source contains more branches than the target.",
+ ),
+ (
+ MergeFailureReason.HG_TARGET_HAS_MULTIPLE_HEADS,
+ "This pull request cannot be merged because the target `ref_name` has multiple heads: `a,b,c`.",
+ ),
+ (
+ MergeFailureReason.TARGET_IS_LOCKED,
+ "This pull request cannot be merged because the target repository is locked by user:123.",
+ ),
+ (
+ MergeFailureReason.MISSING_TARGET_REF,
+ "This pull request cannot be merged because the target reference `ref_name` is missing.",
+ ),
+ (
+ MergeFailureReason.MISSING_SOURCE_REF,
+ "This pull request cannot be merged because the source reference `ref_name` is missing.",
+ ),
+ (
+ MergeFailureReason.SUBREPO_MERGE_FAILED,
+ "This pull request cannot be merged because of conflicts related to sub repositories.",
+ ),
+ ],
+)
def test_merge_response_message(mr_type, expected_msg):
- merge_ref = Reference('type', 'ref_name', '6126b7bfcc82ad2d3deaee22af926b082ce54cc6')
+ merge_ref = Reference("type", "ref_name", "6126b7bfcc82ad2d3deaee22af926b082ce54cc6")
metadata = {
- 'unresolved_files': 'CONFLICT_FILE',
- 'exception': "CRASH",
- 'target': 'some-repo',
- 'merge_commit': 'merge_commit',
- 'target_ref': merge_ref,
- 'source_ref': merge_ref,
- 'heads': ','.join(['a', 'b', 'c']),
- 'locked_by': 'user:123'
+ "unresolved_files": "CONFLICT_FILE",
+ "exception": "CRASH",
+ "target": "some-repo",
+ "merge_commit": "merge_commit",
+ "target_ref": merge_ref,
+ "source_ref": merge_ref,
+ "heads": ",".join(["a", "b", "c"]),
+ "locked_by": "user:123",
}
merge_response = MergeResponse(True, True, merge_ref, mr_type, metadata=metadata)
@@ -573,30 +526,28 @@ def merge_extras(request, user_regular):
"""
extras = {
- 'ip': '127.0.0.1',
- 'username': user_regular.username,
- 'user_id': user_regular.user_id,
- 'action': 'push',
- 'repository': 'fake_target_repo_name',
- 'scm': 'git',
- 'config': request.config.getini('pyramid_config'),
- 'repo_store': '',
- 'make_lock': None,
- 'locked_by': [None, None, None],
- 'server_url': 'http://test.example.com:5000',
- 'hooks': ['push', 'pull'],
- 'is_shadow_repo': False,
+ "ip": "127.0.0.1",
+ "username": user_regular.username,
+ "user_id": user_regular.user_id,
+ "action": "push",
+ "repository": "fake_target_repo_name",
+ "scm": "git",
+ "config": request.config.getini("pyramid_config"),
+ "repo_store": "",
+ "make_lock": None,
+ "locked_by": [None, None, None],
+ "server_url": "http://test.example.com:5000",
+ "hooks": ["push", "pull"],
+ "is_shadow_repo": False,
}
return extras
-@pytest.mark.usefixtures('config_stub')
+@pytest.mark.usefixtures("config_stub")
class TestUpdateCommentHandling(object):
-
- @pytest.fixture(autouse=True, scope='class')
+ @pytest.fixture(autouse=True, scope="class")
def enable_outdated_comments(self, request, baseapp):
- config_patch = mock.patch.dict(
- 'rhodecode.CONFIG', {'rhodecode_use_outdated_comments': True})
+ config_patch = mock.patch.dict("rhodecode.CONFIG", {"rhodecode_use_outdated_comments": True})
config_patch.start()
@request.addfinalizer
@@ -605,206 +556,194 @@ class TestUpdateCommentHandling(object):
def test_comment_stays_unflagged_on_unchanged_diff(self, pr_util):
commits = [
- {'message': 'a'},
- {'message': 'b', 'added': [FileNode(b'file_b', b'test_content\n')]},
- {'message': 'c', 'added': [FileNode(b'file_c', b'test_content\n')]},
+ {"message": "a"},
+ {"message": "b", "added": [FileNode(b"file_b", b"test_content\n")]},
+ {"message": "c", "added": [FileNode(b"file_c", b"test_content\n")]},
]
- pull_request = pr_util.create_pull_request(
- commits=commits, target_head='a', source_head='b', revisions=['b'])
- pr_util.create_inline_comment(file_path='file_b')
- pr_util.add_one_commit(head='c')
+ pull_request = pr_util.create_pull_request(commits=commits, target_head="a", source_head="b", revisions=["b"])
+ pr_util.create_inline_comment(file_path="file_b")
+ pr_util.add_one_commit(head="c")
assert_inline_comments(pull_request, visible=1, outdated=0)
def test_comment_stays_unflagged_on_change_above(self, pr_util):
- original_content = b''.join((b'line %d\n' % x for x in range(1, 11)))
- updated_content = b'new_line_at_top\n' + original_content
+ original_content = b"".join((b"line %d\n" % x for x in range(1, 11)))
+ updated_content = b"new_line_at_top\n" + original_content
commits = [
- {'message': 'a'},
- {'message': 'b', 'added': [FileNode(b'file_b', original_content)]},
- {'message': 'c', 'changed': [FileNode(b'file_b', updated_content)]},
+ {"message": "a"},
+ {"message": "b", "added": [FileNode(b"file_b", original_content)]},
+ {"message": "c", "changed": [FileNode(b"file_b", updated_content)]},
]
- pull_request = pr_util.create_pull_request(
- commits=commits, target_head='a', source_head='b', revisions=['b'])
+ pull_request = pr_util.create_pull_request(commits=commits, target_head="a", source_head="b", revisions=["b"])
with outdated_comments_patcher():
- comment = pr_util.create_inline_comment(
- line_no=u'n8', file_path='file_b')
- pr_util.add_one_commit(head='c')
+ comment = pr_util.create_inline_comment(line_no="n8", file_path="file_b")
+ pr_util.add_one_commit(head="c")
assert_inline_comments(pull_request, visible=1, outdated=0)
- assert comment.line_no == u'n9'
+ assert comment.line_no == "n9"
def test_comment_stays_unflagged_on_change_below(self, pr_util):
- original_content = b''.join([b'line %d\n' % x for x in range(10)])
- updated_content = original_content + b'new_line_at_end\n'
+ original_content = b"".join([b"line %d\n" % x for x in range(10)])
+ updated_content = original_content + b"new_line_at_end\n"
commits = [
- {'message': 'a'},
- {'message': 'b', 'added': [FileNode(b'file_b', original_content)]},
- {'message': 'c', 'changed': [FileNode(b'file_b', updated_content)]},
+ {"message": "a"},
+ {"message": "b", "added": [FileNode(b"file_b", original_content)]},
+ {"message": "c", "changed": [FileNode(b"file_b", updated_content)]},
]
- pull_request = pr_util.create_pull_request(
- commits=commits, target_head='a', source_head='b', revisions=['b'])
- pr_util.create_inline_comment(file_path='file_b')
- pr_util.add_one_commit(head='c')
+ pull_request = pr_util.create_pull_request(commits=commits, target_head="a", source_head="b", revisions=["b"])
+ pr_util.create_inline_comment(file_path="file_b")
+ pr_util.add_one_commit(head="c")
assert_inline_comments(pull_request, visible=1, outdated=0)
- @pytest.mark.parametrize('line_no', ['n4', 'o4', 'n10', 'o9'])
+ @pytest.mark.parametrize("line_no", ["n4", "o4", "n10", "o9"])
def test_comment_flagged_on_change_around_context(self, pr_util, line_no):
- base_lines = [b'line %d\n' % x for x in range(1, 13)]
+ base_lines = [b"line %d\n" % x for x in range(1, 13)]
change_lines = list(base_lines)
- change_lines.insert(6, b'line 6a added\n')
+ change_lines.insert(6, b"line 6a added\n")
# Changes on the last line of sight
update_lines = list(change_lines)
- update_lines[0] = b'line 1 changed\n'
- update_lines[-1] = b'line 12 changed\n'
+ update_lines[0] = b"line 1 changed\n"
+ update_lines[-1] = b"line 12 changed\n"
def file_b(lines):
- return FileNode(b'file_b', b''.join(lines))
+ return FileNode(b"file_b", b"".join(lines))
commits = [
- {'message': 'a', 'added': [file_b(base_lines)]},
- {'message': 'b', 'changed': [file_b(change_lines)]},
- {'message': 'c', 'changed': [file_b(update_lines)]},
+ {"message": "a", "added": [file_b(base_lines)]},
+ {"message": "b", "changed": [file_b(change_lines)]},
+ {"message": "c", "changed": [file_b(update_lines)]},
]
- pull_request = pr_util.create_pull_request(
- commits=commits, target_head='a', source_head='b', revisions=['b'])
- pr_util.create_inline_comment(line_no=line_no, file_path='file_b')
+ pull_request = pr_util.create_pull_request(commits=commits, target_head="a", source_head="b", revisions=["b"])
+ pr_util.create_inline_comment(line_no=line_no, file_path="file_b")
with outdated_comments_patcher():
- pr_util.add_one_commit(head='c')
+ pr_util.add_one_commit(head="c")
assert_inline_comments(pull_request, visible=0, outdated=1)
- @pytest.mark.parametrize("change, content", [
- ('changed', b'changed\n'),
- ('removed', b''),
- ], ids=['changed', b'removed'])
+ @pytest.mark.parametrize(
+ "change, content",
+ [
+ ("changed", b"changed\n"),
+ ("removed", b""),
+ ],
+ ids=["changed", b"removed"],
+ )
def test_comment_flagged_on_change(self, pr_util, change, content):
commits = [
- {'message': 'a'},
- {'message': 'b', 'added': [FileNode(b'file_b', b'test_content\n')]},
- {'message': 'c', change: [FileNode(b'file_b', content)]},
+ {"message": "a"},
+ {"message": "b", "added": [FileNode(b"file_b", b"test_content\n")]},
+ {"message": "c", change: [FileNode(b"file_b", content)]},
]
- pull_request = pr_util.create_pull_request(
- commits=commits, target_head='a', source_head='b', revisions=['b'])
- pr_util.create_inline_comment(file_path='file_b')
+ pull_request = pr_util.create_pull_request(commits=commits, target_head="a", source_head="b", revisions=["b"])
+ pr_util.create_inline_comment(file_path="file_b")
with outdated_comments_patcher():
- pr_util.add_one_commit(head='c')
+ pr_util.add_one_commit(head="c")
assert_inline_comments(pull_request, visible=0, outdated=1)
-@pytest.mark.usefixtures('config_stub')
+@pytest.mark.usefixtures("config_stub")
class TestUpdateChangedFiles(object):
-
def test_no_changes_on_unchanged_diff(self, pr_util):
commits = [
- {'message': 'a'},
- {'message': 'b',
- 'added': [FileNode(b'file_b', b'test_content b\n')]},
- {'message': 'c',
- 'added': [FileNode(b'file_c', b'test_content c\n')]},
+ {"message": "a"},
+ {"message": "b", "added": [FileNode(b"file_b", b"test_content b\n")]},
+ {"message": "c", "added": [FileNode(b"file_c", b"test_content c\n")]},
]
# open a PR from a to b, adding file_b
pull_request = pr_util.create_pull_request(
- commits=commits, target_head='a', source_head='b', revisions=['b'],
- name_suffix='per-file-review')
+ commits=commits, target_head="a", source_head="b", revisions=["b"], name_suffix="per-file-review"
+ )
# modify PR adding new file file_c
- pr_util.add_one_commit(head='c')
+ pr_util.add_one_commit(head="c")
- assert_pr_file_changes(
- pull_request,
- added=['file_c'],
- modified=[],
- removed=[])
+ assert_pr_file_changes(pull_request, added=["file_c"], modified=[], removed=[])
def test_modify_and_undo_modification_diff(self, pr_util):
commits = [
- {'message': 'a'},
- {'message': 'b',
- 'added': [FileNode(b'file_b', b'test_content b\n')]},
- {'message': 'c',
- 'changed': [FileNode(b'file_b', b'test_content b modified\n')]},
- {'message': 'd',
- 'changed': [FileNode(b'file_b', b'test_content b\n')]},
+ {"message": "a"},
+ {"message": "b", "added": [FileNode(b"file_b", b"test_content b\n")]},
+ {"message": "c", "changed": [FileNode(b"file_b", b"test_content b modified\n")]},
+ {"message": "d", "changed": [FileNode(b"file_b", b"test_content b\n")]},
]
# open a PR from a to b, adding file_b
pull_request = pr_util.create_pull_request(
- commits=commits, target_head='a', source_head='b', revisions=['b'],
- name_suffix='per-file-review')
+ commits=commits, target_head="a", source_head="b", revisions=["b"], name_suffix="per-file-review"
+ )
# modify PR modifying file file_b
- pr_util.add_one_commit(head='c')
+ pr_util.add_one_commit(head="c")
- assert_pr_file_changes(
- pull_request,
- added=[],
- modified=['file_b'],
- removed=[])
+ assert_pr_file_changes(pull_request, added=[], modified=["file_b"], removed=[])
# move the head again to d, which rollbacks change,
# meaning we should indicate no changes
- pr_util.add_one_commit(head='d')
+ pr_util.add_one_commit(head="d")
- assert_pr_file_changes(
- pull_request,
- added=[],
- modified=[],
- removed=[])
+ assert_pr_file_changes(pull_request, added=[], modified=[], removed=[])
def test_updated_all_files_in_pr(self, pr_util):
commits = [
- {'message': 'a'},
- {'message': 'b', 'added': [
- FileNode(b'file_a', b'test_content a\n'),
- FileNode(b'file_b', b'test_content b\n'),
- FileNode(b'file_c', b'test_content c\n')]},
- {'message': 'c', 'changed': [
- FileNode(b'file_a', b'test_content a changed\n'),
- FileNode(b'file_b', b'test_content b changed\n'),
- FileNode(b'file_c', b'test_content c changed\n')]},
+ {"message": "a"},
+ {
+ "message": "b",
+ "added": [
+ FileNode(b"file_a", b"test_content a\n"),
+ FileNode(b"file_b", b"test_content b\n"),
+ FileNode(b"file_c", b"test_content c\n"),
+ ],
+ },
+ {
+ "message": "c",
+ "changed": [
+ FileNode(b"file_a", b"test_content a changed\n"),
+ FileNode(b"file_b", b"test_content b changed\n"),
+ FileNode(b"file_c", b"test_content c changed\n"),
+ ],
+ },
]
# open a PR from a to b, changing 3 files
pull_request = pr_util.create_pull_request(
- commits=commits, target_head='a', source_head='b', revisions=['b'],
- name_suffix='per-file-review')
+ commits=commits, target_head="a", source_head="b", revisions=["b"], name_suffix="per-file-review"
+ )
- pr_util.add_one_commit(head='c')
+ pr_util.add_one_commit(head="c")
- assert_pr_file_changes(
- pull_request,
- added=[],
- modified=['file_a', 'file_b', 'file_c'],
- removed=[])
+ assert_pr_file_changes(pull_request, added=[], modified=["file_a", "file_b", "file_c"], removed=[])
def test_updated_and_removed_all_files_in_pr(self, pr_util):
commits = [
- {'message': 'a'},
- {'message': 'b', 'added': [
- FileNode(b'file_a', b'test_content a\n'),
- FileNode(b'file_b', b'test_content b\n'),
- FileNode(b'file_c', b'test_content c\n')]},
- {'message': 'c', 'removed': [
- FileNode(b'file_a', b'test_content a changed\n'),
- FileNode(b'file_b', b'test_content b changed\n'),
- FileNode(b'file_c', b'test_content c changed\n')]},
+ {"message": "a"},
+ {
+ "message": "b",
+ "added": [
+ FileNode(b"file_a", b"test_content a\n"),
+ FileNode(b"file_b", b"test_content b\n"),
+ FileNode(b"file_c", b"test_content c\n"),
+ ],
+ },
+ {
+ "message": "c",
+ "removed": [
+ FileNode(b"file_a", b"test_content a changed\n"),
+ FileNode(b"file_b", b"test_content b changed\n"),
+ FileNode(b"file_c", b"test_content c changed\n"),
+ ],
+ },
]
# open a PR from a to b, removing 3 files
pull_request = pr_util.create_pull_request(
- commits=commits, target_head='a', source_head='b', revisions=['b'],
- name_suffix='per-file-review')
+ commits=commits, target_head="a", source_head="b", revisions=["b"], name_suffix="per-file-review"
+ )
- pr_util.add_one_commit(head='c')
+ pr_util.add_one_commit(head="c")
- assert_pr_file_changes(
- pull_request,
- added=[],
- modified=[],
- removed=['file_a', 'file_b', 'file_c'])
+ assert_pr_file_changes(pull_request, added=[], modified=[], removed=["file_a", "file_b", "file_c"])
def test_update_writes_snapshot_into_pull_request_version(pr_util, config_stub):
@@ -866,8 +805,7 @@ def test_update_adds_a_comment_to_the_pull_request_about_the_change(pr_util, con
.. |under_review| replace:: *"Under Review"*"""
).format(commit_id[:12])
- pull_request_comments = sorted(
- pull_request.comments, key=lambda c: c.modified_at)
+ pull_request_comments = sorted(pull_request.comments, key=lambda c: c.modified_at)
update_comment = pull_request_comments[-1]
assert update_comment.text == expected_message
@@ -890,8 +828,8 @@ def test_create_version_from_snapshot_updates_attributes(pr_util, config_stub):
version = PullRequestModel()._create_version_from_snapshot(pull_request)
# Check attributes
- assert version.title == pr_util.create_parameters['title']
- assert version.description == pr_util.create_parameters['description']
+ assert version.title == pr_util.create_parameters["title"]
+ assert version.description == pr_util.create_parameters["description"]
assert version.status == PullRequest.STATUS_CLOSED
# versions get updated created_on
@@ -899,11 +837,11 @@ def test_create_version_from_snapshot_updates_attributes(pr_util, config_stub):
assert version.updated_on == updated_on
assert version.user_id == pull_request.user_id
- assert version.revisions == pr_util.create_parameters['revisions']
+ assert version.revisions == pr_util.create_parameters["revisions"]
assert version.source_repo == pr_util.source_repository
- assert version.source_ref == pr_util.create_parameters['source_ref']
+ assert version.source_ref == pr_util.create_parameters["source_ref"]
assert version.target_repo == pr_util.target_repository
- assert version.target_ref == pr_util.create_parameters['target_ref']
+ assert version.target_ref == pr_util.create_parameters["target_ref"]
assert version._last_merge_source_rev == pull_request._last_merge_source_rev
assert version._last_merge_target_rev == pull_request._last_merge_target_rev
assert version.last_merge_status == pull_request.last_merge_status
@@ -921,15 +859,9 @@ def test_link_comments_to_version_only_updates_unlinked_comments(pr_util, config
Session().commit()
# Expect that only the new comment is linked to version2
- assert (
- comment_unlinked.pull_request_version_id ==
- version2.pull_request_version_id)
- assert (
- comment_linked.pull_request_version_id ==
- version1.pull_request_version_id)
- assert (
- comment_unlinked.pull_request_version_id !=
- comment_linked.pull_request_version_id)
+ assert comment_unlinked.pull_request_version_id == version2.pull_request_version_id
+ assert comment_linked.pull_request_version_id == version1.pull_request_version_id
+ assert comment_unlinked.pull_request_version_id != comment_linked.pull_request_version_id
def test_calculate_commits():
@@ -945,35 +877,26 @@ def test_calculate_commits():
def assert_inline_comments(pull_request, visible=None, outdated=None):
if visible is not None:
inline_comments = CommentsModel().get_inline_comments(
- pull_request.target_repo.repo_id, pull_request=pull_request)
- inline_cnt = len(CommentsModel().get_inline_comments_as_list(
- inline_comments))
+ pull_request.target_repo.repo_id, pull_request=pull_request
+ )
+ inline_cnt = len(CommentsModel().get_inline_comments_as_list(inline_comments))
assert inline_cnt == visible
if outdated is not None:
- outdated_comments = CommentsModel().get_outdated_comments(
- pull_request.target_repo.repo_id, pull_request)
+ outdated_comments = CommentsModel().get_outdated_comments(pull_request.target_repo.repo_id, pull_request)
assert len(outdated_comments) == outdated
-def assert_pr_file_changes(
- pull_request, added=None, modified=None, removed=None):
+def assert_pr_file_changes(pull_request, added=None, modified=None, removed=None):
pr_versions = PullRequestModel().get_versions(pull_request)
# always use first version, ie original PR to calculate changes
pull_request_version = pr_versions[0]
- old_diff_data, new_diff_data = PullRequestModel()._generate_update_diffs(
- pull_request, pull_request_version)
- file_changes = PullRequestModel()._calculate_file_changes(
- old_diff_data, new_diff_data)
+ old_diff_data, new_diff_data = PullRequestModel()._generate_update_diffs(pull_request, pull_request_version)
+ file_changes = PullRequestModel()._calculate_file_changes(old_diff_data, new_diff_data)
- assert added == file_changes.added, \
- 'expected added:%s vs value:%s' % (added, file_changes.added)
- assert modified == file_changes.modified, \
- 'expected modified:%s vs value:%s' % (modified, file_changes.modified)
- assert removed == file_changes.removed, \
- 'expected removed:%s vs value:%s' % (removed, file_changes.removed)
+ assert added == file_changes.added, "expected added:%s vs value:%s" % (added, file_changes.added)
+ assert modified == file_changes.modified, "expected modified:%s vs value:%s" % (modified, file_changes.modified)
+ assert removed == file_changes.removed, "expected removed:%s vs value:%s" % (removed, file_changes.removed)
def outdated_comments_patcher(use_outdated=True):
- return mock.patch.object(
- CommentsModel, 'use_outdated_comments',
- return_value=use_outdated)
+ return mock.patch.object(CommentsModel, "use_outdated_comments", return_value=use_outdated)
diff --git a/rhodecode/tests/models/test_repo_groups.py b/rhodecode/tests/models/test_repo_groups.py
index 91a88a75..dee2a806 100644
--- a/rhodecode/tests/models/test_repo_groups.py
+++ b/rhodecode/tests/models/test_repo_groups.py
@@ -23,7 +23,7 @@ from sqlalchemy.exc import IntegrityError
import pytest
from rhodecode.tests import TESTS_TMP_PATH
-from rhodecode.tests.fixture import Fixture
+from rhodecode.tests.fixtures.rc_fixture import Fixture
from rhodecode.model.repo_group import RepoGroupModel
from rhodecode.model.repo import RepoModel
diff --git a/rhodecode/tests/models/test_user_group_permissions_on_repo_groups.py b/rhodecode/tests/models/test_user_group_permissions_on_repo_groups.py
index c32f7beb..83279902 100644
--- a/rhodecode/tests/models/test_user_group_permissions_on_repo_groups.py
+++ b/rhodecode/tests/models/test_user_group_permissions_on_repo_groups.py
@@ -28,7 +28,7 @@ from rhodecode.model.user_group import UserGroupModel
from rhodecode.tests.models.common import (
_create_project_tree, check_tree_perms, _get_perms, _check_expected_count,
expected_count, _destroy_project_tree)
-from rhodecode.tests.fixture import Fixture
+from rhodecode.tests.fixtures.rc_fixture import Fixture
fixture = Fixture()
diff --git a/rhodecode/tests/models/test_user_groups.py b/rhodecode/tests/models/test_user_groups.py
index 6f27e775..c21b6a31 100644
--- a/rhodecode/tests/models/test_user_groups.py
+++ b/rhodecode/tests/models/test_user_groups.py
@@ -22,7 +22,7 @@ import pytest
from rhodecode.model.db import User
from rhodecode.tests import TEST_USER_REGULAR_LOGIN
-from rhodecode.tests.fixture import Fixture
+from rhodecode.tests.fixtures.rc_fixture import Fixture
from rhodecode.model.user_group import UserGroupModel
from rhodecode.model.meta import Session
diff --git a/rhodecode/tests/models/test_users.py b/rhodecode/tests/models/test_users.py
index 1c9184a0..c4851c75 100644
--- a/rhodecode/tests/models/test_users.py
+++ b/rhodecode/tests/models/test_users.py
@@ -27,7 +27,7 @@ from rhodecode.model.user import UserModel
from rhodecode.model.user_group import UserGroupModel
from rhodecode.model.repo import RepoModel
from rhodecode.model.repo_group import RepoGroupModel
-from rhodecode.tests.fixture import Fixture
+from rhodecode.tests.fixtures.rc_fixture import Fixture
from rhodecode.lib.str_utils import safe_str
diff --git a/rhodecode/tests/other/test_validators.py b/rhodecode/tests/other/test_validators.py
index 6be345e6..d4fd4842 100644
--- a/rhodecode/tests/other/test_validators.py
+++ b/rhodecode/tests/other/test_validators.py
@@ -32,11 +32,11 @@ from rhodecode.model.meta import Session
from rhodecode.model.repo_group import RepoGroupModel
from rhodecode.model.db import ChangesetStatus, Repository
from rhodecode.model.changeset_status import ChangesetStatusModel
-from rhodecode.tests.fixture import Fixture
+from rhodecode.tests.fixtures.rc_fixture import Fixture
fixture = Fixture()
-pytestmark = pytest.mark.usefixtures('baseapp')
+pytestmark = pytest.mark.usefixtures("baseapp")
@pytest.fixture()
diff --git a/rhodecode/tests/rhodecode.ini b/rhodecode/tests/rhodecode.ini
index ab57657f..c628eba7 100644
--- a/rhodecode/tests/rhodecode.ini
+++ b/rhodecode/tests/rhodecode.ini
@@ -111,7 +111,7 @@ app.base_url = http://rhodecode.local
app.service_api.host = http://rhodecode.local:10020
; Secret for Service API authentication.
-app.service_api.token =
+app.service_api.token = secret4
; Unique application ID. Should be a random unique string for security.
app_instance_uuid = rc-production
@@ -351,7 +351,7 @@ archive_cache.objectstore.retry_attempts = 10
; and served from the cache during subsequent requests for the same archive of
; the repository. This path is important to be shared across filesystems and with
; RhodeCode and vcsserver
-archive_cache.filesystem.store_dir = %(here)s/rc-tests/archive_cache
+archive_cache.filesystem.store_dir = %(here)s/.rc-test-data/archive_cache
; The limit in GB sets how much data we cache before recycling last used, defaults to 10 gb
archive_cache.filesystem.cache_size_gb = 2
@@ -406,7 +406,7 @@ celery.task_store_eager_result = true
; Default cache dir for caches. Putting this into a ramdisk can boost performance.
; eg. /tmpfs/data_ramdisk, however this directory might require large amount of space
-cache_dir = %(here)s/rc-test-data
+cache_dir = %(here)s/.rc-test-data
; *********************************************
; `sql_cache_short` cache for heavy SQL queries
@@ -435,7 +435,7 @@ rc_cache.cache_repo_longterm.max_size = 10000
rc_cache.cache_general.backend = dogpile.cache.rc.file_namespace
rc_cache.cache_general.expiration_time = 43200
; file cache store path. Defaults to `cache_dir =` value or tempdir if both values are not set
-rc_cache.cache_general.arguments.filename = %(here)s/rc-tests/cache-backend/cache_general_db
+rc_cache.cache_general.arguments.filename = %(here)s/.rc-test-data/cache-backend/cache_general_db
; alternative `cache_general` redis backend with distributed lock
#rc_cache.cache_general.backend = dogpile.cache.rc.redis
@@ -454,6 +454,10 @@ rc_cache.cache_general.arguments.filename = %(here)s/rc-tests/cache-backend/cach
; auto-renew lock to prevent stale locks, slower but safer. Use only if problems happen
#rc_cache.cache_general.arguments.lock_auto_renewal = true
+; prefix for redis keys used for this cache backend, the final key is constructed using {custom-prefix}{key}
+#rc_cache.cache_general.arguments.key_prefix = custom-prefix-
+
+
; *************************************************
; `cache_perms` cache for permission tree, auth TTL
; for simplicity use rc.file_namespace backend,
@@ -462,7 +466,7 @@ rc_cache.cache_general.arguments.filename = %(here)s/rc-tests/cache-backend/cach
rc_cache.cache_perms.backend = dogpile.cache.rc.file_namespace
rc_cache.cache_perms.expiration_time = 0
; file cache store path. Defaults to `cache_dir =` value or tempdir if both values are not set
-rc_cache.cache_perms.arguments.filename = %(here)s/rc-tests/cache-backend/cache_perms_db
+rc_cache.cache_perms.arguments.filename = %(here)s/.rc-test-data/cache-backend/cache_perms_db
; alternative `cache_perms` redis backend with distributed lock
#rc_cache.cache_perms.backend = dogpile.cache.rc.redis
@@ -481,6 +485,10 @@ rc_cache.cache_perms.arguments.filename = %(here)s/rc-tests/cache-backend/cache_
; auto-renew lock to prevent stale locks, slower but safer. Use only if problems happen
#rc_cache.cache_perms.arguments.lock_auto_renewal = true
+; prefix for redis keys used for this cache backend, the final key is constructed using {custom-prefix}{key}
+#rc_cache.cache_perms.arguments.key_prefix = custom-prefix-
+
+
; ***************************************************
; `cache_repo` cache for file tree, Readme, RSS FEEDS
; for simplicity use rc.file_namespace backend,
@@ -489,7 +497,7 @@ rc_cache.cache_perms.arguments.filename = %(here)s/rc-tests/cache-backend/cache_
rc_cache.cache_repo.backend = dogpile.cache.rc.file_namespace
rc_cache.cache_repo.expiration_time = 2592000
; file cache store path. Defaults to `cache_dir =` value or tempdir if both values are not set
-rc_cache.cache_repo.arguments.filename = %(here)s/rc-tests/cache-backend/cache_repo_db
+rc_cache.cache_repo.arguments.filename = %(here)s/.rc-test-data/cache-backend/cache_repo_db
; alternative `cache_repo` redis backend with distributed lock
#rc_cache.cache_repo.backend = dogpile.cache.rc.redis
@@ -508,6 +516,10 @@ rc_cache.cache_repo.arguments.filename = %(here)s/rc-tests/cache-backend/cache_r
; auto-renew lock to prevent stale locks, slower but safer. Use only if problems happen
#rc_cache.cache_repo.arguments.lock_auto_renewal = true
+; prefix for redis keys used for this cache backend, the final key is constructed using {custom-prefix}{key}
+#rc_cache.cache_repo.arguments.key_prefix = custom-prefix-
+
+
; ##############
; BEAKER SESSION
; ##############
@@ -516,7 +528,7 @@ rc_cache.cache_repo.arguments.filename = %(here)s/rc-tests/cache-backend/cache_r
; types are file, ext:redis, ext:database, ext:memcached
; Fastest ones are ext:redis and ext:database, DO NOT use memory type for session
beaker.session.type = file
-beaker.session.data_dir = %(here)s/rc-tests/data/sessions
+beaker.session.data_dir = %(here)s/.rc-test-data/data/sessions
; Redis based sessions
#beaker.session.type = ext:redis
@@ -532,7 +544,7 @@ beaker.session.data_dir = %(here)s/rc-tests/data/sessions
beaker.session.key = rhodecode
beaker.session.secret = test-rc-uytcxaz
-beaker.session.lock_dir = %(here)s/rc-tests/data/sessions/lock
+beaker.session.lock_dir = %(here)s/.rc-test-data/data/sessions/lock
; Secure encrypted cookie. Requires AES and AES python libraries
; you must disable beaker.session.secret to use this
@@ -564,7 +576,7 @@ beaker.session.secure = false
; WHOOSH Backend, doesn't require additional services to run
; it works good with few dozen repos
search.module = rhodecode.lib.index.whoosh
-search.location = %(here)s/rc-tests/data/index
+search.location = %(here)s/.rc-test-data/data/index
; ####################
; CHANNELSTREAM CONFIG
@@ -584,7 +596,7 @@ channelstream.server = channelstream:9800
; see Nginx/Apache configuration examples in our docs
channelstream.ws_url = ws://rhodecode.yourserver.com/_channelstream
channelstream.secret = ENV_GENERATED
-channelstream.history.location = %(here)s/rc-tests/channelstream_history
+channelstream.history.location = %(here)s/.rc-test-data/channelstream_history
; Internal application path that Javascript uses to connect into.
; If you use proxy-prefix the prefix should be added before /_channelstream
@@ -601,7 +613,7 @@ channelstream.proxy_path = /_channelstream
; pymysql is an alternative driver for MySQL, use in case of problems with default one
#sqlalchemy.db1.url = mysql+pymysql://root:qweqwe@localhost/rhodecode
-sqlalchemy.db1.url = sqlite:///%(here)s/rc-tests/rhodecode_test.db?timeout=30
+sqlalchemy.db1.url = sqlite:///%(here)s/.rc-test-data/rhodecode_test.db?timeout=30
; see sqlalchemy docs for other advanced settings
; print the sql statements to output
@@ -737,7 +749,7 @@ ssh.generate_authorized_keyfile = true
; Path to the authorized_keys file where the generate entries are placed.
; It is possible to have multiple key files specified in `sshd_config` e.g.
; AuthorizedKeysFile %h/.ssh/authorized_keys %h/.ssh/authorized_keys_rhodecode
-ssh.authorized_keys_file_path = %(here)s/rc-tests/authorized_keys_rhodecode
+ssh.authorized_keys_file_path = %(here)s/.rc-test-data/authorized_keys_rhodecode
; Command to execute the SSH wrapper. The binary is available in the
; RhodeCode installation directory.
diff --git a/rhodecode/tests/run_full_tests.sh b/rhodecode/tests/run_full_tests.sh
deleted file mode 100755
index d50eefca..00000000
--- a/rhodecode/tests/run_full_tests.sh
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/sh
-set -e
-
-## MIGRATIONS AND DB TESTS ##
-echo "DATABASE CREATION TESTS"
-rhodecode/tests/database/test_creation.sh
-
-echo "DATABASE MIGRATIONS TESTS"
-rhodecode/tests/database/test_migration.sh
-
-## TEST VCS OPERATIONS ##
-echo "VCS FUNCTIONAL TESTS"
-rhodecode/tests/test_vcs_operations.sh
-
-## TOX TESTS ##
-echo "TOX TESTS"
-tox -r --develop
diff --git a/rhodecode/tests/server_utils.py b/rhodecode/tests/server_utils.py
index 4b062a47..d5aadc4b 100644
--- a/rhodecode/tests/server_utils.py
+++ b/rhodecode/tests/server_utils.py
@@ -24,13 +24,13 @@ import tempfile
import pytest
import subprocess
import logging
-from urllib.request import urlopen
-from urllib.error import URLError
+import requests
import configparser
from rhodecode.tests import TEST_USER_ADMIN_LOGIN, TEST_USER_ADMIN_PASS
from rhodecode.tests.utils import is_url_reachable
+from rhodecode.tests import console_printer
log = logging.getLogger(__name__)
@@ -49,7 +49,7 @@ def get_host_url(pyramid_config):
def assert_no_running_instance(url):
if is_url_reachable(url):
- print(f"Hint: Usually this means another instance of server "
+ console_printer(f"Hint: Usually this means another instance of server "
f"is running in the background at {url}.")
pytest.fail(f"Port is not free at {url}, cannot start server at")
@@ -58,8 +58,9 @@ class ServerBase(object):
_args = []
log_file_name = 'NOT_DEFINED.log'
status_url_tmpl = 'http://{host}:{port}/_admin/ops/ping'
+ console_marker = " :warning: [green]pytest-setup[/green] "
- def __init__(self, config_file, log_file):
+ def __init__(self, config_file, log_file, env):
self.config_file = config_file
config = configparser.ConfigParser()
config.read(config_file)
@@ -69,10 +70,10 @@ class ServerBase(object):
self._args = []
self.log_file = log_file or os.path.join(
tempfile.gettempdir(), self.log_file_name)
+ self.env = env
self.process = None
self.server_out = None
- log.info("Using the {} configuration:{}".format(
- self.__class__.__name__, config_file))
+ log.info(f"Using the {self.__class__.__name__} configuration:{config_file}")
if not os.path.isfile(config_file):
raise RuntimeError(f'Failed to get config at {config_file}')
@@ -110,18 +111,17 @@ class ServerBase(object):
while time.time() - start < timeout:
try:
- urlopen(status_url)
+ requests.get(status_url)
break
- except URLError:
+ except requests.exceptions.ConnectionError:
time.sleep(0.2)
else:
pytest.fail(
- "Starting the {} failed or took more than {} "
- "seconds. cmd: `{}`".format(
- self.__class__.__name__, timeout, self.command))
+ f"Starting the {self.__class__.__name__} failed or took more than {timeout} seconds."
+ f"cmd: `{self.command}`"
+ )
- log.info('Server of {} ready at url {}'.format(
- self.__class__.__name__, status_url))
+ log.info(f'Server of {self.__class__.__name__} ready at url {status_url}')
def shutdown(self):
self.process.kill()
@@ -130,7 +130,7 @@ class ServerBase(object):
def get_log_file_with_port(self):
log_file = list(self.log_file.partition('.log'))
- log_file.insert(1, get_port(self.config_file))
+ log_file.insert(1, f'-{get_port(self.config_file)}')
log_file = ''.join(log_file)
return log_file
@@ -140,11 +140,12 @@ class RcVCSServer(ServerBase):
Represents a running VCSServer instance.
"""
- log_file_name = 'rc-vcsserver.log'
+ log_file_name = 'rhodecode-vcsserver.log'
status_url_tmpl = 'http://{host}:{port}/status'
- def __init__(self, config_file, log_file=None, workers='3'):
- super(RcVCSServer, self).__init__(config_file, log_file)
+ def __init__(self, config_file, log_file=None, workers='3', env=None, info_prefix=''):
+ super(RcVCSServer, self).__init__(config_file, log_file, env)
+ self.info_prefix = info_prefix
self._args = [
'gunicorn',
'--bind', self.bind_addr,
@@ -164,9 +165,10 @@ class RcVCSServer(ServerBase):
host_url = self.host_url()
assert_no_running_instance(host_url)
- print(f'rhodecode-vcsserver starting at: {host_url}')
- print(f'rhodecode-vcsserver command: {self.command}')
- print(f'rhodecode-vcsserver logfile: {self.log_file}')
+ console_printer(f'{self.console_marker}{self.info_prefix}rhodecode-vcsserver starting at: {host_url}')
+ console_printer(f'{self.console_marker}{self.info_prefix}rhodecode-vcsserver command: {self.command}')
+ console_printer(f'{self.console_marker}{self.info_prefix}rhodecode-vcsserver logfile: {self.log_file}')
+ console_printer()
self.process = subprocess.Popen(
self._args, bufsize=0, env=env,
@@ -178,11 +180,12 @@ class RcWebServer(ServerBase):
Represents a running RCE web server used as a test fixture.
"""
- log_file_name = 'rc-web.log'
+ log_file_name = 'rhodecode-ce.log'
status_url_tmpl = 'http://{host}:{port}/_admin/ops/ping'
- def __init__(self, config_file, log_file=None, workers='2'):
- super(RcWebServer, self).__init__(config_file, log_file)
+ def __init__(self, config_file, log_file=None, workers='2', env=None, info_prefix=''):
+ super(RcWebServer, self).__init__(config_file, log_file, env)
+ self.info_prefix = info_prefix
self._args = [
'gunicorn',
'--bind', self.bind_addr,
@@ -195,7 +198,8 @@ class RcWebServer(ServerBase):
def start(self):
env = os.environ.copy()
- env['RC_NO_TMP_PATH'] = '1'
+ if self.env:
+ env.update(self.env)
self.log_file = self.get_log_file_with_port()
self.server_out = open(self.log_file, 'w')
@@ -203,9 +207,10 @@ class RcWebServer(ServerBase):
host_url = self.host_url()
assert_no_running_instance(host_url)
- print(f'rhodecode-web starting at: {host_url}')
- print(f'rhodecode-web command: {self.command}')
- print(f'rhodecode-web logfile: {self.log_file}')
+ console_printer(f'{self.console_marker}{self.info_prefix}rhodecode-ce starting at: {host_url}')
+ console_printer(f'{self.console_marker}{self.info_prefix}rhodecode-ce command: {self.command}')
+ console_printer(f'{self.console_marker}{self.info_prefix}rhodecode-ce logfile: {self.log_file}')
+ console_printer()
self.process = subprocess.Popen(
self._args, bufsize=0, env=env,
@@ -229,3 +234,44 @@ class RcWebServer(ServerBase):
}
params.update(**kwargs)
return params['user'], params['passwd']
+
+class CeleryServer(ServerBase):
+ log_file_name = 'rhodecode-celery.log'
+ status_url_tmpl = 'http://{host}:{port}/_admin/ops/ping'
+
+ def __init__(self, config_file, log_file=None, workers='2', env=None, info_prefix=''):
+ super(CeleryServer, self).__init__(config_file, log_file, env)
+ self.info_prefix = info_prefix
+ self._args = \
+ ['celery',
+ '--no-color',
+ '--app=rhodecode.lib.celerylib.loader',
+ 'worker',
+ '--autoscale=4,2',
+ '--max-tasks-per-child=30',
+ '--task-events',
+ '--loglevel=DEBUG',
+ '--ini=' + self.config_file]
+
+ def start(self):
+ env = os.environ.copy()
+ env['RC_NO_TEST_ENV'] = '1'
+
+ self.log_file = self.get_log_file_with_port()
+ self.server_out = open(self.log_file, 'w')
+
+ host_url = "Celery" #self.host_url()
+ #assert_no_running_instance(host_url)
+
+ console_printer(f'{self.console_marker}{self.info_prefix}rhodecode-celery starting at: {host_url}')
+ console_printer(f'{self.console_marker}{self.info_prefix}rhodecode-celery command: {self.command}')
+ console_printer(f'{self.console_marker}{self.info_prefix}rhodecode-celery logfile: {self.log_file}')
+ console_printer()
+
+ self.process = subprocess.Popen(
+ self._args, bufsize=0, env=env,
+ stdout=self.server_out, stderr=self.server_out)
+
+
+ def wait_until_ready(self, timeout=30):
+ time.sleep(2)
diff --git a/rhodecode/tests/test_vcs_operations.sh b/rhodecode/tests/test_vcs_operations.sh
deleted file mode 100755
index 60009b23..00000000
--- a/rhodecode/tests/test_vcs_operations.sh
+++ /dev/null
@@ -1,27 +0,0 @@
-#!/bin/sh
-set -e
-
-SQLITE_DB_PATH=/mnt/hgfs/marcink-shared/workspace-python/rhodecode
-RC_LOG=/tmp/rc.log
-INI_FILE=test.ini
-TEST_DB_NAME=rhodecode_test
-
-
-for databaseName in p m s; do
- # set the different DBs
- if [ "$databaseName" = "s" ]; then
- echo "sqlite"
- rhodecode-config --filename=$INI_FILE --update '[app:main]sqlalchemy.db1.url=sqlite:///'$SQLITE_DB_PATH/$TEST_DB_NAME'.sqlite'
- elif [ "$databaseName" = "p" ]; then
- echo "postgres"
- rhodecode-config --filename=$INI_FILE --update '[app:main]sqlalchemy.db1.url=postgresql://postgres:qweqwe@localhost/'$TEST_DB_NAME''
- elif [ "$databaseName" = "m" ]; then
- echo "mysql"
- rhodecode-config --filename=$INI_FILE --update '[app:main]sqlalchemy.db1.url=mysql://root:qweqwe@localhost/'$TEST_DB_NAME''
- fi
-
- # running just VCS tests
- RC_NO_TMP_PATH=1 py.test \
- rhodecode/tests/other/test_vcs_operations.py
-
-done
diff --git a/rhodecode/tests/utils.py b/rhodecode/tests/utils.py
index ec551d33..64a5d8f4 100644
--- a/rhodecode/tests/utils.py
+++ b/rhodecode/tests/utils.py
@@ -36,24 +36,29 @@ from webtest.app import TestResponse, TestApp
import pytest
-try:
- import rc_testdata
-except ImportError:
- raise ImportError('Failed to import rc_testdata, '
- 'please make sure this package is installed from requirements_test.txt')
-
from rhodecode.model.db import User, Repository
from rhodecode.model.meta import Session
from rhodecode.model.scm import ScmModel
from rhodecode.lib.vcs.backends.svn.repository import SubversionRepository
from rhodecode.lib.vcs.backends.base import EmptyCommit
-from rhodecode.tests import login_user_session
+from rhodecode.tests import login_user_session, console_printer
+from rhodecode.authentication import AuthenticationPluginRegistry
+from rhodecode.model.settings import SettingsModel
log = logging.getLogger(__name__)
-def print_to_func(value, print_to=sys.stderr):
- print(value, file=print_to)
+def console_printer_utils(msg):
+ console_printer(f" :white_check_mark: [green]test-utils[/green] {msg}")
+
+
+def get_rc_testdata():
+ try:
+ import rc_testdata
+ except ImportError:
+ raise ImportError('Failed to import rc_testdata, '
+ 'please make sure this package is installed from requirements_test.txt')
+ return rc_testdata
class CustomTestResponse(TestResponse):
@@ -73,7 +78,6 @@ class CustomTestResponse(TestResponse):
assert string in res
"""
print_body = kw.pop('print_body', False)
- print_to = kw.pop('print_to', sys.stderr)
if 'no' in kw:
no = kw['no']
@@ -89,18 +93,18 @@ class CustomTestResponse(TestResponse):
for s in strings:
if s not in self:
- print_to_func(f"Actual response (no {s!r}):", print_to=print_to)
- print_to_func(f"body output saved as `{f}`", print_to=print_to)
+ console_printer_utils(f"Actual response (no {s!r}):")
+ console_printer_utils(f"body output saved as `{f}`")
if print_body:
- print_to_func(str(self), print_to=print_to)
+ console_printer_utils(str(self))
raise IndexError(f"Body does not contain string {s!r}, body output saved as {f}")
for no_s in no:
if no_s in self:
- print_to_func(f"Actual response (has {no_s!r})", print_to=print_to)
- print_to_func(f"body output saved as `{f}`", print_to=print_to)
+ console_printer_utils(f"Actual response (has {no_s!r})")
+ console_printer_utils(f"body output saved as `{f}`")
if print_body:
- print_to_func(str(self), print_to=print_to)
+ console_printer_utils(str(self))
raise IndexError(f"Body contains bad string {no_s!r}, body output saved as {f}")
def assert_response(self):
@@ -209,6 +213,7 @@ def extract_git_repo_from_dump(dump_name, repo_name):
"""Create git repo `repo_name` from dump `dump_name`."""
repos_path = ScmModel().repos_path
target_path = os.path.join(repos_path, repo_name)
+ rc_testdata = get_rc_testdata()
rc_testdata.extract_git_dump(dump_name, target_path)
return target_path
@@ -217,6 +222,7 @@ def extract_hg_repo_from_dump(dump_name, repo_name):
"""Create hg repo `repo_name` from dump `dump_name`."""
repos_path = ScmModel().repos_path
target_path = os.path.join(repos_path, repo_name)
+ rc_testdata = get_rc_testdata()
rc_testdata.extract_hg_dump(dump_name, target_path)
return target_path
@@ -245,6 +251,7 @@ def _load_svn_dump_into_repo(dump_name, repo_path):
Currently the dumps are in rc_testdata. They might later on be
integrated with the main repository once they stabilize more.
"""
+ rc_testdata = get_rc_testdata()
dump = rc_testdata.load_svn_dump(dump_name)
load_dump = subprocess.Popen(
['svnadmin', 'load', repo_path],
@@ -254,9 +261,7 @@ def _load_svn_dump_into_repo(dump_name, repo_path):
if load_dump.returncode != 0:
log.error("Output of load_dump command: %s", out)
log.error("Error output of load_dump command: %s", err)
- raise Exception(
- 'Failed to load dump "%s" into repository at path "%s".'
- % (dump_name, repo_path))
+ raise Exception(f'Failed to load dump "{dump_name}" into repository at path "{repo_path}".')
class AssertResponse(object):
@@ -492,3 +497,54 @@ def permission_update_data_generator(csrf_token, default=None, grant=None, revok
('perm_del_member_type_{}'.format(obj_id), obj_type),
])
return form_data
+
+
+
+class AuthPluginManager:
+
+ def cleanup(self):
+ self._enable_plugins(['egg:rhodecode-enterprise-ce#rhodecode'])
+
+ def enable(self, plugins_list, override=None):
+ return self._enable_plugins(plugins_list, override)
+
+ @classmethod
+ def _enable_plugins(cls, plugins_list, override: object = None):
+ override = override or {}
+ params = {
+ 'auth_plugins': ','.join(plugins_list),
+ }
+
+ # helper translate some names to others, to fix settings code
+ name_map = {
+ 'token': 'authtoken'
+ }
+ log.debug('enable_auth_plugins: enabling following auth-plugins: %s', plugins_list)
+
+ for module in plugins_list:
+ plugin_name = module.partition('#')[-1]
+ if plugin_name in name_map:
+ plugin_name = name_map[plugin_name]
+ enabled_plugin = f'auth_{plugin_name}_enabled'
+ cache_ttl = f'auth_{plugin_name}_cache_ttl'
+
+ # default params that are needed for each plugin,
+ # `enabled` and `cache_ttl`
+ params.update({
+ enabled_plugin: True,
+ cache_ttl: 0
+ })
+ if override.get:
+ params.update(override.get(module, {}))
+
+ validated_params = params
+
+ for k, v in validated_params.items():
+ setting = SettingsModel().create_or_update_setting(k, v)
+ Session().add(setting)
+ Session().commit()
+
+ AuthenticationPluginRegistry.invalidate_auth_plugins_cache(hard=True)
+
+ enabled_plugins = SettingsModel().get_auth_plugins()
+ assert plugins_list == enabled_plugins
diff --git a/rhodecode/tests/vcs/__init__.py b/rhodecode/tests/vcs/__init__.py
index bdc53285..c4d86aeb 100644
--- a/rhodecode/tests/vcs/__init__.py
+++ b/rhodecode/tests/vcs/__init__.py
@@ -1,4 +1,3 @@
-
# Copyright (C) 2010-2023 RhodeCode GmbH
#
# This program is free software: you can redistribute it and/or modify
diff --git a/rhodecode/tests/vcs/conftest.py b/rhodecode/tests/vcs/conftest.py
index 5d321182..7e0313f8 100644
--- a/rhodecode/tests/vcs/conftest.py
+++ b/rhodecode/tests/vcs/conftest.py
@@ -1,4 +1,3 @@
-
# Copyright (C) 2010-2023 RhodeCode GmbH
#
# This program is free software: you can redistribute it and/or modify
@@ -32,8 +31,7 @@ from rhodecode.tests.utils import check_skip_backends, check_xfail_backends
@pytest.fixture()
-def vcs_repository_support(
- request, backend_alias, baseapp, _vcs_repo_container):
+def vcs_repository_support(request, backend_alias, baseapp, _vcs_repo_container):
"""
Provide a test repository for the test run.
@@ -63,7 +61,7 @@ def vcs_repository_support(
return backend_alias, repo
-@pytest.fixture(scope='class')
+@pytest.fixture(scope="class")
def _vcs_repo_container(request):
"""
Internal fixture intended to help support class based scoping on demand.
@@ -73,13 +71,12 @@ def _vcs_repo_container(request):
def _create_vcs_repo_container(request):
repo_container = VcsRepoContainer()
- if not request.config.getoption('--keep-tmp-path'):
+ if not request.config.getoption("--keep-tmp-path"):
request.addfinalizer(repo_container.cleanup)
return repo_container
class VcsRepoContainer(object):
-
def __init__(self):
self._cleanup_paths = []
self._repos = {}
@@ -98,14 +95,14 @@ class VcsRepoContainer(object):
def _should_create_repo_per_test(cls):
- return getattr(cls, 'recreate_repo_per_test', False)
+ return getattr(cls, "recreate_repo_per_test", False)
def _create_empty_repository(cls, backend_alias=None):
Backend = get_backend(backend_alias or cls.backend_alias)
repo_path = get_new_dir(str(time.time()))
repo = Backend(repo_path, create=True)
- if hasattr(cls, '_get_commits'):
+ if hasattr(cls, "_get_commits"):
commits = cls._get_commits()
cls.tip = _add_commits_to_repo(repo, commits)
@@ -127,7 +124,7 @@ def config():
specific content is required.
"""
config = Config()
- config.set('section-a', 'a-1', 'value-a-1')
+ config.set("section-a", "a-1", "value-a-1")
return config
@@ -136,24 +133,24 @@ def _add_commits_to_repo(repo, commits):
tip = None
for commit in commits:
- for node in commit.get('added', []):
+ for node in commit.get("added", []):
if not isinstance(node, FileNode):
node = FileNode(safe_bytes(node.path), content=node.content)
imc.add(node)
- for node in commit.get('changed', []):
+ for node in commit.get("changed", []):
if not isinstance(node, FileNode):
node = FileNode(safe_bytes(node.path), content=node.content)
imc.change(node)
- for node in commit.get('removed', []):
+ for node in commit.get("removed", []):
imc.remove(FileNode(safe_bytes(node.path)))
tip = imc.commit(
- message=str(commit['message']),
- author=str(commit['author']),
- date=commit['date'],
- branch=commit.get('branch')
+ message=str(commit["message"]),
+ author=str(commit["author"]),
+ date=commit["date"],
+ branch=commit.get("branch"),
)
return tip
@@ -183,16 +180,15 @@ def generate_repo_with_commits(vcs_repo):
start_date = datetime.datetime(2010, 1, 1, 20)
for x in range(num):
yield {
- 'message': 'Commit %d' % x,
- 'author': 'Joe Doe ',
- 'date': start_date + datetime.timedelta(hours=12 * x),
- 'added': [
- FileNode(b'file_%d.txt' % x, content=b'Foobar %d' % x),
+ "message": "Commit %d" % x,
+ "author": "Joe Doe ",
+ "date": start_date + datetime.timedelta(hours=12 * x),
+ "added": [
+ FileNode(b"file_%d.txt" % x, content=b"Foobar %d" % x),
+ ],
+ "modified": [
+ FileNode(b"file_%d.txt" % x, content=b"Foobar %d modified" % (x - 1)),
],
- 'modified': [
- FileNode(b'file_%d.txt' % x,
- content=b'Foobar %d modified' % (x-1)),
- ]
}
def commit_maker(num=5):
@@ -231,34 +227,33 @@ class BackendTestMixin(object):
created
before every single test. Defaults to ``True``.
"""
+
recreate_repo_per_test = True
@classmethod
def _get_commits(cls):
commits = [
{
- 'message': 'Initial commit',
- 'author': 'Joe Doe ',
- 'date': datetime.datetime(2010, 1, 1, 20),
- 'added': [
- FileNode(b'foobar', content=b'Foobar'),
- FileNode(b'foobar2', content=b'Foobar II'),
- FileNode(b'foo/bar/baz', content=b'baz here!'),
+ "message": "Initial commit",
+ "author": "Joe Doe ",
+ "date": datetime.datetime(2010, 1, 1, 20),
+ "added": [
+ FileNode(b"foobar", content=b"Foobar"),
+ FileNode(b"foobar2", content=b"Foobar II"),
+ FileNode(b"foo/bar/baz", content=b"baz here!"),
],
},
{
- 'message': 'Changes...',
- 'author': 'Jane Doe ',
- 'date': datetime.datetime(2010, 1, 1, 21),
- 'added': [
- FileNode(b'some/new.txt', content=b'news...'),
+ "message": "Changes...",
+ "author": "Jane Doe ",
+ "date": datetime.datetime(2010, 1, 1, 21),
+ "added": [
+ FileNode(b"some/new.txt", content=b"news..."),
],
- 'changed': [
- FileNode(b'foobar', b'Foobar I'),
+ "changed": [
+ FileNode(b"foobar", b"Foobar I"),
],
- 'removed': [],
+ "removed": [],
},
]
return commits
-
-
diff --git a/rhodecode/tests/vcs/test_archives.py b/rhodecode/tests/vcs/test_archives.py
index b9be4745..a22ff43d 100644
--- a/rhodecode/tests/vcs/test_archives.py
+++ b/rhodecode/tests/vcs/test_archives.py
@@ -1,4 +1,3 @@
-
# Copyright (C) 2010-2023 RhodeCode GmbH
#
# This program is free software: you can redistribute it and/or modify
@@ -43,121 +42,120 @@ def d_cache_config():
@pytest.mark.usefixtures("vcs_repository_support")
class TestArchives(BackendTestMixin):
-
@classmethod
def _get_commits(cls):
start_date = datetime.datetime(2010, 1, 1, 20)
yield {
- 'message': 'Initial Commit',
- 'author': 'Joe Doe ',
- 'date': start_date + datetime.timedelta(hours=12),
- 'added': [
- FileNode(b'executable_0o100755', b'mode_755', mode=0o100755),
- FileNode(b'executable_0o100500', b'mode_500', mode=0o100500),
- FileNode(b'not_executable', b'mode_644', mode=0o100644),
+ "message": "Initial Commit",
+ "author": "Joe Doe ",
+ "date": start_date + datetime.timedelta(hours=12),
+ "added": [
+ FileNode(b"executable_0o100755", b"mode_755", mode=0o100755),
+ FileNode(b"executable_0o100500", b"mode_500", mode=0o100500),
+ FileNode(b"not_executable", b"mode_644", mode=0o100644),
],
}
for x in range(5):
yield {
- 'message': 'Commit %d' % x,
- 'author': 'Joe Doe ',
- 'date': start_date + datetime.timedelta(hours=12 * x),
- 'added': [
- FileNode(b'%d/file_%d.txt' % (x, x), content=b'Foobar %d' % x),
+ "message": "Commit %d" % x,
+ "author": "Joe Doe ",
+ "date": start_date + datetime.timedelta(hours=12 * x),
+ "added": [
+ FileNode(b"%d/file_%d.txt" % (x, x), content=b"Foobar %d" % x),
],
}
- @pytest.mark.parametrize('compressor', ['gz', 'bz2'])
+ @pytest.mark.parametrize("compressor", ["gz", "bz2"])
def test_archive_tar(self, compressor, tmpdir, tmp_path, d_cache_config):
-
- archive_node = tmp_path / 'archive-node'
+ archive_node = tmp_path / "archive-node"
archive_node.touch()
archive_lnk = self.tip.archive_repo(
- str(archive_node), kind=f't{compressor}', archive_dir_name='repo', cache_config=d_cache_config)
+ str(archive_node), kind=f"t{compressor}", archive_dir_name="repo", cache_config=d_cache_config
+ )
out_dir = tmpdir
- out_file = tarfile.open(str(archive_lnk), f'r|{compressor}')
+ out_file = tarfile.open(str(archive_lnk), f"r|{compressor}")
out_file.extractall(out_dir)
out_file.close()
for x in range(5):
- node_path = '%d/file_%d.txt' % (x, x)
- with open(os.path.join(out_dir, 'repo/' + node_path), 'rb') as f:
+ node_path = "%d/file_%d.txt" % (x, x)
+ with open(os.path.join(out_dir, "repo/" + node_path), "rb") as f:
file_content = f.read()
assert file_content == self.tip.get_node(node_path).content
shutil.rmtree(out_dir)
- @pytest.mark.parametrize('compressor', ['gz', 'bz2'])
+ @pytest.mark.parametrize("compressor", ["gz", "bz2"])
def test_archive_tar_symlink(self, compressor):
- pytest.skip('Not supported')
+ pytest.skip("Not supported")
- @pytest.mark.parametrize('compressor', ['gz', 'bz2'])
+ @pytest.mark.parametrize("compressor", ["gz", "bz2"])
def test_archive_tar_file_modes(self, compressor, tmpdir, tmp_path, d_cache_config):
- archive_node = tmp_path / 'archive-node'
+ archive_node = tmp_path / "archive-node"
archive_node.touch()
archive_lnk = self.tip.archive_repo(
- str(archive_node), kind='t{}'.format(compressor), archive_dir_name='repo', cache_config=d_cache_config)
+ str(archive_node), kind="t{}".format(compressor), archive_dir_name="repo", cache_config=d_cache_config
+ )
out_dir = tmpdir
- out_file = tarfile.open(str(archive_lnk), 'r|{}'.format(compressor))
+ out_file = tarfile.open(str(archive_lnk), "r|{}".format(compressor))
out_file.extractall(out_dir)
out_file.close()
def dest(inp):
return os.path.join(out_dir, "repo/" + inp)
- assert oct(os.stat(dest('not_executable')).st_mode) == '0o100644'
+ assert oct(os.stat(dest("not_executable")).st_mode) == "0o100644"
def test_archive_zip(self, tmp_path, d_cache_config):
- archive_node = tmp_path / 'archive-node'
- archive_node.touch()
-
- archive_lnk = self.tip.archive_repo(str(archive_node), kind='zip',
- archive_dir_name='repo', cache_config=d_cache_config)
- zip_file = zipfile.ZipFile(str(archive_lnk))
-
- for x in range(5):
- node_path = '%d/file_%d.txt' % (x, x)
- data = zip_file.read(f'repo/{node_path}')
-
- decompressed = io.BytesIO()
- decompressed.write(data)
- assert decompressed.getvalue() == \
- self.tip.get_node(node_path).content
- decompressed.close()
-
- def test_archive_zip_with_metadata(self, tmp_path, d_cache_config):
- archive_node = tmp_path / 'archive-node'
+ archive_node = tmp_path / "archive-node"
archive_node.touch()
archive_lnk = self.tip.archive_repo(
- str(archive_node), kind='zip',
- archive_dir_name='repo', write_metadata=True, cache_config=d_cache_config)
-
+ str(archive_node), kind="zip", archive_dir_name="repo", cache_config=d_cache_config
+ )
zip_file = zipfile.ZipFile(str(archive_lnk))
- metafile = zip_file.read('repo/.archival.txt')
-
- raw_id = ascii_bytes(self.tip.raw_id)
- assert b'commit_id:%b' % raw_id in metafile
for x in range(5):
- node_path = '%d/file_%d.txt' % (x, x)
- data = zip_file.read(f'repo/{node_path}')
+ node_path = "%d/file_%d.txt" % (x, x)
+ data = zip_file.read(f"repo/{node_path}")
+
decompressed = io.BytesIO()
decompressed.write(data)
- assert decompressed.getvalue() == \
- self.tip.get_node(node_path).content
+ assert decompressed.getvalue() == self.tip.get_node(node_path).content
+ decompressed.close()
+
+ def test_archive_zip_with_metadata(self, tmp_path, d_cache_config):
+ archive_node = tmp_path / "archive-node"
+ archive_node.touch()
+
+ archive_lnk = self.tip.archive_repo(
+ str(archive_node), kind="zip", archive_dir_name="repo", write_metadata=True, cache_config=d_cache_config
+ )
+
+ zip_file = zipfile.ZipFile(str(archive_lnk))
+ metafile = zip_file.read("repo/.archival.txt")
+
+ raw_id = ascii_bytes(self.tip.raw_id)
+ assert b"commit_id:%b" % raw_id in metafile
+
+ for x in range(5):
+ node_path = "%d/file_%d.txt" % (x, x)
+ data = zip_file.read(f"repo/{node_path}")
+ decompressed = io.BytesIO()
+ decompressed.write(data)
+ assert decompressed.getvalue() == self.tip.get_node(node_path).content
decompressed.close()
def test_archive_wrong_kind(self, tmp_path, d_cache_config):
- archive_node = tmp_path / 'archive-node'
+ archive_node = tmp_path / "archive-node"
archive_node.touch()
with pytest.raises(ImproperArchiveTypeError):
- self.tip.archive_repo(str(archive_node), kind='wrong kind', cache_config=d_cache_config)
+ self.tip.archive_repo(str(archive_node), kind="wrong kind", cache_config=d_cache_config)
@pytest.fixture()
@@ -167,8 +165,8 @@ def base_commit():
"""
commit = base.BaseCommit()
commit.repository = mock.Mock()
- commit.repository.name = 'fake_repo'
- commit.short_id = 'fake_id'
+ commit.repository.name = "fake_repo"
+ commit.short_id = "fake_id"
return commit
@@ -180,19 +178,17 @@ def test_validate_archive_prefix_enforces_non_ascii_as_prefix(base_commit):
def test_validate_archive_prefix_empty_prefix(base_commit):
# TODO: johbo: Should raise a ValueError here.
with pytest.raises(VCSError):
- base_commit._validate_archive_prefix('')
+ base_commit._validate_archive_prefix("")
def test_validate_archive_prefix_with_leading_slash(base_commit):
# TODO: johbo: Should raise a ValueError here.
with pytest.raises(VCSError):
- base_commit._validate_archive_prefix('/any')
+ base_commit._validate_archive_prefix("/any")
def test_validate_archive_prefix_falls_back_to_repository_name(base_commit):
prefix = base_commit._validate_archive_prefix(None)
- expected_prefix = base_commit._ARCHIVE_PREFIX_TEMPLATE.format(
- repo_name='fake_repo',
- short_id='fake_id')
+ expected_prefix = base_commit._ARCHIVE_PREFIX_TEMPLATE.format(repo_name="fake_repo", short_id="fake_id")
assert isinstance(prefix, str)
assert prefix == expected_prefix
diff --git a/rhodecode/tests/vcs/test_branches.py b/rhodecode/tests/vcs/test_branches.py
index 2159c6f9..2cea7691 100644
--- a/rhodecode/tests/vcs/test_branches.py
+++ b/rhodecode/tests/vcs/test_branches.py
@@ -64,18 +64,14 @@ class TestBranches(BackendTestMixin):
def test_new_head(self):
tip = self.repo.get_commit()
- self.imc.add(
- FileNode(b"docs/index.txt", content=b"Documentation\n")
- )
+ self.imc.add(FileNode(b"docs/index.txt", content=b"Documentation\n"))
foobar_tip = self.imc.commit(
message="New branch: foobar",
author="joe ",
branch="foobar",
parents=[tip],
)
- self.imc.change(
- FileNode(b"docs/index.txt", content=b"Documentation\nand more...\n")
- )
+ self.imc.change(FileNode(b"docs/index.txt", content=b"Documentation\nand more...\n"))
assert foobar_tip.branch == "foobar"
newtip = self.imc.commit(
message="At foobar_tip branch",
@@ -96,21 +92,15 @@ class TestBranches(BackendTestMixin):
@pytest.mark.backends("git", "hg")
def test_branch_with_slash_in_name(self):
self.imc.add(FileNode(b"extrafile", content=b"Some data\n"))
- self.imc.commit(
- "Branch with a slash!", author="joe ", branch="issue/123"
- )
+ self.imc.commit("Branch with a slash!", author="joe ", branch="issue/123")
assert "issue/123" in self.repo.branches
@pytest.mark.backends("git", "hg")
def test_branch_with_slash_in_name_and_similar_without(self):
self.imc.add(FileNode(b"extrafile", content=b"Some data\n"))
- self.imc.commit(
- "Branch with a slash!", author="joe ", branch="issue/123"
- )
+ self.imc.commit("Branch with a slash!", author="joe ", branch="issue/123")
self.imc.add(FileNode(b"extrafile II", content=b"Some data\n"))
- self.imc.commit(
- "Branch without a slash...", author="joe ", branch="123"
- )
+ self.imc.commit("Branch without a slash...", author="joe ", branch="123")
assert "issue/123" in self.repo.branches
assert "123" in self.repo.branches
diff --git a/rhodecode/tests/vcs/test_client_http.py b/rhodecode/tests/vcs/test_client_http.py
index eb7fe2bc..2618dd24 100644
--- a/rhodecode/tests/vcs/test_client_http.py
+++ b/rhodecode/tests/vcs/test_client_http.py
@@ -1,4 +1,3 @@
-
# Copyright (C) 2010-2023 RhodeCode GmbH
#
# This program is free software: you can redistribute it and/or modify
@@ -28,9 +27,7 @@ from rhodecode.lib.vcs import client_http, exceptions
def is_new_connection(logger, level, message):
- return (
- logger == 'requests.packages.urllib3.connectionpool' and
- message.startswith('Starting new HTTP'))
+ return logger == "requests.packages.urllib3.connectionpool" and message.startswith("Starting new HTTP")
@pytest.fixture()
@@ -54,7 +51,7 @@ def stub_fail_session():
"""
session = mock.Mock()
post = session.post()
- post.content = msgpack.packb({'error': '500'})
+ post.content = msgpack.packb({"error": "500"})
post.status_code = 500
session.reset_mock()
@@ -89,44 +86,37 @@ def test_uses_persistent_http_connections(caplog, vcsbackend_hg):
for x in range(5):
remote_call(normal=True, closed=False)
- new_connections = [
- r for r in caplog.record_tuples if is_new_connection(*r)]
+ new_connections = [r for r in caplog.record_tuples if is_new_connection(*r)]
assert len(new_connections) <= 1
def test_repo_maker_uses_session_for_classmethods(stub_session_factory):
- repo_maker = client_http.RemoteVCSMaker(
- 'server_and_port', 'endpoint', 'test_dummy_scm', stub_session_factory)
+ repo_maker = client_http.RemoteVCSMaker("server_and_port", "endpoint", "test_dummy_scm", stub_session_factory)
repo_maker.example_call()
- stub_session_factory().post.assert_called_with(
- 'http://server_and_port/endpoint', data=mock.ANY)
+ stub_session_factory().post.assert_called_with("http://server_and_port/endpoint", data=mock.ANY)
-def test_repo_maker_uses_session_for_instance_methods(
- stub_session_factory, config):
- repo_maker = client_http.RemoteVCSMaker(
- 'server_and_port', 'endpoint', 'test_dummy_scm', stub_session_factory)
- repo = repo_maker('stub_path', 'stub_repo_id', config)
+def test_repo_maker_uses_session_for_instance_methods(stub_session_factory, config):
+ repo_maker = client_http.RemoteVCSMaker("server_and_port", "endpoint", "test_dummy_scm", stub_session_factory)
+ repo = repo_maker("stub_path", "stub_repo_id", config)
repo.example_call()
- stub_session_factory().post.assert_called_with(
- 'http://server_and_port/endpoint', data=mock.ANY)
+ stub_session_factory().post.assert_called_with("http://server_and_port/endpoint", data=mock.ANY)
-@mock.patch('rhodecode.lib.vcs.client_http.ThreadlocalSessionFactory')
-@mock.patch('rhodecode.lib.vcs.connection')
-def test_connect_passes_in_the_same_session(
- connection, session_factory_class, stub_session):
+@mock.patch("rhodecode.lib.vcs.client_http.ThreadlocalSessionFactory")
+@mock.patch("rhodecode.lib.vcs.connection")
+def test_connect_passes_in_the_same_session(connection, session_factory_class, stub_session):
session_factory = session_factory_class.return_value
session_factory.return_value = stub_session
- vcs.connect_http('server_and_port')
+ vcs.connect_http("server_and_port")
-def test_repo_maker_uses_session_that_throws_error(
- stub_session_failing_factory, config):
+def test_repo_maker_uses_session_that_throws_error(stub_session_failing_factory, config):
repo_maker = client_http.RemoteVCSMaker(
- 'server_and_port', 'endpoint', 'test_dummy_scm', stub_session_failing_factory)
- repo = repo_maker('stub_path', 'stub_repo_id', config)
+ "server_and_port", "endpoint", "test_dummy_scm", stub_session_failing_factory
+ )
+ repo = repo_maker("stub_path", "stub_repo_id", config)
with pytest.raises(exceptions.HttpVCSCommunicationError):
repo.example_call()
diff --git a/rhodecode/tests/vcs/test_commits.py b/rhodecode/tests/vcs/test_commits.py
index 81fedd0d..df57ca1f 100644
--- a/rhodecode/tests/vcs/test_commits.py
+++ b/rhodecode/tests/vcs/test_commits.py
@@ -1,4 +1,3 @@
-
# Copyright (C) 2010-2023 RhodeCode GmbH
#
# This program is free software: you can redistribute it and/or modify
@@ -23,27 +22,31 @@ import time
import pytest
from rhodecode.lib.str_utils import safe_bytes
-from rhodecode.lib.vcs.backends.base import (
- CollectionGenerator, FILEMODE_DEFAULT, EmptyCommit)
+from rhodecode.lib.vcs.backends.base import CollectionGenerator, FILEMODE_DEFAULT, EmptyCommit
from rhodecode.lib.vcs.exceptions import (
- BranchDoesNotExistError, CommitDoesNotExistError,
- RepositoryError, EmptyRepositoryError)
+ BranchDoesNotExistError,
+ CommitDoesNotExistError,
+ RepositoryError,
+ EmptyRepositoryError,
+)
from rhodecode.lib.vcs.nodes import (
- FileNode, AddedFileNodesGenerator,
- ChangedFileNodesGenerator, RemovedFileNodesGenerator)
+ FileNode,
+ AddedFileNodesGenerator,
+ ChangedFileNodesGenerator,
+ RemovedFileNodesGenerator,
+)
from rhodecode.tests import get_new_dir
from rhodecode.tests.vcs.conftest import BackendTestMixin
class TestBaseChangeset(object):
-
def test_is_deprecated(self):
from rhodecode.lib.vcs.backends.base import BaseChangeset
+
pytest.deprecated_call(BaseChangeset)
class TestEmptyCommit(object):
-
def test_branch_without_alias_returns_none(self):
commit = EmptyCommit()
assert commit.branch is None
@@ -58,29 +61,28 @@ class TestCommitsInNonEmptyRepo(BackendTestMixin):
start_date = datetime.datetime(2010, 1, 1, 20)
for x in range(5):
yield {
- 'message': 'Commit %d' % x,
- 'author': 'Joe Doe ',
- 'date': start_date + datetime.timedelta(hours=12 * x),
- 'added': [
- FileNode(b'file_%d.txt' % x,
- content=b'Foobar %d' % x),
+ "message": "Commit %d" % x,
+ "author": "Joe Doe ",
+ "date": start_date + datetime.timedelta(hours=12 * x),
+ "added": [
+ FileNode(b"file_%d.txt" % x, content=b"Foobar %d" % x),
],
}
def test_walk_returns_empty_list_in_case_of_file(self):
- result = list(self.tip.walk('file_0.txt'))
+ result = list(self.tip.walk("file_0.txt"))
assert result == []
@pytest.mark.backends("git", "hg")
def test_new_branch(self):
- self.imc.add(FileNode(b'docs/index.txt', content=b'Documentation\n'))
+ self.imc.add(FileNode(b"docs/index.txt", content=b"Documentation\n"))
foobar_tip = self.imc.commit(
- message='New branch: foobar',
- author='joe ',
- branch='foobar',
+ message="New branch: foobar",
+ author="joe ",
+ branch="foobar",
)
- assert 'foobar' in self.repo.branches
- assert foobar_tip.branch == 'foobar'
+ assert "foobar" in self.repo.branches
+ assert foobar_tip.branch == "foobar"
# 'foobar' should be the only branch that contains the new commit
branch = list(self.repo.branches.values())
assert branch[0] != branch[1]
@@ -89,18 +91,14 @@ class TestCommitsInNonEmptyRepo(BackendTestMixin):
def test_new_head_in_default_branch(self):
tip = self.repo.get_commit()
- self.imc.add(
- FileNode(b"docs/index.txt", content=b"Documentation\n")
- )
+ self.imc.add(FileNode(b"docs/index.txt", content=b"Documentation\n"))
foobar_tip = self.imc.commit(
message="New branch: foobar",
author="joe ",
branch="foobar",
parents=[tip],
)
- self.imc.change(
- FileNode(b"docs/index.txt", content=b"Documentation\nand more...\n")
- )
+ self.imc.change(FileNode(b"docs/index.txt", content=b"Documentation\nand more...\n"))
assert foobar_tip.branch == "foobar"
newtip = self.imc.commit(
message="At foobar_tip branch",
@@ -132,51 +130,55 @@ class TestCommitsInNonEmptyRepo(BackendTestMixin):
:return:
"""
DEFAULT_BRANCH = self.repo.DEFAULT_BRANCH_NAME
- TEST_BRANCH = 'docs'
+ TEST_BRANCH = "docs"
org_tip = self.repo.get_commit()
- self.imc.add(FileNode(b'readme.txt', content=b'Document\n'))
+ self.imc.add(FileNode(b"readme.txt", content=b"Document\n"))
initial = self.imc.commit(
- message='Initial commit',
- author='joe ',
+ message="Initial commit",
+ author="joe ",
parents=[org_tip],
- branch=DEFAULT_BRANCH,)
+ branch=DEFAULT_BRANCH,
+ )
- self.imc.add(FileNode(b'newdoc.txt', content=b'foobar\n'))
+ self.imc.add(FileNode(b"newdoc.txt", content=b"foobar\n"))
docs_branch_commit1 = self.imc.commit(
- message='New branch: docs',
- author='joe ',
+ message="New branch: docs",
+ author="joe ",
parents=[initial],
- branch=TEST_BRANCH,)
+ branch=TEST_BRANCH,
+ )
- self.imc.add(FileNode(b'newdoc2.txt', content=b'foobar2\n'))
+ self.imc.add(FileNode(b"newdoc2.txt", content=b"foobar2\n"))
docs_branch_commit2 = self.imc.commit(
- message='New branch: docs2',
- author='joe ',
+ message="New branch: docs2",
+ author="joe ",
parents=[docs_branch_commit1],
- branch=TEST_BRANCH,)
+ branch=TEST_BRANCH,
+ )
- self.imc.add(FileNode(b'newfile', content=b'hello world\n'))
+ self.imc.add(FileNode(b"newfile", content=b"hello world\n"))
self.imc.commit(
- message='Back in default branch',
- author='joe ',
+ message="Back in default branch",
+ author="joe ",
parents=[initial],
- branch=DEFAULT_BRANCH,)
+ branch=DEFAULT_BRANCH,
+ )
default_branch_commits = self.repo.get_commits(branch_name=DEFAULT_BRANCH)
assert docs_branch_commit1 not in list(default_branch_commits)
assert docs_branch_commit2 not in list(default_branch_commits)
docs_branch_commits = self.repo.get_commits(
- start_id=self.repo.commit_ids[0], end_id=self.repo.commit_ids[-1],
- branch_name=TEST_BRANCH)
+ start_id=self.repo.commit_ids[0], end_id=self.repo.commit_ids[-1], branch_name=TEST_BRANCH
+ )
assert docs_branch_commit1 in list(docs_branch_commits)
assert docs_branch_commit2 in list(docs_branch_commits)
@pytest.mark.backends("svn")
def test_get_commits_respects_branch_name_svn(self, vcsbackend_svn):
- repo = vcsbackend_svn['svn-simple-layout']
- commits = repo.get_commits(branch_name='trunk')
+ repo = vcsbackend_svn["svn-simple-layout"]
+ commits = repo.get_commits(branch_name="trunk")
commit_indexes = [c.idx for c in commits]
assert commit_indexes == [1, 2, 3, 7, 12, 15]
@@ -214,13 +216,10 @@ class TestCommits(BackendTestMixin):
start_date = datetime.datetime(2010, 1, 1, 20)
for x in range(5):
yield {
- 'message': 'Commit %d' % x,
- 'author': 'Joe Doe ',
- 'date': start_date + datetime.timedelta(hours=12 * x),
- 'added': [
- FileNode(b'file_%d.txt' % x,
- content=b'Foobar %d' % x)
- ],
+ "message": "Commit %d" % x,
+ "author": "Joe Doe ",
+ "date": start_date + datetime.timedelta(hours=12 * x),
+ "added": [FileNode(b"file_%d.txt" % x, content=b"Foobar %d" % x)],
}
def test_simple(self):
@@ -231,11 +230,11 @@ class TestCommits(BackendTestMixin):
tip = self.repo.get_commit()
# json.dumps(tip) uses .__json__() method
data = tip.__json__()
- assert 'branch' in data
- assert data['revision']
+ assert "branch" in data
+ assert data["revision"]
def test_retrieve_tip(self):
- tip = self.repo.get_commit('tip')
+ tip = self.repo.get_commit("tip")
assert tip == self.repo.get_commit()
def test_invalid(self):
@@ -259,34 +258,34 @@ class TestCommits(BackendTestMixin):
def test_size(self):
tip = self.repo.get_commit()
- size = 5 * len('Foobar N') # Size of 5 files
+ size = 5 * len("Foobar N") # Size of 5 files
assert tip.size == size
def test_size_at_commit(self):
tip = self.repo.get_commit()
- size = 5 * len('Foobar N') # Size of 5 files
+ size = 5 * len("Foobar N") # Size of 5 files
assert self.repo.size_at_commit(tip.raw_id) == size
def test_size_at_first_commit(self):
commit = self.repo[0]
- size = len('Foobar N') # Size of 1 file
+ size = len("Foobar N") # Size of 1 file
assert self.repo.size_at_commit(commit.raw_id) == size
def test_author(self):
tip = self.repo.get_commit()
- assert_text_equal(tip.author, 'Joe Doe ')
+ assert_text_equal(tip.author, "Joe Doe ")
def test_author_name(self):
tip = self.repo.get_commit()
- assert_text_equal(tip.author_name, 'Joe Doe')
+ assert_text_equal(tip.author_name, "Joe Doe")
def test_author_email(self):
tip = self.repo.get_commit()
- assert_text_equal(tip.author_email, 'joe.doe@example.com')
+ assert_text_equal(tip.author_email, "joe.doe@example.com")
def test_message(self):
tip = self.repo.get_commit()
- assert_text_equal(tip.message, 'Commit 4')
+ assert_text_equal(tip.message, "Commit 4")
def test_diff(self):
tip = self.repo.get_commit()
@@ -296,7 +295,7 @@ class TestCommits(BackendTestMixin):
def test_prev(self):
tip = self.repo.get_commit()
prev_commit = tip.prev()
- assert prev_commit.message == 'Commit 3'
+ assert prev_commit.message == "Commit 3"
def test_prev_raises_on_first_commit(self):
commit = self.repo.get_commit(commit_idx=0)
@@ -311,7 +310,7 @@ class TestCommits(BackendTestMixin):
def test_next(self):
commit = self.repo.get_commit(commit_idx=2)
next_commit = commit.next()
- assert next_commit.message == 'Commit 3'
+ assert next_commit.message == "Commit 3"
def test_next_raises_on_tip(self):
commit = self.repo.get_commit()
@@ -320,36 +319,36 @@ class TestCommits(BackendTestMixin):
def test_get_path_commit(self):
commit = self.repo.get_commit()
- commit.get_path_commit('file_4.txt')
- assert commit.message == 'Commit 4'
+ commit.get_path_commit("file_4.txt")
+ assert commit.message == "Commit 4"
def test_get_filenodes_generator(self):
tip = self.repo.get_commit()
filepaths = [node.path for node in tip.get_filenodes_generator()]
- assert filepaths == ['file_%d.txt' % x for x in range(5)]
+ assert filepaths == ["file_%d.txt" % x for x in range(5)]
def test_get_file_annotate(self):
file_added_commit = self.repo.get_commit(commit_idx=3)
- annotations = list(file_added_commit.get_file_annotate('file_3.txt'))
+ annotations = list(file_added_commit.get_file_annotate("file_3.txt"))
line_no, commit_id, commit_loader, line = annotations[0]
assert line_no == 1
assert commit_id == file_added_commit.raw_id
assert commit_loader() == file_added_commit
- assert b'Foobar 3' in line
+ assert b"Foobar 3" in line
def test_get_file_annotate_does_not_exist(self):
file_added_commit = self.repo.get_commit(commit_idx=2)
# TODO: Should use a specific exception class here?
with pytest.raises(Exception):
- list(file_added_commit.get_file_annotate('file_3.txt'))
+ list(file_added_commit.get_file_annotate("file_3.txt"))
def test_get_file_annotate_tip(self):
tip = self.repo.get_commit()
commit = self.repo.get_commit(commit_idx=3)
- expected_values = list(commit.get_file_annotate('file_3.txt'))
- annotations = list(tip.get_file_annotate('file_3.txt'))
+ expected_values = list(commit.get_file_annotate("file_3.txt"))
+ annotations = list(tip.get_file_annotate("file_3.txt"))
# Note: Skip index 2 because the loader function is not the same
for idx in (0, 1, 3):
@@ -398,7 +397,7 @@ class TestCommits(BackendTestMixin):
repo = self.Backend(repo_path, create=True)
with pytest.raises(EmptyRepositoryError):
- list(repo.get_commits(start_id='foobar'))
+ list(repo.get_commits(start_id="foobar"))
def test_get_commits_respects_hidden(self):
commits = self.repo.get_commits(show_hidden=True)
@@ -424,8 +423,7 @@ class TestCommits(BackendTestMixin):
def test_get_commits_respects_start_date_with_branch(self):
start_date = datetime.datetime(2010, 1, 2)
- commits = self.repo.get_commits(
- start_date=start_date, branch_name=self.repo.DEFAULT_BRANCH_NAME)
+ commits = self.repo.get_commits(start_date=start_date, branch_name=self.repo.DEFAULT_BRANCH_NAME)
assert isinstance(commits, CollectionGenerator)
# Should be 4 commits after 2010-01-02 00:00:00
assert len(commits) == 4
@@ -435,8 +433,7 @@ class TestCommits(BackendTestMixin):
def test_get_commits_respects_start_date_and_end_date(self):
start_date = datetime.datetime(2010, 1, 2)
end_date = datetime.datetime(2010, 1, 3)
- commits = self.repo.get_commits(start_date=start_date,
- end_date=end_date)
+ commits = self.repo.get_commits(start_date=start_date, end_date=end_date)
assert isinstance(commits, CollectionGenerator)
assert len(commits) == 2
for c in commits:
@@ -459,23 +456,22 @@ class TestCommits(BackendTestMixin):
assert list(commit_ids) == list(reversed(self.repo.commit_ids))
def test_get_commits_slice_generator(self):
- commits = self.repo.get_commits(
- branch_name=self.repo.DEFAULT_BRANCH_NAME)
+ commits = self.repo.get_commits(branch_name=self.repo.DEFAULT_BRANCH_NAME)
assert isinstance(commits, CollectionGenerator)
commit_slice = list(commits[1:3])
assert len(commit_slice) == 2
def test_get_commits_raise_commitdoesnotexist_for_wrong_start(self):
with pytest.raises(CommitDoesNotExistError):
- list(self.repo.get_commits(start_id='foobar'))
+ list(self.repo.get_commits(start_id="foobar"))
def test_get_commits_raise_commitdoesnotexist_for_wrong_end(self):
with pytest.raises(CommitDoesNotExistError):
- list(self.repo.get_commits(end_id='foobar'))
+ list(self.repo.get_commits(end_id="foobar"))
def test_get_commits_raise_branchdoesnotexist_for_wrong_branch_name(self):
with pytest.raises(BranchDoesNotExistError):
- list(self.repo.get_commits(branch_name='foobar'))
+ list(self.repo.get_commits(branch_name="foobar"))
def test_get_commits_raise_repositoryerror_for_wrong_start_end(self):
start_id = self.repo.commit_ids[-1]
@@ -498,13 +494,16 @@ class TestCommits(BackendTestMixin):
assert commit1 is not None
assert commit2 is not None
assert 1 != commit1
- assert 'string' != commit1
+ assert "string" != commit1
-@pytest.mark.parametrize("filename, expected", [
- ("README.rst", False),
- ("README", True),
-])
+@pytest.mark.parametrize(
+ "filename, expected",
+ [
+ ("README.rst", False),
+ ("README", True),
+ ],
+)
def test_commit_is_link(vcsbackend, filename, expected):
commit = vcsbackend.repo.get_commit()
link_status = commit.is_link(filename)
@@ -519,75 +518,74 @@ class TestCommitsChanges(BackendTestMixin):
def _get_commits(cls):
return [
{
- 'message': 'Initial',
- 'author': 'Joe Doe ',
- 'date': datetime.datetime(2010, 1, 1, 20),
- 'added': [
- FileNode(b'foo/bar', content=b'foo'),
- FileNode(safe_bytes('foo/bał'), content=b'foo'),
- FileNode(b'foobar', content=b'foo'),
- FileNode(b'qwe', content=b'foo'),
+ "message": "Initial",
+ "author": "Joe Doe ",
+ "date": datetime.datetime(2010, 1, 1, 20),
+ "added": [
+ FileNode(b"foo/bar", content=b"foo"),
+ FileNode(safe_bytes("foo/bał"), content=b"foo"),
+ FileNode(b"foobar", content=b"foo"),
+ FileNode(b"qwe", content=b"foo"),
],
},
{
- 'message': 'Massive changes',
- 'author': 'Joe Doe ',
- 'date': datetime.datetime(2010, 1, 1, 22),
- 'added': [FileNode(b'fallout', content=b'War never changes')],
- 'changed': [
- FileNode(b'foo/bar', content=b'baz'),
- FileNode(b'foobar', content=b'baz'),
+ "message": "Massive changes",
+ "author": "Joe Doe ",
+ "date": datetime.datetime(2010, 1, 1, 22),
+ "added": [FileNode(b"fallout", content=b"War never changes")],
+ "changed": [
+ FileNode(b"foo/bar", content=b"baz"),
+ FileNode(b"foobar", content=b"baz"),
],
- 'removed': [FileNode(b'qwe')],
+ "removed": [FileNode(b"qwe")],
},
]
def test_initial_commit(self, local_dt_to_utc):
commit = self.repo.get_commit(commit_idx=0)
assert set(commit.added) == {
- commit.get_node('foo/bar'),
- commit.get_node('foo/bał'),
- commit.get_node('foobar'),
- commit.get_node('qwe')
+ commit.get_node("foo/bar"),
+ commit.get_node("foo/bał"),
+ commit.get_node("foobar"),
+ commit.get_node("qwe"),
}
assert set(commit.changed) == set()
assert set(commit.removed) == set()
- assert set(commit.affected_files) == {'foo/bar', 'foo/bał', 'foobar', 'qwe'}
- assert commit.date == local_dt_to_utc(
- datetime.datetime(2010, 1, 1, 20, 0))
+ assert set(commit.affected_files) == {"foo/bar", "foo/bał", "foobar", "qwe"}
+ assert commit.date == local_dt_to_utc(datetime.datetime(2010, 1, 1, 20, 0))
def test_head_added(self):
commit = self.repo.get_commit()
assert isinstance(commit.added, AddedFileNodesGenerator)
- assert set(commit.added) == {commit.get_node('fallout')}
+ assert set(commit.added) == {commit.get_node("fallout")}
assert isinstance(commit.changed, ChangedFileNodesGenerator)
- assert set(commit.changed) == {commit.get_node('foo/bar'), commit.get_node('foobar')}
+ assert set(commit.changed) == {commit.get_node("foo/bar"), commit.get_node("foobar")}
assert isinstance(commit.removed, RemovedFileNodesGenerator)
assert len(commit.removed) == 1
- assert list(commit.removed)[0].path == 'qwe'
+ assert list(commit.removed)[0].path == "qwe"
def test_get_filemode(self):
commit = self.repo.get_commit()
- assert FILEMODE_DEFAULT == commit.get_file_mode('foo/bar')
+ assert FILEMODE_DEFAULT == commit.get_file_mode("foo/bar")
def test_get_filemode_non_ascii(self):
commit = self.repo.get_commit()
- assert FILEMODE_DEFAULT == commit.get_file_mode('foo/bał')
- assert FILEMODE_DEFAULT == commit.get_file_mode('foo/bał')
+ assert FILEMODE_DEFAULT == commit.get_file_mode("foo/bał")
+ assert FILEMODE_DEFAULT == commit.get_file_mode("foo/bał")
def test_get_path_history(self):
commit = self.repo.get_commit()
- history = commit.get_path_history('foo/bar')
+ history = commit.get_path_history("foo/bar")
assert len(history) == 2
def test_get_path_history_with_limit(self):
commit = self.repo.get_commit()
- history = commit.get_path_history('foo/bar', limit=1)
+ history = commit.get_path_history("foo/bar", limit=1)
assert len(history) == 1
def test_get_path_history_first_commit(self):
commit = self.repo[0]
- history = commit.get_path_history('foo/bar')
+ history = commit.get_path_history("foo/bar")
assert len(history) == 1
diff --git a/rhodecode/tests/vcs/test_config.py b/rhodecode/tests/vcs/test_config.py
index 9aac9d64..4ecea4a2 100644
--- a/rhodecode/tests/vcs/test_config.py
+++ b/rhodecode/tests/vcs/test_config.py
@@ -1,4 +1,3 @@
-
# Copyright (C) 2010-2023 RhodeCode GmbH
#
# This program is free software: you can redistribute it and/or modify
@@ -21,14 +20,17 @@ import pytest
def test_get_existing_value(config):
- value = config.get('section-a', 'a-1')
- assert value == 'value-a-1'
+ value = config.get("section-a", "a-1")
+ assert value == "value-a-1"
-@pytest.mark.parametrize('section, option', [
- ('section-a', 'does-not-exist'),
- ('does-not-exist', 'does-not-exist'),
-])
+@pytest.mark.parametrize(
+ "section, option",
+ [
+ ("section-a", "does-not-exist"),
+ ("does-not-exist", "does-not-exist"),
+ ],
+)
def test_get_unset_value_returns_none(config, section, option):
value = config.get(section, option)
assert value is None
@@ -41,11 +43,11 @@ def test_allows_to_create_a_copy(config):
def test_changes_in_the_copy_dont_affect_the_original(config):
clone = config.copy()
- clone.set('section-a', 'a-2', 'value-a-2')
- assert set(config.serialize()) == {('section-a', 'a-1', 'value-a-1')}
+ clone.set("section-a", "a-2", "value-a-2")
+ assert set(config.serialize()) == {("section-a", "a-1", "value-a-1")}
def test_changes_in_the_original_dont_affect_the_copy(config):
clone = config.copy()
- config.set('section-a', 'a-2', 'value-a-2')
- assert set(clone.serialize()) == {('section-a', 'a-1', 'value-a-1')}
+ config.set("section-a", "a-2", "value-a-2")
+ assert set(clone.serialize()) == {("section-a", "a-1", "value-a-1")}
diff --git a/rhodecode/tests/vcs/test_diff.py b/rhodecode/tests/vcs/test_diff.py
index 190b22b0..38b4a3f4 100644
--- a/rhodecode/tests/vcs/test_diff.py
+++ b/rhodecode/tests/vcs/test_diff.py
@@ -1,4 +1,3 @@
-
# Copyright (C) 2010-2023 RhodeCode GmbH
#
# This program is free software: you can redistribute it and/or modify
@@ -25,7 +24,6 @@ from rhodecode.tests.vcs.conftest import BackendTestMixin
class TestGetDiffValidation:
-
def test_raises_on_string_input(self, vcsbackend):
repo = vcsbackend.repo
with pytest.raises(TypeError):
@@ -54,63 +52,58 @@ class TestGetDiffValidation:
def test_supports_path1_parameter(self, vcsbackend):
repo = vcsbackend.repo
commit = repo[1]
- repo.get_diff(
- repo.EMPTY_COMMIT, commit,
- path='vcs/__init__.py', path1='vcs/__init__.py')
+ repo.get_diff(repo.EMPTY_COMMIT, commit, path="vcs/__init__.py", path1="vcs/__init__.py")
@pytest.mark.backends("git", "hg")
def test_raises_value_error_if_paths_not_supported(self, vcsbackend):
repo = vcsbackend.repo
commit = repo[1]
with pytest.raises(ValueError):
- repo.get_diff(
- repo.EMPTY_COMMIT, commit,
- path='trunk/example.py', path1='branches/argparse/example.py')
+ repo.get_diff(repo.EMPTY_COMMIT, commit, path="trunk/example.py", path1="branches/argparse/example.py")
@pytest.mark.usefixtures("vcs_repository_support")
class TestRepositoryGetDiff(BackendTestMixin):
-
recreate_repo_per_test = False
@classmethod
def _get_commits(cls):
commits = [
{
- 'message': 'Initial commit',
- 'author': 'Joe Doe ',
- 'date': datetime.datetime(2010, 1, 1, 20),
- 'added': [
- FileNode(b'foobar', content=b'foobar'),
- FileNode(b'foobar2', content=b'foobar2'),
+ "message": "Initial commit",
+ "author": "Joe Doe ",
+ "date": datetime.datetime(2010, 1, 1, 20),
+ "added": [
+ FileNode(b"foobar", content=b"foobar"),
+ FileNode(b"foobar2", content=b"foobar2"),
],
},
{
- 'message': 'Changed foobar, added foobar3',
- 'author': 'Jane Doe ',
- 'date': datetime.datetime(2010, 1, 1, 21),
- 'added': [
- FileNode(b'foobar3', content=b'foobar3'),
+ "message": "Changed foobar, added foobar3",
+ "author": "Jane Doe ",
+ "date": datetime.datetime(2010, 1, 1, 21),
+ "added": [
+ FileNode(b"foobar3", content=b"foobar3"),
],
- 'changed': [
- FileNode(b'foobar', b'FOOBAR'),
+ "changed": [
+ FileNode(b"foobar", b"FOOBAR"),
],
},
{
- 'message': 'Removed foobar, changed foobar3',
- 'author': 'Jane Doe ',
- 'date': datetime.datetime(2010, 1, 1, 22),
- 'changed': [
- FileNode(b'foobar3', content=b'FOOBAR\nFOOBAR\nFOOBAR\n'),
+ "message": "Removed foobar, changed foobar3",
+ "author": "Jane Doe ",
+ "date": datetime.datetime(2010, 1, 1, 22),
+ "changed": [
+ FileNode(b"foobar3", content=b"FOOBAR\nFOOBAR\nFOOBAR\n"),
],
- 'removed': [FileNode(b'foobar')],
+ "removed": [FileNode(b"foobar")],
},
{
- 'message': 'Whitespace changes',
- 'author': 'Jane Doe ',
- 'date': datetime.datetime(2010, 1, 1, 23),
- 'changed': [
- FileNode(b'foobar3', content=b'FOOBAR \nFOOBAR\nFOOBAR\n'),
+ "message": "Whitespace changes",
+ "author": "Jane Doe ",
+ "date": datetime.datetime(2010, 1, 1, 23),
+ "changed": [
+ FileNode(b"foobar3", content=b"FOOBAR \nFOOBAR\nFOOBAR\n"),
],
},
]
@@ -130,28 +123,24 @@ class TestRepositoryGetDiff(BackendTestMixin):
assert diff.raw.tobytes() == self.third_commit_diffs[self.repo.alias]
def test_ignore_whitespace(self):
- diff = self.repo.get_diff(
- self.repo[2], self.repo[3], ignore_whitespace=True)
- assert b'@@' not in diff.raw.tobytes()
+ diff = self.repo.get_diff(self.repo[2], self.repo[3], ignore_whitespace=True)
+ assert b"@@" not in diff.raw.tobytes()
def test_only_one_file(self):
- diff = self.repo.get_diff(
- self.repo.EMPTY_COMMIT, self.repo[0], path='foobar')
- assert b'foobar2' not in diff.raw.tobytes()
+ diff = self.repo.get_diff(self.repo.EMPTY_COMMIT, self.repo[0], path="foobar")
+ assert b"foobar2" not in diff.raw.tobytes()
def test_context_parameter(self):
first_commit = self.repo.get_commit(commit_idx=0)
- diff = self.repo.get_diff(
- self.repo.EMPTY_COMMIT, first_commit, context=2)
+ diff = self.repo.get_diff(self.repo.EMPTY_COMMIT, first_commit, context=2)
assert diff.raw.tobytes() == self.first_commit_diffs[self.repo.alias]
def test_context_only_one_file(self):
- diff = self.repo.get_diff(
- self.repo.EMPTY_COMMIT, self.repo[0], path='foobar', context=2)
+ diff = self.repo.get_diff(self.repo.EMPTY_COMMIT, self.repo[0], path="foobar", context=2)
assert diff.raw.tobytes() == self.first_commit_one_file[self.repo.alias]
first_commit_diffs = {
- 'git': br"""diff --git a/foobar b/foobar
+ "git": rb"""diff --git a/foobar b/foobar
new file mode 100644
index 0000000..f6ea049
--- /dev/null
@@ -168,7 +157,7 @@ index 0000000..e8c9d6b
+foobar2
\ No newline at end of file
""",
- 'hg': br"""diff --git a/foobar b/foobar
+ "hg": rb"""diff --git a/foobar b/foobar
new file mode 100644
--- /dev/null
+++ b/foobar
@@ -183,7 +172,7 @@ new file mode 100644
+foobar2
\ No newline at end of file
""",
- 'svn': b"""Index: foobar
+ "svn": b"""Index: foobar
===================================================================
diff --git a/foobar b/foobar
new file mode 10644
@@ -205,7 +194,7 @@ new file mode 10644
}
second_commit_diffs = {
- 'git': br"""diff --git a/foobar b/foobar
+ "git": rb"""diff --git a/foobar b/foobar
index f6ea049..389865b 100644
--- a/foobar
+++ b/foobar
@@ -223,7 +212,7 @@ index 0000000..c11c37d
+foobar3
\ No newline at end of file
""",
- 'hg': br"""diff --git a/foobar b/foobar
+ "hg": rb"""diff --git a/foobar b/foobar
--- a/foobar
+++ b/foobar
@@ -1,1 +1,1 @@
@@ -239,7 +228,7 @@ new file mode 100644
+foobar3
\ No newline at end of file
""",
- 'svn': b"""Index: foobar
+ "svn": b"""Index: foobar
===================================================================
diff --git a/foobar b/foobar
--- a/foobar\t(revision 1)
@@ -262,7 +251,7 @@ new file mode 10644
}
third_commit_diffs = {
- 'git': br"""diff --git a/foobar b/foobar
+ "git": rb"""diff --git a/foobar b/foobar
deleted file mode 100644
index 389865b..0000000
--- a/foobar
@@ -281,7 +270,7 @@ index c11c37d..f932447 100644
+FOOBAR
+FOOBAR
""",
- 'hg': br"""diff --git a/foobar b/foobar
+ "hg": rb"""diff --git a/foobar b/foobar
deleted file mode 100644
--- a/foobar
+++ /dev/null
@@ -298,7 +287,7 @@ diff --git a/foobar3 b/foobar3
+FOOBAR
+FOOBAR
""",
- 'svn': b"""Index: foobar
+ "svn": b"""Index: foobar
===================================================================
diff --git a/foobar b/foobar
deleted file mode 10644
@@ -322,7 +311,7 @@ diff --git a/foobar3 b/foobar3
}
first_commit_one_file = {
- 'git': br"""diff --git a/foobar b/foobar
+ "git": rb"""diff --git a/foobar b/foobar
new file mode 100644
index 0000000..f6ea049
--- /dev/null
@@ -331,7 +320,7 @@ index 0000000..f6ea049
+foobar
\ No newline at end of file
""",
- 'hg': br"""diff --git a/foobar b/foobar
+ "hg": rb"""diff --git a/foobar b/foobar
new file mode 100644
--- /dev/null
+++ b/foobar
@@ -339,7 +328,7 @@ new file mode 100644
+foobar
\ No newline at end of file
""",
- 'svn': b"""Index: foobar
+ "svn": b"""Index: foobar
===================================================================
diff --git a/foobar b/foobar
new file mode 10644
@@ -353,13 +342,11 @@ new file mode 10644
class TestSvnGetDiff(object):
-
- @pytest.mark.parametrize('path, path1', [
- ('trunk/example.py', 'tags/v0.2/example.py'),
- ('trunk', 'tags/v0.2')
- ], ids=['file', 'dir'])
+ @pytest.mark.parametrize(
+ "path, path1", [("trunk/example.py", "tags/v0.2/example.py"), ("trunk", "tags/v0.2")], ids=["file", "dir"]
+ )
def test_diff_to_tagged_version(self, vcsbackend_svn, path, path1):
- repo = vcsbackend_svn['svn-simple-layout']
+ repo = vcsbackend_svn["svn-simple-layout"]
commit1 = repo[-2]
commit2 = repo[-1]
diff = repo.get_diff(commit1, commit2, path=path, path1=path1)
@@ -386,7 +373,7 @@ diff --git a/example.py b/example.py
'''
def test_diff_of_moved_directory(self, vcsbackend_svn):
- repo = vcsbackend_svn['svn-move-directory']
+ repo = vcsbackend_svn["svn-move-directory"]
diff = repo.get_diff(repo[0], repo[1])
# TODO: johbo: Think about supporting svn directory nodes
# a little bit better, source is here like a file
@@ -408,7 +395,6 @@ new file mode 10644
@pytest.mark.usefixtures("vcs_repository_support")
class TestGetDiffBinary(BackendTestMixin):
-
recreate_repo_per_test = False
# Note: "Fake" PNG files, has the correct magic as prefix
@@ -419,26 +405,29 @@ class TestGetDiffBinary(BackendTestMixin):
def _get_commits():
commits = [
{
- 'message': 'Add binary file image.png',
- 'author': 'Joe Doe ',
- 'date': datetime.datetime(2010, 1, 1, 20),
- 'added': [
- FileNode(b'image.png', content=TestGetDiffBinary.BINARY),
- ]},
+ "message": "Add binary file image.png",
+ "author": "Joe Doe ",
+ "date": datetime.datetime(2010, 1, 1, 20),
+ "added": [
+ FileNode(b"image.png", content=TestGetDiffBinary.BINARY),
+ ],
+ },
{
- 'message': 'Modify image.png',
- 'author': 'Joe Doe ',
- 'date': datetime.datetime(2010, 1, 1, 21),
- 'changed': [
- FileNode(b'image.png', content=TestGetDiffBinary.BINARY2),
- ]},
+ "message": "Modify image.png",
+ "author": "Joe Doe ",
+ "date": datetime.datetime(2010, 1, 1, 21),
+ "changed": [
+ FileNode(b"image.png", content=TestGetDiffBinary.BINARY2),
+ ],
+ },
{
- 'message': 'Remove image.png',
- 'author': 'Joe Doe ',
- 'date': datetime.datetime(2010, 1, 1, 21),
- 'removed': [
- FileNode(b'image.png'),
- ]},
+ "message": "Remove image.png",
+ "author": "Joe Doe ",
+ "date": datetime.datetime(2010, 1, 1, 21),
+ "removed": [
+ FileNode(b"image.png"),
+ ],
+ },
]
return commits
@@ -446,7 +435,7 @@ class TestGetDiffBinary(BackendTestMixin):
diff = self.repo.get_diff(self.repo.EMPTY_COMMIT, self.repo[0])
expected = {
- 'git': b"""diff --git a/image.png b/image.png
+ "git": b"""diff --git a/image.png b/image.png
new file mode 100644
index 0000000000000000000000000000000000000000..28380fd4a25c58be1b68b523ba2a314f4459ee9c
GIT binary patch
@@ -457,7 +446,7 @@ literal 0
Hc$@',
- 'date': datetime.datetime(2010, 1, 1, 20),
- 'added': nodes,
+ "message": "Initial commit",
+ "author": "Joe Doe ",
+ "date": datetime.datetime(2010, 1, 1, 20),
+ "added": nodes,
},
]
return commits
diff --git a/rhodecode/tests/vcs/test_getitem.py b/rhodecode/tests/vcs/test_getitem.py
index 883646ce..d95c7bd8 100644
--- a/rhodecode/tests/vcs/test_getitem.py
+++ b/rhodecode/tests/vcs/test_getitem.py
@@ -1,4 +1,3 @@
-
# Copyright (C) 2010-2023 RhodeCode GmbH
#
# This program is free software: you can redistribute it and/or modify
@@ -28,28 +27,30 @@ from rhodecode.tests.vcs.conftest import BackendTestMixin
@pytest.mark.usefixtures("vcs_repository_support")
class TestGetitem(BackendTestMixin):
-
@classmethod
def _get_commits(cls):
start_date = datetime.datetime(2010, 1, 1, 20)
for x in range(5):
yield {
- 'message': 'Commit %d' % x,
- 'author': 'Joe Doe ',
- 'date': start_date + datetime.timedelta(hours=12 * x),
- 'added': [
- FileNode(b'file_%d.txt' % x, content='Foobar %d' % x),
+ "message": "Commit %d" % x,
+ "author": "Joe Doe ",
+ "date": start_date + datetime.timedelta(hours=12 * x),
+ "added": [
+ FileNode(b"file_%d.txt" % x, content="Foobar %d" % x),
],
}
def test_last_item_is_tip(self):
assert self.repo[-1] == self.repo.get_commit()
- @pytest.mark.parametrize("offset, message", [
- (-1, 'Commit 4'),
- (-2, 'Commit 3'),
- (-5, 'Commit 0'),
- ])
+ @pytest.mark.parametrize(
+ "offset, message",
+ [
+ (-1, "Commit 4"),
+ (-2, "Commit 3"),
+ (-5, "Commit 0"),
+ ],
+ )
def test_negative_offset_fetches_correct_commit(self, offset, message):
assert self.repo[offset].message == message
diff --git a/rhodecode/tests/vcs/test_getslice.py b/rhodecode/tests/vcs/test_getslice.py
index add11b3f..225aaf83 100644
--- a/rhodecode/tests/vcs/test_getslice.py
+++ b/rhodecode/tests/vcs/test_getslice.py
@@ -1,4 +1,3 @@
-
# Copyright (C) 2010-2023 RhodeCode GmbH
#
# This program is free software: you can redistribute it and/or modify
@@ -25,17 +24,16 @@ from rhodecode.tests.vcs.conftest import BackendTestMixin
@pytest.mark.usefixtures("vcs_repository_support")
class TestGetslice(BackendTestMixin):
-
@classmethod
def _get_commits(cls):
start_date = datetime.datetime(2010, 1, 1, 20)
for x in range(5):
yield {
- 'message': 'Commit %d' % x,
- 'author': 'Joe Doe ',
- 'date': start_date + datetime.timedelta(hours=12 * x),
- 'added': [
- FileNode(b'file_%d.txt' % x, content='Foobar %d' % x),
+ "message": "Commit %d" % x,
+ "author": "Joe Doe ",
+ "date": start_date + datetime.timedelta(hours=12 * x),
+ "added": [
+ FileNode(b"file_%d.txt" % x, content="Foobar %d" % x),
],
}
@@ -43,34 +41,24 @@ class TestGetslice(BackendTestMixin):
assert list(self.repo[-1:])[0] == self.repo.get_commit()
def test__getslice__respects_start_index(self):
- assert list(self.repo[2:]) == \
- [self.repo.get_commit(commit_id)
- for commit_id in self.repo.commit_ids[2:]]
+ assert list(self.repo[2:]) == [self.repo.get_commit(commit_id) for commit_id in self.repo.commit_ids[2:]]
def test__getslice__respects_negative_start_index(self):
- assert list(self.repo[-2:]) == \
- [self.repo.get_commit(commit_id)
- for commit_id in self.repo.commit_ids[-2:]]
+ assert list(self.repo[-2:]) == [self.repo.get_commit(commit_id) for commit_id in self.repo.commit_ids[-2:]]
def test__getslice__respects_end_index(self):
- assert list(self.repo[:2]) == \
- [self.repo.get_commit(commit_id)
- for commit_id in self.repo.commit_ids[:2]]
+ assert list(self.repo[:2]) == [self.repo.get_commit(commit_id) for commit_id in self.repo.commit_ids[:2]]
def test__getslice__respects_negative_end_index(self):
- assert list(self.repo[:-2]) == \
- [self.repo.get_commit(commit_id)
- for commit_id in self.repo.commit_ids[:-2]]
+ assert list(self.repo[:-2]) == [self.repo.get_commit(commit_id) for commit_id in self.repo.commit_ids[:-2]]
def test__getslice__start_grater_than_end(self):
assert list(self.repo[10:0]) == []
def test__getslice__negative_iteration(self):
- assert list(self.repo[::-1]) == \
- [self.repo.get_commit(commit_id)
- for commit_id in self.repo.commit_ids[::-1]]
+ assert list(self.repo[::-1]) == [self.repo.get_commit(commit_id) for commit_id in self.repo.commit_ids[::-1]]
def test__getslice__iterate_even(self):
- assert list(self.repo[0:10:2]) == \
- [self.repo.get_commit(commit_id)
- for commit_id in self.repo.commit_ids[0:10:2]]
+ assert list(self.repo[0:10:2]) == [
+ self.repo.get_commit(commit_id) for commit_id in self.repo.commit_ids[0:10:2]
+ ]
diff --git a/rhodecode/tests/vcs/test_git.py b/rhodecode/tests/vcs/test_git.py
index 3bdd6c41..48e3c7fc 100644
--- a/rhodecode/tests/vcs/test_git.py
+++ b/rhodecode/tests/vcs/test_git.py
@@ -1,4 +1,3 @@
-
# Copyright (C) 2010-2023 RhodeCode GmbH
#
# This program is free software: you can redistribute it and/or modify
@@ -27,12 +26,9 @@ import pytest
from rhodecode.lib.utils import make_db_config
from rhodecode.lib.vcs.backends.base import Reference
-from rhodecode.lib.vcs.backends.git import (
- GitRepository, GitCommit, discover_git_version)
-from rhodecode.lib.vcs.exceptions import (
- RepositoryError, VCSError, NodeDoesNotExistError)
-from rhodecode.lib.vcs.nodes import (
- NodeKind, FileNode, DirNode, NodeState, SubModuleNode)
+from rhodecode.lib.vcs.backends.git import GitRepository, GitCommit, discover_git_version
+from rhodecode.lib.vcs.exceptions import RepositoryError, VCSError, NodeDoesNotExistError
+from rhodecode.lib.vcs.nodes import NodeKind, FileNode, DirNode, NodeState, SubModuleNode
from rhodecode.tests import TEST_GIT_REPO, TEST_GIT_REPO_CLONE, get_new_dir
from rhodecode.tests.vcs.conftest import BackendTestMixin
@@ -40,7 +36,7 @@ from rhodecode.tests.vcs.conftest import BackendTestMixin
pytestmark = pytest.mark.backends("git")
-DIFF_FROM_REMOTE = br"""diff --git a/foobar b/foobar
+DIFF_FROM_REMOTE = rb"""diff --git a/foobar b/foobar
new file mode 100644
index 0000000..f6ea049
--- /dev/null
@@ -64,7 +60,6 @@ def callable_get_diff(*args, **kwargs):
class TestGitRepository(object):
-
@pytest.fixture(autouse=True)
def prepare(self, request, baseapp):
self.repo = GitRepository(TEST_GIT_REPO, bare=True)
@@ -74,9 +69,8 @@ class TestGitRepository(object):
"""
Return a non bare clone of the base repo.
"""
- clone_path = str(tmpdir.join('clone-repo'))
- repo_clone = GitRepository(
- clone_path, create=True, src_url=self.repo.path, bare=False)
+ clone_path = str(tmpdir.join("clone-repo"))
+ repo_clone = GitRepository(clone_path, create=True, src_url=self.repo.path, bare=False)
return repo_clone
@@ -84,20 +78,18 @@ class TestGitRepository(object):
"""
Return a non bare empty repo.
"""
- clone_path = str(tmpdir.join('empty-repo'))
+ clone_path = str(tmpdir.join("empty-repo"))
return GitRepository(clone_path, create=True, bare=bare)
def test_wrong_repo_path(self):
- wrong_repo_path = '/tmp/errorrepo_git'
+ wrong_repo_path = "/tmp/errorrepo_git"
with pytest.raises(RepositoryError):
GitRepository(wrong_repo_path)
def test_repo_clone(self, tmp_path_factory):
repo = GitRepository(TEST_GIT_REPO)
- clone_path = '{}_{}'.format(tmp_path_factory.mktemp('_'), TEST_GIT_REPO_CLONE)
- repo_clone = GitRepository(
- clone_path,
- src_url=TEST_GIT_REPO, create=True, do_workspace_checkout=True)
+ clone_path = f"{tmp_path_factory.mktemp('_')}_{TEST_GIT_REPO_CLONE}"
+ repo_clone = GitRepository(clone_path, src_url=TEST_GIT_REPO, create=True, do_workspace_checkout=True)
assert len(repo.commit_ids) == len(repo_clone.commit_ids)
# Checking hashes of commits should be enough
@@ -107,48 +99,42 @@ class TestGitRepository(object):
def test_repo_clone_without_create(self):
with pytest.raises(RepositoryError):
- GitRepository(
- TEST_GIT_REPO_CLONE + '_wo_create', src_url=TEST_GIT_REPO)
+ GitRepository(TEST_GIT_REPO_CLONE + "_wo_create", src_url=TEST_GIT_REPO)
def test_repo_clone_with_update(self, tmp_path_factory):
repo = GitRepository(TEST_GIT_REPO)
- clone_path = '{}_{}_update'.format(tmp_path_factory.mktemp('_'), TEST_GIT_REPO_CLONE)
+ clone_path = "{}_{}_update".format(tmp_path_factory.mktemp("_"), TEST_GIT_REPO_CLONE)
- repo_clone = GitRepository(
- clone_path,
- create=True, src_url=TEST_GIT_REPO, do_workspace_checkout=True)
+ repo_clone = GitRepository(clone_path, create=True, src_url=TEST_GIT_REPO, do_workspace_checkout=True)
assert len(repo.commit_ids) == len(repo_clone.commit_ids)
# check if current workdir was updated
- fpath = os.path.join(clone_path, 'MANIFEST.in')
+ fpath = os.path.join(clone_path, "MANIFEST.in")
assert os.path.isfile(fpath)
def test_repo_clone_without_update(self, tmp_path_factory):
repo = GitRepository(TEST_GIT_REPO)
- clone_path = '{}_{}_without_update'.format(tmp_path_factory.mktemp('_'), TEST_GIT_REPO_CLONE)
- repo_clone = GitRepository(
- clone_path,
- create=True, src_url=TEST_GIT_REPO, do_workspace_checkout=False)
+ clone_path = "{}_{}_without_update".format(tmp_path_factory.mktemp("_"), TEST_GIT_REPO_CLONE)
+ repo_clone = GitRepository(clone_path, create=True, src_url=TEST_GIT_REPO, do_workspace_checkout=False)
assert len(repo.commit_ids) == len(repo_clone.commit_ids)
# check if current workdir was *NOT* updated
- fpath = os.path.join(clone_path, 'MANIFEST.in')
+ fpath = os.path.join(clone_path, "MANIFEST.in")
# Make sure it's not bare repo
assert not repo_clone.bare
assert not os.path.isfile(fpath)
def test_repo_clone_into_bare_repo(self, tmp_path_factory):
repo = GitRepository(TEST_GIT_REPO)
- clone_path = '{}_{}_bare.git'.format(tmp_path_factory.mktemp('_'), TEST_GIT_REPO_CLONE)
- repo_clone = GitRepository(
- clone_path, create=True, src_url=repo.path, bare=True)
+ clone_path = "{}_{}_bare.git".format(tmp_path_factory.mktemp("_"), TEST_GIT_REPO_CLONE)
+ repo_clone = GitRepository(clone_path, create=True, src_url=repo.path, bare=True)
assert repo_clone.bare
def test_create_repo_is_not_bare_by_default(self):
- repo = GitRepository(get_new_dir('not-bare-by-default'), create=True)
+ repo = GitRepository(get_new_dir("not-bare-by-default"), create=True)
assert not repo.bare
def test_create_bare_repo(self):
- repo = GitRepository(get_new_dir('bare-repo'), create=True, bare=True)
+ repo = GitRepository(get_new_dir("bare-repo"), create=True, bare=True)
assert repo.bare
def test_update_server_info(self):
@@ -167,37 +153,38 @@ class TestGitRepository(object):
def test_commit_ids(self):
# there are 112 commits (by now)
# so we can assume they would be available from now on
- subset = {'c1214f7e79e02fc37156ff215cd71275450cffc3',
- '38b5fe81f109cb111f549bfe9bb6b267e10bc557',
- 'fa6600f6848800641328adbf7811fd2372c02ab2',
- '102607b09cdd60e2793929c4f90478be29f85a17',
- '49d3fd156b6f7db46313fac355dca1a0b94a0017',
- '2d1028c054665b962fa3d307adfc923ddd528038',
- 'd7e0d30fbcae12c90680eb095a4f5f02505ce501',
- 'ff7ca51e58c505fec0dd2491de52c622bb7a806b',
- 'dd80b0f6cf5052f17cc738c2951c4f2070200d7f',
- '8430a588b43b5d6da365400117c89400326e7992',
- 'd955cd312c17b02143c04fa1099a352b04368118',
- 'f67b87e5c629c2ee0ba58f85197e423ff28d735b',
- 'add63e382e4aabc9e1afdc4bdc24506c269b7618',
- 'f298fe1189f1b69779a4423f40b48edf92a703fc',
- 'bd9b619eb41994cac43d67cf4ccc8399c1125808',
- '6e125e7c890379446e98980d8ed60fba87d0f6d1',
- 'd4a54db9f745dfeba6933bf5b1e79e15d0af20bd',
- '0b05e4ed56c802098dfc813cbe779b2f49e92500',
- '191caa5b2c81ed17c0794bf7bb9958f4dcb0b87e',
- '45223f8f114c64bf4d6f853e3c35a369a6305520',
- 'ca1eb7957a54bce53b12d1a51b13452f95bc7c7e',
- 'f5ea29fc42ef67a2a5a7aecff10e1566699acd68',
- '27d48942240f5b91dfda77accd2caac94708cc7d',
- '622f0eb0bafd619d2560c26f80f09e3b0b0d78af',
- 'e686b958768ee96af8029fe19c6050b1a8dd3b2b'}
+ subset = {
+ "c1214f7e79e02fc37156ff215cd71275450cffc3",
+ "38b5fe81f109cb111f549bfe9bb6b267e10bc557",
+ "fa6600f6848800641328adbf7811fd2372c02ab2",
+ "102607b09cdd60e2793929c4f90478be29f85a17",
+ "49d3fd156b6f7db46313fac355dca1a0b94a0017",
+ "2d1028c054665b962fa3d307adfc923ddd528038",
+ "d7e0d30fbcae12c90680eb095a4f5f02505ce501",
+ "ff7ca51e58c505fec0dd2491de52c622bb7a806b",
+ "dd80b0f6cf5052f17cc738c2951c4f2070200d7f",
+ "8430a588b43b5d6da365400117c89400326e7992",
+ "d955cd312c17b02143c04fa1099a352b04368118",
+ "f67b87e5c629c2ee0ba58f85197e423ff28d735b",
+ "add63e382e4aabc9e1afdc4bdc24506c269b7618",
+ "f298fe1189f1b69779a4423f40b48edf92a703fc",
+ "bd9b619eb41994cac43d67cf4ccc8399c1125808",
+ "6e125e7c890379446e98980d8ed60fba87d0f6d1",
+ "d4a54db9f745dfeba6933bf5b1e79e15d0af20bd",
+ "0b05e4ed56c802098dfc813cbe779b2f49e92500",
+ "191caa5b2c81ed17c0794bf7bb9958f4dcb0b87e",
+ "45223f8f114c64bf4d6f853e3c35a369a6305520",
+ "ca1eb7957a54bce53b12d1a51b13452f95bc7c7e",
+ "f5ea29fc42ef67a2a5a7aecff10e1566699acd68",
+ "27d48942240f5b91dfda77accd2caac94708cc7d",
+ "622f0eb0bafd619d2560c26f80f09e3b0b0d78af",
+ "e686b958768ee96af8029fe19c6050b1a8dd3b2b",
+ }
assert subset.issubset(set(self.repo.commit_ids))
def test_slicing(self):
# 4 1 5 10 95
- for sfrom, sto, size in [(0, 4, 4), (1, 2, 1), (10, 15, 5),
- (10, 20, 10), (5, 100, 95)]:
+ for sfrom, sto, size in [(0, 4, 4), (1, 2, 1), (10, 15, 5), (10, 20, 10), (5, 100, 95)]:
commit_ids = list(self.repo[sfrom:sto])
assert len(commit_ids) == size
assert commit_ids[0] == self.repo.get_commit(commit_idx=sfrom)
@@ -214,8 +201,8 @@ class TestGitRepository(object):
def test_tags(self):
# TODO: Need more tests here
- assert 'v0.1.1' in self.repo.tags
- assert 'v0.1.2' in self.repo.tags
+ assert "v0.1.1" in self.repo.tags
+ assert "v0.1.2" in self.repo.tags
for __, commit_id in self.repo.tags.items():
assert isinstance(self.repo.get_commit(commit_id), GitCommit)
@@ -229,37 +216,34 @@ class TestGitRepository(object):
init_commit = self.repo.get_commit(commit_id)
init_author = init_commit.author
- assert init_commit.message == 'initial import\n'
- assert init_author == 'Marcin Kuzminski '
+ assert init_commit.message == "initial import\n"
+ assert init_author == "Marcin Kuzminski "
assert init_author == init_commit.committer
- for path in ('vcs/__init__.py',
- 'vcs/backends/BaseRepository.py',
- 'vcs/backends/__init__.py'):
+ for path in ("vcs/__init__.py", "vcs/backends/BaseRepository.py", "vcs/backends/__init__.py"):
assert isinstance(init_commit.get_node(path), FileNode)
- for path in ('', 'vcs', 'vcs/backends'):
+ for path in ("", "vcs", "vcs/backends"):
assert isinstance(init_commit.get_node(path), DirNode)
with pytest.raises(NodeDoesNotExistError):
- init_commit.get_node(path='foobar')
+ init_commit.get_node(path="foobar")
- node = init_commit.get_node('vcs/')
- assert hasattr(node, 'kind')
+ node = init_commit.get_node("vcs/")
+ assert hasattr(node, "kind")
assert node.kind == NodeKind.DIR
- node = init_commit.get_node('vcs')
- assert hasattr(node, 'kind')
+ node = init_commit.get_node("vcs")
+ assert hasattr(node, "kind")
assert node.kind == NodeKind.DIR
- node = init_commit.get_node('vcs/__init__.py')
- assert hasattr(node, 'kind')
+ node = init_commit.get_node("vcs/__init__.py")
+ assert hasattr(node, "kind")
assert node.kind == NodeKind.FILE
def test_not_existing_commit(self):
with pytest.raises(RepositoryError):
- self.repo.get_commit('f' * 40)
+ self.repo.get_commit("f" * 40)
def test_commit10(self):
-
commit10 = self.repo.get_commit(self.repo.commit_ids[9])
README = """===
VCS
@@ -273,7 +257,7 @@ Introduction
TODO: To be written...
"""
- node = commit10.get_node('README.rst')
+ node = commit10.get_node("README.rst")
assert node.kind == NodeKind.FILE
assert node.str_content == README
@@ -283,39 +267,39 @@ TODO: To be written...
def test_checkout_with_create(self, tmpdir):
repo_clone = self.get_clone_repo(tmpdir)
- new_branch = 'new_branch'
- assert repo_clone._current_branch() == 'master'
- assert set(repo_clone.branches) == {'master'}
+ new_branch = "new_branch"
+ assert repo_clone._current_branch() == "master"
+ assert set(repo_clone.branches) == {"master"}
repo_clone._checkout(new_branch, create=True)
# Branches is a lazy property so we need to recrete the Repo object.
repo_clone = GitRepository(repo_clone.path)
- assert set(repo_clone.branches) == {'master', new_branch}
+ assert set(repo_clone.branches) == {"master", new_branch}
assert repo_clone._current_branch() == new_branch
def test_checkout(self, tmpdir):
repo_clone = self.get_clone_repo(tmpdir)
- repo_clone._checkout('new_branch', create=True)
- repo_clone._checkout('master')
+ repo_clone._checkout("new_branch", create=True)
+ repo_clone._checkout("master")
- assert repo_clone._current_branch() == 'master'
+ assert repo_clone._current_branch() == "master"
def test_checkout_same_branch(self, tmpdir):
repo_clone = self.get_clone_repo(tmpdir)
- repo_clone._checkout('master')
- assert repo_clone._current_branch() == 'master'
+ repo_clone._checkout("master")
+ assert repo_clone._current_branch() == "master"
def test_checkout_branch_already_exists(self, tmpdir):
repo_clone = self.get_clone_repo(tmpdir)
with pytest.raises(RepositoryError):
- repo_clone._checkout('master', create=True)
+ repo_clone._checkout("master", create=True)
def test_checkout_bare_repo(self):
with pytest.raises(RepositoryError):
- self.repo._checkout('master')
+ self.repo._checkout("master")
def test_current_branch_bare_repo(self):
with pytest.raises(RepositoryError):
@@ -326,8 +310,8 @@ TODO: To be written...
assert repo._current_branch() is None
def test_local_clone(self, tmp_path_factory):
- clone_path = str(tmp_path_factory.mktemp('test-local-clone'))
- self.repo._local_clone(clone_path, 'master')
+ clone_path = str(tmp_path_factory.mktemp("test-local-clone"))
+ self.repo._local_clone(clone_path, "master")
repo_clone = GitRepository(clone_path)
assert self.repo.commit_ids == repo_clone.commit_ids
@@ -338,23 +322,23 @@ TODO: To be written...
# Create a new branch in source repo
new_branch_commit = source_repo.commit_ids[-3]
source_repo._checkout(new_branch_commit)
- source_repo._checkout('new_branch', create=True)
+ source_repo._checkout("new_branch", create=True)
- clone_path = str(tmpdir.join('git-clone-path-1'))
- source_repo._local_clone(clone_path, 'new_branch')
+ clone_path = str(tmpdir.join("git-clone-path-1"))
+ source_repo._local_clone(clone_path, "new_branch")
repo_clone = GitRepository(clone_path)
- assert source_repo.commit_ids[:-3 + 1] == repo_clone.commit_ids
+ assert source_repo.commit_ids[: -3 + 1] == repo_clone.commit_ids
- clone_path = str(tmpdir.join('git-clone-path-2'))
- source_repo._local_clone(clone_path, 'master')
+ clone_path = str(tmpdir.join("git-clone-path-2"))
+ source_repo._local_clone(clone_path, "master")
repo_clone = GitRepository(clone_path)
assert source_repo.commit_ids == repo_clone.commit_ids
def test_local_clone_fails_if_target_exists(self):
with pytest.raises(RepositoryError):
- self.repo._local_clone(self.repo.path, 'master')
+ self.repo._local_clone(self.repo.path, "master")
def test_local_fetch(self, tmpdir):
target_repo = self.get_empty_repo(tmpdir)
@@ -364,30 +348,30 @@ TODO: To be written...
master_commit = source_repo.commit_ids[-1]
new_branch_commit = source_repo.commit_ids[-3]
source_repo._checkout(new_branch_commit)
- source_repo._checkout('new_branch', create=True)
+ source_repo._checkout("new_branch", create=True)
- target_repo._local_fetch(source_repo.path, 'new_branch')
+ target_repo._local_fetch(source_repo.path, "new_branch")
assert target_repo._last_fetch_heads() == [new_branch_commit]
- target_repo._local_fetch(source_repo.path, 'master')
+ target_repo._local_fetch(source_repo.path, "master")
assert target_repo._last_fetch_heads() == [master_commit]
def test_local_fetch_from_bare_repo(self, tmpdir):
target_repo = self.get_empty_repo(tmpdir)
- target_repo._local_fetch(self.repo.path, 'master')
+ target_repo._local_fetch(self.repo.path, "master")
master_commit = self.repo.commit_ids[-1]
assert target_repo._last_fetch_heads() == [master_commit]
def test_local_fetch_from_same_repo(self):
with pytest.raises(ValueError):
- self.repo._local_fetch(self.repo.path, 'master')
+ self.repo._local_fetch(self.repo.path, "master")
def test_local_fetch_branch_does_not_exist(self, tmpdir):
target_repo = self.get_empty_repo(tmpdir)
with pytest.raises(RepositoryError):
- target_repo._local_fetch(self.repo.path, 'new_branch')
+ target_repo._local_fetch(self.repo.path, "new_branch")
def test_local_pull(self, tmpdir):
target_repo = self.get_empty_repo(tmpdir)
@@ -397,19 +381,19 @@ TODO: To be written...
master_commit = source_repo.commit_ids[-1]
new_branch_commit = source_repo.commit_ids[-3]
source_repo._checkout(new_branch_commit)
- source_repo._checkout('new_branch', create=True)
+ source_repo._checkout("new_branch", create=True)
- target_repo._local_pull(source_repo.path, 'new_branch')
+ target_repo._local_pull(source_repo.path, "new_branch")
target_repo = GitRepository(target_repo.path)
assert target_repo.head == new_branch_commit
- target_repo._local_pull(source_repo.path, 'master')
+ target_repo._local_pull(source_repo.path, "master")
target_repo = GitRepository(target_repo.path)
assert target_repo.head == master_commit
def test_local_pull_in_bare_repo(self):
with pytest.raises(RepositoryError):
- self.repo._local_pull(self.repo.path, 'master')
+ self.repo._local_pull(self.repo.path, "master")
def test_local_merge(self, tmpdir):
target_repo = self.get_empty_repo(tmpdir)
@@ -419,159 +403,144 @@ TODO: To be written...
master_commit = source_repo.commit_ids[-1]
new_branch_commit = source_repo.commit_ids[-3]
source_repo._checkout(new_branch_commit)
- source_repo._checkout('new_branch', create=True)
+ source_repo._checkout("new_branch", create=True)
# This is required as one cannot do a -ff-only merge in an empty repo.
- target_repo._local_pull(source_repo.path, 'new_branch')
+ target_repo._local_pull(source_repo.path, "new_branch")
- target_repo._local_fetch(source_repo.path, 'master')
- merge_message = 'Merge message\n\nDescription:...'
- user_name = 'Albert Einstein'
- user_email = 'albert@einstein.com'
- target_repo._local_merge(merge_message, user_name, user_email,
- target_repo._last_fetch_heads())
+ target_repo._local_fetch(source_repo.path, "master")
+ merge_message = "Merge message\n\nDescription:..."
+ user_name = "Albert Einstein"
+ user_email = "albert@einstein.com"
+ target_repo._local_merge(merge_message, user_name, user_email, target_repo._last_fetch_heads())
target_repo = GitRepository(target_repo.path)
assert target_repo.commit_ids[-2] == master_commit
last_commit = target_repo.get_commit(target_repo.head)
assert last_commit.message.strip() == merge_message
- assert last_commit.author == '%s <%s>' % (user_name, user_email)
+ assert last_commit.author == "%s <%s>" % (user_name, user_email)
- assert not os.path.exists(
- os.path.join(target_repo.path, '.git', 'MERGE_HEAD'))
+ assert not os.path.exists(os.path.join(target_repo.path, ".git", "MERGE_HEAD"))
def test_local_merge_raises_exception_on_conflict(self, vcsbackend_git):
target_repo = vcsbackend_git.create_repo(number_of_commits=1)
- vcsbackend_git.ensure_file(b'README', b'I will conflict with you!!!')
+ vcsbackend_git.ensure_file(b"README", b"I will conflict with you!!!")
- target_repo._local_fetch(self.repo.path, 'master')
+ target_repo._local_fetch(self.repo.path, "master")
with pytest.raises(RepositoryError):
- target_repo._local_merge(
- 'merge_message', 'user name', 'user@name.com',
- target_repo._last_fetch_heads())
+ target_repo._local_merge("merge_message", "user name", "user@name.com", target_repo._last_fetch_heads())
# Check we are not left in an intermediate merge state
- assert not os.path.exists(
- os.path.join(target_repo.path, '.git', 'MERGE_HEAD'))
+ assert not os.path.exists(os.path.join(target_repo.path, ".git", "MERGE_HEAD"))
def test_local_merge_into_empty_repo(self, tmpdir):
target_repo = self.get_empty_repo(tmpdir)
# This is required as one cannot do a -ff-only merge in an empty repo.
- target_repo._local_fetch(self.repo.path, 'master')
+ target_repo._local_fetch(self.repo.path, "master")
with pytest.raises(RepositoryError):
- target_repo._local_merge(
- 'merge_message', 'user name', 'user@name.com',
- target_repo._last_fetch_heads())
+ target_repo._local_merge("merge_message", "user name", "user@name.com", target_repo._last_fetch_heads())
def test_local_merge_in_bare_repo(self):
with pytest.raises(RepositoryError):
- self.repo._local_merge(
- 'merge_message', 'user name', 'user@name.com', None)
+ self.repo._local_merge("merge_message", "user name", "user@name.com", None)
def test_local_push_non_bare(self, tmpdir):
target_repo = self.get_empty_repo(tmpdir)
- pushed_branch = 'pushed_branch'
- self.repo._local_push('master', target_repo.path, pushed_branch)
+ pushed_branch = "pushed_branch"
+ self.repo._local_push("master", target_repo.path, pushed_branch)
# Fix the HEAD of the target repo, or otherwise GitRepository won't
# report any branches.
- with open(os.path.join(target_repo.path, '.git', 'HEAD'), 'w') as f:
- f.write('ref: refs/heads/%s' % pushed_branch)
+ with open(os.path.join(target_repo.path, ".git", "HEAD"), "w") as f:
+ f.write("ref: refs/heads/%s" % pushed_branch)
target_repo = GitRepository(target_repo.path)
- assert (target_repo.branches[pushed_branch] ==
- self.repo.branches['master'])
+ assert target_repo.branches[pushed_branch] == self.repo.branches["master"]
def test_local_push_bare(self, tmpdir):
target_repo = self.get_empty_repo(tmpdir, bare=True)
- pushed_branch = 'pushed_branch'
- self.repo._local_push('master', target_repo.path, pushed_branch)
+ pushed_branch = "pushed_branch"
+ self.repo._local_push("master", target_repo.path, pushed_branch)
# Fix the HEAD of the target repo, or otherwise GitRepository won't
# report any branches.
- with open(os.path.join(target_repo.path, 'HEAD'), 'w') as f:
- f.write('ref: refs/heads/%s' % pushed_branch)
+ with open(os.path.join(target_repo.path, "HEAD"), "w") as f:
+ f.write("ref: refs/heads/%s" % pushed_branch)
target_repo = GitRepository(target_repo.path)
- assert (target_repo.branches[pushed_branch] ==
- self.repo.branches['master'])
+ assert target_repo.branches[pushed_branch] == self.repo.branches["master"]
def test_local_push_non_bare_target_branch_is_checked_out(self, tmpdir):
target_repo = self.get_clone_repo(tmpdir)
- pushed_branch = 'pushed_branch'
+ pushed_branch = "pushed_branch"
# Create a new branch in source repo
new_branch_commit = target_repo.commit_ids[-3]
target_repo._checkout(new_branch_commit)
target_repo._checkout(pushed_branch, create=True)
- self.repo._local_push('master', target_repo.path, pushed_branch)
+ self.repo._local_push("master", target_repo.path, pushed_branch)
target_repo = GitRepository(target_repo.path)
- assert (target_repo.branches[pushed_branch] ==
- self.repo.branches['master'])
+ assert target_repo.branches[pushed_branch] == self.repo.branches["master"]
def test_local_push_raises_exception_on_conflict(self, vcsbackend_git):
target_repo = vcsbackend_git.create_repo(number_of_commits=1)
with pytest.raises(RepositoryError):
- self.repo._local_push('master', target_repo.path, 'master')
+ self.repo._local_push("master", target_repo.path, "master")
def test_hooks_can_be_enabled_via_env_variable_for_local_push(self, tmpdir):
target_repo = self.get_empty_repo(tmpdir, bare=True)
- with mock.patch.object(self.repo, 'run_git_command') as run_mock:
- self.repo._local_push(
- 'master', target_repo.path, 'master', enable_hooks=True)
- env = run_mock.call_args[1]['extra_env']
- assert 'RC_SKIP_HOOKS' not in env
+ with mock.patch.object(self.repo, "run_git_command") as run_mock:
+ self.repo._local_push("master", target_repo.path, "master", enable_hooks=True)
+ env = run_mock.call_args[1]["extra_env"]
+ assert "RC_SKIP_HOOKS" not in env
def _add_failing_hook(self, repo_path, hook_name, bare=False):
- path_components = (
- ['hooks', hook_name] if bare else ['.git', 'hooks', hook_name])
+ path_components = ["hooks", hook_name] if bare else [".git", "hooks", hook_name]
hook_path = os.path.join(repo_path, *path_components)
- with open(hook_path, 'w') as f:
+ with open(hook_path, "w") as f:
script_lines = [
- '#!%s' % sys.executable,
- 'import os',
- 'import sys',
+ "#!%s" % sys.executable,
+ "import os",
+ "import sys",
'if os.environ.get("RC_SKIP_HOOKS"):',
- ' sys.exit(0)',
- 'sys.exit(1)',
+ " sys.exit(0)",
+ "sys.exit(1)",
]
- f.write('\n'.join(script_lines))
+ f.write("\n".join(script_lines))
os.chmod(hook_path, 0o755)
def test_local_push_does_not_execute_hook(self, tmpdir):
target_repo = self.get_empty_repo(tmpdir)
- pushed_branch = 'pushed_branch'
- self._add_failing_hook(target_repo.path, 'pre-receive')
- self.repo._local_push('master', target_repo.path, pushed_branch)
+ pushed_branch = "pushed_branch"
+ self._add_failing_hook(target_repo.path, "pre-receive")
+ self.repo._local_push("master", target_repo.path, pushed_branch)
# Fix the HEAD of the target repo, or otherwise GitRepository won't
# report any branches.
- with open(os.path.join(target_repo.path, '.git', 'HEAD'), 'w') as f:
- f.write('ref: refs/heads/%s' % pushed_branch)
+ with open(os.path.join(target_repo.path, ".git", "HEAD"), "w") as f:
+ f.write("ref: refs/heads/%s" % pushed_branch)
target_repo = GitRepository(target_repo.path)
- assert (target_repo.branches[pushed_branch] ==
- self.repo.branches['master'])
+ assert target_repo.branches[pushed_branch] == self.repo.branches["master"]
def test_local_push_executes_hook(self, tmpdir):
target_repo = self.get_empty_repo(tmpdir, bare=True)
- self._add_failing_hook(target_repo.path, 'pre-receive', bare=True)
+ self._add_failing_hook(target_repo.path, "pre-receive", bare=True)
with pytest.raises(RepositoryError):
- self.repo._local_push(
- 'master', target_repo.path, 'master', enable_hooks=True)
+ self.repo._local_push("master", target_repo.path, "master", enable_hooks=True)
def test_maybe_prepare_merge_workspace(self):
workspace = self.repo._maybe_prepare_merge_workspace(
- 2, 'pr2', Reference('branch', 'master', 'unused'),
- Reference('branch', 'master', 'unused'))
+ 2, "pr2", Reference("branch", "master", "unused"), Reference("branch", "master", "unused")
+ )
assert os.path.isdir(workspace)
workspace_repo = GitRepository(workspace)
@@ -579,14 +548,14 @@ TODO: To be written...
# Calling it a second time should also succeed
workspace = self.repo._maybe_prepare_merge_workspace(
- 2, 'pr2', Reference('branch', 'master', 'unused'),
- Reference('branch', 'master', 'unused'))
+ 2, "pr2", Reference("branch", "master", "unused"), Reference("branch", "master", "unused")
+ )
assert os.path.isdir(workspace)
def test_maybe_prepare_merge_workspace_different_refs(self):
workspace = self.repo._maybe_prepare_merge_workspace(
- 2, 'pr2', Reference('branch', 'master', 'unused'),
- Reference('branch', 'develop', 'unused'))
+ 2, "pr2", Reference("branch", "master", "unused"), Reference("branch", "develop", "unused")
+ )
assert os.path.isdir(workspace)
workspace_repo = GitRepository(workspace)
@@ -594,48 +563,47 @@ TODO: To be written...
# Calling it a second time should also succeed
workspace = self.repo._maybe_prepare_merge_workspace(
- 2, 'pr2', Reference('branch', 'master', 'unused'),
- Reference('branch', 'develop', 'unused'))
+ 2, "pr2", Reference("branch", "master", "unused"), Reference("branch", "develop", "unused")
+ )
assert os.path.isdir(workspace)
def test_cleanup_merge_workspace(self):
workspace = self.repo._maybe_prepare_merge_workspace(
- 2, 'pr3', Reference('branch', 'master', 'unused'),
- Reference('branch', 'master', 'unused'))
- self.repo.cleanup_merge_workspace(2, 'pr3')
+ 2, "pr3", Reference("branch", "master", "unused"), Reference("branch", "master", "unused")
+ )
+ self.repo.cleanup_merge_workspace(2, "pr3")
assert not os.path.exists(workspace)
def test_cleanup_merge_workspace_invalid_workspace_id(self):
# No assert: because in case of an inexistent workspace this function
# should still succeed.
- self.repo.cleanup_merge_workspace(1, 'pr4')
+ self.repo.cleanup_merge_workspace(1, "pr4")
def test_set_refs(self):
- test_ref = 'refs/test-refs/abcde'
- test_commit_id = 'ecb86e1f424f2608262b130db174a7dfd25a6623'
+ test_ref = "refs/test-refs/abcde"
+ test_commit_id = "ecb86e1f424f2608262b130db174a7dfd25a6623"
self.repo.set_refs(test_ref, test_commit_id)
- stdout, _ = self.repo.run_git_command(['show-ref'])
+ stdout, _ = self.repo.run_git_command(["show-ref"])
assert test_ref in stdout
assert test_commit_id in stdout
def test_remove_ref(self):
- test_ref = 'refs/test-refs/abcde'
- test_commit_id = 'ecb86e1f424f2608262b130db174a7dfd25a6623'
+ test_ref = "refs/test-refs/abcde"
+ test_commit_id = "ecb86e1f424f2608262b130db174a7dfd25a6623"
self.repo.set_refs(test_ref, test_commit_id)
- stdout, _ = self.repo.run_git_command(['show-ref'])
+ stdout, _ = self.repo.run_git_command(["show-ref"])
assert test_ref in stdout
assert test_commit_id in stdout
self.repo.remove_ref(test_ref)
- stdout, _ = self.repo.run_git_command(['show-ref'])
+ stdout, _ = self.repo.run_git_command(["show-ref"])
assert test_ref not in stdout
assert test_commit_id not in stdout
class TestGitCommit(object):
-
@pytest.fixture(autouse=True)
def prepare(self):
self.repo = GitRepository(TEST_GIT_REPO)
@@ -643,11 +611,11 @@ class TestGitCommit(object):
def test_default_commit(self):
tip = self.repo.get_commit()
assert tip == self.repo.get_commit(None)
- assert tip == self.repo.get_commit('tip')
+ assert tip == self.repo.get_commit("tip")
def test_root_node(self):
tip = self.repo.get_commit()
- assert tip.root is tip.get_node('')
+ assert tip.root is tip.get_node("")
def test_lazy_fetch(self):
"""
@@ -655,7 +623,7 @@ class TestGitCommit(object):
the commit. This test is somewhat hard to write as order of tests
is a key here. Written by running command after command in a shell.
"""
- commit_id = '2a13f185e4525f9d4b59882791a2d397b90d5ddc'
+ commit_id = "2a13f185e4525f9d4b59882791a2d397b90d5ddc"
assert commit_id in self.repo.commit_ids
commit = self.repo.get_commit(commit_id)
assert len(commit.nodes) == 0
@@ -665,31 +633,29 @@ class TestGitCommit(object):
# accessing root.nodes updates commit.nodes
assert len(commit.nodes) == 9
- docs = root.get_node('docs')
+ docs = root.get_node("docs")
# we haven't yet accessed anything new as docs dir was already cached
assert len(commit.nodes) == 9
assert len(docs.nodes) == 8
# accessing docs.nodes updates commit.nodes
assert len(commit.nodes) == 17
- assert docs is commit.get_node('docs')
+ assert docs is commit.get_node("docs")
assert docs is root.nodes[0]
assert docs is root.dirs[0]
- assert docs is commit.get_node('docs')
+ assert docs is commit.get_node("docs")
def test_nodes_with_commit(self):
- commit_id = '2a13f185e4525f9d4b59882791a2d397b90d5ddc'
+ commit_id = "2a13f185e4525f9d4b59882791a2d397b90d5ddc"
commit = self.repo.get_commit(commit_id)
root = commit.root
- docs = root.get_node('docs')
- assert docs is commit.get_node('docs')
- api = docs.get_node('api')
- assert api is commit.get_node('docs/api')
- index = api.get_node('index.rst')
- assert index is commit.get_node('docs/api/index.rst')
- assert index is commit.get_node('docs')\
- .get_node('api')\
- .get_node('index.rst')
+ docs = root.get_node("docs")
+ assert docs is commit.get_node("docs")
+ api = docs.get_node("api")
+ assert api is commit.get_node("docs/api")
+ index = api.get_node("index.rst")
+ assert index is commit.get_node("docs/api/index.rst")
+ assert index is commit.get_node("docs").get_node("api").get_node("index.rst")
def test_branch_and_tags(self):
"""
@@ -716,19 +682,12 @@ class TestGitCommit(object):
def test_file_size(self):
to_check = (
- ('c1214f7e79e02fc37156ff215cd71275450cffc3',
- 'vcs/backends/BaseRepository.py', 502),
- ('d7e0d30fbcae12c90680eb095a4f5f02505ce501',
- 'vcs/backends/hg.py', 854),
- ('6e125e7c890379446e98980d8ed60fba87d0f6d1',
- 'setup.py', 1068),
-
- ('d955cd312c17b02143c04fa1099a352b04368118',
- 'vcs/backends/base.py', 2921),
- ('ca1eb7957a54bce53b12d1a51b13452f95bc7c7e',
- 'vcs/backends/base.py', 3936),
- ('f50f42baeed5af6518ef4b0cb2f1423f3851a941',
- 'vcs/backends/base.py', 6189),
+ ("c1214f7e79e02fc37156ff215cd71275450cffc3", "vcs/backends/BaseRepository.py", 502),
+ ("d7e0d30fbcae12c90680eb095a4f5f02505ce501", "vcs/backends/hg.py", 854),
+ ("6e125e7c890379446e98980d8ed60fba87d0f6d1", "setup.py", 1068),
+ ("d955cd312c17b02143c04fa1099a352b04368118", "vcs/backends/base.py", 2921),
+ ("ca1eb7957a54bce53b12d1a51b13452f95bc7c7e", "vcs/backends/base.py", 3936),
+ ("f50f42baeed5af6518ef4b0cb2f1423f3851a941", "vcs/backends/base.py", 6189),
)
for commit_id, path, size in to_check:
node = self.repo.get_commit(commit_id).get_node(path)
@@ -736,80 +695,77 @@ class TestGitCommit(object):
assert node.size == size
def test_file_history_from_commits(self):
- node = self.repo[10].get_node('setup.py')
+ node = self.repo[10].get_node("setup.py")
commit_ids = [commit.raw_id for commit in node.history]
- assert ['ff7ca51e58c505fec0dd2491de52c622bb7a806b'] == commit_ids
+ assert ["ff7ca51e58c505fec0dd2491de52c622bb7a806b"] == commit_ids
- node = self.repo[20].get_node('setup.py')
+ node = self.repo[20].get_node("setup.py")
node_ids = [commit.raw_id for commit in node.history]
- assert ['191caa5b2c81ed17c0794bf7bb9958f4dcb0b87e',
- 'ff7ca51e58c505fec0dd2491de52c622bb7a806b'] == node_ids
+ assert ["191caa5b2c81ed17c0794bf7bb9958f4dcb0b87e", "ff7ca51e58c505fec0dd2491de52c622bb7a806b"] == node_ids
# special case we check history from commit that has this particular
# file changed this means we check if it's included as well
- node = self.repo.get_commit('191caa5b2c81ed17c0794bf7bb9958f4dcb0b87e') \
- .get_node('setup.py')
+ node = self.repo.get_commit("191caa5b2c81ed17c0794bf7bb9958f4dcb0b87e").get_node("setup.py")
node_ids = [commit.raw_id for commit in node.history]
- assert ['191caa5b2c81ed17c0794bf7bb9958f4dcb0b87e',
- 'ff7ca51e58c505fec0dd2491de52c622bb7a806b'] == node_ids
+ assert ["191caa5b2c81ed17c0794bf7bb9958f4dcb0b87e", "ff7ca51e58c505fec0dd2491de52c622bb7a806b"] == node_ids
def test_file_history(self):
# we can only check if those commits are present in the history
# as we cannot update this test every time file is changed
files = {
- 'setup.py': [
- '54386793436c938cff89326944d4c2702340037d',
- '51d254f0ecf5df2ce50c0b115741f4cf13985dab',
- '998ed409c795fec2012b1c0ca054d99888b22090',
- '5e0eb4c47f56564395f76333f319d26c79e2fb09',
- '0115510b70c7229dbc5dc49036b32e7d91d23acd',
- '7cb3fd1b6d8c20ba89e2264f1c8baebc8a52d36e',
- '2a13f185e4525f9d4b59882791a2d397b90d5ddc',
- '191caa5b2c81ed17c0794bf7bb9958f4dcb0b87e',
- 'ff7ca51e58c505fec0dd2491de52c622bb7a806b',
+ "setup.py": [
+ "54386793436c938cff89326944d4c2702340037d",
+ "51d254f0ecf5df2ce50c0b115741f4cf13985dab",
+ "998ed409c795fec2012b1c0ca054d99888b22090",
+ "5e0eb4c47f56564395f76333f319d26c79e2fb09",
+ "0115510b70c7229dbc5dc49036b32e7d91d23acd",
+ "7cb3fd1b6d8c20ba89e2264f1c8baebc8a52d36e",
+ "2a13f185e4525f9d4b59882791a2d397b90d5ddc",
+ "191caa5b2c81ed17c0794bf7bb9958f4dcb0b87e",
+ "ff7ca51e58c505fec0dd2491de52c622bb7a806b",
],
- 'vcs/nodes.py': [
- '33fa3223355104431402a888fa77a4e9956feb3e',
- 'fa014c12c26d10ba682fadb78f2a11c24c8118e1',
- 'e686b958768ee96af8029fe19c6050b1a8dd3b2b',
- 'ab5721ca0a081f26bf43d9051e615af2cc99952f',
- 'c877b68d18e792a66b7f4c529ea02c8f80801542',
- '4313566d2e417cb382948f8d9d7c765330356054',
- '6c2303a793671e807d1cfc70134c9ca0767d98c2',
- '54386793436c938cff89326944d4c2702340037d',
- '54000345d2e78b03a99d561399e8e548de3f3203',
- '1c6b3677b37ea064cb4b51714d8f7498f93f4b2b',
- '2d03ca750a44440fb5ea8b751176d1f36f8e8f46',
- '2a08b128c206db48c2f0b8f70df060e6db0ae4f8',
- '30c26513ff1eb8e5ce0e1c6b477ee5dc50e2f34b',
- 'ac71e9503c2ca95542839af0ce7b64011b72ea7c',
- '12669288fd13adba2a9b7dd5b870cc23ffab92d2',
- '5a0c84f3e6fe3473e4c8427199d5a6fc71a9b382',
- '12f2f5e2b38e6ff3fbdb5d722efed9aa72ecb0d5',
- '5eab1222a7cd4bfcbabc218ca6d04276d4e27378',
- 'f50f42baeed5af6518ef4b0cb2f1423f3851a941',
- 'd7e390a45f6aa96f04f5e7f583ad4f867431aa25',
- 'f15c21f97864b4f071cddfbf2750ec2e23859414',
- 'e906ef056cf539a4e4e5fc8003eaf7cf14dd8ade',
- 'ea2b108b48aa8f8c9c4a941f66c1a03315ca1c3b',
- '84dec09632a4458f79f50ddbbd155506c460b4f9',
- '0115510b70c7229dbc5dc49036b32e7d91d23acd',
- '2a13f185e4525f9d4b59882791a2d397b90d5ddc',
- '3bf1c5868e570e39569d094f922d33ced2fa3b2b',
- 'b8d04012574729d2c29886e53b1a43ef16dd00a1',
- '6970b057cffe4aab0a792aa634c89f4bebf01441',
- 'dd80b0f6cf5052f17cc738c2951c4f2070200d7f',
- 'ff7ca51e58c505fec0dd2491de52c622bb7a806b',
+ "vcs/nodes.py": [
+ "33fa3223355104431402a888fa77a4e9956feb3e",
+ "fa014c12c26d10ba682fadb78f2a11c24c8118e1",
+ "e686b958768ee96af8029fe19c6050b1a8dd3b2b",
+ "ab5721ca0a081f26bf43d9051e615af2cc99952f",
+ "c877b68d18e792a66b7f4c529ea02c8f80801542",
+ "4313566d2e417cb382948f8d9d7c765330356054",
+ "6c2303a793671e807d1cfc70134c9ca0767d98c2",
+ "54386793436c938cff89326944d4c2702340037d",
+ "54000345d2e78b03a99d561399e8e548de3f3203",
+ "1c6b3677b37ea064cb4b51714d8f7498f93f4b2b",
+ "2d03ca750a44440fb5ea8b751176d1f36f8e8f46",
+ "2a08b128c206db48c2f0b8f70df060e6db0ae4f8",
+ "30c26513ff1eb8e5ce0e1c6b477ee5dc50e2f34b",
+ "ac71e9503c2ca95542839af0ce7b64011b72ea7c",
+ "12669288fd13adba2a9b7dd5b870cc23ffab92d2",
+ "5a0c84f3e6fe3473e4c8427199d5a6fc71a9b382",
+ "12f2f5e2b38e6ff3fbdb5d722efed9aa72ecb0d5",
+ "5eab1222a7cd4bfcbabc218ca6d04276d4e27378",
+ "f50f42baeed5af6518ef4b0cb2f1423f3851a941",
+ "d7e390a45f6aa96f04f5e7f583ad4f867431aa25",
+ "f15c21f97864b4f071cddfbf2750ec2e23859414",
+ "e906ef056cf539a4e4e5fc8003eaf7cf14dd8ade",
+ "ea2b108b48aa8f8c9c4a941f66c1a03315ca1c3b",
+ "84dec09632a4458f79f50ddbbd155506c460b4f9",
+ "0115510b70c7229dbc5dc49036b32e7d91d23acd",
+ "2a13f185e4525f9d4b59882791a2d397b90d5ddc",
+ "3bf1c5868e570e39569d094f922d33ced2fa3b2b",
+ "b8d04012574729d2c29886e53b1a43ef16dd00a1",
+ "6970b057cffe4aab0a792aa634c89f4bebf01441",
+ "dd80b0f6cf5052f17cc738c2951c4f2070200d7f",
+ "ff7ca51e58c505fec0dd2491de52c622bb7a806b",
],
- 'vcs/backends/git.py': [
- '4cf116ad5a457530381135e2f4c453e68a1b0105',
- '9a751d84d8e9408e736329767387f41b36935153',
- 'cb681fb539c3faaedbcdf5ca71ca413425c18f01',
- '428f81bb652bcba8d631bce926e8834ff49bdcc6',
- '180ab15aebf26f98f714d8c68715e0f05fa6e1c7',
- '2b8e07312a2e89e92b90426ab97f349f4bce2a3a',
- '50e08c506174d8645a4bb517dd122ac946a0f3bf',
- '54000345d2e78b03a99d561399e8e548de3f3203',
+ "vcs/backends/git.py": [
+ "4cf116ad5a457530381135e2f4c453e68a1b0105",
+ "9a751d84d8e9408e736329767387f41b36935153",
+ "cb681fb539c3faaedbcdf5ca71ca413425c18f01",
+ "428f81bb652bcba8d631bce926e8834ff49bdcc6",
+ "180ab15aebf26f98f714d8c68715e0f05fa6e1c7",
+ "2b8e07312a2e89e92b90426ab97f349f4bce2a3a",
+ "50e08c506174d8645a4bb517dd122ac946a0f3bf",
+ "54000345d2e78b03a99d561399e8e548de3f3203",
],
}
for path, commit_ids in files.items():
@@ -817,79 +773,79 @@ class TestGitCommit(object):
node_ids = [commit.raw_id for commit in node.history]
assert set(commit_ids).issubset(set(node_ids)), (
"We assumed that %s is subset of commit_ids for which file %s "
- "has been changed, and history of that node returned: %s"
- % (commit_ids, path, node_ids))
+ "has been changed, and history of that node returned: %s" % (commit_ids, path, node_ids)
+ )
def test_file_annotate(self):
files = {
- 'vcs/backends/__init__.py': {
- 'c1214f7e79e02fc37156ff215cd71275450cffc3': {
- 'lines_no': 1,
- 'commits': [
- 'c1214f7e79e02fc37156ff215cd71275450cffc3',
+ "vcs/backends/__init__.py": {
+ "c1214f7e79e02fc37156ff215cd71275450cffc3": {
+ "lines_no": 1,
+ "commits": [
+ "c1214f7e79e02fc37156ff215cd71275450cffc3",
],
},
- '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647': {
- 'lines_no': 21,
- 'commits': [
- '49d3fd156b6f7db46313fac355dca1a0b94a0017',
- '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
- '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
- '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
- '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
- '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
- '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
- '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
- '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
- '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
- '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
- '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
- '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
- '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
- '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
- '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
- '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
- '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
- '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
- '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
- '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
+ "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647": {
+ "lines_no": 21,
+ "commits": [
+ "49d3fd156b6f7db46313fac355dca1a0b94a0017",
+ "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
+ "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
+ "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
+ "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
+ "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
+ "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
+ "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
+ "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
+ "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
+ "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
+ "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
+ "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
+ "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
+ "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
+ "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
+ "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
+ "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
+ "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
+ "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
+ "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
],
},
- 'e29b67bd158580fc90fc5e9111240b90e6e86064': {
- 'lines_no': 32,
- 'commits': [
- '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
- '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
- '5eab1222a7cd4bfcbabc218ca6d04276d4e27378',
- '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
- '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
- '992f38217b979d0b0987d0bae3cc26dac85d9b19',
- '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
- '54000345d2e78b03a99d561399e8e548de3f3203',
- '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
- '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
- '78c3f0c23b7ee935ec276acb8b8212444c33c396',
- '992f38217b979d0b0987d0bae3cc26dac85d9b19',
- '992f38217b979d0b0987d0bae3cc26dac85d9b19',
- '992f38217b979d0b0987d0bae3cc26dac85d9b19',
- '992f38217b979d0b0987d0bae3cc26dac85d9b19',
- '2a13f185e4525f9d4b59882791a2d397b90d5ddc',
- '992f38217b979d0b0987d0bae3cc26dac85d9b19',
- '78c3f0c23b7ee935ec276acb8b8212444c33c396',
- '992f38217b979d0b0987d0bae3cc26dac85d9b19',
- '992f38217b979d0b0987d0bae3cc26dac85d9b19',
- '992f38217b979d0b0987d0bae3cc26dac85d9b19',
- '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
- '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
- '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
- '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
- '992f38217b979d0b0987d0bae3cc26dac85d9b19',
- '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
- '992f38217b979d0b0987d0bae3cc26dac85d9b19',
- '992f38217b979d0b0987d0bae3cc26dac85d9b19',
- '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
- '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
- '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
+ "e29b67bd158580fc90fc5e9111240b90e6e86064": {
+ "lines_no": 32,
+ "commits": [
+ "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
+ "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
+ "5eab1222a7cd4bfcbabc218ca6d04276d4e27378",
+ "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
+ "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
+ "992f38217b979d0b0987d0bae3cc26dac85d9b19",
+ "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
+ "54000345d2e78b03a99d561399e8e548de3f3203",
+ "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
+ "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
+ "78c3f0c23b7ee935ec276acb8b8212444c33c396",
+ "992f38217b979d0b0987d0bae3cc26dac85d9b19",
+ "992f38217b979d0b0987d0bae3cc26dac85d9b19",
+ "992f38217b979d0b0987d0bae3cc26dac85d9b19",
+ "992f38217b979d0b0987d0bae3cc26dac85d9b19",
+ "2a13f185e4525f9d4b59882791a2d397b90d5ddc",
+ "992f38217b979d0b0987d0bae3cc26dac85d9b19",
+ "78c3f0c23b7ee935ec276acb8b8212444c33c396",
+ "992f38217b979d0b0987d0bae3cc26dac85d9b19",
+ "992f38217b979d0b0987d0bae3cc26dac85d9b19",
+ "992f38217b979d0b0987d0bae3cc26dac85d9b19",
+ "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
+ "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
+ "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
+ "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
+ "992f38217b979d0b0987d0bae3cc26dac85d9b19",
+ "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
+ "992f38217b979d0b0987d0bae3cc26dac85d9b19",
+ "992f38217b979d0b0987d0bae3cc26dac85d9b19",
+ "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
+ "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
+ "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
],
},
},
@@ -903,37 +859,32 @@ class TestGitCommit(object):
l1_2 = [x[2]().raw_id for x in commit.get_file_annotate(fname)]
assert l1_1 == l1_2
l1 = l1_1
- l2 = files[fname][commit_id]['commits']
+ l2 = files[fname][commit_id]["commits"]
assert l1 == l2, (
"The lists of commit_ids for %s@commit_id %s"
"from annotation list should match each other, "
- "got \n%s \nvs \n%s " % (fname, commit_id, l1, l2))
+ "got \n%s \nvs \n%s " % (fname, commit_id, l1, l2)
+ )
def test_files_state(self):
"""
Tests state of FileNodes.
"""
- node = self.repo\
- .get_commit('e6ea6d16e2f26250124a1f4b4fe37a912f9d86a0')\
- .get_node('vcs/utils/diffs.py')
+ node = self.repo.get_commit("e6ea6d16e2f26250124a1f4b4fe37a912f9d86a0").get_node("vcs/utils/diffs.py")
assert node.state, NodeState.ADDED
assert node.added
assert not node.changed
assert not node.not_changed
assert not node.removed
- node = self.repo\
- .get_commit('33fa3223355104431402a888fa77a4e9956feb3e')\
- .get_node('.hgignore')
+ node = self.repo.get_commit("33fa3223355104431402a888fa77a4e9956feb3e").get_node(".hgignore")
assert node.state, NodeState.CHANGED
assert not node.added
assert node.changed
assert not node.not_changed
assert not node.removed
- node = self.repo\
- .get_commit('e29b67bd158580fc90fc5e9111240b90e6e86064')\
- .get_node('setup.py')
+ node = self.repo.get_commit("e29b67bd158580fc90fc5e9111240b90e6e86064").get_node("setup.py")
assert node.state, NodeState.NOT_CHANGED
assert not node.added
assert not node.changed
@@ -942,48 +893,38 @@ class TestGitCommit(object):
# If node has REMOVED state then trying to fetch it would raise
# CommitError exception
- commit = self.repo.get_commit(
- 'fa6600f6848800641328adbf7811fd2372c02ab2')
- path = 'vcs/backends/BaseRepository.py'
+ commit = self.repo.get_commit("fa6600f6848800641328adbf7811fd2372c02ab2")
+ path = "vcs/backends/BaseRepository.py"
with pytest.raises(NodeDoesNotExistError):
commit.get_node(path)
# but it would be one of ``removed`` (commit's attribute)
assert path in [rf.path for rf in commit.removed]
- commit = self.repo.get_commit(
- '54386793436c938cff89326944d4c2702340037d')
- changed = [
- 'setup.py', 'tests/test_nodes.py', 'vcs/backends/hg.py',
- 'vcs/nodes.py']
+ commit = self.repo.get_commit("54386793436c938cff89326944d4c2702340037d")
+ changed = ["setup.py", "tests/test_nodes.py", "vcs/backends/hg.py", "vcs/nodes.py"]
assert set(changed) == set([f.path for f in commit.changed])
def test_unicode_branch_refs(self):
unicode_branches = {
- 'refs/heads/unicode': '6c0ce52b229aa978889e91b38777f800e85f330b',
- u'refs/heads/uniçö∂e': 'ürl',
+ "refs/heads/unicode": "6c0ce52b229aa978889e91b38777f800e85f330b",
+ "refs/heads/uniçö∂e": "ürl",
}
- with mock.patch(
- ("rhodecode.lib.vcs.backends.git.repository"
- ".GitRepository._refs"),
- unicode_branches):
+ with mock.patch(("rhodecode.lib.vcs.backends.git.repository" ".GitRepository._refs"), unicode_branches):
branches = self.repo.branches
- assert 'unicode' in branches
- assert 'uniçö∂e' in branches
+ assert "unicode" in branches
+ assert "uniçö∂e" in branches
def test_unicode_tag_refs(self):
unicode_tags = {
- 'refs/tags/unicode': '6c0ce52b229aa978889e91b38777f800e85f330b',
- u'refs/tags/uniçö∂e': '6c0ce52b229aa978889e91b38777f800e85f330b',
+ "refs/tags/unicode": "6c0ce52b229aa978889e91b38777f800e85f330b",
+ "refs/tags/uniçö∂e": "6c0ce52b229aa978889e91b38777f800e85f330b",
}
- with mock.patch(
- ("rhodecode.lib.vcs.backends.git.repository"
- ".GitRepository._refs"),
- unicode_tags):
+ with mock.patch(("rhodecode.lib.vcs.backends.git.repository" ".GitRepository._refs"), unicode_tags):
tags = self.repo.tags
- assert 'unicode' in tags
- assert 'uniçö∂e' in tags
+ assert "unicode" in tags
+ assert "uniçö∂e" in tags
def test_commit_message_is_unicode(self):
for commit in self.repo:
@@ -995,190 +936,186 @@ class TestGitCommit(object):
def test_repo_files_content_types(self):
commit = self.repo.get_commit()
- for node in commit.get_node('/'):
+ for node in commit.get_node("/"):
if node.is_file():
assert type(node.content) == bytes
assert type(node.str_content) == str
def test_wrong_path(self):
# There is 'setup.py' in the root dir but not there:
- path = 'foo/bar/setup.py'
+ path = "foo/bar/setup.py"
tip = self.repo.get_commit()
with pytest.raises(VCSError):
tip.get_node(path)
- @pytest.mark.parametrize("author_email, commit_id", [
- ('marcin@python-blog.com', 'c1214f7e79e02fc37156ff215cd71275450cffc3'),
- ('lukasz.balcerzak@python-center.pl',
- 'ff7ca51e58c505fec0dd2491de52c622bb7a806b'),
- ('none@none', '8430a588b43b5d6da365400117c89400326e7992'),
- ])
+ @pytest.mark.parametrize(
+ "author_email, commit_id",
+ [
+ ("marcin@python-blog.com", "c1214f7e79e02fc37156ff215cd71275450cffc3"),
+ ("lukasz.balcerzak@python-center.pl", "ff7ca51e58c505fec0dd2491de52c622bb7a806b"),
+ ("none@none", "8430a588b43b5d6da365400117c89400326e7992"),
+ ],
+ )
def test_author_email(self, author_email, commit_id):
commit = self.repo.get_commit(commit_id)
assert author_email == commit.author_email
- @pytest.mark.parametrize("author, commit_id", [
- ('Marcin Kuzminski', 'c1214f7e79e02fc37156ff215cd71275450cffc3'),
- ('Lukasz Balcerzak', 'ff7ca51e58c505fec0dd2491de52c622bb7a806b'),
- ('marcink', '8430a588b43b5d6da365400117c89400326e7992'),
- ])
+ @pytest.mark.parametrize(
+ "author, commit_id",
+ [
+ ("Marcin Kuzminski", "c1214f7e79e02fc37156ff215cd71275450cffc3"),
+ ("Lukasz Balcerzak", "ff7ca51e58c505fec0dd2491de52c622bb7a806b"),
+ ("marcink", "8430a588b43b5d6da365400117c89400326e7992"),
+ ],
+ )
def test_author_username(self, author, commit_id):
commit = self.repo.get_commit(commit_id)
assert author == commit.author_name
class TestLargeFileRepo(object):
-
def test_large_file(self, backend_git):
conf = make_db_config()
- repo = backend_git.create_test_repo('largefiles', conf)
+ git_largefiles_store = conf.get("vcs_git_lfs", "store_location")
+
+ repo = backend_git.create_test_repo("largefiles", conf)
tip = repo.scm_instance().get_commit()
+ node = tip.get_node("1MB.zip")
+
# extract stored LF node into the origin cache
- lfs_store = os.path.join(repo.repo_path, repo.repo_name, 'lfs_store')
+ repo_lfs_store: str = os.path.join(repo.repo_path, repo.repo_name, "lfs_store")
- oid = '7b331c02e313c7599d5a90212e17e6d3cb729bd2e1c9b873c302a63c95a2f9bf'
- oid_path = os.path.join(lfs_store, oid)
- # Todo: oid path depends on LFSOidStorage.store_suffix. Once it will be changed update below line accordingly
- oid_destination = os.path.join(
- conf.get('vcs_git_lfs', 'store_location'), f'objects/{oid[:2]}/{oid[2:4]}/{oid}')
+ oid: str = "7b331c02e313c7599d5a90212e17e6d3cb729bd2e1c9b873c302a63c95a2f9bf"
+ # where the OID actually is INSIDE the repo...
+ oid_path = os.path.join(repo_lfs_store, oid)
+
+ # Note: oid path depends on LFSOidStore.store_suffix. Once it will be changed update below line accordingly
+ oid_destination = os.path.join(git_largefiles_store, f"objects/{oid[:2]}/{oid[2:4]}/{oid}")
- os.makedirs(os.path.dirname(oid_destination))
shutil.copy(oid_path, oid_destination)
- node = tip.get_node('1MB.zip')
-
lf_node = node.get_largefile_node()
assert lf_node.is_largefile() is True
assert lf_node.size == 1024000
- assert lf_node.name == '1MB.zip'
+ assert lf_node.name == "1MB.zip"
@pytest.mark.usefixtures("vcs_repository_support")
class TestGitSpecificWithRepo(BackendTestMixin):
-
@classmethod
def _get_commits(cls):
return [
{
- 'message': 'Initial',
- 'author': 'Joe Doe ',
- 'date': datetime.datetime(2010, 1, 1, 20),
- 'added': [
- FileNode(b'foobar/static/js/admin/base.js', content=b'base'),
- FileNode(b'foobar/static/admin', content=b'admin', mode=0o120000), # this is a link
- FileNode(b'foo', content=b'foo'),
+ "message": "Initial",
+ "author": "Joe Doe ",
+ "date": datetime.datetime(2010, 1, 1, 20),
+ "added": [
+ FileNode(b"foobar/static/js/admin/base.js", content=b"base"),
+ FileNode(b"foobar/static/admin", content=b"admin", mode=0o120000), # this is a link
+ FileNode(b"foo", content=b"foo"),
],
},
{
- 'message': 'Second',
- 'author': 'Joe Doe ',
- 'date': datetime.datetime(2010, 1, 1, 22),
- 'added': [
- FileNode(b'foo2', content=b'foo2'),
+ "message": "Second",
+ "author": "Joe Doe ",
+ "date": datetime.datetime(2010, 1, 1, 22),
+ "added": [
+ FileNode(b"foo2", content=b"foo2"),
],
},
]
def test_paths_slow_traversing(self):
commit = self.repo.get_commit()
- assert commit.get_node('foobar').get_node('static').get_node('js')\
- .get_node('admin').get_node('base.js').content == b'base'
+ assert (
+ commit.get_node("foobar").get_node("static").get_node("js").get_node("admin").get_node("base.js").content
+ == b"base"
+ )
def test_paths_fast_traversing(self):
commit = self.repo.get_commit()
- assert commit.get_node('foobar/static/js/admin/base.js').content == b'base'
+ assert commit.get_node("foobar/static/js/admin/base.js").content == b"base"
def test_get_diff_runs_git_command_with_hashes(self):
comm1 = self.repo[0]
comm2 = self.repo[1]
- with mock.patch.object(self.repo, '_remote', return_value=mock.Mock()) as remote_mock:
+ with mock.patch.object(self.repo, "_remote", return_value=mock.Mock()) as remote_mock:
remote_mock.diff = mock.MagicMock(side_effect=callable_get_diff)
self.repo.get_diff(comm1, comm2)
remote_mock.diff.assert_called_once_with(
- comm1.raw_id, comm2.raw_id,
- file_filter=None, opt_ignorews=False, context=3)
+ comm1.raw_id, comm2.raw_id, file_filter=None, opt_ignorews=False, context=3
+ )
def test_get_diff_runs_git_command_with_str_hashes(self):
comm2 = self.repo[1]
- with mock.patch.object(self.repo, '_remote', return_value=mock.Mock()) as remote_mock:
+ with mock.patch.object(self.repo, "_remote", return_value=mock.Mock()) as remote_mock:
remote_mock.diff = mock.MagicMock(side_effect=callable_get_diff)
self.repo.get_diff(self.repo.EMPTY_COMMIT, comm2)
remote_mock.diff.assert_called_once_with(
- self.repo.EMPTY_COMMIT.raw_id, comm2.raw_id,
- file_filter=None, opt_ignorews=False, context=3)
+ self.repo.EMPTY_COMMIT.raw_id, comm2.raw_id, file_filter=None, opt_ignorews=False, context=3
+ )
def test_get_diff_runs_git_command_with_path_if_its_given(self):
comm1 = self.repo[0]
comm2 = self.repo[1]
- with mock.patch.object(self.repo, '_remote', return_value=mock.Mock()) as remote_mock:
+ with mock.patch.object(self.repo, "_remote", return_value=mock.Mock()) as remote_mock:
remote_mock.diff = mock.MagicMock(side_effect=callable_get_diff)
- self.repo.get_diff(comm1, comm2, 'foo')
+ self.repo.get_diff(comm1, comm2, "foo")
remote_mock.diff.assert_called_once_with(
- self.repo._lookup_commit(0), comm2.raw_id,
- file_filter='foo', opt_ignorews=False, context=3)
+ self.repo._lookup_commit(0), comm2.raw_id, file_filter="foo", opt_ignorews=False, context=3
+ )
@pytest.mark.usefixtures("vcs_repository_support")
class TestGitRegression(BackendTestMixin):
-
@classmethod
def _get_commits(cls):
return [
{
- 'message': 'Initial',
- 'author': 'Joe Doe ',
- 'date': datetime.datetime(2010, 1, 1, 20),
- 'added': [
- FileNode(b'bot/__init__.py', content=b'base'),
- FileNode(b'bot/templates/404.html', content=b'base'),
- FileNode(b'bot/templates/500.html', content=b'base'),
+ "message": "Initial",
+ "author": "Joe Doe ",
+ "date": datetime.datetime(2010, 1, 1, 20),
+ "added": [
+ FileNode(b"bot/__init__.py", content=b"base"),
+ FileNode(b"bot/templates/404.html", content=b"base"),
+ FileNode(b"bot/templates/500.html", content=b"base"),
],
},
{
- 'message': 'Second',
- 'author': 'Joe Doe ',
- 'date': datetime.datetime(2010, 1, 1, 22),
- 'added': [
- FileNode(b'bot/build/migrations/1.py', content=b'foo2'),
- FileNode(b'bot/build/migrations/2.py', content=b'foo2'),
- FileNode(b'bot/build/static/templates/f.html', content=b'foo2'),
- FileNode(b'bot/build/static/templates/f1.html', content=b'foo2'),
- FileNode(b'bot/build/templates/err.html', content=b'foo2'),
- FileNode(b'bot/build/templates/err2.html', content=b'foo2'),
+ "message": "Second",
+ "author": "Joe Doe ",
+ "date": datetime.datetime(2010, 1, 1, 22),
+ "added": [
+ FileNode(b"bot/build/migrations/1.py", content=b"foo2"),
+ FileNode(b"bot/build/migrations/2.py", content=b"foo2"),
+ FileNode(b"bot/build/static/templates/f.html", content=b"foo2"),
+ FileNode(b"bot/build/static/templates/f1.html", content=b"foo2"),
+ FileNode(b"bot/build/templates/err.html", content=b"foo2"),
+ FileNode(b"bot/build/templates/err2.html", content=b"foo2"),
],
},
]
- @pytest.mark.parametrize("path, expected_paths", [
- ('bot', [
- 'bot/build',
- 'bot/templates',
- 'bot/__init__.py']),
- ('bot/build', [
- 'bot/build/migrations',
- 'bot/build/static',
- 'bot/build/templates']),
- ('bot/build/static', [
- 'bot/build/static/templates']),
- ('bot/build/static/templates', [
- 'bot/build/static/templates/f.html',
- 'bot/build/static/templates/f1.html']),
- ('bot/build/templates', [
- 'bot/build/templates/err.html',
- 'bot/build/templates/err2.html']),
- ('bot/templates/', [
- 'bot/templates/404.html',
- 'bot/templates/500.html']),
- ])
+ @pytest.mark.parametrize(
+ "path, expected_paths",
+ [
+ ("bot", ["bot/build", "bot/templates", "bot/__init__.py"]),
+ ("bot/build", ["bot/build/migrations", "bot/build/static", "bot/build/templates"]),
+ ("bot/build/static", ["bot/build/static/templates"]),
+ ("bot/build/static/templates", ["bot/build/static/templates/f.html", "bot/build/static/templates/f1.html"]),
+ ("bot/build/templates", ["bot/build/templates/err.html", "bot/build/templates/err2.html"]),
+ ("bot/templates/", ["bot/templates/404.html", "bot/templates/500.html"]),
+ ],
+ )
def test_similar_paths(self, path, expected_paths):
commit = self.repo.get_commit()
paths = [n.path for n in commit.get_nodes(path)]
@@ -1186,122 +1123,120 @@ class TestGitRegression(BackendTestMixin):
class TestDiscoverGitVersion(object):
-
def test_returns_git_version(self, baseapp):
version = discover_git_version()
assert version
def test_returns_empty_string_without_vcsserver(self):
mock_connection = mock.Mock()
- mock_connection.discover_git_version = mock.Mock(
- side_effect=Exception)
- with mock.patch('rhodecode.lib.vcs.connection.Git', mock_connection):
+ mock_connection.discover_git_version = mock.Mock(side_effect=Exception)
+ with mock.patch("rhodecode.lib.vcs.connection.Git", mock_connection):
version = discover_git_version()
- assert version == ''
+ assert version == ""
class TestGetSubmoduleUrl(object):
def test_submodules_file_found(self):
- commit = GitCommit(repository=mock.Mock(), raw_id='abcdef12', idx=1)
+ commit = GitCommit(repository=mock.Mock(), raw_id="abcdef12", idx=1)
node = mock.Mock()
- with mock.patch.object(
- commit, 'get_node', return_value=node) as get_node_mock:
+ with mock.patch.object(commit, "get_node", return_value=node) as get_node_mock:
node.str_content = (
- '[submodule "subrepo1"]\n'
- '\tpath = subrepo1\n'
- '\turl = https://code.rhodecode.com/dulwich\n'
+ '[submodule "subrepo1"]\n' "\tpath = subrepo1\n" "\turl = https://code.rhodecode.com/dulwich\n"
)
- result = commit._get_submodule_url('subrepo1')
- get_node_mock.assert_called_once_with('.gitmodules')
- assert result == 'https://code.rhodecode.com/dulwich'
+ result = commit._get_submodule_url("subrepo1")
+ get_node_mock.assert_called_once_with(".gitmodules")
+ assert result == "https://code.rhodecode.com/dulwich"
def test_complex_submodule_path(self):
- commit = GitCommit(repository=mock.Mock(), raw_id='abcdef12', idx=1)
+ commit = GitCommit(repository=mock.Mock(), raw_id="abcdef12", idx=1)
node = mock.Mock()
- with mock.patch.object(
- commit, 'get_node', return_value=node) as get_node_mock:
+ with mock.patch.object(commit, "get_node", return_value=node) as get_node_mock:
node.str_content = (
'[submodule "complex/subrepo/path"]\n'
- '\tpath = complex/subrepo/path\n'
- '\turl = https://code.rhodecode.com/dulwich\n'
+ "\tpath = complex/subrepo/path\n"
+ "\turl = https://code.rhodecode.com/dulwich\n"
)
- result = commit._get_submodule_url('complex/subrepo/path')
- get_node_mock.assert_called_once_with('.gitmodules')
- assert result == 'https://code.rhodecode.com/dulwich'
+ result = commit._get_submodule_url("complex/subrepo/path")
+ get_node_mock.assert_called_once_with(".gitmodules")
+ assert result == "https://code.rhodecode.com/dulwich"
def test_submodules_file_not_found(self):
- commit = GitCommit(repository=mock.Mock(), raw_id='abcdef12', idx=1)
- with mock.patch.object(
- commit, 'get_node', side_effect=NodeDoesNotExistError):
- result = commit._get_submodule_url('complex/subrepo/path')
+ commit = GitCommit(repository=mock.Mock(), raw_id="abcdef12", idx=1)
+ with mock.patch.object(commit, "get_node", side_effect=NodeDoesNotExistError):
+ result = commit._get_submodule_url("complex/subrepo/path")
assert result is None
def test_path_not_found(self):
- commit = GitCommit(repository=mock.Mock(), raw_id='abcdef12', idx=1)
+ commit = GitCommit(repository=mock.Mock(), raw_id="abcdef12", idx=1)
node = mock.Mock()
- with mock.patch.object(
- commit, 'get_node', return_value=node) as get_node_mock:
+ with mock.patch.object(commit, "get_node", return_value=node) as get_node_mock:
node.str_content = (
- '[submodule "subrepo1"]\n'
- '\tpath = subrepo1\n'
- '\turl = https://code.rhodecode.com/dulwich\n'
+ '[submodule "subrepo1"]\n' "\tpath = subrepo1\n" "\turl = https://code.rhodecode.com/dulwich\n"
)
- result = commit._get_submodule_url('subrepo2')
- get_node_mock.assert_called_once_with('.gitmodules')
+ result = commit._get_submodule_url("subrepo2")
+ get_node_mock.assert_called_once_with(".gitmodules")
assert result is None
def test_returns_cached_values(self):
- commit = GitCommit(repository=mock.Mock(), raw_id='abcdef12', idx=1)
+ commit = GitCommit(repository=mock.Mock(), raw_id="abcdef12", idx=1)
node = mock.Mock()
- with mock.patch.object(
- commit, 'get_node', return_value=node) as get_node_mock:
+ with mock.patch.object(commit, "get_node", return_value=node) as get_node_mock:
node.str_content = (
- '[submodule "subrepo1"]\n'
- '\tpath = subrepo1\n'
- '\turl = https://code.rhodecode.com/dulwich\n'
+ '[submodule "subrepo1"]\n' "\tpath = subrepo1\n" "\turl = https://code.rhodecode.com/dulwich\n"
)
for _ in range(3):
- commit._get_submodule_url('subrepo1')
- get_node_mock.assert_called_once_with('.gitmodules')
+ commit._get_submodule_url("subrepo1")
+ get_node_mock.assert_called_once_with(".gitmodules")
def test_get_node_returns_a_link(self):
repository = mock.Mock()
- repository.alias = 'git'
- commit = GitCommit(repository=repository, raw_id='abcdef12', idx=1)
- submodule_url = 'https://code.rhodecode.com/dulwich'
- get_id_patch = mock.patch.object(
- commit, '_get_tree_id_for_path', return_value=(1, 'link'))
- get_submodule_patch = mock.patch.object(
- commit, '_get_submodule_url', return_value=submodule_url)
+ repository.alias = "git"
+ commit = GitCommit(repository=repository, raw_id="abcdef12", idx=1)
+ submodule_url = "https://code.rhodecode.com/dulwich"
+ get_id_patch = mock.patch.object(commit, "_get_tree_id_for_path", return_value=(1, "link"))
+ get_submodule_patch = mock.patch.object(commit, "_get_submodule_url", return_value=submodule_url)
with get_id_patch, get_submodule_patch as submodule_mock:
- node = commit.get_node('/abcde')
+ node = commit.get_node("/abcde")
- submodule_mock.assert_called_once_with('/abcde')
+ submodule_mock.assert_called_once_with("/abcde")
assert type(node) == SubModuleNode
assert node.url == submodule_url
def test_get_nodes_returns_links(self):
repository = mock.MagicMock()
- repository.alias = 'git'
- repository._remote.tree_items.return_value = [
- ('subrepo', 'stat', 1, 'link')
- ]
- commit = GitCommit(repository=repository, raw_id='abcdef12', idx=1)
- submodule_url = 'https://code.rhodecode.com/dulwich'
- get_id_patch = mock.patch.object(
- commit, '_get_tree_id_for_path', return_value=(1, 'tree'))
- get_submodule_patch = mock.patch.object(
- commit, '_get_submodule_url', return_value=submodule_url)
+ repository.alias = "git"
+ repository._remote.tree_items.return_value = [("subrepo", "stat", 1, "link")]
+ commit = GitCommit(repository=repository, raw_id="abcdef12", idx=1)
+ submodule_url = "https://code.rhodecode.com/dulwich"
+ get_id_patch = mock.patch.object(commit, "_get_tree_id_for_path", return_value=(1, "tree"))
+ get_submodule_patch = mock.patch.object(commit, "_get_submodule_url", return_value=submodule_url)
with get_id_patch, get_submodule_patch as submodule_mock:
- nodes = commit.get_nodes('/abcde')
+ nodes = commit.get_nodes("/abcde")
- submodule_mock.assert_called_once_with('/abcde/subrepo')
+ submodule_mock.assert_called_once_with("/abcde/subrepo")
assert len(nodes) == 1
assert type(nodes[0]) == SubModuleNode
assert nodes[0].url == submodule_url
+
+
+class TestGetShadowInstance(object):
+
+ @pytest.fixture()
+ def repo(self, vcsbackend_git):
+ _git_repo = vcsbackend_git.repo
+
+ mock.patch.object(_git_repo, "config", mock.Mock())
+ connection_mock = mock.Mock(unsafe=True, name="connection.Hg")
+
+ mock.patch("rhodecode.lib.vcs.connection.Git", connection_mock)
+ return _git_repo
+
+ def test_getting_shadow_instance_copies_config(self, repo):
+ shadow = repo.get_shadow_instance(repo.path)
+ assert shadow.config.serialize() == repo.config.serialize()
diff --git a/rhodecode/tests/vcs/test_hg.py b/rhodecode/tests/vcs/test_hg.py
index 20c90207..cf7ce267 100644
--- a/rhodecode/tests/vcs/test_hg.py
+++ b/rhodecode/tests/vcs/test_hg.py
@@ -1,4 +1,3 @@
-
# Copyright (C) 2010-2023 RhodeCode GmbH
#
# This program is free software: you can redistribute it and/or modify
@@ -25,11 +24,9 @@ import pytest
from rhodecode.lib.str_utils import safe_bytes
from rhodecode.lib.utils import make_db_config
from rhodecode.lib.vcs import backends
-from rhodecode.lib.vcs.backends.base import (
- Reference, MergeResponse, MergeFailureReason)
+from rhodecode.lib.vcs.backends.base import Reference, MergeResponse, MergeFailureReason
from rhodecode.lib.vcs.backends.hg import MercurialRepository, MercurialCommit
-from rhodecode.lib.vcs.exceptions import (
- RepositoryError, VCSError, NodeDoesNotExistError, CommitDoesNotExistError)
+from rhodecode.lib.vcs.exceptions import RepositoryError, VCSError, NodeDoesNotExistError, CommitDoesNotExistError
from rhodecode.lib.vcs.nodes import FileNode, NodeKind, NodeState
from rhodecode.tests import TEST_HG_REPO, TEST_HG_REPO_CLONE, repo_id_generator
@@ -44,12 +41,13 @@ def repo_path_generator():
i = 0
while True:
i += 1
- yield '%s-%d' % (TEST_HG_REPO_CLONE, i)
+ yield "%s-%d" % (TEST_HG_REPO_CLONE, i)
+
REPO_PATH_GENERATOR = repo_path_generator()
-@pytest.fixture(scope='class', autouse=True)
+@pytest.fixture(scope="class", autouse=True)
def repo(request, baseapp):
repo = MercurialRepository(TEST_HG_REPO)
if request.cls:
@@ -58,7 +56,6 @@ def repo(request, baseapp):
class TestMercurialRepository(object):
-
# pylint: disable=protected-access
def get_clone_repo(self):
@@ -66,8 +63,7 @@ class TestMercurialRepository(object):
Return a clone of the base repo.
"""
clone_path = next(REPO_PATH_GENERATOR)
- repo_clone = MercurialRepository(
- clone_path, create=True, src_url=self.repo.path)
+ repo_clone = MercurialRepository(clone_path, create=True, src_url=self.repo.path)
return repo_clone
@@ -78,40 +74,39 @@ class TestMercurialRepository(object):
return MercurialRepository(next(REPO_PATH_GENERATOR), create=True)
def test_wrong_repo_path(self):
- wrong_repo_path = '/tmp/errorrepo_hg'
+ wrong_repo_path = "/tmp/errorrepo_hg"
with pytest.raises(RepositoryError):
MercurialRepository(wrong_repo_path)
def test_unicode_path_repo(self):
with pytest.raises(VCSError):
- MercurialRepository('iShouldFail')
+ MercurialRepository("iShouldFail")
def test_unicode_commit_id(self):
with pytest.raises(CommitDoesNotExistError):
- self.repo.get_commit('unicode-commit-id')
+ self.repo.get_commit("unicode-commit-id")
with pytest.raises(CommitDoesNotExistError):
- self.repo.get_commit('unÃcøde-spéçial-chärÃ¥cter-commit-id')
+ self.repo.get_commit("unÃcøde-spéçial-chärÃ¥cter-commit-id")
def test_unicode_bookmark(self):
- self.repo.bookmark('unicode-bookmark')
- self.repo.bookmark('unÃcøde-spéçial-chärÃ¥cter-bookmark')
+ self.repo.bookmark("unicode-bookmark")
+ self.repo.bookmark("unÃcøde-spéçial-chärÃ¥cter-bookmark")
def test_unicode_branch(self):
with pytest.raises(KeyError):
- assert self.repo.branches['unicode-branch']
+ assert self.repo.branches["unicode-branch"]
with pytest.raises(KeyError):
- assert self.repo.branches['unÃcøde-spéçial-chärÃ¥cter-branch']
+ assert self.repo.branches["unÃcøde-spéçial-chärÃ¥cter-branch"]
def test_repo_clone(self):
if os.path.exists(TEST_HG_REPO_CLONE):
self.fail(
- 'Cannot test mercurial clone repo as location %s already '
- 'exists. You should manually remove it first.'
- % TEST_HG_REPO_CLONE)
+ "Cannot test mercurial clone repo as location %s already "
+ "exists. You should manually remove it first." % TEST_HG_REPO_CLONE
+ )
repo = MercurialRepository(TEST_HG_REPO)
- repo_clone = MercurialRepository(TEST_HG_REPO_CLONE,
- src_url=TEST_HG_REPO)
+ repo_clone = MercurialRepository(TEST_HG_REPO_CLONE, create=True, src_url=TEST_HG_REPO)
assert len(repo.commit_ids) == len(repo_clone.commit_ids)
# Checking hashes of commits should be enough
for commit in repo.get_commits():
@@ -121,72 +116,80 @@ class TestMercurialRepository(object):
def test_repo_clone_with_update(self):
repo = MercurialRepository(TEST_HG_REPO)
repo_clone = MercurialRepository(
- TEST_HG_REPO_CLONE + '_w_update',
- src_url=TEST_HG_REPO, do_workspace_checkout=True)
+ TEST_HG_REPO_CLONE + "_w_update", create=True, src_url=TEST_HG_REPO, do_workspace_checkout=True
+ )
assert len(repo.commit_ids) == len(repo_clone.commit_ids)
# check if current workdir was updated
- assert os.path.isfile(
- os.path.join(TEST_HG_REPO_CLONE + '_w_update', 'MANIFEST.in'))
+ assert os.path.isfile(os.path.join(TEST_HG_REPO_CLONE + "_w_update", "MANIFEST.in"))
def test_repo_clone_without_update(self):
repo = MercurialRepository(TEST_HG_REPO)
repo_clone = MercurialRepository(
- TEST_HG_REPO_CLONE + '_wo_update',
- src_url=TEST_HG_REPO, do_workspace_checkout=False)
+ TEST_HG_REPO_CLONE + "_wo_update", create=True, src_url=TEST_HG_REPO, do_workspace_checkout=False
+ )
assert len(repo.commit_ids) == len(repo_clone.commit_ids)
- assert not os.path.isfile(
- os.path.join(TEST_HG_REPO_CLONE + '_wo_update', 'MANIFEST.in'))
+ assert not os.path.isfile(os.path.join(TEST_HG_REPO_CLONE + "_wo_update", "MANIFEST.in"))
def test_commit_ids(self):
# there are 21 commits at bitbucket now
# so we can assume they would be available from now on
- subset = {'b986218ba1c9b0d6a259fac9b050b1724ed8e545', '3d8f361e72ab303da48d799ff1ac40d5ac37c67e',
- '6cba7170863a2411822803fa77a0a264f1310b35', '56349e29c2af3ac913b28bde9a2c6154436e615b',
- '2dda4e345facb0ccff1a191052dd1606dba6781d', '6fff84722075f1607a30f436523403845f84cd9e',
- '7d4bc8ec6be56c0f10425afb40b6fc315a4c25e7', '3803844fdbd3b711175fc3da9bdacfcd6d29a6fb',
- 'dc5d2c0661b61928834a785d3e64a3f80d3aad9c', 'be90031137367893f1c406e0a8683010fd115b79',
- 'db8e58be770518cbb2b1cdfa69146e47cd481481', '84478366594b424af694a6c784cb991a16b87c21',
- '17f8e105dddb9f339600389c6dc7175d395a535c', '20a662e756499bde3095ffc9bc0643d1def2d0eb',
- '2e319b85e70a707bba0beff866d9f9de032aa4f9', '786facd2c61deb9cf91e9534735124fb8fc11842',
- '94593d2128d38210a2fcd1aabff6dda0d6d9edf8', 'aa6a0de05b7612707db567078e130a6cd114a9a7',
- 'eada5a770da98ab0dd7325e29d00e0714f228d09'
- }
+ subset = {
+ "b986218ba1c9b0d6a259fac9b050b1724ed8e545",
+ "3d8f361e72ab303da48d799ff1ac40d5ac37c67e",
+ "6cba7170863a2411822803fa77a0a264f1310b35",
+ "56349e29c2af3ac913b28bde9a2c6154436e615b",
+ "2dda4e345facb0ccff1a191052dd1606dba6781d",
+ "6fff84722075f1607a30f436523403845f84cd9e",
+ "7d4bc8ec6be56c0f10425afb40b6fc315a4c25e7",
+ "3803844fdbd3b711175fc3da9bdacfcd6d29a6fb",
+ "dc5d2c0661b61928834a785d3e64a3f80d3aad9c",
+ "be90031137367893f1c406e0a8683010fd115b79",
+ "db8e58be770518cbb2b1cdfa69146e47cd481481",
+ "84478366594b424af694a6c784cb991a16b87c21",
+ "17f8e105dddb9f339600389c6dc7175d395a535c",
+ "20a662e756499bde3095ffc9bc0643d1def2d0eb",
+ "2e319b85e70a707bba0beff866d9f9de032aa4f9",
+ "786facd2c61deb9cf91e9534735124fb8fc11842",
+ "94593d2128d38210a2fcd1aabff6dda0d6d9edf8",
+ "aa6a0de05b7612707db567078e130a6cd114a9a7",
+ "eada5a770da98ab0dd7325e29d00e0714f228d09",
+ }
assert subset.issubset(set(self.repo.commit_ids))
# check if we have the proper order of commits
org = [
- 'b986218ba1c9b0d6a259fac9b050b1724ed8e545',
- '3d8f361e72ab303da48d799ff1ac40d5ac37c67e',
- '6cba7170863a2411822803fa77a0a264f1310b35',
- '56349e29c2af3ac913b28bde9a2c6154436e615b',
- '2dda4e345facb0ccff1a191052dd1606dba6781d',
- '6fff84722075f1607a30f436523403845f84cd9e',
- '7d4bc8ec6be56c0f10425afb40b6fc315a4c25e7',
- '3803844fdbd3b711175fc3da9bdacfcd6d29a6fb',
- 'dc5d2c0661b61928834a785d3e64a3f80d3aad9c',
- 'be90031137367893f1c406e0a8683010fd115b79',
- 'db8e58be770518cbb2b1cdfa69146e47cd481481',
- '84478366594b424af694a6c784cb991a16b87c21',
- '17f8e105dddb9f339600389c6dc7175d395a535c',
- '20a662e756499bde3095ffc9bc0643d1def2d0eb',
- '2e319b85e70a707bba0beff866d9f9de032aa4f9',
- '786facd2c61deb9cf91e9534735124fb8fc11842',
- '94593d2128d38210a2fcd1aabff6dda0d6d9edf8',
- 'aa6a0de05b7612707db567078e130a6cd114a9a7',
- 'eada5a770da98ab0dd7325e29d00e0714f228d09',
- '2c1885c735575ca478bf9e17b0029dca68824458',
- 'd9bcd465040bf869799b09ad732c04e0eea99fe9',
- '469e9c847fe1f6f7a697b8b25b4bc5b48780c1a7',
- '4fb8326d78e5120da2c7468dcf7098997be385da',
- '62b4a097164940bd66030c4db51687f3ec035eed',
- '536c1a19428381cfea92ac44985304f6a8049569',
- '965e8ab3c44b070cdaa5bf727ddef0ada980ecc4',
- '9bb326a04ae5d98d437dece54be04f830cf1edd9',
- 'f8940bcb890a98c4702319fbe36db75ea309b475',
- 'ff5ab059786ebc7411e559a2cc309dfae3625a3b',
- '6b6ad5f82ad5bb6190037671bd254bd4e1f4bf08',
- 'ee87846a61c12153b51543bf860e1026c6d3dcba',
+ "b986218ba1c9b0d6a259fac9b050b1724ed8e545",
+ "3d8f361e72ab303da48d799ff1ac40d5ac37c67e",
+ "6cba7170863a2411822803fa77a0a264f1310b35",
+ "56349e29c2af3ac913b28bde9a2c6154436e615b",
+ "2dda4e345facb0ccff1a191052dd1606dba6781d",
+ "6fff84722075f1607a30f436523403845f84cd9e",
+ "7d4bc8ec6be56c0f10425afb40b6fc315a4c25e7",
+ "3803844fdbd3b711175fc3da9bdacfcd6d29a6fb",
+ "dc5d2c0661b61928834a785d3e64a3f80d3aad9c",
+ "be90031137367893f1c406e0a8683010fd115b79",
+ "db8e58be770518cbb2b1cdfa69146e47cd481481",
+ "84478366594b424af694a6c784cb991a16b87c21",
+ "17f8e105dddb9f339600389c6dc7175d395a535c",
+ "20a662e756499bde3095ffc9bc0643d1def2d0eb",
+ "2e319b85e70a707bba0beff866d9f9de032aa4f9",
+ "786facd2c61deb9cf91e9534735124fb8fc11842",
+ "94593d2128d38210a2fcd1aabff6dda0d6d9edf8",
+ "aa6a0de05b7612707db567078e130a6cd114a9a7",
+ "eada5a770da98ab0dd7325e29d00e0714f228d09",
+ "2c1885c735575ca478bf9e17b0029dca68824458",
+ "d9bcd465040bf869799b09ad732c04e0eea99fe9",
+ "469e9c847fe1f6f7a697b8b25b4bc5b48780c1a7",
+ "4fb8326d78e5120da2c7468dcf7098997be385da",
+ "62b4a097164940bd66030c4db51687f3ec035eed",
+ "536c1a19428381cfea92ac44985304f6a8049569",
+ "965e8ab3c44b070cdaa5bf727ddef0ada980ecc4",
+ "9bb326a04ae5d98d437dece54be04f830cf1edd9",
+ "f8940bcb890a98c4702319fbe36db75ea309b475",
+ "ff5ab059786ebc7411e559a2cc309dfae3625a3b",
+ "6b6ad5f82ad5bb6190037671bd254bd4e1f4bf08",
+ "ee87846a61c12153b51543bf860e1026c6d3dcba",
]
assert org == self.repo.commit_ids[:31]
@@ -197,8 +200,7 @@ class TestMercurialRepository(object):
def test_slicing(self):
# 4 1 5 10 95
- for sfrom, sto, size in [(0, 4, 4), (1, 2, 1), (10, 15, 5),
- (10, 20, 10), (5, 100, 95)]:
+ for sfrom, sto, size in [(0, 4, 4), (1, 2, 1), (10, 15, 5), (10, 20, 10), (5, 100, 95)]:
indexes = list(self.repo[sfrom:sto])
assert len(indexes) == size
assert indexes[0] == self.repo.get_commit(commit_idx=sfrom)
@@ -208,64 +210,64 @@ class TestMercurialRepository(object):
# TODO: Need more tests here
# active branches
- assert 'default' in self.repo.branches
- assert 'stable' in self.repo.branches
+ assert "default" in self.repo.branches
+ assert "stable" in self.repo.branches
# closed
- assert 'git' in self.repo._get_branches(closed=True)
- assert 'web' in self.repo._get_branches(closed=True)
+ assert "git" in self.repo._get_branches(closed=True)
+ assert "web" in self.repo._get_branches(closed=True)
for name, id in self.repo.branches.items():
assert isinstance(self.repo.get_commit(id), MercurialCommit)
def test_tip_in_tags(self):
# tip is always a tag
- assert 'tip' in self.repo.tags
+ assert "tip" in self.repo.tags
def test_tip_commit_in_tags(self):
tip = self.repo.get_commit()
- assert self.repo.tags['tip'] == tip.raw_id
+ assert self.repo.tags["tip"] == tip.raw_id
def test_initial_commit(self):
init_commit = self.repo.get_commit(commit_idx=0)
init_author = init_commit.author
- assert init_commit.message == 'initial import'
- assert init_author == 'Marcin Kuzminski '
+ assert init_commit.message == "initial import"
+ assert init_author == "Marcin Kuzminski "
assert init_author == init_commit.committer
- assert sorted(init_commit._file_paths) == sorted([
- 'vcs/__init__.py',
- 'vcs/backends/BaseRepository.py',
- 'vcs/backends/__init__.py',
- ])
- assert sorted(init_commit._dir_paths) == sorted(
- ['', 'vcs', 'vcs/backends'])
+ assert sorted(init_commit._file_paths) == sorted(
+ [
+ "vcs/__init__.py",
+ "vcs/backends/BaseRepository.py",
+ "vcs/backends/__init__.py",
+ ]
+ )
+ assert sorted(init_commit._dir_paths) == sorted(["", "vcs", "vcs/backends"])
- assert init_commit._dir_paths + init_commit._file_paths == \
- init_commit._paths
+ assert init_commit._dir_paths + init_commit._file_paths == init_commit._paths
with pytest.raises(NodeDoesNotExistError):
- init_commit.get_node(path='foobar')
+ init_commit.get_node(path="foobar")
- node = init_commit.get_node('vcs/')
- assert hasattr(node, 'kind')
+ node = init_commit.get_node("vcs/")
+ assert hasattr(node, "kind")
assert node.kind == NodeKind.DIR
- node = init_commit.get_node('vcs')
- assert hasattr(node, 'kind')
+ node = init_commit.get_node("vcs")
+ assert hasattr(node, "kind")
assert node.kind == NodeKind.DIR
- node = init_commit.get_node('vcs/__init__.py')
- assert hasattr(node, 'kind')
+ node = init_commit.get_node("vcs/__init__.py")
+ assert hasattr(node, "kind")
assert node.kind == NodeKind.FILE
def test_not_existing_commit(self):
# rawid
with pytest.raises(RepositoryError):
- self.repo.get_commit('abcd' * 10)
+ self.repo.get_commit("abcd" * 10)
# shortid
with pytest.raises(RepositoryError):
- self.repo.get_commit('erro' * 4)
+ self.repo.get_commit("erro" * 4)
# numeric
with pytest.raises(RepositoryError):
self.repo.get_commit(commit_idx=self.repo.count() + 1)
@@ -289,7 +291,7 @@ Introduction
TODO: To be written...
"""
- node = commit10.get_node('README.rst')
+ node = commit10.get_node("README.rst")
assert node.kind == NodeKind.FILE
assert node.str_content == README
@@ -308,77 +310,73 @@ TODO: To be written...
repo_clone = self.get_clone_repo()
branches = repo_clone.branches
- repo_clone._update('default')
- assert branches['default'] == repo_clone._identify()
- repo_clone._update('stable')
- assert branches['stable'] == repo_clone._identify()
+ repo_clone._update("default")
+ assert branches["default"] == repo_clone._identify()
+ repo_clone._update("stable")
+ assert branches["stable"] == repo_clone._identify()
def test_local_pull_branch(self):
target_repo = self.get_empty_repo()
source_repo = self.get_clone_repo()
- default = Reference(
- 'branch', 'default', source_repo.branches['default'])
+ default = Reference("branch", "default", source_repo.branches["default"])
target_repo._local_pull(source_repo.path, default)
target_repo = MercurialRepository(target_repo.path)
- assert (target_repo.branches['default'] ==
- source_repo.branches['default'])
+ assert target_repo.branches["default"] == source_repo.branches["default"]
- stable = Reference('branch', 'stable', source_repo.branches['stable'])
+ stable = Reference("branch", "stable", source_repo.branches["stable"])
target_repo._local_pull(source_repo.path, stable)
target_repo = MercurialRepository(target_repo.path)
- assert target_repo.branches['stable'] == source_repo.branches['stable']
+ assert target_repo.branches["stable"] == source_repo.branches["stable"]
def test_local_pull_bookmark(self):
target_repo = self.get_empty_repo()
source_repo = self.get_clone_repo()
- commits = list(source_repo.get_commits(branch_name='default'))
+ commits = list(source_repo.get_commits(branch_name="default"))
foo1_id = commits[-5].raw_id
- foo1 = Reference('book', 'foo1', foo1_id)
+ foo1 = Reference("book", "foo1", foo1_id)
source_repo._update(foo1_id)
- source_repo.bookmark('foo1')
+ source_repo.bookmark("foo1")
foo2_id = commits[-3].raw_id
- foo2 = Reference('book', 'foo2', foo2_id)
+ foo2 = Reference("book", "foo2", foo2_id)
source_repo._update(foo2_id)
- source_repo.bookmark('foo2')
+ source_repo.bookmark("foo2")
target_repo._local_pull(source_repo.path, foo1)
target_repo = MercurialRepository(target_repo.path)
- assert target_repo.branches['default'] == commits[-5].raw_id
+ assert target_repo.branches["default"] == commits[-5].raw_id
target_repo._local_pull(source_repo.path, foo2)
target_repo = MercurialRepository(target_repo.path)
- assert target_repo.branches['default'] == commits[-3].raw_id
+ assert target_repo.branches["default"] == commits[-3].raw_id
def test_local_pull_commit(self):
target_repo = self.get_empty_repo()
source_repo = self.get_clone_repo()
- commits = list(source_repo.get_commits(branch_name='default'))
+ commits = list(source_repo.get_commits(branch_name="default"))
commit_id = commits[-5].raw_id
- commit = Reference('rev', commit_id, commit_id)
+ commit = Reference("rev", commit_id, commit_id)
target_repo._local_pull(source_repo.path, commit)
target_repo = MercurialRepository(target_repo.path)
- assert target_repo.branches['default'] == commit_id
+ assert target_repo.branches["default"] == commit_id
commit_id = commits[-3].raw_id
- commit = Reference('rev', commit_id, commit_id)
+ commit = Reference("rev", commit_id, commit_id)
target_repo._local_pull(source_repo.path, commit)
target_repo = MercurialRepository(target_repo.path)
- assert target_repo.branches['default'] == commit_id
+ assert target_repo.branches["default"] == commit_id
def test_local_pull_from_same_repo(self):
- reference = Reference('branch', 'default', None)
+ reference = Reference("branch", "default", None)
with pytest.raises(ValueError):
self.repo._local_pull(self.repo.path, reference)
- def test_validate_pull_reference_raises_on_missing_reference(
- self, vcsbackend_hg):
+ def test_validate_pull_reference_raises_on_missing_reference(self, vcsbackend_hg):
target_repo = vcsbackend_hg.create_repo(number_of_commits=1)
- reference = Reference(
- 'book', 'invalid_reference', 'a' * 40)
+ reference = Reference("book", "invalid_reference", "a" * 40)
with pytest.raises(CommitDoesNotExistError):
target_repo._validate_pull_reference(reference)
@@ -387,51 +385,48 @@ TODO: To be written...
assert set(self.repo._heads()) == set(self.repo.branches.values())
def test_ancestor(self):
- commits = [
- c.raw_id for c in self.repo.get_commits(branch_name='default')]
+ commits = [c.raw_id for c in self.repo.get_commits(branch_name="default")]
assert self.repo._ancestor(commits[-3], commits[-5]) == commits[-5]
assert self.repo._ancestor(commits[-5], commits[-3]) == commits[-5]
def test_local_push(self):
target_repo = self.get_empty_repo()
- revisions = list(self.repo.get_commits(branch_name='default'))
+ revisions = list(self.repo.get_commits(branch_name="default"))
revision = revisions[-5].raw_id
self.repo._local_push(revision, target_repo.path)
target_repo = MercurialRepository(target_repo.path)
- assert target_repo.branches['default'] == revision
+ assert target_repo.branches["default"] == revision
def test_hooks_can_be_enabled_for_local_push(self):
- revision = 'deadbeef'
- repo_path = 'test_group/test_repo'
- with mock.patch.object(self.repo, '_remote') as remote_mock:
+ revision = "deadbeef"
+ repo_path = "test_group/test_repo"
+ with mock.patch.object(self.repo, "_remote") as remote_mock:
self.repo._local_push(revision, repo_path, enable_hooks=True)
- remote_mock.push.assert_called_once_with(
- [revision], repo_path, hooks=True, push_branches=False)
+ remote_mock.push.assert_called_once_with([revision], repo_path, hooks=True, push_branches=False)
def test_local_merge(self, vcsbackend_hg):
target_repo = vcsbackend_hg.create_repo(number_of_commits=1)
source_repo = vcsbackend_hg.clone_repo(target_repo)
- vcsbackend_hg.add_file(target_repo, b'README_MERGE1', b'Version 1')
+ vcsbackend_hg.add_file(target_repo, b"README_MERGE1", b"Version 1")
target_repo = MercurialRepository(target_repo.path)
- target_rev = target_repo.branches['default']
- target_ref = Reference(
- type='branch', name='default', commit_id=target_rev)
- vcsbackend_hg.add_file(source_repo, b'README_MERGE2', b'Version 2')
+ target_rev = target_repo.branches["default"]
+ target_ref = Reference(type="branch", name="default", commit_id=target_rev)
+ vcsbackend_hg.add_file(source_repo, b"README_MERGE2", b"Version 2")
source_repo = MercurialRepository(source_repo.path)
- source_rev = source_repo.branches['default']
- source_ref = Reference(
- type='branch', name='default', commit_id=source_rev)
+ source_rev = source_repo.branches["default"]
+ source_ref = Reference(type="branch", name="default", commit_id=source_rev)
target_repo._local_pull(source_repo.path, source_ref)
- merge_message = 'Merge message\n\nDescription:...'
- user_name = 'Albert Einstein'
- user_email = 'albert@einstein.com'
+ merge_message = "Merge message\n\nDescription:..."
+ user_name = "Albert Einstein"
+ user_email = "albert@einstein.com"
merge_commit_id, needs_push = target_repo._local_merge(
- target_ref, merge_message, user_name, user_email, source_ref)
+ target_ref, merge_message, user_name, user_email, source_ref
+ )
assert needs_push
target_repo = MercurialRepository(target_repo.path)
@@ -439,30 +434,28 @@ TODO: To be written...
assert target_repo.commit_ids[-2] == source_rev
last_commit = target_repo.get_commit(merge_commit_id)
assert last_commit.message.strip() == merge_message
- assert last_commit.author == '%s <%s>' % (user_name, user_email)
+ assert last_commit.author == "%s <%s>" % (user_name, user_email)
- assert not os.path.exists(
- os.path.join(target_repo.path, '.hg', 'merge', 'state'))
+ assert not os.path.exists(os.path.join(target_repo.path, ".hg", "merge", "state"))
def test_local_merge_source_is_fast_forward(self, vcsbackend_hg):
target_repo = vcsbackend_hg.create_repo(number_of_commits=1)
source_repo = vcsbackend_hg.clone_repo(target_repo)
- target_rev = target_repo.branches['default']
- target_ref = Reference(
- type='branch', name='default', commit_id=target_rev)
- vcsbackend_hg.add_file(source_repo, 'README_MERGE2', 'Version 2')
+ target_rev = target_repo.branches["default"]
+ target_ref = Reference(type="branch", name="default", commit_id=target_rev)
+ vcsbackend_hg.add_file(source_repo, "README_MERGE2", "Version 2")
source_repo = MercurialRepository(source_repo.path)
- source_rev = source_repo.branches['default']
- source_ref = Reference(
- type='branch', name='default', commit_id=source_rev)
+ source_rev = source_repo.branches["default"]
+ source_ref = Reference(type="branch", name="default", commit_id=source_rev)
target_repo._local_pull(source_repo.path, source_ref)
- merge_message = 'Merge message\n\nDescription:...'
- user_name = 'Albert Einstein'
- user_email = 'albert@einstein.com'
+ merge_message = "Merge message\n\nDescription:..."
+ user_name = "Albert Einstein"
+ user_email = "albert@einstein.com"
merge_commit_id, needs_push = target_repo._local_merge(
- target_ref, merge_message, user_name, user_email, source_ref)
+ target_ref, merge_message, user_name, user_email, source_ref
+ )
assert merge_commit_id == source_rev
assert needs_push
@@ -470,70 +463,62 @@ TODO: To be written...
assert target_repo.commit_ids[-2] == target_rev
assert target_repo.commit_ids[-1] == source_rev
- assert not os.path.exists(
- os.path.join(target_repo.path, '.hg', 'merge', 'state'))
+ assert not os.path.exists(os.path.join(target_repo.path, ".hg", "merge", "state"))
def test_local_merge_source_is_integrated(self, vcsbackend_hg):
target_repo = vcsbackend_hg.create_repo(number_of_commits=1)
- target_rev = target_repo.branches['default']
- target_ref = Reference(
- type='branch', name='default', commit_id=target_rev)
+ target_rev = target_repo.branches["default"]
+ target_ref = Reference(type="branch", name="default", commit_id=target_rev)
- merge_message = 'Merge message\n\nDescription:...'
- user_name = 'Albert Einstein'
- user_email = 'albert@einstein.com'
+ merge_message = "Merge message\n\nDescription:..."
+ user_name = "Albert Einstein"
+ user_email = "albert@einstein.com"
merge_commit_id, needs_push = target_repo._local_merge(
- target_ref, merge_message, user_name, user_email, target_ref)
+ target_ref, merge_message, user_name, user_email, target_ref
+ )
assert merge_commit_id == target_rev
assert not needs_push
target_repo = MercurialRepository(target_repo.path)
assert target_repo.commit_ids[-1] == target_rev
- assert not os.path.exists(
- os.path.join(target_repo.path, '.hg', 'merge', 'state'))
+ assert not os.path.exists(os.path.join(target_repo.path, ".hg", "merge", "state"))
def test_local_merge_raises_exception_on_conflict(self, vcsbackend_hg):
target_repo = vcsbackend_hg.create_repo(number_of_commits=1)
source_repo = vcsbackend_hg.clone_repo(target_repo)
- vcsbackend_hg.add_file(target_repo, 'README_MERGE', 'Version 1')
+ vcsbackend_hg.add_file(target_repo, "README_MERGE", "Version 1")
target_repo = MercurialRepository(target_repo.path)
- target_rev = target_repo.branches['default']
- target_ref = Reference(
- type='branch', name='default', commit_id=target_rev)
- vcsbackend_hg.add_file(source_repo, 'README_MERGE', 'Version 2')
+ target_rev = target_repo.branches["default"]
+ target_ref = Reference(type="branch", name="default", commit_id=target_rev)
+ vcsbackend_hg.add_file(source_repo, "README_MERGE", "Version 2")
source_repo = MercurialRepository(source_repo.path)
- source_rev = source_repo.branches['default']
- source_ref = Reference(
- type='branch', name='default', commit_id=source_rev)
+ source_rev = source_repo.branches["default"]
+ source_ref = Reference(type="branch", name="default", commit_id=source_rev)
target_repo._local_pull(source_repo.path, source_ref)
with pytest.raises(RepositoryError):
- target_repo._local_merge(
- target_ref, 'merge_message', 'user name', 'user@name.com',
- source_ref)
+ target_repo._local_merge(target_ref, "merge_message", "user name", "user@name.com", source_ref)
# Check we are not left in an intermediate merge state
- assert not os.path.exists(
- os.path.join(target_repo.path, '.hg', 'merge', 'state'))
+ assert not os.path.exists(os.path.join(target_repo.path, ".hg", "merge", "state"))
def test_local_merge_of_two_branches_of_the_same_repo(self, backend_hg):
commits = [
- {'message': 'a'},
- {'message': 'b', 'branch': 'b'},
+ {"message": "a"},
+ {"message": "b", "branch": "b"},
]
repo = backend_hg.create_repo(commits)
commit_ids = backend_hg.commit_ids
- target_ref = Reference(
- type='branch', name='default', commit_id=commit_ids['a'])
- source_ref = Reference(
- type='branch', name='b', commit_id=commit_ids['b'])
- merge_message = 'Merge message\n\nDescription:...'
- user_name = 'Albert Einstein'
- user_email = 'albert@einstein.com'
+ target_ref = Reference(type="branch", name="default", commit_id=commit_ids["a"])
+ source_ref = Reference(type="branch", name="b", commit_id=commit_ids["b"])
+ merge_message = "Merge message\n\nDescription:..."
+ user_name = "Albert Einstein"
+ user_email = "albert@einstein.com"
vcs_repo = repo.scm_instance()
merge_commit_id, needs_push = vcs_repo._local_merge(
- target_ref, merge_message, user_name, user_email, source_ref)
+ target_ref, merge_message, user_name, user_email, source_ref
+ )
assert merge_commit_id != source_ref.commit_id
assert needs_push is True
commit = vcs_repo.get_commit(merge_commit_id)
@@ -541,63 +526,62 @@ TODO: To be written...
assert commit.message == merge_message
def test_maybe_prepare_merge_workspace(self):
- workspace = self.repo._maybe_prepare_merge_workspace(
- 1, 'pr2', 'unused', 'unused2')
+ workspace = self.repo._maybe_prepare_merge_workspace(1, "pr2", "unused", "unused2")
assert os.path.isdir(workspace)
workspace_repo = MercurialRepository(workspace)
assert workspace_repo.branches == self.repo.branches
# Calling it a second time should also succeed
- workspace = self.repo._maybe_prepare_merge_workspace(
- 1, 'pr2', 'unused', 'unused2')
+ workspace = self.repo._maybe_prepare_merge_workspace(1, "pr2", "unused", "unused2")
assert os.path.isdir(workspace)
def test_cleanup_merge_workspace(self):
- workspace = self.repo._maybe_prepare_merge_workspace(
- 1, 'pr3', 'unused', 'unused2')
+ workspace = self.repo._maybe_prepare_merge_workspace(1, "pr3", "unused", "unused2")
assert os.path.isdir(workspace)
- self.repo.cleanup_merge_workspace(1, 'pr3')
+ self.repo.cleanup_merge_workspace(1, "pr3")
assert not os.path.exists(workspace)
def test_cleanup_merge_workspace_invalid_workspace_id(self):
# No assert: because in case of an inexistent workspace this function
# should still succeed.
- self.repo.cleanup_merge_workspace(1, 'pr4')
+ self.repo.cleanup_merge_workspace(1, "pr4")
def test_merge_target_is_bookmark(self, vcsbackend_hg):
target_repo = vcsbackend_hg.create_repo(number_of_commits=1)
source_repo = vcsbackend_hg.clone_repo(target_repo)
- vcsbackend_hg.add_file(target_repo, 'README_MERGE1', 'Version 1')
- vcsbackend_hg.add_file(source_repo, 'README_MERGE2', 'Version 2')
+ vcsbackend_hg.add_file(target_repo, "README_MERGE1", "Version 1")
+ vcsbackend_hg.add_file(source_repo, "README_MERGE2", "Version 2")
imc = source_repo.in_memory_commit
- imc.add(FileNode(b'file_x', content=source_repo.name))
- imc.commit(
- message='Automatic commit from repo merge test',
- author='Automatic ')
+ imc.add(FileNode(b"file_x", content=source_repo.name))
+ imc.commit(message="Automatic commit from repo merge test", author="Automatic ")
target_commit = target_repo.get_commit()
source_commit = source_repo.get_commit()
default_branch = target_repo.DEFAULT_BRANCH_NAME
- bookmark_name = 'bookmark'
+ bookmark_name = "bookmark"
target_repo._update(default_branch)
target_repo.bookmark(bookmark_name)
- target_ref = Reference('book', bookmark_name, target_commit.raw_id)
- source_ref = Reference('branch', default_branch, source_commit.raw_id)
- workspace_id = 'test-merge'
+ target_ref = Reference("book", bookmark_name, target_commit.raw_id)
+ source_ref = Reference("branch", default_branch, source_commit.raw_id)
+ workspace_id = "test-merge"
repo_id = repo_id_generator(target_repo.path)
merge_response = target_repo.merge(
- repo_id, workspace_id, target_ref, source_repo, source_ref,
- 'test user', 'test@rhodecode.com', 'merge message 1',
- dry_run=False)
- expected_merge_response = MergeResponse(
- True, True, merge_response.merge_ref,
- MergeFailureReason.NONE)
+ repo_id,
+ workspace_id,
+ target_ref,
+ source_repo,
+ source_ref,
+ "test user",
+ "test@rhodecode.com",
+ "merge message 1",
+ dry_run=False,
+ )
+ expected_merge_response = MergeResponse(True, True, merge_response.merge_ref, MergeFailureReason.NONE)
assert merge_response == expected_merge_response
- target_repo = backends.get_backend(vcsbackend_hg.alias)(
- target_repo.path)
+ target_repo = backends.get_backend(vcsbackend_hg.alias)(target_repo.path)
target_commits = list(target_repo.get_commits())
commit_ids = [c.raw_id for c in target_commits[:-1]]
assert source_ref.commit_id in commit_ids
@@ -605,43 +589,43 @@ TODO: To be written...
merge_commit = target_commits[-1]
assert merge_commit.raw_id == merge_response.merge_ref.commit_id
- assert merge_commit.message.strip() == 'merge message 1'
- assert merge_commit.author == 'test user '
+ assert merge_commit.message.strip() == "merge message 1"
+ assert merge_commit.author == "test user "
# Check the bookmark was updated in the target repo
- assert (
- target_repo.bookmarks[bookmark_name] ==
- merge_response.merge_ref.commit_id)
+ assert target_repo.bookmarks[bookmark_name] == merge_response.merge_ref.commit_id
def test_merge_source_is_bookmark(self, vcsbackend_hg):
target_repo = vcsbackend_hg.create_repo(number_of_commits=1)
source_repo = vcsbackend_hg.clone_repo(target_repo)
imc = source_repo.in_memory_commit
- imc.add(FileNode(b'file_x', content=source_repo.name))
- imc.commit(
- message='Automatic commit from repo merge test',
- author='Automatic ')
+ imc.add(FileNode(b"file_x", content=source_repo.name))
+ imc.commit(message="Automatic commit from repo merge test", author="Automatic ")
target_commit = target_repo.get_commit()
source_commit = source_repo.get_commit()
default_branch = target_repo.DEFAULT_BRANCH_NAME
- bookmark_name = 'bookmark'
- target_ref = Reference('branch', default_branch, target_commit.raw_id)
+ bookmark_name = "bookmark"
+ target_ref = Reference("branch", default_branch, target_commit.raw_id)
source_repo._update(default_branch)
source_repo.bookmark(bookmark_name)
- source_ref = Reference('book', bookmark_name, source_commit.raw_id)
- workspace_id = 'test-merge'
+ source_ref = Reference("book", bookmark_name, source_commit.raw_id)
+ workspace_id = "test-merge"
repo_id = repo_id_generator(target_repo.path)
merge_response = target_repo.merge(
- repo_id, workspace_id, target_ref, source_repo, source_ref,
- 'test user', 'test@rhodecode.com', 'merge message 1',
- dry_run=False)
- expected_merge_response = MergeResponse(
- True, True, merge_response.merge_ref,
- MergeFailureReason.NONE)
+ repo_id,
+ workspace_id,
+ target_ref,
+ source_repo,
+ source_ref,
+ "test user",
+ "test@rhodecode.com",
+ "merge message 1",
+ dry_run=False,
+ )
+ expected_merge_response = MergeResponse(True, True, merge_response.merge_ref, MergeFailureReason.NONE)
assert merge_response == expected_merge_response
- target_repo = backends.get_backend(vcsbackend_hg.alias)(
- target_repo.path)
+ target_repo = backends.get_backend(vcsbackend_hg.alias)(target_repo.path)
target_commits = list(target_repo.get_commits())
commit_ids = [c.raw_id for c in target_commits]
assert source_ref.commit_id == commit_ids[-1]
@@ -650,78 +634,89 @@ TODO: To be written...
def test_merge_target_has_multiple_heads(self, vcsbackend_hg):
target_repo = vcsbackend_hg.create_repo(number_of_commits=2)
source_repo = vcsbackend_hg.clone_repo(target_repo)
- vcsbackend_hg.add_file(target_repo, 'README_MERGE1', 'Version 1')
- vcsbackend_hg.add_file(source_repo, 'README_MERGE2', 'Version 2')
+ vcsbackend_hg.add_file(target_repo, "README_MERGE1", "Version 1")
+ vcsbackend_hg.add_file(source_repo, "README_MERGE2", "Version 2")
# add an extra head to the target repo
imc = target_repo.in_memory_commit
- imc.add(FileNode(b'file_x', content='foo'))
+ imc.add(FileNode(b"file_x", content="foo"))
commits = list(target_repo.get_commits())
imc.commit(
- message='Automatic commit from repo merge test',
- author='Automatic ', parents=commits[0:1])
+ message="Automatic commit from repo merge test",
+ author="Automatic ",
+ parents=commits[0:1],
+ )
target_commit = target_repo.get_commit()
source_commit = source_repo.get_commit()
default_branch = target_repo.DEFAULT_BRANCH_NAME
target_repo._update(default_branch)
- target_ref = Reference('branch', default_branch, target_commit.raw_id)
- source_ref = Reference('branch', default_branch, source_commit.raw_id)
- workspace_id = 'test-merge'
+ target_ref = Reference("branch", default_branch, target_commit.raw_id)
+ source_ref = Reference("branch", default_branch, source_commit.raw_id)
+ workspace_id = "test-merge"
- assert len(target_repo._heads(branch='default')) == 2
- heads = target_repo._heads(branch='default')
+ assert len(target_repo._heads(branch="default")) == 2
+ heads = target_repo._heads(branch="default")
expected_merge_response = MergeResponse(
- False, False, None,
- MergeFailureReason.HG_TARGET_HAS_MULTIPLE_HEADS,
- metadata={'heads': heads})
+ False, False, None, MergeFailureReason.HG_TARGET_HAS_MULTIPLE_HEADS, metadata={"heads": heads}
+ )
repo_id = repo_id_generator(target_repo.path)
merge_response = target_repo.merge(
- repo_id, workspace_id, target_ref, source_repo, source_ref,
- 'test user', 'test@rhodecode.com', 'merge message 1',
- dry_run=False)
+ repo_id,
+ workspace_id,
+ target_ref,
+ source_repo,
+ source_ref,
+ "test user",
+ "test@rhodecode.com",
+ "merge message 1",
+ dry_run=False,
+ )
assert merge_response == expected_merge_response
def test_merge_rebase_source_is_updated_bookmark(self, vcsbackend_hg):
target_repo = vcsbackend_hg.create_repo(number_of_commits=1)
source_repo = vcsbackend_hg.clone_repo(target_repo)
- vcsbackend_hg.add_file(target_repo, b'README_MERGE1', b'Version 1')
- vcsbackend_hg.add_file(source_repo, b'README_MERGE2', b'Version 2')
+ vcsbackend_hg.add_file(target_repo, b"README_MERGE1", b"Version 1")
+ vcsbackend_hg.add_file(source_repo, b"README_MERGE2", b"Version 2")
imc = source_repo.in_memory_commit
- imc.add(FileNode(b'file_x', content=safe_bytes(source_repo.name)))
- imc.commit(
- message='Automatic commit from repo merge test',
- author='Automatic ')
+ imc.add(FileNode(b"file_x", content=safe_bytes(source_repo.name)))
+ imc.commit(message="Automatic commit from repo merge test", author="Automatic ")
target_commit = target_repo.get_commit()
source_commit = source_repo.get_commit()
- vcsbackend_hg.add_file(source_repo, b'LICENSE', b'LICENSE Info')
+ vcsbackend_hg.add_file(source_repo, b"LICENSE", b"LICENSE Info")
default_branch = target_repo.DEFAULT_BRANCH_NAME
- bookmark_name = 'bookmark'
+ bookmark_name = "bookmark"
source_repo._update(default_branch)
source_repo.bookmark(bookmark_name)
- target_ref = Reference('branch', default_branch, target_commit.raw_id)
- source_ref = Reference('book', bookmark_name, source_commit.raw_id)
+ target_ref = Reference("branch", default_branch, target_commit.raw_id)
+ source_ref = Reference("book", bookmark_name, source_commit.raw_id)
repo_id = repo_id_generator(target_repo.path)
- workspace_id = 'test-merge'
+ workspace_id = "test-merge"
merge_response = target_repo.merge(
- repo_id, workspace_id, target_ref, source_repo, source_ref,
- 'test user', 'test@rhodecode.com', 'merge message 1',
- dry_run=False, use_rebase=True)
+ repo_id,
+ workspace_id,
+ target_ref,
+ source_repo,
+ source_ref,
+ "test user",
+ "test@rhodecode.com",
+ "merge message 1",
+ dry_run=False,
+ use_rebase=True,
+ )
- expected_merge_response = MergeResponse(
- True, True, merge_response.merge_ref,
- MergeFailureReason.NONE)
+ expected_merge_response = MergeResponse(True, True, merge_response.merge_ref, MergeFailureReason.NONE)
assert merge_response == expected_merge_response
- target_repo = backends.get_backend(vcsbackend_hg.alias)(
- target_repo.path)
+ target_repo = backends.get_backend(vcsbackend_hg.alias)(target_repo.path)
last_commit = target_repo.get_commit()
assert last_commit.message == source_commit.message
assert last_commit.author == source_commit.author
@@ -736,27 +731,28 @@ TODO: To be written...
class TestGetShadowInstance(object):
@pytest.fixture()
- def repo(self, vcsbackend_hg, monkeypatch):
- repo = vcsbackend_hg.repo
- monkeypatch.setattr(repo, 'config', mock.Mock())
- monkeypatch.setattr('rhodecode.lib.vcs.connection.Hg', mock.Mock())
- return repo
+ def repo(self, vcsbackend_hg):
+ _hg_repo = vcsbackend_hg.repo
+ connection_mock = mock.Mock(unsafe=True, name="connection.Hg")
+ mock.patch("rhodecode.lib.vcs.connection.Hg", connection_mock)
+ return _hg_repo
- def test_passes_config(self, repo):
+ def test_getting_shadow_instance_copies_config(self, repo):
shadow = repo.get_shadow_instance(repo.path)
- assert shadow.config == repo.config.copy()
+ assert shadow.config.serialize() == repo.config.serialize()
- def test_disables_hooks(self, repo):
+ def test_disables_hooks_section(self, repo):
+ repo.config.set('hooks', 'foo', 'val')
shadow = repo.get_shadow_instance(repo.path)
- shadow.config.clear_section.assert_called_once_with('hooks')
+ assert not shadow.config.items('hooks')
def test_allows_to_keep_hooks(self, repo):
+ repo.config.set('hooks', 'foo', 'val')
shadow = repo.get_shadow_instance(repo.path, enable_hooks=True)
- assert not shadow.config.clear_section.called
+ assert shadow.config.items('hooks')
class TestMercurialCommit(object):
-
def _test_equality(self, commit):
idx = commit.idx
assert commit == self.repo.get_commit(commit_idx=idx)
@@ -768,15 +764,15 @@ class TestMercurialCommit(object):
self._test_equality(commit)
def test_default_commit(self):
- tip = self.repo.get_commit('tip')
+ tip = self.repo.get_commit("tip")
assert tip == self.repo.get_commit()
assert tip == self.repo.get_commit(commit_id=None)
assert tip == self.repo.get_commit(commit_idx=None)
assert tip == list(self.repo[-1:])[0]
def test_root_node(self):
- tip = self.repo.get_commit('tip')
- assert tip.root is tip.get_node('')
+ tip = self.repo.get_commit("tip")
+ assert tip.root is tip.get_node("")
def test_lazy_fetch(self):
"""
@@ -792,44 +788,43 @@ class TestMercurialCommit(object):
# accessing root.nodes updates commit.nodes
assert len(commit.nodes) == 9
- docs = root.get_node('docs')
+ docs = root.get_node("docs")
# we haven't yet accessed anything new as docs dir was already cached
assert len(commit.nodes) == 9
assert len(docs.nodes) == 8
# accessing docs.nodes updates commit.nodes
assert len(commit.nodes) == 17
- assert docs is commit.get_node('docs')
+ assert docs is commit.get_node("docs")
assert docs is root.nodes[0]
assert docs is root.dirs[0]
- assert docs is commit.get_node('docs')
+ assert docs is commit.get_node("docs")
def test_nodes_with_commit(self):
commit = self.repo.get_commit(commit_idx=45)
root = commit.root
- docs = root.get_node('docs')
- assert docs is commit.get_node('docs')
- api = docs.get_node('api')
- assert api is commit.get_node('docs/api')
- index = api.get_node('index.rst')
- assert index is commit.get_node('docs/api/index.rst')
- assert index is commit.get_node(
- 'docs').get_node('api').get_node('index.rst')
+ docs = root.get_node("docs")
+ assert docs is commit.get_node("docs")
+ api = docs.get_node("api")
+ assert api is commit.get_node("docs/api")
+ index = api.get_node("index.rst")
+ assert index is commit.get_node("docs/api/index.rst")
+ assert index is commit.get_node("docs").get_node("api").get_node("index.rst")
def test_branch_and_tags(self):
commit0 = self.repo.get_commit(commit_idx=0)
- assert commit0.branch == 'default'
+ assert commit0.branch == "default"
assert commit0.tags == []
commit10 = self.repo.get_commit(commit_idx=10)
- assert commit10.branch == 'default'
+ assert commit10.branch == "default"
assert commit10.tags == []
commit44 = self.repo.get_commit(commit_idx=44)
- assert commit44.branch == 'web'
+ assert commit44.branch == "web"
- tip = self.repo.get_commit('tip')
- assert 'tip' in tip.tags
+ tip = self.repo.get_commit("tip")
+ assert "tip" in tip.tags
def test_bookmarks(self):
commit0 = self.repo.get_commit(commit_idx=0)
@@ -842,46 +837,84 @@ class TestMercurialCommit(object):
def test_file_size(self):
to_check = (
- (10, 'setup.py', 1068),
- (20, 'setup.py', 1106),
- (60, 'setup.py', 1074),
-
- (10, 'vcs/backends/base.py', 2921),
- (20, 'vcs/backends/base.py', 3936),
- (60, 'vcs/backends/base.py', 6189),
+ (10, "setup.py", 1068),
+ (20, "setup.py", 1106),
+ (60, "setup.py", 1074),
+ (10, "vcs/backends/base.py", 2921),
+ (20, "vcs/backends/base.py", 3936),
+ (60, "vcs/backends/base.py", 6189),
)
for idx, path, size in to_check:
self._test_file_size(idx, path, size)
def test_file_history_from_commits(self):
- node = self.repo[10].get_node('setup.py')
+ node = self.repo[10].get_node("setup.py")
commit_ids = [commit.raw_id for commit in node.history]
- assert ['3803844fdbd3b711175fc3da9bdacfcd6d29a6fb'] == commit_ids
+ assert ["3803844fdbd3b711175fc3da9bdacfcd6d29a6fb"] == commit_ids
- node = self.repo[20].get_node('setup.py')
+ node = self.repo[20].get_node("setup.py")
node_ids = [commit.raw_id for commit in node.history]
- assert ['eada5a770da98ab0dd7325e29d00e0714f228d09',
- '3803844fdbd3b711175fc3da9bdacfcd6d29a6fb'] == node_ids
+ assert ["eada5a770da98ab0dd7325e29d00e0714f228d09", "3803844fdbd3b711175fc3da9bdacfcd6d29a6fb"] == node_ids
# special case we check history from commit that has this particular
# file changed this means we check if it's included as well
- node = self.repo.get_commit('eada5a770da98ab0dd7325e29d00e0714f228d09')\
- .get_node('setup.py')
+ node = self.repo.get_commit("eada5a770da98ab0dd7325e29d00e0714f228d09").get_node("setup.py")
node_ids = [commit.raw_id for commit in node.history]
- assert ['eada5a770da98ab0dd7325e29d00e0714f228d09',
- '3803844fdbd3b711175fc3da9bdacfcd6d29a6fb'] == node_ids
+ assert ["eada5a770da98ab0dd7325e29d00e0714f228d09", "3803844fdbd3b711175fc3da9bdacfcd6d29a6fb"] == node_ids
def test_file_history(self):
# we can only check if those commits are present in the history
# as we cannot update this test every time file is changed
files = {
- 'setup.py': [7, 18, 45, 46, 47, 69, 77],
- 'vcs/nodes.py': [
- 7, 8, 24, 26, 30, 45, 47, 49, 56, 57, 58, 59, 60, 61, 73, 76],
- 'vcs/backends/hg.py': [
- 4, 5, 6, 11, 12, 13, 14, 15, 16, 21, 22, 23, 26, 27, 28, 30,
- 31, 33, 35, 36, 37, 38, 39, 40, 41, 44, 45, 47, 48, 49, 53, 54,
- 55, 58, 60, 61, 67, 68, 69, 70, 73, 77, 78, 79, 82],
+ "setup.py": [7, 18, 45, 46, 47, 69, 77],
+ "vcs/nodes.py": [7, 8, 24, 26, 30, 45, 47, 49, 56, 57, 58, 59, 60, 61, 73, 76],
+ "vcs/backends/hg.py": [
+ 4,
+ 5,
+ 6,
+ 11,
+ 12,
+ 13,
+ 14,
+ 15,
+ 16,
+ 21,
+ 22,
+ 23,
+ 26,
+ 27,
+ 28,
+ 30,
+ 31,
+ 33,
+ 35,
+ 36,
+ 37,
+ 38,
+ 39,
+ 40,
+ 41,
+ 44,
+ 45,
+ 47,
+ 48,
+ 49,
+ 53,
+ 54,
+ 55,
+ 58,
+ 60,
+ 61,
+ 67,
+ 68,
+ 69,
+ 70,
+ 73,
+ 77,
+ 78,
+ 79,
+ 82,
+ ],
}
for path, indexes in files.items():
tip = self.repo.get_commit(commit_idx=indexes[-1])
@@ -889,72 +922,105 @@ class TestMercurialCommit(object):
node_indexes = [commit.idx for commit in node.history]
assert set(indexes).issubset(set(node_indexes)), (
"We assumed that %s is subset of commits for which file %s "
- "has been changed, and history of that node returned: %s"
- % (indexes, path, node_indexes))
+ "has been changed, and history of that node returned: %s" % (indexes, path, node_indexes)
+ )
def test_file_annotate(self):
files = {
- 'vcs/backends/__init__.py': {
+ "vcs/backends/__init__.py": {
89: {
- 'lines_no': 31,
- 'commits': [
- 32, 32, 61, 32, 32, 37, 32, 32, 32, 44,
- 37, 37, 37, 37, 45, 37, 44, 37, 37, 37,
- 32, 32, 32, 32, 37, 32, 37, 37, 32,
- 32, 32
- ]
- },
- 20: {
- 'lines_no': 1,
- 'commits': [4]
+ "lines_no": 31,
+ "commits": [
+ 32,
+ 32,
+ 61,
+ 32,
+ 32,
+ 37,
+ 32,
+ 32,
+ 32,
+ 44,
+ 37,
+ 37,
+ 37,
+ 37,
+ 45,
+ 37,
+ 44,
+ 37,
+ 37,
+ 37,
+ 32,
+ 32,
+ 32,
+ 32,
+ 37,
+ 32,
+ 37,
+ 37,
+ 32,
+ 32,
+ 32,
+ ],
},
+ 20: {"lines_no": 1, "commits": [4]},
55: {
- 'lines_no': 31,
- 'commits': [
- 32, 32, 45, 32, 32, 37, 32, 32, 32, 44,
- 37, 37, 37, 37, 45, 37, 44, 37, 37, 37,
- 32, 32, 32, 32, 37, 32, 37, 37, 32,
- 32, 32
- ]
- }
+ "lines_no": 31,
+ "commits": [
+ 32,
+ 32,
+ 45,
+ 32,
+ 32,
+ 37,
+ 32,
+ 32,
+ 32,
+ 44,
+ 37,
+ 37,
+ 37,
+ 37,
+ 45,
+ 37,
+ 44,
+ 37,
+ 37,
+ 37,
+ 32,
+ 32,
+ 32,
+ 32,
+ 37,
+ 32,
+ 37,
+ 37,
+ 32,
+ 32,
+ 32,
+ ],
+ },
},
- 'vcs/exceptions.py': {
+ "vcs/exceptions.py": {
89: {
- 'lines_no': 18,
- 'commits': [
- 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
- 16, 16, 17, 16, 16, 18, 18, 18
- ]
+ "lines_no": 18,
+ "commits": [16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 16, 16, 18, 18, 18],
},
20: {
- 'lines_no': 18,
- 'commits': [
- 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
- 16, 16, 17, 16, 16, 18, 18, 18
- ]
+ "lines_no": 18,
+ "commits": [16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 16, 16, 18, 18, 18],
},
55: {
- 'lines_no': 18,
- 'commits': [
- 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
- 17, 16, 16, 18, 18, 18
- ]
- }
+ "lines_no": 18,
+ "commits": [16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 16, 16, 18, 18, 18],
+ },
+ },
+ "MANIFEST.in": {
+ 89: {"lines_no": 5, "commits": [7, 7, 7, 71, 71]},
+ 20: {"lines_no": 3, "commits": [7, 7, 7]},
+ 55: {"lines_no": 3, "commits": [7, 7, 7]},
},
- 'MANIFEST.in': {
- 89: {
- 'lines_no': 5,
- 'commits': [7, 7, 7, 71, 71]
- },
- 20: {
- 'lines_no': 3,
- 'commits': [7, 7, 7]
- },
- 55: {
- 'lines_no': 3,
- 'commits': [7, 7, 7]
- }
- }
}
for fname, commit_dict in files.items():
@@ -963,13 +1029,13 @@ class TestMercurialCommit(object):
l1_1 = [x[1] for x in commit.get_file_annotate(fname)]
l1_2 = [x[2]().raw_id for x in commit.get_file_annotate(fname)]
assert l1_1 == l1_2
- l1 = l1_2 = [
- x[2]().idx for x in commit.get_file_annotate(fname)]
- l2 = files[fname][idx]['commits']
+ l1 = l1_2 = [x[2]().idx for x in commit.get_file_annotate(fname)]
+ l2 = files[fname][idx]["commits"]
assert l1 == l2, (
"The lists of commit for %s@commit_id%s"
"from annotation list should match each other,"
- "got \n%s \nvs \n%s " % (fname, idx, l1, l2))
+ "got \n%s \nvs \n%s " % (fname, idx, l1, l2)
+ )
def test_commit_state(self):
"""
@@ -981,28 +1047,52 @@ class TestMercurialCommit(object):
# changed: 13
# added: 20
# removed: 1
- changed = set([
- '.hgignore', 'README.rst', 'docs/conf.py', 'docs/index.rst',
- 'setup.py', 'tests/test_hg.py', 'tests/test_nodes.py',
- 'vcs/__init__.py', 'vcs/backends/__init__.py',
- 'vcs/backends/base.py', 'vcs/backends/hg.py', 'vcs/nodes.py',
- 'vcs/utils/__init__.py'])
+ changed = set(
+ [
+ ".hgignore",
+ "README.rst",
+ "docs/conf.py",
+ "docs/index.rst",
+ "setup.py",
+ "tests/test_hg.py",
+ "tests/test_nodes.py",
+ "vcs/__init__.py",
+ "vcs/backends/__init__.py",
+ "vcs/backends/base.py",
+ "vcs/backends/hg.py",
+ "vcs/nodes.py",
+ "vcs/utils/__init__.py",
+ ]
+ )
- added = set([
- 'docs/api/backends/hg.rst', 'docs/api/backends/index.rst',
- 'docs/api/index.rst', 'docs/api/nodes.rst',
- 'docs/api/web/index.rst', 'docs/api/web/simplevcs.rst',
- 'docs/installation.rst', 'docs/quickstart.rst', 'setup.cfg',
- 'vcs/utils/baseui_config.py', 'vcs/utils/web.py',
- 'vcs/web/__init__.py', 'vcs/web/exceptions.py',
- 'vcs/web/simplevcs/__init__.py', 'vcs/web/simplevcs/exceptions.py',
- 'vcs/web/simplevcs/middleware.py', 'vcs/web/simplevcs/models.py',
- 'vcs/web/simplevcs/settings.py', 'vcs/web/simplevcs/utils.py',
- 'vcs/web/simplevcs/views.py'])
+ added = set(
+ [
+ "docs/api/backends/hg.rst",
+ "docs/api/backends/index.rst",
+ "docs/api/index.rst",
+ "docs/api/nodes.rst",
+ "docs/api/web/index.rst",
+ "docs/api/web/simplevcs.rst",
+ "docs/installation.rst",
+ "docs/quickstart.rst",
+ "setup.cfg",
+ "vcs/utils/baseui_config.py",
+ "vcs/utils/web.py",
+ "vcs/web/__init__.py",
+ "vcs/web/exceptions.py",
+ "vcs/web/simplevcs/__init__.py",
+ "vcs/web/simplevcs/exceptions.py",
+ "vcs/web/simplevcs/middleware.py",
+ "vcs/web/simplevcs/models.py",
+ "vcs/web/simplevcs/settings.py",
+ "vcs/web/simplevcs/utils.py",
+ "vcs/web/simplevcs/views.py",
+ ]
+ )
- removed = set(['docs/api.rst'])
+ removed = set(["docs/api.rst"])
- commit64 = self.repo.get_commit('46ad32a4f974')
+ commit64 = self.repo.get_commit("46ad32a4f974")
assert set((node.path for node in commit64.added)) == added
assert set((node.path for node in commit64.changed)) == changed
assert set((node.path for node in commit64.removed)) == removed
@@ -1012,10 +1102,9 @@ class TestMercurialCommit(object):
# changed: 13
# added: 20
# removed: 1
- commit88 = self.repo.get_commit('b090f22d27d6')
+ commit88 = self.repo.get_commit("b090f22d27d6")
assert set((node.path for node in commit88.added)) == set()
- assert set((node.path for node in commit88.changed)) == \
- set(['.hgignore'])
+ assert set((node.path for node in commit88.changed)) == set([".hgignore"])
assert set((node.path for node in commit88.removed)) == set()
#
@@ -1025,24 +1114,25 @@ class TestMercurialCommit(object):
# changed: 4 ['vcs/web/simplevcs/models.py', ...]
# removed: 1 ['vcs/utils/web.py']
commit85 = self.repo.get_commit(commit_idx=85)
- assert set((node.path for node in commit85.added)) == set([
- 'vcs/utils/diffs.py',
- 'vcs/web/simplevcs/views/diffs.py'])
- assert set((node.path for node in commit85.changed)) == set([
- 'vcs/web/simplevcs/models.py',
- 'vcs/web/simplevcs/utils.py',
- 'vcs/web/simplevcs/views/__init__.py',
- 'vcs/web/simplevcs/views/repository.py',
- ])
- assert set((node.path for node in commit85.removed)) == \
- set(['vcs/utils/web.py'])
+ assert set((node.path for node in commit85.added)) == set(
+ ["vcs/utils/diffs.py", "vcs/web/simplevcs/views/diffs.py"]
+ )
+ assert set((node.path for node in commit85.changed)) == set(
+ [
+ "vcs/web/simplevcs/models.py",
+ "vcs/web/simplevcs/utils.py",
+ "vcs/web/simplevcs/views/__init__.py",
+ "vcs/web/simplevcs/views/repository.py",
+ ]
+ )
+ assert set((node.path for node in commit85.removed)) == set(["vcs/utils/web.py"])
def test_files_state(self):
"""
Tests state of FileNodes.
"""
commit = self.repo.get_commit(commit_idx=85)
- node = commit.get_node('vcs/utils/diffs.py')
+ node = commit.get_node("vcs/utils/diffs.py")
assert node.state, NodeState.ADDED
assert node.added
assert not node.changed
@@ -1050,7 +1140,7 @@ class TestMercurialCommit(object):
assert not node.removed
commit = self.repo.get_commit(commit_idx=88)
- node = commit.get_node('.hgignore')
+ node = commit.get_node(".hgignore")
assert node.state, NodeState.CHANGED
assert not node.added
assert node.changed
@@ -1058,7 +1148,7 @@ class TestMercurialCommit(object):
assert not node.removed
commit = self.repo.get_commit(commit_idx=85)
- node = commit.get_node('setup.py')
+ node = commit.get_node("setup.py")
assert node.state, NodeState.NOT_CHANGED
assert not node.added
assert not node.changed
@@ -1068,7 +1158,7 @@ class TestMercurialCommit(object):
# If node has REMOVED state then trying to fetch it would raise
# CommitError exception
commit = self.repo.get_commit(commit_idx=2)
- path = 'vcs/backends/BaseRepository.py'
+ path = "vcs/backends/BaseRepository.py"
with pytest.raises(NodeDoesNotExistError):
commit.get_node(path)
# but it would be one of ``removed`` (commit's attribute)
@@ -1084,57 +1174,53 @@ class TestMercurialCommit(object):
def test_repo_files_content_type(self):
test_commit = self.repo.get_commit(commit_idx=100)
- for node in test_commit.get_node('/'):
+ for node in test_commit.get_node("/"):
if node.is_file():
assert type(node.content) == bytes
assert type(node.str_content) == str
def test_wrong_path(self):
# There is 'setup.py' in the root dir but not there:
- path = 'foo/bar/setup.py'
+ path = "foo/bar/setup.py"
with pytest.raises(VCSError):
self.repo.get_commit().get_node(path)
def test_author_email(self):
- assert 'marcin@python-blog.com' == \
- self.repo.get_commit('b986218ba1c9').author_email
- assert 'lukasz.balcerzak@python-center.pl' == \
- self.repo.get_commit('3803844fdbd3').author_email
- assert '' == self.repo.get_commit('84478366594b').author_email
+ assert "marcin@python-blog.com" == self.repo.get_commit("b986218ba1c9").author_email
+ assert "lukasz.balcerzak@python-center.pl" == self.repo.get_commit("3803844fdbd3").author_email
+ assert "" == self.repo.get_commit("84478366594b").author_email
def test_author_username(self):
- assert 'Marcin Kuzminski' == \
- self.repo.get_commit('b986218ba1c9').author_name
- assert 'Lukasz Balcerzak' == \
- self.repo.get_commit('3803844fdbd3').author_name
- assert 'marcink' == \
- self.repo.get_commit('84478366594b').author_name
+ assert "Marcin Kuzminski" == self.repo.get_commit("b986218ba1c9").author_name
+ assert "Lukasz Balcerzak" == self.repo.get_commit("3803844fdbd3").author_name
+ assert "marcink" == self.repo.get_commit("84478366594b").author_name
class TestLargeFileRepo(object):
-
def test_large_file(self, backend_hg):
- repo = backend_hg.create_test_repo('largefiles', make_db_config())
+ conf = make_db_config()
+ hg_largefiles_store = conf.get("largefiles", "usercache")
+ repo = backend_hg.create_test_repo("largefiles", conf)
tip = repo.scm_instance().get_commit()
- node = tip.get_node('.hglf/thisfileislarge')
+ node = tip.get_node(".hglf/thisfileislarge")
lf_node = node.get_largefile_node()
assert lf_node.is_largefile() is True
assert lf_node.size == 1024000
- assert lf_node.name == '.hglf/thisfileislarge'
+ assert lf_node.name == ".hglf/thisfileislarge"
class TestGetBranchName(object):
def test_returns_ref_name_when_type_is_branch(self):
- ref = self._create_ref('branch', 'fake-name')
+ ref = self._create_ref("branch", "fake-name")
result = self.repo._get_branch_name(ref)
assert result == ref.name
@pytest.mark.parametrize("type_", ("book", "tag"))
def test_queries_remote_when_type_is_not_branch(self, type_):
- ref = self._create_ref(type_, 'wrong-fake-name')
+ ref = self._create_ref(type_, "wrong-fake-name")
with mock.patch.object(self.repo, "_remote") as remote_mock:
remote_mock.ctx_branch.return_value = "fake-name"
result = self.repo._get_branch_name(ref)
@@ -1144,7 +1230,7 @@ class TestGetBranchName(object):
def _create_ref(self, type_, name):
ref = mock.Mock()
ref.type = type_
- ref.name = 'wrong-fake-name'
+ ref.name = "wrong-fake-name"
ref.commit_id = "deadbeef"
return ref
@@ -1153,8 +1239,7 @@ class TestIsTheSameBranch(object):
def test_returns_true_when_branches_are_equal(self):
source_ref = mock.Mock(name="source-ref")
target_ref = mock.Mock(name="target-ref")
- branch_name_patcher = mock.patch.object(
- self.repo, "_get_branch_name", return_value="default")
+ branch_name_patcher = mock.patch.object(self.repo, "_get_branch_name", return_value="default")
with branch_name_patcher as branch_name_mock:
result = self.repo._is_the_same_branch(source_ref, target_ref)
@@ -1171,8 +1256,7 @@ class TestIsTheSameBranch(object):
def side_effect(ref):
return ref.name
- branch_name_patcher = mock.patch.object(
- self.repo, "_get_branch_name", side_effect=side_effect)
+ branch_name_patcher = mock.patch.object(self.repo, "_get_branch_name", side_effect=side_effect)
with branch_name_patcher as branch_name_mock:
result = self.repo._is_the_same_branch(source_ref, target_ref)
diff --git a/rhodecode/tests/vcs/test_hg_vcsserver_cache_invalidation.py b/rhodecode/tests/vcs/test_hg_vcsserver_cache_invalidation.py
index d5868e5c..c6b5f522 100644
--- a/rhodecode/tests/vcs/test_hg_vcsserver_cache_invalidation.py
+++ b/rhodecode/tests/vcs/test_hg_vcsserver_cache_invalidation.py
@@ -1,5 +1,3 @@
-
-
# Copyright (C) 2016-2023 RhodeCode GmbH
#
# This program is free software: you can redistribute it and/or modify
@@ -35,45 +33,47 @@ class TestMercurialRemoteRepoInvalidation(object):
"""
# Default reference used as a dummy during tests.
- default_ref = Reference('branch', 'default', None)
+ default_ref = Reference("branch", "default", None)
# Methods of vcsserver.hg.HgRemote that are "writing" operations.
writing_methods = [
- 'bookmark',
- 'commit',
- 'merge',
- 'pull',
- 'pull_cmd',
- 'rebase',
- 'strip',
- 'tag',
+ "bookmark",
+ "commit",
+ "merge",
+ "pull",
+ "pull_cmd",
+ "rebase",
+ "strip",
+ "tag",
]
- @pytest.mark.parametrize('method_name, method_args', [
- ('_local_merge', [default_ref, None, None, None, default_ref]),
- ('_local_pull', ['', default_ref]),
- ('bookmark', [None]),
- ('pull', ['', default_ref]),
- ('remove_tag', ['mytag', None]),
- ('strip', [None]),
- ('tag', ['newtag', None]),
- ])
- def test_method_invokes_invalidate_on_remote_repo(
- self, method_name, method_args, backend_hg):
+ @pytest.mark.parametrize(
+ "method_name, method_args",
+ [
+ ("_local_merge", [default_ref, None, None, None, default_ref]),
+ ("_local_pull", ["", default_ref]),
+ ("bookmark", [None]),
+ ("pull", ["", default_ref]),
+ ("remove_tag", ["mytag", None]),
+ ("strip", [None]),
+ ("tag", ["newtag", None]),
+ ],
+ )
+ def test_method_invokes_invalidate_on_remote_repo(self, method_name, method_args, backend_hg):
"""
Check that the listed methods are invalidating the VCSServer cache
after invoking a writing method of their remote repository object.
"""
- tags = {'mytag': 'mytag-id'}
+ tags = {"mytag": "mytag-id"}
def add_tag(name, raw_id, *args, **kwds):
tags[name] = raw_id
repo = backend_hg.repo.scm_instance()
- with patch.object(repo, '_remote') as remote:
+ with patch.object(repo, "_remote") as remote:
repo.tags = tags
- remote.lookup.return_value = ('commit-id', 'commit-idx')
+ remote.lookup.return_value = ("commit-id", "commit-idx")
remote.tags.return_value = tags
remote._get_tags.return_value = tags
remote.is_empty.return_value = False
@@ -98,6 +98,7 @@ class TestMercurialRemoteRepoInvalidation(object):
references.
"""
from rhodecode.model.pull_request import PullRequestModel
+
repo_id = pull_request.target_repo.repo_id
target_vcs = pull_request.target_repo.scm_instance()
target_ref = pull_request.target_ref_parts
@@ -107,7 +108,8 @@ class TestMercurialRemoteRepoInvalidation(object):
pr = PullRequestModel()
workspace_id = pr._workspace_id(pull_request)
shadow_repository_path = target_vcs._maybe_prepare_merge_workspace(
- repo_id, workspace_id, target_ref, source_ref)
+ repo_id, workspace_id, target_ref, source_ref
+ )
shadow_repo = target_vcs.get_shadow_instance(shadow_repository_path, cache=True)
# This will populate the cache of the mercurial repository object
@@ -116,7 +118,7 @@ class TestMercurialRemoteRepoInvalidation(object):
return shadow_repo, source_ref, target_ref
- @pytest.mark.backends('hg')
+ @pytest.mark.backends("hg")
def test_commit_does_not_exist_error_happens(self, pr_util, app):
"""
This test is somewhat special. It does not really test the system
@@ -132,18 +134,18 @@ class TestMercurialRemoteRepoInvalidation(object):
source_vcs = pull_request.source_repo.scm_instance()
shadow_repo, source_ref, target_ref = self._prepare_shadow_repo(pull_request)
- initial_cache_uid = shadow_repo._remote._wire['context']
- initial_commit_ids = shadow_repo._remote.get_all_commit_ids('visible')
+ initial_cache_uid = shadow_repo._remote._wire["context"]
+ initial_commit_ids = shadow_repo._remote.get_all_commit_ids("visible")
# Pull from target and source references but without invalidation of
# RemoteRepo objects and without VCSServer caching of mercurial repository objects.
- with patch.object(shadow_repo._remote, 'invalidate_vcs_cache'):
+ with patch.object(shadow_repo._remote, "invalidate_vcs_cache"):
# NOTE: Do not use patch.dict() to disable the cache because it
# restores the WHOLE dict and not only the patched keys.
- shadow_repo._remote._wire['cache'] = False
+ shadow_repo._remote._wire["cache"] = False
shadow_repo._local_pull(target_vcs.path, target_ref)
shadow_repo._local_pull(source_vcs.path, source_ref)
- shadow_repo._remote._wire['cache'] = True
+ shadow_repo._remote._wire["cache"] = True
# Try to lookup the target_ref in shadow repo. This should work because
# test_repo_maker_uses_session_for_instance_methods
@@ -153,14 +155,14 @@ class TestMercurialRemoteRepoInvalidation(object):
# we ensure that call context has not changed, this is what
# `invalidate_vcs_cache` does
- assert initial_cache_uid == shadow_repo._remote._wire['context']
+ assert initial_cache_uid == shadow_repo._remote._wire["context"]
# If we try to lookup all commits.
# repo commit cache doesn't get invalidated. (Due to patched
# invalidation and caching above).
- assert initial_commit_ids == shadow_repo._remote.get_all_commit_ids('visible')
+ assert initial_commit_ids == shadow_repo._remote.get_all_commit_ids("visible")
- @pytest.mark.backends('hg')
+ @pytest.mark.backends("hg")
def test_commit_does_not_exist_error_does_not_happen(self, pr_util, app):
"""
This test simulates a pull request merge in which the pull operations
@@ -179,10 +181,10 @@ class TestMercurialRemoteRepoInvalidation(object):
# of RemoteRepo objects.
# NOTE: Do not use patch.dict() to disable the cache because it
# restores the WHOLE dict and not only the patched keys.
- shadow_repo._remote._wire['cache'] = False
+ shadow_repo._remote._wire["cache"] = False
shadow_repo._local_pull(target_vcs.path, target_ref)
shadow_repo._local_pull(source_vcs.path, source_ref)
- shadow_repo._remote._wire['cache'] = True
+ shadow_repo._remote._wire["cache"] = True
# Try to lookup the target and source references in shadow repo. This
# should work because the RemoteRepo object gets invalidated during the
diff --git a/rhodecode/tests/vcs/test_inmemory.py b/rhodecode/tests/vcs/test_inmemory.py
index 632d0638..e28bed33 100644
--- a/rhodecode/tests/vcs/test_inmemory.py
+++ b/rhodecode/tests/vcs/test_inmemory.py
@@ -1,4 +1,3 @@
-
# Copyright (C) 2010-2023 RhodeCode GmbH
#
# This program is free software: you can redistribute it and/or modify
@@ -20,15 +19,21 @@
"""
Tests so called "in memory commits" commit API of vcs.
"""
+
import datetime
import pytest
from rhodecode.lib.str_utils import safe_bytes, safe_str
from rhodecode.lib.vcs.exceptions import (
- EmptyRepositoryError, NodeAlreadyAddedError, NodeAlreadyExistsError,
- NodeAlreadyRemovedError, NodeAlreadyChangedError, NodeDoesNotExistError,
- NodeNotChangedError)
+ EmptyRepositoryError,
+ NodeAlreadyAddedError,
+ NodeAlreadyExistsError,
+ NodeAlreadyRemovedError,
+ NodeAlreadyChangedError,
+ NodeDoesNotExistError,
+ NodeNotChangedError,
+)
from rhodecode.lib.vcs.nodes import DirNode, FileNode
from rhodecode.tests.vcs.conftest import BackendTestMixin
@@ -36,19 +41,21 @@ from rhodecode.tests.vcs.conftest import BackendTestMixin
@pytest.fixture()
def nodes():
nodes = [
- FileNode(b'foobar', content=b'Foo & bar'),
- FileNode(b'foobar2', content=b'Foo & bar, doubled!'),
- FileNode(b'foo bar with spaces', content=b''),
- FileNode(b'foo/bar/baz', content=b'Inside'),
- FileNode(b'foo/bar/file.bin', content=(
- b'\xd0\xcf\x11\xe0\xa1\xb1\x1a\xe1\x00\x00\x00\x00\x00\x00'
- b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00;\x00\x03\x00\xfe'
- b'\xff\t\x00\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
- b'\x01\x00\x00\x00\x1a\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00'
- b'\x00\x18\x00\x00\x00\x01\x00\x00\x00\xfe\xff\xff\xff\x00\x00'
- b'\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff'
- b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'
- )
+ FileNode(b"foobar", content=b"Foo & bar"),
+ FileNode(b"foobar2", content=b"Foo & bar, doubled!"),
+ FileNode(b"foo bar with spaces", content=b""),
+ FileNode(b"foo/bar/baz", content=b"Inside"),
+ FileNode(
+ b"foo/bar/file.bin",
+ content=(
+ b"\xd0\xcf\x11\xe0\xa1\xb1\x1a\xe1\x00\x00\x00\x00\x00\x00"
+ b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00;\x00\x03\x00\xfe"
+ b"\xff\t\x00\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ b"\x01\x00\x00\x00\x1a\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00"
+ b"\x00\x18\x00\x00\x00\x01\x00\x00\x00\xfe\xff\xff\xff\x00\x00"
+ b"\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff"
+ b"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
+ ),
),
]
return nodes
@@ -80,14 +87,14 @@ class TestInMemoryCommit(BackendTestMixin):
def test_add_on_branch_hg(self, nodes):
for node in nodes:
self.imc.add(node)
- self.commit(branch='stable')
+ self.commit(branch="stable")
self.assert_successful_commit(nodes)
@pytest.mark.backends("git")
def test_add_on_branch_git(self, nodes):
for node in nodes:
self.imc.add(node)
- self.commit(branch='stable')
+ self.commit(branch="stable")
self.assert_successful_commit(nodes)
def test_add_in_bulk(self, nodes):
@@ -98,10 +105,8 @@ class TestInMemoryCommit(BackendTestMixin):
def test_add_non_ascii_files(self):
nodes = [
- FileNode(safe_bytes('żółwik/zwierzątko_utf8_str'),
- content=safe_bytes('ćććć')),
- FileNode(safe_bytes('żółwik/zwierzątko_unicode'),
- content=safe_bytes('ćććć')),
+ FileNode(safe_bytes("żółwik/zwierzątko_utf8_str"), content=safe_bytes("ćććć")),
+ FileNode(safe_bytes("żółwik/zwierzątko_unicode"), content=safe_bytes("ćććć")),
]
for node in nodes:
@@ -112,60 +117,56 @@ class TestInMemoryCommit(BackendTestMixin):
def commit(self, branch=None):
self.old_commit_count = len(self.repo.commit_ids)
- self.commit_message = 'Test commit with unicode: żółwik'
- self.commit_author = f'{self.__class__.__name__} '
- self.commit = self.imc.commit(
- message=self.commit_message, author=self.commit_author,
- branch=branch)
+ self.commit_message = "Test commit with unicode: żółwik"
+ self.commit_author = f"{self.__class__.__name__} "
+ self.commit = self.imc.commit(message=self.commit_message, author=self.commit_author, branch=branch)
def test_add_actually_adds_all_nodes_at_second_commit_too(self):
to_add = [
- FileNode(b'foo/bar/image.png', content=b'\0'),
- FileNode(b'foo/README.txt', content=b'readme!'),
+ FileNode(b"foo/bar/image.png", content=b"\0"),
+ FileNode(b"foo/README.txt", content=b"readme!"),
]
self.imc.add(*to_add)
- commit = self.imc.commit('Initial', 'joe doe ')
- assert isinstance(commit.get_node('foo'), DirNode)
- assert isinstance(commit.get_node('foo/bar'), DirNode)
+ commit = self.imc.commit("Initial", "joe doe ")
+ assert isinstance(commit.get_node("foo"), DirNode)
+ assert isinstance(commit.get_node("foo/bar"), DirNode)
self.assert_nodes_in_commit(commit, to_add)
# commit some more files again
to_add = [
- FileNode(b'foo/bar/foobaz/bar', content=b'foo'),
- FileNode(b'foo/bar/another/bar', content=b'foo'),
- FileNode(b'foo/baz.txt', content=b'foo'),
- FileNode(b'foobar/foobaz/file', content=b'foo'),
- FileNode(b'foobar/barbaz', content=b'foo'),
+ FileNode(b"foo/bar/foobaz/bar", content=b"foo"),
+ FileNode(b"foo/bar/another/bar", content=b"foo"),
+ FileNode(b"foo/baz.txt", content=b"foo"),
+ FileNode(b"foobar/foobaz/file", content=b"foo"),
+ FileNode(b"foobar/barbaz", content=b"foo"),
]
self.imc.add(*to_add)
- commit = self.imc.commit('Another', 'joe doe ')
+ commit = self.imc.commit("Another", "joe doe ")
self.assert_nodes_in_commit(commit, to_add)
def test_add_raise_already_added(self):
- node = FileNode(b'foobar', content=b'baz')
+ node = FileNode(b"foobar", content=b"baz")
self.imc.add(node)
with pytest.raises(NodeAlreadyAddedError):
self.imc.add(node)
def test_check_integrity_raise_already_exist(self):
- node = FileNode(b'foobar', content=b'baz')
+ node = FileNode(b"foobar", content=b"baz")
self.imc.add(node)
- self.imc.commit(message='Added foobar',
- author='Some Name ')
+ self.imc.commit(message="Added foobar", author="Some Name ")
self.imc.add(node)
with pytest.raises(NodeAlreadyExistsError):
- self.imc.commit(message='new message',
- author='Some Name ')
+ self.imc.commit(message="new message", author="Some Name ")
def test_change(self):
- self.imc.add(FileNode(b'foo/bar/baz', content=b'foo'))
- self.imc.add(FileNode(b'foo/fbar', content=b'foobar'))
- tip = self.imc.commit('Initial', 'joe doe ')
+ self.imc.add(FileNode(b"foo/bar/baz", content=b"foo"))
+ self.imc.add(FileNode(b"foo/fbar", content=b"foobar"))
+ tip = self.imc.commit("Initial", "joe doe ")
# Change node's content
- node = FileNode(b'foo/bar/baz', content=b'My **changed** content')
+ node = FileNode(b"foo/bar/baz", content=b"My **changed** content")
self.imc.change(node)
- self.imc.commit('Changed %s' % node.path, 'joe doe ')
+ self.imc.commit("Changed %s" % node.path, "joe doe ")
newtip = self.repo.get_commit()
assert tip != newtip
@@ -174,28 +175,22 @@ class TestInMemoryCommit(BackendTestMixin):
def test_change_non_ascii(self):
to_add = [
- FileNode(safe_bytes('żółwik/zwierzątko'),
- content=safe_bytes('ćććć')),
- FileNode(safe_bytes('żółwik/zwierzątko_uni'),
- content=safe_bytes('ćććć')),
+ FileNode(safe_bytes("żółwik/zwierzątko"), content=safe_bytes("ćććć")),
+ FileNode(safe_bytes("żółwik/zwierzątko_uni"), content=safe_bytes("ćććć")),
]
for node in to_add:
self.imc.add(node)
- tip = self.imc.commit('Initial', 'joe doe ')
+ tip = self.imc.commit("Initial", "joe doe ")
# Change node's content
- node = FileNode(safe_bytes('żółwik/zwierzątko'),
- content=b'My **changed** content')
+ node = FileNode(safe_bytes("żółwik/zwierzątko"), content=b"My **changed** content")
self.imc.change(node)
- self.imc.commit('Changed %s' % safe_str(node.path),
- author='joe doe ')
+ self.imc.commit("Changed %s" % safe_str(node.path), author="joe doe ")
- node_uni = FileNode(safe_bytes('żółwik/zwierzątko_uni'),
- content=b'My **changed** content')
+ node_uni = FileNode(safe_bytes("żółwik/zwierzątko_uni"), content=b"My **changed** content")
self.imc.change(node_uni)
- self.imc.commit('Changed %s' % safe_str(node_uni.path),
- author='joe doe ')
+ self.imc.commit("Changed %s" % safe_str(node_uni.path), author="joe doe ")
newtip = self.repo.get_commit()
assert tip != newtip
@@ -204,24 +199,24 @@ class TestInMemoryCommit(BackendTestMixin):
self.assert_nodes_in_commit(newtip, (node, node_uni))
def test_change_raise_empty_repository(self):
- node = FileNode(b'foobar')
+ node = FileNode(b"foobar")
with pytest.raises(EmptyRepositoryError):
self.imc.change(node)
def test_check_integrity_change_raise_node_does_not_exist(self):
- node = FileNode(b'foobar', content=b'baz')
+ node = FileNode(b"foobar", content=b"baz")
self.imc.add(node)
- self.imc.commit(message='Added foobar', author='Some Name ')
- node = FileNode(b'not-foobar', content=b'')
+ self.imc.commit(message="Added foobar", author="Some Name ")
+ node = FileNode(b"not-foobar", content=b"")
self.imc.change(node)
with pytest.raises(NodeDoesNotExistError):
- self.imc.commit(message='Changed not existing node', author='Some Name ')
+ self.imc.commit(message="Changed not existing node", author="Some Name ")
def test_change_raise_node_already_changed(self):
- node = FileNode(b'foobar', content=b'baz')
+ node = FileNode(b"foobar", content=b"baz")
self.imc.add(node)
- self.imc.commit(message='Added foobar', author='Some Nam ')
- node = FileNode(b'foobar', content=b'more baz')
+ self.imc.commit(message="Added foobar", author="Some Nam ")
+ node = FileNode(b"foobar", content=b"more baz")
self.imc.change(node)
with pytest.raises(NodeAlreadyChangedError):
self.imc.change(node)
@@ -233,14 +228,14 @@ class TestInMemoryCommit(BackendTestMixin):
self.imc.change(node)
with pytest.raises(NodeNotChangedError):
self.imc.commit(
- message='Trying to mark node as changed without touching it',
- author='Some Name ')
+ message="Trying to mark node as changed without touching it", author="Some Name "
+ )
def test_change_raise_node_already_removed(self):
- node = FileNode(b'foobar', content=b'baz')
+ node = FileNode(b"foobar", content=b"baz")
self.imc.add(node)
- self.imc.commit(message='Added foobar', author='Some Name ')
- self.imc.remove(FileNode(b'foobar'))
+ self.imc.commit(message="Added foobar", author="Some Name ")
+ self.imc.remove(FileNode(b"foobar"))
with pytest.raises(NodeAlreadyRemovedError):
self.imc.change(node)
@@ -251,7 +246,7 @@ class TestInMemoryCommit(BackendTestMixin):
node = nodes[0]
assert node.content == tip.get_node(node.path).content
self.imc.remove(node)
- self.imc.commit(message=f'Removed {node.path}', author='Some Name ')
+ self.imc.commit(message=f"Removed {node.path}", author="Some Name ")
newtip = self.repo.get_commit()
assert tip != newtip
@@ -260,31 +255,27 @@ class TestInMemoryCommit(BackendTestMixin):
newtip.get_node(node.path)
def test_remove_last_file_from_directory(self):
- node = FileNode(b'omg/qwe/foo/bar', content=b'foobar')
+ node = FileNode(b"omg/qwe/foo/bar", content=b"foobar")
self.imc.add(node)
- self.imc.commit('added', author='joe doe ')
+ self.imc.commit("added", author="joe doe ")
self.imc.remove(node)
- tip = self.imc.commit('removed', 'joe doe ')
+ tip = self.imc.commit("removed", "joe doe ")
with pytest.raises(NodeDoesNotExistError):
- tip.get_node('omg/qwe/foo/bar')
+ tip.get_node("omg/qwe/foo/bar")
def test_remove_raise_node_does_not_exist(self, nodes):
self.imc.remove(nodes[0])
with pytest.raises(NodeDoesNotExistError):
- self.imc.commit(
- message='Trying to remove node at empty repository',
- author='Some Name ')
+ self.imc.commit(message="Trying to remove node at empty repository", author="Some Name ")
def test_check_integrity_remove_raise_node_does_not_exist(self, nodes):
self.test_add(nodes) # Performs first commit
- node = FileNode(b'no-such-file')
+ node = FileNode(b"no-such-file")
self.imc.remove(node)
with pytest.raises(NodeDoesNotExistError):
- self.imc.commit(
- message='Trying to remove not existing node',
- author='Some Name ')
+ self.imc.commit(message="Trying to remove not existing node", author="Some Name ")
def test_remove_raise_node_already_removed(self, nodes):
self.test_add(nodes) # Performs first commit
@@ -297,13 +288,13 @@ class TestInMemoryCommit(BackendTestMixin):
def test_remove_raise_node_already_changed(self, nodes):
self.test_add(nodes) # Performs first commit
- node = FileNode(nodes[0].bytes_path, content=b'Bending time')
+ node = FileNode(nodes[0].bytes_path, content=b"Bending time")
self.imc.change(node)
with pytest.raises(NodeAlreadyChangedError):
self.imc.remove(node)
def test_reset(self):
- self.imc.add(FileNode(b'foo', content=b'bar'))
+ self.imc.add(FileNode(b"foo", content=b"bar"))
# self.imc.change(FileNode(b'baz', content='new'))
# self.imc.remove(FileNode(b'qwe'))
self.imc.reset()
@@ -313,11 +304,11 @@ class TestInMemoryCommit(BackendTestMixin):
N = 3 # number of commits to perform
last = None
for x in range(N):
- fname = safe_bytes('file%s' % str(x).rjust(5, '0'))
- content = safe_bytes('foobar\n' * x)
+ fname = safe_bytes("file%s" % str(x).rjust(5, "0"))
+ content = safe_bytes("foobar\n" * x)
node = FileNode(fname, content=content)
self.imc.add(node)
- commit = self.imc.commit("Commit no. %s" % (x + 1), author='Vcs User ')
+ commit = self.imc.commit("Commit no. %s" % (x + 1), author="Vcs User ")
assert last != commit
last = commit
@@ -329,12 +320,10 @@ class TestInMemoryCommit(BackendTestMixin):
assert len(repo.commit_ids) == N
def test_date_attr(self, local_dt_to_utc):
- node = FileNode(b'foobar.txt', content=b'Foobared!')
+ node = FileNode(b"foobar.txt", content=b"Foobared!")
self.imc.add(node)
date = datetime.datetime(1985, 1, 30, 1, 45)
- commit = self.imc.commit(
- "Committed at time when I was born ;-)",
- author='Test User ', date=date)
+ commit = self.imc.commit("Committed at time when I was born ;-)", author="Test User ", date=date)
assert commit.date == local_dt_to_utc(date)
diff --git a/rhodecode/tests/vcs/test_nodes.py b/rhodecode/tests/vcs/test_nodes.py
index 5a3d5207..e745816e 100644
--- a/rhodecode/tests/vcs/test_nodes.py
+++ b/rhodecode/tests/vcs/test_nodes.py
@@ -1,4 +1,3 @@
-
# Copyright (C) 2010-2023 RhodeCode GmbH
#
# This program is free software: you can redistribute it and/or modify
@@ -38,34 +37,34 @@ def binary_filenode():
b"\x10\x08\x06\x00\x00\x00\x1f??a\x00\x00\x00\x04gAMA\x00\x00\xaf?7"
b"\x05\x8a?\x00\x00\x00\x19tEXtSoftware\x00Adobe ImageReadyq?e<\x00"
b"\x00\x025IDAT8?\xa5\x93?K\x94Q\x14\x87\x9f\xf7?Q\x1bs4?\x03\x9a"
- b"\xa8?B\x02\x8b$\x10[U;i\x13?6h?&h[?\"\x14j?\xa2M\x7fB\x14F\x9aQ?&"
- b"\x842?\x0b\x89\"\x82??!?\x9c!\x9c2l??{N\x8bW\x9dY\xb4\t/\x1c?="
- b"\x9b?}????\xa9*;9!?\x83\x91?[?\\v*?D\x04\'`EpNp\xa2X\'U?pVq\"Sw."
+ b'\xa8?B\x02\x8b$\x10[U;i\x13?6h?&h[?"\x14j?\xa2M\x7fB\x14F\x9aQ?&'
+ b'\x842?\x0b\x89"\x82??!?\x9c!\x9c2l??{N\x8bW\x9dY\xb4\t/\x1c?='
+ b"\x9b?}????\xa9*;9!?\x83\x91?[?\\v*?D\x04'`EpNp\xa2X'U?pVq\"Sw."
b"\x1e?\x08\x01D?jw????\xbc??7{|\x9b?\x89$\x01??W@\x15\x9c\x05q`Lt/"
b"\x97?\x94\xa1d?\x18~?\x18?\x18W[%\xb0?\x83??\x14\x88\x8dB?\xa6H"
- b"\tL\tl\x19>/\x01`\xac\xabx?\x9cl\nx\xb0\x98\x07\x95\x88D$\"q["
+ b'\tL\tl\x19>/\x01`\xac\xabx?\x9cl\nx\xb0\x98\x07\x95\x88D$"q['
b"\x19?d\x00(o\n\xa0??\x7f\xb9\xa4?\x1bF\x1f\x8e\xac\xa8?j??eUU}?.?"
- b"\x9f\x8cE??x\x94??\r\xbdtoJU5\"0N\x10U?\x00??V\t\x02\x9f\x81?U?"
- b"\x00\x9eM\xae2?r\x9b7\x83\x82\x8aP3????.?&\"?\xb7ZP \x0cJ?\x80\x15T\x95\x9a\x00??S\x8c\r?\xa1"
b"\x03\x07?\x96\x9b\xa7\xab=E??\xa4\xb3?\x19q??B\x91=\x8d??k?J"
- b"\x0bV\"??\xf7x?\xa1\x00?\\.\x87\x87???\x02F@D\x99],??\x10#?X"
+ b'\x0bV"??\xf7x?\xa1\x00?\\.\x87\x87???\x02F@D\x99],??\x10#?X'
b"\xb7=\xb9\x10?Z\x1by???cI??\x1ag?\x92\xbc?T?t[\x92\x81?<_\x17~"
b"\x92\x88?H%?\x10Q\x02\x9f\n\x81qQ\x0bm?\x1bX?\xb1AK\xa6\x9e\xb9?u"
- b"\xb2?1\xbe|/\x92M@\xa2!F?\xa9>\"\r\x92\x8e?>\x9a9Qv\x127?a"
+ b'\xb2?1\xbe|/\x92M@\xa2!F?\xa9>"\r\x92\x8e?>\x9a9Qv\x127?a'
b"\xac?Y?8?:??]X???9\x80\xb7?u?\x0b#BZ\x8d=\x1d?p\x00\x00\x00\x00"
- b"IEND\xaeB`\x82")
+ b"IEND\xaeB`\x82"
+ )
return FileNode(filename, content=data)
+
return node_maker
class TestNodeBasics:
-
- @pytest.mark.parametrize("path", ['/foo', '/foo/bar'])
- @pytest.mark.parametrize(
- "kind", [NodeKind.FILE, NodeKind.DIR], ids=["FILE", "DIR"])
+ @pytest.mark.parametrize("path", ["/foo", "/foo/bar"])
+ @pytest.mark.parametrize("kind", [NodeKind.FILE, NodeKind.DIR], ids=["FILE", "DIR"])
def test_init_wrong_paths(self, path, kind):
"""
Cannot initialize Node objects with path with slash at the beginning.
@@ -74,44 +73,46 @@ class TestNodeBasics:
with pytest.raises(NodeError):
Node(path, kind)
- @pytest.mark.parametrize("path", ['path', 'some/path'])
- @pytest.mark.parametrize(
- "kind", [NodeKind.FILE, NodeKind.DIR], ids=["FILE", "DIR"])
+ @pytest.mark.parametrize("path", ["path", "some/path"])
+ @pytest.mark.parametrize("kind", [NodeKind.FILE, NodeKind.DIR], ids=["FILE", "DIR"])
def test_name(self, path, kind):
path = safe_bytes(path)
node = Node(path, kind)
- assert node.name == 'path'
+ assert node.name == "path"
def test_name_root(self):
- node = Node(b'', NodeKind.DIR)
- assert node.name == ''
+ node = Node(b"", NodeKind.DIR)
+ assert node.name == ""
def test_root_node_cannot_be_file(self):
with pytest.raises(NodeError):
- Node(b'', NodeKind.FILE)
+ Node(b"", NodeKind.FILE)
def test_kind_setter(self):
- node = Node(b'', NodeKind.DIR)
+ node = Node(b"", NodeKind.DIR)
with pytest.raises(NodeError):
node.kind = NodeKind.FILE
def test_compare_equal(self):
- node1 = FileNode(b'test', content=b'')
- node2 = FileNode(b'test', content=b'')
+ node1 = FileNode(b"test", content=b"")
+ node2 = FileNode(b"test", content=b"")
assert node1 == node2
assert not node1 != node2
def test_compare_unequal(self):
- node1 = FileNode(b'test', content=b'a')
- node2 = FileNode(b'test', content=b'b')
+ node1 = FileNode(b"test", content=b"a")
+ node2 = FileNode(b"test", content=b"b")
assert node1 != node2
assert not node1 == node2
- @pytest.mark.parametrize("node_path, expected_parent_path", [
- ('', b''),
- ('some/path/', b'some/'),
- ('some/longer/path/', b'some/longer/'),
- ])
+ @pytest.mark.parametrize(
+ "node_path, expected_parent_path",
+ [
+ ("", b""),
+ ("some/path/", b"some/"),
+ ("some/longer/path/", b"some/longer/"),
+ ],
+ )
def test_parent_path_new(self, node_path, expected_parent_path):
"""
Tests if node's parent path are properly computed.
@@ -119,11 +120,10 @@ class TestNodeBasics:
node_path = safe_bytes(node_path)
node = Node(node_path, NodeKind.DIR)
parent_path = node.get_parent_path()
- assert (parent_path.endswith(b'/') or
- node.is_root() and parent_path == b'')
+ assert parent_path.endswith(b"/") or node.is_root() and parent_path == b""
assert parent_path == expected_parent_path
- '''
+ """
def _test_trailing_slash(self, path):
if not path.endswith('/'):
pytest.fail("Trailing slash tests needs paths to end with slash")
@@ -134,22 +134,22 @@ class TestNodeBasics:
def test_trailing_slash(self):
for path in ('/', 'foo/', 'foo/bar/', 'foo/bar/biz/'):
self._test_trailing_slash(path)
- '''
+ """
def test_is_file(self):
- node = Node(b'any', NodeKind.FILE)
+ node = Node(b"any", NodeKind.FILE)
assert node.is_file()
- node = FileNode(b'any')
+ node = FileNode(b"any")
assert node.is_file()
with pytest.raises(AttributeError):
node.nodes # noqa
def test_is_dir(self):
- node = Node(b'any_dir', NodeKind.DIR)
+ node = Node(b"any_dir", NodeKind.DIR)
assert node.is_dir()
- node = DirNode(b'any_dir')
+ node = DirNode(b"any_dir")
assert node.is_dir()
with pytest.raises(NodeError):
@@ -157,14 +157,14 @@ class TestNodeBasics:
def test_dir_node_iter(self):
nodes = [
- DirNode(b'docs'),
- DirNode(b'tests'),
- FileNode(b'bar'),
- FileNode(b'foo'),
- FileNode(b'readme.txt'),
- FileNode(b'setup.py'),
+ DirNode(b"docs"),
+ DirNode(b"tests"),
+ FileNode(b"bar"),
+ FileNode(b"foo"),
+ FileNode(b"readme.txt"),
+ FileNode(b"setup.py"),
]
- dirnode = DirNode(b'', nodes=nodes)
+ dirnode = DirNode(b"", nodes=nodes)
for node in dirnode:
assert node == dirnode.get_node(node.path)
@@ -172,15 +172,15 @@ class TestNodeBasics:
"""
Without link to commit nodes should raise NodeError.
"""
- node = FileNode(b'anything')
+ node = FileNode(b"anything")
with pytest.raises(NodeError):
node.state # noqa
- node = DirNode(b'anything')
+ node = DirNode(b"anything")
with pytest.raises(NodeError):
node.state # noqa
def test_file_node_stat(self):
- node = FileNode(b'foobar', b'empty... almost')
+ node = FileNode(b"foobar", b"empty... almost")
mode = node.mode # default should be 0100644
assert mode & stat.S_IRUSR
assert mode & stat.S_IWUSR
@@ -193,36 +193,36 @@ class TestNodeBasics:
assert not mode & stat.S_IXOTH
def test_file_node_is_executable(self):
- node = FileNode(b'foobar', b'empty... almost', mode=0o100755)
+ node = FileNode(b"foobar", b"empty... almost", mode=0o100755)
assert node.is_executable
- node = FileNode(b'foobar', b'empty... almost', mode=0o100500)
+ node = FileNode(b"foobar", b"empty... almost", mode=0o100500)
assert node.is_executable
- node = FileNode(b'foobar', b'empty... almost', mode=0o100644)
+ node = FileNode(b"foobar", b"empty... almost", mode=0o100644)
assert not node.is_executable
def test_file_node_is_not_symlink(self):
- node = FileNode(b'foobar', b'empty...')
+ node = FileNode(b"foobar", b"empty...")
assert not node.is_link()
def test_mimetype(self):
- py_node = FileNode(b'test.py')
- tar_node = FileNode(b'test.tar.gz')
+ py_node = FileNode(b"test.py")
+ tar_node = FileNode(b"test.tar.gz")
- ext = 'CustomExtension'
+ ext = "CustomExtension"
- my_node2 = FileNode(b'myfile2')
+ my_node2 = FileNode(b"myfile2")
my_node2._mimetype = [ext]
- my_node3 = FileNode(b'myfile3')
+ my_node3 = FileNode(b"myfile3")
my_node3._mimetype = [ext, ext]
- assert py_node.mimetype == 'text/x-python'
- assert py_node.get_mimetype() == ('text/x-python', None)
+ assert py_node.mimetype == "text/x-python"
+ assert py_node.get_mimetype() == ("text/x-python", None)
- assert tar_node.mimetype == 'application/x-tar'
- assert tar_node.get_mimetype() == ('application/x-tar', 'gzip')
+ assert tar_node.mimetype == "application/x-tar"
+ assert tar_node.get_mimetype() == ("application/x-tar", "gzip")
with pytest.raises(NodeError):
my_node2.get_mimetype()
@@ -232,47 +232,45 @@ class TestNodeBasics:
def test_lines_counts(self):
lines = [
- b'line1\n',
- b'line2\n',
- b'line3\n',
- b'\n',
- b'\n',
- b'line4\n',
+ b"line1\n",
+ b"line2\n",
+ b"line3\n",
+ b"\n",
+ b"\n",
+ b"line4\n",
]
- py_node = FileNode(b'test.py', b''.join(lines))
+ py_node = FileNode(b"test.py", b"".join(lines))
assert (len(lines), len(lines)) == py_node.lines()
assert (len(lines), len(lines) - 2) == py_node.lines(count_empty=True)
def test_lines_no_newline(self):
- py_node = FileNode(b'test.py', b'oneline')
+ py_node = FileNode(b"test.py", b"oneline")
assert (1, 1) == py_node.lines()
assert (1, 1) == py_node.lines(count_empty=True)
class TestNodeContent(object):
-
def test_if_binary(self, binary_filenode):
- filenode = binary_filenode(b'calendar.jpg')
+ filenode = binary_filenode(b"calendar.jpg")
assert filenode.is_binary
def test_binary_line_counts(self, binary_filenode):
- tar_node = binary_filenode(b'archive.tar.gz')
+ tar_node = binary_filenode(b"archive.tar.gz")
assert (0, 0) == tar_node.lines(count_empty=True)
def test_binary_mimetype(self, binary_filenode):
- tar_node = binary_filenode(b'archive.tar.gz')
- assert tar_node.mimetype == 'application/x-tar'
+ tar_node = binary_filenode(b"archive.tar.gz")
+ assert tar_node.mimetype == "application/x-tar"
@pytest.mark.usefixtures("vcs_repository_support")
class TestNodesCommits(BackendTestMixin):
-
def test_node_last_commit(self, generate_repo_with_commits):
repo = generate_repo_with_commits(20)
last_commit = repo.get_commit()
for x in range(3):
- node = last_commit.get_node(f'file_{x}.txt')
+ node = last_commit.get_node(f"file_{x}.txt")
assert node.last_commit == repo[x]
diff --git a/rhodecode/tests/vcs/test_repository.py b/rhodecode/tests/vcs/test_repository.py
index f1dc3a81..2ba82e49 100644
--- a/rhodecode/tests/vcs/test_repository.py
+++ b/rhodecode/tests/vcs/test_repository.py
@@ -114,9 +114,7 @@ class TestRepositoryBase(BackendTestMixin):
assert len(self.repo.get_hook_location()) != 0
def test_last_change(self, local_dt_to_utc):
- assert self.repo.last_change >= local_dt_to_utc(
- datetime.datetime(2010, 1, 1, 21, 0)
- )
+ assert self.repo.last_change >= local_dt_to_utc(datetime.datetime(2010, 1, 1, 21, 0))
def test_last_change_in_empty_repository(self, vcsbackend, local_dt_to_utc):
delta = datetime.timedelta(seconds=1)
@@ -195,9 +193,7 @@ class TestRepositoryCompare:
@pytest.mark.parametrize("merge", [True, False])
def test_compare_commits_of_same_repository(self, vcsbackend, merge):
target_repo = vcsbackend.create_repo(number_of_commits=5)
- target_repo.compare(
- target_repo[1].raw_id, target_repo[3].raw_id, target_repo, merge=merge
- )
+ target_repo.compare(target_repo[1].raw_id, target_repo[3].raw_id, target_repo, merge=merge)
@pytest.mark.xfail_backends("svn")
@pytest.mark.parametrize("merge", [True, False])
@@ -209,9 +205,7 @@ class TestRepositoryCompare:
vcsbackend.add_file(source_repo, b"newfile", b"somecontent")
source_commit = source_repo.get_commit()
- target_repo.compare(
- target_repo[1].raw_id, source_repo[3].raw_id, source_repo, merge=merge
- )
+ target_repo.compare(target_repo[1].raw_id, source_repo[3].raw_id, source_repo, merge=merge)
@pytest.mark.xfail_backends("svn")
@pytest.mark.parametrize("merge", [True, False])
@@ -351,9 +345,7 @@ class TestRepositoryMerge(object):
"merge message 1",
dry_run=False,
)
- expected_merge_response = MergeResponse(
- True, True, merge_response.merge_ref, MergeFailureReason.NONE
- )
+ expected_merge_response = MergeResponse(True, True, merge_response.merge_ref, MergeFailureReason.NONE)
assert merge_response == expected_merge_response
target_repo = backends.get_backend(vcsbackend.alias)(self.target_repo.path)
@@ -385,9 +377,7 @@ class TestRepositoryMerge(object):
"merge message 2",
dry_run=False,
)
- expected_merge_response = MergeResponse(
- True, True, merge_response.merge_ref, MergeFailureReason.NONE
- )
+ expected_merge_response = MergeResponse(True, True, merge_response.merge_ref, MergeFailureReason.NONE)
assert merge_response == expected_merge_response
target_repo = backends.get_backend(vcsbackend.alias)(self.target_repo.path)
@@ -422,9 +412,9 @@ class TestRepositoryMerge(object):
# Multiple merges may differ in their commit id. Therefore, we set the
# commit id to `None` before comparing the merge responses.
- merge_response.merge_ref.commit_id = 'abcdeabcde'
+ merge_response.merge_ref.commit_id = "abcdeabcde"
- merge_response_update.merge_ref.commit_id = 'abcdeabcde'
+ merge_response_update.merge_ref.commit_id = "abcdeabcde"
assert merge_response == merge_response_update
assert merge_response.possible is True
@@ -436,9 +426,7 @@ class TestRepositoryMerge(object):
def test_merge_conflict(self, vcsbackend, dry_run):
self.prepare_for_conflict(vcsbackend)
- expected_merge_response = MergeResponse(
- False, False, None, MergeFailureReason.MERGE_FAILED
- )
+ expected_merge_response = MergeResponse(False, False, None, MergeFailureReason.MERGE_FAILED)
merge_response = self.target_repo.merge(
self.repo_id,
@@ -491,9 +479,7 @@ class TestRepositoryMerge(object):
def test_merge_missing_source_reference(self, vcsbackend):
self.prepare_for_success(vcsbackend)
- source_ref = Reference(
- self.source_ref.type, "not_existing", self.source_ref.commit_id
- )
+ source_ref = Reference(self.source_ref.type, "not_existing", self.source_ref.commit_id)
expected_merge_response = MergeResponse(
False,
False,
@@ -523,9 +509,7 @@ class TestRepositoryMerge(object):
metadata={"exception": "ErrorForTest"},
)
- with mock.patch.object(
- self.target_repo, "_merge_repo", side_effect=RepositoryError()
- ):
+ with mock.patch.object(self.target_repo, "_merge_repo", side_effect=RepositoryError()):
merge_response = self.target_repo.merge(
self.repo_id,
self.workspace_id,
@@ -559,9 +543,7 @@ class TestRepositoryMerge(object):
workspace_id = "test-errors-in-merge"
repo_id = repo_id_generator(workspace_id)
with pytest.raises(ValueError):
- repo.merge(
- repo_id, workspace_id, ref, self, ref, "user name", "user@email.com"
- )
+ repo.merge(repo_id, workspace_id, ref, self, ref, "user name", "user@email.com")
@pytest.mark.usefixtures("vcs_repository_support")
diff --git a/rhodecode/tests/vcs/test_svn.py b/rhodecode/tests/vcs/test_svn.py
index f4510b35..620c244f 100644
--- a/rhodecode/tests/vcs/test_svn.py
+++ b/rhodecode/tests/vcs/test_svn.py
@@ -1,4 +1,3 @@
-
# Copyright (C) 2010-2023 RhodeCode GmbH
#
# This program is free software: you can redistribute it and/or modify
@@ -47,13 +46,13 @@ def head(repo):
def test_init_fails_if_path_does_not_exist():
- path = os.path.join(TEST_DIR, 'i-do-not-exist')
+ path = os.path.join(TEST_DIR, "i-do-not-exist")
with pytest.raises(VCSError):
SubversionRepository(path)
def test_init_fails_if_path_is_not_a_valid_repository(tmpdir):
- path = str(tmpdir.mkdir('unicode ä'))
+ path = str(tmpdir.mkdir("unicode ä"))
with pytest.raises(VCSError):
SubversionRepository(path)
@@ -61,17 +60,14 @@ def test_init_fails_if_path_is_not_a_valid_repository(tmpdir):
def test_repo_clone(vcsbackend, reposerver):
source = vcsbackend.create_repo(number_of_commits=3)
reposerver.serve(source)
- repo = SubversionRepository(
- vcsbackend.new_repo_path(),
- create=True,
- src_url=reposerver.url)
+ repo = SubversionRepository(vcsbackend.new_repo_path(), create=True, src_url=reposerver.url)
assert source.commit_ids == repo.commit_ids
assert source[0].message == repo[0].message
def test_latest_commit(head):
- assert head.raw_id == '393'
+ assert head.raw_id == "393"
def test_commit_description(head):
@@ -79,18 +75,22 @@ def test_commit_description(head):
def test_commit_author(head):
- assert head.author == 'marcin'
+ assert head.author == "marcin"
-@pytest.mark.parametrize("filename, content, mime_type", [
- (b'test.txt', b'Text content\n', None),
- (b'test.bin', b'\0 binary \0', 'application/octet-stream'),
-], ids=['text', 'binary'])
+@pytest.mark.parametrize(
+ "filename, content, mime_type",
+ [
+ (b"test.txt", b"Text content\n", None),
+ (b"test.bin", b"\0 binary \0", "application/octet-stream"),
+ ],
+ ids=["text", "binary"],
+)
def test_sets_mime_type_correctly(vcsbackend, filename, content, mime_type):
repo = vcsbackend.create_repo()
vcsbackend.ensure_file(filename, content)
file_properties = repo._remote.node_properties(filename, 1)
- assert file_properties.get('svn:mime-type') == mime_type
+ assert file_properties.get("svn:mime-type") == mime_type
def test_slice_access(repo):
@@ -100,7 +100,7 @@ def test_slice_access(repo):
end = start + page_size - 1
commits = list(repo[start:end])
- assert [commit.raw_id for commit in commits] == ['1', '2', '3', '4']
+ assert [commit.raw_id for commit in commits] == ["1", "2", "3", "4"]
def test_walk_changelog_page(repo):
@@ -110,14 +110,14 @@ def test_walk_changelog_page(repo):
end = start + page_size - 1
commits = list(repo[start:end])
- changelog = [
- 'r%s, %s, %s' % (c.raw_id, c.author, c.message) for c in commits]
+ changelog = ["r%s, %s, %s" % (c.raw_id, c.author, c.message) for c in commits]
expexted_messages = [
- 'r1, marcin, initial import',
- 'r2, marcin, hg ignore',
- 'r3, marcin, Pip standards refactor',
- 'r4, marcin, Base repository few new functions added']
+ "r1, marcin, initial import",
+ "r2, marcin, hg ignore",
+ "r3, marcin, Pip standards refactor",
+ "r4, marcin, Base repository few new functions added",
+ ]
assert changelog == expexted_messages
@@ -128,68 +128,68 @@ def test_read_full_file_tree(head):
def test_topnode_files_attribute(head):
- topnode = head.get_node('')
+ topnode = head.get_node("")
topnode.files
-
-
-@pytest.mark.parametrize("filename, content, branch, mime_type", [
- ('branches/plain/test.txt', b'Text content\n', 'plain', None),
- ('branches/uniçö∂e/test.bin', b'\0 binary \0', 'uniçö∂e', 'application/octet-stream'),
-], ids=['text', 'binary'])
+@pytest.mark.parametrize(
+ "filename, content, branch, mime_type",
+ [
+ ("branches/plain/test.txt", b"Text content\n", "plain", None),
+ ("branches/uniçö∂e/test.bin", b"\0 binary \0", "uniçö∂e", "application/octet-stream"),
+ ],
+ ids=["text", "binary"],
+)
def test_unicode_refs(vcsbackend, filename, content, branch, mime_type):
filename = safe_bytes(filename)
repo = vcsbackend.create_repo()
vcsbackend.ensure_file(filename, content)
- with mock.patch(("rhodecode.lib.vcs.backends.svn.repository"
- ".SubversionRepository._patterns_from_section"),
- return_value=['branches/*']):
- assert f'branches/{branch}' in repo.branches
+ with mock.patch(
+ ("rhodecode.lib.vcs.backends.svn.repository" ".SubversionRepository._patterns_from_section"),
+ return_value=["branches/*"],
+ ):
+ assert f"branches/{branch}" in repo.branches
def test_compatible_version(monkeypatch, vcsbackend):
- monkeypatch.setattr(settings, 'SVN_COMPATIBLE_VERSION', 'pre-1.8-compatible')
+ monkeypatch.setattr(settings, "SVN_COMPATIBLE_VERSION", "pre-1.8-compatible")
path = vcsbackend.new_repo_path()
SubversionRepository(path, create=True)
- with open(f'{path}/db/format') as f:
+ with open(f"{path}/db/format") as f:
first_line = f.readline().strip()
- assert first_line == '4'
+ assert first_line == "4"
def test_invalid_compatible_version(monkeypatch, vcsbackend):
- monkeypatch.setattr(settings, 'SVN_COMPATIBLE_VERSION', 'i-am-an-invalid-setting')
+ monkeypatch.setattr(settings, "SVN_COMPATIBLE_VERSION", "i-am-an-invalid-setting")
path = vcsbackend.new_repo_path()
with pytest.raises(Exception):
SubversionRepository(path, create=True)
class TestSVNCommit(object):
-
@pytest.fixture(autouse=True)
def prepare(self, repo):
self.repo = repo
def test_file_history_from_commits(self):
- node = self.repo[10].get_node('setup.py')
+ node = self.repo[10].get_node("setup.py")
commit_ids = [commit.raw_id for commit in node.history]
- assert ['8'] == commit_ids
+ assert ["8"] == commit_ids
- node = self.repo[20].get_node('setup.py')
+ node = self.repo[20].get_node("setup.py")
node_ids = [commit.raw_id for commit in node.history]
- assert ['18',
- '8'] == node_ids
+ assert ["18", "8"] == node_ids
# special case we check history from commit that has this particular
# file changed this means we check if it's included as well
- node = self.repo.get_commit('18').get_node('setup.py')
+ node = self.repo.get_commit("18").get_node("setup.py")
node_ids = [commit.raw_id for commit in node.history]
- assert ['18',
- '8'] == node_ids
+ assert ["18", "8"] == node_ids
def test_repo_files_content_type(self):
test_commit = self.repo.get_commit(commit_idx=100)
- for node in test_commit.get_node('/'):
+ for node in test_commit.get_node("/"):
if node.is_file():
assert type(node.content) == bytes
assert type(node.str_content) == str
diff --git a/rhodecode/tests/vcs/test_tags.py b/rhodecode/tests/vcs/test_tags.py
index 72972991..b5774ccb 100644
--- a/rhodecode/tests/vcs/test_tags.py
+++ b/rhodecode/tests/vcs/test_tags.py
@@ -1,4 +1,3 @@
-
# Copyright (C) 2010-2023 RhodeCode GmbH
#
# This program is free software: you can redistribute it and/or modify
@@ -20,8 +19,7 @@
import pytest
from rhodecode.tests.vcs.conftest import BackendTestMixin
-from rhodecode.lib.vcs.exceptions import (
- TagAlreadyExistError, TagDoesNotExistError)
+from rhodecode.lib.vcs.exceptions import TagAlreadyExistError, TagDoesNotExistError
pytestmark = pytest.mark.backends("git", "hg")
@@ -29,11 +27,10 @@ pytestmark = pytest.mark.backends("git", "hg")
@pytest.mark.usefixtures("vcs_repository_support")
class TestTags(BackendTestMixin):
-
def test_new_tag(self):
tip = self.repo.get_commit()
tagsize = len(self.repo.tags)
- tag = self.repo.tag('last-commit', 'joe', tip.raw_id)
+ tag = self.repo.tag("last-commit", "joe", tip.raw_id)
assert len(self.repo.tags) == tagsize + 1
for top, __, __ in tip.walk():
@@ -41,29 +38,29 @@ class TestTags(BackendTestMixin):
def test_tag_already_exist(self):
tip = self.repo.get_commit()
- self.repo.tag('last-commit', 'joe', tip.raw_id)
+ self.repo.tag("last-commit", "joe", tip.raw_id)
with pytest.raises(TagAlreadyExistError):
- self.repo.tag('last-commit', 'joe', tip.raw_id)
+ self.repo.tag("last-commit", "joe", tip.raw_id)
commit = self.repo.get_commit(commit_idx=0)
with pytest.raises(TagAlreadyExistError):
- self.repo.tag('last-commit', 'jane', commit.raw_id)
+ self.repo.tag("last-commit", "jane", commit.raw_id)
def test_remove_tag(self):
tip = self.repo.get_commit()
- self.repo.tag('last-commit', 'joe', tip.raw_id)
+ self.repo.tag("last-commit", "joe", tip.raw_id)
tagsize = len(self.repo.tags)
- self.repo.remove_tag('last-commit', user='evil joe')
+ self.repo.remove_tag("last-commit", user="evil joe")
assert len(self.repo.tags) == tagsize - 1
def test_remove_tag_which_does_not_exist(self):
with pytest.raises(TagDoesNotExistError):
- self.repo.remove_tag('last-commit', user='evil joe')
+ self.repo.remove_tag("last-commit", user="evil joe")
def test_name_with_slash(self):
- self.repo.tag('19/10/11', 'joe')
- assert '19/10/11' in self.repo.tags
- self.repo.tag('rel.11', 'joe')
- assert 'rel.11' in self.repo.tags
+ self.repo.tag("19/10/11", "joe")
+ assert "19/10/11" in self.repo.tags
+ self.repo.tag("rel.11", "joe")
+ assert "rel.11" in self.repo.tags
diff --git a/rhodecode/tests/vcs/test_utils.py b/rhodecode/tests/vcs/test_utils.py
index ccf87c29..0b79766b 100644
--- a/rhodecode/tests/vcs/test_utils.py
+++ b/rhodecode/tests/vcs/test_utils.py
@@ -1,4 +1,3 @@
-
# Copyright (C) 2010-2023 RhodeCode GmbH
#
# This program is free software: you can redistribute it and/or modify
@@ -34,23 +33,20 @@ from rhodecode.lib.vcs.utils.paths import get_dirs_for_path
@pytest.mark.usefixtures("baseapp")
class TestPaths(object):
-
def _test_get_dirs_for_path(self, path, expected):
"""
Tests if get_dirs_for_path returns same as expected.
"""
expected = sorted(expected)
result = sorted(get_dirs_for_path(path))
- assert result == expected, (
- "%s != %s which was expected result for path %s"
- % (result, expected, path))
+ assert result == expected, "%s != %s which was expected result for path %s" % (result, expected, path)
def test_get_dirs_for_path(self):
- path = 'foo/bar/baz/file'
+ path = "foo/bar/baz/file"
paths_and_results = (
- ('foo/bar/baz/file', ['foo', 'foo/bar', 'foo/bar/baz']),
- ('foo/bar/', ['foo', 'foo/bar']),
- ('foo/bar', ['foo']),
+ ("foo/bar/baz/file", ["foo", "foo/bar", "foo/bar/baz"]),
+ ("foo/bar/", ["foo", "foo/bar"]),
+ ("foo/bar", ["foo"]),
)
for path, expected in paths_and_results:
self._test_get_dirs_for_path(path, expected)
@@ -59,18 +55,17 @@ class TestPaths(object):
new = tmpdir.strpath
assert get_scms_for_path(new) == []
- os.mkdir(os.path.join(new, '.tux'))
+ os.mkdir(os.path.join(new, ".tux"))
assert get_scms_for_path(new) == []
- os.mkdir(os.path.join(new, '.git'))
- assert set(get_scms_for_path(new)) == set(['git'])
+ os.mkdir(os.path.join(new, ".git"))
+ assert set(get_scms_for_path(new)) == set(["git"])
- os.mkdir(os.path.join(new, '.hg'))
- assert set(get_scms_for_path(new)) == set(['git', 'hg'])
+ os.mkdir(os.path.join(new, ".hg"))
+ assert set(get_scms_for_path(new)) == set(["git", "hg"])
class TestGetScm(object):
-
def test_existing_repository(self, vcs_repository_support):
alias, repo = vcs_repository_support
assert (alias, repo.path) == get_scm(repo.path)
@@ -81,114 +76,101 @@ class TestGetScm(object):
def test_get_scm_error_path(self):
with pytest.raises(VCSError):
- get_scm('err')
+ get_scm("err")
def test_get_two_scms_for_path(self, tmpdir):
multialias_repo_path = str(tmpdir)
git_default_branch = GitRepository.DEFAULT_BRANCH_NAME
- subprocess.check_call(['hg', 'init', multialias_repo_path])
- subprocess.check_call(['git', '-c', f'init.defaultBranch={git_default_branch}', 'init', multialias_repo_path])
+ subprocess.check_call(["hg", "init", multialias_repo_path])
+ subprocess.check_call(["git", "-c", f"init.defaultBranch={git_default_branch}", "init", multialias_repo_path])
with pytest.raises(VCSError):
get_scm(multialias_repo_path)
def test_ignores_svn_working_copy(self, tmpdir):
- tmpdir.mkdir('.svn')
+ tmpdir.mkdir(".svn")
with pytest.raises(VCSError):
get_scm(tmpdir.strpath)
class TestParseDatetime(object):
-
def test_datetime_text(self):
- assert parse_datetime('2010-04-07 21:29:41') == \
- datetime.datetime(2010, 4, 7, 21, 29, 41)
+ assert parse_datetime("2010-04-07 21:29:41") == datetime.datetime(2010, 4, 7, 21, 29, 41)
def test_no_seconds(self):
- assert parse_datetime('2010-04-07 21:29') == \
- datetime.datetime(2010, 4, 7, 21, 29)
+ assert parse_datetime("2010-04-07 21:29") == datetime.datetime(2010, 4, 7, 21, 29)
def test_date_only(self):
- assert parse_datetime('2010-04-07') == \
- datetime.datetime(2010, 4, 7)
+ assert parse_datetime("2010-04-07") == datetime.datetime(2010, 4, 7)
def test_another_format(self):
- assert parse_datetime('04/07/10 21:29:41') == \
- datetime.datetime(2010, 4, 7, 21, 29, 41)
+ assert parse_datetime("04/07/10 21:29:41") == datetime.datetime(2010, 4, 7, 21, 29, 41)
def test_now(self):
- assert parse_datetime('now') - datetime.datetime.now() < \
- datetime.timedelta(seconds=1)
+ assert parse_datetime("now") - datetime.datetime.now() < datetime.timedelta(seconds=1)
def test_today(self):
today = datetime.date.today()
- assert parse_datetime('today') == \
- datetime.datetime(*today.timetuple()[:3])
+ assert parse_datetime("today") == datetime.datetime(*today.timetuple()[:3])
def test_yesterday(self):
yesterday = datetime.date.today() - datetime.timedelta(days=1)
- assert parse_datetime('yesterday') == \
- datetime.datetime(*yesterday.timetuple()[:3])
+ assert parse_datetime("yesterday") == datetime.datetime(*yesterday.timetuple()[:3])
def test_tomorrow(self):
tomorrow = datetime.date.today() + datetime.timedelta(days=1)
args = tomorrow.timetuple()[:3] + (23, 59, 59)
- assert parse_datetime('tomorrow') == datetime.datetime(*args)
+ assert parse_datetime("tomorrow") == datetime.datetime(*args)
def test_days(self):
timestamp = datetime.datetime.today() - datetime.timedelta(days=3)
args = timestamp.timetuple()[:3] + (0, 0, 0, 0)
expected = datetime.datetime(*args)
- assert parse_datetime('3d') == expected
- assert parse_datetime('3 d') == expected
- assert parse_datetime('3 day') == expected
- assert parse_datetime('3 days') == expected
+ assert parse_datetime("3d") == expected
+ assert parse_datetime("3 d") == expected
+ assert parse_datetime("3 day") == expected
+ assert parse_datetime("3 days") == expected
def test_weeks(self):
timestamp = datetime.datetime.today() - datetime.timedelta(days=3 * 7)
args = timestamp.timetuple()[:3] + (0, 0, 0, 0)
expected = datetime.datetime(*args)
- assert parse_datetime('3w') == expected
- assert parse_datetime('3 w') == expected
- assert parse_datetime('3 week') == expected
- assert parse_datetime('3 weeks') == expected
+ assert parse_datetime("3w") == expected
+ assert parse_datetime("3 w") == expected
+ assert parse_datetime("3 week") == expected
+ assert parse_datetime("3 weeks") == expected
def test_mixed(self):
- timestamp = (
- datetime.datetime.today() - datetime.timedelta(days=2 * 7 + 3))
+ timestamp = datetime.datetime.today() - datetime.timedelta(days=2 * 7 + 3)
args = timestamp.timetuple()[:3] + (0, 0, 0, 0)
expected = datetime.datetime(*args)
- assert parse_datetime('2w3d') == expected
- assert parse_datetime('2w 3d') == expected
- assert parse_datetime('2w 3 days') == expected
- assert parse_datetime('2 weeks 3 days') == expected
+ assert parse_datetime("2w3d") == expected
+ assert parse_datetime("2w 3d") == expected
+ assert parse_datetime("2w 3 days") == expected
+ assert parse_datetime("2 weeks 3 days") == expected
-@pytest.mark.parametrize("test_str, name, email", [
- ('Marcin Kuzminski ',
- 'Marcin Kuzminski', 'marcin@python-works.com'),
- ('Marcin Kuzminski Spaces < marcin@python-works.com >',
- 'Marcin Kuzminski Spaces', 'marcin@python-works.com'),
- ('Marcin Kuzminski ',
- 'Marcin Kuzminski', 'marcin.kuzminski@python-works.com'),
- ('mrf RFC_SPEC ',
- 'mrf RFC_SPEC', 'marcin+kuzminski@python-works.com'),
- ('username ',
- 'username', 'user@email.com'),
- ('username ',
- '', 'justemail@mail.com'),
- ('justname',
- 'justname', ''),
- ('Mr Double Name withemail@email.com ',
- 'Mr Double Name', 'withemail@email.com'),
-])
+@pytest.mark.parametrize(
+ "test_str, name, email",
+ [
+ ("Marcin Kuzminski ", "Marcin Kuzminski", "marcin@python-works.com"),
+ ("Marcin Kuzminski Spaces < marcin@python-works.com >", "Marcin Kuzminski Spaces", "marcin@python-works.com"),
+ (
+ "Marcin Kuzminski ",
+ "Marcin Kuzminski",
+ "marcin.kuzminski@python-works.com",
+ ),
+ ("mrf RFC_SPEC ", "mrf RFC_SPEC", "marcin+kuzminski@python-works.com"),
+ ("username ", "username", "user@email.com"),
+ ("username ", "", "justemail@mail.com"),
+ ("justname", "justname", ""),
+ ("Mr Double Name withemail@email.com ", "Mr Double Name", "withemail@email.com"),
+ ],
+)
class TestAuthorExtractors(object):
-
def test_author_email(self, test_str, name, email):
assert email == author_email(test_str)
diff --git a/rhodecode/tests/vcs/test_vcs.py b/rhodecode/tests/vcs/test_vcs.py
index 465c7a1a..3f9a89f8 100644
--- a/rhodecode/tests/vcs/test_vcs.py
+++ b/rhodecode/tests/vcs/test_vcs.py
@@ -1,4 +1,3 @@
-
# Copyright (C) 2010-2023 RhodeCode GmbH
#
# This program is free software: you can redistribute it and/or modify
@@ -20,6 +19,7 @@
"""
Tests for main module's methods.
"""
+
import os
import tempfile
import shutil
@@ -48,7 +48,7 @@ def test_alias_detect(backend):
def test_wrong_alias():
- alias = 'wrong_alias'
+ alias = "wrong_alias"
with pytest.raises(VCSError):
get_backend(alias)
@@ -77,12 +77,13 @@ def test_get_vcs_instance_by_path_multiple_repos(request):
Test that ``get_vcs_instance_by_path`` returns None if a path is passed
to a directory with multiple repositories.
"""
- empty_dir = tempfile.mkdtemp(prefix='pytest-empty-dir-')
- os.mkdir(os.path.join(empty_dir, '.git'))
- os.mkdir(os.path.join(empty_dir, '.hg'))
+ empty_dir = tempfile.mkdtemp(prefix="pytest-empty-dir-")
+ os.mkdir(os.path.join(empty_dir, ".git"))
+ os.mkdir(os.path.join(empty_dir, ".hg"))
def fin():
shutil.rmtree(empty_dir)
+
request.addfinalizer(fin)
repo = get_vcs_instance(empty_dir)
@@ -90,39 +91,32 @@ def test_get_vcs_instance_by_path_multiple_repos(request):
assert repo is None
-@mock.patch('rhodecode.lib.vcs.backends.get_scm')
-@mock.patch('rhodecode.lib.vcs.backends.get_backend')
-def test_get_vcs_instance_by_path_args_passed(
- get_backend_mock, get_scm_mock, tmpdir, vcs_repo):
+@mock.patch("rhodecode.lib.vcs.backends.get_scm")
+@mock.patch("rhodecode.lib.vcs.backends.get_backend")
+def test_get_vcs_instance_by_path_args_passed(get_backend_mock, get_scm_mock, tmpdir, vcs_repo):
"""
Test that the arguments passed to ``get_vcs_instance_by_path`` are
forwarded to the vcs backend class.
"""
backend = mock.MagicMock()
get_backend_mock.return_value = backend
- args = ['these-are-test-args', 0, True, None]
+ args = ["these-are-test-args", 0, True, None]
repo = vcs_repo.path
get_vcs_instance(repo, *args)
backend.assert_called_with(*args, repo_path=repo)
-@mock.patch('rhodecode.lib.vcs.backends.get_scm')
-@mock.patch('rhodecode.lib.vcs.backends.get_backend')
-def test_get_vcs_instance_by_path_kwargs_passed(
- get_backend_mock, get_scm_mock, vcs_repo):
+@mock.patch("rhodecode.lib.vcs.backends.get_scm")
+@mock.patch("rhodecode.lib.vcs.backends.get_backend")
+def test_get_vcs_instance_by_path_kwargs_passed(get_backend_mock, get_scm_mock, vcs_repo):
"""
Test that the keyword arguments passed to ``get_vcs_instance_by_path`` are
forwarded to the vcs backend class.
"""
backend = mock.MagicMock()
get_backend_mock.return_value = backend
- kwargs = {
- 'foo': 'these-are-test-args',
- 'bar': 0,
- 'baz': True,
- 'foobar': None
- }
+ kwargs = {"foo": "these-are-test-args", "bar": 0, "baz": True, "foobar": None}
repo = vcs_repo.path
get_vcs_instance(repo, **kwargs)
diff --git a/rhodecode/tests/vcs/utils.py b/rhodecode/tests/vcs/utils.py
index df0832f5..f3565848 100644
--- a/rhodecode/tests/vcs/utils.py
+++ b/rhodecode/tests/vcs/utils.py
@@ -1,4 +1,3 @@
-
# Copyright (C) 2010-2023 RhodeCode GmbH
#
# This program is free software: you can redistribute it and/or modify
@@ -37,7 +36,7 @@ def run_command(cmd, args):
"""
Runs command on the system with given ``args``.
"""
- command = ' '.join((cmd, args))
+ command = " ".join((cmd, args))
p = Popen(command, shell=True)
status = os.waitpid(p.pid, 0)[1]
return status
@@ -51,12 +50,11 @@ def eprint(msg):
Appends line break.
"""
sys.stderr.write(msg)
- sys.stderr.write('\n')
+ sys.stderr.write("\n")
# TODO: Revisit once we have CI running, if this is not helping us, remove it
class SCMFetcher(object):
-
def __init__(self, alias, test_repo_path):
"""
:param clone_cmd: command which would clone remote repository; pass
@@ -75,9 +73,8 @@ class SCMFetcher(object):
Tries to fetch repository from remote path.
"""
remote = self.remote_repo
- eprint(
- "Fetching repository %s into %s" % (remote, self.test_repo_path))
- run_command(self.clone_cmd, '%s %s' % (remote, self.test_repo_path))
+ eprint("Fetching repository %s into %s" % (remote, self.test_repo_path))
+ run_command(self.clone_cmd, "%s %s" % (remote, self.test_repo_path))
def get_normalized_path(path):
@@ -88,29 +85,29 @@ def get_normalized_path(path):
"""
if os.path.exists(path):
dir, basename = os.path.split(path)
- splitted_name = basename.split('.')
+ splitted_name = basename.split(".")
if len(splitted_name) > 1:
ext = splitted_name[-1]
else:
ext = None
- name = '.'.join(splitted_name[:-1])
- matcher = re.compile(r'^.*-(\d{5})$')
+ name = ".".join(splitted_name[:-1])
+ matcher = re.compile(r"^.*-(\d{5})$")
start = 0
m = matcher.match(name)
if not m:
# Haven't append number yet so return first
- newname = f'{name}-00000'
+ newname = f"{name}-00000"
newpath = os.path.join(dir, newname)
if ext:
- newpath = '.'.join((newpath, ext))
+ newpath = ".".join((newpath, ext))
return get_normalized_path(newpath)
else:
start = int(m.group(1)[-5:]) + 1
for x in range(start, 10000):
- newname = name[:-5] + str(x).rjust(5, '0')
+ newname = name[:-5] + str(x).rjust(5, "0")
newpath = os.path.join(dir, newname)
if ext:
- newpath = '.'.join((newpath, ext))
+ newpath = ".".join((newpath, ext))
if not os.path.exists(newpath):
return newpath
raise VCSTestError("Couldn't compute new path for %s" % path)
diff --git a/rhodecode/tests/vcs_operations/__init__.py b/rhodecode/tests/vcs_operations/__init__.py
index b3881ecb..b77f7f30 100644
--- a/rhodecode/tests/vcs_operations/__init__.py
+++ b/rhodecode/tests/vcs_operations/__init__.py
@@ -1,5 +1,4 @@
-
-# Copyright (C) 2010-2023 RhodeCode GmbH
+# 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
@@ -36,7 +35,6 @@ from rhodecode.lib.str_utils import safe_str
from rhodecode.tests import GIT_REPO, HG_REPO, SVN_REPO
DEBUG = True
-RC_LOG = os.path.join(tempfile.gettempdir(), 'rc.log')
REPO_GROUP = 'a_repo_group'
HG_REPO_WITH_GROUP = f'{REPO_GROUP}/{HG_REPO}'
GIT_REPO_WITH_GROUP = f'{REPO_GROUP}/{GIT_REPO}'
diff --git a/rhodecode/tests/vcs_operations/conftest.py b/rhodecode/tests/vcs_operations/conftest.py
index d70fb2cd..0cf8a4fb 100644
--- a/rhodecode/tests/vcs_operations/conftest.py
+++ b/rhodecode/tests/vcs_operations/conftest.py
@@ -1,5 +1,4 @@
-
-# Copyright (C) 2010-2023 RhodeCode GmbH
+# 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
@@ -19,22 +18,17 @@
"""
py.test config for test suite for making push/pull operations.
-
-.. important::
-
- You must have git >= 1.8.5 for tests to work fine. With 68b939b git started
- to redirect things to stderr instead of stdout.
"""
import os
-import tempfile
-import textwrap
+
+import pyramid.paster
import pytest
import logging
import requests
from rhodecode import events
-from rhodecode.lib.str_utils import safe_bytes
+from rhodecode.lib.type_utils import AttributeDict
from rhodecode.model.db import Integration, UserRepoToPerm, Permission, \
UserToRepoBranchPermission, User
from rhodecode.model.integration import IntegrationModel
@@ -42,11 +36,13 @@ from rhodecode.model.db import Repository
from rhodecode.model.meta import Session
from rhodecode.integrations.types.webhook import WebhookIntegrationType
+
from rhodecode.tests import GIT_REPO, HG_REPO, SVN_REPO
from rhodecode.tests.conftest import HTTPBIN_DOMAIN, HTTPBIN_POST
-from rhodecode.tests.fixture import Fixture
-from rhodecode.tests.server_utils import RcWebServer
-
+from rhodecode.tests.fixtures.rc_fixture import Fixture
+from rhodecode.tests.fixtures.fixture_utils import backend_base
+from rhodecode.tests.utils import set_anonymous_access, AuthPluginManager
+from rhodecode.tests import console_printer
REPO_GROUP = 'a_repo_group'
HG_REPO_WITH_GROUP = f'{REPO_GROUP}/{HG_REPO}'
@@ -62,39 +58,42 @@ def check_httpbin_connection():
response = requests.get(HTTPBIN_DOMAIN, timeout=5)
return response.status_code == 200
except Exception as e:
- print(e)
+ console_printer(e)
return False
+#overrides backend_N with init_pyramid_app instead of baseapp
+@pytest.fixture()
+def vcs_backend_git(request, init_pyramid_app, test_repo):
+ return backend_base(request, 'git', test_repo)
-@pytest.fixture(scope="module")
-def rcextensions(request, db_connection, tmpdir_factory):
- """
- Installs a testing rcextensions pack to ensure they work as expected.
- """
- init_content = textwrap.dedent("""
- # Forward import the example rcextensions to make it
- # active for our tests.
- from rhodecode.tests.other.example_rcextensions import *
- """)
- # Note: rcextensions are looked up based on the path of the ini file
- root_path = tmpdir_factory.getbasetemp()
- rcextensions_path = root_path.join('rcextensions')
- init_path = rcextensions_path.join('__init__.py')
+@pytest.fixture()
+def vcs_backend_hg(request, init_pyramid_app, test_repo):
+ return backend_base(request, 'hg', test_repo)
- if rcextensions_path.check():
- pytest.fail(
- "Path for rcextensions already exists, please clean up before "
- "test run this path: %s" % (rcextensions_path, ))
- else:
- request.addfinalizer(rcextensions_path.remove)
- init_path.write_binary(safe_bytes(init_content), ensure=True)
+
+@pytest.fixture()
+def vcs_backend_svn(request, init_pyramid_app, test_repo):
+ return backend_base(request, 'svn', test_repo)
@pytest.fixture(scope="module")
-def repos(request, db_connection):
+def tmp_storage_location(request, tmpdir_factory):
+ """
+ Defines a module level storage_location, used mostly to define per-test persistent repo storage
+ shared across vcsserver, rhodecode and celery
+ """
+
+ dest = tmpdir_factory.mktemp('tmp_storage_location_', numbered=True)
+ log.info("Creating test TMP directory at %s", dest)
+ return dest
+
+
+@pytest.fixture(scope="module")
+def repo_group_repos(request):
"""Create a copy of each test repo in a repo group."""
+
fixture = Fixture()
repo_group = fixture.create_repo_group(REPO_GROUP)
repo_group_id = repo_group.group_id
@@ -116,67 +115,117 @@ def repos(request, db_connection):
fixture.destroy_repo_group(repo_group_id)
-@pytest.fixture(scope="module")
-def rc_web_server_config_modification():
- return []
+@pytest.fixture(scope='module')
+def rcstack_vcsserver_factory(vcsserver_factory):
+ return vcsserver_factory
-@pytest.fixture(scope="module")
-def rc_web_server_config_factory(testini_factory, rc_web_server_config_modification):
+@pytest.fixture(scope='module')
+def rcstack_celery_factory(celery_factory):
+ return celery_factory
+
+
+@pytest.fixture(scope='module')
+def rcstack_rhodecode_factory(rhodecode_factory):
+ return rhodecode_factory
+
+
+@pytest.fixture(scope='module')
+def init_pyramid_app(request, available_port_factory, ini_config_factory, rcstack_vcsserver_factory, tmp_storage_location):
+ from rhodecode.lib.config_utils import get_app_config
+ from rhodecode.config.middleware import make_pyramid_app
+
+ store_dir = tmp_storage_location
+ port = available_port_factory()
+ rcstack_vcsserver_factory(
+ request,
+ store_dir=store_dir,
+ port=port,
+ info_prefix='init-app-'
+ )
+
+ app_ini_config = ini_config_factory(store_dir)
+
+ pyramid.paster.setup_logging(app_ini_config)
+
+ settings = get_app_config(app_ini_config)
+ settings['startup.import_repos'] = True
+ settings['vcs.server'] = f'localhost:{port}'
+ settings['repo_store.path'] = str(store_dir)
+ pyramid_app = make_pyramid_app({'__file__': app_ini_config}, **settings)
+
+ return pyramid_app
+
+
+@pytest.fixture(scope='module')
+def rcstack(request, tmp_storage_location, rcextensions, available_port_factory, rcstack_vcsserver_factory, rcstack_celery_factory, rcstack_rhodecode_factory):
"""
- Configuration file used for the fixture `rc_web_server`.
+ Runs minimal rcstack, i.e vcsserver, celery, rhodecode unpacks rcextensions and repos to a shared location
"""
-
- def factory(rcweb_port, vcsserver_port):
- custom_params = [
- {'handler_console': {'level': 'DEBUG'}},
- {'server:main': {'port': rcweb_port}},
- {'app:main': {'vcs.server': 'localhost:%s' % vcsserver_port}}
- ]
- custom_params.extend(rc_web_server_config_modification)
- return testini_factory(custom_params)
- return factory
-
-
-@pytest.fixture(scope="module")
-def rc_web_server(
- request, vcsserver_factory, available_port_factory,
- rc_web_server_config_factory, repos, rcextensions):
- """
- Run the web server as a subprocess. with its own instance of vcsserver
- """
- rcweb_port: int = available_port_factory()
- log.info('Using rcweb ops test port %s', rcweb_port)
+ rcstack_data = AttributeDict()
+ store_dir = tmp_storage_location
vcsserver_port: int = available_port_factory()
- log.info('Using vcsserver ops test port %s', vcsserver_port)
+ vcsserver_log = os.path.join(tmp_storage_location, 'vcsserver.log')
- vcs_log = os.path.join(tempfile.gettempdir(), 'rc_op_vcs.log')
- vcsserver_factory(
- request, vcsserver_port=vcsserver_port,
- log_file=vcs_log,
+ log.info('Using vcsserver test port %s and log %s', vcsserver_port, vcsserver_log) # start vcsserver
+ _factory = rcstack_vcsserver_factory(
+ request,
+ store_dir=store_dir,
+ port=vcsserver_port,
+ log_file=vcsserver_log,
overrides=(
- {'server:main': {'workers': 2}},
- {'server:main': {'graceful_timeout': 10}},
+ {'handler_console': {'level': 'DEBUG'}},
+ ))
+ rcstack_data.vcsserver_port = vcsserver_port
+ rcstack_data.vcsserver_log = _factory.log_file
+
+
+ celery_log = os.path.join(tmp_storage_location, 'celery.log')
+
+
+ log.info('Using celery log %s', celery_log)
+ # start celery
+ _factory = rcstack_celery_factory(
+ request,
+ store_dir=store_dir,
+ port=None,
+ log_file=celery_log,
+ overrides=(
+ {'handler_console': {'level': 'DEBUG'}},
+ {'app:main': {'vcs.server': f'localhost:{vcsserver_port}'}},
+ {'app:main': {'repo_store.path': store_dir}}
))
- rc_log = os.path.join(tempfile.gettempdir(), 'rc_op_web.log')
- rc_web_server_config = rc_web_server_config_factory(
- rcweb_port=rcweb_port,
- vcsserver_port=vcsserver_port)
- server = RcWebServer(rc_web_server_config, log_file=rc_log)
- server.start()
+ rcstack_data.celery_log = _factory.log_file
- @request.addfinalizer
- def cleanup():
- server.shutdown()
+ rhodecode_port: int = available_port_factory()
+ rhodecode_log = os.path.join(tmp_storage_location, 'rhodecode.log')
- server.wait_until_ready()
- return server
+
+ log.info('Using rhodecode test port %s and log %s', rhodecode_port, rhodecode_port)
+
+ # start rhodecode
+ rc = rcstack_rhodecode_factory(
+ request,
+ store_dir=store_dir,
+ port=rhodecode_port,
+ log_file=rhodecode_log,
+ overrides=(
+ {'handler_console': {'level': 'DEBUG'}},
+ {'app:main': {'vcs.server': f'localhost:{vcsserver_port}'}},
+ {'app:main': {'repo_store.path': store_dir}}
+ ))
+
+ rcstack_data.rhodecode_port = rhodecode_port
+ rcstack_data.rhodecode_log = rc.log_file
+
+ rc.rcstack_data = rcstack_data
+ return rc
@pytest.fixture()
-def disable_locking(baseapp):
+def disable_locking(init_pyramid_app):
r = Repository.get_by_repo_name(GIT_REPO)
Repository.unlock(r)
r.enable_locking = False
@@ -190,6 +239,28 @@ def disable_locking(baseapp):
Session().commit()
+@pytest.fixture()
+def disable_anonymous_user(request, init_pyramid_app, db_connection):
+ set_anonymous_access(False)
+
+ @request.addfinalizer
+ def cleanup():
+ set_anonymous_access(True)
+
+
+@pytest.fixture(scope='module')
+def enable_auth_plugins(request, init_pyramid_app):
+ """
+ Return a factory object that when called, allows to control which
+ authentication plugins are enabled.
+ """
+
+ enabler = AuthPluginManager()
+ request.addfinalizer(enabler.cleanup)
+
+ return enabler
+
+
@pytest.fixture()
def fs_repo_only(request, rhodecode_fixtures):
def fs_repo_fabric(repo_name, repo_type):
diff --git a/rhodecode/tests/vcs_operations/test_vcs_calls_custom_auth_code_403.py b/rhodecode/tests/vcs_operations/test_vcs_calls_custom_auth_code_403.py
index 24d022bc..76fc59ca 100644
--- a/rhodecode/tests/vcs_operations/test_vcs_calls_custom_auth_code_403.py
+++ b/rhodecode/tests/vcs_operations/test_vcs_calls_custom_auth_code_403.py
@@ -1,4 +1,3 @@
-
# Copyright (C) 2010-2023 RhodeCode GmbH
#
# This program is free software: you can redistribute it and/or modify
@@ -32,25 +31,27 @@ from rhodecode.tests import (GIT_REPO, HG_REPO)
from rhodecode.tests.vcs_operations import Command
-@pytest.fixture(scope="module")
-def rc_web_server_config_modification():
- return [
- {'app:main': {'auth_ret_code': '403'}},
- #{'app:main': {'auth_ret_code_detection': 'true'}},
- ]
+custom_code = [
+ {'app:main': {'auth_ret_code': '403'}},
+]
+@pytest.mark.parametrize('rcstack', custom_code, indirect=True)
+@pytest.mark.usefixtures(
+ "init_pyramid_app",
+ "repo_group_repos",
+ "disable_anonymous_user",
+ "disable_locking",
+)
+class TestVCSOperationsAuthCode403(object):
-@pytest.mark.usefixtures("disable_locking", "disable_anonymous_user")
-class TestVCSOperationsOnCustomIniConfig(object):
-
- def test_clone_wrong_credentials_hg_ret_code(self, rc_web_server, tmpdir):
- clone_url = rc_web_server.repo_clone_url(HG_REPO, passwd='bad!')
- stdout, stderr = Command('/tmp').execute(
+ def test_clone_wrong_credentials_hg_ret_code(self, rcstack, tmpdir):
+ clone_url = rcstack.repo_clone_url(HG_REPO, passwd='bad!')
+ stdout, stderr = Command(tmpdir.strpath).execute(
'hg clone', clone_url, tmpdir.strpath)
assert 'abort: HTTP Error 403: Forbidden' in stderr
- def test_clone_wrong_credentials_git_ret_code(self, rc_web_server, tmpdir):
- clone_url = rc_web_server.repo_clone_url(GIT_REPO, passwd='bad!')
- stdout, stderr = Command('/tmp').execute(
+ def test_clone_wrong_credentials_git_ret_code(self, rcstack, tmpdir):
+ clone_url = rcstack.repo_clone_url(GIT_REPO, passwd='bad!')
+ stdout, stderr = Command(tmpdir.strpath).execute(
'git clone', clone_url, tmpdir.strpath)
assert 'The requested URL returned error: 403' in stderr
diff --git a/rhodecode/tests/vcs_operations/test_vcs_calls_custom_auth_code_404.py b/rhodecode/tests/vcs_operations/test_vcs_calls_custom_auth_code_404.py
index acd13296..3271cb7f 100644
--- a/rhodecode/tests/vcs_operations/test_vcs_calls_custom_auth_code_404.py
+++ b/rhodecode/tests/vcs_operations/test_vcs_calls_custom_auth_code_404.py
@@ -31,26 +31,27 @@ import pytest
from rhodecode.tests import (GIT_REPO, HG_REPO)
from rhodecode.tests.vcs_operations import Command
+custom_code = [
+ {'app:main': {'auth_ret_code': '404'}},
+]
-@pytest.fixture(scope="module")
-def rc_web_server_config_modification():
- return [
- {'app:main': {'auth_ret_code': '404'}},
- #{'app:main': {'auth_ret_code_detection': 'false'}},
- ]
+@pytest.mark.parametrize('rcstack', custom_code, indirect=True)
+@pytest.mark.usefixtures(
+ "init_pyramid_app",
+ "repo_group_repos",
+ "disable_anonymous_user",
+ "disable_locking",
+)
+class TestVCSOperationsOnCustomAuthCode404(object):
-
-@pytest.mark.usefixtures("disable_locking", "disable_anonymous_user")
-class TestVCSOperationsOnCustomIniConfig(object):
-
- def test_clone_wrong_credentials_hg_ret_code(self, rc_web_server, tmpdir):
- clone_url = rc_web_server.repo_clone_url(HG_REPO, passwd='bad!')
- stdout, stderr = Command('/tmp').execute(
+ def test_clone_wrong_credentials_hg_ret_code(self, rcstack, tmpdir):
+ clone_url = rcstack.repo_clone_url(HG_REPO, passwd='bad!')
+ stdout, stderr = Command(tmpdir.strpath).execute(
'hg clone', clone_url, tmpdir.strpath)
assert 'abort: HTTP Error 404: Not Found' in stderr
- def test_clone_wrong_credentials_git_ret_code(self, rc_web_server, tmpdir):
- clone_url = rc_web_server.repo_clone_url(GIT_REPO, passwd='bad!')
- stdout, stderr = Command('/tmp').execute(
+ def test_clone_wrong_credentials_git_ret_code(self, rcstack, tmpdir):
+ clone_url = rcstack.repo_clone_url(GIT_REPO, passwd='bad!')
+ stdout, stderr = Command(tmpdir.strpath).execute(
'git clone', clone_url, tmpdir.strpath)
assert 'not found' in stderr
diff --git a/rhodecode/tests/vcs_operations/test_vcs_calls_custom_auth_code_bad_code.py b/rhodecode/tests/vcs_operations/test_vcs_calls_custom_auth_code_bad_code.py
index 9202aace..18610a4e 100644
--- a/rhodecode/tests/vcs_operations/test_vcs_calls_custom_auth_code_bad_code.py
+++ b/rhodecode/tests/vcs_operations/test_vcs_calls_custom_auth_code_bad_code.py
@@ -32,25 +32,27 @@ from rhodecode.tests import (GIT_REPO, HG_REPO)
from rhodecode.tests.vcs_operations import Command
-@pytest.fixture(scope="module")
-def rc_web_server_config_modification():
- return [
- {'app:main': {'auth_ret_code': '600'}},
- #{'app:main': {'auth_ret_code_detection': 'false'}},
- ]
+custom_code = [
+ {'app:main': {'auth_ret_code': '600'}},
+]
-
-@pytest.mark.usefixtures("disable_locking", "disable_anonymous_user")
+@pytest.mark.parametrize('rcstack', custom_code, indirect=True)
+@pytest.mark.usefixtures(
+ "init_pyramid_app",
+ "repo_group_repos",
+ "disable_anonymous_user",
+ "disable_locking",
+)
class TestVCSOperationsOnCustomIniConfig(object):
- def test_clone_wrong_credentials_hg_ret_code(self, rc_web_server, tmpdir):
- clone_url = rc_web_server.repo_clone_url(HG_REPO, passwd='bad!')
- stdout, stderr = Command('/tmp').execute(
+ def test_clone_wrong_credentials_hg_ret_code(self, rcstack, tmpdir):
+ clone_url = rcstack.repo_clone_url(HG_REPO, passwd='bad!')
+ stdout, stderr = Command(tmpdir.strpath).execute(
'hg clone', clone_url, tmpdir.strpath)
assert 'abort: authorization failed' in stderr
- def test_clone_wrong_credentials_git_ret_code(self, rc_web_server, tmpdir):
- clone_url = rc_web_server.repo_clone_url(GIT_REPO, passwd='bad!')
- stdout, stderr = Command('/tmp').execute(
+ def test_clone_wrong_credentials_git_ret_code(self, rcstack, tmpdir):
+ clone_url = rcstack.repo_clone_url(GIT_REPO, passwd='bad!')
+ stdout, stderr = Command(tmpdir.strpath).execute(
'git clone', clone_url, tmpdir.strpath)
assert 'fatal: Authentication failed' in stderr
diff --git a/rhodecode/tests/vcs_operations/test_vcs_calls_small_post_buffer.py b/rhodecode/tests/vcs_operations/test_vcs_calls_small_post_buffer.py
index b419622d..1b0b8aeb 100644
--- a/rhodecode/tests/vcs_operations/test_vcs_calls_small_post_buffer.py
+++ b/rhodecode/tests/vcs_operations/test_vcs_calls_small_post_buffer.py
@@ -1,4 +1,3 @@
-
# Copyright (C) 2010-2023 RhodeCode GmbH
#
# This program is free software: you can redistribute it and/or modify
@@ -20,13 +19,10 @@
"""
Test suite for making push/pull operations, on specially modified INI files
-.. important::
-
- You must have git >= 1.8.5 for tests to work fine. With 68b939b git started
- to redirect things to stderr instead of stdout.
"""
import os
+import pytest
from rhodecode.lib.vcs.backends.git.repository import GitRepository
from rhodecode.lib.vcs.nodes import FileNode
@@ -35,31 +31,39 @@ from rhodecode.tests.vcs_operations import Command
from .test_vcs_operations_git import _check_proper_clone, _check_proper_git_push
-def test_git_clone_with_small_push_buffer(backend_git, rc_web_server, tmpdir):
- clone_url = rc_web_server.repo_clone_url(GIT_REPO)
- cmd = Command('/tmp')
- stdout, stderr = cmd.execute(
- 'git -c http.postBuffer=1024 clone', clone_url, tmpdir.strpath)
- _check_proper_clone(stdout, stderr, 'git')
- cmd.assert_returncode_success()
+@pytest.mark.usefixtures(
+ "init_pyramid_app",
+ "repo_group_repos",
+ "disable_anonymous_user",
+ "disable_locking",
+)
+class TestVCSOperationsOnCustomIniConfig(object):
+
+ def test_git_clone_with_small_push_buffer(self, vcs_backend_git, rcstack, tmpdir):
+ clone_url = rcstack.repo_clone_url(GIT_REPO)
+ cmd = Command(tmpdir.strpath)
+ stdout, stderr = cmd.execute(
+ 'git -c http.postBuffer=1024 clone', clone_url, tmpdir.strpath)
+ _check_proper_clone(stdout, stderr, 'git')
+ cmd.assert_returncode_success()
-def test_git_push_with_small_push_buffer(backend_git, rc_web_server, tmpdir):
- empty_repo = backend_git.create_repo()
+ def test_git_push_with_small_push_buffer(self, vcs_backend_git, rcstack, tmpdir):
+ empty_repo = vcs_backend_git.create_repo()
- clone_url = rc_web_server.repo_clone_url(empty_repo.repo_name)
+ clone_url = rcstack.repo_clone_url(empty_repo.repo_name)
- cmd = Command(tmpdir.strpath)
- cmd.execute('git clone', clone_url)
+ cmd = Command(tmpdir.strpath)
+ cmd.execute('git clone', clone_url)
- repo = GitRepository(os.path.join(tmpdir.strpath, empty_repo.repo_name))
- repo.in_memory_commit.add(FileNode(b'readme.md', content=b'## Hello'))
- repo.in_memory_commit.commit(
- message='Commit on branch Master',
- author='Automatic test ',
- branch='master')
+ repo = GitRepository(os.path.join(tmpdir.strpath, empty_repo.repo_name))
+ repo.in_memory_commit.add(FileNode(b'readme.md', content=b'## Hello'))
+ repo.in_memory_commit.commit(
+ message='Commit on branch Master',
+ author='Automatic test ',
+ branch='master')
- repo_cmd = Command(repo.path)
- stdout, stderr = repo_cmd.execute(
- f'git -c http.postBuffer=1024 push --verbose {clone_url} master')
- _check_proper_git_push(stdout, stderr, branch='master')
+ repo_cmd = Command(repo.path)
+ stdout, stderr = repo_cmd.execute(
+ f'git -c http.postBuffer=1024 push --verbose {clone_url} master')
+ _check_proper_git_push(stdout, stderr, branch='master')
diff --git a/rhodecode/tests/vcs_operations/test_vcs_operations_bad_client.py b/rhodecode/tests/vcs_operations/test_vcs_operations_bad_client.py
new file mode 100644
index 00000000..514e3f19
--- /dev/null
+++ b/rhodecode/tests/vcs_operations/test_vcs_operations_bad_client.py
@@ -0,0 +1,89 @@
+# 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 .
+#
+# 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/
+
+"""
+Test suite for making push/pull operations, on specially modified INI files
+"""
+
+import pytest
+
+from rhodecode.model.meta import Session
+from rhodecode.model.settings import SettingsModel
+
+from rhodecode.tests import GIT_REPO, HG_REPO
+from rhodecode.tests.vcs_operations import Command, _add_files_and_push
+
+
+@pytest.fixture()
+def bad_client_setter_factory(request):
+ def _factory(client_type, client_str_val):
+ # set allowed clients
+ setting = SettingsModel().create_or_update_setting(name=f"{client_type}_allowed_clients", val=client_str_val)
+ Session().add(setting)
+ Session().commit()
+
+ @request.addfinalizer
+ def cleanup():
+ setting2 = SettingsModel().create_or_update_setting(name=f"{client_type}_allowed_clients", val="*")
+ Session().add(setting2)
+ Session().commit()
+
+ return _factory
+
+
+@pytest.mark.usefixtures(
+ "init_pyramid_app",
+ "repo_group_repos",
+ "disable_anonymous_user",
+ "disable_locking",
+)
+class TestVCSOperationsOnUsingBadClient(object):
+ def test_push_with_bad_client_repo_by_other_user_hg(self, rcstack, tmpdir):
+ clone_url = rcstack.repo_clone_url(HG_REPO)
+ stdout, stderr = Command(tmpdir.strpath).execute("hg clone", clone_url, tmpdir.strpath)
+
+ # set allowed clients
+ setting = SettingsModel().create_or_update_setting(name=f"hg_allowed_clients", val="0.0.0")
+ Session().add(setting)
+ Session().commit()
+
+ # push fails repo is locked by other user !
+ push_url = rcstack.repo_clone_url(HG_REPO)
+ stdout, stderr = _add_files_and_push("hg", tmpdir.strpath, clone_url=push_url)
+ msg = "Your hg client (ver=mercurial/proto-1.0 (Mercurial 6.7.4)) is forbidden by security rules"
+ assert msg in stderr
+
+ def test_push_with_bad_client_repo_by_other_user_git(self, rcstack, tmpdir):
+ clone_url = rcstack.repo_clone_url(GIT_REPO)
+ stdout, stderr = Command(tmpdir.strpath).execute("git clone", clone_url, tmpdir.strpath)
+
+ # set allowed clients
+ setting = SettingsModel().create_or_update_setting(name=f"git_allowed_clients", val="0.0.0")
+ Session().add(setting)
+ Session().commit()
+
+ # push fails repo is locked by other user!
+ push_url = rcstack.repo_clone_url(GIT_REPO)
+ stdout, stderr = _add_files_and_push("git", tmpdir.strpath, clone_url=push_url)
+
+ err = "Your git client (ver=git/2.45.2) is forbidden by security rules"
+ assert err in stderr
+
+ @pytest.mark.xfail(reason="Lack of proper SVN support of cloning")
+ def test_push_with_bad_client_repo_by_other_user_svn(self, rcstack, tmpdir):
+ raise NotImplementedError("lacks svn support")
diff --git a/rhodecode/tests/vcs_operations/test_vcs_operations_branch_protection.py b/rhodecode/tests/vcs_operations/test_vcs_operations_branch_protection.py
index 3b1be329..400fac8d 100644
--- a/rhodecode/tests/vcs_operations/test_vcs_operations_branch_protection.py
+++ b/rhodecode/tests/vcs_operations/test_vcs_operations_branch_protection.py
@@ -27,7 +27,12 @@ from rhodecode.tests.vcs_operations import (
Command, _check_proper_hg_push, _check_proper_git_push, _add_files_and_push)
-@pytest.mark.usefixtures("disable_anonymous_user")
+@pytest.mark.usefixtures(
+ "init_pyramid_app",
+ "repo_group_repos",
+ "disable_anonymous_user",
+ "disable_locking",
+)
class TestVCSOperations(object):
@pytest.mark.parametrize('username, password', [
@@ -41,13 +46,13 @@ class TestVCSOperations(object):
'branch.push_force',
])
def test_push_to_protected_branch_fails_with_message_hg(
- self, rc_web_server, tmpdir, branch_perm, user_util,
+ self, rcstack, tmpdir, branch_perm, user_util,
branch_permission_setter, username, password):
repo = user_util.create_repo(repo_type='hg')
repo_name = repo.repo_name
branch_permission_setter(repo_name, username, permission=branch_perm)
- clone_url = rc_web_server.repo_clone_url(
+ clone_url = rcstack.repo_clone_url(
repo.repo_name, user=username, passwd=password)
Command(os.path.dirname(tmpdir.strpath)).execute(
'hg clone', clone_url, tmpdir.strpath)
@@ -58,8 +63,8 @@ class TestVCSOperations(object):
_check_proper_hg_push(stdout, stderr)
else:
msg = f"Branch `default` changes rejected by rule `*`=>{branch_perm}"
- assert msg in stdout
- assert "transaction abort" in stdout
+ assert msg in stderr
+ #assert "transaction abort" in stdout
@pytest.mark.parametrize('username, password', [
(TEST_USER_ADMIN_LOGIN, TEST_USER_ADMIN_PASS),
@@ -72,13 +77,13 @@ class TestVCSOperations(object):
'branch.push_force',
])
def test_push_to_protected_branch_fails_with_message_git(
- self, rc_web_server, tmpdir, branch_perm, user_util,
+ self, rcstack, tmpdir, branch_perm, user_util,
branch_permission_setter, username, password):
repo = user_util.create_repo(repo_type='git')
repo_name = repo.repo_name
branch_permission_setter(repo_name, username, permission=branch_perm)
- clone_url = rc_web_server.repo_clone_url(
+ clone_url = rcstack.repo_clone_url(
repo.repo_name, user=username, passwd=password)
Command(os.path.dirname(tmpdir.strpath)).execute(
'git clone', clone_url, tmpdir.strpath)
diff --git a/rhodecode/tests/vcs_operations/test_vcs_operations_by_auth_tokens.py b/rhodecode/tests/vcs_operations/test_vcs_operations_by_auth_tokens.py
index 05c7ab7c..9890825a 100644
--- a/rhodecode/tests/vcs_operations/test_vcs_operations_by_auth_tokens.py
+++ b/rhodecode/tests/vcs_operations/test_vcs_operations_by_auth_tokens.py
@@ -1,5 +1,4 @@
-
-# Copyright (C) 2010-2023 RhodeCode GmbH
+# 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
@@ -20,10 +19,6 @@
"""
Test suite for making push/pull operations, on specially modified INI files
-.. important::
-
- You must have git >= 1.8.5 for tests to work fine. With 68b939b git started
- to redirect things to stderr instead of stdout.
"""
import pytest
@@ -36,10 +31,15 @@ from rhodecode.tests import (GIT_REPO, HG_REPO)
from rhodecode.tests.vcs_operations import (Command, _check_proper_clone)
-@pytest.mark.usefixtures("disable_locking", "disable_anonymous_user")
-class TestVCSOperations(object):
+@pytest.mark.usefixtures(
+ "init_pyramid_app",
+ "repo_group_repos",
+ "disable_anonymous_user",
+ "disable_locking",
+)
+class TestVCSOperationsByAuthTokens:
def test_clone_by_auth_token(
- self, rc_web_server, tmpdir, user_util, enable_auth_plugins):
+ self, rcstack, tmpdir, user_util, enable_auth_plugins):
enable_auth_plugins.enable([
'egg:rhodecode-enterprise-ce#token',
@@ -49,16 +49,16 @@ class TestVCSOperations(object):
user = user_util.create_user()
token = user.auth_tokens[1]
- clone_url = rc_web_server.repo_clone_url(
+ clone_url = rcstack.repo_clone_url(
HG_REPO, user=user.username, passwd=token)
- stdout, stderr = Command('/tmp').execute(
+ stdout, stderr = Command(tmpdir.strpath).execute(
'hg clone', clone_url, tmpdir.strpath)
_check_proper_clone(stdout, stderr, 'hg')
def test_clone_by_auth_token_expired(
- self, rc_web_server, tmpdir, user_util, enable_auth_plugins):
+ self, rcstack, tmpdir, user_util, enable_auth_plugins):
enable_auth_plugins.enable([
'egg:rhodecode-enterprise-ce#token',
'egg:rhodecode-enterprise-ce#rhodecode'
@@ -69,18 +69,18 @@ class TestVCSOperations(object):
user.user_id, 'test-token', -10, AuthTokenModel.cls.ROLE_VCS)
token = auth_token.api_key
- clone_url = rc_web_server.repo_clone_url(
+ clone_url = rcstack.repo_clone_url(
HG_REPO, user=user.username, passwd=token)
- stdout, stderr = Command('/tmp').execute(
+ stdout, stderr = Command(tmpdir.strpath).execute(
'hg clone', clone_url, tmpdir.strpath)
assert 'abort: authorization failed' in stderr
msg = 'reason: bad or inactive token.'
- rc_web_server.assert_message_in_server_logs(msg)
+ rcstack.assert_message_in_server_logs(msg)
def test_clone_by_auth_token_bad_role(
- self, rc_web_server, tmpdir, user_util, enable_auth_plugins):
+ self, rcstack, tmpdir, user_util, enable_auth_plugins):
enable_auth_plugins.enable([
'egg:rhodecode-enterprise-ce#token',
'egg:rhodecode-enterprise-ce#rhodecode'
@@ -91,15 +91,15 @@ class TestVCSOperations(object):
user.user_id, 'test-token', -1, AuthTokenModel.cls.ROLE_API)
token = auth_token.api_key
- clone_url = rc_web_server.repo_clone_url(
+ clone_url = rcstack.repo_clone_url(
HG_REPO, user=user.username, passwd=token)
- stdout, stderr = Command('/tmp').execute(
+ stdout, stderr = Command(tmpdir.strpath).execute(
'hg clone', clone_url, tmpdir.strpath)
assert 'abort: authorization failed' in stderr
def test_clone_by_auth_token_user_disabled(
- self, rc_web_server, tmpdir, user_util, enable_auth_plugins):
+ self, rcstack, tmpdir, user_util, enable_auth_plugins):
enable_auth_plugins.enable([
'egg:rhodecode-enterprise-ce#token',
'egg:rhodecode-enterprise-ce#rhodecode'
@@ -111,18 +111,18 @@ class TestVCSOperations(object):
Session().commit()
token = user.auth_tokens[1]
- clone_url = rc_web_server.repo_clone_url(
+ clone_url = rcstack.repo_clone_url(
HG_REPO, user=user.username, passwd=token)
- stdout, stderr = Command('/tmp').execute(
+ stdout, stderr = Command(tmpdir.strpath).execute(
'hg clone', clone_url, tmpdir.strpath)
assert 'abort: authorization failed' in stderr
msg = 'reason: account not active.'
- rc_web_server.assert_message_in_server_logs(msg)
+ rcstack.assert_message_in_server_logs(msg)
def test_clone_by_auth_token_with_scope(
- self, rc_web_server, tmpdir, user_util, enable_auth_plugins):
+ self, rcstack, tmpdir, user_util, enable_auth_plugins):
enable_auth_plugins.enable([
'egg:rhodecode-enterprise-ce#token',
'egg:rhodecode-enterprise-ce#rhodecode'
@@ -138,15 +138,15 @@ class TestVCSOperations(object):
Session().add(auth_token)
Session().commit()
- clone_url = rc_web_server.repo_clone_url(
+ clone_url = rcstack.repo_clone_url(
HG_REPO, user=user.username, passwd=token)
- stdout, stderr = Command('/tmp').execute(
+ stdout, stderr = Command(tmpdir.strpath).execute(
'hg clone', clone_url, tmpdir.strpath)
_check_proper_clone(stdout, stderr, 'hg')
def test_clone_by_auth_token_with_wrong_scope(
- self, rc_web_server, tmpdir, user_util, enable_auth_plugins):
+ self, rcstack, tmpdir, user_util, enable_auth_plugins):
enable_auth_plugins.enable([
'egg:rhodecode-enterprise-ce#token',
'egg:rhodecode-enterprise-ce#rhodecode'
@@ -162,13 +162,13 @@ class TestVCSOperations(object):
Session().add(auth_token)
Session().commit()
- clone_url = rc_web_server.repo_clone_url(
+ clone_url = rcstack.repo_clone_url(
HG_REPO, user=user.username, passwd=token)
- stdout, stderr = Command('/tmp').execute(
+ stdout, stderr = Command(tmpdir.strpath).execute(
'hg clone', clone_url, tmpdir.strpath)
assert 'abort: authorization failed' in stderr
msg = 'reason: bad or inactive token.'
- rc_web_server.assert_message_in_server_logs(msg)
+ rcstack.assert_message_in_server_logs(msg)
diff --git a/rhodecode/tests/vcs_operations/test_vcs_operations_clone.py b/rhodecode/tests/vcs_operations/test_vcs_operations_clone.py
new file mode 100644
index 00000000..04d6d6ba
--- /dev/null
+++ b/rhodecode/tests/vcs_operations/test_vcs_operations_clone.py
@@ -0,0 +1,63 @@
+
+# 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 .
+#
+# 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/
+
+"""
+Test suite for making push/pull operations, on specially modified INI files
+"""
+
+import pytest
+
+from rhodecode.tests import GIT_REPO, SVN_REPO, HG_REPO
+
+from rhodecode.tests.vcs_operations import (Command, _check_proper_clone)
+from rhodecode.tests.vcs_operations.test_vcs_operations_svn import get_cli_flags
+
+
+@pytest.mark.usefixtures(
+ "init_pyramid_app",
+ "repo_group_repos",
+ "disable_anonymous_user",
+ "disable_locking",
+)
+class TestVCSOperationsClone:
+
+ def test_clone_git_repo_by_admin(self, rcstack, tmpdir):
+ clone_url = rcstack.repo_clone_url(GIT_REPO)
+ cmd = Command(tmpdir.strpath)
+ stdout, stderr = cmd.execute('git clone', clone_url, tmpdir.strpath)
+ _check_proper_clone(stdout, stderr, 'git')
+ cmd.assert_returncode_success()
+
+ def test_clone_hg_repo_by_admin(self, rcstack, tmpdir):
+ clone_url = rcstack.repo_clone_url(HG_REPO)
+ cmd = Command(tmpdir.strpath)
+ stdout, stderr = cmd.execute('hg clone', clone_url, tmpdir.strpath)
+ _check_proper_clone(stdout, stderr, 'hg')
+ cmd.assert_returncode_success()
+
+ @pytest.mark.xfail(reason='Lack of proper SVN support of cloning')
+ def test_clone_svn_repo_by_admin(self, rcstack, tmpdir):
+ clone_url = rcstack.repo_clone_url(SVN_REPO)
+ username, password = rcstack.repo_clone_credentials()
+ flags, auth = get_cli_flags(username, password)
+ cmd = Command(tmpdir.strpath)
+ stdout, stderr = cmd.execute(
+ f'svn checkout {flags} {auth}', clone_url, tmpdir.strpath)
+ _check_proper_clone(stdout, stderr, 'svn')
+ cmd.assert_returncode_success()
diff --git a/rhodecode/tests/vcs_operations/test_vcs_operations_force_push.py b/rhodecode/tests/vcs_operations/test_vcs_operations_force_push.py
index b290c406..53469d95 100644
--- a/rhodecode/tests/vcs_operations/test_vcs_operations_force_push.py
+++ b/rhodecode/tests/vcs_operations/test_vcs_operations_force_push.py
@@ -1,4 +1,3 @@
-
# Copyright (C) 2010-2023 RhodeCode GmbH
#
# This program is free software: you can redistribute it and/or modify
@@ -27,12 +26,17 @@ from rhodecode.tests.vcs_operations import (
_add_files, _add_files_and_push)
-@pytest.mark.usefixtures("disable_anonymous_user")
+@pytest.mark.usefixtures(
+ "init_pyramid_app",
+ "repo_group_repos",
+ "disable_anonymous_user",
+ "disable_locking",
+)
class TestVCSOperations(object):
- def test_push_force_hg(self, rc_web_server, tmpdir, user_util):
+ def test_push_force_hg(self, rcstack, tmpdir, user_util):
repo = user_util.create_repo(repo_type='hg')
- clone_url = rc_web_server.repo_clone_url(repo.repo_name)
+ clone_url = rcstack.repo_clone_url(repo.repo_name)
Command(os.path.dirname(tmpdir.strpath)).execute(
'hg clone', clone_url, tmpdir.strpath)
@@ -50,9 +54,9 @@ class TestVCSOperations(object):
_check_proper_hg_push(stdout, stderr)
- def test_push_force_git(self, rc_web_server, tmpdir, user_util):
+ def test_push_force_git(self, rcstack, tmpdir, user_util):
repo = user_util.create_repo(repo_type='git')
- clone_url = rc_web_server.repo_clone_url(repo.repo_name)
+ clone_url = rcstack.repo_clone_url(repo.repo_name)
Command(os.path.dirname(tmpdir.strpath)).execute(
'git clone', clone_url, tmpdir.strpath)
@@ -69,13 +73,12 @@ class TestVCSOperations(object):
assert '(forced update)' in stderr
def test_push_force_hg_blocked_by_branch_permissions(
- self, rc_web_server, tmpdir, user_util, branch_permission_setter):
+ self, rcstack, tmpdir, user_util, branch_permission_setter):
repo = user_util.create_repo(repo_type='hg')
repo_name = repo.repo_name
username = TEST_USER_ADMIN_LOGIN
- branch_permission_setter(repo_name, username, permission='branch.push')
- clone_url = rc_web_server.repo_clone_url(repo.repo_name)
+ clone_url = rcstack.repo_clone_url(repo.repo_name)
Command(os.path.dirname(tmpdir.strpath)).execute(
'hg clone', clone_url, tmpdir.strpath)
@@ -88,21 +91,21 @@ class TestVCSOperations(object):
'hg checkout -r 1 && hg commit -m "starting new head"')
_add_files('hg', tmpdir.strpath, clone_url=clone_url)
+ branch_permission_setter(repo_name, username, permission='branch.push')
stdout, stderr = Command(tmpdir.strpath).execute(
f'hg push --verbose -f {clone_url}')
- assert "Branch `default` changes rejected by rule `*`=>branch.push" in stdout
- assert "FORCE PUSH FORBIDDEN" in stdout
- assert "transaction abort" in stdout
+ assert "Branch `default` changes rejected by rule `*`=>branch.push" in stderr
+ assert "FORCE PUSH FORBIDDEN" in stderr
def test_push_force_git_blocked_by_branch_permissions(
- self, rc_web_server, tmpdir, user_util, branch_permission_setter):
+ self, rcstack, tmpdir, user_util, branch_permission_setter):
repo = user_util.create_repo(repo_type='git')
repo_name = repo.repo_name
username = TEST_USER_ADMIN_LOGIN
branch_permission_setter(repo_name, username, permission='branch.push')
- clone_url = rc_web_server.repo_clone_url(repo.repo_name)
+ clone_url = rcstack.repo_clone_url(repo.repo_name)
Command(os.path.dirname(tmpdir.strpath)).execute(
'git clone', clone_url, tmpdir.strpath)
diff --git a/rhodecode/tests/vcs_operations/test_vcs_operations_git.py b/rhodecode/tests/vcs_operations/test_vcs_operations_git.py
index d8d85cda..561da0e1 100644
--- a/rhodecode/tests/vcs_operations/test_vcs_operations_git.py
+++ b/rhodecode/tests/vcs_operations/test_vcs_operations_git.py
@@ -25,8 +25,6 @@ Test suite for making push/pull operations, on specially modified INI files
You must have git >= 1.8.5 for tests to work fine. With 68b939b git started
to redirect things to stderr instead of stdout.
"""
-
-
import time
import pytest
@@ -42,41 +40,46 @@ from rhodecode.tests.vcs_operations import (
_add_files_and_push, GIT_REPO_WITH_GROUP)
-@pytest.mark.usefixtures("disable_locking", "disable_anonymous_user")
-class TestVCSOperations(object):
+@pytest.mark.usefixtures(
+ "init_pyramid_app",
+ "repo_group_repos",
+ "disable_anonymous_user",
+ "disable_locking",
+)
+class TestVCSOperationsGit:
- def test_clone_git_repo_by_admin(self, rc_web_server, tmpdir):
- clone_url = rc_web_server.repo_clone_url(GIT_REPO)
- cmd = Command('/tmp')
+ def test_clone_git_repo_by_admin(self, rcstack, tmpdir):
+ clone_url = rcstack.repo_clone_url(GIT_REPO)
+ cmd = Command(tmpdir.strpath)
stdout, stderr = cmd.execute('git clone', clone_url, tmpdir.strpath)
_check_proper_clone(stdout, stderr, 'git')
cmd.assert_returncode_success()
- def test_clone_git_repo_by_admin_with_git_suffix(self, rc_web_server, tmpdir):
- clone_url = rc_web_server.repo_clone_url(GIT_REPO)
- cmd = Command('/tmp')
+ def test_clone_git_repo_by_admin_with_git_suffix(self, rcstack, tmpdir):
+ clone_url = rcstack.repo_clone_url(GIT_REPO)
+ cmd = Command(tmpdir.strpath)
stdout, stderr = cmd.execute('git clone', clone_url+".git", tmpdir.strpath)
_check_proper_clone(stdout, stderr, 'git')
cmd.assert_returncode_success()
- def test_clone_git_repo_by_id_by_admin(self, rc_web_server, tmpdir):
+ def test_clone_git_repo_by_id_by_admin(self, rcstack, tmpdir):
repo_id = Repository.get_by_repo_name(GIT_REPO).repo_id
- clone_url = rc_web_server.repo_clone_url('_%s' % repo_id)
- cmd = Command('/tmp')
+ clone_url = rcstack.repo_clone_url('_%s' % repo_id)
+ cmd = Command(tmpdir.strpath)
stdout, stderr = cmd.execute('git clone', clone_url, tmpdir.strpath)
_check_proper_clone(stdout, stderr, 'git')
cmd.assert_returncode_success()
- def test_clone_git_repo_with_group_by_admin(self, rc_web_server, tmpdir):
- clone_url = rc_web_server.repo_clone_url(GIT_REPO_WITH_GROUP)
- cmd = Command('/tmp')
+ def test_clone_git_repo_with_group_by_admin(self, rcstack, tmpdir):
+ clone_url = rcstack.repo_clone_url(GIT_REPO_WITH_GROUP)
+ cmd = Command(tmpdir.strpath)
stdout, stderr = cmd.execute('git clone', clone_url, tmpdir.strpath)
_check_proper_clone(stdout, stderr, 'git')
cmd.assert_returncode_success()
- def test_clone_git_repo_shallow_by_admin(self, rc_web_server, tmpdir):
- clone_url = rc_web_server.repo_clone_url(GIT_REPO)
- cmd = Command('/tmp')
+ def test_clone_git_repo_shallow_by_admin(self, rcstack, tmpdir):
+ clone_url = rcstack.repo_clone_url(GIT_REPO)
+ cmd = Command(tmpdir.strpath)
stdout, stderr = cmd.execute(
'git clone --depth=1', clone_url, tmpdir.strpath)
@@ -84,65 +87,64 @@ class TestVCSOperations(object):
assert 'Cloning into' in stderr
cmd.assert_returncode_success()
-
- def test_clone_wrong_credentials_git(self, rc_web_server, tmpdir):
- clone_url = rc_web_server.repo_clone_url(GIT_REPO, passwd='bad!')
- stdout, stderr = Command('/tmp').execute(
+ def test_clone_wrong_credentials_git(self, rcstack, tmpdir):
+ clone_url = rcstack.repo_clone_url(GIT_REPO, passwd='bad!')
+ stdout, stderr = Command(tmpdir.strpath).execute(
'git clone', clone_url, tmpdir.strpath)
assert 'fatal: Authentication failed' in stderr
- def test_clone_git_dir_as_hg(self, rc_web_server, tmpdir):
- clone_url = rc_web_server.repo_clone_url(GIT_REPO)
- stdout, stderr = Command('/tmp').execute(
+ def test_clone_git_dir_as_hg(self, rcstack, tmpdir):
+ clone_url = rcstack.repo_clone_url(GIT_REPO)
+ stdout, stderr = Command(tmpdir.strpath).execute(
'hg clone', clone_url, tmpdir.strpath)
assert 'HTTP Error 404: Not Found' in stderr
- def test_clone_non_existing_path_hg(self, rc_web_server, tmpdir):
- clone_url = rc_web_server.repo_clone_url('trololo')
- stdout, stderr = Command('/tmp').execute(
+ def test_clone_non_existing_path_hg(self, rcstack, tmpdir):
+ clone_url = rcstack.repo_clone_url('trololo')
+ stdout, stderr = Command(tmpdir.strpath).execute(
'hg clone', clone_url, tmpdir.strpath)
assert 'HTTP Error 404: Not Found' in stderr
- def test_clone_non_existing_path_git(self, rc_web_server, tmpdir):
- clone_url = rc_web_server.repo_clone_url('trololo')
- stdout, stderr = Command('/tmp').execute('git clone', clone_url)
+ def test_clone_non_existing_path_git(self, rcstack, tmpdir):
+ clone_url = rcstack.repo_clone_url('trololo')
+ stdout, stderr = Command(tmpdir.strpath).execute('git clone', clone_url)
assert 'not found' in stderr
- def test_clone_git_with_slashes(self, rc_web_server, tmpdir):
- clone_url = rc_web_server.repo_clone_url('//' + GIT_REPO)
- stdout, stderr = Command('/tmp').execute('git clone', clone_url)
+ def test_clone_git_with_slashes(self, rcstack, tmpdir):
+ clone_url = rcstack.repo_clone_url('//' + GIT_REPO)
+ stdout, stderr = Command(tmpdir.strpath).execute('git clone', clone_url)
assert 'not found' in stderr
def test_clone_existing_path_git_not_in_database(
- self, rc_web_server, tmpdir, fs_repo_only):
+ self, rcstack, tmpdir, fs_repo_only):
db_name = fs_repo_only('not-in-db-git', repo_type='git')
- clone_url = rc_web_server.repo_clone_url(db_name)
- stdout, stderr = Command('/tmp').execute(
+ clone_url = rcstack.repo_clone_url(db_name)
+ stdout, stderr = Command(tmpdir.strpath).execute(
'git clone', clone_url, tmpdir.strpath)
assert 'not found' in stderr
def test_clone_existing_path_git_not_in_database_different_scm(
- self, rc_web_server, tmpdir, fs_repo_only):
+ self, rcstack, tmpdir, fs_repo_only):
db_name = fs_repo_only('not-in-db-hg', repo_type='hg')
- clone_url = rc_web_server.repo_clone_url(db_name)
- stdout, stderr = Command('/tmp').execute(
+ clone_url = rcstack.repo_clone_url(db_name)
+ stdout, stderr = Command(tmpdir.strpath).execute(
'git clone', clone_url, tmpdir.strpath)
assert 'not found' in stderr
- def test_clone_non_existing_store_path_git(self, rc_web_server, tmpdir, user_util):
+ def test_clone_non_existing_store_path_git(self, rcstack, tmpdir, user_util):
repo = user_util.create_repo(repo_type='git')
- clone_url = rc_web_server.repo_clone_url(repo.repo_name)
+ clone_url = rcstack.repo_clone_url(repo.repo_name)
# Damage repo by removing it's folder
RepoModel()._delete_filesystem_repo(repo)
- stdout, stderr = Command('/tmp').execute(
+ stdout, stderr = Command(tmpdir.strpath).execute(
'git clone', clone_url, tmpdir.strpath)
assert 'not found' in stderr
- def test_push_new_file_git(self, rc_web_server, tmpdir):
- clone_url = rc_web_server.repo_clone_url(GIT_REPO)
- stdout, stderr = Command('/tmp').execute(
+ def test_push_new_file_git(self, rcstack, tmpdir):
+ clone_url = rcstack.repo_clone_url(GIT_REPO)
+ stdout, stderr = Command(tmpdir.strpath).execute(
'git clone', clone_url, tmpdir.strpath)
# commit some stuff into this repo
@@ -151,37 +153,37 @@ class TestVCSOperations(object):
_check_proper_git_push(stdout, stderr)
- def test_push_wrong_credentials_git(self, rc_web_server, tmpdir):
- clone_url = rc_web_server.repo_clone_url(GIT_REPO)
- stdout, stderr = Command('/tmp').execute(
+ def test_push_wrong_credentials_git(self, rcstack, tmpdir):
+ clone_url = rcstack.repo_clone_url(GIT_REPO)
+ stdout, stderr = Command(tmpdir.strpath).execute(
'git clone', clone_url, tmpdir.strpath)
- push_url = rc_web_server.repo_clone_url(
+ push_url = rcstack.repo_clone_url(
GIT_REPO, user='bad', passwd='name')
stdout, stderr = _add_files_and_push(
'git', tmpdir.strpath, clone_url=push_url)
assert 'fatal: Authentication failed' in stderr
- def test_push_back_to_wrong_url_git(self, rc_web_server, tmpdir):
- clone_url = rc_web_server.repo_clone_url(GIT_REPO)
- stdout, stderr = Command('/tmp').execute(
+ def test_push_back_to_wrong_url_git(self, rcstack, tmpdir):
+ clone_url = rcstack.repo_clone_url(GIT_REPO)
+ stdout, stderr = Command(tmpdir.strpath).execute(
'git clone', clone_url, tmpdir.strpath)
stdout, stderr = _add_files_and_push(
'git', tmpdir.strpath,
- clone_url=rc_web_server.repo_clone_url('not-existing'))
+ clone_url=rcstack.repo_clone_url('not-existing'))
assert 'not found' in stderr
- def test_ip_restriction_git(self, rc_web_server, tmpdir):
+ def test_ip_restriction_git(self, rcstack, tmpdir):
user_model = UserModel()
try:
user_model.add_extra_ip(TEST_USER_ADMIN_LOGIN, '10.10.10.10/32')
Session().commit()
time.sleep(2)
- clone_url = rc_web_server.repo_clone_url(GIT_REPO)
- stdout, stderr = Command('/tmp').execute(
+ clone_url = rcstack.repo_clone_url(GIT_REPO)
+ stdout, stderr = Command(tmpdir.strpath).execute(
'git clone', clone_url, tmpdir.strpath)
msg = "The requested URL returned error: 403"
assert msg in stderr
@@ -193,7 +195,7 @@ class TestVCSOperations(object):
time.sleep(2)
- cmd = Command('/tmp')
+ cmd = Command(tmpdir.strpath)
stdout, stderr = cmd.execute('git clone', clone_url, tmpdir.strpath)
cmd.assert_returncode_success()
_check_proper_clone(stdout, stderr, 'git')
diff --git a/rhodecode/tests/vcs_operations/test_vcs_operations_hg.py b/rhodecode/tests/vcs_operations/test_vcs_operations_hg.py
index 74d8e035..ae9a47e7 100644
--- a/rhodecode/tests/vcs_operations/test_vcs_operations_hg.py
+++ b/rhodecode/tests/vcs_operations/test_vcs_operations_hg.py
@@ -1,5 +1,4 @@
-
-# Copyright (C) 2010-2023 RhodeCode GmbH
+# 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
@@ -19,11 +18,6 @@
"""
Test suite for making push/pull operations, on specially modified INI files
-
-.. important::
-
- You must have git >= 1.8.5 for tests to work fine. With 68b939b git started
- to redirect things to stderr instead of stdout.
"""
@@ -42,96 +36,101 @@ from rhodecode.tests.vcs_operations import (
Command, _check_proper_clone, _add_files_and_push, HG_REPO_WITH_GROUP)
-@pytest.mark.usefixtures("disable_locking", "disable_anonymous_user")
-class TestVCSOperations(object):
+@pytest.mark.usefixtures(
+ "init_pyramid_app",
+ "repo_group_repos",
+ "disable_anonymous_user",
+ "disable_locking",
+)
+class TestVCSOperationsHg(object):
- def test_clone_hg_repo_by_admin(self, rc_web_server, tmpdir):
- clone_url = rc_web_server.repo_clone_url(HG_REPO)
- stdout, stderr = Command('/tmp').execute(
+ def test_clone_hg_repo_by_admin(self, rcstack, tmpdir):
+ clone_url = rcstack.repo_clone_url(HG_REPO)
+ stdout, stderr = Command(tmpdir.strpath).execute(
'hg clone', clone_url, tmpdir.strpath)
_check_proper_clone(stdout, stderr, 'hg')
- def test_clone_hg_repo_by_admin_pull_protocol(self, rc_web_server, tmpdir):
- clone_url = rc_web_server.repo_clone_url(HG_REPO)
- stdout, stderr = Command('/tmp').execute(
+ def test_clone_hg_repo_by_admin_pull_protocol(self, rcstack, tmpdir):
+ clone_url = rcstack.repo_clone_url(HG_REPO)
+ stdout, stderr = Command(tmpdir.strpath).execute(
'hg clone --pull', clone_url, tmpdir.strpath)
_check_proper_clone(stdout, stderr, 'hg')
- def test_clone_hg_repo_by_admin_pull_stream_protocol(self, rc_web_server, tmpdir):
- clone_url = rc_web_server.repo_clone_url(HG_REPO)
- stdout, stderr = Command('/tmp').execute(
+ def test_clone_hg_repo_by_admin_pull_stream_protocol(self, rcstack, tmpdir):
+ clone_url = rcstack.repo_clone_url(HG_REPO)
+ stdout, stderr = Command(tmpdir.strpath).execute(
'hg clone --pull --stream', clone_url, tmpdir.strpath)
assert 'files to transfer,' in stdout
assert 'transferred 1.' in stdout
assert '114 files updated,' in stdout
- def test_clone_hg_repo_by_id_by_admin(self, rc_web_server, tmpdir):
+ def test_clone_hg_repo_by_id_by_admin(self, rcstack, tmpdir):
repo_id = Repository.get_by_repo_name(HG_REPO).repo_id
- clone_url = rc_web_server.repo_clone_url('_%s' % repo_id)
- stdout, stderr = Command('/tmp').execute(
+ clone_url = rcstack.repo_clone_url('_%s' % repo_id)
+ stdout, stderr = Command(tmpdir.strpath).execute(
'hg clone', clone_url, tmpdir.strpath)
_check_proper_clone(stdout, stderr, 'hg')
- def test_clone_hg_repo_with_group_by_admin(self, rc_web_server, tmpdir):
- clone_url = rc_web_server.repo_clone_url(HG_REPO_WITH_GROUP)
- stdout, stderr = Command('/tmp').execute(
+ def test_clone_hg_repo_with_group_by_admin(self, rcstack, tmpdir):
+ clone_url = rcstack.repo_clone_url(HG_REPO_WITH_GROUP)
+ stdout, stderr = Command(tmpdir.strpath).execute(
'hg clone', clone_url, tmpdir.strpath)
_check_proper_clone(stdout, stderr, 'hg')
- def test_clone_wrong_credentials_hg(self, rc_web_server, tmpdir):
- clone_url = rc_web_server.repo_clone_url(HG_REPO, passwd='bad!')
- stdout, stderr = Command('/tmp').execute(
+ def test_clone_wrong_credentials_hg(self, rcstack, tmpdir):
+ clone_url = rcstack.repo_clone_url(HG_REPO, passwd='bad!')
+ stdout, stderr = Command(tmpdir.strpath).execute(
'hg clone', clone_url, tmpdir.strpath)
assert 'abort: authorization failed' in stderr
- def test_clone_git_dir_as_hg(self, rc_web_server, tmpdir):
- clone_url = rc_web_server.repo_clone_url(GIT_REPO)
- stdout, stderr = Command('/tmp').execute(
+ def test_clone_git_dir_as_hg(self, rcstack, tmpdir):
+ clone_url = rcstack.repo_clone_url(GIT_REPO)
+ stdout, stderr = Command(tmpdir.strpath).execute(
'hg clone', clone_url, tmpdir.strpath)
assert 'HTTP Error 404: Not Found' in stderr
- def test_clone_non_existing_path_hg(self, rc_web_server, tmpdir):
- clone_url = rc_web_server.repo_clone_url('trololo')
- stdout, stderr = Command('/tmp').execute(
+ def test_clone_non_existing_path_hg(self, rcstack, tmpdir):
+ clone_url = rcstack.repo_clone_url('trololo')
+ stdout, stderr = Command(tmpdir.strpath).execute(
'hg clone', clone_url, tmpdir.strpath)
assert 'HTTP Error 404: Not Found' in stderr
- def test_clone_hg_with_slashes(self, rc_web_server, tmpdir):
- clone_url = rc_web_server.repo_clone_url('//' + HG_REPO)
- stdout, stderr = Command('/tmp').execute('hg clone', clone_url, tmpdir.strpath)
+ def test_clone_hg_with_slashes(self, rcstack, tmpdir):
+ clone_url = rcstack.repo_clone_url('//' + HG_REPO)
+ stdout, stderr = Command(tmpdir.strpath).execute('hg clone', clone_url, tmpdir.strpath)
assert 'HTTP Error 404: Not Found' in stderr
def test_clone_existing_path_hg_not_in_database(
- self, rc_web_server, tmpdir, fs_repo_only):
+ self, rcstack, tmpdir, fs_repo_only):
db_name = fs_repo_only('not-in-db-hg', repo_type='hg')
- clone_url = rc_web_server.repo_clone_url(db_name)
- stdout, stderr = Command('/tmp').execute(
+ clone_url = rcstack.repo_clone_url(db_name)
+ stdout, stderr = Command(tmpdir.strpath).execute(
'hg clone', clone_url, tmpdir.strpath)
assert 'HTTP Error 404: Not Found' in stderr
def test_clone_existing_path_hg_not_in_database_different_scm(
- self, rc_web_server, tmpdir, fs_repo_only):
+ self, rcstack, tmpdir, fs_repo_only):
db_name = fs_repo_only('not-in-db-git', repo_type='git')
- clone_url = rc_web_server.repo_clone_url(db_name)
- stdout, stderr = Command('/tmp').execute(
+ clone_url = rcstack.repo_clone_url(db_name)
+ stdout, stderr = Command(tmpdir.strpath).execute(
'hg clone', clone_url, tmpdir.strpath)
assert 'HTTP Error 404: Not Found' in stderr
- def test_clone_non_existing_store_path_hg(self, rc_web_server, tmpdir, user_util):
+ def test_clone_non_existing_store_path_hg(self, rcstack, tmpdir, user_util):
repo = user_util.create_repo()
- clone_url = rc_web_server.repo_clone_url(repo.repo_name)
+ clone_url = rcstack.repo_clone_url(repo.repo_name)
# Damage repo by removing it's folder
RepoModel()._delete_filesystem_repo(repo)
- stdout, stderr = Command('/tmp').execute(
+ stdout, stderr = Command(tmpdir.strpath).execute(
'hg clone', clone_url, tmpdir.strpath)
assert 'HTTP Error 404: Not Found' in stderr
- def test_push_new_file_hg(self, rc_web_server, tmpdir):
- clone_url = rc_web_server.repo_clone_url(HG_REPO)
- stdout, stderr = Command('/tmp').execute(
+ def test_push_new_file_hg(self, rcstack, tmpdir):
+ clone_url = rcstack.repo_clone_url(HG_REPO)
+ stdout, stderr = Command(tmpdir.strpath).execute(
'hg clone', clone_url, tmpdir.strpath)
stdout, stderr = _add_files_and_push(
@@ -140,7 +139,7 @@ class TestVCSOperations(object):
assert 'pushing to' in stdout
assert 'size summary' in stdout
- def test_push_invalidates_cache(self, rc_web_server, tmpdir):
+ def test_push_invalidates_cache(self, rcstack, tmpdir):
hg_repo = Repository.get_by_repo_name(HG_REPO)
# init cache objects
@@ -159,8 +158,8 @@ class TestVCSOperations(object):
old_ids = [x.cache_state_uid for x in cache_keys]
# clone to init cache
- clone_url = rc_web_server.repo_clone_url(hg_repo.repo_name)
- stdout, stderr = Command('/tmp').execute(
+ clone_url = rcstack.repo_clone_url(hg_repo.repo_name)
+ stdout, stderr = Command(tmpdir.strpath).execute(
'hg clone', clone_url, tmpdir.strpath)
cache_keys = hg_repo.cache_keys
@@ -180,37 +179,37 @@ class TestVCSOperations(object):
new_ids = [x.cache_state_uid for x in cache_keys]
assert new_ids != old_ids
- def test_push_wrong_credentials_hg(self, rc_web_server, tmpdir):
- clone_url = rc_web_server.repo_clone_url(HG_REPO)
- stdout, stderr = Command('/tmp').execute(
+ def test_push_wrong_credentials_hg(self, rcstack, tmpdir):
+ clone_url = rcstack.repo_clone_url(HG_REPO)
+ stdout, stderr = Command(tmpdir.strpath).execute(
'hg clone', clone_url, tmpdir.strpath)
- push_url = rc_web_server.repo_clone_url(
+ push_url = rcstack.repo_clone_url(
HG_REPO, user='bad', passwd='name')
stdout, stderr = _add_files_and_push(
'hg', tmpdir.strpath, clone_url=push_url)
assert 'abort: authorization failed' in stderr
- def test_push_back_to_wrong_url_hg(self, rc_web_server, tmpdir):
- clone_url = rc_web_server.repo_clone_url(HG_REPO)
- stdout, stderr = Command('/tmp').execute(
+ def test_push_back_to_wrong_url_hg(self, rcstack, tmpdir):
+ clone_url = rcstack.repo_clone_url(HG_REPO)
+ stdout, stderr = Command(tmpdir.strpath).execute(
'hg clone', clone_url, tmpdir.strpath)
stdout, stderr = _add_files_and_push(
'hg', tmpdir.strpath,
- clone_url=rc_web_server.repo_clone_url('not-existing'))
+ clone_url=rcstack.repo_clone_url('not-existing'))
assert 'HTTP Error 404: Not Found' in stderr
- def test_ip_restriction_hg(self, rc_web_server, tmpdir):
+ def test_ip_restriction_hg(self, rcstack, tmpdir):
user_model = UserModel()
try:
user_model.add_extra_ip(TEST_USER_ADMIN_LOGIN, '10.10.10.10/32')
Session().commit()
time.sleep(2)
- clone_url = rc_web_server.repo_clone_url(HG_REPO)
- stdout, stderr = Command('/tmp').execute(
+ clone_url = rcstack.repo_clone_url(HG_REPO)
+ stdout, stderr = Command(tmpdir.strpath).execute(
'hg clone', clone_url, tmpdir.strpath)
assert 'abort: HTTP Error 403: Forbidden' in stderr
finally:
@@ -221,6 +220,6 @@ class TestVCSOperations(object):
time.sleep(2)
- stdout, stderr = Command('/tmp').execute(
+ stdout, stderr = Command(tmpdir.strpath).execute(
'hg clone', clone_url, tmpdir.strpath)
_check_proper_clone(stdout, stderr, 'hg')
diff --git a/rhodecode/tests/vcs_operations/test_vcs_operations_integrations_trigger.py b/rhodecode/tests/vcs_operations/test_vcs_operations_integrations_trigger.py
index f9d918c3..c316fd2f 100644
--- a/rhodecode/tests/vcs_operations/test_vcs_operations_integrations_trigger.py
+++ b/rhodecode/tests/vcs_operations/test_vcs_operations_integrations_trigger.py
@@ -1,4 +1,3 @@
-
# Copyright (C) 2010-2023 RhodeCode GmbH
#
# This program is free software: you can redistribute it and/or modify
@@ -19,11 +18,6 @@
"""
Test suite for making push/pull operations, on specially modified INI files
-
-.. important::
-
- You must have git >= 1.8.5 for tests to work fine. With 68b939b git started
- to redirect things to stderr instead of stdout.
"""
import pytest
@@ -37,32 +31,41 @@ from rhodecode.tests.vcs_operations.conftest import check_httpbin_connection
connection_available = pytest.mark.skipif(
not check_httpbin_connection(), reason="No outside internet connection available")
+@pytest.mark.usefixtures(
+ "init_pyramid_app",
+ "repo_group_repos",
+ "disable_anonymous_user",
+ "disable_locking",
+ "enable_webhook_push_integration"
+)
+class TestVCSOperationsOnIntegrationsTrigger(object):
-@pytest.mark.usefixtures("baseapp", "enable_webhook_push_integration")
-class TestVCSOperationsOnCustomIniConfig(object):
+ def test_push_with_webhook_hg(self, rcstack, tmpdir):
+ clone_url = rcstack.repo_clone_url(HG_REPO)
- def test_push_with_webhook_hg(self, rc_web_server, tmpdir):
- clone_url = rc_web_server.repo_clone_url(HG_REPO)
+ Command(tmpdir.strpath).execute('hg clone', clone_url, tmpdir.strpath)
- Command('/tmp').execute('hg clone', clone_url, tmpdir.strpath)
-
- push_url = rc_web_server.repo_clone_url(HG_REPO)
+ push_url = rcstack.repo_clone_url(HG_REPO)
_add_files_and_push('hg', tmpdir.strpath, clone_url=push_url)
- rc_log = rc_web_server.get_rc_log()
- assert 'ERROR' not in rc_log
- assert "executing task TASK:<@task: rhodecode.integrations.types.webhook.post_to_webhook" in rc_log
- assert "handling event repo-push with integration = 1.8.5 for tests to work fine. With 68b939b git started
- to redirect things to stderr instead of stdout.
"""
-
import pytest
from rhodecode.model.db import User, Repository
from rhodecode.model.meta import Session
from rhodecode.model.repo import RepoModel
-from rhodecode.tests import (
- GIT_REPO, HG_REPO, TEST_USER_ADMIN_LOGIN, TEST_USER_REGULAR_LOGIN,
- TEST_USER_REGULAR_PASS)
-from rhodecode.tests.vcs_operations import (
- Command, _check_proper_clone, _check_proper_git_push, _add_files_and_push)
+from rhodecode.tests import GIT_REPO, HG_REPO, TEST_USER_ADMIN_LOGIN, TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS
+from rhodecode.tests.vcs_operations import Command, _check_proper_clone, _check_proper_git_push, _add_files_and_push
-@pytest.fixture(scope="module")
-def rc_web_server_config_modification():
- return [
- {'app:main': {'lock_ret_code': '423'}},
- ]
+custom_code = [
+ {'app:main': {'auth_ret_code': '423'}},
+]
-
-@pytest.mark.usefixtures("disable_locking", "disable_anonymous_user")
-class TestVCSOperationsOnCustomIniConfig(object):
-
- def test_clone_and_create_lock_hg(self, rc_web_server, tmpdir):
+@pytest.mark.parametrize('rcstack', custom_code, indirect=True)
+@pytest.mark.usefixtures(
+ "init_pyramid_app",
+ "repo_group_repos",
+ "disable_anonymous_user",
+ "disable_locking",
+)
+class TestVCSOperationsOnLockingRepos(object):
+ def test_clone_and_create_lock_hg(self, rcstack, tmpdir):
# enable locking
r = Repository.get_by_repo_name(HG_REPO)
r.enable_locking = True
Session().add(r)
Session().commit()
# clone
- clone_url = rc_web_server.repo_clone_url(HG_REPO)
- stdout, stderr = Command('/tmp').execute(
- 'hg clone', clone_url, tmpdir.strpath)
+ clone_url = rcstack.repo_clone_url(HG_REPO)
+ stdout, stderr = Command(tmpdir.strpath).execute("hg clone", clone_url, tmpdir.strpath)
# check if lock was made
r = Repository.get_by_repo_name(HG_REPO)
- assert r.locked[0] == User.get_by_username(
- TEST_USER_ADMIN_LOGIN).user_id
+ assert r.locked[0] == User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id
- def test_clone_and_create_lock_git(self, rc_web_server, tmpdir):
+ def test_clone_and_create_lock_git(self, rcstack, tmpdir):
# enable locking
r = Repository.get_by_repo_name(GIT_REPO)
r.enable_locking = True
Session().add(r)
Session().commit()
# clone
- clone_url = rc_web_server.repo_clone_url(GIT_REPO)
- stdout, stderr = Command('/tmp').execute(
- 'git clone', clone_url, tmpdir.strpath)
+ clone_url = rcstack.repo_clone_url(GIT_REPO)
+ stdout, stderr = Command(tmpdir.strpath).execute("git clone", clone_url, tmpdir.strpath)
# check if lock was made
r = Repository.get_by_repo_name(GIT_REPO)
- assert r.locked[0] == User.get_by_username(
- TEST_USER_ADMIN_LOGIN).user_id
+ assert r.locked[0] == User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id
- def test_clone_after_repo_was_locked_hg(self, rc_web_server, tmpdir):
+ def test_clone_after_repo_was_locked_hg(self, rcstack, tmpdir):
# lock repo
r = Repository.get_by_repo_name(HG_REPO)
Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id)
# pull fails since repo is locked
- clone_url = rc_web_server.repo_clone_url(HG_REPO)
- stdout, stderr = Command('/tmp').execute(
- 'hg clone', clone_url, tmpdir.strpath)
- msg = ("""abort: HTTP Error 423: Repository `%s` locked by user `%s`"""
- % (HG_REPO, TEST_USER_ADMIN_LOGIN))
+ clone_url = rcstack.repo_clone_url(HG_REPO)
+ stdout, stderr = Command(tmpdir.strpath).execute("hg clone", clone_url, tmpdir.strpath)
+ msg = f"abort: HTTP Error 423: Repository `{HG_REPO}` locked by user `{TEST_USER_ADMIN_LOGIN}`"
assert msg in stderr
- def test_clone_after_repo_was_locked_git(self, rc_web_server, tmpdir):
+ def test_clone_after_repo_was_locked_git(self, rcstack, tmpdir):
# lock repo
r = Repository.get_by_repo_name(GIT_REPO)
Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id)
# pull fails since repo is locked
- clone_url = rc_web_server.repo_clone_url(GIT_REPO)
- stdout, stderr = Command('/tmp').execute(
- 'git clone', clone_url, tmpdir.strpath)
+ clone_url = rcstack.repo_clone_url(GIT_REPO)
+ stdout, stderr = Command(tmpdir.strpath).execute("git clone", clone_url, tmpdir.strpath)
- lock_msg = (
- 'remote: ERROR: Repository `vcs_test_git` locked by user ' +
- '`test_admin`. Reason:`lock_auto`')
+ lock_msg = "remote: ERROR: Repository `vcs_test_git` locked by user `test_admin`. Reason:`lock_auto`"
assert lock_msg in stderr
- assert 'remote: Pre pull hook failed: aborting' in stderr
- assert 'fatal: remote did not send all necessary objects' in stderr
+ assert "fatal: remote did not send all necessary objects" in stderr
+ assert "remote: Pre pull hook failed: aborting" in stderr
- def test_push_on_locked_repo_by_other_user_hg(self, rc_web_server, tmpdir):
- clone_url = rc_web_server.repo_clone_url(HG_REPO)
- stdout, stderr = Command('/tmp').execute(
- 'hg clone', clone_url, tmpdir.strpath)
+ def test_push_on_locked_repo_by_other_user_hg(self, rcstack, tmpdir):
+ clone_url = rcstack.repo_clone_url(HG_REPO)
+ stdout, stderr = Command(tmpdir.strpath).execute("hg clone", clone_url, tmpdir.strpath)
# lock repo
r = Repository.get_by_repo_name(HG_REPO)
# let this user actually push !
- RepoModel().grant_user_permission(repo=r, user=TEST_USER_REGULAR_LOGIN,
- perm='repository.write')
+ RepoModel().grant_user_permission(repo=r, user=TEST_USER_REGULAR_LOGIN, perm="repository.write")
Session().commit()
Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id)
# push fails repo is locked by other user !
- push_url = rc_web_server.repo_clone_url(
- HG_REPO,
- user=TEST_USER_REGULAR_LOGIN, passwd=TEST_USER_REGULAR_PASS)
- stdout, stderr = _add_files_and_push(
- 'hg', tmpdir.strpath, clone_url=push_url)
- msg = ("""abort: HTTP Error 423: Repository `%s` locked by user `%s`"""
- % (HG_REPO, TEST_USER_ADMIN_LOGIN))
+ push_url = rcstack.repo_clone_url(HG_REPO, user=TEST_USER_REGULAR_LOGIN, passwd=TEST_USER_REGULAR_PASS)
+ stdout, stderr = _add_files_and_push("hg", tmpdir.strpath, clone_url=push_url)
+ msg = f"abort: HTTP Error 423: Repository `{HG_REPO}` locked by user `{TEST_USER_ADMIN_LOGIN}`"
assert msg in stderr
- def test_push_on_locked_repo_by_other_user_git(
- self, rc_web_server, tmpdir):
- clone_url = rc_web_server.repo_clone_url(GIT_REPO)
- stdout, stderr = Command('/tmp').execute(
- 'git clone', clone_url, tmpdir.strpath)
+ def test_push_on_locked_repo_by_other_user_git(self, rcstack, tmpdir):
+ clone_url = rcstack.repo_clone_url(GIT_REPO)
+ stdout, stderr = Command(tmpdir.strpath).execute("git clone", clone_url, tmpdir.strpath)
# lock repo
r = Repository.get_by_repo_name(GIT_REPO)
# let this user actually push !
- RepoModel().grant_user_permission(repo=r, user=TEST_USER_REGULAR_LOGIN,
- perm='repository.write')
+ RepoModel().grant_user_permission(repo=r, user=TEST_USER_REGULAR_LOGIN, perm="repository.write")
Session().commit()
Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id)
# push fails repo is locked by other user!
- push_url = rc_web_server.repo_clone_url(
- GIT_REPO,
- user=TEST_USER_REGULAR_LOGIN, passwd=TEST_USER_REGULAR_PASS)
- stdout, stderr = _add_files_and_push(
- 'git', tmpdir.strpath, clone_url=push_url)
+ push_url = rcstack.repo_clone_url(GIT_REPO, user=TEST_USER_REGULAR_LOGIN, passwd=TEST_USER_REGULAR_PASS)
+ stdout, stderr = _add_files_and_push("git", tmpdir.strpath, clone_url=push_url)
- err = 'Repository `%s` locked by user `%s`' % (
- GIT_REPO, TEST_USER_ADMIN_LOGIN)
+ err = f"Repository `{GIT_REPO}` locked by user `{TEST_USER_ADMIN_LOGIN}`"
# err = 'RPC failed; result=22, HTTP code = 423'
assert err in stderr
- def test_push_unlocks_repository_hg(self, rc_web_server, tmpdir):
+ def test_push_unlocks_repository_hg(self, rcstack, tmpdir):
# enable locking
r = Repository.get_by_repo_name(HG_REPO)
r.enable_locking = True
Session().add(r)
Session().commit()
- clone_url = rc_web_server.repo_clone_url(HG_REPO)
- stdout, stderr = Command('/tmp').execute(
- 'hg clone', clone_url, tmpdir.strpath)
- _check_proper_clone(stdout, stderr, 'hg')
+ clone_url = rcstack.repo_clone_url(HG_REPO)
+ stdout, stderr = Command(tmpdir.strpath).execute("hg clone", clone_url, tmpdir.strpath)
+ _check_proper_clone(stdout, stderr, "hg")
# check for lock repo after clone
r = Repository.get_by_repo_name(HG_REPO)
@@ -177,16 +146,14 @@ class TestVCSOperationsOnCustomIniConfig(object):
assert r.locked[0] == uid
# push is ok and repo is now unlocked
- stdout, stderr = _add_files_and_push(
- 'hg', tmpdir.strpath, clone_url=clone_url)
- assert ('remote: Released lock on repo `%s`' % HG_REPO) in stdout
+ stdout, stderr = _add_files_and_push("hg", tmpdir.strpath, clone_url=clone_url)
+ assert f"remote: Released lock on repo `{HG_REPO}`" in stdout
# we need to cleanup the Session Here !
Session.remove()
r = Repository.get_by_repo_name(HG_REPO)
assert r.locked == [None, None, None]
- def test_push_unlocks_repository_git(self, rc_web_server, tmpdir):
-
+ def test_push_unlocks_repository_git(self, rcstack, tmpdir):
# Note: Did a first debugging session. Seems that
# Repository.get_locking_state is called twice. The second call
# has the action "pull" and does not reset the lock.
@@ -197,19 +164,16 @@ class TestVCSOperationsOnCustomIniConfig(object):
Session().add(r)
Session().commit()
- clone_url = rc_web_server.repo_clone_url(GIT_REPO)
- stdout, stderr = Command('/tmp').execute(
- 'git clone', clone_url, tmpdir.strpath)
- _check_proper_clone(stdout, stderr, 'git')
+ clone_url = rcstack.repo_clone_url(GIT_REPO)
+ stdout, stderr = Command(tmpdir.strpath).execute("git clone", clone_url, tmpdir.strpath)
+ _check_proper_clone(stdout, stderr, "git")
# check for lock repo after clone
r = Repository.get_by_repo_name(GIT_REPO)
- assert r.locked[0] == User.get_by_username(
- TEST_USER_ADMIN_LOGIN).user_id
+ assert r.locked[0] == User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id
# push is ok and repo is now unlocked
- stdout, stderr = _add_files_and_push(
- 'git', tmpdir.strpath, clone_url=clone_url)
+ stdout, stderr = _add_files_and_push("git", tmpdir.strpath, clone_url=clone_url)
_check_proper_git_push(stdout, stderr)
# assert ('remote: Released lock on repo `%s`' % GIT_REPO) in stdout
diff --git a/rhodecode/tests/vcs_operations/test_vcs_operations_locking_custom_code.py b/rhodecode/tests/vcs_operations/test_vcs_operations_locking_custom_code.py
index 820c71ea..9bddd51f 100644
--- a/rhodecode/tests/vcs_operations/test_vcs_operations_locking_custom_code.py
+++ b/rhodecode/tests/vcs_operations/test_vcs_operations_locking_custom_code.py
@@ -1,4 +1,3 @@
-
# Copyright (C) 2010-2023 RhodeCode GmbH
#
# This program is free software: you can redistribute it and/or modify
@@ -26,102 +25,83 @@ Test suite for making push/pull operations, on specially modified INI files
to redirect things to stderr instead of stdout.
"""
-
import pytest
from rhodecode.model.db import User, Repository
from rhodecode.model.meta import Session
from rhodecode.model.repo import RepoModel
-from rhodecode.tests import (
- GIT_REPO, HG_REPO, TEST_USER_ADMIN_LOGIN, TEST_USER_REGULAR_LOGIN,
- TEST_USER_REGULAR_PASS)
+from rhodecode.tests import GIT_REPO, HG_REPO, TEST_USER_ADMIN_LOGIN, TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS
from rhodecode.tests.vcs_operations import Command, _add_files_and_push
+custom_code = [
+ {'app:main': {'lock_ret_code': '400'}},
+]
-@pytest.fixture(scope="module")
-def rc_web_server_config_modification():
- return [
- {'app:main': {'lock_ret_code': '400'}},
- ]
-
-
-@pytest.mark.usefixtures("disable_locking", "disable_anonymous_user")
-class TestVCSOperationsOnCustomIniConfig(object):
-
- def test_clone_after_repo_was_locked_hg(self, rc_web_server, tmpdir):
+@pytest.mark.parametrize('rcstack', custom_code, indirect=True)
+@pytest.mark.usefixtures(
+ "init_pyramid_app",
+ "repo_group_repos",
+ "disable_anonymous_user",
+ "disable_locking",
+)
+class TestVCSOperationsOnCustomLockingCode(object):
+ def test_clone_after_repo_was_locked_hg(self, rcstack, tmpdir):
# lock repo
r = Repository.get_by_repo_name(HG_REPO)
Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id)
# pull fails since repo is locked
- clone_url = rc_web_server.repo_clone_url(HG_REPO)
- stdout, stderr = Command('/tmp').execute(
- 'hg clone', clone_url, tmpdir.strpath)
- msg = ("""abort: HTTP Error 400: Repository `%s` locked by user `%s`"""
- % (HG_REPO, TEST_USER_ADMIN_LOGIN))
+ clone_url = rcstack.repo_clone_url(HG_REPO)
+ stdout, stderr = Command(tmpdir.strpath).execute("hg clone", clone_url, tmpdir.strpath)
+ msg = f"abort: HTTP Error 400: Repository `{HG_REPO}` locked by user `{TEST_USER_ADMIN_LOGIN}`"
assert msg in stderr
- def test_clone_after_repo_was_locked_git(self, rc_web_server, tmpdir):
+ def test_clone_after_repo_was_locked_git(self, rcstack, tmpdir):
# lock repo
r = Repository.get_by_repo_name(GIT_REPO)
Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id)
# pull fails since repo is locked
- clone_url = rc_web_server.repo_clone_url(GIT_REPO)
- stdout, stderr = Command('/tmp').execute(
- 'git clone', clone_url, tmpdir.strpath)
+ clone_url = rcstack.repo_clone_url(GIT_REPO)
+ stdout, stderr = Command(tmpdir.strpath).execute("git clone", clone_url, tmpdir.strpath)
- lock_msg = (
- 'remote: ERROR: Repository `vcs_test_git` locked by user ' +
- '`test_admin`. Reason:`lock_auto`')
+ lock_msg = "remote: ERROR: Repository `vcs_test_git` locked by user `test_admin`. Reason:`lock_auto`"
assert lock_msg in stderr
- assert 'remote: Pre pull hook failed: aborting' in stderr
- assert 'fatal: remote did not send all necessary objects' in stderr
+ assert "remote: Pre pull hook failed: aborting" in stderr
+ assert "fatal: remote did not send all necessary objects" in stderr
- def test_push_on_locked_repo_by_other_user_hg(self, rc_web_server, tmpdir):
- clone_url = rc_web_server.repo_clone_url(HG_REPO)
- stdout, stderr = Command('/tmp').execute(
- 'hg clone', clone_url, tmpdir.strpath)
+ def test_push_on_locked_repo_by_other_user_hg(self, rcstack, tmpdir):
+ clone_url = rcstack.repo_clone_url(HG_REPO)
+ stdout, stderr = Command(tmpdir.strpath).execute("hg clone", clone_url, tmpdir.strpath)
# lock repo
r = Repository.get_by_repo_name(HG_REPO)
# let this user actually push !
- RepoModel().grant_user_permission(repo=r, user=TEST_USER_REGULAR_LOGIN,
- perm='repository.write')
+ RepoModel().grant_user_permission(repo=r, user=TEST_USER_REGULAR_LOGIN, perm="repository.write")
Session().commit()
Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id)
# push fails repo is locked by other user !
- push_url = rc_web_server.repo_clone_url(
- HG_REPO,
- user=TEST_USER_REGULAR_LOGIN, passwd=TEST_USER_REGULAR_PASS)
- stdout, stderr = _add_files_and_push(
- 'hg', tmpdir.strpath, clone_url=push_url)
- msg = ("""abort: HTTP Error 400: Repository `%s` locked by user `%s`"""
- % (HG_REPO, TEST_USER_ADMIN_LOGIN))
+ push_url = rcstack.repo_clone_url(HG_REPO, user=TEST_USER_REGULAR_LOGIN, passwd=TEST_USER_REGULAR_PASS)
+ stdout, stderr = _add_files_and_push("hg", tmpdir.strpath, clone_url=push_url)
+ msg = f"abort: HTTP Error 400: Repository `{HG_REPO}` locked by user `{TEST_USER_ADMIN_LOGIN}`"
+
assert msg in stderr
- def test_push_on_locked_repo_by_other_user_git(
- self, rc_web_server, tmpdir):
- clone_url = rc_web_server.repo_clone_url(GIT_REPO)
- stdout, stderr = Command('/tmp').execute(
- 'git clone', clone_url, tmpdir.strpath)
+ def test_push_on_locked_repo_by_other_user_git(self, rcstack, tmpdir):
+ clone_url = rcstack.repo_clone_url(GIT_REPO)
+ stdout, stderr = Command(tmpdir.strpath).execute("git clone", clone_url, tmpdir.strpath)
# lock repo
r = Repository.get_by_repo_name(GIT_REPO)
# let this user actually push !
- RepoModel().grant_user_permission(repo=r, user=TEST_USER_REGULAR_LOGIN,
- perm='repository.write')
+ RepoModel().grant_user_permission(repo=r, user=TEST_USER_REGULAR_LOGIN, perm="repository.write")
Session().commit()
Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id)
# push fails repo is locked by other user!
- push_url = rc_web_server.repo_clone_url(
- GIT_REPO,
- user=TEST_USER_REGULAR_LOGIN, passwd=TEST_USER_REGULAR_PASS)
- stdout, stderr = _add_files_and_push(
- 'git', tmpdir.strpath, clone_url=push_url)
+ push_url = rcstack.repo_clone_url(GIT_REPO, user=TEST_USER_REGULAR_LOGIN, passwd=TEST_USER_REGULAR_PASS)
+ stdout, stderr = _add_files_and_push("git", tmpdir.strpath, clone_url=push_url)
- err = 'Repository `%s` locked by user `%s`' % (
- GIT_REPO, TEST_USER_ADMIN_LOGIN)
+ err = f"Repository `{GIT_REPO}` locked by user `{TEST_USER_ADMIN_LOGIN}`"
assert err in stderr
diff --git a/rhodecode/tests/vcs_operations/test_vcs_operations_new_branch_push.py b/rhodecode/tests/vcs_operations/test_vcs_operations_new_branch_push.py
index 1d09112c..fa469b0a 100644
--- a/rhodecode/tests/vcs_operations/test_vcs_operations_new_branch_push.py
+++ b/rhodecode/tests/vcs_operations/test_vcs_operations_new_branch_push.py
@@ -26,12 +26,16 @@ from rhodecode.tests.vcs_operations import (
Command, _check_proper_hg_push, _check_proper_git_push, _add_files_and_push)
-@pytest.mark.usefixtures("disable_anonymous_user")
-class TestVCSOperations(object):
+@pytest.mark.usefixtures(
+ "init_pyramid_app",
+ "repo_group_repos",
+ "disable_anonymous_user",
+)
+class TestVCSOperationsNewBranchPush(object):
- def test_push_new_branch_hg(self, rc_web_server, tmpdir, user_util):
+ def test_push_new_branch_hg(self, rcstack, tmpdir, user_util):
repo = user_util.create_repo(repo_type='hg')
- clone_url = rc_web_server.repo_clone_url(repo.repo_name)
+ clone_url = rcstack.repo_clone_url(repo.repo_name)
Command(os.path.dirname(tmpdir.strpath)).execute(
'hg clone', clone_url, tmpdir.strpath)
@@ -48,9 +52,9 @@ class TestVCSOperations(object):
_check_proper_hg_push(stdout, stderr)
- def test_push_new_branch_git(self, rc_web_server, tmpdir, user_util):
+ def test_push_new_branch_git(self, rcstack, tmpdir, user_util):
repo = user_util.create_repo(repo_type='git')
- clone_url = rc_web_server.repo_clone_url(repo.repo_name)
+ clone_url = rcstack.repo_clone_url(repo.repo_name)
Command(os.path.dirname(tmpdir.strpath)).execute(
'git clone', clone_url, tmpdir.strpath)
@@ -67,13 +71,13 @@ class TestVCSOperations(object):
_check_proper_git_push(stdout, stderr, branch='dev')
def test_push_new_branch_hg_with_branch_permissions_no_force_push(
- self, rc_web_server, tmpdir, user_util, branch_permission_setter):
+ self, rcstack, tmpdir, user_util, branch_permission_setter):
repo = user_util.create_repo(repo_type='hg')
repo_name = repo.repo_name
username = TEST_USER_ADMIN_LOGIN
branch_permission_setter(repo_name, username, permission='branch.push')
- clone_url = rc_web_server.repo_clone_url(repo.repo_name)
+ clone_url = rcstack.repo_clone_url(repo.repo_name)
Command(os.path.dirname(tmpdir.strpath)).execute(
'hg clone', clone_url, tmpdir.strpath)
@@ -91,13 +95,13 @@ class TestVCSOperations(object):
_check_proper_hg_push(stdout, stderr)
def test_push_new_branch_git_with_branch_permissions_no_force_push(
- self, rc_web_server, tmpdir, user_util, branch_permission_setter):
+ self, rcstack, tmpdir, user_util, branch_permission_setter):
repo = user_util.create_repo(repo_type='git')
repo_name = repo.repo_name
username = TEST_USER_ADMIN_LOGIN
branch_permission_setter(repo_name, username, permission='branch.push')
- clone_url = rc_web_server.repo_clone_url(repo.repo_name)
+ clone_url = rcstack.repo_clone_url(repo.repo_name)
Command(os.path.dirname(tmpdir.strpath)).execute(
'git clone', clone_url, tmpdir.strpath)
diff --git a/rhodecode/tests/vcs_operations/test_vcs_operations_rcextensions_push.py b/rhodecode/tests/vcs_operations/test_vcs_operations_rcextensions_push.py
new file mode 100644
index 00000000..899261b8
--- /dev/null
+++ b/rhodecode/tests/vcs_operations/test_vcs_operations_rcextensions_push.py
@@ -0,0 +1,81 @@
+# 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 .
+#
+# 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 os
+import pytest
+
+from rhodecode.tests.fixtures.rcextensions_fixtures import store_rcextensions
+from rhodecode.tests.vcs_operations import (
+ Command, _check_proper_hg_push, _check_proper_git_push,
+ _add_files_and_push)
+
+
+@pytest.mark.usefixtures(
+ "init_pyramid_app",
+ "repo_group_repos",
+ "disable_anonymous_user",
+ "disable_locking",
+)
+class TestVCSOperationsWithRCExtensions(object):
+
+ def test_push_when_rcextensions_fail_hg(self, rcstack, tmpdir, user_util, rcextensions, rcextensions_modification):
+ repo = user_util.create_repo(repo_type='hg')
+ clone_url = rcstack.repo_clone_url(repo.repo_name)
+ Command(os.path.dirname(tmpdir.strpath)).execute(
+ 'hg clone', clone_url, tmpdir.strpath)
+
+ stdout, stderr = _add_files_and_push(
+ 'hg', tmpdir.strpath, clone_url=clone_url)
+ _check_proper_hg_push(stdout, stderr)
+
+ mods = [
+ ('_pre_push_hook',
+ """
+ return HookResponse(1, 'HOOK_FAIL_TEST_HG')
+ """)
+ ]
+ rcstack_location = os.path.dirname(rcstack.config_file)
+ with rcextensions_modification(rcstack_location, mods):
+ stdout, stderr = _add_files_and_push(
+ 'hg', tmpdir.strpath, clone_url=clone_url)
+ assert 'HOOK_FAIL_TEST_HG' in stdout
+
+ def test_push_when_rcextensions_fail_git(self, rcstack, tmpdir, user_util, rcextensions, rcextensions_modification):
+ repo = user_util.create_repo(repo_type='git')
+ clone_url = rcstack.repo_clone_url(repo.repo_name)
+ Command(os.path.dirname(tmpdir.strpath)).execute(
+ 'git clone', clone_url, tmpdir.strpath)
+
+ stdout, stderr = _add_files_and_push(
+ 'git', tmpdir.strpath, clone_url=clone_url)
+ _check_proper_git_push(stdout, stderr)
+
+ mods = [
+ ('_pre_push_hook',
+ """
+ return HookResponse(1, 'HOOK_FAIL_TEST_GIT')
+ """)
+ ]
+
+ rcstack_location = os.path.dirname(rcstack.config_file)
+ with rcextensions_modification(rcstack_location, mods):
+ stdout, stderr = _add_files_and_push(
+ 'git', tmpdir.strpath, clone_url=clone_url)
+ assert 'HOOK_FAIL_TEST_GIT' in stderr
+
diff --git a/rhodecode/tests/vcs_operations/test_vcs_operations_special.py b/rhodecode/tests/vcs_operations/test_vcs_operations_special.py
index b28e9e1f..d5bff9a4 100644
--- a/rhodecode/tests/vcs_operations/test_vcs_operations_special.py
+++ b/rhodecode/tests/vcs_operations/test_vcs_operations_special.py
@@ -32,13 +32,16 @@ from rhodecode.tests.vcs_operations import (
_add_files_and_push)
-@pytest.mark.usefixtures("disable_locking")
+@pytest.mark.usefixtures(
+ "init_pyramid_app",
+ "repo_group_repos",
+ "disable_locking",
+)
class TestVCSOperationsSpecial(object):
- def test_git_sets_default_branch_if_not_master(
- self, backend_git, tmpdir, rc_web_server):
- empty_repo = backend_git.create_repo()
- clone_url = rc_web_server.repo_clone_url(empty_repo.repo_name)
+ def test_git_sets_default_branch_if_not_master(self, vcs_backend_git, tmpdir, rcstack):
+ empty_repo = vcs_backend_git.create_repo()
+ clone_url = rcstack.repo_clone_url(empty_repo.repo_name)
cmd = Command(tmpdir.strpath)
cmd.execute('git clone', clone_url)
@@ -63,25 +66,24 @@ class TestVCSOperationsSpecial(object):
# Doing an explicit commit in order to get latest user logs on MySQL
Session().commit()
- def test_git_fetches_from_remote_repository_with_annotated_tags(
- self, backend_git, rc_web_server):
+ def test_git_fetches_from_remote_repository_with_annotated_tags(self, vcs_backend_git, rcstack):
# Note: This is a test specific to the git backend. It checks the
# integration of fetching from a remote repository which contains
# annotated tags.
# Dulwich shows this specific behavior only when
# operating against a remote repository.
- source_repo = backend_git['annotated-tag']
- target_vcs_repo = backend_git.create_repo().scm_instance()
- target_vcs_repo.fetch(rc_web_server.repo_clone_url(source_repo.repo_name))
+ source_repo = vcs_backend_git['annotated-tag']
+ target_vcs_repo = vcs_backend_git.create_repo().scm_instance()
+ target_vcs_repo.fetch(rcstack.repo_clone_url(source_repo.repo_name))
- def test_git_push_shows_pull_request_refs(self, backend_git, rc_web_server, tmpdir):
+ def test_git_push_shows_pull_request_refs(self, vcs_backend_git, rcstack, tmpdir):
"""
test if remote info about refs is visible
"""
- empty_repo = backend_git.create_repo()
+ empty_repo = vcs_backend_git.create_repo()
- clone_url = rc_web_server.repo_clone_url(empty_repo.repo_name)
+ clone_url = rcstack.repo_clone_url(empty_repo.repo_name)
cmd = Command(tmpdir.strpath)
cmd.execute('git clone', clone_url)
@@ -97,7 +99,7 @@ class TestVCSOperationsSpecial(object):
stdout, stderr = repo_cmd.execute('git push --verbose origin master')
_check_proper_git_push(stdout, stderr, branch='master')
- ref = f'{rc_web_server.host_url()}/{empty_repo.repo_name}/pull-request/new?branch=master'
+ ref = f'{rcstack.host_url()}/{empty_repo.repo_name}/pull-request/new?branch=master'
assert f'remote: RhodeCode: open pull request link: {ref}' in stderr
assert 'remote: RhodeCode: push completed' in stderr
@@ -129,14 +131,14 @@ class TestVCSOperationsSpecial(object):
stdout, stderr = repo_cmd.execute('git push --verbose origin feature')
_check_proper_git_push(stdout, stderr, branch='feature')
- ref = f'{rc_web_server.host_url()}/{empty_repo.repo_name}/pull-request/new?branch=feature'
+ ref = f'{rcstack.host_url()}/{empty_repo.repo_name}/pull-request/new?branch=feature'
assert f'remote: RhodeCode: open pull request link: {ref}' in stderr
assert 'remote: RhodeCode: push completed' in stderr
- def test_hg_push_shows_pull_request_refs(self, backend_hg, rc_web_server, tmpdir):
- empty_repo = backend_hg.create_repo()
+ def test_hg_push_shows_pull_request_refs(self, vcs_backend_hg, rcstack, tmpdir):
+ empty_repo = vcs_backend_hg.create_repo()
- clone_url = rc_web_server.repo_clone_url(empty_repo.repo_name)
+ clone_url = rcstack.repo_clone_url(empty_repo.repo_name)
cmd = Command(tmpdir.strpath)
cmd.execute('hg clone', clone_url)
@@ -154,7 +156,7 @@ class TestVCSOperationsSpecial(object):
stdout, stderr = repo_cmd.execute('hg push --verbose', clone_url)
_check_proper_hg_push(stdout, stderr, branch='default')
- ref = f'{rc_web_server.host_url()}/{empty_repo.repo_name}/pull-request/new?branch=default'
+ ref = f'{rcstack.host_url()}/{empty_repo.repo_name}/pull-request/new?branch=default'
assert f'remote: RhodeCode: open pull request link: {ref}' in stdout
assert 'remote: RhodeCode: push completed' in stdout
@@ -189,14 +191,14 @@ class TestVCSOperationsSpecial(object):
stdout, stderr = repo_cmd.execute('hg push --new-branch --verbose', clone_url)
_check_proper_hg_push(stdout, stderr, branch='feature')
- ref = f'{rc_web_server.host_url()}/{empty_repo.repo_name}/pull-request/new?branch=feature'
+ ref = f'{rcstack.host_url()}/{empty_repo.repo_name}/pull-request/new?branch=feature'
assert f'remote: RhodeCode: open pull request link: {ref}' in stdout
assert 'remote: RhodeCode: push completed' in stdout
- def test_hg_push_shows_pull_request_refs_book(self, backend_hg, rc_web_server, tmpdir):
- empty_repo = backend_hg.create_repo()
+ def test_hg_push_shows_pull_request_refs_book(self, vcs_backend_hg, rcstack, tmpdir):
+ empty_repo = vcs_backend_hg.create_repo()
- clone_url = rc_web_server.repo_clone_url(empty_repo.repo_name)
+ clone_url = rcstack.repo_clone_url(empty_repo.repo_name)
cmd = Command(tmpdir.strpath)
cmd.execute('hg clone', clone_url)
@@ -214,7 +216,7 @@ class TestVCSOperationsSpecial(object):
stdout, stderr = repo_cmd.execute('hg push --verbose', clone_url)
_check_proper_hg_push(stdout, stderr, branch='default')
- ref = f'{rc_web_server.host_url()}/{empty_repo.repo_name}/pull-request/new?branch=default'
+ ref = f'{rcstack.host_url()}/{empty_repo.repo_name}/pull-request/new?branch=default'
assert f'remote: RhodeCode: open pull request link: {ref}' in stdout
assert 'remote: RhodeCode: push completed' in stdout
@@ -232,23 +234,23 @@ class TestVCSOperationsSpecial(object):
stdout, stderr = repo_cmd.execute('hg push -B feature2 --verbose', clone_url)
_check_proper_hg_push(stdout, stderr, branch='default')
- ref = f'{rc_web_server.host_url()}/{empty_repo.repo_name}/pull-request/new?branch=default'
+ ref = f'{rcstack.host_url()}/{empty_repo.repo_name}/pull-request/new?branch=default'
assert f'remote: RhodeCode: open pull request link: {ref}' in stdout
- ref = f'{rc_web_server.host_url()}/{empty_repo.repo_name}/pull-request/new?bookmark=feature2'
+ ref = f'{rcstack.host_url()}/{empty_repo.repo_name}/pull-request/new?bookmark=feature2'
assert f'remote: RhodeCode: open pull request link: {ref}' in stdout
assert 'remote: RhodeCode: push completed' in stdout
assert 'exporting bookmark feature2' in stdout
- def test_push_is_forbidden_on_archived_repo_hg(self, backend_hg, rc_web_server, tmpdir):
- empty_repo = backend_hg.create_repo()
+ def test_push_is_forbidden_on_archived_repo_hg(self, vcs_backend_hg, rcstack, tmpdir):
+ empty_repo = vcs_backend_hg.create_repo()
repo_name = empty_repo.repo_name
repo = Repository.get_by_repo_name(repo_name)
repo.archived = True
Session().commit()
- clone_url = rc_web_server.repo_clone_url(repo_name)
- stdout, stderr = Command('/tmp').execute(
+ clone_url = rcstack.repo_clone_url(repo_name)
+ stdout, stderr = Command(tmpdir.strpath).execute(
'hg clone', clone_url, tmpdir.strpath)
stdout, stderr = _add_files_and_push(
@@ -256,16 +258,16 @@ class TestVCSOperationsSpecial(object):
assert 'abort: HTTP Error 403: Forbidden' in stderr
- def test_push_is_forbidden_on_archived_repo_git(self, backend_git, rc_web_server, tmpdir):
- empty_repo = backend_git.create_repo()
+ def test_push_is_forbidden_on_archived_repo_git(self, vcs_backend_git, rcstack, tmpdir):
+ empty_repo = vcs_backend_git.create_repo()
repo_name = empty_repo.repo_name
repo = Repository.get_by_repo_name(repo_name)
repo.archived = True
Session().commit()
- clone_url = rc_web_server.repo_clone_url(repo_name)
- stdout, stderr = Command('/tmp').execute(
+ clone_url = rcstack.repo_clone_url(repo_name)
+ stdout, stderr = Command(tmpdir.strpath).execute(
'git clone', clone_url, tmpdir.strpath)
stdout, stderr = _add_files_and_push(
diff --git a/rhodecode/tests/vcs_operations/test_vcs_operations_svn.py b/rhodecode/tests/vcs_operations/test_vcs_operations_svn.py
index 0b60ebfc..4dc7a98a 100644
--- a/rhodecode/tests/vcs_operations/test_vcs_operations_svn.py
+++ b/rhodecode/tests/vcs_operations/test_vcs_operations_svn.py
@@ -49,97 +49,110 @@ def get_cli_flags(username, password):
return flags, auth
-@pytest.mark.usefixtures("disable_locking", "disable_anonymous_user")
-class TestVCSOperations(object):
+@pytest.mark.usefixtures(
+ "init_pyramid_app",
+ "repo_group_repos",
+ "disable_anonymous_user",
+ "disable_locking",
+)
+class TestVCSOperationsSVN(object):
- def test_clone_svn_repo_by_admin(self, rc_web_server, tmpdir):
- clone_url = rc_web_server.repo_clone_url(SVN_REPO)
- username, password = rc_web_server.repo_clone_credentials()
+ @pytest.mark.xfail(reason='Lack of proper SVN support of cloning')
+ def test_clone_svn_repo_by_admin(self, rcstack, tmpdir):
+ clone_url = rcstack.repo_clone_url(SVN_REPO)
+ username, password = rcstack.repo_clone_credentials()
- cmd = Command('/tmp')
+ cmd = Command(tmpdir.strpath)
flags, auth = get_cli_flags(username, password)
- stdout, stderr = Command('/tmp').execute(
+ stdout, stderr = Command(tmpdir.strpath).execute(
f'svn checkout {flags} {auth}', clone_url, tmpdir.strpath)
_check_proper_clone(stdout, stderr, 'svn')
cmd.assert_returncode_success()
- def test_clone_svn_repo_by_id_by_admin(self, rc_web_server, tmpdir):
+ @pytest.mark.xfail(reason='Lack of proper SVN support of cloning')
+ def test_clone_svn_repo_by_id_by_admin(self, rcstack, tmpdir):
repo_id = Repository.get_by_repo_name(SVN_REPO).repo_id
- username, password = rc_web_server.repo_clone_credentials()
+ username, password = rcstack.repo_clone_credentials()
- clone_url = rc_web_server.repo_clone_url('_%s' % repo_id)
- cmd = Command('/tmp')
+ clone_url = rcstack.repo_clone_url('_%s' % repo_id)
+ cmd = Command(tmpdir.strpath)
flags, auth = get_cli_flags(username, password)
- stdout, stderr = Command('/tmp').execute(
+ stdout, stderr = Command(tmpdir.strpath).execute(
f'svn checkout {flags} {auth}', clone_url, tmpdir.strpath)
_check_proper_clone(stdout, stderr, 'svn')
cmd.assert_returncode_success()
- def test_clone_svn_repo_with_group_by_admin(self, rc_web_server, tmpdir):
- clone_url = rc_web_server.repo_clone_url(SVN_REPO_WITH_GROUP)
- username, password = rc_web_server.repo_clone_credentials()
+ @pytest.mark.xfail(reason='Lack of proper SVN support of cloning')
+ def test_clone_svn_repo_with_group_by_admin(self, rcstack, tmpdir):
+ clone_url = rcstack.repo_clone_url(SVN_REPO_WITH_GROUP)
+ username, password = rcstack.repo_clone_credentials()
flags, auth = get_cli_flags(username, password)
- stdout, stderr = Command('/tmp').execute(
+ stdout, stderr = Command(tmpdir.strpath).execute(
f'svn checkout {flags} {auth}', clone_url, tmpdir.strpath)
_check_proper_clone(stdout, stderr, 'svn')
- cmd.assert_returncode_success()
+ rcstack.assert_returncode_success()
- def test_clone_wrong_credentials_svn(self, rc_web_server, tmpdir):
- clone_url = rc_web_server.repo_clone_url(SVN_REPO)
- username, password = rc_web_server.repo_clone_credentials()
+ @pytest.mark.xfail(reason='Lack of proper SVN support of cloning')
+ def test_clone_wrong_credentials_svn(self, rcstack, tmpdir):
+ clone_url = rcstack.repo_clone_url(SVN_REPO)
+ username, password = rcstack.repo_clone_credentials()
password = 'bad-password'
flags, auth = get_cli_flags(username, password)
- stdout, stderr = Command('/tmp').execute(
+ stdout, stderr = Command(tmpdir.strpath).execute(
f'svn checkout {flags} {auth}', clone_url, tmpdir.strpath)
assert 'fatal: Authentication failed' in stderr
- def test_clone_svn_with_slashes(self, rc_web_server, tmpdir):
- clone_url = rc_web_server.repo_clone_url('//' + SVN_REPO)
+ @pytest.mark.xfail(reason='Lack of proper SVN support of cloning')
+ def test_clone_svn_with_slashes(self, rcstack, tmpdir):
+ clone_url = rcstack.repo_clone_url('//' + SVN_REPO)
username, password = '', ''
flags, auth = get_cli_flags(username, password)
- stdout, stderr = Command('/tmp').execute(
+ stdout, stderr = Command(tmpdir.strpath).execute(
f'svn checkout {flags} {auth}', clone_url)
assert 'not found' in stderr
+ @pytest.mark.xfail(reason='Lack of proper SVN support of cloning')
def test_clone_existing_path_svn_not_in_database(
- self, rc_web_server, tmpdir, fs_repo_only):
+ self, rcstack, tmpdir, fs_repo_only):
db_name = fs_repo_only('not-in-db-git', repo_type='git')
- clone_url = rc_web_server.repo_clone_url(db_name)
+ clone_url = rcstack.repo_clone_url(db_name)
username, password = '', ''
flags, auth = get_cli_flags(username, password)
- stdout, stderr = Command('/tmp').execute(
+ stdout, stderr = Command(tmpdir.strpath).execute(
f'svn checkout {flags} {auth}', clone_url, tmpdir.strpath)
assert 'not found' in stderr
+ @pytest.mark.xfail(reason='Lack of proper SVN support of cloning')
def test_clone_existing_path_svn_not_in_database_different_scm(
- self, rc_web_server, tmpdir, fs_repo_only):
+ self, rcstack, tmpdir, fs_repo_only):
db_name = fs_repo_only('not-in-db-hg', repo_type='hg')
- clone_url = rc_web_server.repo_clone_url(db_name)
+ clone_url = rcstack.repo_clone_url(db_name)
username, password = '', ''
flags, auth = get_cli_flags(username, password)
- stdout, stderr = Command('/tmp').execute(
+ stdout, stderr = Command(tmpdir.strpath).execute(
f'svn checkout {flags} {auth}', clone_url, tmpdir.strpath)
assert 'not found' in stderr
- def test_clone_non_existing_store_path_svn(self, rc_web_server, tmpdir, user_util):
+ @pytest.mark.xfail(reason='Lack of proper SVN support of cloning')
+ def test_clone_non_existing_store_path_svn(self, rcstack, tmpdir, user_util):
repo = user_util.create_repo(repo_type='git')
- clone_url = rc_web_server.repo_clone_url(repo.repo_name)
+ clone_url = rcstack.repo_clone_url(repo.repo_name)
# Damage repo by removing it's folder
RepoModel()._delete_filesystem_repo(repo)
@@ -147,16 +160,17 @@ class TestVCSOperations(object):
username, password = '', ''
flags, auth = get_cli_flags(username, password)
- stdout, stderr = Command('/tmp').execute(
+ stdout, stderr = Command(tmpdir.strpath).execute(
f'svn checkout {flags} {auth}', clone_url, tmpdir.strpath)
assert 'not found' in stderr
- def test_push_new_file_svn(self, rc_web_server, tmpdir):
- clone_url = rc_web_server.repo_clone_url(SVN_REPO)
+ @pytest.mark.xfail(reason='Lack of proper SVN support of cloning')
+ def test_push_new_file_svn(self, rcstack, tmpdir):
+ clone_url = rcstack.repo_clone_url(SVN_REPO)
username, password = '', ''
flags, auth = get_cli_flags(username, password)
- stdout, stderr = Command('/tmp').execute(
+ stdout, stderr = Command(tmpdir.strpath).execute(
f'svn checkout {flags} {auth}', clone_url, tmpdir.strpath)
# commit some stuff into this repo
@@ -165,37 +179,40 @@ class TestVCSOperations(object):
_check_proper_svn_push(stdout, stderr)
- def test_push_wrong_credentials_svn(self, rc_web_server, tmpdir):
- clone_url = rc_web_server.repo_clone_url(SVN_REPO)
+ @pytest.mark.xfail(reason='Lack of proper SVN support of cloning')
+ def test_push_wrong_credentials_svn(self, rcstack, tmpdir):
+ clone_url = rcstack.repo_clone_url(SVN_REPO)
- username, password = rc_web_server.repo_clone_credentials()
+ username, password = rcstack.repo_clone_credentials()
flags, auth = get_cli_flags(username, password)
- stdout, stderr = Command('/tmp').execute(
+ stdout, stderr = Command(tmpdir.strpath).execute(
f'svn checkout {flags} {auth}', clone_url, tmpdir.strpath)
- push_url = rc_web_server.repo_clone_url(
+ push_url = rcstack.repo_clone_url(
SVN_REPO, user='bad', passwd='name')
stdout, stderr = _add_files_and_push(
'svn', tmpdir.strpath, clone_url=push_url, username=username, password=password)
assert 'fatal: Authentication failed' in stderr
- def test_push_back_to_wrong_url_svn(self, rc_web_server, tmpdir):
- clone_url = rc_web_server.repo_clone_url(SVN_REPO)
+ @pytest.mark.xfail(reason='Lack of proper SVN support of cloning')
+ def test_push_back_to_wrong_url_svn(self, rcstack, tmpdir):
+ clone_url = rcstack.repo_clone_url(SVN_REPO)
username, password = '', ''
flags, auth = get_cli_flags(username, password)
- stdout, stderr = Command('/tmp').execute(
+ stdout, stderr = Command(tmpdir.strpath).execute(
f'svn checkout {flags} {auth}', clone_url, tmpdir.strpath)
stdout, stderr = _add_files_and_push(
'svn', tmpdir.strpath,
- clone_url=rc_web_server.repo_clone_url('not-existing'), username=username, password=password)
+ clone_url=rcstack.repo_clone_url('not-existing'), username=username, password=password)
assert 'not found' in stderr
- def test_ip_restriction_svn(self, rc_web_server, tmpdir):
+ @pytest.mark.xfail(reason='Lack of proper SVN support of cloning')
+ def test_ip_restriction_svn(self, rcstack, tmpdir):
user_model = UserModel()
username, password = '', ''
flags, auth = get_cli_flags(username, password)
@@ -204,9 +221,9 @@ class TestVCSOperations(object):
user_model.add_extra_ip(TEST_USER_ADMIN_LOGIN, '10.10.10.10/32')
Session().commit()
time.sleep(2)
- clone_url = rc_web_server.repo_clone_url(SVN_REPO)
+ clone_url = rcstack.repo_clone_url(SVN_REPO)
- stdout, stderr = Command('/tmp').execute(
+ stdout, stderr = Command(tmpdir.strpath).execute(
f'svn checkout {flags} {auth}', clone_url, tmpdir.strpath)
msg = "The requested URL returned error: 403"
assert msg in stderr
@@ -218,7 +235,7 @@ class TestVCSOperations(object):
time.sleep(2)
- cmd = Command('/tmp')
+ cmd = Command(tmpdir.strpath)
stdout, stderr = cmd.execute(f'svn checkout {flags} {auth}', clone_url, tmpdir.strpath)
cmd.assert_returncode_success()
_check_proper_clone(stdout, stderr, 'svn')
diff --git a/rhodecode/tests/vcs_operations/test_vcs_operations_tag_push.py b/rhodecode/tests/vcs_operations/test_vcs_operations_tag_push.py
index eed4aefd..ecee4f9c 100644
--- a/rhodecode/tests/vcs_operations/test_vcs_operations_tag_push.py
+++ b/rhodecode/tests/vcs_operations/test_vcs_operations_tag_push.py
@@ -1,4 +1,3 @@
-
# Copyright (C) 2010-2023 RhodeCode GmbH
#
# This program is free software: you can redistribute it and/or modify
@@ -19,11 +18,6 @@
"""
Test suite for making push/pull operations, on specially modified INI files
-
-.. important::
-
- You must have git >= 1.8.5 for tests to work fine. With 68b939b git started
- to redirect things to stderr instead of stdout.
"""
import pytest
@@ -37,54 +31,59 @@ connection_available = pytest.mark.skipif(
not check_httpbin_connection(), reason="No outside internet connection available")
+
@pytest.mark.usefixtures(
- "disable_locking", "disable_anonymous_user",
- "enable_webhook_push_integration")
-class TestVCSOperationsOnCustomIniConfig(object):
+ "init_pyramid_app",
+ "repo_group_repos",
+ "disable_anonymous_user",
+ "disable_locking",
+ "enable_webhook_push_integration"
+)
+class TestVCSOperationsTagPush(object):
@connection_available
- def test_push_tag_with_commit_hg(self, rc_web_server, tmpdir):
- clone_url = rc_web_server.repo_clone_url(HG_REPO)
- stdout, stderr = Command('/tmp').execute(
+ def test_push_tag_with_commit_hg(self, rcstack, tmpdir):
+ clone_url = rcstack.repo_clone_url(HG_REPO)
+ stdout, stderr = Command(tmpdir.strpath).execute(
'hg clone', clone_url, tmpdir.strpath)
- push_url = rc_web_server.repo_clone_url(HG_REPO)
+ push_url = rcstack.repo_clone_url(HG_REPO)
_add_files_and_push(
'hg', tmpdir.strpath, clone_url=push_url,
tags=[{'name': 'v1.0.0', 'commit': 'added tag v1.0.0'}])
- rc_log = rc_web_server.get_rc_log()
- assert 'ERROR' not in rc_log
- assert "{'name': 'v1.0.0'," in rc_log
+ celery_log = open(rcstack.rcstack_data.celery_log).read()
+ assert 'ERROR' not in celery_log
+ assert "{'name': 'v1.0.0'," in celery_log
@connection_available
def test_push_tag_with_commit_git(
- self, rc_web_server, tmpdir):
- clone_url = rc_web_server.repo_clone_url(GIT_REPO)
- stdout, stderr = Command('/tmp').execute(
+ self, rcstack, tmpdir):
+ clone_url = rcstack.repo_clone_url(GIT_REPO)
+ stdout, stderr = Command(tmpdir.strpath).execute(
'git clone', clone_url, tmpdir.strpath)
- push_url = rc_web_server.repo_clone_url(GIT_REPO)
+ push_url = rcstack.repo_clone_url(GIT_REPO)
_add_files_and_push(
'git', tmpdir.strpath, clone_url=push_url,
tags=[{'name': 'v1.0.0', 'commit': 'added tag v1.0.0'}])
- rc_log = rc_web_server.get_rc_log()
- assert 'ERROR' not in rc_log
- assert "{'name': 'v1.0.0'," in rc_log
+ celery_log = open(rcstack.rcstack_data.celery_log).read()
+ assert 'ERROR' not in celery_log
+ assert "{'name': 'v1.0.0'," in celery_log
@connection_available
def test_push_tag_with_no_commit_git(
- self, rc_web_server, tmpdir):
- clone_url = rc_web_server.repo_clone_url(GIT_REPO)
- stdout, stderr = Command('/tmp').execute(
+ self, rcstack, tmpdir):
+ clone_url = rcstack.repo_clone_url(GIT_REPO)
+ stdout, stderr = Command(tmpdir.strpath).execute(
'git clone', clone_url, tmpdir.strpath)
- push_url = rc_web_server.repo_clone_url(GIT_REPO)
+ push_url = rcstack.repo_clone_url(GIT_REPO)
_add_files_and_push(
'git', tmpdir.strpath, clone_url=push_url,
tags=[{'name': 'v1.0.0', 'commit': 'added tag v1.0.0'}])
- rc_log = rc_web_server.get_rc_log()
- assert 'ERROR' not in rc_log
- assert "{'name': 'v1.0.0'," in rc_log
+ celery_log = open(rcstack.rcstack_data.celery_log).read()
+ assert 'ERROR' not in celery_log
+ assert "{'name': 'v1.0.0'," in celery_log
diff --git a/rhodecode/tests/vcsserver_http.ini b/rhodecode/tests/vcsserver_http.ini
index 62c09696..f72a785d 100644
--- a/rhodecode/tests/vcsserver_http.ini
+++ b/rhodecode/tests/vcsserver_http.ini
@@ -60,7 +60,7 @@ vcs.svn.redis_conn = redis://redis:6379/0
; Default cache dir for caches. Putting this into a ramdisk can boost performance.
; eg. /tmpfs/data_ramdisk, however this directory might require large amount of space
-cache_dir = %(here)s/data
+cache_dir = %(here)s/.rc-vcs-test-data
; ***************************************
; `repo_object` cache, default file based
@@ -141,7 +141,7 @@ level = NOTSET
handlers = console
[logger_vcsserver]
-level = INFO
+level = DEBUG
handlers =
qualname = vcsserver
propagate = 1