cassilds 0.9.2 → 0.12.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. data/CHANGELOG +51 -1
  2. data/LICENSE +0 -0
  3. data/Manifest +25 -7
  4. data/README.md +352 -0
  5. data/Rakefile +169 -1
  6. data/cassilds.gemspec +45 -0
  7. data/conf/{cassandra.in.sh → 0.6/cassandra.in.sh} +0 -0
  8. data/conf/{log4j.properties → 0.6/log4j.properties} +0 -0
  9. data/conf/0.6/schema.json +57 -0
  10. data/conf/{storage-conf.xml → 0.6/storage-conf.xml} +15 -5
  11. data/conf/0.7/cassandra.in.sh +46 -0
  12. data/conf/0.7/cassandra.yaml +336 -0
  13. data/conf/0.7/log4j-server.properties +41 -0
  14. data/conf/0.7/schema.json +57 -0
  15. data/conf/0.7/schema.txt +45 -0
  16. data/conf/0.8/cassandra.in.sh +41 -0
  17. data/conf/0.8/cassandra.yaml +61 -0
  18. data/conf/0.8/log4j-server.properties +40 -0
  19. data/conf/0.8/schema.json +66 -0
  20. data/conf/0.8/schema.txt +51 -0
  21. data/lib/cassandra/0.6/cassandra.rb +58 -13
  22. data/lib/cassandra/0.6/columns.rb +43 -0
  23. data/lib/cassandra/0.6/protocol.rb +16 -18
  24. data/lib/cassandra/0.6.rb +0 -0
  25. data/lib/cassandra/0.7/cassandra.rb +0 -270
  26. data/lib/cassandra/0.7/columns.rb +1 -64
  27. data/lib/cassandra/0.7/protocol.rb +0 -134
  28. data/lib/cassandra/0.7.rb +0 -0
  29. data/lib/cassandra/0.8/cassandra.rb +10 -0
  30. data/lib/cassandra/0.8/columns.rb +4 -0
  31. data/lib/cassandra/0.8/protocol.rb +23 -0
  32. data/lib/cassandra/0.8.rb +7 -0
  33. data/lib/cassandra/array.rb +0 -0
  34. data/lib/cassandra/cassandra.rb +877 -111
  35. data/lib/cassandra/{0.7/column_family.rb → column_family.rb} +0 -0
  36. data/lib/cassandra/columns.rb +72 -6
  37. data/lib/cassandra/comparable.rb +0 -0
  38. data/lib/cassandra/constants.rb +0 -0
  39. data/lib/cassandra/debug.rb +0 -0
  40. data/lib/cassandra/helpers.rb +1 -0
  41. data/lib/cassandra/{0.7/keyspace.rb → keyspace.rb} +0 -0
  42. data/lib/cassandra/long.rb +5 -0
  43. data/lib/cassandra/mock.rb +259 -85
  44. data/lib/cassandra/ordered_hash.rb +10 -18
  45. data/lib/cassandra/protocol.rb +120 -0
  46. data/lib/cassandra/time.rb +0 -0
  47. data/lib/cassandra.rb +6 -7
  48. data/test/cassandra_client_test.rb +0 -0
  49. data/test/cassandra_mock_test.rb +52 -28
  50. data/test/cassandra_test.rb +465 -44
  51. data/test/comparable_types_test.rb +0 -0
  52. data/test/eventmachine_test.rb +30 -30
  53. data/test/ordered_hash_test.rb +6 -0
  54. data/test/test_helper.rb +3 -2
  55. data/vendor/0.6/gen-rb/cassandra.rb +0 -0
  56. data/vendor/0.6/gen-rb/cassandra_constants.rb +0 -0
  57. data/vendor/0.6/gen-rb/cassandra_types.rb +0 -0
  58. data/vendor/0.7/gen-rb/cassandra.rb +0 -0
  59. data/vendor/0.7/gen-rb/cassandra_constants.rb +0 -0
  60. data/vendor/0.7/gen-rb/cassandra_types.rb +4 -2
  61. data/vendor/0.8/gen-rb/cassandra.rb +2215 -0
  62. data/vendor/0.8/gen-rb/cassandra_constants.rb +12 -0
  63. data/vendor/0.8/gen-rb/cassandra_types.rb +816 -0
  64. metadata +50 -27
  65. data/README.rdoc +0 -83
  66. data/cassandra.gemspec +0 -46
  67. data/conf/cassandra.yaml +0 -113
@@ -4,15 +4,21 @@ class CassandraTest < Test::Unit::TestCase
4
4
  include Cassandra::Constants
5
5
 
6
6
  def setup
7
- @twitter = Cassandra.new('Twitter', "127.0.0.1:9160", :retries => 2, :exception_classes => [])
7
+ @twitter = Cassandra.new('Twitter', "127.0.0.1:9160", :retries => 2, :connect_timeout => 0.1, :exception_classes => [])
8
8
  @twitter.clear_keyspace!
9
9
 
10
- @blogs = Cassandra.new('Multiblog')
10
+ @blogs = Cassandra.new('Multiblog', "127.0.0.1:9160", :retries => 2, :connect_timeout => 0.1, :exception_classes => [])
11
11
  @blogs.clear_keyspace!
12
12
 
13
- @blogs_long = Cassandra.new('MultiblogLong')
13
+ @blogs_long = Cassandra.new('MultiblogLong', "127.0.0.1:9160", :retries => 2, :connect_timeout => 0.1, :exception_classes => [])
14
14
  @blogs_long.clear_keyspace!
15
15
 
16
+ @type_conversions = Cassandra.new('TypeConversions', "127.0.0.1:9160", :retries => 2, :connect_timeout => 0.1, :exception_classes => [])
17
+ @type_conversions.clear_keyspace!
18
+
19
+ Cassandra::WRITE_DEFAULTS[:consistency] = Cassandra::Consistency::ONE
20
+ Cassandra::READ_DEFAULTS[:consistency] = Cassandra::Consistency::ONE
21
+
16
22
  @uuids = (0..6).map {|i| SimpleUUID::UUID.new(Time.at(2**(24+i))) }
17
23
  @longs = (0..6).map {|i| Long.new(Time.at(2**(24+i))) }
18
24
  end
@@ -24,13 +30,37 @@ class CassandraTest < Test::Unit::TestCase
24
30
  end
25
31
  end
26
32
 
33
+ def test_setting_default_consistency
34
+ assert_nothing_raised do
35
+ @twitter.default_read_consistency = Cassandra::Consistency::ALL
36
+ end
37
+ assert_equal(Cassandra::READ_DEFAULTS[:consistency], Cassandra::Consistency::ALL)
38
+
39
+ assert_nothing_raised do
40
+ @twitter.default_write_consistency = Cassandra::Consistency::ALL
41
+ end
42
+ assert_equal(Cassandra::WRITE_DEFAULTS[:consistency], Cassandra::Consistency::ALL)
43
+ end
44
+
27
45
  def test_get_key
46
+
28
47
  @twitter.insert(:Users, key, {'body' => 'v', 'user' => 'v'})
29
48
  assert_equal({'body' => 'v', 'user' => 'v'}, @twitter.get(:Users, key))
30
49
  assert_equal(['body', 'user'].sort, @twitter.get(:Users, key).timestamps.keys.sort)
31
50
  assert_equal({}, @twitter.get(:Users, 'bogus'))
32
51
  end
33
52
 
53
+ def test_get_single_column_returns_single_value
54
+ @twitter.insert(:Users, key, {'body' => 'body_text', 'user' => 'user_name'})
55
+ assert_equal('body_text', @twitter.get(:Users, key, 'body'))
56
+ assert_equal('user_name', @twitter.get(:Users, key, 'user'))
57
+
58
+ @blogs.insert(:Blogs, key,
59
+ {@uuids[0] => 'I like this cat', @uuids[1] => 'Buttons is cuter', @uuids[2] => 'I disagree'})
60
+
61
+ assert_equal('I like this cat', @blogs.get(:Blogs, key, @uuids[0]))
62
+ end
63
+
34
64
  def test_get_key_preserving_order
35
65
  # In-order hash is preserved
36
66
  hash = OrderedHash['a', '', 'b', '', 'c', '', 'd', '',]
@@ -43,7 +73,7 @@ class CassandraTest < Test::Unit::TestCase
43
73
  hash = OrderedHash['b', '', 'c', '', 'd', '', 'a', '']
44
74
  @twitter.insert(:Users, key, hash)
45
75
  assert_equal(hash.keys.sort, @twitter.get(:Users, key).keys)
46
- assert_equal(hash.timestamps.keys.sort, @twitter.get(:Users, key).timestamps.keys.sort)
76
+ assert_equal(hash.timestamps.keys.sort, @twitter.get(:Users, key).timestamps.keys)
47
77
  assert_not_equal(hash.keys, @twitter.get(:Users, key).keys)
48
78
  end
49
79
 
@@ -102,9 +132,39 @@ class CassandraTest < Test::Unit::TestCase
102
132
  assert !@twitter.exists?(:Statuses, 'bogus', 'body')
103
133
  end
104
134
 
105
- def test_exists_with_only_key
135
+ def test_get_value_with_range
136
+ k = key
137
+
138
+ 10.times do |i|
139
+ @twitter.insert(:Statuses, k, {"body-#{i}" => 'v'})
140
+ end
141
+
142
+ assert_equal 5, @twitter.get(:Statuses, k, :count => 5).length
143
+ assert_equal 5, @twitter.get(:Statuses, k, :start => "body-5").length
144
+ assert_equal 5, @twitter.get(:Statuses, k, :finish => "body-4").length
145
+ assert_equal 5, @twitter.get(:Statuses, k, :start => "body-1", :count => 5).length
146
+ assert_equal 5, @twitter.get(:Statuses, k, :start => "body-0", :finish => "body-4", :count => 7).length
147
+ end
148
+
149
+ def test_exists
106
150
  @twitter.insert(:Statuses, key, {'body' => 'v'})
107
- assert @twitter.exists?(:Statuses, key)
151
+ assert_equal true, @twitter.exists?(:Statuses, key)
152
+ assert_equal false, @twitter.exists?(:Statuses, 'bogus')
153
+
154
+ columns = {@uuids[1] => 'v1', @uuids[2] => 'v2'}
155
+ @twitter.insert(:StatusRelationships, key, {'user_timelines' => columns})
156
+
157
+ # verify return value when searching by key
158
+ assert_equal true, @twitter.exists?(:StatusRelationships, key)
159
+ assert_equal false, @twitter.exists?(:StatusRelationships, 'bogus')
160
+
161
+ # verify return value when searching by key and column
162
+ assert_equal true, @twitter.exists?(:StatusRelationships, key, 'user_timelines')
163
+ assert_equal false, @twitter.exists?(:StatusRelationships, key, 'bogus')
164
+
165
+ # verify return value when searching by key and column and subcolumn
166
+ assert_equal true, @twitter.exists?(:StatusRelationships, key, 'user_timelines', @uuids[1])
167
+ assert_equal false, @twitter.exists?(:StatusRelationships, key, 'user_timelines', @uuids[3])
108
168
  end
109
169
 
110
170
  def test_get_super_key
@@ -116,9 +176,11 @@ class CassandraTest < Test::Unit::TestCase
116
176
  end
117
177
 
118
178
  def test_get_several_super_keys
119
- columns = {
120
- 'user_timelines' => {@uuids[1] => 'v1'},
121
- 'mentions_timelines' => {@uuids[2] => 'v2'}}
179
+ columns = OrderedHash[
180
+ 'mentions_timelines', {@uuids[2] => 'v2'},
181
+ 'user_timelines', {@uuids[1] => 'v1'}
182
+ ]
183
+
122
184
  @twitter.insert(:StatusRelationships, key, columns)
123
185
 
124
186
  assert_equal(columns, @twitter.get(:StatusRelationships, key))
@@ -165,7 +227,7 @@ class CassandraTest < Test::Unit::TestCase
165
227
  assert_equal(columns.keys.sort, @twitter.get(:StatusRelationships, key, 'user_timelines').timestamps.keys.sort)
166
228
  assert_equal({}, @twitter.get(:StatusRelationships, 'bogus', 'user_timelines'))
167
229
  # FIXME Not sure if this is valid
168
- # assert_nil @twitter.exists?(:StatusRelationships, 'bogus', 'user_timelines')
230
+ assert_equal false, @twitter.exists?(:StatusRelationships, 'bogus', 'user_timelines')
169
231
  end
170
232
 
171
233
  def test_get_super_value
@@ -175,24 +237,129 @@ class CassandraTest < Test::Unit::TestCase
175
237
  assert_nil @twitter.get(:StatusRelationships, 'bogus', 'user_timelines', columns.keys.first)
176
238
  end
177
239
 
240
+ # def test_get_range_with_key_range
241
+ # skip('This test requires the use of OrderPreservingPartitioner on the cluster to work properly.')
242
+ # k = key
243
+ # @twitter.insert(:Statuses, k + '2', {'body' => '1'})
244
+ # @twitter.insert(:Statuses, k + '3', {'body' => '1'})
245
+ # @twitter.insert(:Statuses, k + '4', {'body' => '1'})
246
+ # @twitter.insert(:Statuses, k + '5', {'body' => '1'})
247
+ # @twitter.insert(:Statuses, k + '6', {'body' => '1'})
248
+ # assert_equal([k + '3', k + '4', k + '5'], @twitter.get_range(:Statuses, :start_key => k + '3', :finish_key => k + '5').keys)
249
+ # end
250
+
251
+ def test_get_range
252
+ # make sure that deleted rows are not included in the iteration
253
+ 10.times do |i|
254
+ @twitter.insert(:Statuses, i.to_s, {'body' => '1'})
255
+ @twitter.insert(:Statuses, i.to_s + '_delete_me', {'test' => 'value'})
256
+ @twitter.remove(:Statuses, i.to_s + '_delete_me')
257
+ end
178
258
 
179
- #TODO: add a OPP keyspace for this
180
- # def test_get_range
181
- # @twitter.insert(:Statuses, '2', {'body' => '1'})
182
- # @twitter.insert(:Statuses, '3', {'body' => '1'})
183
- # @twitter.insert(:Statuses, '4', {'body' => '1'})
184
- # @twitter.insert(:Statuses, '5', {'body' => '1'})
185
- # @twitter.insert(:Statuses, '6', {'body' => '1'})
186
- # assert_equal(['3', '4', '5'], @twitter.get_range(:Statuses, :start => '3', :finish => '5'))
187
- # end
259
+ assert_equal(4, @twitter.get_range_keys(:Statuses, :key_count => 4).size)
260
+ end
261
+
262
+ def test_get_range_with_count
263
+ @twitter.insert(:Statuses, key + '1', {'test_column1' => '1', 'test_column2' => '2', 'test_column3' => '2', 'deleted_column' => '1'})
264
+ @twitter.insert(:Statuses, key + '2', {'test_column4' => '3', 'test_column5' => '4', 'test_column6' => '2', 'deleted_column' => '2'})
265
+
266
+ @twitter.get_range(:Statuses, :count => 3) do |key, columns|
267
+ assert_equal columns.count, 3
268
+ end
269
+
270
+ assert_equal 2, @twitter.get_range(:Statuses, :start_key => key + '1', :finish_key => key + '1', :count => 2)[key + '1'].count
271
+
272
+ @twitter.remove(:Statuses, key + '1', 'deleted_column')
273
+ @twitter.remove(:Statuses, key + '2', 'deleted_column')
274
+
275
+ @twitter.get_range(:Statuses, :count => 2) do |key, columns|
276
+ assert_equal columns.count, 2
277
+ end
188
278
 
189
- def test_get_range_count
190
- @twitter.insert(:Statuses, '2', {'body' => '1'})
191
- @twitter.insert(:Statuses, '3', {'body' => '1'})
192
- @twitter.insert(:Statuses, '4', {'body' => '1'})
193
- @twitter.insert(:Statuses, '5', {'body' => '1'})
194
- @twitter.insert(:Statuses, '6', {'body' => '1'})
195
- assert_equal(3, @twitter.get_range(:Statuses, :count => 3).size)
279
+ end
280
+
281
+ def test_get_range_block
282
+ k = key
283
+ 5.times do |i|
284
+ @twitter.insert(:Statuses, k+i.to_s, {"body-#{i.to_s}" => 'v'})
285
+ end
286
+
287
+ values = (0..4).collect{|n| { :key => "test_get_range_block#{n}", :columns => { "body-#{n}" => "v" }} }.reverse
288
+
289
+ returned_value = @twitter.get_range(:Statuses, :start_key => k.to_s, :key_count => 5) do |key,columns|
290
+ expected = values.pop
291
+ assert_equal expected[:key], key
292
+ assert_equal expected[:columns], columns
293
+ end
294
+
295
+ assert_equal [], values
296
+ assert_nil returned_value
297
+ end
298
+
299
+ def test_get_range_reversed
300
+ data = 3.times.map { |i| ["body-#{i.to_s}", "v"] }
301
+ hash = Cassandra::OrderedHash[data]
302
+ reversed_hash = Cassandra::OrderedHash[data.reverse]
303
+
304
+ @twitter.insert(:Statuses, "all-keys", hash)
305
+
306
+ columns = @twitter.get_range(:Statuses, :reversed => true)["all-keys"]
307
+ columns.each do |column|
308
+ assert_equal reversed_hash.shift, column
309
+ end
310
+ end
311
+
312
+ def test_each_key
313
+ k = key
314
+ keys_yielded = []
315
+
316
+ 10.times do |i|
317
+ @twitter.insert(:Statuses, k + i.to_s, {"body-#{i.to_s}" => 'v'})
318
+ end
319
+
320
+ # make sure that deleted rows are not included in the iteration
321
+ @twitter.insert(:Statuses, k + '_delete_me', {'test' => 'value'})
322
+ @twitter.remove(:Statuses, k + '_delete_me')
323
+
324
+ @twitter.each_key(:Statuses) do |key|
325
+ keys_yielded << key
326
+ end
327
+
328
+ assert_equal 10, keys_yielded.length
329
+ end
330
+
331
+ def test_each
332
+ k = key
333
+ key_columns = {}
334
+
335
+ 10.times do |i|
336
+ key_columns[k + i.to_s] = {"body-#{i.to_s}" => 'v', 'single_column_lookup' => "value = #{i.to_s}"}
337
+ @twitter.insert(:Statuses, k + i.to_s, key_columns[k + i.to_s])
338
+ end
339
+
340
+ keys_yielded = []
341
+ @twitter.each(:Statuses, :batch_size => 5) do |key, columns|
342
+ assert_equal key_columns[key], columns
343
+ keys_yielded << key
344
+ end
345
+
346
+ assert_equal 10, keys_yielded.length
347
+
348
+ keys_yielded = []
349
+ @twitter.each(:Statuses, :key_count => 7, :batch_size => 5) do |key, columns|
350
+ assert_equal key_columns[key], columns
351
+ keys_yielded << key
352
+ end
353
+
354
+ assert_equal 7, keys_yielded.length, 'each limits to specified count'
355
+
356
+ keys_yielded = []
357
+ @twitter.each(:Statuses, :columns => ['single_column_lookup'], :batch_size => 5) do |key, columns|
358
+ assert_equal key_columns[key].reject {|k2,v| k2 != 'single_column_lookup'}, columns
359
+ keys_yielded << key
360
+ end
361
+
362
+ assert_equal 10, keys_yielded.length
196
363
  end
197
364
 
198
365
  def test_multi_get
@@ -220,6 +387,13 @@ class CassandraTest < Test::Unit::TestCase
220
387
  assert_equal({}, @twitter.get(:Statuses, key))
221
388
  end
222
389
 
390
+ def test_remove_super_sub_key_errors_for_normal_column_family
391
+ @twitter.insert(:Statuses, key, {'body' => 'v'})
392
+ assert_equal({'body' => 'v'}, @twitter.get(:Statuses, key))
393
+
394
+ assert_raise( ArgumentError) { @twitter.remove(:Statuses, key, 'body' , 'subcolumn') }
395
+ end
396
+
223
397
  def test_remove_value
224
398
  @twitter.insert(:Statuses, key, {'body' => 'v'})
225
399
  @twitter.remove(:Statuses, key, 'body')
@@ -240,11 +414,12 @@ class CassandraTest < Test::Unit::TestCase
240
414
  end
241
415
 
242
416
  def test_remove_super_value
243
- columns = {@uuids[1] => 'v1'}
417
+ columns = {@uuids[1] => 'v1', @uuids[2] => 'v2'}
418
+ column_name_to_remove = @uuids[2]
244
419
  @twitter.insert(:StatusRelationships, key, {'user_timelines' => columns})
245
- @twitter.remove(:StatusRelationships, key, 'user_timelines', columns.keys.first)
246
- assert_nil @twitter.get(:StatusRelationships, key, 'user_timelines', columns.keys.first)
247
- assert_nil @twitter.get(:StatusRelationships, key, 'user_timelines').timestamps[columns.keys.first]
420
+ @twitter.remove(:StatusRelationships, key, 'user_timelines', column_name_to_remove)
421
+ assert_equal( columns.reject{|k,v| k == column_name_to_remove}, @twitter.get(:StatusRelationships, key, 'user_timelines') )
422
+ assert_nil @twitter.get(:StatusRelationships, key, 'user_timelines').timestamps[column_name_to_remove]
248
423
  end
249
424
 
250
425
  def test_clear_column_family
@@ -306,15 +481,21 @@ class CassandraTest < Test::Unit::TestCase
306
481
  end
307
482
 
308
483
  def test_count_keys
309
- @twitter.insert(:Statuses, key + "1", {'body' => '1'})
310
- @twitter.insert(:Statuses, key + "2", {'body' => '2'})
311
- @twitter.insert(:Statuses, key + "3", {'body' => '3'})
484
+ k = key
485
+ @twitter.insert(:Statuses, k + "1", {'body' => '1'})
486
+ @twitter.insert(:Statuses, k + "2", {'body' => '2'})
487
+ @twitter.insert(:Statuses, k + "3", {'body' => '3'})
312
488
  assert_equal 3, @twitter.count_range(:Statuses)
313
489
  end
314
490
 
315
491
  def test_count_columns
316
- @twitter.insert(:Statuses, key, {'body' => 'v1', 'user' => 'v2'})
317
- assert_equal 2, @twitter.count_columns(:Statuses, key)
492
+ columns = (1..200).inject(Hash.new){|h,v| h['column' + v.to_s] = v.to_s; h;}
493
+
494
+ @twitter.insert(:Statuses, key, columns)
495
+ assert_equal 200, @twitter.count_columns(:Statuses, key, :count => 200)
496
+ assert_equal 100, @twitter.count_columns(:Statuses, key)
497
+ assert_equal 55, @twitter.count_columns(:Statuses, key, :count => 55)
498
+
318
499
  end
319
500
 
320
501
  def test_count_super_columns
@@ -343,24 +524,45 @@ class CassandraTest < Test::Unit::TestCase
343
524
  def test_batch_mutate
344
525
  k = key
345
526
 
527
+ @twitter.insert(:Users, k + '0', {'delete_me' => 'v0', 'keep_me' => 'v0'})
346
528
  @twitter.insert(:Users, k + '1', {'body' => 'v1', 'user' => 'v1'})
529
+ initial_subcolumns = {@uuids[1] => 'v1', @uuids[2] => 'v2'}
530
+ @twitter.insert(:StatusRelationships, k, {'user_timelines' => initial_subcolumns, 'dummy_supercolumn' => {@uuids[5] => 'value'}})
531
+ assert_equal(initial_subcolumns, @twitter.get(:StatusRelationships, k, 'user_timelines'))
532
+ assert_equal({@uuids[5] => 'value'}, @twitter.get(:StatusRelationships, k, 'dummy_supercolumn'))
533
+ new_subcolumns = {@uuids[3] => 'v3', @uuids[4] => 'v4'}
534
+ subcolumn_to_delete = initial_subcolumns.keys.first # the first column of the initial set
347
535
 
348
536
  @twitter.batch do
537
+ # Normal Columns
349
538
  @twitter.insert(:Users, k + '2', {'body' => 'v2', 'user' => 'v2'})
350
539
  @twitter.insert(:Users, k + '3', {'body' => 'bogus', 'user' => 'v3'})
351
540
  @twitter.insert(:Users, k + '3', {'body' => 'v3', 'location' => 'v3'})
352
541
  @twitter.insert(:Statuses, k + '3', {'body' => 'v'})
353
542
 
543
+ assert_equal({'delete_me' => 'v0', 'keep_me' => 'v0'}, @twitter.get(:Users, k + '0')) # Written
354
544
  assert_equal({'body' => 'v1', 'user' => 'v1'}, @twitter.get(:Users, k + '1')) # Written
355
545
  assert_equal({}, @twitter.get(:Users, k + '2')) # Not yet written
356
546
  assert_equal({}, @twitter.get(:Statuses, k + '3')) # Not yet written
357
547
 
358
- @twitter.remove(:Users, k + '1')
548
+ @twitter.remove(:Users, k + '1') # Full row
359
549
  assert_equal({'body' => 'v1', 'user' => 'v1'}, @twitter.get(:Users, k + '1')) # Not yet removed
360
550
 
551
+ @twitter.remove(:Users, k + '0', 'delete_me') # A single column of the row
552
+ assert_equal({'delete_me' => 'v0', 'keep_me' => 'v0'}, @twitter.get(:Users, k + '0')) # Not yet removed
553
+
361
554
  @twitter.remove(:Users, k + '4')
362
555
  @twitter.insert(:Users, k + '4', {'body' => 'v4', 'user' => 'v4'})
363
556
  assert_equal({}, @twitter.get(:Users, k + '4')) # Not yet written
557
+
558
+ # SuperColumns
559
+ # Add and delete new sub columns to the user timeline supercolumn
560
+ @twitter.insert(:StatusRelationships, k, {'user_timelines' => new_subcolumns })
561
+ @twitter.remove(:StatusRelationships, k, 'user_timelines' , subcolumn_to_delete ) # Delete the first of the initial_subcolumns from the user_timeline supercolumn
562
+ assert_equal(initial_subcolumns, @twitter.get(:StatusRelationships, k, 'user_timelines')) # No additions or deletes reflected yet
563
+ # Delete a complete supercolumn
564
+ @twitter.remove(:StatusRelationships, k, 'dummy_supercolumn' ) # Delete the full dummy supercolumn
565
+ assert_equal({@uuids[5] => 'value'}, @twitter.get(:StatusRelationships, k, 'dummy_supercolumn')) # dummy supercolumn not yet deleted
364
566
  end
365
567
 
366
568
  assert_equal({'body' => 'v2', 'user' => 'v2'}, @twitter.get(:Users, k + '2')) # Written
@@ -368,11 +570,20 @@ class CassandraTest < Test::Unit::TestCase
368
570
  assert_equal({'body' => 'v4', 'user' => 'v4'}, @twitter.get(:Users, k + '4')) # Written
369
571
  assert_equal({'body' => 'v'}, @twitter.get(:Statuses, k + '3')) # Written
370
572
  assert_equal({}, @twitter.get(:Users, k + '1')) # Removed
573
+
574
+ assert_equal({ 'keep_me' => 'v0'}, @twitter.get(:Users, k + '0')) # 'delete_me' column removed
575
+
371
576
 
372
577
  assert_equal({'body' => 'v2', 'user' => 'v2'}.keys.sort, @twitter.get(:Users, k + '2').timestamps.keys.sort) # Written
373
578
  assert_equal({'body' => 'v3', 'user' => 'v3', 'location' => 'v3'}.keys.sort, @twitter.get(:Users, k + '3').timestamps.keys.sort) # Written and compacted
374
579
  assert_equal({'body' => 'v4', 'user' => 'v4'}.keys.sort, @twitter.get(:Users, k + '4').timestamps.keys.sort) # Written
375
580
  assert_equal({'body' => 'v'}.keys.sort, @twitter.get(:Statuses, k + '3').timestamps.keys.sort) # Written
581
+
582
+ # Final result: initial_subcolumns - initial_subcolumns.first + new_subcolumns
583
+ resulting_subcolumns = initial_subcolumns.merge(new_subcolumns).reject{|k2,v| k2 == subcolumn_to_delete }
584
+ assert_equal(resulting_subcolumns, @twitter.get(:StatusRelationships, key, 'user_timelines'))
585
+ assert_equal({}, @twitter.get(:StatusRelationships, key, 'dummy_supercolumn')) # dummy supercolumn deleted
586
+
376
587
  end
377
588
 
378
589
  def test_complain_about_nil_key
@@ -381,15 +592,8 @@ class CassandraTest < Test::Unit::TestCase
381
592
  end
382
593
  end
383
594
 
384
- def test_raise_access_error_on_nonexistent_keyspace
385
- nonexistent = Cassandra.new('Nonexistent')
386
- assert_raises(Cassandra::AccessError) do
387
- nonexistent.get "foo", "bar"
388
- end
389
- end
390
-
391
595
  def test_nil_sub_column_value
392
- @twitter.insert(:Index, 'asdf', {"thing" => {'jkl' => ''} })
596
+ @twitter.insert(:Indexes, 'asdf', {"thing" => {'jkl' => ''} })
393
597
  end
394
598
 
395
599
  def test_disconnect!
@@ -397,6 +601,13 @@ class CassandraTest < Test::Unit::TestCase
397
601
  assert_nil @twitter.instance_variable_get(:@client)
398
602
  end
399
603
 
604
+ def test_disconnect_when_not_connected!
605
+ assert_nothing_raised do
606
+ @twitter = Cassandra.new('Twitter', "127.0.0.1:9160", :retries => 2, :exception_classes => [])
607
+ @twitter.disconnect!
608
+ end
609
+ end
610
+
400
611
  def test_super_allows_for_non_string_values_while_normal_does_not
401
612
  columns = {'user_timelines' => {@uuids[4] => '4', @uuids[5] => '5'}}
402
613
 
@@ -404,6 +615,216 @@ class CassandraTest < Test::Unit::TestCase
404
615
  @twitter.insert(:Statuses, key, { 'body' => '1' })
405
616
  end
406
617
 
618
+ def test_batch_over_deletes
619
+ k = key
620
+
621
+ @twitter.batch do
622
+ @twitter.insert(:Users, k, {'body' => 'body', 'user' => 'user'})
623
+ @twitter.remove(:Users, k, 'body')
624
+ end
625
+
626
+ assert_equal({'user' => 'user'}, @twitter.get(:Users, k))
627
+ end
628
+
629
+ def test_each_key
630
+ num_users = rand(60)
631
+ num_users.times do |twit_counter|
632
+ @twitter.insert(:Users, "Twitter : #{twit_counter}", {'body' => 'v1', 'user' => 'v1'})
633
+ end
634
+ counter = 0
635
+ @twitter.each_key(:Users) do |_, _|
636
+ counter += 1
637
+ end
638
+ assert_equal num_users, counter
639
+ end
640
+
641
+ def test_each_with_column_predicate
642
+ num_users = rand(60)
643
+ num_users.times do |twit_counter|
644
+ @twitter.insert(:Users, "Twitter : #{twit_counter}", {'body' => 'v1', 'user' => 'v1'})
645
+ end
646
+ counter = 0
647
+ @twitter.each(:Users, :batch_size => 10, :start => 'body', :finish => 'body') do |key, columns|
648
+ assert_equal 1, columns.length
649
+ counter += 1
650
+ end
651
+ assert_equal num_users, counter
652
+ end
653
+
654
+ def test_each_with_super_column
655
+ num_users = rand(50)
656
+ block_name = key
657
+ num_users.times do |twit_counter|
658
+ @twitter.insert(:StatusRelationships, block_name + twit_counter.to_s, {
659
+ 'user_timelines' => {@uuids[1] => 'v1', @uuids[2] => 'v2'},
660
+ 'mentions_timelines' => {@uuids[3] => 'v3'}})
661
+ end
662
+
663
+ counter = 0
664
+ # Restrict to one super column ::
665
+ @twitter.each(:StatusRelationships, :batch_size => 10, :start => 'user_timelines', :finish => 'user_timelines') do |key, columns|
666
+ columns.each do |_, column_value|
667
+ assert_equal 2, column_value.length
668
+ end
669
+ counter += 1
670
+ end
671
+
672
+ #Both super columns
673
+ @twitter.each(:StatusRelationships, :batch_size => 10, :start => 'mentions_timelines', :finish => 'user_timelines') do |key,columns|
674
+ assert_equal 2, columns.length
675
+ counter += 1
676
+ end
677
+
678
+ assert_equal num_users*2, counter
679
+
680
+ end
681
+
682
+ def test_each_column_types
683
+ num_users = rand(60)
684
+ num_users.times do |twit_counter|
685
+ @type_conversions.insert(:UUIDColumnConversion, twit_counter.to_s, {@uuids[1] => 'v1'})
686
+ end
687
+ counter = 0
688
+ @type_conversions.each(:UUIDColumnConversion) do |_, columns|
689
+ counter += 1
690
+ columns.keys.each {|column_name| assert_equal SimpleUUID::UUID, column_name.class}
691
+ end
692
+ assert_equal num_users, counter
693
+ end
694
+
695
+
696
+ if CASSANDRA_VERSION.to_f >= 0.7
697
+ def test_creating_and_dropping_new_index
698
+ @twitter.create_index('Twitter', 'Statuses', 'column_name', 'LongType')
699
+ assert_nil @twitter.create_index('Twitter', 'Statuses', 'column_name', 'LongType')
700
+
701
+ @twitter.drop_index('Twitter', 'Statuses', 'column_name')
702
+ assert_nil @twitter.drop_index('Twitter', 'Statuses', 'column_name')
703
+
704
+ # Recreating and redropping the same index should not error either.
705
+ @twitter.create_index('Twitter', 'Statuses', 'column_name', 'LongType')
706
+ @twitter.drop_index('Twitter', 'Statuses', 'column_name')
707
+ end
708
+
709
+ def test_get_indexed_slices
710
+ @twitter.create_index('Twitter', 'Statuses', 'x', 'LongType')
711
+
712
+ @twitter.insert(:Statuses, 'row1', { 'x' => [0,10].pack("NN") })
713
+
714
+ (2..10).to_a.each do |i|
715
+ @twitter.insert(:Statuses, 'row' + i.to_s, { 'x' => [0,20].pack("NN"), 'non_indexed' => [i].pack('N*') })
716
+ end
717
+
718
+ @twitter.insert(:Statuses, 'row11', { 'x' => [0,30].pack("NN") })
719
+
720
+ expressions = [{:column_name => 'x', :value => [0,20].pack("NN"), :comparison => "=="}]
721
+
722
+ # verify multiples will be returned
723
+ assert_equal 9, @twitter.get_indexed_slices(:Statuses, expressions).length
724
+
725
+ # verify that GT and LT queries perform properly
726
+ expressions = [
727
+ {:column_name => 'x', :value => [0,20].pack("NN"), :comparison => "=="},
728
+ {:column_name => 'non_indexed', :value => [5].pack("N*"), :comparison => ">"}
729
+ ]
730
+ assert_equal(5, @twitter.get_indexed_slices(:Statuses, expressions).length)
731
+ end
732
+
733
+ def test_old_get_indexed_slices
734
+ @twitter.create_index('Twitter', 'Statuses', 'x', 'LongType')
735
+
736
+ @twitter.insert(:Statuses, 'row1', { 'x' => [0,10].pack("NN") })
737
+
738
+ (2..10).to_a.each do |i|
739
+ @twitter.insert(:Statuses, 'row' + i.to_s, { 'x' => [0,20].pack("NN"), 'non_indexed' => [i].pack('N*') })
740
+ end
741
+
742
+ @twitter.insert(:Statuses, 'row11', { 'x' => [0,30].pack("NN") })
743
+
744
+ idx_expr = @twitter.create_idx_expr('x', [0,20].pack("NN"), "==")
745
+
746
+ # verify count is observed
747
+ idx_clause = @twitter.create_idx_clause([idx_expr], "", 1)
748
+ assert_equal 1, @twitter.get_indexed_slices(:Statuses, idx_clause).length
749
+
750
+ # verify multiples will be returned
751
+ idx_clause = @twitter.create_idx_clause([idx_expr])
752
+ assert_equal 9, @twitter.get_indexed_slices(:Statuses, idx_clause).length
753
+
754
+ # verify that GT and LT queries perform properly
755
+ idx_expr = [
756
+ @twitter.create_idx_expr('x', [0,20].pack("NN"), "=="),
757
+ @twitter.create_idx_expr('non_indexed', [5].pack("N*"), ">")
758
+ ]
759
+ idx_clause = @twitter.create_idx_clause(idx_expr)
760
+ assert_equal(5, @twitter.get_indexed_slices(:Statuses, idx_clause).length)
761
+ end
762
+
763
+ def test_column_family_mutation
764
+ k = key
765
+
766
+ if @twitter.column_families.include?(k)
767
+ @twitter.drop_column_family(k)
768
+ end
769
+
770
+ # Verify add_column_family works as desired.
771
+ @twitter.add_column_family(
772
+ Cassandra::ColumnFamily.new(
773
+ :keyspace => 'Twitter',
774
+ :name => k
775
+ )
776
+ )
777
+ assert @twitter.column_families.include?(k)
778
+
779
+ if CASSANDRA_VERSION.to_f == 0.7
780
+ # Verify rename_column_family works properly
781
+ @twitter.rename_column_family(k, k + '_renamed')
782
+ assert @twitter.column_families.include?(k + '_renamed')
783
+
784
+ # Change it back and validate
785
+ @twitter.rename_column_family(k + '_renamed', k)
786
+ assert @twitter.column_families.include?(k)
787
+ end
788
+
789
+ temp_cf_def = @twitter.column_families[k]
790
+ temp_cf_def.comment = k
791
+ @twitter.update_column_family(temp_cf_def)
792
+ assert @twitter.column_families.include?(k)
793
+
794
+ @twitter.drop_column_family(k)
795
+ assert !@twitter.column_families.include?(k)
796
+ end
797
+ end
798
+
799
+ if CASSANDRA_VERSION.to_f >= 0.8
800
+ def test_adding_getting_value_in_counter
801
+ assert_nil @twitter.add(:UserCounters, 'bob', 5, 'tweet_count')
802
+ assert_equal(5, @twitter.get(:UserCounters, 'bob', 'tweet_count'))
803
+ assert_nil @twitter.get(:UserCounters, 'bogus', 'tweet_count')
804
+ end
805
+
806
+ def test_get_counter_slice
807
+ assert_nil @twitter.add(:UserCounters, 'bob', 5, 'tweet_count')
808
+ assert_equal({'tweet_count' => 5}, @twitter.get(:UserCounters, 'bob', :start => "tweet_count", :finish => "tweet_count"))
809
+ end
810
+
811
+ def test_adding_getting_value_in_multiple_counters
812
+ assert_nil @twitter.add(:UserCounters, 'bob', 5, 'tweet_count')
813
+ assert_nil @twitter.add(:UserCounters, 'bob', 7, 'follower_count')
814
+ assert_equal(5, @twitter.get(:UserCounters, 'bob', 'tweet_count'))
815
+ assert_nil @twitter.get(:UserCounters, 'bogus', 'tweet_count')
816
+ assert_equal([5, 7], @twitter.get_columns(:UserCounters, 'bob', ['tweet_count', 'follower_count']))
817
+ assert_equal([5, 7, nil], @twitter.get_columns(:UserCounters, 'bob', ['tweet_count', 'follower_count', 'bogus']))
818
+ end
819
+
820
+ def test_adding_getting_value_in_multiple_counters_with_super_columns
821
+ assert_nil @twitter.add(:UserCounterAggregates, 'bob', 1, 'DAU', 'today')
822
+ assert_nil @twitter.add(:UserCounterAggregates, 'bob', 2, 'DAU', 'tomorrow')
823
+ assert_equal(1, @twitter.get(:UserCounterAggregates, 'bob', 'DAU', 'today'))
824
+ assert_equal(2, @twitter.get(:UserCounterAggregates, 'bob', 'DAU', 'tomorrow'))
825
+ end
826
+ end
827
+
407
828
  private
408
829
 
409
830
  def key
File without changes