mcmire-cassandra 0.12.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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