Merge pull request #408 from datastax/improved_metadata_test
Adding tests for Materialized views. Fixing issues associated with test timeouts and other small changes.
This commit is contained in:
@@ -25,7 +25,7 @@ build:
|
||||
sudo apt-get install -y libev4 libev-dev
|
||||
fi
|
||||
pip install -r test-requirements.txt
|
||||
|
||||
pip install nose-ignore-docstring
|
||||
|
||||
if [[ $CYTHON == 'CYTHON' ]]; then
|
||||
pip install cython
|
||||
@@ -38,12 +38,12 @@ build:
|
||||
fi
|
||||
|
||||
echo "==========RUNNING CQLENGINE TESTS=========="
|
||||
CASSANDRA_VERSION=$CCM_CASSANDRA_VERSION nosetests -s -v --with-xunit --xunit-file=cqle_results.xml tests/integration/cqlengine/ || true
|
||||
CASSANDRA_VERSION=$CCM_CASSANDRA_VERSION nosetests -s -v --logging-format="[%(levelname)s] %(asctime)s %(thread)d: %(message)s" --with-ignore-docstrings --with-xunit --xunit-file=cqle_results.xml tests/integration/cqlengine/ || true
|
||||
|
||||
echo "==========RUNNING INTEGRATION TESTS=========="
|
||||
CASSANDRA_VERSION=$CCM_CASSANDRA_VERSION nosetests -s -v --with-xunit --xunit-file=standard_results.xml tests/integration/standard/ || true
|
||||
CASSANDRA_VERSION=$CCM_CASSANDRA_VERSION nosetests -s -v --logging-format="[%(levelname)s] %(asctime)s %(thread)d: %(message)s" --with-ignore-docstrings --with-xunit --xunit-file=standard_results.xml tests/integration/standard/ || true
|
||||
|
||||
echo "==========RUNNING LONG INTEGRATION TESTS=========="
|
||||
CASSANDRA_VERSION=$CCM_CASSANDRA_VERSION nosetests -s -v --with-xunit --xunit-file=long_results.xml tests/integration/long/ || true
|
||||
CASSANDRA_VERSION=$CCM_CASSANDRA_VERSION nosetests -s -v --logging-format="[%(levelname)s] %(asctime)s %(thread)d: %(message)s" --with-ignore-docstrings --with-xunit --xunit-file=long_results.xml tests/integration/long/ || true
|
||||
- xunit:
|
||||
- "*_results.xml"
|
||||
@@ -271,6 +271,7 @@ def execute_until_pass(session, query):
|
||||
|
||||
raise RuntimeError("Failed to execute query after 100 attempts: {0}".format(query))
|
||||
|
||||
|
||||
def setup_keyspace(ipformat=None):
|
||||
# wait for nodes to startup
|
||||
time.sleep(10)
|
||||
@@ -332,3 +333,149 @@ class UpDownWaiter(object):
|
||||
|
||||
def wait_for_up(self):
|
||||
self.up_event.wait()
|
||||
|
||||
|
||||
class BasicKeyspaceUnitTestCase(unittest.TestCase):
|
||||
"""
|
||||
This is basic unit test case that provides various utility methods that can be leveraged for testcase setup and tear
|
||||
down
|
||||
"""
|
||||
@property
|
||||
def keyspace_name(self):
|
||||
return self.ks_name
|
||||
|
||||
@property
|
||||
def class_table_name(self):
|
||||
return self.ks_name
|
||||
|
||||
@property
|
||||
def function_table_name(self):
|
||||
return self._testMethodName.lower()
|
||||
|
||||
@classmethod
|
||||
def drop_keyspace(cls):
|
||||
execute_until_pass(cls.session, "DROP KEYSPACE {0}".format(cls.ks_name))
|
||||
|
||||
@classmethod
|
||||
def create_keyspace(cls, rf):
|
||||
ddl = "CREATE KEYSPACE {0} WITH replication = {{'class': 'SimpleStrategy', 'replication_factor': '{1}'}}".format(cls.ks_name, rf)
|
||||
execute_until_pass(cls.session, ddl)
|
||||
|
||||
@classmethod
|
||||
def common_setup(cls, rf, create_class_table=False, skip_if_cass_version_less_than=None):
|
||||
cls.cluster = Cluster(protocol_version=PROTOCOL_VERSION)
|
||||
cls.session = cls.cluster.connect()
|
||||
cls.ks_name = cls.__name__.lower()
|
||||
cls.create_keyspace(rf)
|
||||
|
||||
if create_class_table:
|
||||
|
||||
ddl = '''
|
||||
CREATE TABLE {0}.{1} (
|
||||
k int PRIMARY KEY,
|
||||
v int )'''.format(cls.ks_name, cls.ks_name)
|
||||
execute_until_pass(cls.session, ddl)
|
||||
|
||||
def create_function_table(self):
|
||||
ddl = '''
|
||||
CREATE TABLE {0}.{1} (
|
||||
k int PRIMARY KEY,
|
||||
v int )'''.format(self.keyspace_name, self.function_table_name)
|
||||
execute_until_pass(self.session, ddl)
|
||||
|
||||
def drop_function_table(self):
|
||||
ddl = "DROP TABLE {0}.{1} ".format(self.keyspace_name, self.function_table_name)
|
||||
execute_until_pass(self.session, ddl)
|
||||
|
||||
|
||||
class BasicSharedKeyspaceUnitTestCase(BasicKeyspaceUnitTestCase):
|
||||
"""
|
||||
This is basic unit test case that can be leveraged to scope a keyspace to a specific test class.
|
||||
creates a keyspace named after the testclass with a rf of 1.
|
||||
"""
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.common_setup(1)
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
cls.drop_keyspace()
|
||||
cls.cluster.shutdown()
|
||||
|
||||
|
||||
class BasicSharedKeyspaceUnitTestCaseWTable(BasicSharedKeyspaceUnitTestCase):
|
||||
"""
|
||||
This is basic unit test case that can be leveraged to scope a keyspace to a specific test class.
|
||||
creates a keyspace named after the testclass with a rf of 1, and a table named after the class
|
||||
"""
|
||||
@classmethod
|
||||
def setUpClass(self):
|
||||
self.common_setup(1, True)
|
||||
|
||||
|
||||
class BasicSharedKeyspaceUnitTestCaseRF2(BasicSharedKeyspaceUnitTestCase):
|
||||
"""
|
||||
This is basic unit test case that can be leveraged to scope a keyspace to a specific test class.
|
||||
creates a keyspace named after the test class with a rf of 2, and a table named after the class
|
||||
"""
|
||||
@classmethod
|
||||
def setUpClass(self):
|
||||
self.common_setup(2)
|
||||
|
||||
|
||||
class BasicSharedKeyspaceUnitTestCaseWTable(BasicSharedKeyspaceUnitTestCase):
|
||||
"""
|
||||
This is basic unit test case that can be leveraged to scope a keyspace to a specific test class.
|
||||
creates a keyspace named after the testc lass with a rf of 2, and a table named after the class
|
||||
"""
|
||||
@classmethod
|
||||
def setUpClass(self):
|
||||
self.common_setup(2, True)
|
||||
|
||||
|
||||
class BasicSharedKeyspaceUnitTestCaseRF3(BasicSharedKeyspaceUnitTestCase):
|
||||
"""
|
||||
This is basic unit test case that can be leveraged to scope a keyspace to a specific test class.
|
||||
creates a keyspace named after the test class with a rf of 3
|
||||
"""
|
||||
@classmethod
|
||||
def setUpClass(self):
|
||||
self.common_setup(3)
|
||||
|
||||
|
||||
class BasicSharedKeyspaceUnitTestCaseRF3WTable(BasicSharedKeyspaceUnitTestCase):
|
||||
"""
|
||||
This is basic unit test case that can be leveraged to scope a keyspace to a specific test class.
|
||||
creates a keyspace named after the test class with a rf of 3 and a table named after the class
|
||||
"""
|
||||
@classmethod
|
||||
def setUpClass(self):
|
||||
self.common_setup(3, True)
|
||||
|
||||
|
||||
class BasicSharedKeyspaceUnitTestCaseWFunctionTable(BasicSharedKeyspaceUnitTestCase):
|
||||
""""
|
||||
This is basic unit test case that can be leveraged to scope a keyspace to a specific test class.
|
||||
creates a keyspace named after the test class with a rf of 3 and a table named after the class
|
||||
the table is scoped to just the unit test and will be removed.
|
||||
|
||||
"""
|
||||
def setUp(self):
|
||||
self.create_function_table()
|
||||
|
||||
def tearDown(self):
|
||||
self.drop_function_table()
|
||||
|
||||
|
||||
class BasicSegregatedKeyspaceUnitTestCase(BasicKeyspaceUnitTestCase):
|
||||
"""
|
||||
This unit test will create and teardown a keyspace for each individual unit tests.
|
||||
It has overhead and should only be used with complex unit test were sharing a keyspace will
|
||||
cause issues.
|
||||
"""
|
||||
def setUp(self):
|
||||
self.common_setup(1)
|
||||
|
||||
def tearDown(self):
|
||||
self.drop_keyspace()
|
||||
self.cluster.shutdown()
|
||||
|
||||
@@ -12,6 +12,12 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
|
||||
try:
|
||||
import unittest2 as unittest
|
||||
except ImportError:
|
||||
import unittest # noqa
|
||||
|
||||
from cassandra.cqlengine.management import sync_table, drop_table
|
||||
from tests.integration.cqlengine.base import BaseCassEngTestCase
|
||||
from cassandra.cqlengine.models import Model
|
||||
@@ -19,6 +25,7 @@ from uuid import uuid4
|
||||
from cassandra.cqlengine import columns
|
||||
import mock
|
||||
from cassandra.cqlengine.connection import get_session
|
||||
from tests.integration import CASSANDRA_VERSION
|
||||
|
||||
|
||||
class TestTTLModel(Model):
|
||||
@@ -51,12 +58,14 @@ class BaseDefaultTTLTest(BaseCassEngTestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
if CASSANDRA_VERSION >= '2.0':
|
||||
super(BaseDefaultTTLTest, cls).setUpClass()
|
||||
sync_table(TestDefaultTTLModel)
|
||||
sync_table(TestTTLModel)
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
if CASSANDRA_VERSION >= '2.0':
|
||||
super(BaseDefaultTTLTest, cls).tearDownClass()
|
||||
drop_table(TestDefaultTTLModel)
|
||||
drop_table(TestTTLModel)
|
||||
@@ -91,7 +100,6 @@ class TTLModelTests(BaseTTLTest):
|
||||
self.assertTrue(isinstance(qs, TestTTLModel.__queryset__), type(qs))
|
||||
|
||||
|
||||
|
||||
class TTLInstanceUpdateTest(BaseTTLTest):
|
||||
def test_update_includes_ttl(self):
|
||||
session = get_session()
|
||||
@@ -109,9 +117,6 @@ class TTLInstanceUpdateTest(BaseTTLTest):
|
||||
model.ttl(60).update(text="goodbye forever")
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class TTLInstanceTest(BaseTTLTest):
|
||||
def test_instance_is_returned(self):
|
||||
"""
|
||||
@@ -151,6 +156,7 @@ class TTLBlindUpdateTest(BaseTTLTest):
|
||||
self.assertIn("USING TTL", query)
|
||||
|
||||
|
||||
@unittest.skipIf(CASSANDRA_VERSION < '2.0', "default_time_to_Live was introduce in C* 2.0, currently running {0}".format(CASSANDRA_VERSION))
|
||||
class TTLDefaultTest(BaseDefaultTTLTest):
|
||||
def test_default_ttl_not_set(self):
|
||||
session = get_session()
|
||||
|
||||
@@ -503,7 +503,7 @@ class ClusterTests(unittest.TestCase):
|
||||
cluster.shutdown()
|
||||
|
||||
def test_idle_heartbeat(self):
|
||||
interval = 1
|
||||
interval = 2
|
||||
cluster = Cluster(protocol_version=PROTOCOL_VERSION, idle_heartbeat_interval=interval)
|
||||
if PROTOCOL_VERSION < 3:
|
||||
cluster.set_core_connections_per_host(HostDistance.LOCAL, 1)
|
||||
@@ -520,7 +520,7 @@ class ClusterTests(unittest.TestCase):
|
||||
connection_request_ids[id(c)] = deque(c.request_ids) # copy of request ids
|
||||
|
||||
# let two heatbeat intervals pass (first one had startup messages in it)
|
||||
time.sleep(2 * interval + interval/10.)
|
||||
time.sleep(2 * interval + interval/2)
|
||||
|
||||
connections = [c for holders in cluster.get_connection_holders() for c in holders.get_connections()]
|
||||
|
||||
|
||||
@@ -32,8 +32,10 @@ from cassandra.metadata import (Metadata, KeyspaceMetadata, IndexMetadata, Index
|
||||
get_schema_parser)
|
||||
from cassandra.policies import SimpleConvictionPolicy
|
||||
from cassandra.pool import Host
|
||||
from cassandra.query import SimpleStatement, ConsistencyLevel
|
||||
|
||||
from tests.integration import get_cluster, use_singledc, PROTOCOL_VERSION, get_server_versions, execute_until_pass
|
||||
from tests.integration import get_cluster, use_singledc, PROTOCOL_VERSION, get_server_versions, execute_until_pass, \
|
||||
BasicSharedKeyspaceUnitTestCase, BasicSegregatedKeyspaceUnitTestCase
|
||||
|
||||
|
||||
def setup_module():
|
||||
@@ -307,8 +309,8 @@ class SchemaMetadataTests(unittest.TestCase):
|
||||
statements = [s.strip() for s in statements.split(';')]
|
||||
statements = list(filter(bool, statements))
|
||||
self.assertEqual(3, len(statements))
|
||||
self.assertEqual(d_index, statements[1])
|
||||
self.assertEqual(e_index, statements[2])
|
||||
self.assertIn(d_index, statements)
|
||||
self.assertIn(e_index, statements)
|
||||
|
||||
# make sure indexes are included in KeyspaceMetadata.export_as_string()
|
||||
ksmeta = self.cluster.metadata.keyspaces[self.ksname]
|
||||
@@ -1901,23 +1903,17 @@ class BadMetaTest(unittest.TestCase):
|
||||
self.assertIn("/*\nWarning:", m.export_as_string())
|
||||
|
||||
|
||||
class MaterializedViewMetadataTest(unittest.TestCase):
|
||||
|
||||
ksname = "materialized_view_test"
|
||||
class MaterializedViewMetadataTestSimple(BasicSharedKeyspaceUnitTestCase):
|
||||
|
||||
def setUp(self):
|
||||
if CASS_SERVER_VERSION < (3, 0):
|
||||
raise unittest.SkipTest("Materialized views require Cassandra 3.0+")
|
||||
|
||||
self.cluster = Cluster(protocol_version=PROTOCOL_VERSION)
|
||||
self.session = self.cluster.connect()
|
||||
execute_until_pass(self.session,
|
||||
"CREATE KEYSPACE {0} WITH replication = {{'class': 'SimpleStrategy', 'replication_factor': '1'}}"
|
||||
.format(self.ksname))
|
||||
self.session.execute("CREATE TABLE {0}.{1} (pk int PRIMARY KEY, c int)".format(self.keyspace_name, self.function_table_name))
|
||||
self.session.execute("CREATE MATERIALIZED VIEW {0}.mv1 AS SELECT c FROM {0}.{1} WHERE c IS NOT NULL PRIMARY KEY (pk, c)".format(self.keyspace_name, self.function_table_name))
|
||||
|
||||
def tearDown(self):
|
||||
execute_until_pass(self.session, "DROP KEYSPACE {0}".format(self.ksname))
|
||||
self.cluster.shutdown()
|
||||
self.session.execute("DROP MATERIALIZED VIEW {0}.mv1".format(self.keyspace_name))
|
||||
self.session.execute("DROP TABLE {0}.{1}".format(self.keyspace_name, self.function_table_name))
|
||||
|
||||
def test_materialized_view_metadata_creation(self):
|
||||
"""
|
||||
@@ -1935,14 +1931,11 @@ class MaterializedViewMetadataTest(unittest.TestCase):
|
||||
@test_category metadata
|
||||
"""
|
||||
|
||||
self.session.execute("CREATE TABLE {0}.table1 (pk int PRIMARY KEY, c int)".format(self.ksname))
|
||||
self.session.execute("CREATE MATERIALIZED VIEW {0}.mv1 AS SELECT c FROM {0}.table1 WHERE c IS NOT NULL PRIMARY KEY (pk, c)".format(self.ksname))
|
||||
self.assertIn("mv1", self.cluster.metadata.keyspaces[self.keyspace_name].views)
|
||||
self.assertIn("mv1", self.cluster.metadata.keyspaces[self.keyspace_name].tables[self.function_table_name].views)
|
||||
|
||||
self.assertIn("mv1", self.cluster.metadata.keyspaces[self.ksname].views)
|
||||
self.assertIn("mv1", self.cluster.metadata.keyspaces[self.ksname].tables["table1"].views)
|
||||
|
||||
self.assertEqual(self.ksname, self.cluster.metadata.keyspaces[self.ksname].tables["table1"].views["mv1"].keyspace_name)
|
||||
self.assertEqual("table1", self.cluster.metadata.keyspaces[self.ksname].tables["table1"].views["mv1"].base_table_name)
|
||||
self.assertEqual(self.keyspace_name, self.cluster.metadata.keyspaces[self.keyspace_name].tables[self.function_table_name].views["mv1"].keyspace_name)
|
||||
self.assertEqual(self.function_table_name, self.cluster.metadata.keyspaces[self.keyspace_name].tables[self.function_table_name].views["mv1"].base_table_name)
|
||||
|
||||
def test_materialized_view_metadata_alter(self):
|
||||
"""
|
||||
@@ -1959,15 +1952,10 @@ class MaterializedViewMetadataTest(unittest.TestCase):
|
||||
|
||||
@test_category metadata
|
||||
"""
|
||||
self.assertIn("SizeTieredCompactionStrategy", self.cluster.metadata.keyspaces[self.keyspace_name].tables[self.function_table_name].views["mv1"].options["compaction"]["class"] )
|
||||
|
||||
self.session.execute("CREATE TABLE {0}.table1 (pk int PRIMARY KEY, c int)".format(self.ksname))
|
||||
self.session.execute("CREATE MATERIALIZED VIEW {0}.mv1 AS SELECT c FROM {0}.table1 WHERE c IS NOT NULL PRIMARY KEY (pk, c)".format(self.ksname))
|
||||
|
||||
self.assertIn("SizeTieredCompactionStrategy", self.cluster.metadata.keyspaces[self.ksname].tables["table1"].views["mv1"].options["compaction"]["class"])
|
||||
|
||||
self.session.execute("ALTER MATERIALIZED VIEW {0}.mv1 WITH compaction = {{ 'class' : 'LeveledCompactionStrategy' }}".format(self.ksname))
|
||||
self.assertIn("LeveledCompactionStrategy", self.cluster.metadata.keyspaces[self.ksname].tables["table1"].views["mv1"].options["compaction"]["class"])
|
||||
|
||||
self.session.execute("ALTER MATERIALIZED VIEW {0}.mv1 WITH compaction = {{ 'class' : 'LeveledCompactionStrategy' }}".format(self.keyspace_name))
|
||||
self.assertIn("LeveledCompactionStrategy", self.cluster.metadata.keyspaces[self.keyspace_name].tables[self.function_table_name].views["mv1"].options["compaction"]["class"])
|
||||
|
||||
def test_materialized_view_metadata_drop(self):
|
||||
"""
|
||||
@@ -1985,14 +1973,21 @@ class MaterializedViewMetadataTest(unittest.TestCase):
|
||||
@test_category metadata
|
||||
"""
|
||||
|
||||
self.session.execute("CREATE TABLE {0}.table1 (pk int PRIMARY KEY, c int)".format(self.ksname))
|
||||
self.session.execute("CREATE MATERIALIZED VIEW {0}.mv1 AS SELECT c FROM {0}.table1 WHERE c IS NOT NULL PRIMARY KEY (pk, c)".format(self.ksname))
|
||||
self.session.execute("DROP MATERIALIZED VIEW {0}.mv1".format(self.ksname))
|
||||
self.session.execute("DROP MATERIALIZED VIEW {0}.mv1".format(self.keyspace_name))
|
||||
|
||||
self.assertNotIn("mv1", self.cluster.metadata.keyspaces[self.ksname].tables["table1"].views)
|
||||
self.assertNotIn("mv1", self.cluster.metadata.keyspaces[self.ksname].views)
|
||||
self.assertDictEqual({}, self.cluster.metadata.keyspaces[self.ksname].tables["table1"].views)
|
||||
self.assertDictEqual({}, self.cluster.metadata.keyspaces[self.ksname].views)
|
||||
self.assertNotIn("mv1", self.cluster.metadata.keyspaces[self.keyspace_name].tables[self.function_table_name].views)
|
||||
self.assertNotIn("mv1", self.cluster.metadata.keyspaces[self.keyspace_name].views)
|
||||
self.assertDictEqual({}, self.cluster.metadata.keyspaces[self.keyspace_name].tables[self.function_table_name].views)
|
||||
self.assertDictEqual({}, self.cluster.metadata.keyspaces[self.keyspace_name].views)
|
||||
|
||||
self.session.execute("CREATE MATERIALIZED VIEW {0}.mv1 AS SELECT c FROM {0}.{1} WHERE c IS NOT NULL PRIMARY KEY (pk, c)".format(self.keyspace_name, self.function_table_name))
|
||||
|
||||
|
||||
class MaterializedViewMetadataTestComplex(BasicSegregatedKeyspaceUnitTestCase):
|
||||
def setUp(self):
|
||||
if CASS_SERVER_VERSION < (3, 0):
|
||||
raise unittest.SkipTest("Materialized views require Cassandra 3.0+")
|
||||
super(MaterializedViewMetadataTestComplex, self).setUp()
|
||||
|
||||
def test_create_view_metadata(self):
|
||||
"""
|
||||
@@ -2016,7 +2011,7 @@ class MaterializedViewMetadataTest(unittest.TestCase):
|
||||
day INT,
|
||||
score INT,
|
||||
PRIMARY KEY (user, game, year, month, day)
|
||||
)""".format(self.ksname)
|
||||
)""".format(self.keyspace_name)
|
||||
|
||||
self.session.execute(create_table)
|
||||
|
||||
@@ -2024,11 +2019,11 @@ class MaterializedViewMetadataTest(unittest.TestCase):
|
||||
SELECT game, year, month, score, user, day FROM {0}.scores
|
||||
WHERE game IS NOT NULL AND year IS NOT NULL AND month IS NOT NULL AND score IS NOT NULL AND user IS NOT NULL AND day IS NOT NULL
|
||||
PRIMARY KEY ((game, year, month), score, user, day)
|
||||
WITH CLUSTERING ORDER BY (score DESC, user ASC, day ASC)""".format(self.ksname)
|
||||
WITH CLUSTERING ORDER BY (score DESC, user ASC, day ASC)""".format(self.keyspace_name)
|
||||
|
||||
self.session.execute(create_mv)
|
||||
score_table = self.cluster.metadata.keyspaces[self.ksname].tables['scores']
|
||||
mv = self.cluster.metadata.keyspaces[self.ksname].views['monthlyhigh']
|
||||
score_table = self.cluster.metadata.keyspaces[self.keyspace_name].tables['scores']
|
||||
mv = self.cluster.metadata.keyspaces[self.keyspace_name].views['monthlyhigh']
|
||||
|
||||
self.assertIsNotNone(score_table.views["monthlyhigh"])
|
||||
self.assertIsNotNone(len(score_table.views), 1)
|
||||
@@ -2056,7 +2051,7 @@ class MaterializedViewMetadataTest(unittest.TestCase):
|
||||
self.assertIsNotNone(score_table.columns['score'])
|
||||
|
||||
# Validate basic mv information
|
||||
self.assertEquals(mv.keyspace_name, self.ksname)
|
||||
self.assertEquals(mv.keyspace_name, self.keyspace_name)
|
||||
self.assertEquals(mv.name, "monthlyhigh")
|
||||
self.assertEquals(mv.base_table_name, "scores")
|
||||
self.assertFalse(mv.include_all_columns)
|
||||
@@ -2110,7 +2105,7 @@ class MaterializedViewMetadataTest(unittest.TestCase):
|
||||
self.assertEquals(day_column.is_static, mv.clustering_key[2].is_static)
|
||||
self.assertEquals(day_column.is_reversed, mv.clustering_key[2].is_reversed)
|
||||
|
||||
def test_create_mv_changes(self):
|
||||
def test_base_table_mv_changes(self):
|
||||
"""
|
||||
test to ensure that materialized view metadata is properly updated with base table changes
|
||||
|
||||
@@ -2132,39 +2127,53 @@ class MaterializedViewMetadataTest(unittest.TestCase):
|
||||
day INT,
|
||||
score TEXT,
|
||||
PRIMARY KEY (user, game, year, month, day)
|
||||
)""".format(self.ksname)
|
||||
)""".format(self.keyspace_name)
|
||||
|
||||
self.session.execute(create_table)
|
||||
|
||||
view_name = 'monthlyhigh'
|
||||
create_mv = """CREATE MATERIALIZED VIEW {0}.{1} AS
|
||||
create_mv = """CREATE MATERIALIZED VIEW {0}.monthlyhigh AS
|
||||
SELECT game, year, month, score, user, day FROM {0}.scores
|
||||
WHERE game IS NOT NULL AND year IS NOT NULL AND month IS NOT NULL AND score IS NOT NULL AND user IS NOT NULL AND day IS NOT NULL
|
||||
PRIMARY KEY ((game, year, month), score, user, day)
|
||||
WITH CLUSTERING ORDER BY (score DESC, user ASC, day ASC)""".format(self.ksname, view_name)
|
||||
WITH CLUSTERING ORDER BY (score DESC, user ASC, day ASC)""".format(self.keyspace_name)
|
||||
|
||||
create_mv_alltime = """CREATE MATERIALIZED VIEW {0}.alltimehigh AS
|
||||
SELECT * FROM {0}.scores
|
||||
WHERE game IS NOT NULL AND score IS NOT NULL AND user IS NOT NULL AND year IS NOT NULL AND month IS NOT NULL AND day IS NOT NULL
|
||||
PRIMARY KEY (game, score, user, year, month, day)
|
||||
WITH CLUSTERING ORDER BY (score DESC)""".format(self.keyspace_name)
|
||||
|
||||
self.session.execute(create_mv)
|
||||
score_table = self.cluster.metadata.keyspaces[self.ksname].tables['scores']
|
||||
|
||||
self.assertIn(view_name, score_table.views)
|
||||
self.assertIn(view_name, self.cluster.metadata.keyspaces[self.ksname].views)
|
||||
self.session.execute(create_mv_alltime)
|
||||
|
||||
insert_fouls = """ALTER TABLE {0}.scores ADD fouls INT""".format(self.ksname)
|
||||
score_table = self.cluster.metadata.keyspaces[self.keyspace_name].tables['scores']
|
||||
|
||||
self.assertIsNotNone(score_table.views["monthlyhigh"])
|
||||
self.assertEqual(len(self.cluster.metadata.keyspaces[self.keyspace_name].views), 2)
|
||||
|
||||
insert_fouls = """ALTER TABLE {0}.scores ADD fouls INT""".format((self.keyspace_name))
|
||||
|
||||
self.session.execute(insert_fouls)
|
||||
self.assertIn(view_name, self.cluster.metadata.keyspaces[self.ksname].views)
|
||||
self.assertEqual(len(self.cluster.metadata.keyspaces[self.keyspace_name].views), 2)
|
||||
|
||||
alter_scores = """ALTER TABLE {0}.scores ALTER score TYPE blob""".format(self.ksname)
|
||||
alter_scores = """ALTER TABLE {0}.scores ALTER score blob""".format((self.keyspace_name))
|
||||
|
||||
self.session.execute(alter_scores) # ERROR https://issues.apache.org/jira/browse/CASSANDRA-10424
|
||||
self.assertIn(view_name, self.cluster.metadata.keyspaces[self.ksname].views)
|
||||
self.session.execute(alter_scores)
|
||||
self.assertEqual(len(self.cluster.metadata.keyspaces[self.keyspace_name].views), 2)
|
||||
|
||||
score_column = self.cluster.metadata.keyspaces[self.ksname].tables['scores'].columns['score']
|
||||
score_column = self.cluster.metadata.keyspaces[self.keyspace_name].tables['scores'].columns['score']
|
||||
self.assertEquals(score_column.typestring, 'blob')
|
||||
|
||||
score_mv_column = self.cluster.metadata.keyspaces[self.ksname].views["monthlyhigh"].columns['score']
|
||||
score_mv_column = self.cluster.metadata.keyspaces[self.keyspace_name].views["monthlyhigh"].columns['score']
|
||||
self.assertEquals(score_mv_column.typestring, 'blob')
|
||||
|
||||
mv_alltime = self.cluster.metadata.keyspaces[self.keyspace_name].views["alltimehigh"]
|
||||
self.assertIn("fouls", mv_alltime.columns)
|
||||
|
||||
mv_alltime_fouls_comumn = self.cluster.metadata.keyspaces[self.keyspace_name].views["alltimehigh"].columns['fouls']
|
||||
self.assertEquals(mv_alltime_fouls_comumn.typestring, 'int')
|
||||
|
||||
def test_metadata_with_quoted_identifiers(self):
|
||||
"""
|
||||
test to ensure that materialized view metadata is properly constructed when quoted identifiers are used
|
||||
@@ -2184,7 +2193,7 @@ class MaterializedViewMetadataTest(unittest.TestCase):
|
||||
"theKey" int,
|
||||
"the;Clustering" int,
|
||||
"the Value" int,
|
||||
PRIMARY KEY ("theKey", "the;Clustering"))""".format(self.ksname)
|
||||
PRIMARY KEY ("theKey", "the;Clustering"))""".format(self.keyspace_name)
|
||||
|
||||
self.session.execute(create_table)
|
||||
|
||||
@@ -2192,12 +2201,12 @@ class MaterializedViewMetadataTest(unittest.TestCase):
|
||||
SELECT "theKey", "the;Clustering", "the Value"
|
||||
FROM {0}.t1
|
||||
WHERE "theKey" IS NOT NULL AND "the;Clustering" IS NOT NULL AND "the Value" IS NOT NULL
|
||||
PRIMARY KEY ("theKey", "the;Clustering")""".format(self.ksname)
|
||||
PRIMARY KEY ("theKey", "the;Clustering")""".format(self.keyspace_name)
|
||||
|
||||
self.session.execute(create_mv)
|
||||
|
||||
t1_table = self.cluster.metadata.keyspaces[self.ksname].tables['t1']
|
||||
mv = self.cluster.metadata.keyspaces[self.ksname].views['mv1']
|
||||
t1_table = self.cluster.metadata.keyspaces[self.keyspace_name].tables['t1']
|
||||
mv = self.cluster.metadata.keyspaces[self.keyspace_name].views['mv1']
|
||||
|
||||
self.assertIsNotNone(t1_table.views["mv1"])
|
||||
self.assertIsNotNone(len(t1_table.views), 1)
|
||||
@@ -2216,7 +2225,7 @@ class MaterializedViewMetadataTest(unittest.TestCase):
|
||||
self.assertIsNotNone(t1_table.columns['the Value'])
|
||||
|
||||
# Validate basic mv information
|
||||
self.assertEquals(mv.keyspace_name, self.ksname)
|
||||
self.assertEquals(mv.keyspace_name, self.keyspace_name)
|
||||
self.assertEquals(mv.name, "mv1")
|
||||
self.assertEquals(mv.base_table_name, "t1")
|
||||
self.assertFalse(mv.include_all_columns)
|
||||
|
||||
@@ -26,13 +26,15 @@ from cassandra.query import (PreparedStatement, BoundStatement, SimpleStatement,
|
||||
from cassandra.cluster import Cluster
|
||||
from cassandra.policies import HostDistance
|
||||
|
||||
from tests.integration import use_singledc, PROTOCOL_VERSION
|
||||
from tests.integration import use_singledc, PROTOCOL_VERSION, BasicSharedKeyspaceUnitTestCase, get_server_versions
|
||||
|
||||
import re
|
||||
|
||||
|
||||
def setup_module():
|
||||
use_singledc()
|
||||
global CASS_SERVER_VERSION
|
||||
CASS_SERVER_VERSION = get_server_versions()[0]
|
||||
|
||||
|
||||
class QueryTests(unittest.TestCase):
|
||||
@@ -617,3 +619,163 @@ class BatchStatementDefaultRoutingKeyTests(unittest.TestCase):
|
||||
|
||||
self.assertIsNotNone(batch.routing_key)
|
||||
self.assertEqual(batch.routing_key, self.prepared.bind((1, 0)).routing_key)
|
||||
|
||||
|
||||
class MaterializedViewQueryTest(BasicSharedKeyspaceUnitTestCase):
|
||||
|
||||
def setUp(self):
|
||||
if CASS_SERVER_VERSION < (3, 0):
|
||||
raise unittest.SkipTest("Materialized views require Cassandra 3.0+")
|
||||
|
||||
def test_mv_filtering(self):
|
||||
"""
|
||||
Test to ensure that cql filtering where clauses are properly supported in the python driver.
|
||||
|
||||
test_mv_filtering Tests that various complex MV where clauses produce the correct results. It also validates that
|
||||
these results and the grammar is supported appropriately.
|
||||
|
||||
@since 3.0.0
|
||||
@jira_ticket PYTHON-399
|
||||
@expected_result Materialized view where clauses should produce the appropriate results.
|
||||
|
||||
@test_category materialized_view
|
||||
"""
|
||||
create_table = """CREATE TABLE {0}.scores(
|
||||
user TEXT,
|
||||
game TEXT,
|
||||
year INT,
|
||||
month INT,
|
||||
day INT,
|
||||
score INT,
|
||||
PRIMARY KEY (user, game, year, month, day)
|
||||
)""".format(self.ksname)
|
||||
|
||||
self.session.execute(create_table)
|
||||
|
||||
create_mv_alltime = """CREATE MATERIALIZED VIEW {0}.alltimehigh AS
|
||||
SELECT * FROM {0}.scores
|
||||
WHERE game IS NOT NULL AND score IS NOT NULL AND user IS NOT NULL AND year IS NOT NULL AND month IS NOT NULL AND day IS NOT NULL
|
||||
PRIMARY KEY (game, score, user, year, month, day)
|
||||
WITH CLUSTERING ORDER BY (score DESC)""".format(self.ksname)
|
||||
|
||||
create_mv_dailyhigh = """CREATE MATERIALIZED VIEW {0}.dailyhigh AS
|
||||
SELECT * FROM {0}.scores
|
||||
WHERE game IS NOT NULL AND year IS NOT NULL AND month IS NOT NULL AND day IS NOT NULL AND score IS NOT NULL AND user IS NOT NULL
|
||||
PRIMARY KEY ((game, year, month, day), score, user)
|
||||
WITH CLUSTERING ORDER BY (score DESC)""".format(self.ksname)
|
||||
|
||||
create_mv_monthlyhigh = """CREATE MATERIALIZED VIEW {0}.monthlyhigh AS
|
||||
SELECT * FROM {0}.scores
|
||||
WHERE game IS NOT NULL AND year IS NOT NULL AND month IS NOT NULL AND score IS NOT NULL AND user IS NOT NULL AND day IS NOT NULL
|
||||
PRIMARY KEY ((game, year, month), score, user, day)
|
||||
WITH CLUSTERING ORDER BY (score DESC)""".format(self.ksname)
|
||||
|
||||
create_mv_filtereduserhigh = """CREATE MATERIALIZED VIEW {0}.filtereduserhigh AS
|
||||
SELECT * FROM {0}.scores
|
||||
WHERE user in ('jbellis', 'pcmanus') AND game IS NOT NULL AND score IS NOT NULL AND year is NOT NULL AND day is not NULL and month IS NOT NULL
|
||||
PRIMARY KEY (game, score, user, year, month, day)
|
||||
WITH CLUSTERING ORDER BY (score DESC)""".format(self.ksname)
|
||||
|
||||
self.session.execute(create_mv_alltime)
|
||||
self.session.execute(create_mv_dailyhigh)
|
||||
self.session.execute(create_mv_monthlyhigh)
|
||||
self.session.execute(create_mv_filtereduserhigh)
|
||||
|
||||
prepared_insert = self.session.prepare("""INSERT INTO {0}.scores (user, game, year, month, day, score) VALUES (?, ?, ? ,? ,?, ?)""".format(self.ksname))
|
||||
|
||||
bound = prepared_insert.bind(('pcmanus', 'Coup', 2015, 5, 1, 4000))
|
||||
self.session.execute(bound)
|
||||
bound = prepared_insert.bind(('jbellis', 'Coup', 2015, 5, 3, 1750))
|
||||
self.session.execute(bound)
|
||||
bound = prepared_insert.bind(('yukim', 'Coup', 2015, 5, 3, 2250))
|
||||
self.session.execute(bound)
|
||||
bound = prepared_insert.bind(('tjake', 'Coup', 2015, 5, 3, 500))
|
||||
self.session.execute(bound)
|
||||
bound = prepared_insert.bind(('iamaleksey', 'Coup', 2015, 6, 1, 2500))
|
||||
self.session.execute(bound)
|
||||
bound = prepared_insert.bind(('tjake', 'Coup', 2015, 6, 2, 1000))
|
||||
self.session.execute(bound)
|
||||
bound = prepared_insert.bind(('pcmanus', 'Coup', 2015, 6, 2, 2000))
|
||||
self.session.execute(bound)
|
||||
bound = prepared_insert.bind(('jmckenzie', 'Coup', 2015, 6, 9, 2700))
|
||||
self.session.execute(bound)
|
||||
bound = prepared_insert.bind(('jbellis', 'Coup', 2015, 6, 20, 3500))
|
||||
self.session.execute(bound)
|
||||
bound = prepared_insert.bind(('jbellis', 'Checkers', 2015, 6, 20, 1200))
|
||||
self.session.execute(bound)
|
||||
bound = prepared_insert.bind(('jbellis', 'Chess', 2015, 6, 21, 3500))
|
||||
self.session.execute(bound)
|
||||
bound = prepared_insert.bind(('pcmanus', 'Chess', 2015, 1, 25, 3200))
|
||||
self.session.execute(bound)
|
||||
|
||||
# Test simple statement and alltime high filtering
|
||||
query_statement = SimpleStatement("SELECT * FROM {0}.alltimehigh WHERE game='Coup'".format(self.ksname),
|
||||
consistency_level=ConsistencyLevel.QUORUM)
|
||||
results = self.session.execute(query_statement)
|
||||
self.assertEquals(results[0].game, 'Coup')
|
||||
self.assertEquals(results[0].year, 2015)
|
||||
self.assertEquals(results[0].month, 5)
|
||||
self.assertEquals(results[0].day, 1)
|
||||
self.assertEquals(results[0].score, 4000)
|
||||
self.assertEquals(results[0].user, "pcmanus")
|
||||
|
||||
# Test prepared statement and daily high filtering
|
||||
prepared_query = self.session.prepare("SELECT * FROM {0}.dailyhigh WHERE game=? AND year=? AND month=? and day=?".format(self.ksname).format(self.ksname))
|
||||
bound_query = prepared_query.bind(("Coup", 2015, 6, 2))
|
||||
results = self.session.execute(bound_query)
|
||||
self.assertEquals(results[0].game, 'Coup')
|
||||
self.assertEquals(results[0].year, 2015)
|
||||
self.assertEquals(results[0].month, 6)
|
||||
self.assertEquals(results[0].day, 2)
|
||||
self.assertEquals(results[0].score, 2000)
|
||||
self.assertEquals(results[0].user, "pcmanus")
|
||||
|
||||
self.assertEquals(results[1].game, 'Coup')
|
||||
self.assertEquals(results[1].year, 2015)
|
||||
self.assertEquals(results[1].month, 6)
|
||||
self.assertEquals(results[1].day, 2)
|
||||
self.assertEquals(results[1].score, 1000)
|
||||
self.assertEquals(results[1].user, "tjake")
|
||||
|
||||
# Test montly high range queries
|
||||
prepared_query = self.session.prepare("SELECT * FROM {0}.monthlyhigh WHERE game=? AND year=? AND month=? and score >= ? and score <= ?".format(self.ksname).format(self.ksname))
|
||||
bound_query = prepared_query.bind(("Coup", 2015, 6, 2500, 3500))
|
||||
results = self.session.execute(bound_query)
|
||||
self.assertEquals(results[0].game, 'Coup')
|
||||
self.assertEquals(results[0].year, 2015)
|
||||
self.assertEquals(results[0].month, 6)
|
||||
self.assertEquals(results[0].day, 20)
|
||||
self.assertEquals(results[0].score, 3500)
|
||||
self.assertEquals(results[0].user, "jbellis")
|
||||
|
||||
self.assertEquals(results[1].game, 'Coup')
|
||||
self.assertEquals(results[1].year, 2015)
|
||||
self.assertEquals(results[1].month, 6)
|
||||
self.assertEquals(results[1].day, 9)
|
||||
self.assertEquals(results[1].score, 2700)
|
||||
self.assertEquals(results[1].user, "jmckenzie")
|
||||
|
||||
self.assertEquals(results[2].game, 'Coup')
|
||||
self.assertEquals(results[2].year, 2015)
|
||||
self.assertEquals(results[2].month, 6)
|
||||
self.assertEquals(results[2].day, 1)
|
||||
self.assertEquals(results[2].score, 2500)
|
||||
self.assertEquals(results[2].user, "iamaleksey")
|
||||
|
||||
# Test filtered user high scores
|
||||
query_statement = SimpleStatement("SELECT * FROM {0}.filtereduserhigh WHERE game='Chess'".format(self.ksname),
|
||||
consistency_level=ConsistencyLevel.QUORUM)
|
||||
results = self.session.execute(query_statement)
|
||||
self.assertEquals(results[0].game, 'Chess')
|
||||
self.assertEquals(results[0].year, 2015)
|
||||
self.assertEquals(results[0].month, 6)
|
||||
self.assertEquals(results[0].day, 21)
|
||||
self.assertEquals(results[0].score, 3500)
|
||||
self.assertEquals(results[0].user, "jbellis")
|
||||
|
||||
self.assertEquals(results[1].game, 'Chess')
|
||||
self.assertEquals(results[1].year, 2015)
|
||||
self.assertEquals(results[1].month, 1)
|
||||
self.assertEquals(results[1].day, 25)
|
||||
self.assertEquals(results[1].score, 3200)
|
||||
self.assertEquals(results[1].user, "pcmanus")
|
||||
@@ -12,7 +12,7 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from tests.integration import get_server_versions, use_singledc, PROTOCOL_VERSION
|
||||
from tests.integration import get_server_versions, use_singledc, PROTOCOL_VERSION, BasicSharedKeyspaceUnitTestCaseWFunctionTable
|
||||
|
||||
try:
|
||||
import unittest2 as unittest
|
||||
@@ -28,45 +28,37 @@ def setup_module():
|
||||
use_singledc()
|
||||
|
||||
|
||||
class RowFactoryTests(unittest.TestCase):
|
||||
class RowFactoryTests(BasicSharedKeyspaceUnitTestCaseWFunctionTable):
|
||||
"""
|
||||
Test different row_factories and access code
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
self.cluster = Cluster(protocol_version=PROTOCOL_VERSION)
|
||||
self.session = self.cluster.connect()
|
||||
|
||||
def tearDown(self):
|
||||
self.cluster.shutdown()
|
||||
|
||||
truncate = '''
|
||||
TRUNCATE test3rf.test
|
||||
'''
|
||||
|
||||
insert1 = '''
|
||||
INSERT INTO test3rf.test
|
||||
super(RowFactoryTests, self).setUp()
|
||||
self.insert1 = '''
|
||||
INSERT INTO {0}.{1}
|
||||
( k , v )
|
||||
VALUES
|
||||
( 1 , 1 )
|
||||
'''
|
||||
'''.format(self.keyspace_name, self.function_table_name)
|
||||
|
||||
insert2 = '''
|
||||
INSERT INTO test3rf.test
|
||||
self.insert2 = '''
|
||||
INSERT INTO {0}.{1}
|
||||
( k , v )
|
||||
VALUES
|
||||
( 2 , 2 )
|
||||
'''
|
||||
'''.format(self.keyspace_name, self.function_table_name)
|
||||
|
||||
select = '''
|
||||
SELECT * FROM test3rf.test
|
||||
'''
|
||||
self.select = '''
|
||||
SELECT * FROM {0}.{1}
|
||||
'''.format(self.keyspace_name, self.function_table_name)
|
||||
|
||||
def tearDown(self):
|
||||
self.drop_function_table()
|
||||
|
||||
def test_tuple_factory(self):
|
||||
session = self.session
|
||||
session.row_factory = tuple_factory
|
||||
|
||||
session.execute(self.truncate)
|
||||
session.execute(self.insert1)
|
||||
session.execute(self.insert2)
|
||||
|
||||
@@ -87,7 +79,6 @@ class RowFactoryTests(unittest.TestCase):
|
||||
session = self.session
|
||||
session.row_factory = named_tuple_factory
|
||||
|
||||
session.execute(self.truncate)
|
||||
session.execute(self.insert1)
|
||||
session.execute(self.insert2)
|
||||
|
||||
@@ -107,7 +98,6 @@ class RowFactoryTests(unittest.TestCase):
|
||||
session = self.session
|
||||
session.row_factory = dict_factory
|
||||
|
||||
session.execute(self.truncate)
|
||||
session.execute(self.insert1)
|
||||
session.execute(self.insert2)
|
||||
|
||||
@@ -128,7 +118,6 @@ class RowFactoryTests(unittest.TestCase):
|
||||
session = self.session
|
||||
session.row_factory = ordered_dict_factory
|
||||
|
||||
session.execute(self.truncate)
|
||||
session.execute(self.insert1)
|
||||
session.execute(self.insert2)
|
||||
|
||||
@@ -154,7 +143,6 @@ class NamedTupleFactoryAndNumericColNamesTests(unittest.TestCase):
|
||||
def setup_class(cls):
|
||||
cls.cluster = Cluster(protocol_version=PROTOCOL_VERSION)
|
||||
cls.session = cls.cluster.connect()
|
||||
|
||||
cls._cass_version, cls._cql_version = get_server_versions()
|
||||
ddl = '''
|
||||
CREATE TABLE test1rf.table_num_col ( key blob PRIMARY KEY, "626972746864617465" blob )
|
||||
|
||||
Reference in New Issue
Block a user