Adding decorator for counting underlying query execution, updating some tests to add expected query counts
This commit is contained in:
@@ -14,15 +14,23 @@
|
||||
|
||||
import os
|
||||
import warnings
|
||||
try:
|
||||
import unittest2 as unittest
|
||||
except ImportError:
|
||||
import unittest # noqa
|
||||
from cassandra import ConsistencyLevel
|
||||
|
||||
from cassandra.cqlengine import connection
|
||||
from cassandra.cqlengine.management import create_keyspace_simple, CQLENG_ALLOW_SCHEMA_MANAGEMENT
|
||||
import cassandra
|
||||
|
||||
from tests.integration import get_server_versions, use_single_node, PROTOCOL_VERSION
|
||||
DEFAULT_KEYSPACE = 'cqlengine_test'
|
||||
|
||||
|
||||
CQL_SKIP_EXECUTE = bool(os.getenv('CQL_SKIP_EXECUTE', False))
|
||||
|
||||
|
||||
def setup_package():
|
||||
warnings.simplefilter('always') # for testing warnings, make sure all are let through
|
||||
os.environ[CQLENG_ALLOW_SCHEMA_MANAGEMENT] = '1'
|
||||
@@ -44,3 +52,57 @@ def setup_connection(keyspace_name):
|
||||
consistency=ConsistencyLevel.ONE,
|
||||
protocol_version=PROTOCOL_VERSION,
|
||||
default_keyspace=keyspace_name)
|
||||
|
||||
|
||||
class StatementCounter(object):
|
||||
"""
|
||||
Simple python object used to hold a count of the number of times
|
||||
the wrapped method has been invoked
|
||||
"""
|
||||
def __init__(self, patched_func):
|
||||
self.func = patched_func
|
||||
self.counter = 0
|
||||
|
||||
def wrapped_execute(self, *args, **kwargs):
|
||||
self.counter += 1
|
||||
return self.func(*args, **kwargs)
|
||||
|
||||
def get_counter(self):
|
||||
return self.counter
|
||||
|
||||
|
||||
def execute_count(expected):
|
||||
"""
|
||||
A decorator used wrap cassandra.cqlengine.connection.execute. It counts the number of times this method is invoked
|
||||
then compares it to the number expected. If they don't match it throws an assertion error.
|
||||
This function can be disabled by running the test harness with the env variable CQL_SKIP_EXECUTE=1 set
|
||||
"""
|
||||
def innerCounter(fn):
|
||||
def wrapped_function(*args, **kwargs):
|
||||
# Create a counter monkey patch into cassandra.cqlengine.connection.execute
|
||||
count = StatementCounter(cassandra.cqlengine.connection.execute)
|
||||
original_function = cassandra.cqlengine.connection.execute
|
||||
# Monkey patch in our StatementCounter wrapper
|
||||
cassandra.cqlengine.connection.execute = count.wrapped_execute
|
||||
# Invoked the underlying unit test
|
||||
to_return = fn(*args, **kwargs)
|
||||
# Get the count from our monkey patched counter
|
||||
count.get_counter()
|
||||
# DeMonkey Patch our code
|
||||
cassandra.cqlengine.connection.execute = original_function
|
||||
# Check to see if the count is what you expect
|
||||
tc = unittest.TestCase("__init__")
|
||||
tc.assertEquals(count.get_counter(), expected, "Expected number of cassandra.cqlengine.connection.execute calls doesn't match actual number invoked Expected: {0}, Invoked {1}".format(count.get_counter(), expected))
|
||||
return to_return
|
||||
# Name of the wrapped function must match the original or unittest will error out.
|
||||
wrapped_function.__name__ = fn.__name__
|
||||
wrapped_function.__doc__ = fn.__doc__
|
||||
# Escape hatch
|
||||
if(CQL_SKIP_EXECUTE):
|
||||
return fn
|
||||
else:
|
||||
return wrapped_function
|
||||
|
||||
return innerCounter
|
||||
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ from cassandra.cqlengine.management import drop_table, sync_table
|
||||
from cassandra.cqlengine.models import Model
|
||||
from cassandra.cqlengine.query import BatchQuery, DMLQuery
|
||||
from tests.integration.cqlengine.base import BaseCassEngTestCase
|
||||
from tests.integration.cqlengine import execute_count
|
||||
from cassandra.cluster import Session
|
||||
|
||||
|
||||
@@ -55,6 +56,7 @@ class BatchQueryTests(BaseCassEngTestCase):
|
||||
for obj in TestMultiKeyModel.filter(partition=self.pkey):
|
||||
obj.delete()
|
||||
|
||||
@execute_count(3)
|
||||
def test_insert_success_case(self):
|
||||
|
||||
b = BatchQuery()
|
||||
@@ -67,6 +69,7 @@ class BatchQueryTests(BaseCassEngTestCase):
|
||||
|
||||
TestMultiKeyModel.get(partition=self.pkey, cluster=2)
|
||||
|
||||
@execute_count(4)
|
||||
def test_update_success_case(self):
|
||||
|
||||
inst = TestMultiKeyModel.create(partition=self.pkey, cluster=2, count=3, text='4')
|
||||
@@ -84,6 +87,7 @@ class BatchQueryTests(BaseCassEngTestCase):
|
||||
inst3 = TestMultiKeyModel.get(partition=self.pkey, cluster=2)
|
||||
self.assertEqual(inst3.count, 4)
|
||||
|
||||
@execute_count(4)
|
||||
def test_delete_success_case(self):
|
||||
|
||||
inst = TestMultiKeyModel.create(partition=self.pkey, cluster=2, count=3, text='4')
|
||||
@@ -99,6 +103,7 @@ class BatchQueryTests(BaseCassEngTestCase):
|
||||
with self.assertRaises(TestMultiKeyModel.DoesNotExist):
|
||||
TestMultiKeyModel.get(partition=self.pkey, cluster=2)
|
||||
|
||||
@execute_count(11)
|
||||
def test_context_manager(self):
|
||||
|
||||
with BatchQuery() as b:
|
||||
@@ -112,6 +117,7 @@ class BatchQueryTests(BaseCassEngTestCase):
|
||||
for i in range(5):
|
||||
TestMultiKeyModel.get(partition=self.pkey, cluster=i)
|
||||
|
||||
@execute_count(9)
|
||||
def test_bulk_delete_success_case(self):
|
||||
|
||||
for i in range(1):
|
||||
@@ -127,6 +133,7 @@ class BatchQueryTests(BaseCassEngTestCase):
|
||||
for m in TestMultiKeyModel.all():
|
||||
m.delete()
|
||||
|
||||
@execute_count(0)
|
||||
def test_none_success_case(self):
|
||||
""" Tests that passing None into the batch call clears any batch object """
|
||||
b = BatchQuery()
|
||||
@@ -137,6 +144,7 @@ class BatchQueryTests(BaseCassEngTestCase):
|
||||
q = q.batch(None)
|
||||
self.assertIsNone(q._batch)
|
||||
|
||||
@execute_count(0)
|
||||
def test_dml_none_success_case(self):
|
||||
""" Tests that passing None into the batch call clears any batch object """
|
||||
b = BatchQuery()
|
||||
@@ -147,6 +155,7 @@ class BatchQueryTests(BaseCassEngTestCase):
|
||||
q.batch(None)
|
||||
self.assertIsNone(q._batch)
|
||||
|
||||
@execute_count(3)
|
||||
def test_batch_execute_on_exception_succeeds(self):
|
||||
# makes sure if execute_on_exception == True we still apply the batch
|
||||
drop_table(BatchQueryLogModel)
|
||||
@@ -166,6 +175,7 @@ class BatchQueryTests(BaseCassEngTestCase):
|
||||
# should be 1 because the batch should execute
|
||||
self.assertEqual(1, len(obj))
|
||||
|
||||
@execute_count(2)
|
||||
def test_batch_execute_on_exception_skips_if_not_specified(self):
|
||||
# makes sure if execute_on_exception == True we still apply the batch
|
||||
drop_table(BatchQueryLogModel)
|
||||
@@ -186,12 +196,14 @@ class BatchQueryTests(BaseCassEngTestCase):
|
||||
# should be 0 because the batch should not execute
|
||||
self.assertEqual(0, len(obj))
|
||||
|
||||
@execute_count(1)
|
||||
def test_batch_execute_timeout(self):
|
||||
with mock.patch.object(Session, 'execute') as mock_execute:
|
||||
with BatchQuery(timeout=1) as b:
|
||||
BatchQueryLogModel.batch(b).create(k=2, v=2)
|
||||
self.assertEqual(mock_execute.call_args[-1]['timeout'], 1)
|
||||
|
||||
@execute_count(1)
|
||||
def test_batch_execute_no_timeout(self):
|
||||
with mock.patch.object(Session, 'execute') as mock_execute:
|
||||
with BatchQuery() as b:
|
||||
|
||||
@@ -20,15 +20,17 @@ from tests.integration.cqlengine.base import BaseCassEngTestCase
|
||||
|
||||
from cassandra.cqlengine.management import sync_table
|
||||
from cassandra.cqlengine.management import drop_table
|
||||
from cassandra.cqlengine.models import Model, ModelException
|
||||
from cassandra.cqlengine.models import Model
|
||||
from cassandra.cqlengine import columns
|
||||
from cassandra.cqlengine import query
|
||||
from tests.integration.cqlengine import execute_count
|
||||
|
||||
|
||||
class DateTimeQueryTestModel(Model):
|
||||
|
||||
user = columns.Integer(primary_key=True)
|
||||
day = columns.DateTime(primary_key=True)
|
||||
data = columns.Text()
|
||||
user = columns.Integer(primary_key=True)
|
||||
day = columns.DateTime(primary_key=True)
|
||||
data = columns.Text()
|
||||
|
||||
|
||||
class TestDateTimeQueries(BaseCassEngTestCase):
|
||||
|
||||
@@ -46,12 +48,12 @@ class TestDateTimeQueries(BaseCassEngTestCase):
|
||||
data=str(uuid4())
|
||||
)
|
||||
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
super(TestDateTimeQueries, cls).tearDownClass()
|
||||
drop_table(DateTimeQueryTestModel)
|
||||
|
||||
@execute_count(1)
|
||||
def test_range_query(self):
|
||||
""" Tests that loading from a range of dates works properly """
|
||||
start = datetime(*self.base_date.timetuple()[:3])
|
||||
@@ -60,6 +62,7 @@ class TestDateTimeQueries(BaseCassEngTestCase):
|
||||
results = DateTimeQueryTestModel.filter(user=0, day__gte=start, day__lt=end)
|
||||
assert len(results) == 3
|
||||
|
||||
@execute_count(3)
|
||||
def test_datetime_precision(self):
|
||||
""" Tests that millisecond resolution is preserved when saving datetime objects """
|
||||
now = datetime.now()
|
||||
|
||||
@@ -25,7 +25,7 @@ from cassandra.cqlengine.query import ResultObject
|
||||
from cassandra.concurrent import execute_concurrent_with_args
|
||||
from cassandra.cqlengine import models
|
||||
|
||||
from tests.integration.cqlengine import setup_connection
|
||||
from tests.integration.cqlengine import setup_connection, execute_count
|
||||
from tests.integration.cqlengine.base import BaseCassEngTestCase
|
||||
from tests.integration.cqlengine.query.test_queryset import BaseQuerySetUsage
|
||||
|
||||
@@ -134,6 +134,7 @@ class TestQuerySetCountSelectionAndIteration(BaseQuerySetUsage):
|
||||
cls.keyspace = NamedKeyspace(ks)
|
||||
cls.table = cls.keyspace.table(tn)
|
||||
|
||||
@execute_count(2)
|
||||
def test_count(self):
|
||||
""" Tests that adding filtering statements affects the count query as expected """
|
||||
assert self.table.objects.count() == 12
|
||||
@@ -141,6 +142,7 @@ class TestQuerySetCountSelectionAndIteration(BaseQuerySetUsage):
|
||||
q = self.table.objects(test_id=0)
|
||||
assert q.count() == 4
|
||||
|
||||
@execute_count(2)
|
||||
def test_query_expression_count(self):
|
||||
""" Tests that adding query statements affects the count query as expected """
|
||||
assert self.table.objects.count() == 12
|
||||
@@ -148,6 +150,7 @@ class TestQuerySetCountSelectionAndIteration(BaseQuerySetUsage):
|
||||
q = self.table.objects(self.table.column('test_id') == 0)
|
||||
assert q.count() == 4
|
||||
|
||||
@execute_count(3)
|
||||
def test_iteration(self):
|
||||
""" Tests that iterating over a query set pulls back all of the expected results """
|
||||
q = self.table.objects(test_id=0)
|
||||
@@ -181,6 +184,7 @@ class TestQuerySetCountSelectionAndIteration(BaseQuerySetUsage):
|
||||
compare_set.remove(val)
|
||||
assert len(compare_set) == 0
|
||||
|
||||
@execute_count(2)
|
||||
def test_multiple_iterations_work_properly(self):
|
||||
""" Tests that iterating over a query set more than once works """
|
||||
# test with both the filtering method and the query method
|
||||
@@ -201,6 +205,7 @@ class TestQuerySetCountSelectionAndIteration(BaseQuerySetUsage):
|
||||
compare_set.remove(val)
|
||||
assert len(compare_set) == 0
|
||||
|
||||
@execute_count(2)
|
||||
def test_multiple_iterators_are_isolated(self):
|
||||
"""
|
||||
tests that the use of one iterator does not affect the behavior of another
|
||||
@@ -214,6 +219,7 @@ class TestQuerySetCountSelectionAndIteration(BaseQuerySetUsage):
|
||||
assert next(iter1).attempt_id == attempt_id
|
||||
assert next(iter2).attempt_id == attempt_id
|
||||
|
||||
@execute_count(3)
|
||||
def test_get_success_case(self):
|
||||
"""
|
||||
Tests that the .get() method works on new and existing querysets
|
||||
@@ -235,6 +241,7 @@ class TestQuerySetCountSelectionAndIteration(BaseQuerySetUsage):
|
||||
assert m.test_id == 0
|
||||
assert m.attempt_id == 0
|
||||
|
||||
@execute_count(3)
|
||||
def test_query_expression_get_success_case(self):
|
||||
"""
|
||||
Tests that the .get() method works on new and existing querysets
|
||||
@@ -256,6 +263,7 @@ class TestQuerySetCountSelectionAndIteration(BaseQuerySetUsage):
|
||||
assert m.test_id == 0
|
||||
assert m.attempt_id == 0
|
||||
|
||||
@execute_count(1)
|
||||
def test_get_doesnotexist_exception(self):
|
||||
"""
|
||||
Tests that get calls that don't return a result raises a DoesNotExist error
|
||||
@@ -263,6 +271,7 @@ class TestQuerySetCountSelectionAndIteration(BaseQuerySetUsage):
|
||||
with self.assertRaises(self.table.DoesNotExist):
|
||||
self.table.objects.get(test_id=100)
|
||||
|
||||
@execute_count(1)
|
||||
def test_get_multipleobjects_exception(self):
|
||||
"""
|
||||
Tests that get calls that return multiple results raise a MultipleObjectsReturned error
|
||||
@@ -286,6 +295,7 @@ class TestNamedWithMV(BasicSharedKeyspaceUnitTestCase):
|
||||
super(TestNamedWithMV, cls).tearDownClass()
|
||||
|
||||
@greaterthanorequalcass30
|
||||
@execute_count(5)
|
||||
def test_named_table_with_mv(self):
|
||||
"""
|
||||
Test NamedTable access to materialized views
|
||||
|
||||
@@ -24,6 +24,7 @@ from cassandra.cqlengine.operators import EqualsOperator
|
||||
from cassandra.cqlengine.statements import WhereClause
|
||||
from tests.integration.cqlengine import DEFAULT_KEYSPACE
|
||||
from tests.integration.cqlengine.base import BaseCassEngTestCase
|
||||
from tests.integration.cqlengine import execute_count
|
||||
|
||||
|
||||
class TestQuerySetOperation(BaseCassEngTestCase):
|
||||
@@ -71,6 +72,7 @@ class TestTokenFunction(BaseCassEngTestCase):
|
||||
super(TestTokenFunction, self).tearDown()
|
||||
drop_table(TokenTestModel)
|
||||
|
||||
@execute_count(14)
|
||||
def test_token_function(self):
|
||||
""" Tests that token functions work properly """
|
||||
assert TokenTestModel.objects().count() == 0
|
||||
@@ -127,6 +129,7 @@ class TestTokenFunction(BaseCassEngTestCase):
|
||||
func = functions.Token('a')
|
||||
self.assertRaises(query.QueryException, TestModel.objects.filter, pk__token__gt=func)
|
||||
|
||||
@execute_count(7)
|
||||
def test_named_table_pk_token_function(self):
|
||||
"""
|
||||
Test to ensure that token function work with named tables.
|
||||
|
||||
@@ -40,9 +40,9 @@ from datetime import tzinfo
|
||||
from cassandra.cqlengine import statements
|
||||
from cassandra.cqlengine import operators
|
||||
from cassandra.util import uuid_from_time
|
||||
|
||||
from cassandra.cqlengine.connection import get_session
|
||||
from tests.integration import PROTOCOL_VERSION, CASSANDRA_VERSION, greaterthancass20, greaterthancass21
|
||||
from tests.integration.cqlengine import execute_count
|
||||
|
||||
|
||||
class TzOffset(tzinfo):
|
||||
@@ -105,6 +105,7 @@ class TestMultiClusteringModel(Model):
|
||||
|
||||
|
||||
class TestQuerySetOperation(BaseCassEngTestCase):
|
||||
|
||||
def test_query_filter_parsing(self):
|
||||
"""
|
||||
Tests the queryset filter method parses it's kwargs properly
|
||||
@@ -229,6 +230,7 @@ class TestQuerySetOperation(BaseCassEngTestCase):
|
||||
|
||||
|
||||
class BaseQuerySetUsage(BaseCassEngTestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(BaseQuerySetUsage, cls).setUpClass()
|
||||
@@ -298,6 +300,8 @@ class BaseQuerySetUsage(BaseCassEngTestCase):
|
||||
|
||||
|
||||
class TestQuerySetCountSelectionAndIteration(BaseQuerySetUsage):
|
||||
|
||||
@execute_count(2)
|
||||
def test_count(self):
|
||||
""" Tests that adding filtering statements affects the count query as expected """
|
||||
assert TestModel.objects.count() == 12
|
||||
@@ -305,6 +309,7 @@ class TestQuerySetCountSelectionAndIteration(BaseQuerySetUsage):
|
||||
q = TestModel.objects(test_id=0)
|
||||
assert q.count() == 4
|
||||
|
||||
@execute_count(2)
|
||||
def test_query_expression_count(self):
|
||||
""" Tests that adding query statements affects the count query as expected """
|
||||
assert TestModel.objects.count() == 12
|
||||
@@ -312,6 +317,7 @@ class TestQuerySetCountSelectionAndIteration(BaseQuerySetUsage):
|
||||
q = TestModel.objects(TestModel.test_id == 0)
|
||||
assert q.count() == 4
|
||||
|
||||
@execute_count(3)
|
||||
def test_iteration(self):
|
||||
""" Tests that iterating over a query set pulls back all of the expected results """
|
||||
q = TestModel.objects(test_id=0)
|
||||
@@ -345,6 +351,7 @@ class TestQuerySetCountSelectionAndIteration(BaseQuerySetUsage):
|
||||
compare_set.remove(val)
|
||||
assert len(compare_set) == 0
|
||||
|
||||
@execute_count(2)
|
||||
def test_multiple_iterations_work_properly(self):
|
||||
""" Tests that iterating over a query set more than once works """
|
||||
# test with both the filtering method and the query method
|
||||
@@ -365,6 +372,7 @@ class TestQuerySetCountSelectionAndIteration(BaseQuerySetUsage):
|
||||
compare_set.remove(val)
|
||||
assert len(compare_set) == 0
|
||||
|
||||
@execute_count(2)
|
||||
def test_multiple_iterators_are_isolated(self):
|
||||
"""
|
||||
tests that the use of one iterator does not affect the behavior of another
|
||||
@@ -378,6 +386,7 @@ class TestQuerySetCountSelectionAndIteration(BaseQuerySetUsage):
|
||||
assert next(iter1).attempt_id == attempt_id
|
||||
assert next(iter2).attempt_id == attempt_id
|
||||
|
||||
@execute_count(3)
|
||||
def test_get_success_case(self):
|
||||
"""
|
||||
Tests that the .get() method works on new and existing querysets
|
||||
@@ -399,6 +408,7 @@ class TestQuerySetCountSelectionAndIteration(BaseQuerySetUsage):
|
||||
assert m.test_id == 0
|
||||
assert m.attempt_id == 0
|
||||
|
||||
@execute_count(3)
|
||||
def test_query_expression_get_success_case(self):
|
||||
"""
|
||||
Tests that the .get() method works on new and existing querysets
|
||||
@@ -420,6 +430,7 @@ class TestQuerySetCountSelectionAndIteration(BaseQuerySetUsage):
|
||||
assert m.test_id == 0
|
||||
assert m.attempt_id == 0
|
||||
|
||||
@execute_count(1)
|
||||
def test_get_doesnotexist_exception(self):
|
||||
"""
|
||||
Tests that get calls that don't return a result raises a DoesNotExist error
|
||||
@@ -427,6 +438,7 @@ class TestQuerySetCountSelectionAndIteration(BaseQuerySetUsage):
|
||||
with self.assertRaises(TestModel.DoesNotExist):
|
||||
TestModel.objects.get(test_id=100)
|
||||
|
||||
@execute_count(1)
|
||||
def test_get_multipleobjects_exception(self):
|
||||
"""
|
||||
Tests that get calls that return multiple results raise a MultipleObjectsReturned error
|
||||
@@ -438,7 +450,7 @@ class TestQuerySetCountSelectionAndIteration(BaseQuerySetUsage):
|
||||
"""
|
||||
"""
|
||||
|
||||
|
||||
@execute_count(4)
|
||||
def test_non_quality_filtering():
|
||||
class NonEqualityFilteringModel(Model):
|
||||
|
||||
@@ -463,28 +475,34 @@ def test_non_quality_filtering():
|
||||
|
||||
class TestQuerySetDistinct(BaseQuerySetUsage):
|
||||
|
||||
@execute_count(1)
|
||||
def test_distinct_without_parameter(self):
|
||||
q = TestModel.objects.distinct()
|
||||
self.assertEqual(len(q), 3)
|
||||
|
||||
@execute_count(1)
|
||||
def test_distinct_with_parameter(self):
|
||||
q = TestModel.objects.distinct(['test_id'])
|
||||
self.assertEqual(len(q), 3)
|
||||
|
||||
@execute_count(1)
|
||||
def test_distinct_with_filter(self):
|
||||
q = TestModel.objects.distinct(['test_id']).filter(test_id__in=[1, 2])
|
||||
self.assertEqual(len(q), 2)
|
||||
|
||||
@execute_count(1)
|
||||
def test_distinct_with_non_partition(self):
|
||||
with self.assertRaises(InvalidRequest):
|
||||
q = TestModel.objects.distinct(['description']).filter(test_id__in=[1, 2])
|
||||
len(q)
|
||||
|
||||
@execute_count(1)
|
||||
def test_zero_result(self):
|
||||
q = TestModel.objects.distinct(['test_id']).filter(test_id__in=[52])
|
||||
self.assertEqual(len(q), 0)
|
||||
|
||||
@greaterthancass21
|
||||
@execute_count(2)
|
||||
def test_distinct_with_explicit_count(self):
|
||||
q = TestModel.objects.distinct(['test_id'])
|
||||
self.assertEqual(q.count(), 3)
|
||||
@@ -494,7 +512,7 @@ class TestQuerySetDistinct(BaseQuerySetUsage):
|
||||
|
||||
|
||||
class TestQuerySetOrdering(BaseQuerySetUsage):
|
||||
|
||||
@execute_count(2)
|
||||
def test_order_by_success_case(self):
|
||||
q = TestModel.objects(test_id=0).order_by('attempt_id')
|
||||
expected_order = [0, 1, 2, 3]
|
||||
@@ -523,6 +541,7 @@ class TestQuerySetOrdering(BaseQuerySetUsage):
|
||||
with self.assertRaises(query.QueryException):
|
||||
IndexedTestModel.objects(test_id=0).order_by('attempt_id')
|
||||
|
||||
@execute_count(8)
|
||||
def test_ordering_on_multiple_clustering_columns(self):
|
||||
TestMultiClusteringModel.create(one=1, two=1, three=4)
|
||||
TestMultiClusteringModel.create(one=1, two=1, three=2)
|
||||
@@ -541,23 +560,28 @@ class TestQuerySetOrdering(BaseQuerySetUsage):
|
||||
|
||||
|
||||
class TestQuerySetSlicing(BaseQuerySetUsage):
|
||||
|
||||
@execute_count(1)
|
||||
def test_out_of_range_index_raises_error(self):
|
||||
q = TestModel.objects(test_id=0).order_by('attempt_id')
|
||||
with self.assertRaises(IndexError):
|
||||
q[10]
|
||||
|
||||
@execute_count(1)
|
||||
def test_array_indexing_works_properly(self):
|
||||
q = TestModel.objects(test_id=0).order_by('attempt_id')
|
||||
expected_order = [0, 1, 2, 3]
|
||||
for i in range(len(q)):
|
||||
assert q[i].attempt_id == expected_order[i]
|
||||
|
||||
@execute_count(1)
|
||||
def test_negative_indexing_works_properly(self):
|
||||
q = TestModel.objects(test_id=0).order_by('attempt_id')
|
||||
expected_order = [0, 1, 2, 3]
|
||||
assert q[-1].attempt_id == expected_order[-1]
|
||||
assert q[-2].attempt_id == expected_order[-2]
|
||||
|
||||
@execute_count(1)
|
||||
def test_slicing_works_properly(self):
|
||||
q = TestModel.objects(test_id=0).order_by('attempt_id')
|
||||
expected_order = [0, 1, 2, 3]
|
||||
@@ -568,6 +592,7 @@ class TestQuerySetSlicing(BaseQuerySetUsage):
|
||||
for model, expect in zip(q[0:3:2], expected_order[0:3:2]):
|
||||
self.assertEqual(model.attempt_id, expect)
|
||||
|
||||
@execute_count(1)
|
||||
def test_negative_slicing(self):
|
||||
q = TestModel.objects(test_id=0).order_by('attempt_id')
|
||||
expected_order = [0, 1, 2, 3]
|
||||
@@ -589,6 +614,7 @@ class TestQuerySetSlicing(BaseQuerySetUsage):
|
||||
|
||||
|
||||
class TestQuerySetValidation(BaseQuerySetUsage):
|
||||
|
||||
def test_primary_key_or_index_must_be_specified(self):
|
||||
"""
|
||||
Tests that queries that don't have an equals relation to a primary key or indexed field fail
|
||||
@@ -606,6 +632,7 @@ class TestQuerySetValidation(BaseQuerySetUsage):
|
||||
list([i for i in q])
|
||||
|
||||
@greaterthancass20
|
||||
@execute_count(7)
|
||||
def test_indexed_field_can_be_queried(self):
|
||||
"""
|
||||
Tests that queries on an indexed field will work without any primary key relations specified
|
||||
@@ -633,6 +660,8 @@ class TestQuerySetValidation(BaseQuerySetUsage):
|
||||
|
||||
|
||||
class TestQuerySetDelete(BaseQuerySetUsage):
|
||||
|
||||
@execute_count(9)
|
||||
def test_delete(self):
|
||||
TestModel.objects.create(test_id=3, attempt_id=0, description='try9', expected_result=50, test_result=40)
|
||||
TestModel.objects.create(test_id=3, attempt_id=1, description='try10', expected_result=60, test_result=40)
|
||||
@@ -658,6 +687,7 @@ class TestQuerySetDelete(BaseQuerySetUsage):
|
||||
TestModel.objects(attempt_id=0).delete()
|
||||
|
||||
@unittest.skipIf(CASSANDRA_VERSION < '3.0', "range deletion was introduce in C* 3.0, currently running {0}".format(CASSANDRA_VERSION))
|
||||
@execute_count(18)
|
||||
def test_range_deletion(self):
|
||||
"""
|
||||
Tests that range deletion work as expected
|
||||
@@ -697,6 +727,7 @@ class TestMinMaxTimeUUIDFunctions(BaseCassEngTestCase):
|
||||
super(TestMinMaxTimeUUIDFunctions, cls).tearDownClass()
|
||||
drop_table(TimeUUIDQueryModel)
|
||||
|
||||
@execute_count(7)
|
||||
def test_tzaware_datetime_support(self):
|
||||
"""Test that using timezone aware datetime instances works with the
|
||||
MinTimeUUID/MaxTimeUUID functions.
|
||||
@@ -740,6 +771,7 @@ class TestMinMaxTimeUUIDFunctions(BaseCassEngTestCase):
|
||||
TimeUUIDQueryModel.partition == pk,
|
||||
TimeUUIDQueryModel.time >= functions.MinTimeUUID(midpoint_helsinki))]
|
||||
|
||||
@execute_count(8)
|
||||
def test_success_case(self):
|
||||
""" Test that the min and max time uuid functions work as expected """
|
||||
pk = uuid4()
|
||||
@@ -790,11 +822,14 @@ class TestMinMaxTimeUUIDFunctions(BaseCassEngTestCase):
|
||||
|
||||
|
||||
class TestInOperator(BaseQuerySetUsage):
|
||||
|
||||
@execute_count(1)
|
||||
def test_kwarg_success_case(self):
|
||||
""" Tests the in operator works with the kwarg query method """
|
||||
q = TestModel.filter(test_id__in=[0, 1])
|
||||
assert q.count() == 8
|
||||
|
||||
@execute_count(1)
|
||||
def test_query_expression_success_case(self):
|
||||
""" Tests the in operator works with the query expression query method """
|
||||
q = TestModel.filter(TestModel.test_id.in_([0, 1]))
|
||||
@@ -803,6 +838,8 @@ class TestInOperator(BaseQuerySetUsage):
|
||||
|
||||
@greaterthancass20
|
||||
class TestContainsOperator(BaseQuerySetUsage):
|
||||
|
||||
@execute_count(6)
|
||||
def test_kwarg_success_case(self):
|
||||
""" Tests the CONTAINS operator works with the kwarg query method """
|
||||
q = IndexedCollectionsTestModel.filter(test_list__contains=1)
|
||||
@@ -833,6 +870,7 @@ class TestContainsOperator(BaseQuerySetUsage):
|
||||
q = IndexedCollectionsTestModel.filter(test_map_no_index__contains=1)
|
||||
self.assertEqual(q.count(), 0)
|
||||
|
||||
@execute_count(6)
|
||||
def test_query_expression_success_case(self):
|
||||
""" Tests the CONTAINS operator works with the query expression query method """
|
||||
q = IndexedCollectionsTestModel.filter(IndexedCollectionsTestModel.test_list.contains_(1))
|
||||
@@ -865,6 +903,8 @@ class TestContainsOperator(BaseQuerySetUsage):
|
||||
|
||||
|
||||
class TestValuesList(BaseQuerySetUsage):
|
||||
|
||||
@execute_count(2)
|
||||
def test_values_list(self):
|
||||
q = TestModel.objects.filter(test_id=0, attempt_id=1)
|
||||
item = q.values_list('test_id', 'attempt_id', 'description', 'expected_result', 'test_result').first()
|
||||
@@ -875,6 +915,7 @@ class TestValuesList(BaseQuerySetUsage):
|
||||
|
||||
|
||||
class TestObjectsProperty(BaseQuerySetUsage):
|
||||
@execute_count(1)
|
||||
def test_objects_property_returns_fresh_queryset(self):
|
||||
assert TestModel.objects._result_cache is None
|
||||
len(TestModel.objects) # evaluate queryset
|
||||
@@ -882,6 +923,7 @@ class TestObjectsProperty(BaseQuerySetUsage):
|
||||
|
||||
|
||||
class PageQueryTests(BaseCassEngTestCase):
|
||||
@execute_count(3)
|
||||
def test_paged_result_handling(self):
|
||||
if PROTOCOL_VERSION < 2:
|
||||
raise unittest.SkipTest("Paging requires native protocol 2+, currently using: {0}".format(PROTOCOL_VERSION))
|
||||
@@ -989,6 +1031,7 @@ class TestModelQueryWithDBField(BaseCassEngTestCase):
|
||||
for model in cls.model_list:
|
||||
drop_table(model)
|
||||
|
||||
@execute_count(33)
|
||||
def test_basic_crud(self):
|
||||
"""
|
||||
Tests creation update and delete of object model queries that are using db_field mappings.
|
||||
@@ -1025,6 +1068,7 @@ class TestModelQueryWithDBField(BaseCassEngTestCase):
|
||||
i = model.objects(k0=i.k0, k1=i.k1).first()
|
||||
self.assertIsNone(i)
|
||||
|
||||
@execute_count(21)
|
||||
def test_slice(self):
|
||||
"""
|
||||
Tests slice queries for object models that are using db_field mapping
|
||||
@@ -1047,6 +1091,7 @@ class TestModelQueryWithDBField(BaseCassEngTestCase):
|
||||
self.assertEqual(model.objects(k0=i.k0, k1=i.k1, c0__lt=i.c0).count(), len(clustering_values[:-1]))
|
||||
self.assertEqual(model.objects(k0=i.k0, k1=i.k1, c0__gt=0).count(), len(clustering_values[1:]))
|
||||
|
||||
@execute_count(15)
|
||||
def test_order(self):
|
||||
"""
|
||||
Tests order by queries for object models that are using db_field mapping
|
||||
@@ -1066,6 +1111,7 @@ class TestModelQueryWithDBField(BaseCassEngTestCase):
|
||||
self.assertEqual(model.objects(k0=i.k0, k1=i.k1).order_by('c0').first().c0, clustering_values[0])
|
||||
self.assertEqual(model.objects(k0=i.k0, k1=i.k1).order_by('-c0').first().c0, clustering_values[-1])
|
||||
|
||||
@execute_count(15)
|
||||
def test_index(self):
|
||||
"""
|
||||
Tests queries using index fields for object models using db_field mapping
|
||||
@@ -1086,6 +1132,7 @@ class TestModelQueryWithDBField(BaseCassEngTestCase):
|
||||
self.assertEqual(model.objects(k0=i.k0, k1=i.k1).count(), len(clustering_values))
|
||||
self.assertEqual(model.objects(k0=i.k0, k1=i.k1, v1=0).count(), 1)
|
||||
|
||||
@execute_count(1)
|
||||
def test_db_field_names_used(self):
|
||||
"""
|
||||
Tests to ensure that with generated cql update statements correctly utilize the db_field values.
|
||||
@@ -1145,6 +1192,7 @@ class TestModelQueryWithFetchSize(BaseCassEngTestCase):
|
||||
super(TestModelQueryWithFetchSize, cls).tearDownClass()
|
||||
drop_table(TestModelSmall)
|
||||
|
||||
@execute_count(9)
|
||||
def test_defaultFetchSize(self):
|
||||
with BatchQuery() as b:
|
||||
for i in range(5100):
|
||||
@@ -1202,6 +1250,7 @@ class TestModelQueryWithDifferedFeld(BaseCassEngTestCase):
|
||||
super(TestModelQueryWithDifferedFeld, cls).tearDownClass()
|
||||
drop_table(People)
|
||||
|
||||
@execute_count(8)
|
||||
def test_defaultFetchSize(self):
|
||||
# Populate Table
|
||||
People.objects.create(last_name="Smith", first_name="John", birthday=datetime.now())
|
||||
|
||||
@@ -20,6 +20,7 @@ from cassandra.cqlengine.management import sync_table, drop_table
|
||||
from cassandra.cqlengine import columns
|
||||
from tests.integration.cqlengine import is_prepend_reversed
|
||||
from tests.integration.cqlengine.base import BaseCassEngTestCase
|
||||
from tests.integration.cqlengine import execute_count
|
||||
|
||||
|
||||
class TestQueryUpdateModel(Model):
|
||||
@@ -45,6 +46,7 @@ class QueryUpdateTests(BaseCassEngTestCase):
|
||||
super(QueryUpdateTests, cls).tearDownClass()
|
||||
drop_table(TestQueryUpdateModel)
|
||||
|
||||
@execute_count(8)
|
||||
def test_update_values(self):
|
||||
""" tests calling udpate on a queryset """
|
||||
partition = uuid4()
|
||||
@@ -65,6 +67,7 @@ class QueryUpdateTests(BaseCassEngTestCase):
|
||||
self.assertEqual(row.count, 6 if i == 3 else i)
|
||||
self.assertEqual(row.text, str(i))
|
||||
|
||||
@execute_count(6)
|
||||
def test_update_values_validation(self):
|
||||
""" tests calling udpate on models with values passed in """
|
||||
partition = uuid4()
|
||||
@@ -91,6 +94,7 @@ class QueryUpdateTests(BaseCassEngTestCase):
|
||||
with self.assertRaises(ValidationError):
|
||||
TestQueryUpdateModel.objects(partition=uuid4(), cluster=3).update(cluster=5000)
|
||||
|
||||
@execute_count(8)
|
||||
def test_null_update_deletes_column(self):
|
||||
""" setting a field to null in the update should issue a delete statement """
|
||||
partition = uuid4()
|
||||
@@ -111,6 +115,7 @@ class QueryUpdateTests(BaseCassEngTestCase):
|
||||
self.assertEqual(row.count, i)
|
||||
self.assertEqual(row.text, None if i == 3 else str(i))
|
||||
|
||||
@execute_count(9)
|
||||
def test_mixed_value_and_null_update(self):
|
||||
""" tests that updating a columns value, and removing another works properly """
|
||||
partition = uuid4()
|
||||
@@ -131,9 +136,7 @@ class QueryUpdateTests(BaseCassEngTestCase):
|
||||
self.assertEqual(row.count, 6 if i == 3 else i)
|
||||
self.assertEqual(row.text, None if i == 3 else str(i))
|
||||
|
||||
def test_counter_updates(self):
|
||||
pass
|
||||
|
||||
@execute_count(3)
|
||||
def test_set_add_updates(self):
|
||||
partition = uuid4()
|
||||
cluster = 1
|
||||
@@ -144,6 +147,7 @@ class QueryUpdateTests(BaseCassEngTestCase):
|
||||
obj = TestQueryUpdateModel.objects.get(partition=partition, cluster=cluster)
|
||||
self.assertEqual(obj.text_set, set(("foo", "bar")))
|
||||
|
||||
@execute_count(2)
|
||||
def test_set_add_updates_new_record(self):
|
||||
""" If the key doesn't exist yet, an update creates the record
|
||||
"""
|
||||
@@ -154,6 +158,7 @@ class QueryUpdateTests(BaseCassEngTestCase):
|
||||
obj = TestQueryUpdateModel.objects.get(partition=partition, cluster=cluster)
|
||||
self.assertEqual(obj.text_set, set(("bar",)))
|
||||
|
||||
@execute_count(3)
|
||||
def test_set_remove_updates(self):
|
||||
partition = uuid4()
|
||||
cluster = 1
|
||||
@@ -165,6 +170,7 @@ class QueryUpdateTests(BaseCassEngTestCase):
|
||||
obj = TestQueryUpdateModel.objects.get(partition=partition, cluster=cluster)
|
||||
self.assertEqual(obj.text_set, set(("baz",)))
|
||||
|
||||
@execute_count(3)
|
||||
def test_set_remove_new_record(self):
|
||||
""" Removing something not in the set should silently do nothing
|
||||
"""
|
||||
@@ -178,6 +184,7 @@ class QueryUpdateTests(BaseCassEngTestCase):
|
||||
obj = TestQueryUpdateModel.objects.get(partition=partition, cluster=cluster)
|
||||
self.assertEqual(obj.text_set, set(("foo",)))
|
||||
|
||||
@execute_count(3)
|
||||
def test_list_append_updates(self):
|
||||
partition = uuid4()
|
||||
cluster = 1
|
||||
@@ -189,6 +196,7 @@ class QueryUpdateTests(BaseCassEngTestCase):
|
||||
obj = TestQueryUpdateModel.objects.get(partition=partition, cluster=cluster)
|
||||
self.assertEqual(obj.text_list, ["foo", "bar"])
|
||||
|
||||
@execute_count(3)
|
||||
def test_list_prepend_updates(self):
|
||||
""" Prepend two things since order is reversed by default by CQL """
|
||||
partition = uuid4()
|
||||
@@ -204,6 +212,7 @@ class QueryUpdateTests(BaseCassEngTestCase):
|
||||
expected = (prepended[::-1] if is_prepend_reversed() else prepended) + original
|
||||
self.assertEqual(obj.text_list, expected)
|
||||
|
||||
@execute_count(3)
|
||||
def test_map_update_updates(self):
|
||||
""" Merge a dictionary into existing value """
|
||||
partition = uuid4()
|
||||
@@ -217,6 +226,7 @@ class QueryUpdateTests(BaseCassEngTestCase):
|
||||
obj = TestQueryUpdateModel.objects.get(partition=partition, cluster=cluster)
|
||||
self.assertEqual(obj.text_map, {"foo": '1', "bar": '3', "baz": '4'})
|
||||
|
||||
@execute_count(3)
|
||||
def test_map_update_none_deletes_key(self):
|
||||
""" The CQL behavior is if you set a key in a map to null it deletes
|
||||
that key from the map. Test that this works with __update.
|
||||
|
||||
Reference in New Issue
Block a user