http://git-wip-us.apache.org/repos/asf/cassandra-dtest/blob/49b2dda4/thrift_test.py ---------------------------------------------------------------------- diff --git a/thrift_test.py b/thrift_test.py new file mode 100644 index 0000000..23e3f7b --- /dev/null +++ b/thrift_test.py @@ -0,0 +1,2649 @@ +import re +import struct +import time +import uuid +import pytest +import logging + +from thrift.protocol import TBinaryProtocol +from thrift.Thrift import TApplicationException +from thrift.transport import TSocket, TTransport + +from tools.assertions import assert_length_equal +from tools.misc import ImmutableMapping + +from dtest_setup_overrides import DTestSetupOverrides +from dtest import CASSANDRA_VERSION_FROM_BUILD, Tester + +from thrift_bindings.thrift010 import Cassandra +from thrift_bindings.thrift010.Cassandra import (CfDef, Column, ColumnDef, + ColumnOrSuperColumn, ColumnParent, + ColumnPath, ColumnSlice, + ConsistencyLevel, CounterColumn, + Deletion, IndexExpression, + IndexOperator, IndexType, + InvalidRequestException, KeyRange, + KeySlice, KsDef, MultiSliceRequest, + Mutation, NotFoundException, + SlicePredicate, SliceRange, + SuperColumn) +from tools.assertions import (assert_all, assert_none, assert_one) + +since = pytest.mark.since +logger = logging.getLogger(__name__) + + +def get_thrift_client(host='127.0.0.1', port=9160): + socket = TSocket.TSocket(host, port) + transport = TTransport.TFramedTransport(socket) + protocol = TBinaryProtocol.TBinaryProtocol(transport) + client = Cassandra.Client(protocol) + client.transport = transport + return client + + +client = None + +pid_fname = "system_test.pid" + + +def pid(): + return int(open(pid_fname).read()) + + +@since('2.0', max_version='4') +class TestThrift(Tester): + + @pytest.fixture(scope='function', autouse=True) + def fixture_dtest_setup_overrides(self): + dtest_setup_overrides = DTestSetupOverrides() + """ + @jira_ticket CASSANDRA-7653 + """ + dtest_setup_overrides.cluster_options = ImmutableMapping( + {'partitioner': 'org.apache.cassandra.dht.ByteOrderedPartitioner', + 'start_rpc': 'true'}) + return dtest_setup_overrides + + @pytest.fixture(scope='function', autouse=True) + def fixture_set_cluster_settings(self, fixture_dtest_setup): + fixture_dtest_setup.cluster.populate(1) + node1, = fixture_dtest_setup.cluster.nodelist() + + # If vnodes are not used, we must set our own initial_token + # Because ccm will not set a hex token for ByteOrderedPartitioner + # automatically. It does not matter what token we set as we only + # ever use one node. + if not self.dtest_config.use_vnodes: + node1.set_configuration_options(values={'initial_token': "a".encode('hex')}) + + fixture_dtest_setup.cluster.start(wait_for_binary_proto=True) + fixture_dtest_setup.cluster.nodelist()[0].watch_log_for("Listening for thrift clients") # Wait for the thrift port to open + time.sleep(0.1) + # this is ugly, but the whole test module is written against a global client + global client + client = get_thrift_client() + client.transport.open() + self.define_schema() + + yield client + + client.transport.close() + + def define_schema(self): + keyspace1 = Cassandra.KsDef('Keyspace1', 'org.apache.cassandra.locator.SimpleStrategy', {'replication_factor': '1'}, + cf_defs=[ + Cassandra.CfDef('Keyspace1', 'Standard1'), + Cassandra.CfDef('Keyspace1', 'Standard2'), + Cassandra.CfDef('Keyspace1', 'Standard3', column_metadata=[Cassandra.ColumnDef('c1', 'AsciiType'), Cassandra.ColumnDef('c2', 'AsciiType')]), + Cassandra.CfDef('Keyspace1', 'Standard4', column_metadata=[Cassandra.ColumnDef('c1', 'AsciiType')]), + Cassandra.CfDef('Keyspace1', 'StandardLong1', comparator_type='LongType'), + Cassandra.CfDef('Keyspace1', 'StandardInteger1', comparator_type='IntegerType'), + Cassandra.CfDef('Keyspace1', 'StandardComposite', comparator_type='CompositeType(AsciiType, AsciiType)'), + Cassandra.CfDef('Keyspace1', 'Super1', column_type='Super', subcomparator_type='LongType'), + Cassandra.CfDef('Keyspace1', 'Super2', column_type='Super', subcomparator_type='LongType'), + Cassandra.CfDef('Keyspace1', 'Super3', column_type='Super', comparator_type='LongType', subcomparator_type='UTF8Type'), + Cassandra.CfDef('Keyspace1', 'Counter1', default_validation_class='CounterColumnType'), + Cassandra.CfDef('Keyspace1', 'SuperCounter1', column_type='Super', default_validation_class='CounterColumnType'), + Cassandra.CfDef('Keyspace1', 'Indexed1', column_metadata=[Cassandra.ColumnDef('birthdate', 'LongType', Cassandra.IndexType.KEYS, 'birthdate_index')]), + Cassandra.CfDef('Keyspace1', 'Indexed2', comparator_type='TimeUUIDType', column_metadata=[Cassandra.ColumnDef(uuid.UUID('00000000-0000-1000-0000-000000000000').bytes, 'LongType', Cassandra.IndexType.KEYS)]), + Cassandra.CfDef('Keyspace1', 'Indexed3', comparator_type='TimeUUIDType', column_metadata=[Cassandra.ColumnDef(uuid.UUID('00000000-0000-1000-0000-000000000000').bytes, 'UTF8Type', Cassandra.IndexType.KEYS)]), + Cassandra.CfDef('Keyspace1', 'Indexed4', column_metadata=[Cassandra.ColumnDef('a', 'LongType', Cassandra.IndexType.KEYS, 'a_index'), Cassandra.ColumnDef('z', 'UTF8Type')]), + Cassandra.CfDef('Keyspace1', 'Expiring', default_time_to_live=2) + ]) + + keyspace2 = Cassandra.KsDef('Keyspace2', 'org.apache.cassandra.locator.SimpleStrategy', {'replication_factor': '1'}, + cf_defs=[ + Cassandra.CfDef('Keyspace2', 'Standard1'), + Cassandra.CfDef('Keyspace2', 'Standard3'), + Cassandra.CfDef('Keyspace2', 'Super3', column_type='Super', subcomparator_type='BytesType'), + Cassandra.CfDef('Keyspace2', 'Super4', column_type='Super', subcomparator_type='TimeUUIDType'), ]) + + for ks in [keyspace1, keyspace2]: + cls.client.system_add_keyspace(ks) + + +def i64(n): + return _i64(n) + + +def i32(n): + return _i32(n) + + +def i16(n): + return _i16(n) + + +def composite(item1, item2=None, eoc='\x00'): + packed = _i16(len(item1)) + item1 + eoc + if item2 is not None: + packed += _i16(len(item2)) + item2 + packed += eoc + return packed + + +def _i64(n): + return struct.pack('>q', n) # big endian = network order + + +def _i32(n): + return struct.pack('>i', n) # big endian = network order + + +def _i16(n): + return struct.pack('>h', n) # big endian = network order + + +_SIMPLE_COLUMNS = [Column('c1', 'value1', 0), + Column('c2', 'value2', 0)] +_SUPER_COLUMNS = [SuperColumn(name='sc1', columns=[Column(_i64(4), 'value4', 0)]), + SuperColumn(name='sc2', columns=[Column(_i64(5), 'value5', 0), + Column(_i64(6), 'value6', 0)])] + + +def _assert_column(column_family, key, column, value, ts=0): + try: + assert client.get(key, ColumnPath(column_family, column=column), ConsistencyLevel.ONE).column == Column(column, value, ts) + except NotFoundException: + raise Exception('expected %s:%s:%s:%s, but was not present' % (column_family, key, column, value)) + + +def _assert_columnpath_exists(key, column_path): + try: + assert client.get(key, column_path, ConsistencyLevel.ONE) + except NotFoundException: + raise Exception('expected %s with %s but was not present.' % (key, column_path)) + + +def _assert_no_columnpath(key, column_path): + try: + client.get(key, column_path, ConsistencyLevel.ONE) + assert False, ('columnpath %s existed in %s when it should not' % (column_path, key)) + except NotFoundException: + assert True, 'column did not exist' + + +def _insert_simple(): + return _insert_multi(['key1']) + + +def _insert_multi(keys): + CL = ConsistencyLevel.ONE + for key in keys: + client.insert(key, ColumnParent('Standard1'), Column('c1', 'value1', 0), CL) + client.insert(key, ColumnParent('Standard1'), Column('c2', 'value2', 0), CL) + + +def _insert_batch(): + cfmap = {'Standard1': [Mutation(ColumnOrSuperColumn(c)) for c in _SIMPLE_COLUMNS], + 'Standard2': [Mutation(ColumnOrSuperColumn(c)) for c in _SIMPLE_COLUMNS]} + client.batch_mutate({'key1': cfmap}, ConsistencyLevel.ONE) + + +def _big_slice(key, column_parent): + p = SlicePredicate(slice_range=SliceRange('', '', False, 1000)) + return client.get_slice(key, column_parent, p, ConsistencyLevel.ONE) + + +def _big_multislice(keys, column_parent): + p = SlicePredicate(slice_range=SliceRange('', '', False, 1000)) + return client.multiget_slice(keys, column_parent, p, ConsistencyLevel.ONE) + + +def _verify_batch(): + _verify_simple() + L = [result.column + for result in _big_slice('key1', ColumnParent('Standard2'))] + assert L == _SIMPLE_COLUMNS, L + + +def _verify_simple(): + assert client.get('key1', ColumnPath('Standard1', column='c1'), ConsistencyLevel.ONE).column == Column('c1', 'value1', 0) + L = [result.column + for result in _big_slice('key1', ColumnParent('Standard1'))] + assert L == _SIMPLE_COLUMNS, L + + +def _insert_super(key='key1'): + client.insert(key, ColumnParent('Super1', 'sc1'), Column(_i64(4), 'value4', 0), ConsistencyLevel.ONE) + client.insert(key, ColumnParent('Super1', 'sc2'), Column(_i64(5), 'value5', 0), ConsistencyLevel.ONE) + client.insert(key, ColumnParent('Super1', 'sc2'), Column(_i64(6), 'value6', 0), ConsistencyLevel.ONE) + + +def _insert_range(): + client.insert('key1', ColumnParent('Standard1'), Column('c1', 'value1', 0), ConsistencyLevel.ONE) + client.insert('key1', ColumnParent('Standard1'), Column('c2', 'value2', 0), ConsistencyLevel.ONE) + client.insert('key1', ColumnParent('Standard1'), Column('c3', 'value3', 0), ConsistencyLevel.ONE) + + +def _verify_range(): + p = SlicePredicate(slice_range=SliceRange('c1', 'c2', False, 1000)) + result = client.get_slice('key1', ColumnParent('Standard1'), p, ConsistencyLevel.ONE) + assert len(result) == 2 + assert result[0].column.name == 'c1' + assert result[1].column.name == 'c2' + + p = SlicePredicate(slice_range=SliceRange('c3', 'c2', True, 1000)) + result = client.get_slice('key1', ColumnParent('Standard1'), p, ConsistencyLevel.ONE) + assert len(result) == 2 + assert result[0].column.name == 'c3' + assert result[1].column.name == 'c2' + + p = SlicePredicate(slice_range=SliceRange('a', 'z', False, 1000)) + result = client.get_slice('key1', ColumnParent('Standard1'), p, ConsistencyLevel.ONE) + assert len(result) == 3, result + + p = SlicePredicate(slice_range=SliceRange('a', 'z', False, 2)) + result = client.get_slice('key1', ColumnParent('Standard1'), p, ConsistencyLevel.ONE) + assert len(result) == 2, result + + +def _set_keyspace(keyspace): + client.set_keyspace(keyspace) + + +def _insert_super_range(): + client.insert('key1', ColumnParent('Super1', 'sc1'), Column(_i64(4), 'value4', 0), ConsistencyLevel.ONE) + client.insert('key1', ColumnParent('Super1', 'sc2'), Column(_i64(5), 'value5', 0), ConsistencyLevel.ONE) + client.insert('key1', ColumnParent('Super1', 'sc2'), Column(_i64(6), 'value6', 0), ConsistencyLevel.ONE) + client.insert('key1', ColumnParent('Super1', 'sc3'), Column(_i64(7), 'value7', 0), ConsistencyLevel.ONE) + time.sleep(0.1) + + +def _verify_super_range(): + p = SlicePredicate(slice_range=SliceRange('sc2', 'sc3', False, 2)) + result = client.get_slice('key1', ColumnParent('Super1'), p, ConsistencyLevel.ONE) + assert len(result) == 2 + assert result[0].super_column.name == 'sc2' + assert result[1].super_column.name == 'sc3' + + p = SlicePredicate(slice_range=SliceRange('sc3', 'sc2', True, 2)) + result = client.get_slice('key1', ColumnParent('Super1'), p, ConsistencyLevel.ONE) + assert len(result) == 2 + assert result[0].super_column.name == 'sc3' + assert result[1].super_column.name == 'sc2' + + +def _verify_super(supercf='Super1', key='key1'): + assert client.get(key, ColumnPath(supercf, 'sc1', _i64(4)), ConsistencyLevel.ONE).column == Column(_i64(4), 'value4', 0) + slice = [result.super_column + for result in _big_slice(key, ColumnParent('Super1'))] + assert slice == _SUPER_COLUMNS, slice + + +def _expect_exception(fn, type_): + try: + r = fn() + except type_ as t: + return t + else: + raise Exception('expected %s; got %s' % (type_.__name__, r)) + + +def _expect_missing(fn): + _expect_exception(fn, NotFoundException) + + +def get_range_slice(client, parent, predicate, start, end, count, cl, row_filter=None): + kr = KeyRange(start, end, count=count, row_filter=row_filter) + return client.get_range_slices(parent, predicate, kr, cl) + + +def _insert_six_columns(key='abc'): + CL = ConsistencyLevel.ONE + client.insert(key, ColumnParent('Standard1'), Column('a', '1', 0), CL) + client.insert(key, ColumnParent('Standard1'), Column('b', '2', 0), CL) + client.insert(key, ColumnParent('Standard1'), Column('c', '3', 0), CL) + client.insert(key, ColumnParent('Standard1'), Column('d', '4', 0), CL) + client.insert(key, ColumnParent('Standard1'), Column('e', '5', 0), CL) + client.insert(key, ColumnParent('Standard1'), Column('f', '6', 0), CL) + + +def _big_multi_slice(key='abc'): + c1 = ColumnSlice() + c1.start = 'a' + c1.finish = 'c' + c2 = ColumnSlice() + c2.start = 'e' + c2.finish = 'f' + m = MultiSliceRequest() + m.key = key + m.column_parent = ColumnParent('Standard1') + m.column_slices = [c1, c2] + m.reversed = False + m.count = 10 + m.consistency_level = ConsistencyLevel.ONE + return client.get_multi_slice(m) + + +_MULTI_SLICE_COLUMNS = [Column('a', '1', 0), Column('b', '2', 0), Column('c', '3', 0), Column('e', '5', 0), Column('f', '6', 0)] + + +@since('2.0', max_version='4') +class TestMutations(TestThrift): + + def truncate_all(self, *table_names): + for table in table_names: + client.truncate(table) + + def test_insert(self): + _set_keyspace('Keyspace1') + self.truncate_all('Standard1') + _insert_simple() + _verify_simple() + + def test_empty_slice(self): + _set_keyspace('Keyspace1') + self.truncate_all('Standard2', 'Super1') + assert _big_slice('key1', ColumnParent('Standard2')) == [] + assert _big_slice('key1', ColumnParent('Super1')) == [] + + def test_cas(self): + _set_keyspace('Keyspace1') + self.truncate_all('Standard1', 'Standard3', 'Standard4') + + def cas(expected, updates, column_family): + return client.cas('key1', column_family, expected, updates, ConsistencyLevel.SERIAL, ConsistencyLevel.QUORUM) + + def test_cas_operations(first_columns, second_columns, column_family): + # partition should be empty, so cas expecting any existing values should fail + cas_result = cas(first_columns, first_columns, column_family) + assert not cas_result.success + assert len(cas_result.current_values) == 0, cas_result + + # cas of empty columns -> first_columns should succeed + # and the reading back from the table should match first_columns + assert cas([], first_columns, column_family).success + result = [cosc.column for cosc in _big_slice('key1', ColumnParent(column_family))] + # CAS will use its own timestamp, so we can't just compare result == _SIMPLE_COLUMNS + assert dict((c.name, c.value) for c in result) == dict((ex.name, ex.value) for ex in first_columns) + + # now that the partition has been updated, repeating the + # operation which expects it to be empty should not succeed + cas_result = cas([], first_columns, column_family) + assert not cas_result.success + # When we CAS for non-existence, current_values is the first live column of the row + assert dict((c.name, c.value) for c in cas_result.current_values) == {first_columns[0].name: first_columns[0].value}, cas_result + + # CL.SERIAL for reads + assert client.get('key1', ColumnPath(column_family, column=first_columns[0].name), ConsistencyLevel.SERIAL).column.value == first_columns[0].value + + # cas first_columns -> second_columns should succeed + assert cas(first_columns, second_columns, column_family).success + + # as before, an operation with an incorrect expectation should fail + cas_result = cas(first_columns, second_columns, column_family) + assert not cas_result.success + + updated_columns = [Column('c1', 'value101', 1), + Column('c2', 'value102', 1)] + + logger.debug("Testing CAS operations on dynamic cf") + test_cas_operations(_SIMPLE_COLUMNS, updated_columns, 'Standard1') + logger.debug("Testing CAS operations on static cf") + test_cas_operations(_SIMPLE_COLUMNS, updated_columns, 'Standard3') + logger.debug("Testing CAS on mixed static/dynamic cf") + test_cas_operations(_SIMPLE_COLUMNS, updated_columns, 'Standard4') + + def test_missing_super(self): + _set_keyspace('Keyspace1') + self.truncate_all('Super1') + + _expect_missing(lambda: client.get('key1', ColumnPath('Super1', 'sc1', _i64(1)), ConsistencyLevel.ONE)) + _insert_super() + _expect_missing(lambda: client.get('key1', ColumnPath('Super1', 'sc1', _i64(1)), ConsistencyLevel.ONE)) + + def test_count(self): + _set_keyspace('Keyspace1') + self.truncate_all('Standard1', 'Standard2', 'Super1') + + _insert_simple() + _insert_super() + p = SlicePredicate(slice_range=SliceRange('', '', False, 1000)) + assert client.get_count('key1', ColumnParent('Standard2'), p, ConsistencyLevel.ONE) == 0 + assert client.get_count('key1', ColumnParent('Standard1'), p, ConsistencyLevel.ONE) == 2 + assert client.get_count('key1', ColumnParent('Super1', 'sc2'), p, ConsistencyLevel.ONE) == 2 + assert client.get_count('key1', ColumnParent('Super1'), p, ConsistencyLevel.ONE) == 2 + + # Let's make that a little more interesting + client.insert('key1', ColumnParent('Standard1'), Column('c3', 'value3', 0), ConsistencyLevel.ONE) + client.insert('key1', ColumnParent('Standard1'), Column('c4', 'value4', 0), ConsistencyLevel.ONE) + client.insert('key1', ColumnParent('Standard1'), Column('c5', 'value5', 0), ConsistencyLevel.ONE) + + p = SlicePredicate(slice_range=SliceRange('c2', 'c4', False, 1000)) + assert client.get_count('key1', ColumnParent('Standard1'), p, ConsistencyLevel.ONE) == 3 + + def test_count_paging(self): + _set_keyspace('Keyspace1') + self.truncate_all('Standard1') + + _insert_simple() + + # Exercise paging + column_parent = ColumnParent('Standard1') + # Paging for small columns starts at 1024 columns + columns_to_insert = [Column('c%d' % (i,), 'value%d' % (i,), 0) for i in range(3, 1026)] + cfmap = {'Standard1': [Mutation(ColumnOrSuperColumn(c)) for c in columns_to_insert]} + client.batch_mutate({'key1': cfmap}, ConsistencyLevel.ONE) + + p = SlicePredicate(slice_range=SliceRange('', '', False, 2000)) + assert client.get_count('key1', column_parent, p, ConsistencyLevel.ONE) == 1025 + + # Ensure that the count limit isn't clobbered + p = SlicePredicate(slice_range=SliceRange('', '', False, 10)) + assert client.get_count('key1', ColumnParent('Standard1'), p, ConsistencyLevel.ONE) == 10 + + # test get_count() to work correctly with 'count' settings around page size (CASSANDRA-4833) + def test_count_around_page_size(self): + _set_keyspace('Keyspace1') + self.truncate_all('Standard1') + + def slice_predicate(count): + return SlicePredicate(slice_range=SliceRange('', '', False, count)) + + key = 'key1' + parent = ColumnParent('Standard1') + cl = ConsistencyLevel.ONE + + for i in range(0, 3050): + client.insert(key, parent, Column(str(i), '', 0), cl) + + # same as page size + assert client.get_count(key, parent, slice_predicate(1024), cl) == 1024 + + # 1 above page size + assert client.get_count(key, parent, slice_predicate(1025), cl) == 1025 + + # above number or columns + assert client.get_count(key, parent, slice_predicate(4000), cl) == 3050 + + # same as number of columns + assert client.get_count(key, parent, slice_predicate(3050), cl) == 3050 + + # 1 above number of columns + assert client.get_count(key, parent, slice_predicate(3051), cl) == 3050 + + def test_super_insert(self): + _set_keyspace('Keyspace1') + self.truncate_all('Super1') + + _insert_super() + _verify_super() + + def test_super_get(self): + _set_keyspace('Keyspace1') + self.truncate_all('Super1') + + _insert_super() + result = client.get('key1', ColumnPath('Super1', 'sc2'), ConsistencyLevel.ONE).super_column + assert result == _SUPER_COLUMNS[1], result + + def test_super_subcolumn_limit(self): + _set_keyspace('Keyspace1') + self.truncate_all('Super1') + _insert_super() + p = SlicePredicate(slice_range=SliceRange('', '', False, 1)) + column_parent = ColumnParent('Super1', 'sc2') + slice = [result.column + for result in client.get_slice('key1', column_parent, p, ConsistencyLevel.ONE)] + assert slice == [Column(_i64(5), 'value5', 0)], slice + p = SlicePredicate(slice_range=SliceRange('', '', True, 1)) + slice = [result.column + for result in client.get_slice('key1', column_parent, p, ConsistencyLevel.ONE)] + assert slice == [Column(_i64(6), 'value6', 0)], slice + + def test_long_order(self): + _set_keyspace('Keyspace1') + self.truncate_all('StandardLong1') + + def long_xrange(start, stop, step): + i = start + while i < stop: + yield i + i += step + L = [] + for i in long_xrange(0, 104294967296, 429496729): + name = _i64(i) + client.insert('key1', ColumnParent('StandardLong1'), Column(name, 'v', 0), ConsistencyLevel.ONE) + L.append(name) + slice = [result.column.name for result in _big_slice('key1', ColumnParent('StandardLong1'))] + assert slice == L, slice + + def test_integer_order(self): + _set_keyspace('Keyspace1') + self.truncate_all('StandardInteger1') + + def long_xrange(start, stop, step): + i = start + while i >= stop: + yield i + i -= step + L = [] + for i in long_xrange(104294967296, 0, 429496729): + name = _i64(i) + client.insert('key1', ColumnParent('StandardInteger1'), Column(name, 'v', 0), ConsistencyLevel.ONE) + L.append(name) + slice = [result.column.name for result in _big_slice('key1', ColumnParent('StandardInteger1'))] + L.sort() + assert slice == L, slice + + def test_time_uuid(self): + _set_keyspace('Keyspace2') + self.truncate_all('Super4') + + import uuid + L = [] + + # 100 isn't enough to fail reliably if the comparator is borked + for i in range(500): + L.append(uuid.uuid1()) + client.insert('key1', ColumnParent('Super4', 'sc1'), Column(L[-1].bytes, 'value%s' % i, i), ConsistencyLevel.ONE) + slice = _big_slice('key1', ColumnParent('Super4', 'sc1')) + assert len(slice) == 500, len(slice) + for i in range(500): + u = slice[i].column + assert u.value == 'value%s' % i + assert u.name == L[i].bytes + + p = SlicePredicate(slice_range=SliceRange('', '', True, 1)) + column_parent = ColumnParent('Super4', 'sc1') + slice = [result.column + for result in client.get_slice('key1', column_parent, p, ConsistencyLevel.ONE)] + assert slice == [Column(L[-1].bytes, 'value499', 499)], slice + + p = SlicePredicate(slice_range=SliceRange('', L[2].bytes, False, 1000)) + column_parent = ColumnParent('Super4', 'sc1') + slice = [result.column + for result in client.get_slice('key1', column_parent, p, ConsistencyLevel.ONE)] + assert slice == [Column(L[0].bytes, 'value0', 0), + Column(L[1].bytes, 'value1', 1), + Column(L[2].bytes, 'value2', 2)], slice + + p = SlicePredicate(slice_range=SliceRange(L[2].bytes, '', True, 1000)) + column_parent = ColumnParent('Super4', 'sc1') + slice = [result.column + for result in client.get_slice('key1', column_parent, p, ConsistencyLevel.ONE)] + assert slice == [Column(L[2].bytes, 'value2', 2), + Column(L[1].bytes, 'value1', 1), + Column(L[0].bytes, 'value0', 0)], slice + + p = SlicePredicate(slice_range=SliceRange(L[2].bytes, '', False, 1)) + column_parent = ColumnParent('Super4', 'sc1') + slice = [result.column + for result in client.get_slice('key1', column_parent, p, ConsistencyLevel.ONE)] + assert slice == [Column(L[2].bytes, 'value2', 2)], slice + + def test_long_remove(self): + _set_keyspace('Keyspace1') + self.truncate_all('StandardLong1') + + column_parent = ColumnParent('StandardLong1') + sp = SlicePredicate(slice_range=SliceRange('', '', False, 1)) + for i in range(10): + parent = ColumnParent('StandardLong1') + + client.insert('key1', parent, Column(_i64(i), 'value1', 10 * i), ConsistencyLevel.ONE) + client.remove('key1', ColumnPath('StandardLong1'), 10 * i + 1, ConsistencyLevel.ONE) + slice = client.get_slice('key1', column_parent, sp, ConsistencyLevel.ONE) + assert slice == [], slice + # resurrect + client.insert('key1', parent, Column(_i64(i), 'value2', 10 * i + 2), ConsistencyLevel.ONE) + slice = [result.column + for result in client.get_slice('key1', column_parent, sp, ConsistencyLevel.ONE)] + assert slice == [Column(_i64(i), 'value2', 10 * i + 2)], (slice, i) + + def test_integer_remove(self): + _set_keyspace('Keyspace1') + self.truncate_all('StandardInteger1') + + column_parent = ColumnParent('StandardInteger1') + sp = SlicePredicate(slice_range=SliceRange('', '', False, 1)) + for i in range(10): + parent = ColumnParent('StandardInteger1') + + client.insert('key1', parent, Column(_i64(i), 'value1', 10 * i), ConsistencyLevel.ONE) + client.remove('key1', ColumnPath('StandardInteger1'), 10 * i + 1, ConsistencyLevel.ONE) + slice = client.get_slice('key1', column_parent, sp, ConsistencyLevel.ONE) + assert slice == [], slice + # resurrect + client.insert('key1', parent, Column(_i64(i), 'value2', 10 * i + 2), ConsistencyLevel.ONE) + slice = [result.column + for result in client.get_slice('key1', column_parent, sp, ConsistencyLevel.ONE)] + assert slice == [Column(_i64(i), 'value2', 10 * i + 2)], (slice, i) + + def test_batch_insert(self): + _set_keyspace('Keyspace1') + self.truncate_all('Standard1', 'Standard2') + _insert_batch() + _verify_batch() + + def test_batch_mutate_standard_columns(self): + _set_keyspace('Keyspace1') + self.truncate_all('Standard1', 'Standard2') + + column_families = ['Standard1', 'Standard2'] + keys = ['key_%d' % i for i in range(27, 32)] + mutations = [Mutation(ColumnOrSuperColumn(c)) for c in _SIMPLE_COLUMNS] + mutation_map = dict((column_family, mutations) for column_family in column_families) + keyed_mutations = dict((key, mutation_map) for key in keys) + + client.batch_mutate(keyed_mutations, ConsistencyLevel.ONE) + + for column_family in column_families: + for key in keys: + _assert_column(column_family, key, 'c1', 'value1') + + def test_batch_mutate_remove_standard_columns(self): + _set_keyspace('Keyspace1') + self.truncate_all('Standard1', 'Standard2') + + column_families = ['Standard1', 'Standard2'] + keys = ['key_%d' % i for i in range(11, 21)] + _insert_multi(keys) + + mutations = [Mutation(deletion=Deletion(20, predicate=SlicePredicate(column_names=[c.name]))) for c in _SIMPLE_COLUMNS] + mutation_map = dict((column_family, mutations) for column_family in column_families) + + keyed_mutations = dict((key, mutation_map) for key in keys) + + client.batch_mutate(keyed_mutations, ConsistencyLevel.ONE) + + for column_family in column_families: + for c in _SIMPLE_COLUMNS: + for key in keys: + _assert_no_columnpath(key, ColumnPath(column_family, column=c.name)) + + def test_batch_mutate_remove_standard_row(self): + _set_keyspace('Keyspace1') + self.truncate_all('Standard1', 'Standard2') + + column_families = ['Standard1', 'Standard2'] + keys = ['key_%d' % i for i in range(11, 21)] + _insert_multi(keys) + + mutations = [Mutation(deletion=Deletion(20))] + mutation_map = dict((column_family, mutations) for column_family in column_families) + + keyed_mutations = dict((key, mutation_map) for key in keys) + + client.batch_mutate(keyed_mutations, ConsistencyLevel.ONE) + + for column_family in column_families: + for c in _SIMPLE_COLUMNS: + for key in keys: + _assert_no_columnpath(key, ColumnPath(column_family, column=c.name)) + + def test_batch_mutate_remove_super_columns_with_standard_under(self): + _set_keyspace('Keyspace1') + self.truncate_all('Super1', 'Super2') + + column_families = ['Super1', 'Super2'] + keys = ['key_%d' % i for i in range(11, 21)] + _insert_super() + + mutations = [] + for sc in _SUPER_COLUMNS: + names = [] + for c in sc.columns: + names.append(c.name) + mutations.append(Mutation(deletion=Deletion(20, super_column=c.name, predicate=SlicePredicate(column_names=names)))) + + mutation_map = dict((column_family, mutations) for column_family in column_families) + + keyed_mutations = dict((key, mutation_map) for key in keys) + + client.batch_mutate(keyed_mutations, ConsistencyLevel.ONE) + for column_family in column_families: + for sc in _SUPER_COLUMNS: + for c in sc.columns: + for key in keys: + _assert_no_columnpath(key, ColumnPath(column_family, super_column=sc.name, column=c.name)) + + def test_batch_mutate_remove_super_columns_with_none_given_underneath(self): + _set_keyspace('Keyspace1') + self.truncate_all('Super1') + + keys = ['key_%d' % i for i in range(17, 21)] + + for key in keys: + _insert_super(key) + + mutations = [] + + for sc in _SUPER_COLUMNS: + mutations.append(Mutation(deletion=Deletion(20, + super_column=sc.name))) + + mutation_map = {'Super1': mutations} + + keyed_mutations = dict((key, mutation_map) for key in keys) + + # Sanity check + for sc in _SUPER_COLUMNS: + for key in keys: + _assert_columnpath_exists(key, ColumnPath('Super1', super_column=sc.name)) + + client.batch_mutate(keyed_mutations, ConsistencyLevel.ONE) + + for sc in _SUPER_COLUMNS: + for c in sc.columns: + for key in keys: + _assert_no_columnpath(key, ColumnPath('Super1', super_column=sc.name)) + + def test_batch_mutate_remove_super_columns_entire_row(self): + _set_keyspace('Keyspace1') + self.truncate_all('Super1') + + keys = ['key_%d' % i for i in range(17, 21)] + + for key in keys: + _insert_super(key) + + mutations = [] + + mutations.append(Mutation(deletion=Deletion(20))) + + mutation_map = {'Super1': mutations} + + keyed_mutations = dict((key, mutation_map) for key in keys) + + # Sanity check + for sc in _SUPER_COLUMNS: + for key in keys: + _assert_columnpath_exists(key, ColumnPath('Super1', super_column=sc.name)) + + client.batch_mutate(keyed_mutations, ConsistencyLevel.ONE) + + for sc in _SUPER_COLUMNS: + for key in keys: + _assert_no_columnpath(key, ColumnPath('Super1', super_column=sc.name)) + + # known failure: see CASSANDRA-10046 + def test_batch_mutate_remove_slice_standard(self): + _set_keyspace('Keyspace1') + self.truncate_all('Standard1') + + columns = [Column('c1', 'value1', 0), + Column('c2', 'value2', 0), + Column('c3', 'value3', 0), + Column('c4', 'value4', 0), + Column('c5', 'value5', 0)] + + for column in columns: + client.insert('key', ColumnParent('Standard1'), column, ConsistencyLevel.ONE) + + d = Deletion(1, predicate=SlicePredicate(slice_range=SliceRange(start='c2', finish='c4'))) + client.batch_mutate({'key': {'Standard1': [Mutation(deletion=d)]}}, ConsistencyLevel.ONE) + + _assert_columnpath_exists('key', ColumnPath('Standard1', column='c1')) + _assert_no_columnpath('key', ColumnPath('Standard1', column='c2')) + _assert_no_columnpath('key', ColumnPath('Standard1', column='c3')) + _assert_no_columnpath('key', ColumnPath('Standard1', column='c4')) + _assert_columnpath_exists('key', ColumnPath('Standard1', column='c5')) + + # known failure: see CASSANDRA-10046 + def test_batch_mutate_remove_slice_of_entire_supercolumns(self): + _set_keyspace('Keyspace1') + self.truncate_all('Super1') + + columns = [SuperColumn(name='sc1', columns=[Column(_i64(1), 'value1', 0)]), + SuperColumn(name='sc2', + columns=[Column(_i64(2), 'value2', 0), Column(_i64(3), 'value3', 0)]), + SuperColumn(name='sc3', columns=[Column(_i64(4), 'value4', 0)]), + SuperColumn(name='sc4', + columns=[Column(_i64(5), 'value5', 0), Column(_i64(6), 'value6', 0)]), + SuperColumn(name='sc5', columns=[Column(_i64(7), 'value7', 0)])] + + for column in columns: + for subcolumn in column.columns: + client.insert('key', ColumnParent('Super1', column.name), subcolumn, ConsistencyLevel.ONE) + + d = Deletion(1, predicate=SlicePredicate(slice_range=SliceRange(start='sc2', finish='sc4'))) + client.batch_mutate({'key': {'Super1': [Mutation(deletion=d)]}}, ConsistencyLevel.ONE) + + _assert_columnpath_exists('key', ColumnPath('Super1', super_column='sc1', column=_i64(1))) + _assert_no_columnpath('key', ColumnPath('Super1', super_column='sc2', column=_i64(2))) + _assert_no_columnpath('key', ColumnPath('Super1', super_column='sc2', column=_i64(3))) + _assert_no_columnpath('key', ColumnPath('Super1', super_column='sc3', column=_i64(4))) + _assert_no_columnpath('key', ColumnPath('Super1', super_column='sc4', column=_i64(5))) + _assert_no_columnpath('key', ColumnPath('Super1', super_column='sc4', column=_i64(6))) + _assert_columnpath_exists('key', ColumnPath('Super1', super_column='sc5', column=_i64(7))) + + @since('1.0', '2.2') + def test_batch_mutate_remove_slice_part_of_supercolumns(self): + _set_keyspace('Keyspace1') + self.truncate_all('Super1') + + columns = [Column(_i64(1), 'value1', 0), + Column(_i64(2), 'value2', 0), + Column(_i64(3), 'value3', 0), + Column(_i64(4), 'value4', 0), + Column(_i64(5), 'value5', 0)] + + for column in columns: + client.insert('key', ColumnParent('Super1', 'sc1'), column, ConsistencyLevel.ONE) + + r = SliceRange(start=_i64(2), finish=_i64(4)) + d = Deletion(1, super_column='sc1', predicate=SlicePredicate(slice_range=r)) + client.batch_mutate({'key': {'Super1': [Mutation(deletion=d)]}}, ConsistencyLevel.ONE) + + _assert_columnpath_exists('key', ColumnPath('Super1', super_column='sc1', column=_i64(1))) + _assert_no_columnpath('key', ColumnPath('Super1', super_column='sc1', column=_i64(2))) + _assert_no_columnpath('key', ColumnPath('Super1', super_column='sc1', column=_i64(3))) + _assert_no_columnpath('key', ColumnPath('Super1', super_column='sc1', column=_i64(4))) + _assert_columnpath_exists('key', ColumnPath('Super1', super_column='sc1', column=_i64(5))) + + def test_batch_mutate_insertions_and_deletions(self): + _set_keyspace('Keyspace1') + self.truncate_all('Super1', 'Super2') + + first_insert = SuperColumn("sc1", + columns=[Column(_i64(20), 'value20', 3), + Column(_i64(21), 'value21', 3)]) + second_insert = SuperColumn("sc1", + columns=[Column(_i64(20), 'value20', 3), + Column(_i64(21), 'value21', 3)]) + first_deletion = {'super_column': "sc1", + 'predicate': SlicePredicate(column_names=[_i64(22), _i64(23)])} + second_deletion = {'super_column': "sc2", + 'predicate': SlicePredicate(column_names=[_i64(22), _i64(23)])} + + keys = ['key_30', 'key_31'] + for key in keys: + sc = SuperColumn('sc1', [Column(_i64(22), 'value22', 0), + Column(_i64(23), 'value23', 0)]) + cfmap = {'Super1': [Mutation(ColumnOrSuperColumn(super_column=sc))]} + client.batch_mutate({key: cfmap}, ConsistencyLevel.ONE) + + sc2 = SuperColumn('sc2', [Column(_i64(22), 'value22', 0), + Column(_i64(23), 'value23', 0)]) + cfmap2 = {'Super2': [Mutation(ColumnOrSuperColumn(super_column=sc2))]} + client.batch_mutate({key: cfmap2}, ConsistencyLevel.ONE) + + cfmap3 = { + 'Super1': [Mutation(ColumnOrSuperColumn(super_column=first_insert)), + Mutation(deletion=Deletion(3, **first_deletion))], + + 'Super2': [Mutation(deletion=Deletion(2, **second_deletion)), + Mutation(ColumnOrSuperColumn(super_column=second_insert))] + } + + keyed_mutations = dict((key, cfmap3) for key in keys) + client.batch_mutate(keyed_mutations, ConsistencyLevel.ONE) + + for key in keys: + for c in [_i64(22), _i64(23)]: + _assert_no_columnpath(key, ColumnPath('Super1', super_column='sc1', column=c)) + _assert_no_columnpath(key, ColumnPath('Super2', super_column='sc2', column=c)) + + for c in [_i64(20), _i64(21)]: + _assert_columnpath_exists(key, ColumnPath('Super1', super_column='sc1', column=c)) + _assert_columnpath_exists(key, ColumnPath('Super2', super_column='sc1', column=c)) + + def test_bad_system_calls(self): + def duplicate_index_names(): + _set_keyspace('Keyspace1') + cd1 = ColumnDef('foo', 'BytesType', IndexType.KEYS, 'i') + cd2 = ColumnDef('bar', 'BytesType', IndexType.KEYS, 'i') + cf = CfDef('Keyspace1', 'BadCF', column_metadata=[cd1, cd2]) + client.system_add_column_family(cf) + _expect_exception(duplicate_index_names, InvalidRequestException) + + def test_bad_batch_calls(self): + # mutate_does_not_accept_cosc_and_deletion_in_same_mutation + def too_full(): + _set_keyspace('Keyspace1') + col = ColumnOrSuperColumn(column=Column("foo", 'bar', 0)) + dele = Deletion(2, predicate=SlicePredicate(column_names=['baz'])) + client.batch_mutate({'key_34': {'Standard1': [Mutation(col, dele)]}}, + ConsistencyLevel.ONE) + _expect_exception(too_full, InvalidRequestException) + + # test_batch_mutate_does_not_accept_cosc_on_undefined_cf: + def bad_cf(): + _set_keyspace('Keyspace1') + col = ColumnOrSuperColumn(column=Column("foo", 'bar', 0)) + client.batch_mutate({'key_36': {'Undefined': [Mutation(col)]}}, + ConsistencyLevel.ONE) + _expect_exception(bad_cf, InvalidRequestException) + + # test_batch_mutate_does_not_accept_deletion_on_undefined_cf + def bad_cf_2(): + _set_keyspace('Keyspace1') + d = Deletion(2, predicate=SlicePredicate(column_names=['baz'])) + client.batch_mutate({'key_37': {'Undefined': [Mutation(deletion=d)]}}, + ConsistencyLevel.ONE) + _expect_exception(bad_cf_2, InvalidRequestException) + + # a column value that does not match the declared validator + def send_string_instead_of_long(): + _set_keyspace('Keyspace1') + col = ColumnOrSuperColumn(column=Column('birthdate', 'bar', 0)) + client.batch_mutate({'key_38': {'Indexed1': [Mutation(col)]}}, + ConsistencyLevel.ONE) + _expect_exception(send_string_instead_of_long, InvalidRequestException) + + def test_column_name_lengths(self): + _set_keyspace('Keyspace1') + self.truncate_all('Standard1') + + _expect_exception(lambda: client.insert('key1', ColumnParent('Standard1'), Column('', 'value', 0), ConsistencyLevel.ONE), InvalidRequestException) + client.insert('key1', ColumnParent('Standard1'), Column('x' * 1, 'value', 0), ConsistencyLevel.ONE) + client.insert('key1', ColumnParent('Standard1'), Column('x' * 127, 'value', 0), ConsistencyLevel.ONE) + client.insert('key1', ColumnParent('Standard1'), Column('x' * 128, 'value', 0), ConsistencyLevel.ONE) + client.insert('key1', ColumnParent('Standard1'), Column('x' * 129, 'value', 0), ConsistencyLevel.ONE) + client.insert('key1', ColumnParent('Standard1'), Column('x' * 255, 'value', 0), ConsistencyLevel.ONE) + client.insert('key1', ColumnParent('Standard1'), Column('x' * 256, 'value', 0), ConsistencyLevel.ONE) + client.insert('key1', ColumnParent('Standard1'), Column('x' * 257, 'value', 0), ConsistencyLevel.ONE) + client.insert('key1', ColumnParent('Standard1'), Column('x' * (2 ** 16 - 1), 'value', 0), ConsistencyLevel.ONE) + _expect_exception(lambda: client.insert('key1', ColumnParent('Standard1'), Column('x' * (2 ** 16), 'value', 0), ConsistencyLevel.ONE), InvalidRequestException) + + def test_bad_calls(self): + _set_keyspace('Keyspace1') + + # missing arguments + _expect_exception(lambda: client.insert(None, None, None, None), TApplicationException) + # supercolumn in a non-super CF + _expect_exception(lambda: client.insert('key1', ColumnParent('Standard1', 'x'), Column('y', 'value', 0), ConsistencyLevel.ONE), InvalidRequestException) + # no supercolumn in a super CF + _expect_exception(lambda: client.insert('key1', ColumnParent('Super1'), Column('y', 'value', 0), ConsistencyLevel.ONE), InvalidRequestException) + # column but no supercolumn in remove + _expect_exception(lambda: client.remove('key1', ColumnPath('Super1', column='x'), 0, ConsistencyLevel.ONE), InvalidRequestException) + # super column in non-super CF + _expect_exception(lambda: client.remove('key1', ColumnPath('Standard1', 'y', 'x'), 0, ConsistencyLevel.ONE), InvalidRequestException) + # key too long + _expect_exception(lambda: client.get('x' * 2 ** 16, ColumnPath('Standard1', column='c1'), ConsistencyLevel.ONE), InvalidRequestException) + # empty key + _expect_exception(lambda: client.get('', ColumnPath('Standard1', column='c1'), ConsistencyLevel.ONE), InvalidRequestException) + cfmap = {'Super1': [Mutation(ColumnOrSuperColumn(super_column=c)) for c in _SUPER_COLUMNS], + 'Super2': [Mutation(ColumnOrSuperColumn(super_column=c)) for c in _SUPER_COLUMNS]} + _expect_exception(lambda: client.batch_mutate({'': cfmap}, ConsistencyLevel.ONE), InvalidRequestException) + # empty column name + _expect_exception(lambda: client.get('key1', ColumnPath('Standard1', column=''), ConsistencyLevel.ONE), InvalidRequestException) + # get doesn't specify column name + _expect_exception(lambda: client.get('key1', ColumnPath('Standard1'), ConsistencyLevel.ONE), InvalidRequestException) + # supercolumn in a non-super CF + _expect_exception(lambda: client.get('key1', ColumnPath('Standard1', 'x', 'y'), ConsistencyLevel.ONE), InvalidRequestException) + # get doesn't specify supercolumn name + _expect_exception(lambda: client.get('key1', ColumnPath('Super1'), ConsistencyLevel.ONE), InvalidRequestException) + # invalid CF + _expect_exception(lambda: get_range_slice(client, ColumnParent('S'), SlicePredicate(column_names=['', '']), '', '', 5, ConsistencyLevel.ONE), InvalidRequestException) + # 'x' is not a valid Long + _expect_exception(lambda: client.insert('key1', ColumnParent('Super1', 'sc1'), Column('x', 'value', 0), ConsistencyLevel.ONE), InvalidRequestException) + # start is not a valid Long + p = SlicePredicate(slice_range=SliceRange('x', '', False, 1)) + column_parent = ColumnParent('StandardLong1') + _expect_exception(lambda: client.get_slice('key1', column_parent, p, ConsistencyLevel.ONE), + InvalidRequestException) + # start > finish + p = SlicePredicate(slice_range=SliceRange(_i64(10), _i64(0), False, 1)) + column_parent = ColumnParent('StandardLong1') + _expect_exception(lambda: client.get_slice('key1', column_parent, p, ConsistencyLevel.ONE), + InvalidRequestException) + # start is not a valid Long, supercolumn version + p = SlicePredicate(slice_range=SliceRange('x', '', False, 1)) + column_parent = ColumnParent('Super1', 'sc1') + _expect_exception(lambda: client.get_slice('key1', column_parent, p, ConsistencyLevel.ONE), + InvalidRequestException) + # start > finish, supercolumn version + p = SlicePredicate(slice_range=SliceRange(_i64(10), _i64(0), False, 1)) + column_parent = ColumnParent('Super1', 'sc1') + _expect_exception(lambda: client.get_slice('key1', column_parent, p, ConsistencyLevel.ONE), + InvalidRequestException) + # start > finish, key version + _expect_exception(lambda: get_range_slice(client, ColumnParent('Standard1'), SlicePredicate(column_names=['']), 'z', 'a', 1, ConsistencyLevel.ONE), InvalidRequestException) + # ttl must be greater or equals to zero + column = Column('cttl1', 'value1', 0, -1) + _expect_exception(lambda: client.insert('key1', ColumnParent('Standard1'), column, ConsistencyLevel.ONE), + InvalidRequestException) + # don't allow super_column in Deletion for standard Columntest_expiration_with_default_ttl_and_zero_ttl + deletion = Deletion(1, 'supercolumn', None) + mutation = Mutation(deletion=deletion) + mutations = {'key': {'Standard1': [mutation]}} + _expect_exception(lambda: client.batch_mutate(mutations, ConsistencyLevel.QUORUM), + InvalidRequestException) + # 'x' is not a valid long + deletion = Deletion(1, 'x', None) + mutation = Mutation(deletion=deletion) + mutations = {'key': {'Super3': [mutation]}} + _expect_exception(lambda: client.batch_mutate(mutations, ConsistencyLevel.QUORUM), InvalidRequestException) + # counters don't support ANY + _expect_exception(lambda: client.add('key1', ColumnParent('Counter1', 'x'), CounterColumn('y', 1), ConsistencyLevel.ANY), InvalidRequestException) + + def test_batch_insert_super(self): + _set_keyspace('Keyspace1') + self.truncate_all('Super1', 'Super2') + + cfmap = {'Super1': [Mutation(ColumnOrSuperColumn(super_column=c)) + for c in _SUPER_COLUMNS], + 'Super2': [Mutation(ColumnOrSuperColumn(super_column=c)) + for c in _SUPER_COLUMNS]} + client.batch_mutate({'key1': cfmap}, ConsistencyLevel.ONE) + _verify_super('Super1') + _verify_super('Super2') + + def test_cf_remove_column(self): + _set_keyspace('Keyspace1') + self.truncate_all('Standard1') + + _insert_simple() + client.remove('key1', ColumnPath('Standard1', column='c1'), 1, ConsistencyLevel.ONE) + _expect_missing(lambda: client.get('key1', ColumnPath('Standard1', column='c1'), ConsistencyLevel.ONE)) + assert client.get('key1', ColumnPath('Standard1', column='c2'), ConsistencyLevel.ONE).column \ + == Column('c2', 'value2', 0) + assert _big_slice('key1', ColumnParent('Standard1')) \ + == [ColumnOrSuperColumn(column=Column('c2', 'value2', 0))] + + # New insert, make sure it shows up post-remove: + client.insert('key1', ColumnParent('Standard1'), Column('c3', 'value3', 0), ConsistencyLevel.ONE) + columns = [result.column + for result in _big_slice('key1', ColumnParent('Standard1'))] + assert columns == [Column('c2', 'value2', 0), Column('c3', 'value3', 0)], columns + + # Test resurrection. First, re-insert the value w/ older timestamp, + # and make sure it stays removed + client.insert('key1', ColumnParent('Standard1'), Column('c1', 'value1', 0), ConsistencyLevel.ONE) + columns = [result.column + for result in _big_slice('key1', ColumnParent('Standard1'))] + assert columns == [Column('c2', 'value2', 0), Column('c3', 'value3', 0)], columns + # Next, w/ a newer timestamp; it should come back: + client.insert('key1', ColumnParent('Standard1'), Column('c1', 'value1', 2), ConsistencyLevel.ONE) + columns = [result.column + for result in _big_slice('key1', ColumnParent('Standard1'))] + assert columns == [Column('c1', 'value1', 2), Column('c2', 'value2', 0), Column('c3', 'value3', 0)], columns + + def test_cf_remove(self): + _set_keyspace('Keyspace1') + self.truncate_all('Standard1', 'Super1') + + _insert_simple() + _insert_super() + + # Remove the key1:Standard1 cf; verify super is unaffected + client.remove('key1', ColumnPath('Standard1'), 3, ConsistencyLevel.ONE) + assert _big_slice('key1', ColumnParent('Standard1')) == [] + _verify_super() + + # Test resurrection. First, re-insert a value w/ older timestamp, + # and make sure it stays removed: + client.insert('key1', ColumnParent('Standard1'), Column('c1', 'value1', 0), ConsistencyLevel.ONE) + assert _big_slice('key1', ColumnParent('Standard1')) == [] + # Next, w/ a newer timestamp; it should come back: + client.insert('key1', ColumnParent('Standard1'), Column('c1', 'value1', 4), ConsistencyLevel.ONE) + result = _big_slice('key1', ColumnParent('Standard1')) + assert result == [ColumnOrSuperColumn(column=Column('c1', 'value1', 4))], result + + # check removing the entire super cf, too. + client.remove('key1', ColumnPath('Super1'), 3, ConsistencyLevel.ONE) + assert _big_slice('key1', ColumnParent('Super1')) == [] + assert _big_slice('key1', ColumnParent('Super1', 'sc1')) == [] + + def test_super_cf_remove_and_range_slice(self): + _set_keyspace('Keyspace1') + self.truncate_all('Super1') + + client.insert('key3', ColumnParent('Super1', 'sc1'), Column(_i64(1), 'v1', 0), ConsistencyLevel.ONE) + client.remove('key3', ColumnPath('Super1', 'sc1'), 5, ConsistencyLevel.ONE) + + rows = {} + for row in get_range_slice(client, ColumnParent('Super1'), SlicePredicate(slice_range=SliceRange('', '', False, 1000)), '', '', 1000, ConsistencyLevel.ONE): + scs = [cosc.super_column for cosc in row.columns] + rows[row.key] = scs + assert rows == {'key3': []}, rows + + def test_super_cf_remove_column(self): + _set_keyspace('Keyspace1') + self.truncate_all('Standard1', 'Super1') + + _insert_simple() + _insert_super() + + # Make sure remove clears out what it's supposed to, and _only_ that: + client.remove('key1', ColumnPath('Super1', 'sc2', _i64(5)), 5, ConsistencyLevel.ONE) + _expect_missing(lambda: client.get('key1', ColumnPath('Super1', 'sc2', _i64(5)), ConsistencyLevel.ONE)) + super_columns = [result.super_column for result in _big_slice('key1', ColumnParent('Super1'))] + assert super_columns == [SuperColumn(name='sc1', columns=[Column(_i64(4), 'value4', 0)]), + SuperColumn(name='sc2', columns=[Column(_i64(6), 'value6', 0)])] + _verify_simple() + + # New insert, make sure it shows up post-remove: + client.insert('key1', ColumnParent('Super1', 'sc2'), Column(_i64(7), 'value7', 0), ConsistencyLevel.ONE) + super_columns_expected = [SuperColumn(name='sc1', + columns=[Column(_i64(4), 'value4', 0)]), + SuperColumn(name='sc2', + columns=[Column(_i64(6), 'value6', 0), Column(_i64(7), 'value7', 0)])] + + super_columns = [result.super_column for result in _big_slice('key1', ColumnParent('Super1'))] + assert super_columns == super_columns_expected, super_columns + + # Test resurrection. First, re-insert the value w/ older timestamp, + # and make sure it stays removed: + client.insert('key1', ColumnParent('Super1', 'sc2'), Column(_i64(5), 'value5', 0), ConsistencyLevel.ONE) + + super_columns = [result.super_column for result in _big_slice('key1', ColumnParent('Super1'))] + assert super_columns == super_columns_expected, super_columns + + # Next, w/ a newer timestamp; it should come back + client.insert('key1', ColumnParent('Super1', 'sc2'), Column(_i64(5), 'value5', 6), ConsistencyLevel.ONE) + super_columns = [result.super_column for result in _big_slice('key1', ColumnParent('Super1'))] + super_columns_expected = [SuperColumn(name='sc1', columns=[Column(_i64(4), 'value4', 0)]), + SuperColumn(name='sc2', columns=[Column(_i64(5), 'value5', 6), + Column(_i64(6), 'value6', 0), + Column(_i64(7), 'value7', 0)])] + assert super_columns == super_columns_expected, super_columns + + # shouldn't be able to specify a column w/o a super column for remove + cp = ColumnPath(column_family='Super1', column='sc2') + e = _expect_exception(lambda: client.remove('key1', cp, 5, ConsistencyLevel.ONE), InvalidRequestException) + assert e.why.find("column cannot be specified without") >= 0 + + def test_super_cf_remove_supercolumn(self): + _set_keyspace('Keyspace1') + self.truncate_all('Standard1', 'Super1') + + _insert_simple() + _insert_super() + + # Make sure remove clears out what it's supposed to, and _only_ that: + client.remove('key1', ColumnPath('Super1', 'sc2'), 5, ConsistencyLevel.ONE) + _expect_missing(lambda: client.get('key1', ColumnPath('Super1', 'sc2', _i64(5)), ConsistencyLevel.ONE)) + super_columns = _big_slice('key1', ColumnParent('Super1', 'sc2')) + assert super_columns == [], super_columns + super_columns_expected = [SuperColumn(name='sc1', columns=[Column(_i64(4), 'value4', 0)])] + super_columns = [result.super_column + for result in _big_slice('key1', ColumnParent('Super1'))] + assert super_columns == super_columns_expected, super_columns + _verify_simple() + + # Test resurrection. First, re-insert the value w/ older timestamp, + # and make sure it stays removed: + client.insert('key1', ColumnParent('Super1', 'sc2'), Column(_i64(5), 'value5', 1), ConsistencyLevel.ONE) + super_columns = [result.super_column + for result in _big_slice('key1', ColumnParent('Super1'))] + assert super_columns == super_columns_expected, super_columns + + # Next, w/ a newer timestamp; it should come back + client.insert('key1', ColumnParent('Super1', 'sc2'), Column(_i64(5), 'value5', 6), ConsistencyLevel.ONE) + super_columns = [result.super_column + for result in _big_slice('key1', ColumnParent('Super1'))] + super_columns_expected = [SuperColumn(name='sc1', columns=[Column(_i64(4), 'value4', 0)]), + SuperColumn(name='sc2', columns=[Column(_i64(5), 'value5', 6)])] + assert super_columns == super_columns_expected, super_columns + + # check slicing at the subcolumn level too + p = SlicePredicate(slice_range=SliceRange('', '', False, 1000)) + columns = [result.column + for result in client.get_slice('key1', ColumnParent('Super1', 'sc2'), p, ConsistencyLevel.ONE)] + assert columns == [Column(_i64(5), 'value5', 6)], columns + + def test_super_cf_resurrect_subcolumn(self): + _set_keyspace('Keyspace1') + self.truncate_all('Super1') + + key = 'vijay' + client.insert(key, ColumnParent('Super1', 'sc1'), Column(_i64(4), 'value4', 0), ConsistencyLevel.ONE) + + client.remove(key, ColumnPath('Super1', 'sc1'), 1, ConsistencyLevel.ONE) + + client.insert(key, ColumnParent('Super1', 'sc1'), Column(_i64(4), 'value4', 2), ConsistencyLevel.ONE) + + result = client.get(key, ColumnPath('Super1', 'sc1'), ConsistencyLevel.ONE) + assert result.super_column.columns is not None, result.super_column + + def test_empty_range(self): + _set_keyspace('Keyspace1') + self.truncate_all('Standard1', 'Super1') + + assert get_range_slice(client, ColumnParent('Standard1'), SlicePredicate(column_names=['c1', 'c1']), '', '', 1000, ConsistencyLevel.ONE) == [] + _insert_simple() + assert get_range_slice(client, ColumnParent('Super1'), SlicePredicate(column_names=['c1', 'c1']), '', '', 1000, ConsistencyLevel.ONE) == [] + + @since('2.1') + def test_super_cql_read_compatibility(self): + _set_keyspace('Keyspace1') + self.truncate_all('Super1') + + _insert_super("key1") + _insert_super("key2") + + node1 = self.cluster.nodelist()[0] + session = self.patient_cql_connection(node1) + + session.execute('USE "Keyspace1"') + + assert_all(session, "SELECT * FROM \"Super1\"", + [["key1", "sc1", 4, "value4"], + ["key1", "sc2", 5, "value5"], + ["key1", "sc2", 6, "value6"], + ["key2", "sc1", 4, "value4"], + ["key2", "sc2", 5, "value5"], + ["key2", "sc2", 6, "value6"]]) + + assert_all(session, "SELECT * FROM \"Super1\" WHERE key=textAsBlob('key1')", + [["key1", "sc1", 4, "value4"], + ["key1", "sc2", 5, "value5"], + ["key1", "sc2", 6, "value6"]]) + + assert_all(session, "SELECT * FROM \"Super1\" WHERE key=textAsBlob('key1') AND column1=textAsBlob('sc2')", + [["key1", "sc2", 5, "value5"], + ["key1", "sc2", 6, "value6"]]) + + assert_all(session, "SELECT * FROM \"Super1\" WHERE key=textAsBlob('key1') AND column1=textAsBlob('sc2') AND column2 = 5", + [["key1", "sc2", 5, "value5"]]) + + assert_all(session, "SELECT * FROM \"Super1\" WHERE key = textAsBlob('key1') AND column1 = textAsBlob('sc2')", + [["key1", "sc2", 5, "value5"], + ["key1", "sc2", 6, "value6"]]) + + assert_all(session, "SELECT column2, value FROM \"Super1\" WHERE key = textAsBlob('key1') AND column1 = textAsBlob('sc2')", + [[5, "value5"], + [6, "value6"]]) + + @since('2.1') + def test_super_cql_write_compatibility(self): + _set_keyspace('Keyspace1') + self.truncate_all('Super1') + + node1 = self.cluster.nodelist()[0] + session = self.patient_cql_connection(node1) + + session.execute('USE "Keyspace1"') + + query = "INSERT INTO \"Super1\" (key, column1, column2, value) VALUES (textAsBlob(%s), textAsBlob(%s), %s, textAsBlob(%s)) USING TIMESTAMP 1234" + session.execute(query, ("key1", "sc1", 4, "value4")) + session.execute(query, ("key1", "sc2", 5, "value5")) + session.execute(query, ("key1", "sc2", 6, "value6")) + session.execute(query, ("key2", "sc1", 4, "value4")) + session.execute(query, ("key2", "sc2", 5, "value5")) + session.execute(query, ("key2", "sc2", 6, "value6")) + + p = SlicePredicate(slice_range=SliceRange('sc1', 'sc2', False, 2)) + result = client.get_slice('key1', ColumnParent('Super1'), p, ConsistencyLevel.ONE) + assert_length_equal(result, 2) + assert result[0].super_column.name == 'sc1' + assert result[0].super_column.columns[0], Column(_i64(4), 'value4' == 1234) + assert result[1].super_column.name == 'sc2' + assert result[1].super_column.columns, [Column(_i64(5), 'value5', 1234), Column(_i64(6), 'value6' == 1234)] + + def test_range_with_remove(self): + _set_keyspace('Keyspace1') + self.truncate_all('Standard1') + + _insert_simple() + assert get_range_slice(client, ColumnParent('Standard1'), SlicePredicate(column_names=['c1', 'c1']), 'key1', '', 1000, ConsistencyLevel.ONE)[0].key == 'key1' + + client.remove('key1', ColumnPath('Standard1', column='c1'), 1, ConsistencyLevel.ONE) + client.remove('key1', ColumnPath('Standard1', column='c2'), 1, ConsistencyLevel.ONE) + actual = get_range_slice(client, ColumnParent('Standard1'), SlicePredicate(column_names=['c1', 'c2']), '', '', 1000, ConsistencyLevel.ONE) + assert actual == [KeySlice(columns=[], key='key1')], actual + + def test_range_with_remove_cf(self): + _set_keyspace('Keyspace1') + self.truncate_all('Standard1') + + _insert_simple() + assert get_range_slice(client, ColumnParent('Standard1'), SlicePredicate(column_names=['c1', 'c1']), 'key1', '', 1000, ConsistencyLevel.ONE)[0].key == 'key1' + + client.remove('key1', ColumnPath('Standard1'), 1, ConsistencyLevel.ONE) + actual = get_range_slice(client, ColumnParent('Standard1'), SlicePredicate(column_names=['c1', 'c1']), '', '', 1000, ConsistencyLevel.ONE) + assert actual == [KeySlice(columns=[], key='key1')], actual + + def test_range_collation(self): + _set_keyspace('Keyspace1') + self.truncate_all('Standard1') + + for key in ['-a', '-b', 'a', 'b'] + [str(i) for i in range(100)]: + client.insert(key, ColumnParent('Standard1'), Column(key, 'v', 0), ConsistencyLevel.ONE) + + slices = get_range_slice(client, ColumnParent('Standard1'), SlicePredicate(column_names=['-a', '-a']), '', '', 1000, ConsistencyLevel.ONE) + L = ['-a', '-b', '0', '1', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '2', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '3', '30', '31', '32', '33', '34', '35', '36', '37', '38', '39', '4', '40', '41', '42', '43', '44', '45', '46', '47', '48', '49', '5', '50', '51', '52', '53', '54', '55', '56', '57', '58', '59', '6', '60', '61', '62', '63', '64', '65', '66', '67', '68', '69', '7', '70', '71', '72', '73', '74', '75', '76', '77', '78', '79', '8', '80', '81', '82', '83', '84', '85', '86', '87', '88', '89', '9', '90', '91', '92', '93', '94', '95', '96', '97', '98', '99', 'a', 'b'] + assert len(slices) == len(L) + for key, ks in zip(L, slices): + assert key == ks.key + + def test_range_partial(self): + _set_keyspace('Keyspace1') + self.truncate_all('Standard1') + + for key in ['-a', '-b', 'a', 'b'] + [str(i) for i in range(100)]: + client.insert(key, ColumnParent('Standard1'), Column(key, 'v', 0), ConsistencyLevel.ONE) + + def check_slices_against_keys(keyList, sliceList): + assert len(keyList) == len(sliceList), "%d vs %d" % (len(keyList), len(sliceList)) + for key, ks in zip(keyList, sliceList): + assert key == ks.key + + slices = get_range_slice(client, ColumnParent('Standard1'), SlicePredicate(column_names=['-a', '-a']), 'a', '', 1000, ConsistencyLevel.ONE) + check_slices_against_keys(['a', 'b'], slices) + + slices = get_range_slice(client, ColumnParent('Standard1'), SlicePredicate(column_names=['-a', '-a']), '', '15', 1000, ConsistencyLevel.ONE) + check_slices_against_keys(['-a', '-b', '0', '1', '10', '11', '12', '13', '14', '15'], slices) + + slices = get_range_slice(client, ColumnParent('Standard1'), SlicePredicate(column_names=['-a', '-a']), '50', '51', 1000, ConsistencyLevel.ONE) + check_slices_against_keys(['50', '51'], slices) + + slices = get_range_slice(client, ColumnParent('Standard1'), SlicePredicate(column_names=['-a', '-a']), '1', '', 10, ConsistencyLevel.ONE) + check_slices_against_keys(['1', '10', '11', '12', '13', '14', '15', '16', '17', '18'], slices) + + def test_get_slice_range(self): + _set_keyspace('Keyspace1') + self.truncate_all('Standard1') + + _insert_range() + _verify_range() + + def test_get_slice_super_range(self): + _set_keyspace('Keyspace1') + self.truncate_all('Super1') + + _insert_super_range() + _verify_super_range() + + def test_get_range_slices_tokens(self): + _set_keyspace('Keyspace2') + self.truncate_all('Super3') + + for key in ['key1', 'key2', 'key3', 'key4', 'key5']: + for cname in ['col1', 'col2', 'col3', 'col4', 'col5']: + client.insert(key, ColumnParent('Super3', 'sc1'), Column(cname, 'v-' + cname, 0), ConsistencyLevel.ONE) + + cp = ColumnParent('Super3', 'sc1') + predicate = SlicePredicate(column_names=['col1', 'col3']) + range = KeyRange(start_token='55', end_token='55', count=100) + result = client.get_range_slices(cp, predicate, range, ConsistencyLevel.ONE) + assert len(result) == 5 + assert result[0].columns[0].column.name == 'col1' + assert result[0].columns[1].column.name == 'col3' + + def test_get_range_slice_super(self): + _set_keyspace('Keyspace2') + self.truncate_all('Super3') + + for key in ['key1', 'key2', 'key3', 'key4', 'key5']: + for cname in ['col1', 'col2', 'col3', 'col4', 'col5']: + client.insert(key, ColumnParent('Super3', 'sc1'), Column(cname, 'v-' + cname, 0), ConsistencyLevel.ONE) + + cp = ColumnParent('Super3', 'sc1') + result = get_range_slice(client, cp, SlicePredicate(column_names=['col1', 'col3']), 'key2', 'key4', 5, ConsistencyLevel.ONE) + assert len(result) == 3 + assert result[0].columns[0].column.name == 'col1' + assert result[0].columns[1].column.name == 'col3' + + cp = ColumnParent('Super3') + result = get_range_slice(client, cp, SlicePredicate(column_names=['sc1']), 'key2', 'key4', 5, ConsistencyLevel.ONE) + assert len(result) == 3 + assert list(set(row.columns[0].super_column.name for row in result))[0] == 'sc1' + + def test_get_range_slice(self): + _set_keyspace('Keyspace1') + self.truncate_all('Standard1') + + for key in ['key1', 'key2', 'key3', 'key4', 'key5']: + for cname in ['col1', 'col2', 'col3', 'col4', 'col5']: + client.insert(key, ColumnParent('Standard1'), Column(cname, 'v-' + cname, 0), ConsistencyLevel.ONE) + cp = ColumnParent('Standard1') + + # test empty slice + result = get_range_slice(client, cp, SlicePredicate(column_names=['col1', 'col3']), 'key6', '', 1, ConsistencyLevel.ONE) + assert len(result) == 0 + + # test empty columns + result = get_range_slice(client, cp, SlicePredicate(column_names=['a']), 'key2', '', 1, ConsistencyLevel.ONE) + assert len(result) == 1 + assert len(result[0].columns) == 0 + + # test column_names predicate + result = get_range_slice(client, cp, SlicePredicate(column_names=['col1', 'col3']), 'key2', 'key4', 5, ConsistencyLevel.ONE) + assert len(result) == 3, result + assert result[0].columns[0].column.name == 'col1' + assert result[0].columns[1].column.name == 'col3' + + # row limiting via count. + result = get_range_slice(client, cp, SlicePredicate(column_names=['col1', 'col3']), 'key2', 'key4', 1, ConsistencyLevel.ONE) + assert len(result) == 1 + + # test column slice predicate + result = get_range_slice(client, cp, SlicePredicate(slice_range=SliceRange(start='col2', finish='col4', reversed=False, count=5)), 'key1', 'key2', 5, ConsistencyLevel.ONE) + assert len(result) == 2 + assert result[0].key == 'key1' + assert result[1].key == 'key2' + assert len(result[0].columns) == 3 + assert result[0].columns[0].column.name == 'col2' + assert result[0].columns[2].column.name == 'col4' + + # col limiting via count + result = get_range_slice(client, cp, SlicePredicate(slice_range=SliceRange(start='col2', finish='col4', reversed=False, count=2)), 'key1', 'key2', 5, ConsistencyLevel.ONE) + assert len(result[0].columns) == 2 + + # and reversed + result = get_range_slice(client, cp, SlicePredicate(slice_range=SliceRange(start='col4', finish='col2', reversed=True, count=5)), 'key1', 'key2', 5, ConsistencyLevel.ONE) + assert result[0].columns[0].column.name == 'col4' + assert result[0].columns[2].column.name == 'col2' + + # row limiting via count + result = get_range_slice(client, cp, SlicePredicate(slice_range=SliceRange(start='col2', finish='col4', reversed=False, count=5)), 'key1', 'key2', 1, ConsistencyLevel.ONE) + assert len(result) == 1 + + # removed data + client.remove('key1', ColumnPath('Standard1', column='col1'), 1, ConsistencyLevel.ONE) + result = get_range_slice(client, cp, SlicePredicate(slice_range=SliceRange('', '')), 'key1', 'key2', 5, ConsistencyLevel.ONE) + assert len(result) == 2, result + assert result[0].columns[0].column.name == 'col2', result[0].columns[0].column.name + assert result[1].columns[0].column.name == 'col1' + + def test_wrapped_range_slices(self): + _set_keyspace('Keyspace1') + self.truncate_all('Standard1') + + def copp_token(key): + # I cheated and generated this from Java + return {'a': '00530000000100000001', + 'b': '00540000000100000001', + 'c': '00550000000100000001', + 'd': '00560000000100000001', + 'e': '00580000000100000001'}[key] + + for key in ['a', 'b', 'c', 'd', 'e']: + for cname in ['col1', 'col2', 'col3', 'col4', 'col5']: + client.insert(key, ColumnParent('Standard1'), Column(cname, 'v-' + cname, 0), ConsistencyLevel.ONE) + cp = ColumnParent('Standard1') + + result = client.get_range_slices(cp, SlicePredicate(column_names=['col1', 'col3']), KeyRange(start_token=copp_token('e'), end_token=copp_token('e')), ConsistencyLevel.ONE) + assert [row.key for row in result] == ['a', 'b', 'c', 'd', 'e', ], [row.key for row in result] + + result = client.get_range_slices(cp, SlicePredicate(column_names=['col1', 'col3']), KeyRange(start_token=copp_token('c'), end_token=copp_token('c')), ConsistencyLevel.ONE) + assert [row.key for row in result] == ['a', 'b', 'c', 'd', 'e', ], [row.key for row in result] + + def test_get_slice_by_names(self): + _set_keyspace('Keyspace1') + self.truncate_all('Standard1', 'Super1') + + _insert_range() + p = SlicePredicate(column_names=['c1', 'c2']) + result = client.get_slice('key1', ColumnParent('Standard1'), p, ConsistencyLevel.ONE) + assert len(result) == 2 + assert result[0].column.name == 'c1' + assert result[1].column.name == 'c2' + + _insert_super() + p = SlicePredicate(column_names=[_i64(4)]) + result = client.get_slice('key1', ColumnParent('Super1', 'sc1'), p, ConsistencyLevel.ONE) + assert len(result) == 1 + assert result[0].column.name == _i64(4) + + def test_multiget_slice_with_compact_table(self): + """Insert multiple keys in a compact table and retrieve them using the multiget_slice interface""" + _set_keyspace('Keyspace1') + + # create + cd = ColumnDef('v', 'AsciiType', None, None) + newcf = CfDef('Keyspace1', 'CompactColumnFamily', default_validation_class='AsciiType', column_metadata=[cd]) + client.system_add_column_family(newcf) + + CL = ConsistencyLevel.ONE + for i in range(0, 5): + client.insert('key' + str(i), ColumnParent('CompactColumnFamily'), Column('v', 'value' + str(i), 0), CL) + time.sleep(0.1) + + p = SlicePredicate(column_names=['v']) + rows = client.multiget_slice(['key' + str(i) for i in range(0, 5)], ColumnParent('CompactColumnFamily'), p, ConsistencyLevel.ONE) + + for i in range(0, 5): + key = 'key' + str(i) + assert key in rows + assert len(rows[key]) == 1 + assert rows[key][0].column.name == 'v' + assert rows[key][0].column.value == 'value' + str(i) + + def test_multiget_slice(self): + """Insert multiple keys and retrieve them using the multiget_slice interface""" + _set_keyspace('Keyspace1') + self.truncate_all('Standard1') + + # Generate a list of 10 keys and insert them + num_keys = 10 + keys = ['key' + str(i) for i in range(1, num_keys + 1)] + _insert_multi(keys) + + # Retrieve all 10 key slices + rows = _big_multislice(keys, ColumnParent('Standard1')) + + columns = [ColumnOrSuperColumn(c) for c in _SIMPLE_COLUMNS] + # Validate if the returned rows have the keys requested and if the ColumnOrSuperColumn is what was inserted + for key in keys: + assert key in rows + assert columns == rows[key] + + def test_multi_count(self): + """Insert multiple keys and count them using the multiget interface""" + _set_keyspace('Keyspace1') + self.truncate_all('Standard1') + + # Generate a list of 10 keys countaining 1 to 10 columns and insert them + num_keys = 10 + for i in range(1, num_keys + 1): + key = 'key' + str(i) + for j in range(1, i + 1): + client.insert(key, ColumnParent('Standard1'), Column('c' + str(j), 'value' + str(j), 0), ConsistencyLevel.ONE) + + # Count columns in all 10 keys + keys = ['key' + str(i) for i in range(1, num_keys + 1)] + p = SlicePredicate(slice_range=SliceRange('', '', False, 1000)) + counts = client.multiget_count(keys, ColumnParent('Standard1'), p, ConsistencyLevel.ONE) + + # Check the returned counts + for i in range(1, num_keys + 1): + key = 'key' + str(i) + assert counts[key] == i + + def test_batch_mutate_super_deletion(self): + _set_keyspace('Keyspace1') + self.truncate_all('Super1') + + _insert_super('test') + d = Deletion(1, predicate=SlicePredicate(column_names=['sc1'])) + cfmap = {'Super1': [Mutation(deletion=d)]} + client.batch_mutate({'test': cfmap}, ConsistencyLevel.ONE) + _expect_missing(lambda: client.get('key1', ColumnPath('Super1', 'sc1'), ConsistencyLevel.ONE)) + + def test_super_reinsert(self): + _set_keyspace('Keyspace1') + self.truncate_all('Super1') + + for x in range(3): + client.insert('key1', ColumnParent('Super1', 'sc2'), Column(_i64(x), 'value', 1), ConsistencyLevel.ONE) + + client.remove('key1', ColumnPath('Super1'), 2, ConsistencyLevel.ONE) + + for x in range(3): + client.insert('key1', ColumnParent('Super1', 'sc2'), Column(_i64(x + 3), 'value', 3), ConsistencyLevel.ONE) + + for n in range(1, 4): + p = SlicePredicate(slice_range=SliceRange('', '', False, n)) + slice = client.get_slice('key1', ColumnParent('Super1', 'sc2'), p, ConsistencyLevel.ONE) + assert len(slice) == n, "expected %s results; found %s" % (n, slice) + + def test_describe_keyspace(self): + try: + client.system_drop_keyspace("ValidKsForUpdate") + except InvalidRequestException: + pass # The keyspace doesn't exit, because this test was run in isolation. + + kspaces = client.describe_keyspaces() + if self.cluster.version() >= '3.0': + assert len(kspaces) == 7, [x.name for x in kspaces] # ['Keyspace2', 'Keyspace1', 'system', 'system_traces', 'system_auth', 'system_distributed', 'system_schema'] + elif self.cluster.version() >= '2.2': + assert len(kspaces) == 6, [x.name for x in kspaces] # ['Keyspace2', 'Keyspace1', 'system', 'system_traces', 'system_auth', 'system_distributed'] + else: + assert len(kspaces) == 4, [x.name for x in kspaces] # ['Keyspace2', 'Keyspace1', 'system', 'system_traces'] + + sysks = client.describe_keyspace("system") + assert sysks in kspaces + + ks1 = client.describe_keyspace("Keyspace1") + assert ks1.strategy_options['replication_factor'] == '1', ks1.strategy_options + for cf in ks1.cf_defs: + if cf.name == "Standard1": + cf0 = cf + break + assert cf0.comparator_type == "org.apache.cassandra.db.marshal.BytesType" + + def test_describe(self): + assert client.describe_cluster_name() == 'test' + + def test_describe_ring(self): + assert list(client.describe_ring('Keyspace1'))[0].endpoints == ['127.0.0.1'] + + def test_describe_token_map(self): + # test/conf/cassandra.yaml specifies org.apache.cassandra.dht.ByteOrderedPartitioner + # which uses BytesToken, so this just tests that the string representation of the token + # matches a regex pattern for BytesToken.toString(). + ring = list(client.describe_token_map().items()) + if not self.dtest_config.use_vnodes: + assert len(ring) == 1 + else: + assert len(ring) == int(self.dtest_config.num_tokens) + token, node = ring[0] + if self.dtest_config.use_vnodes: + assert re.match("[0-9A-Fa-f]{32}", token) + assert node == '127.0.0.1' + + def test_describe_partitioner(self): + # Make sure this just reads back the values from the config. + assert client.describe_partitioner() == "org.apache.cassandra.dht.ByteOrderedPartitioner" + + def test_describe_snitch(self): + assert client.describe_snitch() == "org.apache.cassandra.locator.SimpleSnitch" + + def test_invalid_ks_names(self): + def invalid_keyspace(): + client.system_add_keyspace(KsDef('in-valid', 'org.apache.cassandra.locator.SimpleStrategy', {'replication_factor': '1'}, cf_defs=[])) + _expect_exception(invalid_keyspace, InvalidRequestException) + + def test_invalid_strategy_class(self): + def add_invalid_keyspace(): + client.system_add_keyspace(KsDef('ValidKs', 'InvalidStrategyClass', {}, cf_defs=[])) + exc = _expect_exception(add_invalid_keyspace, InvalidRequestException) + s = str(exc) + assert s.find("InvalidStrategyClass") > -1, s + assert s.find("Unable to find replication strategy") > -1, s + + def update_invalid_keyspace(): + client.system_add_keyspace(KsDef('ValidKsForUpdate', 'org.apache.cassandra.locator.SimpleStrategy', {'replication_factor': '1'}, cf_defs=[])) + client.system_update_keyspace(KsDef('ValidKsForUpdate', 'InvalidStrategyClass', {}, cf_defs=[])) + + exc = _expect_exception(update_invalid_keyspace, InvalidRequestException) + s = str(exc) + assert s.find("InvalidStrategyClass") > -1, s + assert s.find("Unable to find replication strategy") > -1, s + + def test_invalid_cf_names(self): + def invalid_cf(): + _set_keyspace('Keyspace1') + newcf = CfDef('Keyspace1', 'in-valid') + client.system_add_column_family(newcf) + _expect_exception(invalid_cf, InvalidRequestException) + + def invalid_cf_inside_new_ks(): + cf = CfDef('ValidKsName_invalid_cf', 'in-valid') + _set_keyspace('system') + client.system_add_keyspace(KsDef('ValidKsName_invalid_cf', 'org.apache.cassandra.locator.SimpleStrategy', {'replication_factor': '1'}, cf_defs=[cf])) + _expect_exception(invalid_cf_inside_new_ks, InvalidRequestException) + + def test_system_cf_recreate(self): + "ensures that keyspaces and column familes can be dropped and recreated in short order" + for x in range(2): + + keyspace = 'test_cf_recreate' + cf_name = 'recreate_cf' + + # create + newcf = CfDef(keyspace, cf_name) + newks = KsDef(keyspace, 'org.apache.cassandra.locator.SimpleStrategy', {'replication_factor': '1'}, cf_defs=[newcf]) + client.system_add_keyspace(newks) + _set_keyspace(keyspace) + + # insert + client.insert('key0', ColumnParent(cf_name), Column('colA', 'colA-value', 0), ConsistencyLevel.ONE) + col1 = client.get_slice('key0', ColumnParent(cf_name), SlicePredicate(slice_range=SliceRange('', '', False, 100)), ConsistencyLevel.ONE)[0].column + assert col1.name == 'colA' and col1.value == 'colA-value' + + # drop + client.system_drop_column_family(cf_name) + + # recreate + client.system_add_column_family(newcf) + + # query + cosc_list = client.get_slice('key0', ColumnParent(cf_name), SlicePredicate(slice_range=SliceRange('', '', False, 100)), ConsistencyLevel.ONE) + # this was failing prior to CASSANDRA-1477. + assert len(cosc_list) == 0, 'cosc length test failed' + + client.system_drop_keyspace(keyspace) + + def test_system_keyspace_operations(self): + # create. note large RF, this is OK + keyspace = KsDef('CreateKeyspace', + 'org.apache.cassandra.locator.SimpleStrategy', + {'replication_factor': '10'}, + cf_defs=[CfDef('CreateKeyspace', 'CreateKsCf')]) + client.system_add_keyspace(keyspace) + newks = client.describe_keyspace('CreateKeyspace') + assert 'CreateKsCf' in [x.name for x in newks.cf_defs] + + _set_keyspace('CreateKeyspace') + + # modify valid + modified_keyspace = KsDef('CreateKeyspace', + 'org.apache.cassandra.locator.OldNetworkTopologyStrategy', + {'replication_factor': '1'}, + cf_defs=[]) + client.system_update_keyspace(modified_keyspace) + modks = client.describe_keyspace('CreateKeyspace') + assert modks.strategy_class == modified_keyspace.strategy_class + assert modks.strategy_options == modified_keyspace.strategy_options + + # check strategy options are validated on modify + def modify_invalid_ks(): + client.system_update_keyspace(KsDef('CreateKeyspace', + 'org.apache.cassandra.locator.SimpleStrategy', + {}, + cf_defs=[])) + _expect_exception(modify_invalid_ks, InvalidRequestException) + + # drop + client.system_drop_keyspace('CreateKeyspace') + + def get_second_ks(): + client.describe_keyspace('CreateKeyspace') + _expect_exception(get_second_ks, NotFoundException) + + # check strategy options are validated on creation + def create_invalid_ks(): + client.system_add_keyspace(KsDef('InvalidKeyspace', + 'org.apache.cassandra.locator.SimpleStrategy', + {}, + cf_defs=[])) + _expect_exception(create_invalid_ks, InvalidRequestException) + + def test_create_then_drop_ks(self): + keyspace = KsDef('AddThenDrop', + strategy_class='org.apache.cassandra.locator.SimpleStrategy', + strategy_options={'replication_factor': '1'}, + cf_defs=[]) + + def test_existence(): + client.describe_keyspace(keyspace.name) + _expect_exception(test_existence, NotFoundException) + client.set_keyspace('system') + client.system_add_keyspace(keyspace) + test_existence() + client.system_drop_keyspace(keyspace.name) + + def test_column_validators(self): + # columndef validation for regular CF + ks = 'Keyspace1' + _set_keyspace(ks) + cd = ColumnDef('col', 'LongType', None, None) + cf = CfDef('Keyspace1', 'ValidatorColumnFamily', column_metadata=[cd]) + client.system_add_column_family(cf) + ks_def = client.describe_keyspace(ks) + assert 'ValidatorColumnFamily' in [x.name for x in ks_def.cf_defs] + + cp = ColumnParent('ValidatorColumnFamily') + col0 = Column('col', _i64(42), 0) + col1 = Column('col', "ceci n'est pas 64bit", 0) + client.insert('key0', cp, col0, ConsistencyLevel.ONE) + e = _expect_exception(lambda: client.insert('key1', cp, col1, ConsistencyLevel.ONE), InvalidRequestException) + assert e.why.find("failed validation") >= 0 + + # columndef validation for super CF + scf = CfDef('Keyspace1', 'ValidatorSuperColumnFamily', column_type='Super', column_metadata=[cd]) + client.system_add_column_family(scf) + ks_def = client.describe_keyspace(ks) + assert 'ValidatorSuperColumnFamily' in [x.name for x in ks_def.cf_defs] + + scp = ColumnParent('ValidatorSuperColumnFamily', 'sc1') + client.insert('key0', scp, col0, ConsistencyLevel.ONE) + e = _expect_exception(lambda: client.insert('key1', scp, col1, ConsistencyLevel.ONE), InvalidRequestException) + assert e.why.find("failed validation") >= 0 + + # columndef and cfdef default validation + cf = CfDef('Keyspace1', 'DefaultValidatorColumnFamily', column_metadata=[cd], default_validation_class='UTF8Type') + client.system_add_column_family(cf) + ks_def = client.describe_keyspace(ks) + assert 'DefaultValidatorColumnFamily' in [x.name for x in ks_def.cf_defs] + + dcp = ColumnParent('DefaultValidatorColumnFamily') + # inserting a longtype into column 'col' is valid at the columndef level + client.insert('key0', dcp, col0, ConsistencyLevel.ONE) + # inserting a UTF8type into column
<TRUNCATED> --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@cassandra.apache.org For additional commands, e-mail: commits-h...@cassandra.apache.org