diff --git a/auth_test.py b/auth_test.py index 1f0dec102c..33f38039a5 100644 --- a/auth_test.py +++ b/auth_test.py @@ -3,7 +3,7 @@ import time from collections import namedtuple from datetime import datetime, timedelta -from distutils.version import LooseVersion +from packaging.version import parse import re import pytest import logging @@ -35,7 +35,7 @@ def role_creator_permissions(self, creator, role): return [(creator, role, perm) for perm in permissions] def cluster_version_has_masking_permissions(self): - return self.cluster.version() >= LooseVersion('5.0') + return self.cluster.version() >= parse('5.0') def data_resource_creator_permissions(self, creator, resource): """ @@ -1371,7 +1371,7 @@ def test_creator_of_db_resource_granted_all_permissions(self): as_mike.execute("CREATE KEYSPACE ks WITH replication = {'class':'SimpleStrategy', 'replication_factor':1}") as_mike.execute("CREATE TABLE ks.cf (id int primary key, val int)") as_mike.execute("CREATE ROLE role1 WITH PASSWORD = '11111' AND SUPERUSER = false AND LOGIN = true") - if self.cluster.version() < LooseVersion('4.2'): + if self.cluster.version() < parse('4.2'): as_mike.execute("""CREATE FUNCTION ks.state_function_1(a int, b int) CALLED ON NULL INPUT RETURNS int @@ -1668,7 +1668,7 @@ def test_filter_granted_permissions_by_resource_type(self): self.superuser.execute("CREATE TABLE ks.cf (id int primary key, val int)") self.superuser.execute("CREATE ROLE mike WITH PASSWORD = '12345' AND SUPERUSER = false AND LOGIN = true") self.superuser.execute("CREATE ROLE role1 WITH SUPERUSER = false AND LOGIN = false") - if self.cluster.version() < LooseVersion('4.2'): + if self.cluster.version() < parse('4.2'): self.superuser.execute("CREATE FUNCTION ks.state_func(a int, b int) CALLED ON NULL INPUT RETURNS int LANGUAGE javascript AS 'a+b'") else: self.superuser.execute("CREATE FUNCTION ks.state_func(a int, b int) CALLED ON NULL INPUT RETURNS int LANGUAGE java AS ' return a+b;'") @@ -2150,7 +2150,7 @@ def test_grant_revoke_udf_permissions(self): """ self.setup_table() self.superuser.execute("CREATE ROLE mike WITH PASSWORD = '12345' AND LOGIN = true") - if self.cluster.version() < LooseVersion('4.2'): + if self.cluster.version() < parse('4.2'): self.superuser.execute("CREATE FUNCTION ks.plus_one ( input int ) CALLED ON NULL INPUT RETURNS int LANGUAGE javascript AS 'input + 1'") self.superuser.execute("CREATE FUNCTION ks.\"plusOne\" ( input int ) CALLED ON NULL INPUT RETURNS int LANGUAGE javascript AS 'input + 1'") else: @@ -2199,7 +2199,7 @@ def test_grant_revoke_are_idempotent(self): """ self.setup_table() self.superuser.execute("CREATE ROLE mike") - if self.cluster.version() < LooseVersion('4.2'): + if self.cluster.version() < parse('4.2'): self.superuser.execute("CREATE FUNCTION ks.plus_one ( input int ) CALLED ON NULL INPUT RETURNS int LANGUAGE javascript AS 'input + 1'") else: self.superuser.execute("CREATE FUNCTION ks.plus_one ( input int ) CALLED ON NULL INPUT RETURNS int LANGUAGE java AS 'return input + 1;'") @@ -2230,7 +2230,7 @@ def test_function_resource_hierarchy_permissions(self): self.superuser.execute("INSERT INTO ks.t1 (k,v) values (1,1)") self.superuser.execute("CREATE ROLE mike WITH PASSWORD = '12345' AND LOGIN = true") self.superuser.execute("GRANT SELECT ON ks.t1 TO mike") - if self.cluster.version() < LooseVersion('4.2'): + if self.cluster.version() < parse('4.2'): self.superuser.execute("CREATE FUNCTION ks.func_one ( input int ) CALLED ON NULL INPUT RETURNS int LANGUAGE javascript AS 'input + 1'") self.superuser.execute("CREATE FUNCTION ks.func_two ( input int ) CALLED ON NULL INPUT RETURNS int LANGUAGE javascript AS 'input + 1'") else: @@ -2289,7 +2289,7 @@ def test_udf_permissions_validation(self): * Verify mike can create a new UDF iff he has the CREATE permission """ self.setup_table() - if self.cluster.version() < LooseVersion('4.2'): + if self.cluster.version() < parse('4.2'): self.superuser.execute("CREATE FUNCTION ks.plus_one ( input int ) CALLED ON NULL INPUT RETURNS int LANGUAGE javascript AS 'input + 1'") else: self.superuser.execute("CREATE FUNCTION ks.plus_one ( input int ) CALLED ON NULL INPUT RETURNS int LANGUAGE java AS 'return input + 1;'") @@ -2297,7 +2297,7 @@ def test_udf_permissions_validation(self): as_mike = self.get_session(user='mike', password='12345') # can't replace an existing function without ALTER permission on the parent ks - if self.cluster.version() < LooseVersion('4.2'): + if self.cluster.version() < parse('4.2'): cql = "CREATE OR REPLACE FUNCTION ks.plus_one( input int ) CALLED ON NULL INPUT RETURNS int LANGUAGE javascript as '1 + input'" else: cql = "CREATE OR REPLACE FUNCTION ks.plus_one( input int ) CALLED ON NULL INPUT RETURNS int LANGUAGE java as 'return 1 + input;'" @@ -2340,7 +2340,7 @@ def test_udf_permissions_validation(self): InvalidRequest) # can't create a new function without CREATE on the parent keyspace's collection of functions - if self.cluster.version() < LooseVersion('4.2'): + if self.cluster.version() < parse('4.2'): cql = "CREATE FUNCTION ks.plus_one ( input int ) CALLED ON NULL INPUT RETURNS int LANGUAGE javascript AS 'input + 1'" else: cql = "CREATE FUNCTION ks.plus_one ( input int ) CALLED ON NULL INPUT RETURNS int LANGUAGE java AS 'return input + 1;'" @@ -2360,7 +2360,7 @@ def test_drop_role_cleans_up_udf_permissions(self): """ self.setup_table() self.superuser.execute("CREATE ROLE mike WITH PASSWORD = '12345' AND LOGIN = true") - if self.cluster.version() < LooseVersion('4.2'): + if self.cluster.version() < parse('4.2'): self.superuser.execute("CREATE FUNCTION ks.plus_one ( input int ) CALLED ON NULL INPUT RETURNS int LANGUAGE javascript AS 'input + 1'") else: self.superuser.execute("CREATE FUNCTION ks.plus_one ( input int ) CALLED ON NULL INPUT RETURNS int LANGUAGE java AS 'return input + 1;'") @@ -2391,7 +2391,7 @@ def test_drop_function_and_keyspace_cleans_up_udf_permissions(self): """ self.setup_table() self.superuser.execute("CREATE ROLE mike WITH PASSWORD = '12345' AND LOGIN = true") - if self.cluster.version() < LooseVersion('4.2'): + if self.cluster.version() < parse('4.2'): self.superuser.execute("CREATE FUNCTION ks.plus_one ( input int ) CALLED ON NULL INPUT RETURNS int LANGUAGE javascript AS 'input + 1'") else: self.superuser.execute("CREATE FUNCTION ks.plus_one ( input int ) CALLED ON NULL INPUT RETURNS int LANGUAGE java AS 'return input + 1;'") @@ -2422,7 +2422,7 @@ def test_udf_with_overloads_permissions(self): """ self.setup_table() self.superuser.execute("CREATE ROLE mike WITH PASSWORD = '12345' AND LOGIN = true") - if self.cluster.version() < LooseVersion('4.2'): + if self.cluster.version() < parse('4.2'): self.superuser.execute("CREATE FUNCTION ks.plus_one ( input int ) CALLED ON NULL INPUT RETURNS int LANGUAGE javascript AS 'input + 1'") self.superuser.execute("CREATE FUNCTION ks.plus_one ( input double ) CALLED ON NULL INPUT RETURNS double LANGUAGE javascript AS 'input + 1'") else: @@ -2469,7 +2469,7 @@ def test_drop_keyspace_cleans_up_function_level_permissions(self): """ self.setup_table() self.superuser.execute("CREATE ROLE mike WITH PASSWORD = '12345' AND LOGIN = true") - if self.cluster.version() < LooseVersion('4.2'): + if self.cluster.version() < parse('4.2'): self.superuser.execute("CREATE FUNCTION ks.state_func (a int, b int) CALLED ON NULL INPUT RETURNS int LANGUAGE javascript AS 'a + b'") else: self.superuser.execute("CREATE FUNCTION ks.state_func (a int, b int) CALLED ON NULL INPUT RETURNS int LANGUAGE java AS 'return a + b;'") @@ -2525,7 +2525,7 @@ def verify_udf_permissions(self, cql): @param cql The statement to verify. Should contain the UDF ks.plus_one """ self.setup_table() - if self.cluster.version() < LooseVersion('4.2'): + if self.cluster.version() < parse('4.2'): self.superuser.execute("CREATE FUNCTION ks.plus_one ( input int ) CALLED ON NULL INPUT RETURNS int LANGUAGE javascript AS 'input + 1'") else: self.superuser.execute("CREATE FUNCTION ks.plus_one ( input int ) CALLED ON NULL INPUT RETURNS int LANGUAGE java AS 'return input + 1;'") @@ -2549,7 +2549,7 @@ def test_inheritence_of_udf_permissions(self): self.setup_table() self.superuser.execute("CREATE ROLE function_user") self.superuser.execute("GRANT EXECUTE ON ALL FUNCTIONS IN KEYSPACE ks TO function_user") - if self.cluster.version() < LooseVersion('4.2'): + if self.cluster.version() < parse('4.2'): self.superuser.execute("CREATE FUNCTION ks.plus_one ( input int ) CALLED ON NULL INPUT RETURNS int LANGUAGE javascript AS 'input + 1'") else: self.superuser.execute("CREATE FUNCTION ks.plus_one ( input int ) CALLED ON NULL INPUT RETURNS int LANGUAGE java AS 'return input + 1;'") @@ -2721,7 +2721,7 @@ def assert_unauthenticated(self, user, password): host, error = response._excinfo[1].errors.popitem() message = "Provided username {user} and/or password are incorrect".format(user=user)\ - if node.cluster.version() >= LooseVersion('3.10') \ + if node.cluster.version() >= parse('3.10') \ else "Username and/or password are incorrect" pattern = 'Failed to authenticate to {host}: Error from server: code=0100 ' \ '[Bad credentials] message="{message}"'.format(host=host, message=message) diff --git a/bootstrap_test.py b/bootstrap_test.py index ec01b892a4..9f4e0461e1 100644 --- a/bootstrap_test.py +++ b/bootstrap_test.py @@ -7,7 +7,8 @@ import time import logging import signal -from distutils.version import LooseVersion +from packaging.version import parse + from cassandra import ConsistencyLevel from cassandra.concurrent import execute_concurrent_with_args @@ -136,7 +137,7 @@ def bootstrap_on_write_survey_and_join(cluster, token): assert len(node2.grep_log('Startup complete, but write survey mode is active, not becoming an active ring member.')) # bootstrapping is considered complete if streaming is successful. Post CEP-21 this is distinct from # fully joining the ring or leaving write survey mode - bootstrap_state = 'COMPLETED' if self.cluster.version() >= LooseVersion('5.1') else 'IN_PROGRESS' + bootstrap_state = 'COMPLETED' if self.cluster.version() >= parse('5.1') else 'IN_PROGRESS' assert_bootstrap_state(self, node2, bootstrap_state) node2.nodetool("join") @@ -329,7 +330,7 @@ def test_rf_gt_nodes_multidc_should_succeed(self): # TCM, node2 also logs the warning as it applies the transform when it gets replicated to it by the CMS. if cluster.version() >= '4.0': warning = 'Your replication factor 3 for keyspace k is higher than the number of nodes 1 for datacenter dc1' - if cluster.version() >= LooseVersion('5.1'): # we now log this on all nodes + if cluster.version() >= parse('5.1'): # we now log this on all nodes assert len(node1.grep_log(warning)) == 2 assert len(node2.grep_log(warning)) == 1 else: @@ -342,7 +343,7 @@ def test_rf_gt_nodes_multidc_should_succeed(self): if cluster.version() >= '4.0': warning = 'Your replication factor 2 for keyspace k is higher than the number of nodes 1 for datacenter dc1' - if cluster.version() >= LooseVersion('5.1'): + if cluster.version() >= parse('5.1'): assert len(node1.grep_log(warning)) == 2 # we now log this on all nodes assert len(node2.grep_log(warning)) == 1 else: @@ -411,7 +412,7 @@ def _bootstrap_test_with_replica_down(self, consistent_range_movement, rf=2): node3 = new_node(cluster, token=node3_token) jvmargs = ["-Dcassandra.consistent.rangemovement={}".format(consistent_range_movement)] - if cluster.version() >= LooseVersion('5.1'): + if cluster.version() >= parse('5.1'): node3.set_configuration_options(values={'progress_barrier_min_consistency_level': 'NODE_LOCAL', 'progress_barrier_default_consistency_level': 'NODE_LOCAL', 'progress_barrier_timeout': '2000ms'}) node3.start(wait_for_binary_proto=successful_bootstrap_expected, wait_other_notice=successful_bootstrap_expected, @@ -782,7 +783,7 @@ def test_failed_bootstrap_wiped_node_can_join(self): # wipe any data for node2 self._cleanup(node2) - if cluster.version() >= LooseVersion('5.1'): + if cluster.version() >= parse('5.1'): node1.watch_log_for("127.0.0.2:7000 is now DOWN", from_mark=mark) res = node1.nodetool('abortbootstrap --ip 127.0.0.2') # Now start it again, it should be allowed to join diff --git a/client_network_stop_start_test.py b/client_network_stop_start_test.py index bc95ca5e74..52031b365f 100644 --- a/client_network_stop_start_test.py +++ b/client_network_stop_start_test.py @@ -1,13 +1,10 @@ import logging -import os -import os.path + import pytest -import shutil import string import time +from packaging.version import parse -from ccmlib.node import TimeoutError -from distutils.version import LooseVersion from dtest import Tester from tools import sslkeygen @@ -50,7 +47,7 @@ def _assert_binary_actually_found(self, node_or_cluster): def _assert_client_enable(self, node, native_enabled=True, thrift_enabled=False): out = node.nodetool("info") self._assert_client_active_msg("Native Transport", native_enabled, out.stdout) - if node.get_cassandra_version() >= LooseVersion('4.0'): + if node.get_cassandra_version() >= parse('4.0'): assert "Thrift" not in out.stdout, "Thrift found in output: {}".format(out.stdout) else: self._assert_client_active_msg("Thrift", thrift_enabled, out.stdout) diff --git a/commitlog_test.py b/commitlog_test.py index 54f217196d..5af90dda06 100644 --- a/commitlog_test.py +++ b/commitlog_test.py @@ -4,7 +4,7 @@ import stat import struct import time -from distutils.version import LooseVersion +from packaging.version import parse import pytest import logging @@ -172,7 +172,7 @@ def test_mv_lock_contention_during_replay(self): @jira_ticket CASSANDRA-11891 """ cluster_ver = self.cluster.version() - if LooseVersion('3.1') <= cluster_ver < LooseVersion('3.7'): + if parse('3.1') <= cluster_ver < parse('3.7'): pytest.skip("Fixed in 3.0.7 and 3.7") node1 = self.node1 @@ -320,7 +320,6 @@ def test_stop_failure_policy(self): self.prepare() self._provoke_commitlog_failure() - time.sleep(2) failure = self.node1.grep_log("Failed .+ commit log segments. Commit disk failure policy is stop; terminating thread") logger.debug(failure) assert failure, "Cannot find the commitlog failure message in logs" diff --git a/compaction_test.py b/compaction_test.py index b37db3ece6..d1fb812cca 100644 --- a/compaction_test.py +++ b/compaction_test.py @@ -4,7 +4,8 @@ import string import tempfile import time -from distutils.version import LooseVersion +from packaging.version import parse + import pytest import parse import logging @@ -150,7 +151,7 @@ def test_bloomfilter_size(self, strategy): dir_count = len(node1.data_directories()) logger.debug("sstable_count is: {}".format(sstable_count)) logger.debug("dir_count is: {}".format(dir_count)) - if node1.get_cassandra_version() < LooseVersion('3.2'): + if node1.get_cassandra_version() < parse('3.2'): size_factor = sstable_count else: size_factor = sstable_count / float(dir_count) @@ -226,7 +227,7 @@ def test_dtcs_deletion(self, strategy): time.sleep(40) expired_sstables = node1.get_sstables('ks', 'cf') expected_sstable_count = 1 - if self.cluster.version() > LooseVersion('3.1'): + if self.cluster.version() > parse('3.1'): expected_sstable_count = cluster.data_dir_count assert len(expired_sstables) == expected_sstable_count # write a new sstable to make DTCS check for expired sstables: @@ -290,7 +291,7 @@ def test_compaction_throughput(self): "B": 1. / (1024 * 1024), } - units = ['MB'] if cluster.version() < LooseVersion('3.6') else ['B', 'KiB', 'MiB', 'GiB'] + units = ['MB'] if cluster.version() < parse('3.6') else ['B', 'KiB', 'MiB', 'GiB'] assert found_units in units logger.debug(avgthroughput) @@ -376,7 +377,7 @@ def test_large_compaction_warning(self): node.nodetool('compact ks large') verb = 'Writing' if self.cluster.version() > '2.2' else 'Compacting' - sizematcher = '\d+ bytes' if self.cluster.version() < LooseVersion('3.6') else '\d+\.\d{3}(K|M|G)iB' + sizematcher = '\d+ bytes' if self.cluster.version() < parse('3.6') else '\d+\.\d{3}(K|M|G)iB' node.watch_log_for('{} large partition ks/large:user \({}'.format(verb, sizematcher), from_mark=mark, timeout=180) ret = list(session.execute("SELECT properties from ks.large where userid = 'user'")) diff --git a/compression_test.py b/compression_test.py index cb7fa88d0e..0686535e49 100644 --- a/compression_test.py +++ b/compression_test.py @@ -3,7 +3,8 @@ import logging from dtest import create_ks -from distutils.version import LooseVersion +from packaging.version import parse + from scrub_test import TestHelper from tools.assertions import assert_crc_check_chance_equal @@ -81,7 +82,7 @@ def test_compression_cql_options(self): assert '256' == meta.options['compression']['chunk_length_in_kb'] assert_crc_check_chance_equal(session, "compression_opts_table", 0.25) - if self.cluster.version() < LooseVersion('5.0'): + if self.cluster.version() < parse('5.0'): warn = node.grep_log("The option crc_check_chance was deprecated as a compression option.") assert len(warn) == 0 session.execute(""" diff --git a/configuration_test.py b/configuration_test.py index 277be6078f..63ddd721d6 100644 --- a/configuration_test.py +++ b/configuration_test.py @@ -8,7 +8,8 @@ from dtest import Tester, create_ks from tools.jmxutils import (JolokiaAgent, make_mbean) -from distutils.version import LooseVersion +from packaging.version import parse + logger = logging.getLogger(__name__) @@ -27,7 +28,7 @@ def test_compression_chunk_length(self): create_table_query = "CREATE TABLE test_table (row varchar, name varchar, value int, PRIMARY KEY (row, name));" - if self.cluster.version() >= LooseVersion('5.0'): + if self.cluster.version() >= parse('5.0'): alter_chunk_len_query = "ALTER TABLE test_table WITH " \ "compression = {{'class' : 'SnappyCompressor', " \ "'chunk_length_in_kb' : {chunk_length}}};" diff --git a/conftest.py b/conftest.py index be4f02c171..4b0f5b76c5 100644 --- a/conftest.py +++ b/conftest.py @@ -10,7 +10,7 @@ import shutil import time from datetime import datetime -from distutils.version import LooseVersion +from packaging.version import parse # Python 3 imports from itertools import zip_longest @@ -377,7 +377,7 @@ def fixture_dtest_setup(request, # Based on https://bugs.python.org/file25808/14894.patch def loose_version_compare(a, b): - for i, j in zip_longest(a.version, b.version, fillvalue=''): + for i, j in zip_longest(str(a), str(b), fillvalue=''): if type(i) != type(j): i = str(i) j = str(j) @@ -389,8 +389,8 @@ def loose_version_compare(a, b): return 1 # Longer version strings with equal prefixes are equal, but if one version string is longer than it is greater - aLen = len(a.version) - bLen = len(b.version) + aLen = len(str(a)) + bLen = len(str(b)) if aLen == bLen: return 0 elif aLen < bLen: @@ -415,7 +415,9 @@ def _skip_msg(current_running_version, since_version, max_version): if loose_version_compare(current_running_version, previous) < 0: return None - previous = LooseVersion('.'.join([str(s) for s in sv.version[:-1]])) + #changed + version_string = '.'.join([str(s) for s in sv.version[:-1]]) + previous = parse(version_string) # no matches found, so fail return "%s < %s" % (current_running_version, since_version) @@ -432,19 +434,19 @@ def fixture_since(request, fixture_dtest_setup): max_version_str = request.node.get_closest_marker('since').kwargs.get('max_version', None) max_version = None if max_version_str: - max_version = LooseVersion(max_version_str) + max_version = parse(max_version_str) since_str_or_list = request.node.get_closest_marker('since').args[0] if not isinstance(since_str_or_list, str) and isinstance(since_str_or_list, collections.Sequence): - since = [LooseVersion(since_str) for since_str in since_str_or_list] + since = [parse(since_str) for since_str in since_str_or_list] else: - since = LooseVersion(since_str_or_list) + since = parse(since_str_or_list) # For upgrade tests don't run the test if any of the involved versions # are excluded by the annotation if hasattr(request.cls, "UPGRADE_PATH"): upgrade_path = request.cls.UPGRADE_PATH if hasattr(upgrade_path, 'upgrade_meta'): - skip_msg = _skip_msg(LooseVersion(upgrade_path.upgrade_meta.family), since, max_version) + skip_msg = _skip_msg(parse(upgrade_path.upgrade_meta.family), since, max_version) if skip_msg: pytest.skip(skip_msg) ccm_repo_cache_dir, _ = ccmlib.repository.setup(upgrade_path.starting_meta.version) @@ -485,7 +487,7 @@ def fixture_ported_to_in_jvm(request, fixture_dtest_setup): if marker: from_str = marker.args[0] if marker.args else "2.2.13" # JVM dtests were introduced on 2.2.13 - ported_from_version = LooseVersion(from_str) + ported_from_version = parse(from_str) use_vnodes = request.config.getoption("--use-vnodes") # For upgrade tests don't run the test if any of the involved versions are excluded by the annotation @@ -497,7 +499,7 @@ def fixture_ported_to_in_jvm(request, fixture_dtest_setup): upgrade_path = request.cls.UPGRADE_PATH if hasattr(upgrade_path, 'upgrade_meta'): - skip_msg = _skip_ported_msg(LooseVersion(upgrade_path.upgrade_meta.family), ported_from_version) + skip_msg = _skip_ported_msg(parse(upgrade_path.upgrade_meta.family), ported_from_version) if skip_msg: pytest.skip(skip_msg) ccm_repo_cache_dir, _ = ccmlib.repository.setup(upgrade_path.starting_meta.version) @@ -518,7 +520,7 @@ def fixture_ported_to_in_jvm(request, fixture_dtest_setup): current_running_version = fixture_dtest_setup.dtest_config.cassandra_version_from_build # vnodes weren't supported nor tested before 4.1, so we can't skip them if the version is older than that - if use_vnodes and loose_version_compare(current_running_version, LooseVersion('4.1')) < 0: + if use_vnodes and loose_version_compare(current_running_version, ('4.1')) < 0: return skip_msg = _skip_ported_msg(current_running_version, ported_from_version) @@ -530,7 +532,7 @@ def fixture_ported_to_in_jvm(request, fixture_dtest_setup): def fixture_skip_version(request, fixture_dtest_setup): marker = request.node.get_closest_marker('skip_version') if marker is not None: - version_to_skip = LooseVersion(marker.args[0]) + version_to_skip = parse(marker.args[0]) if version_to_skip == fixture_dtest_setup.dtest_config.cassandra_version_from_build: pytest.skip("Test marked not to run on version %s" % version_to_skip) diff --git a/counter_test.py b/counter_test.py index 2a9837d703..c325815196 100644 --- a/counter_test.py +++ b/counter_test.py @@ -10,7 +10,8 @@ from tools.assertions import assert_invalid, assert_length_equal, assert_one from dtest import Tester, create_ks, create_cf, mk_bman_path from tools.data import rows_to_list -from distutils.version import LooseVersion +from packaging.version import parse + since = pytest.mark.since logger = logging.getLogger(__name__) @@ -178,7 +179,7 @@ def test_upgrade(self): c counter ) """ - if self.cluster.version() >= LooseVersion('5.0'): + if self.cluster.version() >= parse('5.0'): query = query + "WITH compression = { 'class' : 'SnappyCompressor' }" else: query = query + "WITH compression = { 'sstable_compression' : 'SnappyCompressor' }" diff --git a/cql_test.py b/cql_test.py index 30c5507d02..e1f0075796 100644 --- a/cql_test.py +++ b/cql_test.py @@ -13,7 +13,8 @@ from cassandra.query import SimpleStatement from dtest import Tester, create_ks, mk_bman_path -from distutils.version import LooseVersion +from packaging.version import parse + from thrift_bindings.thrift010.ttypes import \ ConsistencyLevel as ThriftConsistencyLevel from thrift_bindings.thrift010.ttypes import (CfDef, Column, ColumnOrSuperColumn, @@ -651,7 +652,7 @@ def test_prepared_statement_invalidation(self): result = session.execute(wildcard_prepared.bind(None)) assert result, [(0, 0, 0 == None)] - if self.cluster.version() < LooseVersion('3.0'): + if self.cluster.version() < parse('3.0'): explicit_prepared = session.prepare("SELECT k, a, b, d FROM test") # when the type is altered, both statements will need to be re-prepared @@ -1596,7 +1597,7 @@ def _validate_non_existing_or_null_values(self, table_name, session): assert_one(session, "SELECT a, s, d FROM {} WHERE a = 4".format(table_name), [4, 4, None]) def _is_new_lwt_format_version(self, version): - return version > LooseVersion('3.9') or (version > LooseVersion('3.0.9') and version < LooseVersion('3.1')) + return version > parse('3.9') or (version > parse('3.0.9') and version < parse('3.1')) @flaky def test_conditional_updates_on_static_columns_with_null_values(self): diff --git a/cql_tracing_test.py b/cql_tracing_test.py index 6a7a741964..d1ac513dfa 100644 --- a/cql_tracing_test.py +++ b/cql_tracing_test.py @@ -1,7 +1,8 @@ import pytest import logging -from distutils.version import LooseVersion +from packaging.version import parse + from dtest import Tester, create_ks @@ -27,7 +28,7 @@ def prepare(self, create_keyspace=True, nodes=3, rf=3, protocol_version=3, jvm_a cluster = self.cluster opts = {'write_request_timeout_in_ms': 30000, 'read_request_timeout_in_ms': 30000} - if self.cluster.version() >= LooseVersion('4.1'): + if self.cluster.version() >= parse('4.1'): opts['native_transport_timeout'] = '30s' cluster.set_configuration_options(values=opts); @@ -70,7 +71,7 @@ def trace(self, session): """) out, err, _ = node1.run_cqlsh('TRACING ON') - if self.cluster.version() >= LooseVersion('5.0'): + if self.cluster.version() >= parse('5.0'): # See CASSANDRA-18547 assert 'TRACING set to ON' in out else: @@ -144,7 +145,7 @@ def test_tracing_unknown_impl(self): errs = self.cluster.nodelist()[0].grep_log_for_errors() logger.debug('Errors after attempted trace with unknown tracing class: {errs}'.format(errs=errs)) assert len(errs) == 1 - if self.cluster.version() >= LooseVersion('3.10'): + if self.cluster.version() >= parse('3.10'): # See CASSANDRA-11706 and PR #1281 assert len(errs[0]) > 0 else: @@ -177,7 +178,7 @@ def test_tracing_default_impl(self): errs = self.cluster.nodelist()[0].grep_log_for_errors() logger.debug('Errors after attempted trace with default tracing class: {errs}'.format(errs=errs)) assert len(errs) == 1 - if self.cluster.version() >= LooseVersion('3.10'): + if self.cluster.version() >= parse('3.10'): # See CASSANDRA-11706 and PR #1281 assert len(errs[0]) > 0 else: @@ -188,7 +189,7 @@ def test_tracing_default_impl(self): # part of the expected error to avoid having to escape parens and # periods for regexes. - if self.cluster.version() >= LooseVersion('3.10'): + if self.cluster.version() >= parse('3.10'): # See CASSANDRA-11706 and PR #1281 check_for_errs_in = errs[0][1] else: diff --git a/dtest.py b/dtest.py index da7b31a711..8daa5208e8 100644 --- a/dtest.py +++ b/dtest.py @@ -1,14 +1,16 @@ +import os +import sys + import configparser import copy import logging -import os import re import subprocess -import sys + import threading import time import traceback -from distutils.version import LooseVersion +from packaging import version import pytest import cassandra @@ -21,13 +23,12 @@ from cassandra.auth import PlainTextAuthProvider from cassandra.cluster import ExecutionProfile from cassandra.policies import RetryPolicy, RoundRobinPolicy +from tools.misc import retry_till_success from ccmlib.common import get_version_from_build from ccmlib.node import ToolError, TimeoutError -from tools.misc import retry_till_success from upgrade_tests.upgrade_manifest import build_upgrade_pairs - LOG_SAVED_DIR = "logs" try: os.mkdir(LOG_SAVED_DIR) @@ -46,8 +47,8 @@ if config.has_option('main', 'default_dir'): DEFAULT_DIR = os.path.expanduser(config.get('main', 'default_dir')) -MAJOR_VERSION_4 = LooseVersion('4.0') -MAJOR_VERSION_5 = LooseVersion('5.0') +MAJOR_VERSION_4 = version.Version('4.0') +MAJOR_VERSION_5 = version.Version('5.0') logger = logging.getLogger(__name__) @@ -297,13 +298,13 @@ def get_eager_protocol_version(cassandra_version): Returns the highest protocol version accepted by the given C* version """ - if LooseVersion('4.0') <= cassandra_version: + if version.parse('4.0') <= version.parse(cassandra_version): protocol_version = 5 - elif LooseVersion('3.0') <= cassandra_version: + elif version.parse('3.0') <= version.parse(cassandra_version): protocol_version = 4 - elif LooseVersion('2.1') <= cassandra_version: + elif version.parse('2.1') <= version.parse(cassandra_version): protocol_version = 3 - elif LooseVersion('2.0') <= cassandra_version: + elif version.parse('2.0') <= version.parse(cassandra_version): protocol_version = 2 else: protocol_version = 1 @@ -362,7 +363,7 @@ def create_cf(session, name, key_type="varchar", speculative_retry=None, read_re try: retry_till_success(session.execute, query=query, timeout=120, bypassed_exception=cassandra.OperationTimedOut) except cassandra.AlreadyExists: - logger.warn('AlreadyExists executing create cf query \'%s\'' % query) + logger.warning('AlreadyExists executing create cf query \'%s\'' % query) session.cluster.control_connection.wait_for_schema_agreement(wait_time=120) #Going to ignore OperationTimedOut from create CF, so need to validate it was indeed created session.execute('SELECT * FROM %s LIMIT 1' % name); @@ -372,7 +373,7 @@ def create_cf_simple(session, name, query): try: retry_till_success(session.execute, query=query, timeout=120, bypassed_exception=cassandra.OperationTimedOut) except cassandra.AlreadyExists: - logger.warn('AlreadyExists executing create cf query \'%s\'' % query) + logger.warning('AlreadyExists executing create cf query \'%s\'' % query) session.cluster.control_connection.wait_for_schema_agreement(wait_time=120) #Going to ignore OperationTimedOut from create CF, so need to validate it was indeed created session.execute('SELECT * FROM %s LIMIT 1' % name) @@ -392,11 +393,11 @@ def create_ks(session, name, rf): try: retry_till_success(session.execute, query=query, timeout=120, bypassed_exception=cassandra.OperationTimedOut) except cassandra.AlreadyExists: - logger.warn('AlreadyExists executing create ks query \'%s\'' % query) + logger.warning('AlreadyExists executing create ks query \'%s\'' % query) session.cluster.control_connection.wait_for_schema_agreement(wait_time=120) - #Also validates it was indeed created even though we ignored OperationTimedOut - #Might happen some of the time because CircleCI disk IO is unreliable and hangs randomly + # Also validates it was indeed created even though we ignored OperationTimedOut + # Might happen some of the time because CircleCI disk IO is unreliable and hangs randomly session.execute('USE {}'.format(name)) diff --git a/dtest_setup.py b/dtest_setup.py index 3980259bfc..2f994f424d 100644 --- a/dtest_setup.py +++ b/dtest_setup.py @@ -21,7 +21,8 @@ from dtest import (get_ip_from_node, make_execution_profile, get_auth_provider, get_port_from_node, get_eager_protocol_version, hack_legacy_parsing) -from distutils.version import LooseVersion +from packaging.version import parse + from tools.context import log_filter from tools.funcutils import merge_dicts @@ -94,7 +95,7 @@ def install_legacy_parsing(self, node): def install_nodetool_legacy_parsing(self): """ Install nodetool legacy parsing on the cluster """ - if self.cluster.version() < LooseVersion('3.11.13'): + if self.cluster.version() < parse('3.11.13'): logger.debug("hacking nodetool for legacy parsing on {}".format(self.cluster.version())) for node in self.cluster.nodelist(): self.install_legacy_parsing(node) @@ -374,7 +375,7 @@ def dump_jfr_recording(self, nodes): logger.debug(stderr) def supports_v5_protocol(self, cluster_version): - return cluster_version >= LooseVersion('4.0') + return cluster_version >= parse('4.0') def cleanup_last_test_dir(self): if os.path.exists(self.last_test_dir): diff --git a/jmx_auth_test.py b/jmx_auth_test.py index e5b3d03c28..06db6737e0 100644 --- a/jmx_auth_test.py +++ b/jmx_auth_test.py @@ -2,7 +2,8 @@ import string import pytest import logging -from distutils.version import LooseVersion +from packaging.version import parse + from ccmlib.node import ToolError from dtest import Tester @@ -108,7 +109,7 @@ def prepare(self, nodes=1, permissions_validity=0): def authentication_fail_message(self, node, username): return "Provided username {user} and/or password are incorrect".format(user=username) \ - if node.cluster.version() >= LooseVersion('3.10') else "Username and/or password are incorrect" + if node.cluster.version() >= parse('3.10') else "Username and/or password are incorrect" def username(self): return ''.join(random.choice(string.ascii_lowercase) for _ in range(8)) \ No newline at end of file diff --git a/jmx_test.py b/jmx_test.py index bc5f8b1277..4af53fc9ff 100644 --- a/jmx_test.py +++ b/jmx_test.py @@ -8,7 +8,8 @@ import ccmlib.common from ccmlib.node import ToolError -from distutils.version import LooseVersion +from packaging.version import parse + from dtest import Tester, create_ks from tools.jmxutils import (JolokiaAgent, enable_jmx_ssl, make_mbean) @@ -62,7 +63,7 @@ def test_netstats(self): if not isinstance(e, ToolError): raise else: - if cluster.version() >= LooseVersion('5.1'): + if cluster.version() >= parse('5.1'): assert re.search("Server is not initialized yet, cannot run nodetool", repr(e)), str(e) else: assert re.search("ConnectException: 'Connection refused( \(Connection refused\))?'.", repr(e)), str(e) @@ -201,9 +202,9 @@ def test_compactionstats(self): # Run a major compaction. This will be the compaction whose # progress we track. node.nodetool_process('compact keyspace1') - if self.cluster.version() >= LooseVersion('4.0'): + if self.cluster.version() >= parse('4.0'): node.watch_log_for("Compacting") - elif self.cluster.version() >= LooseVersion('3.11'): + elif self.cluster.version() >= parse('3.11'): node.watch_log_for("Major compaction") else: node.watch_log_for("Compacting", filename="debug.log") @@ -223,7 +224,7 @@ def test_compactionstats(self): updated_progress_string = jmx.read_attribute(compaction_manager, 'CompactionSummary')[0] var = 'Compaction@{uuid}(keyspace1, standard1, {progress}/{total})bytes' - if self.cluster.version() >= LooseVersion('4.0'): # CASSANDRA-15954 + if self.cluster.version() >= parse('4.0'): # CASSANDRA-15954 var = 'Compaction({taskUuid}, {progress} / {total} bytes)@{uuid}(keyspace1, standard1)' parsed = parse.search(var, progress_string) if parsed is None: diff --git a/json_test.py b/json_test.py index 69b8b5a56a..4f7d2b3d98 100644 --- a/json_test.py +++ b/json_test.py @@ -7,7 +7,8 @@ import pytest import logging -from distutils.version import LooseVersion +from packaging.version import parse + from ccmlib import common from ccmlib.common import is_win @@ -75,7 +76,7 @@ def _cqlsh(cmds): # avoid having multiple versions of these tests since it would be a bit messy to change the docstrings env['CQLSH_DEFAULT_TIMESTAMP_FORMAT'] = '%Y-%m-%d %H:%M:%S%z' - if tester.cluster.version() >= LooseVersion('2.1'): + if tester.cluster.version() >= parse('2.1'): host = nodes[0].network_interfaces['binary'][0] port = nodes[0].network_interfaces['binary'][1] else: diff --git a/materialized_views_test.py b/materialized_views_test.py index a6c58c1f00..72cc34986a 100644 --- a/materialized_views_test.py +++ b/materialized_views_test.py @@ -19,7 +19,8 @@ from cassandra.cluster import Cluster from cassandra.query import SimpleStatement -from distutils.version import LooseVersion +from packaging.version import parse + from dtest import Tester, get_ip_from_node, create_ks, mk_bman_path from tools.assertions import (assert_all, assert_crc_check_chance_equal, assert_invalid, assert_none, assert_one, @@ -53,7 +54,7 @@ def _rows_to_list(self, rows): def prepare(self, user_table=False, rf=1, options=None, nodes=3, install_byteman=False, **kwargs): cluster = self.cluster - cluster.set_configuration_options({'enable_materialized_views': 'true', 'commitlog_sync_period_in_ms': 1000}) + cluster.set_configuration_options({'enable_materialized_views': 'true'}) cluster.populate([nodes, 0], install_byteman=install_byteman) if options: cluster.set_configuration_options(values=options) @@ -978,7 +979,7 @@ def test_rename_column_atomicity(self): node = self.cluster.nodelist()[0] self._insert_data(session) - time.sleep(1) + assert_one( session, "SELECT * FROM users_by_state WHERE state = 'TX' AND username = 'user1'", @@ -988,7 +989,7 @@ def test_rename_column_atomicity(self): # Rename a column with an injected byteman rule to kill the node after the first schema update self.fixture_dtest_setup.allow_log_errors = True - script_version = '5_1' if self.cluster.version() >= LooseVersion('5.1') else '4x' if self.cluster.version() >= '4' else '3x' + script_version = '5_1' if self.cluster.version() >= parse('5.1') else '4x' if self.cluster.version() >= '4' else '3x' node.byteman_submit([mk_bman_path('merge_schema_failure_{}.btm'.format(script_version))]) with pytest.raises(NoHostAvailable): session.execute("ALTER TABLE users RENAME username TO user") @@ -2040,12 +2041,12 @@ def _base_replica_repair_test(self, fail_mv_lock=False): logger.debug('Shutdown node1') node1.stop(wait_other_notice=True) logger.debug('Delete node1 data') - clear_data_only = True if self.cluster.version() >= LooseVersion('5.1') else False + clear_data_only = True if self.cluster.version() >= parse('5.1') else False node1.clear(clear_all=True, only_data=clear_data_only) jvm_args = [] if fail_mv_lock: - if LooseVersion('3.10') <= self.cluster.version() < LooseVersion('5.1'): # CASSANDRA-10134 + if parse('3.10') <= self.cluster.version() < parse('5.1'): # CASSANDRA-10134 jvm_args = ['-Dcassandra.allow_unsafe_replace=true', '-Dcassandra.replace_address={}'.format(node1.address())] jvm_args.append("-Dcassandra.test.fail_mv_locks_count=1000") # this should not make Keyspace.apply throw WTE on failure to acquire lock @@ -2987,7 +2988,7 @@ def test_mutations_dontblock(self): for y in range(records2): params.append([x, y]) - if self.cluster.version() < LooseVersion('5.0'): + if self.cluster.version() < parse('5.0'): insert = 'INSERT INTO test (int1, int2, date) VALUES (?, ?, toTimestamp(now()))' else: insert = 'INSERT INTO test (int1, int2, date) VALUES (?, ?, to_timestamp(now()))' diff --git a/paging_test.py b/paging_test.py index 971c7778a0..25354301a0 100644 --- a/paging_test.py +++ b/paging_test.py @@ -5,7 +5,8 @@ from flaky import flaky -from distutils.version import LooseVersion +from packaging.version import parse + from cassandra import ConsistencyLevel as CL from cassandra import InvalidRequest, ReadFailure, ReadTimeout @@ -3442,7 +3443,7 @@ def test_failure_threshold_deletions(self): try: self.session.execute(SimpleStatement("select * from paging_test", fetch_size=1000, consistency_level=CL.ALL, retry_policy=FallthroughRetryPolicy())) except ReadTimeout as exc: - assert self.cluster.version() < LooseVersion('2.2') + assert self.cluster.version() < parse('2.2') except ReadFailure as exc: if supports_v5_protocol: assert exc.error_code_map is not None diff --git a/pending_range_test.py b/pending_range_test.py index 1e5451088e..8e4df26e8e 100644 --- a/pending_range_test.py +++ b/pending_range_test.py @@ -1,5 +1,4 @@ import logging -import time import pytest import re @@ -9,11 +8,10 @@ from dtest import Tester, create_ks, mk_bman_path -from distutils.version import LooseVersion +from packaging.version import parse logger = logging.getLogger(__name__) - @pytest.mark.no_vnodes class TestPendingRangeMovements(Tester): @@ -52,7 +50,7 @@ def test_pending_range(self): token = '-634023222112864484' # delay progress of the move operation to give a chance to kill the moving node - if self.cluster.version() >= LooseVersion('5.1'): + if self.cluster.version() >= parse('5.1'): node1.byteman_submit([mk_bman_path('post5.1/delay_streaming_for_move.btm')]) mark = node1.mark_log() @@ -60,7 +58,7 @@ def test_pending_range(self): threading.Thread(target=(lambda: node1.nodetool('move {}'.format(token)))).start() # Watch the log so we know when the node is moving node1.watch_log_for('Moving .* to \[?{}\]?'.format(token), timeout=10, from_mark=mark) - if self.cluster.version() < LooseVersion('5.1'): + if self.cluster.version() < parse('5.1'): node1.watch_log_for('Sleeping {} ms before start streaming/fetching ranges'.format(ring_delay_ms), timeout=10, from_mark=mark) diff --git a/pushed_notifications_test.py b/pushed_notifications_test.py index 581b0ea50f..219dc18c98 100644 --- a/pushed_notifications_test.py +++ b/pushed_notifications_test.py @@ -3,7 +3,8 @@ import logging from datetime import datetime -from distutils.version import LooseVersion +from packaging.version import parse + from threading import Event from cassandra import ConsistencyLevel as CL @@ -35,7 +36,7 @@ def __init__(self, tester, node, notification_types, keyspace=None): self.keyspace = keyspace # get a single, new connection - version = 5 if node.get_cassandra_version() >= LooseVersion('4.0') else None + version = 5 if node.get_cassandra_version() >= parse('4.0') else None session = tester.patient_exclusive_cql_connection(node, protocol_version=version) connection = session.cluster.connection_factory(self.address, is_control_connection=True) @@ -392,7 +393,7 @@ def test_tombstone_failure_threshold_message(self): 'read_request_timeout_in_ms': 30000, # 30 seconds 'range_request_timeout_in_ms': 40000 } - if self.cluster.version() >= LooseVersion('4.1'): + if self.cluster.version() >= parse('4.1'): opts['native_transport_timeout'] = '30s' self.cluster.set_configuration_options(values=opts) self.cluster.populate(3).start() diff --git a/read_repair_test.py b/read_repair_test.py index 2e5335494c..af8233e3cb 100644 --- a/read_repair_test.py +++ b/read_repair_test.py @@ -2,7 +2,8 @@ import glob import os import time -from distutils.version import LooseVersion +from packaging.version import parse + import pytest import logging @@ -394,7 +395,7 @@ def test_tracing_does_not_interfere_with_digest_calculation(self): cluster = self.cluster cluster.populate(3) opts = {'write_request_timeout_in_ms': 30000, 'read_request_timeout_in_ms': 30000} - if cluster.version() >= LooseVersion('4.1'): + if cluster.version() >= parse('4.1'): opts['native_transport_timeout'] = '30s' cluster.set_configuration_options(values=opts) cluster.set_partitioner("org.apache.cassandra.dht.RandomPartitioner") @@ -537,7 +538,7 @@ def test_failed_read_repair(self): node2.byteman_submit([mk_bman_path('read_repair/stop_writes.btm')]) node3.byteman_submit([mk_bman_path('read_repair/stop_writes.btm')]) - script_version = '_5_1' if self.cluster.version() >= LooseVersion('5.1') else '' + script_version = '_5_1' if self.cluster.version() >= parse('5.1') else '' node2.byteman_submit([mk_bman_path('read_repair/stop_rr_writes{}.btm'.format(script_version))]) node3.byteman_submit([mk_bman_path('read_repair/stop_rr_writes{}.btm'.format(script_version))]) @@ -661,7 +662,7 @@ def test_speculative_write(self): session.execute("INSERT INTO ks.tbl (k, c, v) VALUES (1, 1, 2)") # re-enable writes on node 3, leave them off on node2 - script_version = '_5_1' if self.cluster.version() >= LooseVersion('5.1') else '' + script_version = '_5_1' if self.cluster.version() >= parse('5.1') else '' node2.byteman_submit([mk_bman_path('read_repair/stop_rr_writes{}.btm'.format(script_version))]) node1.byteman_submit([mk_bman_path('read_repair/sorted_live_endpoints.btm')]) @@ -705,7 +706,7 @@ def test_quorum_requirement(self): node1.byteman_submit([mk_bman_path('read_repair/sorted_live_endpoints.btm')]) node2.byteman_submit([mk_bman_path('read_repair/stop_data_reads.btm')]) - script_version = '_5_1' if self.cluster.version() >= LooseVersion('5.1') else '' + script_version = '_5_1' if self.cluster.version() >= parse('5.1') else '' node3.byteman_submit([mk_bman_path('read_repair/stop_rr_writes{}.btm'.format(script_version))]) with StorageProxy(node1) as storage_proxy: @@ -751,7 +752,7 @@ def test_quorum_requirement_on_speculated_read(self): node2.byteman_submit([mk_bman_path('read_repair/stop_digest_reads.btm')]) node3.byteman_submit([mk_bman_path('read_repair/stop_data_reads.btm')]) - script_version = '_5_1' if self.cluster.version() >= LooseVersion('5.1') else '' + script_version = '_5_1' if self.cluster.version() >= parse('5.1') else '' node2.byteman_submit([mk_bman_path('read_repair/stop_rr_writes{}.btm'.format(script_version))]) with StorageProxy(node1) as storage_proxy: diff --git a/replace_address_test.py b/replace_address_test.py index 751f0b3f52..98838b1a36 100644 --- a/replace_address_test.py +++ b/replace_address_test.py @@ -1,13 +1,12 @@ import os import tempfile -from distutils.version import LooseVersion +from packaging.version import parse + import pytest import logging import time -from flaky import flaky - from itertools import chain from shutil import rmtree @@ -328,7 +327,7 @@ def _test_replace_node(self, gently=False, jvm_option='replace_address', same_ad # the metadata log is replayed at startup, so the message will be logged # repeatedly (although the movement only actually happens once). We can address # this with smarter logging in Cassandra. - if not same_address and self.cluster.version() < LooseVersion('5.1'): + if not same_address and self.cluster.version() < parse('5.1'): self._verify_tokens_migrated_successfully(previous_log_size) self._verify_data(initial_data) @@ -359,7 +358,7 @@ def test_replace_nonexistent_node(self): logger.debug("Waiting for replace to fail") node_log_str = "/127.0.0.5" if self.cluster.version() < '4.0' else "/127.0.0.5:7000" log_message = "java.lang.RuntimeException: Cannot replace_address {} because it doesn't exist in gossip" \ - if self.cluster.version() < LooseVersion('5.1') \ + if self.cluster.version() < parse('5.1') \ else "Cannot replace node {} which is not currently joined" self.replacement_node.watch_log_for(log_message.format(node_log_str)) assert_not_running(self.replacement_node) @@ -585,7 +584,7 @@ def _test_restart_failed_replace(self, mode): logger.debug("Waiting other nodes to detect node stopped") node_log_str = self.replacement_node.address_for_current_version_slashy() self.query_node.watch_log_for("FatClient {} has been silent for 30000ms, removing from gossip".format(node_log_str), timeout=120) - if self.cluster.version() < LooseVersion('5.1'): + if self.cluster.version() < parse('5.1'): self.query_node.watch_log_for("Node {} failed during replace.".format(node_log_str), timeout=120, filename='debug.log') else: logger.debug("Calling nodetool abortbootstrap --ip {}".format(self.replacement_node.address())) @@ -627,7 +626,7 @@ def test_replace_with_insufficient_replicas(self): # CEP-21: availability is intentionally degraded, so we lower the required number of # acks required for the replacement node to progress to a point where it attempts to # perform streaming - if self.cluster.version() >= LooseVersion('5.1'): + if self.cluster.version() >= parse('5.1'): options = {'progress_barrier_min_consistency_level': 'ONE', 'progress_barrier_default_consistency_level': 'ONE'} diff --git a/replication_test.py b/replication_test.py index 40d5fb2d7f..8e8056387e 100644 --- a/replication_test.py +++ b/replication_test.py @@ -1,7 +1,8 @@ import os import re import time -from distutils.version import LooseVersion +from packaging.version import parse + import pytest import logging @@ -742,7 +743,7 @@ def test_switch_data_center_startup_fails(self): """ expected_error = (r"Cannot start node if snitch's data center (.*) differs from previous data center (.*)\. " "Please fix the snitch configuration, decommission and rebootstrap this node") - if self.cluster.version() < LooseVersion('5.1'): + if self.cluster.version() < parse('5.1'): expected_error += " or use the flag -Dcassandra.ignore_dc=true." self.fixture_dtest_setup.ignore_log_patterns = [expected_error] diff --git a/secondary_indexes_test.py b/secondary_indexes_test.py index 1e14d636fd..5b4e7f1116 100644 --- a/secondary_indexes_test.py +++ b/secondary_indexes_test.py @@ -3,7 +3,8 @@ import re import time import uuid -from distutils.version import LooseVersion +from packaging.version import parse + import pytest import logging @@ -342,7 +343,7 @@ def test_manual_rebuild_index(self): assert before_files != after_files assert 1 == len(list(session.execute(stmt, [lookup_value]))) expected = 1 - if self.cluster.version() >= LooseVersion('5.1'): + if self.cluster.version() >= parse('5.1'): expected = 2 # in tcm PaxosUncommittedIndex is is IndexInfo table # verify that only the expected row is present in the build indexes table diff --git a/snapshot_test.py b/snapshot_test.py index 2a72b98d7f..97a489968d 100644 --- a/snapshot_test.py +++ b/snapshot_test.py @@ -4,7 +4,8 @@ import shutil import subprocess import time -from distutils.version import LooseVersion +from packaging.version import parse + import pytest import logging @@ -340,7 +341,7 @@ def run_archive_commitlog(self, restore_point_in_time=False, restore_archived_co systemlocal_dirs = self.make_snapshot(node1, 'system', 'local', 'local') - if self.cluster.version() >= LooseVersion('5.1'): + if self.cluster.version() >= parse('5.1'): local_dirs = self.make_snapshot(node1, 'system', 'local_metadata_log', 'local_metadata_log') metadata_snapshot_dirs = self.make_snapshot(node1, 'system', 'metadata_snapshots', 'metadata_snapshots') cluster_metadata_snapshot_dirs = self.make_snapshot(node1, 'system_cluster_metadata', 'distributed_metadata_log', 'distributed_metadata_log') @@ -420,7 +421,7 @@ def run_archive_commitlog(self, restore_point_in_time=False, restore_archived_co for local_dir in systemlocal_dirs: self.restore_snapshot(local_dir, node1, 'system', 'local', 'local') - if self.cluster.version() >= LooseVersion('5.1'): + if self.cluster.version() >= parse('5.1'): for local_dir in local_dirs: self.restore_snapshot(local_dir, node1, 'system', 'local_metadata_log', 'local_metadata_log') for snapshot_dir in metadata_snapshot_dirs: @@ -495,7 +496,7 @@ def run_archive_commitlog(self, restore_point_in_time=False, restore_archived_co for systemlocal_snapshot_dir in systemlocal_dirs: shutil.rmtree(systemlocal_snapshot_dir) - if self.cluster.version() >= LooseVersion('5.1'): + if self.cluster.version() >= parse('5.1'): logger.debug("removing snapshot_dir: " + ",".join(local_dirs)) for local_snapshot_dir in local_dirs: shutil.rmtree(local_snapshot_dir) diff --git a/sstable_generation_loading_test.py b/sstable_generation_loading_test.py index 490d1254c8..fb5d24023b 100644 --- a/sstable_generation_loading_test.py +++ b/sstable_generation_loading_test.py @@ -2,7 +2,6 @@ import subprocess import time import distutils.dir_util -from distutils.version import LooseVersion import pytest import logging diff --git a/topology_test.py b/topology_test.py index e1b8908251..0f81ca9920 100644 --- a/topology_test.py +++ b/topology_test.py @@ -1,6 +1,7 @@ import re import time -from distutils.version import LooseVersion +from packaging.version import parse + import pytest import logging @@ -141,7 +142,7 @@ def test_simple_removenode(self): node3_id = node3.nodetool('info').stdout[25:61] node3.stop(wait_other_notice=True) cmd = 'removenode ' + node3_id - if cluster.version() >= LooseVersion('5.1'): + if cluster.version() >= parse('5.1'): cmd = cmd + ' --force' node1.nodetool(cmd) diff --git a/ttl_test.py b/ttl_test.py index c7ee5d9a79..2af5969daa 100644 --- a/ttl_test.py +++ b/ttl_test.py @@ -6,7 +6,8 @@ import logging from collections import OrderedDict -from distutils.version import LooseVersion +from packaging.version import parse + from cassandra import ConsistencyLevel, InvalidRequest from cassandra.query import SimpleStatement @@ -590,8 +591,8 @@ def test_recover_negative_expiration_date_sstables_with_scrub(self): """ session.execute(query) - version = '2.1' if self.cluster.version() < LooseVersion('3.0') else \ - ('3.0' if self.cluster.version() < LooseVersion('3.11') else '3.11') + version = '2.1' if self.cluster.version() < parse('3.0') else \ + ('3.0' if self.cluster.version() < parse('3.11') else '3.11') base_dir = os.path.dirname(os.path.abspath(__file__)) corrupt_sstable_dir = os.path.join(base_dir, 'sstables', 'ttl_test', version) diff --git a/user_functions_test.py b/user_functions_test.py index d0676019eb..2263005125 100644 --- a/user_functions_test.py +++ b/user_functions_test.py @@ -3,7 +3,7 @@ import pytest import logging -from distutils.version import LooseVersion +from packaging.version import parse from cassandra import FunctionFailure @@ -147,7 +147,7 @@ def test_udf_overload(self): session.execute("CREATE OR REPLACE FUNCTION overloaded(v ascii) called on null input RETURNS text LANGUAGE java AS 'return \"f1\";'") # ensure that works with correct specificity - if self.cluster.version() < LooseVersion('4.1'): + if self.cluster.version() < parse('4.1'): assert_invalid(session, "SELECT v FROM tab WHERE k = overloaded('foo')") else: assert_none(session, "SELECT v FROM tab WHERE k = overloaded('foo')") @@ -211,7 +211,7 @@ def test_default_aggregate(self): assert_one(session, "SELECT avg(val) FROM nums", [5.0]) assert_one(session, "SELECT count(*) FROM nums", [9]) - if self.cluster.version() < LooseVersion('4.2'): + if self.cluster.version() < parse('4.2'): session.execute("create function test(a int, b double) called on null input returns int language javascript as 'a + b;'") else: session.execute("create function test(a int, b double) called on null input returns int language java as 'return a + Integer.valueOf(b.intValue());'") @@ -243,7 +243,7 @@ def test_udf_with_udt(self): session.execute("create type test (a text, b int);") session.execute("create function funk(udt test) called on null input returns int language java as 'return Integer.valueOf(udt.getInt(\"b\"));';") - if self.cluster.version() >= LooseVersion('3.6'): + if self.cluster.version() >= parse('3.6'): frozen_vals = (False, True) else: frozen_vals = (True,)