# 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()