Adding decorator for counting underlying query execution, updating some tests to add expected query counts

This commit is contained in:
GregBestland
2016-04-11 16:49:00 -05:00
parent c7f15a2165
commit 47cb3e9015
7 changed files with 162 additions and 13 deletions

View File

@@ -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

View File

@@ -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:

View File

@@ -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()

View File

@@ -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

View File

@@ -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.

View File

@@ -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())

View File

@@ -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.