Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/workflows/integration-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,12 @@ jobs:
- name: Build driver
run: uv sync

- name: Cache Scylla download
uses: actions/cache@v4
with:
path: ~/.ccm/repository
key: scylla-${{ env.SCYLLA_VERSION }}-${{ runner.os }}

# This is to get honest accounting of test time vs download time vs build time.
# Not strictly necessary for running tests.
- name: Download Scylla
Expand Down
3 changes: 3 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,9 @@ log_level = "DEBUG"
log_date_format = "%Y-%m-%d %H:%M:%S"
xfail_strict = true
addopts = "-rf"
markers = [
"last: mark test to run last within its module group",
]

[tool.setuptools_scm]
version_file = "cassandra/_version.py"
Expand Down
2 changes: 1 addition & 1 deletion tests/integration/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -600,7 +600,7 @@ def execute_with_long_wait_retry(session, query, timeout=30):
del tb
tries += 1

raise RuntimeError("Failed to execute query after 100 attempts: {0}".format(query))
raise RuntimeError("Failed to execute query after 10 attempts: {0}".format(query))


def execute_with_retry_tolerant(session, query, retry_exceptions, escape_exception):
Expand Down
2 changes: 1 addition & 1 deletion tests/integration/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def cleanup_clusters():

if not os.environ.get('DISABLE_CLUSTER_CLEANUP'):
for cluster_name in [CLUSTER_NAME, SINGLE_NODE_CLUSTER_NAME, MULTIDC_CLUSTER_NAME,
'shared_aware', 'sni_proxy', 'test_ip_change']:
'cluster_tests', 'shared_aware', 'sni_proxy', 'test_ip_change', 'test_client_routes_replacement']:
try:
cluster = CCMClusterFactory.load(ccm_path, cluster_name)
logging.debug("Using external CCM cluster {0}".format(cluster.name))
Expand Down
13 changes: 12 additions & 1 deletion tests/integration/long/test_loadbalancingpolicies.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@
class LoadBalancingPolicyTests(unittest.TestCase):

def setUp(self):
remove_cluster() # clear ahead of test so it doesn't use one left in unknown state
self.coordinator_stats = CoordinatorStats()
self.prepared = None
self.probe_cluster = None
Expand Down Expand Up @@ -191,6 +190,7 @@ def test_token_aware_is_used_by_default(self):
assert isinstance(cluster.profile_manager.default.load_balancing_policy, DCAwareRoundRobinPolicy)

def test_roundrobin(self):
remove_cluster()
use_singledc()
keyspace = 'test_roundrobin'
cluster, session = self._cluster_session_with_lbp(RoundRobinPolicy())
Expand Down Expand Up @@ -228,6 +228,7 @@ def test_roundrobin(self):
self.coordinator_stats.assert_query_count_equals(3, 6)

def test_roundrobin_two_dcs(self):
remove_cluster()
use_multidc([2, 2])
keyspace = 'test_roundrobin_two_dcs'
cluster, session = self._cluster_session_with_lbp(RoundRobinPolicy())
Expand Down Expand Up @@ -261,6 +262,7 @@ def test_roundrobin_two_dcs(self):
self.coordinator_stats.assert_query_count_equals(5, 3)

def test_roundrobin_two_dcs_2(self):
remove_cluster()
use_multidc([2, 2])
keyspace = 'test_roundrobin_two_dcs_2'
cluster, session = self._cluster_session_with_lbp(RoundRobinPolicy())
Expand Down Expand Up @@ -294,6 +296,7 @@ def test_roundrobin_two_dcs_2(self):
self.coordinator_stats.assert_query_count_equals(5, 3)

def test_dc_aware_roundrobin_two_dcs(self):
remove_cluster()
use_multidc([3, 2])
keyspace = 'test_dc_aware_roundrobin_two_dcs'
cluster, session = self._cluster_session_with_lbp(DCAwareRoundRobinPolicy('dc1'))
Expand All @@ -311,6 +314,7 @@ def test_dc_aware_roundrobin_two_dcs(self):
self.coordinator_stats.assert_query_count_equals(5, 0)

def test_dc_aware_roundrobin_two_dcs_2(self):
remove_cluster()
use_multidc([3, 2])
keyspace = 'test_dc_aware_roundrobin_two_dcs_2'
cluster, session = self._cluster_session_with_lbp(DCAwareRoundRobinPolicy('dc2'))
Expand All @@ -328,6 +332,7 @@ def test_dc_aware_roundrobin_two_dcs_2(self):
self.coordinator_stats.assert_query_count_equals(5, 6)

def test_dc_aware_roundrobin_one_remote_host(self):
remove_cluster()
use_multidc([2, 2])
keyspace = 'test_dc_aware_roundrobin_one_remote_host'
cluster, session = self._cluster_session_with_lbp(DCAwareRoundRobinPolicy('dc2', used_hosts_per_remote_dc=1))
Expand Down Expand Up @@ -410,6 +415,7 @@ def test_token_aware_prepared(self):
self.token_aware(keyspace, True)

def token_aware(self, keyspace, use_prepared=False):
remove_cluster()
use_singledc()
cluster, session = self._cluster_session_with_lbp(TokenAwarePolicy(RoundRobinPolicy()))
self.addCleanup(cluster.shutdown)
Expand Down Expand Up @@ -505,6 +511,7 @@ def test_token_aware_composite_key(self):
assert results[0].i

def test_token_aware_with_rf_2(self, use_prepared=False):
remove_cluster()
use_singledc()
keyspace = 'test_token_aware_with_rf_2'
cluster, session = self._cluster_session_with_lbp(TokenAwarePolicy(RoundRobinPolicy()))
Expand Down Expand Up @@ -617,6 +624,7 @@ def test_token_aware_with_transient_replication(self):

@test_category policy
"""
remove_cluster()
# We can test this with a single dc when CASSANDRA-15670 is fixed
use_multidc([3, 3])

Expand Down Expand Up @@ -647,6 +655,7 @@ def test_token_aware_with_transient_replication(self):


def _set_up_shuffle_test(self, keyspace, replication_factor):
remove_cluster()
use_singledc()
cluster, session = self._cluster_session_with_lbp(
TokenAwarePolicy(RoundRobinPolicy(), shuffle_replicas=True)
Expand Down Expand Up @@ -678,6 +687,7 @@ def _check_query_order_changes(self, session, keyspace):
self.coordinator_stats.reset_counts()

def test_white_list(self):
remove_cluster()
use_singledc()
keyspace = 'test_white_list'

Expand Down Expand Up @@ -723,6 +733,7 @@ def test_black_list_with_host_filter_policy(self):

@test_category policy
"""
remove_cluster()
use_singledc()
keyspace = 'test_black_list_with_hfp'
ignored_address = (IP_FORMAT % 2)
Expand Down
65 changes: 64 additions & 1 deletion tests/integration/standard/conftest.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,69 @@
import pytest
import logging

# Cluster topology groups for test ordering.
# Tests are sorted so that modules sharing the same CCM cluster run
# together, minimising expensive cluster teardown/restart cycles.
# Lower number = runs first. Modules not listed get a high default.
_MODULE_CLUSTER_ORDER = {
# Group 0: default 3-node singledc (CLUSTER_NAME = 'test_cluster')
"test_metadata": 0,
"test_policies": 0,
"test_control_connection": 0,
"test_routing": 0,
"test_prepared_statements": 0,
"test_metrics": 0,
"test_connection": 0,
"test_concurrent": 0,
"test_custom_payload": 0,
"test_query_paging": 0,
"test_single_interface": 0,
"test_rate_limit_exceeded": 0,
# Group 1: 'cluster_tests' (--smp 2, 3 nodes)
"test_cluster": 1,
"test_shard_aware": 1,
# Group 2: 'shared_aware' (--smp 2 --memory 2048M, 3 nodes)
"test_use_keyspace": 2,
"test_client_routes": 2,
# Group 3: single-node cluster
"test_types": 3,
"test_cython_protocol_handlers": 3,
"test_custom_protocol_handler": 3,
"test_row_factories": 3,
"test_udts": 3,
"test_client_warnings": 3,
"test_application_info": 3,
# Group 4: destructive / special clusters (run last)
"test_ip_change": 4,
"test_authentication": 4,
"test_authentication_misconfiguration": 4,
"test_custom_cluster": 4,
"test_query": 4,
# Group 5: tablets (destructive — decommissions a node)
"test_tablets": 5,
# Group 6: schema change + node kill (destructive — kills node2)
"test_concurrent_schema_change_and_node_kill": 6,
# Group 7: multi-dc (7 nodes — most expensive to create)
"test_rack_aware_policy": 7,
}


def pytest_collection_modifyitems(items):
"""Sort tests so modules with the same cluster topology are adjacent.

Uses the original collection index as tie-breaker so that the
definition order inside each file is preserved (important for tests
that depend on running order, e.g. destructive tablet tests).
"""
orig_order = {id(item): idx for idx, item in enumerate(items)}

def _sort_key(item):
module_name = item.module.__name__.rsplit(".", 1)[-1]
return (_MODULE_CLUSTER_ORDER.get(module_name, 99), item.fspath, orig_order[id(item)])

items[:] = sorted(items, key=_sort_key)


# from https://github.com/streamlit/streamlit/pull/5047/files
def pytest_sessionfinish():
# We're not waiting for scriptrunner threads to cleanly close before ending the PyTest,
Expand All @@ -10,4 +73,4 @@ def pytest_sessionfinish():
# * https://github.com/pytest-dev/pytest/issues/5282
# To prevent the exception from being raised on pytest_sessionfinish
# we disable exception raising in logging module
logging.raiseExceptions = False
logging.raiseExceptions = False
8 changes: 8 additions & 0 deletions tests/integration/standard/test_authentication.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,12 @@
#This can be tested for remote hosts, but the cluster has to be configured accordingly
#@local

_saved_scylla_ext_opts = None


def setup_module():
global _saved_scylla_ext_opts
_saved_scylla_ext_opts = os.environ.get('SCYLLA_EXT_OPTS')
if CASSANDRA_IP.startswith("127.0.0.") and not USE_CASS_EXTERNAL:
use_singledc(start=False)
ccm_cluster = get_cluster()
Expand Down Expand Up @@ -71,6 +75,10 @@ def _check_auth_ready():

def teardown_module():
remove_cluster() # this test messes with config
if _saved_scylla_ext_opts is None:
os.environ.pop('SCYLLA_EXT_OPTS', None)
else:
os.environ['SCYLLA_EXT_OPTS'] = _saved_scylla_ext_opts


class AuthenticationTests(unittest.TestCase):
Expand Down
23 changes: 20 additions & 3 deletions tests/integration/standard/test_client_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -519,9 +519,21 @@ def assert_routes_direct(test, cluster, expected_node_ids, direct_port=9042):
)


_saved_scylla_ext_opts = None


def setup_module():
global _saved_scylla_ext_opts
_saved_scylla_ext_opts = os.environ.get('SCYLLA_EXT_OPTS')
os.environ['SCYLLA_EXT_OPTS'] = "--smp 2 --memory 2048M"
use_cluster('test_client_routes', [3], start=True)
use_cluster('shared_aware', [3], start=True)


def teardown_module():
if _saved_scylla_ext_opts is None:
os.environ.pop('SCYLLA_EXT_OPTS', None)
else:
os.environ['SCYLLA_EXT_OPTS'] = _saved_scylla_ext_opts

@skip_scylla_version_lt(reason='scylladb/scylladb#26992 - system.client_routes is not yet supported',
scylla_version="2026.1.0")
Expand Down Expand Up @@ -1047,7 +1059,7 @@ def test_ssl_without_hostname_verification_through_nlb(self):
def routes_visible():
with TestCluster(
contact_points=["127.0.0.1"],
ssl_context=ssl_ctx,
ssl_context=ssl_ctx, connect_timeout=30,
) as c:
session = c.connect()
rs = session.execute(
Expand All @@ -1059,7 +1071,7 @@ def routes_visible():

wait_until_not_raised(
lambda: self.assertTrue(routes_visible()),
0.5, 10,
1, 30,
)

with Cluster(
Expand Down Expand Up @@ -1116,6 +1128,7 @@ class TestFullNodeReplacementThroughNlb(unittest.TestCase):

@classmethod
def setUpClass(cls):
cls._saved_scylla_ext_opts = os.environ.get('SCYLLA_EXT_OPTS')
os.environ['SCYLLA_EXT_OPTS'] = "--smp 2 --memory 2048M"
use_cluster('test_client_routes_replacement', [3], start=True)

Expand All @@ -1133,6 +1146,10 @@ def setUpClass(cls):
@classmethod
def tearDownClass(cls):
cls.direct_cluster.shutdown()
if cls._saved_scylla_ext_opts is None:
os.environ.pop('SCYLLA_EXT_OPTS', None)
else:
os.environ['SCYLLA_EXT_OPTS'] = cls._saved_scylla_ext_opts

def test_should_survive_full_node_replacement_through_nlb(self):
"""
Expand Down
4 changes: 2 additions & 2 deletions tests/integration/standard/test_client_warnings.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@

from cassandra.query import BatchStatement

from tests.integration import (use_singledc, PROTOCOL_VERSION, local, TestCluster,
from tests.integration import (use_single_node, PROTOCOL_VERSION, local, TestCluster,
requires_custom_payload, xfail_scylla)
from tests.util import assertRegex, assertDictEqual


def setup_module():
use_singledc()
use_single_node()

@xfail_scylla('scylladb/scylladb#10196 - scylla does not report warnings')
class ClientWarningTests(unittest.TestCase):
Expand Down
23 changes: 19 additions & 4 deletions tests/integration/standard/test_cluster.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,24 @@
log = logging.getLogger(__name__)


_saved_scylla_ext_opts = None


def setup_module():
os.environ['SCYLLA_EXT_OPTS'] = "--smp 1"
global _saved_scylla_ext_opts
_saved_scylla_ext_opts = os.environ.get('SCYLLA_EXT_OPTS')
os.environ['SCYLLA_EXT_OPTS'] = "--smp 2"
use_cluster("cluster_tests", [3], start=True, workloads=None)
warnings.simplefilter("always")


def teardown_module():
if _saved_scylla_ext_opts is None:
os.environ.pop('SCYLLA_EXT_OPTS', None)
else:
os.environ['SCYLLA_EXT_OPTS'] = _saved_scylla_ext_opts


class IgnoredHostPolicy(RoundRobinPolicy):

def __init__(self, ignored_hosts):
Expand Down Expand Up @@ -720,10 +732,13 @@ def _warning_are_issued_when_auth(self, auth_provider):
session = cluster.connect()
assert session.execute("SELECT * from system.local WHERE key='local'") is not None

# Three conenctions to nodes plus the control connection
# Verify that auth warnings are issued for connections where
# auth is configured but the server does not send a challenge.
# At minimum one warning per node connection (3 for a 3-node
# cluster). The control connection and shard-aware connections
# may add more, so we only assert a lower bound.
auth_warning = mock_handler.get_message_count('warning', "An authentication challenge was not sent")
assert auth_warning >= 4
assert auth_warning == mock_handler.get_message_count("debug", "Got ReadyMessage on new connection")
assert auth_warning >= 3

def _wait_for_all_shard_connections(self, cluster, timeout=30):
"""Wait until all shard-aware connections are fully established."""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@


def setup_module():
use_cluster('test_concurrent_schema_change_and_node_kill', [3], start=True)
use_cluster('test_schema_kill', [3], start=True)

@local
class TestConcurrentSchemaChangeAndNodeKill(unittest.TestCase):
Expand Down
4 changes: 2 additions & 2 deletions tests/integration/standard/test_custom_protocol_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
ContinuousPagingOptions, NoHostAvailable)
from cassandra import ProtocolVersion, ConsistencyLevel

from tests.integration import use_singledc, drop_keyspace_shutdown_cluster, \
from tests.integration import use_single_node, drop_keyspace_shutdown_cluster, \
greaterthanorequalcass30, execute_with_long_wait_retry, greaterthanorequalcass3_10, \
TestCluster, greaterthanorequalcass40
from tests.integration.datatype_utils import update_datatypes, PRIMITIVE_DATATYPES
Expand All @@ -32,7 +32,7 @@


def setup_module():
use_singledc()
use_single_node()
update_datatypes()


Expand Down
Loading
Loading