Add explicit default values to pytest command line options to prevent issues when running tests with pytest's parallel execution where options are not present on upper conftest, so they're just not set at all.
134 lines
5.1 KiB
Python
134 lines
5.1 KiB
Python
#
|
|
# Copyright (C) 2025-present ScyllaDB
|
|
#
|
|
# SPDX-License-Identifier: LicenseRef-ScyllaDB-Source-Available-1.0
|
|
#
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import logging
|
|
from typing import TYPE_CHECKING
|
|
|
|
import pytest
|
|
|
|
from test.cluster.dtest.dtest_config import DTestConfig
|
|
from test.cluster.dtest.dtest_setup import DTestSetup
|
|
from test.cluster.dtest.dtest_setup_overrides import DTestSetupOverrides
|
|
|
|
if TYPE_CHECKING:
|
|
from collections.abc import Generator
|
|
|
|
from pytest import Config, Parser, FixtureRequest
|
|
|
|
from test.pylib.manager_client import ManagerClient
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def pytest_addoption(parser: Parser) -> None:
|
|
parser.addoption("--use-vnodes", action="store_true", default=True, help="Determines wither or not to setup clusters using vnodes for tests")
|
|
parser.addoption("--num-tokens", action="store", default=256, help="Number of tokens to set num_tokens yaml setting to when creating instances with vnodes enabled")
|
|
parser.addoption("--experimental-features", type=lambda s: s.split(","), action="store", help="Pass experimental features <feature>,<feature> to enable", default=None)
|
|
parser.addoption("--tablets", action=argparse.BooleanOptionalAction, default=False, help="Whether to enable tablets support (default: %(default)s)")
|
|
parser.addoption("--force-gossip-topology-changes", action="store_true", default=False, help="force gossip topology changes in a fresh cluster")
|
|
|
|
|
|
def pytest_configure(config: Config) -> None:
|
|
features = {"cdc", "raft", "consistent-cluster-management", "consistent-topology-changes"}
|
|
if experimental_features := config.getoption("--experimental-features"):
|
|
features.update(experimental_features)
|
|
if config.getoption("--force-gossip-topology-changes") and config.getoption("--tablets"):
|
|
raise Exception("--force-gossip-topology-changes and --tablets cannot be used together")
|
|
if config.getoption("--force-gossip-topology-changes"):
|
|
features.remove("consistent-topology-changes")
|
|
if config.getoption("--tablets"):
|
|
features.add("tablets")
|
|
config.scylla_features = features
|
|
|
|
|
|
@pytest.fixture(scope="function", autouse=True)
|
|
def fixture_dtest_setup_overrides(dtest_config: DTestConfig) -> DTestSetupOverrides:
|
|
"""
|
|
no-op default implementation of fixture_dtest_setup_overrides.
|
|
we run this when a test class hasn't implemented their own
|
|
fixture_dtest_setup_overrides
|
|
"""
|
|
return DTestSetupOverrides()
|
|
|
|
|
|
@pytest.fixture(scope="function", autouse=False)
|
|
def fixture_dtest_setup(request: FixtureRequest,
|
|
dtest_config: DTestConfig,
|
|
fixture_dtest_setup_overrides: DTestSetupOverrides,
|
|
manager: ManagerClient,
|
|
build_mode: str) -> Generator[DTestSetup]:
|
|
dtest_setup = DTestSetup(
|
|
dtest_config=dtest_config,
|
|
setup_overrides=fixture_dtest_setup_overrides,
|
|
manager=manager,
|
|
scylla_mode=build_mode,
|
|
)
|
|
|
|
if request.node.get_closest_marker("single_node") or not request.node.get_closest_marker("no_boot_speedups"):
|
|
dtest_setup.cluster_options.setdefault("skip_wait_for_gossip_to_settle", 0)
|
|
|
|
# Reduce waiting time for the nodes to hear from others before joining the ring.
|
|
# Since all test cases run on localhost and there are no large test clusters
|
|
# it's safe to reduce the value to save a lot of time while testing.
|
|
# (Default value for the option is 30s)
|
|
dtest_setup.cluster_options.setdefault("ring_delay_ms", 10000)
|
|
|
|
cluster_options = request.node.get_closest_marker("cluster_options")
|
|
if cluster_options:
|
|
for name, value in cluster_options.kwargs.items():
|
|
dtest_setup.cluster_options.setdefault(name, value)
|
|
|
|
dtest_setup.init_default_config()
|
|
|
|
# at this point we're done with our setup operations in this fixture
|
|
# yield to allow the actual test to run
|
|
yield dtest_setup
|
|
|
|
# phew! we're back after executing the test, now we need to do
|
|
# all of our teardown and cleanup operations
|
|
|
|
dtest_setup.jvm_args = []
|
|
|
|
for con in dtest_setup.connections:
|
|
con.cluster.shutdown()
|
|
dtest_setup.connections = []
|
|
|
|
try:
|
|
dtest_setup.cluster.stop(gently=True)
|
|
except Exception as e: # noqa: BLE001
|
|
logger.error("Error stopping cluster: %s", str(e))
|
|
|
|
manager.ignore_log_patterns.extend(dtest_setup.ignore_log_patterns)
|
|
manager.ignore_cores_log_patterns.extend(dtest_setup.ignore_cores_log_patterns)
|
|
|
|
try:
|
|
if not dtest_setup.allow_log_errors:
|
|
exclude_errors = []
|
|
if marker := request.node.get_closest_marker("exclude_errors"):
|
|
exclude_errors = list(marker.args)
|
|
dtest_setup.check_errors_all_nodes(exclude_errors=exclude_errors)
|
|
finally:
|
|
pass
|
|
|
|
|
|
@pytest.fixture(scope="session", autouse=True)
|
|
def install_debugging_signal_handler() -> None:
|
|
import faulthandler
|
|
|
|
faulthandler.enable()
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
def dtest_config(request: FixtureRequest) -> Generator[DTestConfig]:
|
|
dtest_config = DTestConfig()
|
|
dtest_config.setup(request)
|
|
|
|
yield dtest_config
|