mcmire-cassandra 0.12.2

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