Skip to content

Commit e3849df

Browse files
authored
Merge pull request #210 from Lorak-mmk/fix-clqengine-tests
Fix all tests/integration/cqlengine tests (or mark the ones incompatible with Scylla appropriately) and enable them in CI
2 parents cd1f5ed + df49fdc commit e3849df

File tree

14 files changed

+115
-50
lines changed

14 files changed

+115
-50
lines changed

.github/workflows/integration-tests-python2.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,5 @@ jobs:
2121

2222
- name: Test with pytest
2323
run: |
24-
./ci/run_integration_test.sh tests/integration/standard/test_authentication.py tests/integration/standard/test_cluster.py tests/integration/standard/test_concurrent.py tests/integration/standard/test_connection.py tests/integration/standard/test_control_connection.py tests/integration/standard/test_custom_payload.py tests/integration/standard/test_custom_protocol_handler.py tests/integration/standard/test_cython_protocol_handlers.py tests/integration/standard/test_scylla_cloud.py tests/integration/standard/test_use_keyspace.py tests/integration/standard/test_ip_change.py
24+
./ci/run_integration_test.sh tests/integration/standard/test_authentication.py tests/integration/standard/test_cluster.py tests/integration/standard/test_concurrent.py tests/integration/standard/test_connection.py tests/integration/standard/test_control_connection.py tests/integration/standard/test_custom_payload.py tests/integration/standard/test_custom_protocol_handler.py tests/integration/standard/test_cython_protocol_handlers.py tests/integration/standard/test_scylla_cloud.py tests/integration/standard/test_use_keyspace.py tests/integration/standard/test_ip_change.py tests/integration/cqlengine/
2525
# can't run this, cause only 2 cpus on github actions: tests/integration/standard/test_shard_aware.py

.github/workflows/integration-tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,5 @@ jobs:
2121

2222
- name: Test with pytest
2323
run: |
24-
./ci/run_integration_test.sh tests/integration/standard/test_authentication.py tests/integration/standard/test_cluster.py tests/integration/standard/test_concurrent.py tests/integration/standard/test_connection.py tests/integration/standard/test_control_connection.py tests/integration/standard/test_custom_payload.py tests/integration/standard/test_custom_protocol_handler.py tests/integration/standard/test_cython_protocol_handlers.py tests/integration/standard/test_scylla_cloud.py tests/integration/standard/test_use_keyspace.py tests/integration/standard/test_ip_change.py
24+
./ci/run_integration_test.sh tests/integration/standard/test_authentication.py tests/integration/standard/test_cluster.py tests/integration/standard/test_concurrent.py tests/integration/standard/test_connection.py tests/integration/standard/test_control_connection.py tests/integration/standard/test_custom_payload.py tests/integration/standard/test_custom_protocol_handler.py tests/integration/standard/test_cython_protocol_handlers.py tests/integration/standard/test_scylla_cloud.py tests/integration/standard/test_use_keyspace.py tests/integration/standard/test_ip_change.py tests/integration/cqlengine/
2525
# can't run this, cause only 2 cpus on github actions: tests/integration/standard/test_shard_aware.py

cassandra/cluster.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import logging
3030
from warnings import warn
3131
from random import random
32+
import re
3233
import six
3334
from six.moves import filter, range, queue as Queue
3435
import socket
@@ -5349,6 +5350,8 @@ def cancel_continuous_paging(self):
53495350
except AttributeError:
53505351
raise DriverException("Attempted to cancel paging with no active session. This is only for requests with ContinuousdPagingOptions.")
53515352

5353+
batch_regex = re.compile('^\s*BEGIN\s+[a-zA-Z]*\s*BATCH')
5354+
53525355
@property
53535356
def was_applied(self):
53545357
"""
@@ -5363,7 +5366,8 @@ def was_applied(self):
53635366
if self.response_future.row_factory not in (named_tuple_factory, dict_factory, tuple_factory):
53645367
raise RuntimeError("Cannot determine LWT result with row factory %s" % (self.response_future.row_factory,))
53655368

5366-
is_batch_statement = isinstance(self.response_future.query, BatchStatement)
5369+
is_batch_statement = isinstance(self.response_future.query, BatchStatement) \
5370+
or (isinstance(self.response_future.query, SimpleStatement) and self.batch_regex.match(self.response_future.query.query_string))
53675371
if is_batch_statement and (not self.column_names or self.column_names[0] != "[applied]"):
53685372
raise RuntimeError("No LWT were present in the BatchStatement")
53695373

cassandra/cqlengine/management.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -483,9 +483,17 @@ def _update_options(model, connection=None):
483483
else:
484484
try:
485485
for k, v in value.items():
486-
if existing_value[k] != v:
487-
update_options[name] = value
488-
break
486+
# When creating table with compaction 'class': 'org.apache.cassandra.db.compaction.LeveledCompactionStrategy' in Scylla,
487+
# it will be silently changed to 'class': 'LeveledCompactionStrategy' - same for at least SizeTieredCompactionStrategy,
488+
# probably others too. We need to handle this case here.
489+
if k == 'class' and name == 'compaction':
490+
if existing_value[k] != v and existing_value[k] != v.split('.')[-1]:
491+
update_options[name] = value
492+
break
493+
else:
494+
if existing_value[k] != v:
495+
update_options[name] = value
496+
break
489497
except KeyError:
490498
update_options[name] = value
491499

tests/integration/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,7 @@ def _id_and_mark(f):
337337
lessthenprotocolv4 = unittest.skipUnless(PROTOCOL_VERSION < 4, 'Protocol versions 4 or greater not supported')
338338
greaterthanprotocolv3 = unittest.skipUnless(PROTOCOL_VERSION >= 4, 'Protocol versions less than 4 are not supported')
339339
protocolv6 = unittest.skipUnless(6 in get_supported_protocol_versions(), 'Protocol versions less than 6 are not supported')
340+
340341
greaterthancass20 = unittest.skipUnless(CASSANDRA_VERSION >= Version('2.1'), 'Cassandra version 2.1 or greater required')
341342
greaterthancass21 = unittest.skipUnless(CASSANDRA_VERSION >= Version('2.2'), 'Cassandra version 2.2 or greater required')
342343
greaterthanorequalcass30 = unittest.skipUnless(CASSANDRA_VERSION >= Version('3.0'), 'Cassandra version 3.0 or greater required')
@@ -348,6 +349,7 @@ def _id_and_mark(f):
348349
lessthanorequalcass40 = unittest.skipUnless(CASSANDRA_VERSION <= Version('4.0-a'), 'Cassandra version less or equal to 4.0 required')
349350
lessthancass40 = unittest.skipUnless(CASSANDRA_VERSION < Version('4.0-a'), 'Cassandra version less than 4.0 required')
350351
lessthancass30 = unittest.skipUnless(CASSANDRA_VERSION < Version('3.0'), 'Cassandra version less then 3.0 required')
352+
351353
greaterthanorequaldse68 = unittest.skipUnless(DSE_VERSION and DSE_VERSION >= Version('6.8'), "DSE 6.8 or greater required for this test")
352354
greaterthanorequaldse67 = unittest.skipUnless(DSE_VERSION and DSE_VERSION >= Version('6.7'), "DSE 6.7 or greater required for this test")
353355
greaterthanorequaldse60 = unittest.skipUnless(DSE_VERSION and DSE_VERSION >= Version('6.0'), "DSE 6.0 or greater required for this test")
@@ -356,6 +358,9 @@ def _id_and_mark(f):
356358
lessthandse51 = unittest.skipUnless(DSE_VERSION and DSE_VERSION < Version('5.1'), "DSE version less than 5.1 required")
357359
lessthandse60 = unittest.skipUnless(DSE_VERSION and DSE_VERSION < Version('6.0'), "DSE version less than 6.0 required")
358360

361+
requirescollectionindexes = unittest.skipUnless(SCYLLA_VERSION is None or Version(SCYLLA_VERSION.split(':')[1]) >= Version('5.2'), 'Test requires Scylla >= 5.2 or Cassandra')
362+
requirescustomindexes = unittest.skipUnless(SCYLLA_VERSION is None, 'Currently, Scylla does not support SASI or any other CUSTOM INDEX class.')
363+
359364
pypy = unittest.skipUnless(platform.python_implementation() == "PyPy", "Test is skipped unless it's on PyPy")
360365
notpy3 = unittest.skipIf(sys.version_info >= (3, 0), "Test not applicable for Python 3.x runtime")
361366
requiresmallclockgranularity = unittest.skipIf("Windows" in platform.system() or "asyncore" in EVENT_LOOP_MANAGER,

tests/integration/cqlengine/__init__.py

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,35 +13,19 @@
1313
# limitations under the License.
1414

1515
import os
16-
import warnings
1716
import unittest
1817
from cassandra import ConsistencyLevel
1918

2019
from cassandra.cqlengine import connection
21-
from cassandra.cqlengine.management import create_keyspace_simple, drop_keyspace, CQLENG_ALLOW_SCHEMA_MANAGEMENT
2220
import cassandra
2321

24-
from tests.integration import get_server_versions, use_single_node, PROTOCOL_VERSION, CASSANDRA_IP, ALLOW_BETA_PROTOCOL
22+
from tests.integration import get_server_versions, PROTOCOL_VERSION, CASSANDRA_IP, ALLOW_BETA_PROTOCOL
2523

2624
DEFAULT_KEYSPACE = 'cqlengine_test'
2725

2826

2927
CQL_SKIP_EXECUTE = bool(os.getenv('CQL_SKIP_EXECUTE', False))
3028

31-
32-
def setup_package():
33-
warnings.simplefilter('always') # for testing warnings, make sure all are let through
34-
os.environ[CQLENG_ALLOW_SCHEMA_MANAGEMENT] = '1'
35-
36-
use_single_node()
37-
38-
setup_connection(DEFAULT_KEYSPACE)
39-
create_keyspace_simple(DEFAULT_KEYSPACE, 1)
40-
41-
42-
def teardown_package():
43-
connection.unregister_connection("default")
44-
4529
def is_prepend_reversed():
4630
# do we have https://issues.apache.org/jira/browse/CASSANDRA-8733 ?
4731
ver, _ = get_server_versions()
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# Copyright ScyllaDB, Inc.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
# Copyright DataStax, Inc.
16+
#
17+
# Licensed under the Apache License, Version 2.0 (the "License");
18+
# you may not use this file except in compliance with the License.
19+
# You may obtain a copy of the License at
20+
#
21+
# http://www.apache.org/licenses/LICENSE-2.0
22+
#
23+
# Unless required by applicable law or agreed to in writing, software
24+
# distributed under the License is distributed on an "AS IS" BASIS,
25+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
26+
# See the License for the specific language governing permissions and
27+
# limitations under the License.
28+
29+
import warnings
30+
import os
31+
32+
import pytest
33+
34+
from cassandra.cqlengine import connection
35+
from cassandra.cqlengine.management import create_keyspace_simple, drop_keyspace, CQLENG_ALLOW_SCHEMA_MANAGEMENT
36+
from tests.integration import use_single_node
37+
38+
from . import setup_connection, DEFAULT_KEYSPACE
39+
40+
41+
@pytest.fixture(scope='package', autouse=True)
42+
def cqlengine_fixture():
43+
warnings.simplefilter('always') # for testing warnings, make sure all are let through
44+
os.environ[CQLENG_ALLOW_SCHEMA_MANAGEMENT] = '1'
45+
46+
use_single_node()
47+
48+
setup_connection(DEFAULT_KEYSPACE)
49+
create_keyspace_simple(DEFAULT_KEYSPACE, 1)
50+
51+
yield
52+
53+
drop_keyspace(DEFAULT_KEYSPACE)
54+
connection.unregister_connection("default")

tests/integration/cqlengine/management/test_compaction_settings.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,16 @@ def _verify_options(self, table_meta, expected_options):
118118
for subname, subvalue in value.items():
119119
attr = "'%s': '%s'" % (subname, subvalue)
120120
found_at = cql.find(attr, start)
121-
self.assertTrue(found_at > start)
122-
self.assertTrue(found_at < end)
121+
# When creating table with compaction 'class': 'org.apache.cassandra.db.compaction.LeveledCompactionStrategy' in Scylla,
122+
# it will be silently changed to 'class': 'LeveledCompactionStrategy' - same for at least SizeTieredCompactionStrategy,
123+
# probably others too. We need to handle this case here.
124+
if found_at == -1 and name == 'compaction' and subname == 'class':
125+
attr = "'%s': '%s'" % (subname, subvalue.split('.')[-1])
126+
found_at = cql.find(attr, start)
127+
else:
128+
129+
self.assertTrue(found_at > start)
130+
self.assertTrue(found_at < end)
123131

124132
def test_all_size_tiered_options(self):
125133
class AllSizeTieredOptionsModel(Model):

tests/integration/cqlengine/management/test_management.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
from cassandra.cqlengine.models import Model
2424
from cassandra.cqlengine import columns
2525

26-
from tests.integration import DSE_VERSION, PROTOCOL_VERSION, greaterthancass20, MockLoggingHandler, CASSANDRA_VERSION
26+
from tests.integration import DSE_VERSION, PROTOCOL_VERSION, greaterthancass20, requirescollectionindexes, MockLoggingHandler, CASSANDRA_VERSION
2727
from tests.integration.cqlengine.base import BaseCassEngTestCase
2828
from tests.integration.cqlengine.query.test_queryset import TestModel
2929
from cassandra.cqlengine.usertype import UserType
@@ -426,6 +426,7 @@ def test_sync_index_case_sensitive(self):
426426
self.assertIsNotNone(management._get_index_name_by_column(table_meta, 'second_key'))
427427

428428
@greaterthancass20
429+
@requirescollectionindexes
429430
def test_sync_indexed_set(self):
430431
"""
431432
Tests that models that have container types with indices can be synced.

tests/integration/cqlengine/query/test_named.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
from tests.integration.cqlengine.query.test_queryset import BaseQuerySetUsage
2828

2929

30-
from tests.integration import BasicSharedKeyspaceUnitTestCase, greaterthanorequalcass30
30+
from tests.integration import BasicSharedKeyspaceUnitTestCase, greaterthanorequalcass30, requirescollectionindexes
3131

3232

3333
class TestQuerySetOperation(BaseCassEngTestCase):
@@ -118,7 +118,7 @@ def test_query_expression_where_clause_generation(self):
118118
self.assertIsInstance(where.operator, GreaterThanOrEqualOperator)
119119
self.assertEqual(where.value, 1)
120120

121-
121+
@requirescollectionindexes
122122
class TestQuerySetCountSelectionAndIteration(BaseQuerySetUsage):
123123

124124
@classmethod

tests/integration/cqlengine/query/test_queryset.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
from cassandra.util import uuid_from_time
4040
from cassandra.cqlengine.connection import get_session
4141
from tests.integration import PROTOCOL_VERSION, CASSANDRA_VERSION, greaterthancass20, greaterthancass21, \
42-
greaterthanorequalcass30, TestCluster
42+
greaterthanorequalcass30, TestCluster, requirescollectionindexes
4343
from tests.integration.cqlengine import execute_count, DEFAULT_KEYSPACE
4444

4545

@@ -384,7 +384,7 @@ def tearDownClass(cls):
384384
drop_table(CustomIndexedTestModel)
385385
drop_table(TestMultiClusteringModel)
386386

387-
387+
@requirescollectionindexes
388388
class TestQuerySetCountSelectionAndIteration(BaseQuerySetUsage):
389389

390390
@execute_count(2)
@@ -558,7 +558,7 @@ class NonEqualityFilteringModel(Model):
558558
num = qa.count()
559559
assert num == 1, num
560560

561-
561+
@requirescollectionindexes
562562
class TestQuerySetDistinct(BaseQuerySetUsage):
563563

564564
@execute_count(1)
@@ -597,6 +597,7 @@ def test_distinct_with_explicit_count(self):
597597
self.assertEqual(q.count(), 2)
598598

599599

600+
@requirescollectionindexes
600601
class TestQuerySetOrdering(BaseQuerySetUsage):
601602
@execute_count(2)
602603
def test_order_by_success_case(self):
@@ -645,6 +646,7 @@ def test_ordering_on_multiple_clustering_columns(self):
645646
assert [r.three for r in results] == [1, 2, 3, 4, 5]
646647

647648

649+
@requirescollectionindexes
648650
class TestQuerySetSlicing(BaseQuerySetUsage):
649651

650652
@execute_count(1)
@@ -699,6 +701,7 @@ def test_negative_slicing(self):
699701
self.assertEqual(model.attempt_id, expect)
700702

701703

704+
@requirescollectionindexes
702705
class TestQuerySetValidation(BaseQuerySetUsage):
703706

704707
def test_primary_key_or_index_must_be_specified(self):
@@ -780,6 +783,7 @@ def test_custom_indexed_field_can_be_queried(self):
780783
list(CustomIndexedTestModel.objects.filter(test_id=1, description='test'))
781784

782785

786+
@requirescollectionindexes
783787
class TestQuerySetDelete(BaseQuerySetUsage):
784788

785789
@execute_count(9)
@@ -938,6 +942,7 @@ def test_success_case(self):
938942
assert '4' in datas
939943

940944

945+
@requirescollectionindexes
941946
class TestInOperator(BaseQuerySetUsage):
942947
@execute_count(1)
943948
def test_kwarg_success_case(self):
@@ -998,6 +1003,7 @@ class bool_model2(Model):
9981003

9991004

10001005
@greaterthancass20
1006+
@requirescollectionindexes
10011007
class TestContainsOperator(BaseQuerySetUsage):
10021008

10031009
@execute_count(6)
@@ -1063,6 +1069,7 @@ def test_query_expression_success_case(self):
10631069
self.assertEqual(q.count(), 0)
10641070

10651071

1072+
@requirescollectionindexes
10661073
class TestValuesList(BaseQuerySetUsage):
10671074

10681075
@execute_count(2)
@@ -1075,6 +1082,7 @@ def test_values_list(self):
10751082
assert item == 10
10761083

10771084

1085+
@requirescollectionindexes
10781086
class TestObjectsProperty(BaseQuerySetUsage):
10791087
@execute_count(1)
10801088
def test_objects_property_returns_fresh_queryset(self):
@@ -1105,6 +1113,7 @@ class PagingTest(Model):
11051113
assert len(results) == 2
11061114

11071115

1116+
@requirescollectionindexes
11081117
class ModelQuerySetTimeoutTestCase(BaseQuerySetUsage):
11091118
def test_default_timeout(self):
11101119
with mock.patch.object(Session, 'execute') as mock_execute:
@@ -1122,6 +1131,7 @@ def test_none_timeout(self):
11221131
self.assertEqual(mock_execute.call_args[-1]['timeout'], None)
11231132

11241133

1134+
@requirescollectionindexes
11251135
class DMLQueryTimeoutTestCase(BaseQuerySetUsage):
11261136
def setUp(self):
11271137
self.model = TestModel(test_id=1, attempt_id=1, description='timeout test')

tests/integration/cqlengine/statements/test_base_statement.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626

2727
from tests.integration.cqlengine.base import BaseCassEngTestCase, TestQueryUpdateModel
2828
from tests.integration.cqlengine import DEFAULT_KEYSPACE
29-
from tests.integration import greaterthanorequalcass3_10, TestCluster
29+
from tests.integration import greaterthanorequalcass3_10, requirescustomindexes, TestCluster
3030

3131
from cassandra.cqlengine.connection import execute
3232

@@ -102,6 +102,7 @@ def test_insert_statement_execute(self):
102102
self.assertEqual(TestQueryUpdateModel.objects.count(), 0)
103103

104104
@greaterthanorequalcass3_10
105+
@requirescustomindexes
105106
def test_like_operator(self):
106107
"""
107108
Test to verify the like operator works appropriately

tests/integration/cqlengine/test_batch_query.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,7 @@ def my_callback(*args, **kwargs):
218218
call_history.append(args)
219219

220220
with warnings.catch_warnings(record=True) as w:
221+
warnings.simplefilter("always")
221222
with BatchQuery() as batch:
222223
batch.add_callback(my_callback)
223224
batch.execute()
@@ -243,6 +244,7 @@ def my_callback(*args, **kwargs):
243244

244245
with patch('cassandra.cqlengine.query.BatchQuery.warn_multiple_exec', False):
245246
with warnings.catch_warnings(record=True) as w:
247+
warnings.simplefilter("always")
246248
with BatchQuery() as batch:
247249
batch.add_callback(my_callback)
248250
batch.execute()

0 commit comments

Comments
 (0)