hallelujah-cassandra 0.12.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (92) hide show
  1. data/CHANGELOG +111 -0
  2. data/Gemfile +8 -0
  3. data/LICENSE +202 -0
  4. data/Manifest +91 -0
  5. data/README.md +352 -0
  6. data/Rakefile +171 -0
  7. data/bin/cassandra_helper +16 -0
  8. data/conf/0.6/cassandra.in.sh +47 -0
  9. data/conf/0.6/log4j.properties +38 -0
  10. data/conf/0.6/schema.json +57 -0
  11. data/conf/0.6/storage-conf.xml +352 -0
  12. data/conf/0.7/cassandra.in.sh +46 -0
  13. data/conf/0.7/cassandra.yaml +336 -0
  14. data/conf/0.7/log4j-server.properties +41 -0
  15. data/conf/0.7/schema.json +57 -0
  16. data/conf/0.7/schema.txt +45 -0
  17. data/conf/0.8/cassandra.in.sh +41 -0
  18. data/conf/0.8/cassandra.yaml +61 -0
  19. data/conf/0.8/log4j-server.properties +40 -0
  20. data/conf/0.8/schema.json +69 -0
  21. data/conf/0.8/schema.txt +51 -0
  22. data/conf/1.0/cassandra.in.sh +41 -0
  23. data/conf/1.0/cassandra.yaml +415 -0
  24. data/conf/1.0/log4j-server.properties +40 -0
  25. data/conf/1.0/schema.json +69 -0
  26. data/conf/1.0/schema.txt +51 -0
  27. data/conf/1.1/cassandra.in.sh +41 -0
  28. data/conf/1.1/cassandra.yaml +560 -0
  29. data/conf/1.1/log4j-server.properties +44 -0
  30. data/conf/1.1/schema.json +69 -0
  31. data/conf/1.1/schema.txt +51 -0
  32. data/hallelujah-cassandra.gemspec +43 -0
  33. data/lib/cassandra.rb +39 -0
  34. data/lib/cassandra/0.6.rb +7 -0
  35. data/lib/cassandra/0.6/cassandra.rb +113 -0
  36. data/lib/cassandra/0.6/columns.rb +78 -0
  37. data/lib/cassandra/0.6/protocol.rb +90 -0
  38. data/lib/cassandra/0.7.rb +7 -0
  39. data/lib/cassandra/0.7/cassandra.rb +2 -0
  40. data/lib/cassandra/0.7/columns.rb +4 -0
  41. data/lib/cassandra/0.7/protocol.rb +5 -0
  42. data/lib/cassandra/0.8.rb +7 -0
  43. data/lib/cassandra/0.8/cassandra.rb +25 -0
  44. data/lib/cassandra/0.8/columns.rb +28 -0
  45. data/lib/cassandra/0.8/protocol.rb +10 -0
  46. data/lib/cassandra/1.0.rb +7 -0
  47. data/lib/cassandra/1.0/cassandra.rb +25 -0
  48. data/lib/cassandra/1.0/columns.rb +28 -0
  49. data/lib/cassandra/1.0/protocol.rb +12 -0
  50. data/lib/cassandra/1.1.rb +6 -0
  51. data/lib/cassandra/1.1/cassandra.rb +25 -0
  52. data/lib/cassandra/1.1/columns.rb +28 -0
  53. data/lib/cassandra/1.1/protocol.rb +12 -0
  54. data/lib/cassandra/array.rb +8 -0
  55. data/lib/cassandra/cassandra.rb +1070 -0
  56. data/lib/cassandra/column_family.rb +3 -0
  57. data/lib/cassandra/columns.rb +147 -0
  58. data/lib/cassandra/comparable.rb +28 -0
  59. data/lib/cassandra/composite.rb +118 -0
  60. data/lib/cassandra/constants.rb +11 -0
  61. data/lib/cassandra/debug.rb +9 -0
  62. data/lib/cassandra/helpers.rb +41 -0
  63. data/lib/cassandra/keyspace.rb +3 -0
  64. data/lib/cassandra/long.rb +58 -0
  65. data/lib/cassandra/mock.rb +511 -0
  66. data/lib/cassandra/ordered_hash.rb +192 -0
  67. data/lib/cassandra/protocol.rb +120 -0
  68. data/lib/cassandra/time.rb +11 -0
  69. data/test/cassandra_client_test.rb +20 -0
  70. data/test/cassandra_mock_test.rb +122 -0
  71. data/test/cassandra_test.rb +922 -0
  72. data/test/comparable_types_test.rb +45 -0
  73. data/test/composite_type_test.rb +29 -0
  74. data/test/eventmachine_test.rb +42 -0
  75. data/test/ordered_hash_test.rb +386 -0
  76. data/test/test_helper.rb +15 -0
  77. data/vendor/0.6/gen-rb/cassandra.rb +1481 -0
  78. data/vendor/0.6/gen-rb/cassandra_constants.rb +12 -0
  79. data/vendor/0.6/gen-rb/cassandra_types.rb +482 -0
  80. data/vendor/0.7/gen-rb/cassandra.rb +1936 -0
  81. data/vendor/0.7/gen-rb/cassandra_constants.rb +12 -0
  82. data/vendor/0.7/gen-rb/cassandra_types.rb +681 -0
  83. data/vendor/0.8/gen-rb/cassandra.rb +2215 -0
  84. data/vendor/0.8/gen-rb/cassandra_constants.rb +12 -0
  85. data/vendor/0.8/gen-rb/cassandra_types.rb +824 -0
  86. data/vendor/1.0/gen-rb/cassandra.rb +2215 -0
  87. data/vendor/1.0/gen-rb/cassandra_constants.rb +12 -0
  88. data/vendor/1.0/gen-rb/cassandra_types.rb +857 -0
  89. data/vendor/1.1/gen-rb/cassandra.rb +2571 -0
  90. data/vendor/1.1/gen-rb/cassandra_constants.rb +12 -0
  91. data/vendor/1.1/gen-rb/cassandra_types.rb +928 -0
  92. metadata +260 -0
@@ -0,0 +1,922 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/test_helper')
2
+
3
+ class CassandraTest < Test::Unit::TestCase
4
+ include Cassandra::Constants
5
+
6
+ def setup
7
+ @twitter = Cassandra.new('Twitter', "127.0.0.1:9160", :retries => 2, :connect_timeout => 0.1, :exception_classes => [])
8
+ @twitter.clear_keyspace!
9
+
10
+ @blogs = Cassandra.new('Multiblog', "127.0.0.1:9160", :retries => 2, :connect_timeout => 0.1, :exception_classes => [])
11
+ @blogs.clear_keyspace!
12
+
13
+ @blogs_long = Cassandra.new('MultiblogLong', "127.0.0.1:9160", :retries => 2, :connect_timeout => 0.1, :exception_classes => [])
14
+ @blogs_long.clear_keyspace!
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
+
22
+ @uuids = (0..6).map {|i| SimpleUUID::UUID.new(Time.at(2**(24+i))) }
23
+ @longs = (0..6).map {|i| Long.new(Time.at(2**(24+i))) }
24
+ @composites = [
25
+ Cassandra::Composite.new([5].pack('N'), "zebra"),
26
+ Cassandra::Composite.new([5].pack('N'), "aardvark"),
27
+ Cassandra::Composite.new([1].pack('N'), "elephant"),
28
+ Cassandra::Composite.new([10].pack('N'), "kangaroo"),
29
+ ]
30
+ end
31
+
32
+ def test_inspect
33
+ assert_nothing_raised do
34
+ @blogs.inspect
35
+ @twitter.inspect
36
+ end
37
+ end
38
+
39
+ def test_setting_default_consistency
40
+ assert_nothing_raised do
41
+ @twitter.default_read_consistency = Cassandra::Consistency::ALL
42
+ end
43
+ assert_equal(Cassandra::READ_DEFAULTS[:consistency], Cassandra::Consistency::ALL)
44
+
45
+ assert_nothing_raised do
46
+ @twitter.default_write_consistency = Cassandra::Consistency::ALL
47
+ end
48
+ assert_equal(Cassandra::WRITE_DEFAULTS[:consistency], Cassandra::Consistency::ALL)
49
+ end
50
+
51
+ def test_get_key
52
+
53
+ @twitter.insert(:Users, key, {'body' => 'v', 'user' => 'v'})
54
+ assert_equal({'body' => 'v', 'user' => 'v'}, @twitter.get(:Users, key))
55
+ assert_equal(['body', 'user'].sort, @twitter.get(:Users, key).timestamps.keys.sort)
56
+ assert_equal({}, @twitter.get(:Users, 'bogus'))
57
+ end
58
+
59
+ def test_get_single_column_returns_single_value
60
+ @twitter.insert(:Users, key, {'body' => 'body_text', 'user' => 'user_name'})
61
+ assert_equal('body_text', @twitter.get(:Users, key, 'body'))
62
+ assert_equal('user_name', @twitter.get(:Users, key, 'user'))
63
+
64
+ @blogs.insert(:Blogs, key,
65
+ {@uuids[0] => 'I like this cat', @uuids[1] => 'Buttons is cuter', @uuids[2] => 'I disagree'})
66
+
67
+ assert_equal('I like this cat', @blogs.get(:Blogs, key, @uuids[0]))
68
+ end
69
+
70
+ def test_get_key_preserving_order
71
+ # In-order hash is preserved
72
+ hash = OrderedHash['a', '', 'b', '', 'c', '', 'd', '',]
73
+ @twitter.insert(:Users, key, hash)
74
+ assert_equal(hash.keys, @twitter.get(:Users, key).keys)
75
+
76
+ @twitter.remove(:Users, key)
77
+
78
+ # Out-of-order hash is returned sorted
79
+ hash = OrderedHash['b', '', 'c', '', 'd', '', 'a', '']
80
+ @twitter.insert(:Users, key, hash)
81
+ assert_equal(hash.keys.sort, @twitter.get(:Users, key).keys)
82
+ assert_equal(hash.timestamps.keys.sort, @twitter.get(:Users, key).timestamps.keys)
83
+ assert_not_equal(hash.keys, @twitter.get(:Users, key).keys)
84
+ end
85
+
86
+ def test_get_first_time_uuid_column
87
+ @blogs.insert(:Blogs, key,
88
+ {@uuids[0] => 'I like this cat', @uuids[1] => 'Buttons is cuter', @uuids[2] => 'I disagree'})
89
+
90
+ assert_equal({@uuids[0] => 'I like this cat'}, @blogs.get(:Blogs, key, :count => 1))
91
+ assert_equal({@uuids[2] => 'I disagree'}, @blogs.get(:Blogs, key, :count => 1, :reversed => true))
92
+ assert_equal({}, @blogs.get(:Blogs, 'bogus'))
93
+ end
94
+
95
+ def test_get_multiple_time_uuid_columns
96
+ @blogs.insert(:Blogs, key,
97
+ {@uuids[0] => 'I like this cat', @uuids[1] => 'Buttons is cuter', @uuids[2] => 'I disagree'})
98
+
99
+ assert_equal(['I like this cat', 'Buttons is cuter'], @blogs.get_columns(:Blogs, key, @uuids[0..1]))
100
+ end
101
+
102
+ def test_get_first_long_column
103
+ @blogs_long.insert(:Blogs, key,
104
+ {@longs[0] => 'I like this cat', @longs[1] => 'Buttons is cuter', @longs[2] => 'I disagree'})
105
+
106
+ assert_equal({@longs[0] => 'I like this cat'}, @blogs_long.get(:Blogs, key, :count => 1))
107
+ assert_equal({@longs[2] => 'I disagree'}, @blogs_long.get(:Blogs, key, :count => 1, :reversed => true))
108
+ assert_equal({}, @blogs_long.get(:Blogs, 'bogus'))
109
+
110
+ assert_equal([@longs[0]], @blogs_long.get(:Blogs, key, :count => 1).timestamps.keys)
111
+ assert_equal([@longs[2]], @blogs_long.get(:Blogs, key, :count => 1, :reversed => true).timestamps.keys)
112
+ end
113
+
114
+ def test_long_remove_bug
115
+ @blogs_long.insert(:Blogs, key, {@longs[0] => 'I like this cat'})
116
+ @blogs_long.remove(:Blogs, key)
117
+ assert_equal({}, @blogs_long.get(:Blogs, key, :count => 1))
118
+
119
+ @blogs_long.insert(:Blogs, key, {@longs[0] => 'I really like this cat'})
120
+ assert_equal({@longs[0] => 'I really like this cat'}, @blogs_long.get(:Blogs, key, :count => 1))
121
+ assert_equal([@longs[0]], @blogs_long.get(:Blogs, key, :count => 1).timestamps.keys)
122
+ end
123
+
124
+ def test_get_with_count
125
+ @twitter.insert(:Statuses, key, {'1' => 'v', '2' => 'v', '3' => 'v'})
126
+ assert_equal 1, @twitter.get(:Statuses, key, :count => 1).size
127
+ assert_equal 2, @twitter.get(:Statuses, key, :count => 2).size
128
+ assert_equal 1, @twitter.get(:Statuses, key, :count => 1).timestamps.size
129
+ assert_equal 2, @twitter.get(:Statuses, key, :count => 2).timestamps.size
130
+ end
131
+
132
+ def test_get_value
133
+ @twitter.insert(:Statuses, key, {'body' => 'v'})
134
+ assert_equal 'v', @twitter.get(:Statuses, key, 'body')
135
+ assert_nil @twitter.get(:Statuses, 'bogus', 'body')
136
+
137
+ assert @twitter.exists?(:Statuses, key, 'body')
138
+ assert !@twitter.exists?(:Statuses, 'bogus', 'body')
139
+ end
140
+
141
+ def test_get_value_with_range
142
+ k = key
143
+
144
+ 10.times do |i|
145
+ @twitter.insert(:Statuses, k, {"body-#{i}" => 'v'})
146
+ end
147
+
148
+ assert_equal 5, @twitter.get(:Statuses, k, :count => 5).length
149
+ assert_equal 5, @twitter.get(:Statuses, k, :start => "body-5").length
150
+ assert_equal 5, @twitter.get(:Statuses, k, :finish => "body-4").length
151
+ assert_equal 5, @twitter.get(:Statuses, k, :start => "body-1", :count => 5).length
152
+ assert_equal 5, @twitter.get(:Statuses, k, :start => "body-0", :finish => "body-4", :count => 7).length
153
+ end
154
+
155
+ def test_exists
156
+ @twitter.insert(:Statuses, key, {'body' => 'v'})
157
+ assert_equal true, @twitter.exists?(:Statuses, key)
158
+ assert_equal false, @twitter.exists?(:Statuses, 'bogus')
159
+
160
+ columns = {@uuids[1] => 'v1', @uuids[2] => 'v2'}
161
+ @twitter.insert(:StatusRelationships, key, {'user_timelines' => columns})
162
+
163
+ # verify return value when searching by key
164
+ assert_equal true, @twitter.exists?(:StatusRelationships, key)
165
+ assert_equal false, @twitter.exists?(:StatusRelationships, 'bogus')
166
+
167
+ # verify return value when searching by key and column
168
+ assert_equal true, @twitter.exists?(:StatusRelationships, key, 'user_timelines')
169
+ assert_equal false, @twitter.exists?(:StatusRelationships, key, 'bogus')
170
+
171
+ # verify return value when searching by key and column and subcolumn
172
+ assert_equal true, @twitter.exists?(:StatusRelationships, key, 'user_timelines', @uuids[1])
173
+ assert_equal false, @twitter.exists?(:StatusRelationships, key, 'user_timelines', @uuids[3])
174
+ end
175
+
176
+ def test_get_super_key
177
+ columns = {'user_timelines' => {@uuids[4] => '4', @uuids[5] => '5'}}
178
+ @twitter.insert(:StatusRelationships, key, columns)
179
+ assert_equal(columns, @twitter.get(:StatusRelationships, key))
180
+ assert_equal(columns.keys, @twitter.get(:StatusRelationships, key).timestamps.keys)
181
+ assert_equal({}, @twitter.get(:StatusRelationships, 'bogus'))
182
+ end
183
+
184
+ def test_get_several_super_keys
185
+ columns = OrderedHash[
186
+ 'mentions_timelines', {@uuids[2] => 'v2'},
187
+ 'user_timelines', {@uuids[1] => 'v1'}
188
+ ]
189
+
190
+ @twitter.insert(:StatusRelationships, key, columns)
191
+
192
+ assert_equal(columns, @twitter.get(:StatusRelationships, key))
193
+ assert_equal(columns.keys, @twitter.get(:StatusRelationships, key).timestamps.keys)
194
+ assert_equal({}, @twitter.get(:StatusRelationships, 'bogus'))
195
+ end
196
+
197
+ def test_get_super_sub_keys_with_count
198
+ @twitter.insert(:StatusRelationships, key,
199
+ {'user_timelines' => {@uuids[1] => 'v1', @uuids[2] => 'v2', @uuids[3] => 'v3'}})
200
+ assert_equal({@uuids[1] => 'v1'},
201
+ @twitter.get(:StatusRelationships, key, "user_timelines", :count => 1))
202
+ assert_equal({@uuids[3] => 'v3'},
203
+ @twitter.get(:StatusRelationships, key, "user_timelines", :count => 1, :reversed => true))
204
+ assert_equal([@uuids[1]],
205
+ @twitter.get(:StatusRelationships, key, "user_timelines", :count => 1).timestamps.keys)
206
+ assert_equal([@uuids[3]],
207
+ @twitter.get(:StatusRelationships, key, "user_timelines", :count => 1, :reversed => true).timestamps.keys)
208
+ end
209
+
210
+ def test_get_super_sub_keys_with_ranges
211
+ @twitter.insert(:StatusRelationships, key,
212
+ {'user_timelines' => {
213
+ @uuids[1] => 'v1',
214
+ @uuids[2] => 'v2',
215
+ @uuids[3] => 'v3',
216
+ @uuids[4] => 'v4',
217
+ @uuids[5] => 'v5'}})
218
+
219
+ keys = @twitter.get(:StatusRelationships, key, "user_timelines").keys
220
+ assert_equal keys.sort, keys
221
+ assert_equal({@uuids[1] => 'v1'}, @twitter.get(:StatusRelationships, key, "user_timelines", :finish => @uuids[2], :count => 1))
222
+ assert_equal({@uuids[2] => 'v2'}, @twitter.get(:StatusRelationships, key, "user_timelines", :start => @uuids[2], :count => 1))
223
+ assert_equal 4, @twitter.get(:StatusRelationships, key, "user_timelines", :start => @uuids[2], :finish => @uuids[5]).size
224
+ assert_equal([@uuids[1]], @twitter.get(:StatusRelationships, key, "user_timelines", :finish => @uuids[2], :count => 1).timestamps.keys)
225
+ assert_equal([@uuids[2]], @twitter.get(:StatusRelationships, key, "user_timelines", :start => @uuids[2], :count => 1).timestamps.keys)
226
+ assert_equal 4, @twitter.get(:StatusRelationships, key, "user_timelines", :start => @uuids[2], :finish => @uuids[5]).timestamps.size
227
+ end
228
+
229
+ def test_get_super_sub_key
230
+ columns = {@uuids[1] => 'v1', @uuids[2] => 'v2'}
231
+ @twitter.insert(:StatusRelationships, key, {'user_timelines' => columns})
232
+ assert_equal(columns, @twitter.get(:StatusRelationships, key, 'user_timelines'))
233
+ assert_equal(columns.keys.sort, @twitter.get(:StatusRelationships, key, 'user_timelines').timestamps.keys.sort)
234
+ assert_equal({}, @twitter.get(:StatusRelationships, 'bogus', 'user_timelines'))
235
+ # FIXME Not sure if this is valid
236
+ assert_equal false, @twitter.exists?(:StatusRelationships, 'bogus', 'user_timelines')
237
+ end
238
+
239
+ def test_get_super_value
240
+ columns = {@uuids[1] => 'v1'}
241
+ @twitter.insert(:StatusRelationships, key, {'user_timelines' => columns})
242
+ assert_equal('v1', @twitter.get(:StatusRelationships, key, 'user_timelines', columns.keys.first))
243
+ assert_nil @twitter.get(:StatusRelationships, 'bogus', 'user_timelines', columns.keys.first)
244
+ end
245
+
246
+ # def test_get_range_with_key_range
247
+ # skip('This test requires the use of OrderPreservingPartitioner on the cluster to work properly.')
248
+ # k = key
249
+ # @twitter.insert(:Statuses, k + '2', {'body' => '1'})
250
+ # @twitter.insert(:Statuses, k + '3', {'body' => '1'})
251
+ # @twitter.insert(:Statuses, k + '4', {'body' => '1'})
252
+ # @twitter.insert(:Statuses, k + '5', {'body' => '1'})
253
+ # @twitter.insert(:Statuses, k + '6', {'body' => '1'})
254
+ # assert_equal([k + '3', k + '4', k + '5'], @twitter.get_range(:Statuses, :start_key => k + '3', :finish_key => k + '5').keys)
255
+ # end
256
+
257
+ def test_get_range
258
+ # make sure that deleted rows are not included in the iteration
259
+ 10.times do |i|
260
+ @twitter.insert(:Statuses, i.to_s, {'body' => '1'})
261
+ @twitter.insert(:Statuses, i.to_s + '_delete_me', {'test' => 'value'})
262
+ @twitter.remove(:Statuses, i.to_s + '_delete_me')
263
+ end
264
+
265
+ assert_equal(4, @twitter.get_range_keys(:Statuses, :key_count => 4).size)
266
+ end
267
+
268
+ def test_get_range_with_count
269
+ @twitter.insert(:Statuses, key + '1', {'test_column1' => '1', 'test_column2' => '2', 'test_column3' => '2', 'deleted_column' => '1'})
270
+ @twitter.insert(:Statuses, key + '2', {'test_column4' => '3', 'test_column5' => '4', 'test_column6' => '2', 'deleted_column' => '2'})
271
+
272
+ @twitter.get_range(:Statuses, :count => 3) do |key, columns|
273
+ assert_equal columns.count, 3
274
+ end
275
+
276
+ assert_equal 2, @twitter.get_range(:Statuses, :start_key => key + '1', :finish_key => key + '1', :count => 2)[key + '1'].count
277
+
278
+ @twitter.remove(:Statuses, key + '1', 'deleted_column')
279
+ @twitter.remove(:Statuses, key + '2', 'deleted_column')
280
+
281
+ @twitter.get_range(:Statuses, :count => 2) do |key, columns|
282
+ assert_equal columns.count, 2
283
+ end
284
+
285
+ end
286
+
287
+ def test_get_range_block
288
+ k = key
289
+
290
+ values = {}
291
+ 5.times do |i|
292
+ values[k+i.to_s] = {"body-#{i.to_s}" => 'v'}
293
+ end
294
+
295
+ values.each {|key, columns| @twitter.insert(:Statuses, key, columns) }
296
+
297
+ returned_value = @twitter.get_range(:Statuses, :start_key => k.to_s, :key_count => 5) do |key,columns|
298
+ expected = values.delete(key)
299
+ assert_equal expected, columns
300
+ end
301
+
302
+ assert values.length < 5
303
+ assert_nil returned_value
304
+ end
305
+
306
+ def test_get_range_reversed
307
+ data = 3.times.map { |i| ["body-#{i.to_s}", "v"] }
308
+ hash = Cassandra::OrderedHash[data]
309
+ reversed_hash = Cassandra::OrderedHash[data.reverse]
310
+
311
+ @twitter.insert(:Statuses, "all-keys", hash)
312
+
313
+ columns = @twitter.get_range(:Statuses, :reversed => true)["all-keys"]
314
+ columns.each do |column|
315
+ assert_equal reversed_hash.shift, column
316
+ end
317
+ end
318
+
319
+ def test_get_range_with_start_key_and_key_count
320
+ hash = {"name" => "value"}
321
+ @twitter.insert(:Statuses, "a-key", hash)
322
+ @twitter.insert(:Statuses, "b-key", hash)
323
+ @twitter.insert(:Statuses, "c-key", hash)
324
+
325
+ results = @twitter.get_range(:Statuses, :start_key => "b-key", :key_count => 1)
326
+ assert_equal ["b-key"], results.keys
327
+ end
328
+
329
+ def test_each_key
330
+ k = key
331
+ keys_yielded = []
332
+
333
+ 10.times do |i|
334
+ @twitter.insert(:Statuses, k + i.to_s, {"body-#{i.to_s}" => 'v'})
335
+ end
336
+
337
+ # make sure that deleted rows are not included in the iteration
338
+ @twitter.insert(:Statuses, k + '_delete_me', {'test' => 'value'})
339
+ @twitter.remove(:Statuses, k + '_delete_me')
340
+
341
+ @twitter.each_key(:Statuses) do |key|
342
+ keys_yielded << key
343
+ end
344
+
345
+ assert_equal 10, keys_yielded.length
346
+ end
347
+
348
+ def test_each
349
+ k = key
350
+ key_columns = {}
351
+
352
+ 10.times do |i|
353
+ key_columns[k + i.to_s] = {"body-#{i.to_s}" => 'v', 'single_column_lookup' => "value = #{i.to_s}"}
354
+ @twitter.insert(:Statuses, k + i.to_s, key_columns[k + i.to_s])
355
+ end
356
+
357
+ keys_yielded = []
358
+ @twitter.each(:Statuses, :batch_size => 5) do |key, columns|
359
+ assert_equal key_columns[key], columns
360
+ keys_yielded << key
361
+ end
362
+
363
+ assert_equal 10, keys_yielded.length
364
+
365
+ keys_yielded = []
366
+ @twitter.each(:Statuses, :key_count => 7, :batch_size => 5) do |key, columns|
367
+ assert_equal key_columns[key], columns
368
+ keys_yielded << key
369
+ end
370
+
371
+ assert_equal 7, keys_yielded.length, 'each limits to specified count'
372
+
373
+ keys_yielded = []
374
+ @twitter.each(:Statuses, :columns => ['single_column_lookup'], :batch_size => 5) do |key, columns|
375
+ assert_equal key_columns[key].reject {|k2,v| k2 != 'single_column_lookup'}, columns
376
+ keys_yielded << key
377
+ end
378
+
379
+ assert_equal 10, keys_yielded.length
380
+ end
381
+
382
+ def test_multi_get
383
+ @twitter.insert(:Users, key + '1', {'body' => 'v1', 'user' => 'v1'})
384
+ @twitter.insert(:Users, key + '2', {'body' => 'v2', 'user' => 'v2'})
385
+
386
+ expected = OrderedHash[key + '1', {'body' => 'v1', 'user' => 'v1'}, key + '2', {'body' => 'v2', 'user' => 'v2'}, 'bogus', {}]
387
+ result = @twitter.multi_get(:Users, [key + '1', key + '2', 'bogus'])
388
+ assert_equal expected, result
389
+ assert_equal expected.keys, result.keys
390
+ assert_equal expected.keys.sort, @twitter.multi_get(:Users, [key + '1', key + '2', 'bogus']).timestamps.keys.sort
391
+
392
+ expected = OrderedHash[key + '2', {'body' => 'v2', 'user' => 'v2'}, 'bogus', {}, key + '1', {'body' => 'v1', 'user' => 'v1'}]
393
+ result = @twitter.multi_get(:Users, [key + '2', 'bogus', key + '1'])
394
+ assert_equal expected, result
395
+ assert_equal expected.keys, result.keys
396
+ assert_equal expected.keys.sort, @twitter.multi_get(:Users, [key + '2', 'bogus', key + '1']).timestamps.keys.sort
397
+ end
398
+
399
+ def test_remove_key
400
+ @twitter.insert(:Statuses, key, {'body' => 'v'})
401
+ assert_equal({'body' => 'v'}, @twitter.get(:Statuses, key))
402
+
403
+ @twitter.remove(:Statuses, key)
404
+ assert_equal({}, @twitter.get(:Statuses, key))
405
+ end
406
+
407
+ def test_remove_super_sub_key_errors_for_normal_column_family
408
+ @twitter.insert(:Statuses, key, {'body' => 'v'})
409
+ assert_equal({'body' => 'v'}, @twitter.get(:Statuses, key))
410
+
411
+ assert_raise( ArgumentError) { @twitter.remove(:Statuses, key, 'body' , 'subcolumn') }
412
+ end
413
+
414
+ def test_remove_value
415
+ @twitter.insert(:Statuses, key, {'body' => 'v'})
416
+ @twitter.remove(:Statuses, key, 'body')
417
+ assert_nil @twitter.get(:Statuses, key, 'body')
418
+ assert_nil @twitter.get(:Statuses, key).timestamps['body']
419
+ end
420
+
421
+ def test_remove_super_key
422
+ @twitter.insert(:StatusRelationships, key, {'user_timelines' => {@uuids[1] => 'v1'}})
423
+ @twitter.remove(:StatusRelationships, key)
424
+ assert_equal({}, @twitter.get(:StatusRelationships, key))
425
+ end
426
+
427
+ def test_remove_super_sub_key
428
+ @twitter.insert(:StatusRelationships, key, {'user_timelines' => {@uuids[1] => 'v1'}})
429
+ @twitter.remove(:StatusRelationships, key, 'user_timelines')
430
+ assert_equal({}, @twitter.get(:StatusRelationships, key, 'user_timelines'))
431
+ end
432
+
433
+ def test_remove_super_value
434
+ columns = {@uuids[1] => 'v1', @uuids[2] => 'v2'}
435
+ column_name_to_remove = @uuids[2]
436
+ @twitter.insert(:StatusRelationships, key, {'user_timelines' => columns})
437
+ @twitter.remove(:StatusRelationships, key, 'user_timelines', column_name_to_remove)
438
+ assert_equal( columns.reject{|k,v| k == column_name_to_remove}, @twitter.get(:StatusRelationships, key, 'user_timelines') )
439
+ assert_nil @twitter.get(:StatusRelationships, key, 'user_timelines').timestamps[column_name_to_remove]
440
+ end
441
+
442
+ def test_clear_column_family
443
+ @twitter.insert(:Statuses, key + "1", {'body' => '1'})
444
+ @twitter.insert(:Statuses, key + "2", {'body' => '2'})
445
+ @twitter.insert(:Statuses, key + "3", {'body' => '3'})
446
+ @twitter.clear_column_family!(:Statuses)
447
+ assert_equal 0, @twitter.count_range(:Statuses)
448
+ end
449
+
450
+ def test_insert_key
451
+ @twitter.insert(:Statuses, key, {'body' => 'v', 'user' => 'v'})
452
+ assert_equal({'body' => 'v', 'user' => 'v'}, @twitter.get(:Statuses, key))
453
+ assert_equal(['body', 'user'], @twitter.get(:Statuses, key).timestamps.keys)
454
+ end
455
+
456
+ def test_insert_super_key
457
+ columns = {@uuids[1] => 'v1', @uuids[2] => 'v2'}
458
+ @twitter.insert(:StatusRelationships, key, {'user_timelines' => columns})
459
+ assert_equal(columns, @twitter.get(:StatusRelationships, key, 'user_timelines'))
460
+ assert_equal(columns.keys.sort, @twitter.get(:StatusRelationships, key, 'user_timelines').timestamps.keys.sort)
461
+ end
462
+
463
+ def test_get_columns
464
+ @twitter.insert(:Statuses, key, {'body' => 'v1', 'user' => 'v2'})
465
+ assert_equal(['v1' , 'v2'], @twitter.get_columns(:Statuses, key, ['body', 'user']))
466
+ end
467
+
468
+ def test_get_column_values_super
469
+ user_columns, mentions_columns = {@uuids[1] => 'v1'}, {@uuids[2] => 'v2'}
470
+ @twitter.insert(:StatusRelationships, key,
471
+ {'user_timelines' => user_columns, 'mentions_timelines' => mentions_columns})
472
+ assert_equal [user_columns, mentions_columns],
473
+ @twitter.get_columns(:StatusRelationships, key, ['user_timelines', 'mentions_timelines'])
474
+ end
475
+
476
+ def test_get_sub_column_values_super
477
+ user_columns = {@uuids[1] => 'v1', @uuids[2] => 'v2'}
478
+ @twitter.insert(:StatusRelationships, key, {'user_timelines' => user_columns})
479
+ assert_equal ['v1', 'v2'],
480
+ @twitter.get_columns(:StatusRelationships, key, 'user_timelines', @uuids[1..2])
481
+ end
482
+
483
+ def test_multi_get_columns
484
+ @twitter.insert(:Users, key + '1', {'body' => 'v1', 'user' => 'v1'})
485
+ @twitter.insert(:Users, key + '2', {'body' => 'v2', 'user' => 'v2'})
486
+ assert_equal(
487
+ OrderedHash[key + '1', ['v1', 'v1'], key + '2', ['v2', 'v2'], 'bogus', [nil, nil]],
488
+ @twitter.multi_get_columns(:Users, [key + '1', key + '2', 'bogus'], ['body', 'user']))
489
+ assert_equal(
490
+ OrderedHash[key + '2', ['v2', 'v2'], 'bogus', [nil, nil], key + '1', ['v1', 'v1']],
491
+ @twitter.multi_get_columns(:Users, [key + '2', 'bogus', key + '1'], ['body', 'user']))
492
+ assert_equal(
493
+ OrderedHash[key + '1', ['v1', 'v1'], key + '2', ['v2', 'v2'], 'bogus', [nil, nil]].keys.sort,
494
+ @twitter.multi_get_columns(:Users, [key + '1', key + '2', 'bogus'], ['body', 'user']).timestamps.keys.sort)
495
+ assert_equal(
496
+ OrderedHash[key + '2', ['v2', 'v2'], 'bogus', [nil, nil], key + '1', ['v1', 'v1']].keys.sort,
497
+ @twitter.multi_get_columns(:Users, [key + '2', 'bogus', key + '1'], ['body', 'user']).timestamps.keys.sort)
498
+ end
499
+
500
+ def test_count_keys
501
+ k = key
502
+ @twitter.insert(:Statuses, k + "1", {'body' => '1'})
503
+ @twitter.insert(:Statuses, k + "2", {'body' => '2'})
504
+ @twitter.insert(:Statuses, k + "3", {'body' => '3'})
505
+ assert_equal 3, @twitter.count_range(:Statuses)
506
+ end
507
+
508
+ def test_count_columns
509
+ columns = (1..200).inject(Hash.new){|h,v| h['column' + v.to_s] = v.to_s; h;}
510
+
511
+ @twitter.insert(:Statuses, key, columns)
512
+ assert_equal 200, @twitter.count_columns(:Statuses, key, :count => 200)
513
+ assert_equal 100, @twitter.count_columns(:Statuses, key)
514
+ assert_equal 55, @twitter.count_columns(:Statuses, key, :count => 55)
515
+
516
+ end
517
+
518
+ def test_count_super_columns
519
+ @twitter.insert(:StatusRelationships, key, {
520
+ 'user_timelines' => {@uuids[1] => 'v1'},
521
+ 'mentions_timelines' => {@uuids[2] => 'v2'}})
522
+ assert_equal 2, @twitter.count_columns(:StatusRelationships, key)
523
+ end
524
+
525
+ def test_count_super_sub_columns
526
+ @twitter.insert(:StatusRelationships, key, {'user_timelines' => {@uuids[1] => 'v1', @uuids[2] => 'v2'}})
527
+ assert_equal 2, @twitter.count_columns(:StatusRelationships, key, 'user_timelines')
528
+ end
529
+
530
+ def test_multi_count_columns
531
+ @twitter.insert(:Users, key + '1', {'body' => 'v1', 'user' => 'v1'})
532
+ @twitter.insert(:Users, key + '2', {'body' => 'v2', 'user' => 'v2'})
533
+ assert_equal(
534
+ OrderedHash[key + '1', 2, key + '2', 2, 'bogus', 0],
535
+ @twitter.multi_count_columns(:Users, [key + '1', key + '2', 'bogus']))
536
+ assert_equal(
537
+ OrderedHash[key + '2', 2, 'bogus', 0, key + '1', 2],
538
+ @twitter.multi_count_columns(:Users, [key + '2', 'bogus', key + '1']))
539
+ end
540
+
541
+ def test_batch_mutate
542
+ k = key
543
+
544
+ @twitter.insert(:Users, k + '0', {'delete_me' => 'v0', 'keep_me' => 'v0'})
545
+ @twitter.insert(:Users, k + '1', {'body' => 'v1', 'user' => 'v1'})
546
+ initial_subcolumns = {@uuids[1] => 'v1', @uuids[2] => 'v2'}
547
+ @twitter.insert(:StatusRelationships, k, {'user_timelines' => initial_subcolumns, 'dummy_supercolumn' => {@uuids[5] => 'value'}})
548
+ assert_equal(initial_subcolumns, @twitter.get(:StatusRelationships, k, 'user_timelines'))
549
+ assert_equal({@uuids[5] => 'value'}, @twitter.get(:StatusRelationships, k, 'dummy_supercolumn'))
550
+ new_subcolumns = {@uuids[3] => 'v3', @uuids[4] => 'v4'}
551
+ subcolumn_to_delete = initial_subcolumns.keys.first # the first column of the initial set
552
+
553
+ @twitter.batch do
554
+ # Normal Columns
555
+ @twitter.insert(:Users, k + '2', {'body' => 'v2', 'user' => 'v2'})
556
+ @twitter.insert(:Users, k + '3', {'body' => 'bogus', 'user' => 'v3'})
557
+ @twitter.insert(:Users, k + '3', {'body' => 'v3', 'location' => 'v3'})
558
+ @twitter.insert(:Statuses, k + '3', {'body' => 'v'})
559
+ @twitter.add(:UserCounters, 'bob', 5, 'tweet_count') if CASSANDRA_VERSION.to_f >= 0.8
560
+
561
+ assert_equal({'delete_me' => 'v0', 'keep_me' => 'v0'}, @twitter.get(:Users, k + '0')) # Written
562
+ assert_equal({'body' => 'v1', 'user' => 'v1'}, @twitter.get(:Users, k + '1')) # Written
563
+ assert_equal({}, @twitter.get(:Users, k + '2')) # Not yet written
564
+ assert_equal({}, @twitter.get(:Statuses, k + '3')) # Not yet written
565
+ assert_equal({}, @twitter.get(:UserCounters, 'bob')) if CASSANDRA_VERSION.to_f >= 0.8 # Not yet written
566
+
567
+ @twitter.remove(:Users, k + '1') # Full row
568
+ assert_equal({'body' => 'v1', 'user' => 'v1'}, @twitter.get(:Users, k + '1')) # Not yet removed
569
+
570
+ @twitter.remove(:Users, k + '0', 'delete_me') # A single column of the row
571
+ assert_equal({'delete_me' => 'v0', 'keep_me' => 'v0'}, @twitter.get(:Users, k + '0')) # Not yet removed
572
+
573
+ @twitter.remove(:Users, k + '4')
574
+ @twitter.insert(:Users, k + '4', {'body' => 'v4', 'user' => 'v4'})
575
+ assert_equal({}, @twitter.get(:Users, k + '4')) # Not yet written
576
+
577
+ # SuperColumns
578
+ # Add and delete new sub columns to the user timeline supercolumn
579
+ @twitter.insert(:StatusRelationships, k, {'user_timelines' => new_subcolumns })
580
+ @twitter.remove(:StatusRelationships, k, 'user_timelines' , subcolumn_to_delete ) # Delete the first of the initial_subcolumns from the user_timeline supercolumn
581
+ assert_equal(initial_subcolumns, @twitter.get(:StatusRelationships, k, 'user_timelines')) # No additions or deletes reflected yet
582
+ # Delete a complete supercolumn
583
+ @twitter.remove(:StatusRelationships, k, 'dummy_supercolumn' ) # Delete the full dummy supercolumn
584
+ assert_equal({@uuids[5] => 'value'}, @twitter.get(:StatusRelationships, k, 'dummy_supercolumn')) # dummy supercolumn not yet deleted
585
+ end
586
+
587
+ assert_equal({'body' => 'v2', 'user' => 'v2'}, @twitter.get(:Users, k + '2')) # Written
588
+ assert_equal({'body' => 'v3', 'user' => 'v3', 'location' => 'v3'}, @twitter.get(:Users, k + '3')) # Written and compacted
589
+ assert_equal({'body' => 'v4', 'user' => 'v4'}, @twitter.get(:Users, k + '4')) # Written
590
+ assert_equal({'body' => 'v'}, @twitter.get(:Statuses, k + '3')) # Written
591
+ assert_equal({'tweet_count' => 5}, @twitter.get(:UserCounters, 'bob')) if CASSANDRA_VERSION.to_f >= 0.8 # Written
592
+ assert_equal({}, @twitter.get(:Users, k + '1')) # Removed
593
+
594
+ assert_equal({ 'keep_me' => 'v0'}, @twitter.get(:Users, k + '0')) # 'delete_me' column removed
595
+
596
+
597
+ assert_equal({'body' => 'v2', 'user' => 'v2'}.keys.sort, @twitter.get(:Users, k + '2').timestamps.keys.sort) # Written
598
+ assert_equal({'body' => 'v3', 'user' => 'v3', 'location' => 'v3'}.keys.sort, @twitter.get(:Users, k + '3').timestamps.keys.sort) # Written and compacted
599
+ assert_equal({'body' => 'v4', 'user' => 'v4'}.keys.sort, @twitter.get(:Users, k + '4').timestamps.keys.sort) # Written
600
+ assert_equal({'body' => 'v'}.keys.sort, @twitter.get(:Statuses, k + '3').timestamps.keys.sort) # Written
601
+
602
+ # Final result: initial_subcolumns - initial_subcolumns.first + new_subcolumns
603
+ resulting_subcolumns = initial_subcolumns.merge(new_subcolumns).reject{|k2,v| k2 == subcolumn_to_delete }
604
+ assert_equal(resulting_subcolumns, @twitter.get(:StatusRelationships, key, 'user_timelines'))
605
+ assert_equal({}, @twitter.get(:StatusRelationships, key, 'dummy_supercolumn')) # dummy supercolumn deleted
606
+
607
+ end
608
+
609
+ def test_complain_about_nil_key
610
+ assert_raises(ArgumentError) do
611
+ @twitter.insert(:Statuses, nil, {'text' => 'crap'})
612
+ end
613
+ end
614
+
615
+ def test_nil_sub_column_value
616
+ @twitter.insert(:Indexes, 'asdf', {"thing" => {'jkl' => ''} })
617
+ end
618
+
619
+ def test_disconnect!
620
+ @twitter.disconnect!
621
+ assert_nil @twitter.instance_variable_get(:@client)
622
+ end
623
+
624
+ def test_disconnect_when_not_connected!
625
+ assert_nothing_raised do
626
+ @twitter = Cassandra.new('Twitter', "127.0.0.1:9160", :retries => 2, :exception_classes => [])
627
+ @twitter.disconnect!
628
+ end
629
+ end
630
+
631
+ def test_super_allows_for_non_string_values_while_normal_does_not
632
+ columns = {'user_timelines' => {@uuids[4] => '4', @uuids[5] => '5'}}
633
+
634
+ @twitter.insert(:StatusRelationships, key, columns)
635
+ @twitter.insert(:Statuses, key, { 'body' => '1' })
636
+ end
637
+
638
+ def test_batch_over_deletes
639
+ k = key
640
+
641
+ @twitter.batch do
642
+ @twitter.insert(:Users, k, {'body' => 'body', 'user' => 'user'})
643
+ @twitter.remove(:Users, k, 'body')
644
+ end
645
+
646
+ assert_equal({'user' => 'user'}, @twitter.get(:Users, k))
647
+ end
648
+
649
+ def test_each_key
650
+ num_users = rand(60)
651
+ num_users.times do |twit_counter|
652
+ @twitter.insert(:Users, "Twitter : #{twit_counter}", {'body' => 'v1', 'user' => 'v1'})
653
+ end
654
+ counter = 0
655
+ @twitter.each_key(:Users) do |_, _|
656
+ counter += 1
657
+ end
658
+ assert_equal num_users, counter
659
+ end
660
+
661
+ def test_each_with_column_predicate
662
+ num_users = rand(60)
663
+ num_users.times do |twit_counter|
664
+ @twitter.insert(:Users, "Twitter : #{twit_counter}", {'body' => 'v1', 'user' => 'v1'})
665
+ end
666
+ counter = 0
667
+ @twitter.each(:Users, :batch_size => 10, :start => 'body', :finish => 'body') do |key, columns|
668
+ assert_equal 1, columns.length
669
+ counter += 1
670
+ end
671
+ assert_equal num_users, counter
672
+ end
673
+
674
+ def test_each_with_super_column
675
+ num_users = rand(50)
676
+ block_name = key
677
+ num_users.times do |twit_counter|
678
+ @twitter.insert(:StatusRelationships, block_name + twit_counter.to_s, {
679
+ 'user_timelines' => {@uuids[1] => 'v1', @uuids[2] => 'v2'},
680
+ 'mentions_timelines' => {@uuids[3] => 'v3'}})
681
+ end
682
+
683
+ counter = 0
684
+ # Restrict to one super column ::
685
+ @twitter.each(:StatusRelationships, :batch_size => 10, :start => 'user_timelines', :finish => 'user_timelines') do |key, columns|
686
+ columns.each do |_, column_value|
687
+ assert_equal 2, column_value.length
688
+ end
689
+ counter += 1
690
+ end
691
+
692
+ #Both super columns
693
+ @twitter.each(:StatusRelationships, :batch_size => 10, :start => 'mentions_timelines', :finish => 'user_timelines') do |key,columns|
694
+ assert_equal 2, columns.length
695
+ counter += 1
696
+ end
697
+
698
+ assert_equal num_users*2, counter
699
+
700
+ end
701
+
702
+ def test_each_column_types
703
+ num_users = rand(60)
704
+ num_users.times do |twit_counter|
705
+ @type_conversions.insert(:UUIDColumnConversion, twit_counter.to_s, {@uuids[1] => 'v1'})
706
+ end
707
+ counter = 0
708
+ @type_conversions.each(:UUIDColumnConversion) do |_, columns|
709
+ counter += 1
710
+ columns.keys.each {|column_name| assert_equal SimpleUUID::UUID, column_name.class}
711
+ end
712
+ assert_equal num_users, counter
713
+ end
714
+
715
+
716
+ if CASSANDRA_VERSION.to_f >= 0.7
717
+ def test_creating_and_dropping_new_index
718
+ @twitter.create_index('Twitter', 'Statuses', 'column_name', 'LongType')
719
+ assert_nil @twitter.create_index('Twitter', 'Statuses', 'column_name', 'LongType')
720
+
721
+ @twitter.drop_index('Twitter', 'Statuses', 'column_name')
722
+ assert_nil @twitter.drop_index('Twitter', 'Statuses', 'column_name')
723
+
724
+ # Recreating and redropping the same index should not error either.
725
+ @twitter.create_index('Twitter', 'Statuses', 'column_name', 'LongType')
726
+ @twitter.drop_index('Twitter', 'Statuses', 'column_name')
727
+ end
728
+
729
+ def test_get_indexed_slices
730
+ @twitter.create_index('Twitter', 'Statuses', 'x', 'LongType')
731
+
732
+ @twitter.insert(:Statuses, 'row1', { 'x' => [0,10].pack("NN") })
733
+
734
+ (2..10).to_a.each do |i|
735
+ @twitter.insert(:Statuses, 'row' + i.to_s, { 'x' => [0,20].pack("NN"), 'non_indexed' => [i].pack('N*') })
736
+ end
737
+
738
+ @twitter.insert(:Statuses, 'row11', { 'x' => [0,30].pack("NN") })
739
+
740
+ expressions = [{:column_name => 'x', :value => [0,20].pack("NN"), :comparison => "=="}]
741
+
742
+ # verify multiples will be returned
743
+ assert_equal 9, @twitter.get_indexed_slices(:Statuses, expressions).length
744
+
745
+ # verify that GT and LT queries perform properly
746
+ expressions = [
747
+ {:column_name => 'x', :value => [0,20].pack("NN"), :comparison => "=="},
748
+ {:column_name => 'non_indexed', :value => [5].pack("N*"), :comparison => ">"}
749
+ ]
750
+ assert_equal(5, @twitter.get_indexed_slices(:Statuses, expressions).length)
751
+ end
752
+
753
+ def test_old_get_indexed_slices
754
+ @twitter.create_index('Twitter', 'Statuses', 'x', 'LongType')
755
+
756
+ @twitter.insert(:Statuses, 'row1', { 'x' => [0,10].pack("NN") })
757
+
758
+ (2..10).to_a.each do |i|
759
+ @twitter.insert(:Statuses, 'row' + i.to_s, { 'x' => [0,20].pack("NN"), 'non_indexed' => [i].pack('N*') })
760
+ end
761
+
762
+ @twitter.insert(:Statuses, 'row11', { 'x' => [0,30].pack("NN") })
763
+
764
+ idx_expr = @twitter.create_idx_expr('x', [0,20].pack("NN"), "==")
765
+
766
+ # verify count is observed
767
+ idx_clause = @twitter.create_idx_clause([idx_expr], "", 1)
768
+ assert_equal 1, @twitter.get_indexed_slices(:Statuses, idx_clause).length
769
+
770
+ # verify multiples will be returned
771
+ idx_clause = @twitter.create_idx_clause([idx_expr])
772
+ assert_equal 9, @twitter.get_indexed_slices(:Statuses, idx_clause).length
773
+
774
+ # verify that GT and LT queries perform properly
775
+ idx_expr = [
776
+ @twitter.create_idx_expr('x', [0,20].pack("NN"), "=="),
777
+ @twitter.create_idx_expr('non_indexed', [5].pack("N*"), ">")
778
+ ]
779
+ idx_clause = @twitter.create_idx_clause(idx_expr)
780
+ assert_equal(5, @twitter.get_indexed_slices(:Statuses, idx_clause).length)
781
+ end
782
+
783
+ def test_column_family_mutation
784
+ k = key
785
+
786
+ if @twitter.column_families.include?(k)
787
+ @twitter.drop_column_family(k)
788
+ end
789
+
790
+ # Verify add_column_family works as desired.
791
+ @twitter.add_column_family(
792
+ Cassandra::ColumnFamily.new(
793
+ :keyspace => 'Twitter',
794
+ :name => k
795
+ )
796
+ )
797
+ assert @twitter.column_families.include?(k)
798
+
799
+ if CASSANDRA_VERSION.to_f == 0.7
800
+ # Verify rename_column_family works properly
801
+ @twitter.rename_column_family(k, k + '_renamed')
802
+ assert @twitter.column_families.include?(k + '_renamed')
803
+
804
+ # Change it back and validate
805
+ @twitter.rename_column_family(k + '_renamed', k)
806
+ assert @twitter.column_families.include?(k)
807
+ end
808
+
809
+ temp_cf_def = @twitter.column_families[k]
810
+ temp_cf_def.comment = k
811
+ @twitter.update_column_family(temp_cf_def)
812
+ assert @twitter.column_families.include?(k)
813
+
814
+ @twitter.drop_column_family(k)
815
+ assert !@twitter.column_families.include?(k)
816
+ end
817
+ end
818
+
819
+ if CASSANDRA_VERSION.to_f >= 0.8
820
+ def test_adding_getting_value_in_counter
821
+ assert_nil @twitter.add(:UserCounters, 'bob', 5, 'tweet_count')
822
+ assert_equal(5, @twitter.get(:UserCounters, 'bob', 'tweet_count'))
823
+ assert_nil @twitter.get(:UserCounters, 'bogus', 'tweet_count')
824
+ end
825
+
826
+ def test_get_counter_slice
827
+ assert_nil @twitter.add(:UserCounters, 'bob', 5, 'tweet_count')
828
+ assert_equal({'tweet_count' => 5}, @twitter.get(:UserCounters, 'bob', :start => "tweet_count", :finish => "tweet_count"))
829
+ end
830
+
831
+ def test_adding_getting_value_in_multiple_counters
832
+ assert_nil @twitter.add(:UserCounters, 'bob', 5, 'tweet_count')
833
+ assert_nil @twitter.add(:UserCounters, 'bob', 7, 'follower_count')
834
+ assert_equal(5, @twitter.get(:UserCounters, 'bob', 'tweet_count'))
835
+ assert_nil @twitter.get(:UserCounters, 'bogus', 'tweet_count')
836
+ assert_equal([5, 7], @twitter.get_columns(:UserCounters, 'bob', ['tweet_count', 'follower_count']))
837
+ assert_equal([5, 7, nil], @twitter.get_columns(:UserCounters, 'bob', ['tweet_count', 'follower_count', 'bogus']))
838
+ end
839
+
840
+ def test_adding_getting_value_in_multiple_counters_with_super_columns
841
+ assert_nil @twitter.add(:UserCounterAggregates, 'bob', 1, 'DAU', 'today')
842
+ assert_nil @twitter.add(:UserCounterAggregates, 'bob', 2, 'DAU', 'tomorrow')
843
+ assert_equal(1, @twitter.get(:UserCounterAggregates, 'bob', 'DAU', 'today'))
844
+ assert_equal(2, @twitter.get(:UserCounterAggregates, 'bob', 'DAU', 'tomorrow'))
845
+ end
846
+
847
+ def test_reading_rows_with_super_column_counter
848
+ assert_nil @twitter.add(:UserCounterAggregates, 'bob', 1, 'DAU', 'today')
849
+ assert_nil @twitter.add(:UserCounterAggregates, 'bob', 2, 'DAU', 'tomorrow')
850
+ result = @twitter.get(:UserCounterAggregates, 'bob')
851
+ assert_equal(1, result.size)
852
+ assert_equal(2, result.first.size)
853
+ assert_equal("DAU", result.first[0])
854
+ assert_equal(1, result.first[1]["today"])
855
+ assert_equal(2, result.first[1]["tomorrow"])
856
+ end
857
+
858
+ def test_composite_column_type_conversion
859
+ columns = {}
860
+ @composites.each_with_index do |c, index|
861
+ columns[c] = "value-#{index}"
862
+ end
863
+ @type_conversions.insert(:CompositeColumnConversion, key, columns)
864
+ columns_in_order = [
865
+ Cassandra::Composite.new([1].pack('N'), "elephant"),
866
+ Cassandra::Composite.new([5].pack('N'), "aardvark"),
867
+ Cassandra::Composite.new([5].pack('N'), "zebra"),
868
+ Cassandra::Composite.new([10].pack('N'), "kangaroo"),
869
+ ]
870
+ assert_equal(columns_in_order, @type_conversions.get(:CompositeColumnConversion, key).keys)
871
+
872
+ column_slice = @type_conversions.get(:CompositeColumnConversion, key,
873
+ :start => Cassandra::Composite.new([1].pack('N')),
874
+ :finish => Cassandra::Composite.new([10].pack('N')),
875
+ ).keys
876
+ assert_equal(columns_in_order[0..-2], column_slice)
877
+
878
+ column_slice = @type_conversions.get(:CompositeColumnConversion, key,
879
+ :start => Cassandra::Composite.new([5].pack('N')),
880
+ :finish => Cassandra::Composite.new([5].pack('N'), :slice => :after),
881
+ ).keys
882
+ assert_equal(columns_in_order[1..2], column_slice)
883
+
884
+ column_slice = @type_conversions.get(:CompositeColumnConversion, key,
885
+ :start => Cassandra::Composite.new([5].pack('N'), :slice => :after).to_s,
886
+ ).keys
887
+ assert_equal([columns_in_order[-1]], column_slice)
888
+
889
+ column_slice = @type_conversions.get(:CompositeColumnConversion, key,
890
+ :finish => Cassandra::Composite.new([10].pack('N'), :slice => :before).to_s,
891
+ ).keys
892
+ assert_equal(columns_in_order[0..-2], column_slice)
893
+
894
+ assert_equal('value-2', @type_conversions.get(:CompositeColumnConversion, key, columns_in_order.first))
895
+ end
896
+ end
897
+
898
+ def test_column_timestamps
899
+ base_time = Time.now
900
+ @twitter.insert(:Statuses, "time-key", { "body" => "value" })
901
+
902
+ results = @twitter.get(:Statuses, "time-key")
903
+ assert(results.timestamps["body"] / 1000000 >= base_time.to_i)
904
+ end
905
+
906
+ def test_supercolumn_timestamps
907
+ base_time = Time.now
908
+ @twitter.insert(:StatusRelationships, "time-key", { "super" => { @uuids[1] => "value" }})
909
+
910
+ results = @twitter.get(:StatusRelationships, "time-key")
911
+ assert_nil(results.timestamps["super"])
912
+
913
+ columns = results["super"]
914
+ assert(columns.timestamps[@uuids[1]] / 1000000 >= base_time.to_i)
915
+ end
916
+
917
+ private
918
+
919
+ def key
920
+ caller.first[/`(.*?)'/, 1]
921
+ end
922
+ end