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