cassandra-mavericks 0.21.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (109) hide show
  1. checksums.yaml +15 -0
  2. data/CHANGELOG +150 -0
  3. data/Gemfile +7 -0
  4. data/LICENSE +202 -0
  5. data/Manifest +94 -0
  6. data/README.md +373 -0
  7. data/Rakefile +191 -0
  8. data/bin/cassandra_helper +16 -0
  9. data/cassandra.gemspec +29 -0
  10. data/conf/0.6/cassandra.in.sh +47 -0
  11. data/conf/0.6/log4j.properties +38 -0
  12. data/conf/0.6/schema.json +57 -0
  13. data/conf/0.6/storage-conf.xml +352 -0
  14. data/conf/0.7/cassandra.in.sh +46 -0
  15. data/conf/0.7/cassandra.yaml +336 -0
  16. data/conf/0.7/log4j-server.properties +41 -0
  17. data/conf/0.7/schema.json +57 -0
  18. data/conf/0.7/schema.txt +45 -0
  19. data/conf/0.8/cassandra.in.sh +41 -0
  20. data/conf/0.8/cassandra.yaml +61 -0
  21. data/conf/0.8/log4j-server.properties +40 -0
  22. data/conf/0.8/schema.json +72 -0
  23. data/conf/0.8/schema.txt +57 -0
  24. data/conf/1.0/cassandra.in.sh +41 -0
  25. data/conf/1.0/cassandra.yaml +415 -0
  26. data/conf/1.0/log4j-server.properties +40 -0
  27. data/conf/1.0/schema.json +72 -0
  28. data/conf/1.0/schema.txt +57 -0
  29. data/conf/1.1/cassandra.in.sh +41 -0
  30. data/conf/1.1/cassandra.yaml +567 -0
  31. data/conf/1.1/log4j-server.properties +44 -0
  32. data/conf/1.1/schema.json +72 -0
  33. data/conf/1.1/schema.txt +57 -0
  34. data/conf/1.2/cassandra.in.sh +41 -0
  35. data/conf/1.2/cassandra.yaml +643 -0
  36. data/conf/1.2/log4j-server.properties +44 -0
  37. data/conf/1.2/schema.json +72 -0
  38. data/conf/1.2/schema.txt +57 -0
  39. data/ext/cassandra_native.c +69 -0
  40. data/ext/extconf.rb +9 -0
  41. data/lib/cassandra.rb +47 -0
  42. data/lib/cassandra/0.6.rb +7 -0
  43. data/lib/cassandra/0.6/cassandra.rb +113 -0
  44. data/lib/cassandra/0.6/columns.rb +78 -0
  45. data/lib/cassandra/0.6/protocol.rb +91 -0
  46. data/lib/cassandra/0.7.rb +7 -0
  47. data/lib/cassandra/0.7/cassandra.rb +2 -0
  48. data/lib/cassandra/0.7/columns.rb +4 -0
  49. data/lib/cassandra/0.7/protocol.rb +5 -0
  50. data/lib/cassandra/0.8.rb +7 -0
  51. data/lib/cassandra/0.8/cassandra.rb +25 -0
  52. data/lib/cassandra/0.8/columns.rb +28 -0
  53. data/lib/cassandra/0.8/protocol.rb +10 -0
  54. data/lib/cassandra/1.0.rb +7 -0
  55. data/lib/cassandra/1.0/cassandra.rb +1 -0
  56. data/lib/cassandra/1.0/columns.rb +1 -0
  57. data/lib/cassandra/1.0/protocol.rb +1 -0
  58. data/lib/cassandra/1.1.rb +7 -0
  59. data/lib/cassandra/1.1/cassandra.rb +1 -0
  60. data/lib/cassandra/1.1/columns.rb +1 -0
  61. data/lib/cassandra/1.1/protocol.rb +1 -0
  62. data/lib/cassandra/1.2.rb +7 -0
  63. data/lib/cassandra/1.2/cassandra.rb +1 -0
  64. data/lib/cassandra/1.2/columns.rb +1 -0
  65. data/lib/cassandra/1.2/protocol.rb +1 -0
  66. data/lib/cassandra/array.rb +8 -0
  67. data/lib/cassandra/batch.rb +41 -0
  68. data/lib/cassandra/cassandra.rb +1091 -0
  69. data/lib/cassandra/column_family.rb +3 -0
  70. data/lib/cassandra/columns.rb +172 -0
  71. data/lib/cassandra/comparable.rb +28 -0
  72. data/lib/cassandra/composite.rb +137 -0
  73. data/lib/cassandra/constants.rb +11 -0
  74. data/lib/cassandra/debug.rb +9 -0
  75. data/lib/cassandra/dynamic_composite.rb +118 -0
  76. data/lib/cassandra/helpers.rb +41 -0
  77. data/lib/cassandra/keyspace.rb +3 -0
  78. data/lib/cassandra/long.rb +58 -0
  79. data/lib/cassandra/mock.rb +536 -0
  80. data/lib/cassandra/ordered_hash.rb +195 -0
  81. data/lib/cassandra/protocol.rb +137 -0
  82. data/lib/cassandra/time.rb +11 -0
  83. data/test/cassandra_client_test.rb +20 -0
  84. data/test/cassandra_mock_test.rb +128 -0
  85. data/test/cassandra_test.rb +1367 -0
  86. data/test/comparable_types_test.rb +45 -0
  87. data/test/composite_type_test.rb +86 -0
  88. data/test/eventmachine_test.rb +42 -0
  89. data/test/ordered_hash_test.rb +386 -0
  90. data/test/test_helper.rb +19 -0
  91. data/vendor/0.6/gen-rb/cassandra.rb +1481 -0
  92. data/vendor/0.6/gen-rb/cassandra_constants.rb +12 -0
  93. data/vendor/0.6/gen-rb/cassandra_types.rb +482 -0
  94. data/vendor/0.7/gen-rb/cassandra.rb +1936 -0
  95. data/vendor/0.7/gen-rb/cassandra_constants.rb +12 -0
  96. data/vendor/0.7/gen-rb/cassandra_types.rb +681 -0
  97. data/vendor/0.8/gen-rb/cassandra.rb +2215 -0
  98. data/vendor/0.8/gen-rb/cassandra_constants.rb +12 -0
  99. data/vendor/0.8/gen-rb/cassandra_types.rb +824 -0
  100. data/vendor/1.0/gen-rb/cassandra.rb +2215 -0
  101. data/vendor/1.0/gen-rb/cassandra_constants.rb +12 -0
  102. data/vendor/1.0/gen-rb/cassandra_types.rb +857 -0
  103. data/vendor/1.1/gen-rb/cassandra.rb +2571 -0
  104. data/vendor/1.1/gen-rb/cassandra_constants.rb +12 -0
  105. data/vendor/1.1/gen-rb/cassandra_types.rb +928 -0
  106. data/vendor/1.2/gen-rb/cassandra.rb +3013 -0
  107. data/vendor/1.2/gen-rb/cassandra_constants.rb +13 -0
  108. data/vendor/1.2/gen-rb/cassandra_types.rb +965 -0
  109. metadata +288 -0
@@ -0,0 +1,1367 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/test_helper')
2
+
3
+ class CassandraTest < Test::Unit::TestCase
4
+ include Cassandra::Constants
5
+
6
+ def assert_has_keys(keys, hash)
7
+ assert_equal Set.new(keys), Set.new(hash.keys)
8
+ end
9
+
10
+ def setup
11
+ @twitter = Cassandra.new('Twitter', "127.0.0.1:9160", :retries => 2, :connect_timeout => 1, :timeout => 5, :exception_classes => [])
12
+ @twitter.clear_keyspace!
13
+
14
+ @blogs = Cassandra.new('Multiblog', "127.0.0.1:9160", :retries => 2, :connect_timeout => 1, :timeout => 5, :exception_classes => [])
15
+ @blogs.clear_keyspace!
16
+
17
+ @blogs_long = Cassandra.new('MultiblogLong', "127.0.0.1:9160", :retries => 2, :connect_timeout => 1, :timeout => 5, :exception_classes => [])
18
+ @blogs_long.clear_keyspace!
19
+
20
+ @type_conversions = Cassandra.new('TypeConversions', "127.0.0.1:9160", :retries => 2, :connect_timeout => 1, :timeout => 5, :exception_classes => [])
21
+ @type_conversions.clear_keyspace!
22
+
23
+ Cassandra::WRITE_DEFAULTS[:consistency] = Cassandra::Consistency::ONE
24
+ Cassandra::READ_DEFAULTS[:consistency] = Cassandra::Consistency::ONE
25
+
26
+ @uuids = (0..6).map {|i| SimpleUUID::UUID.new(Time.at(2**(24+i))) }
27
+ @longs = (0..6).map {|i| Long.new(Time.at(2**(24+i))) }
28
+ @composites = [
29
+ Cassandra::Composite.new([5].pack('N'), "zebra"),
30
+ Cassandra::Composite.new([5].pack('N'), "aardvark"),
31
+ Cassandra::Composite.new([1].pack('N'), "elephant"),
32
+ Cassandra::Composite.new([10].pack('N'), "kangaroo"),
33
+ ]
34
+ @dynamic_composites = [
35
+ Cassandra::DynamicComposite.new(['i', [5].pack('N')], ['UTF8Type', "zebra"]),
36
+ Cassandra::DynamicComposite.new(['i', [5].pack('N')], ['UTF8Type', "aardvark"]),
37
+ Cassandra::DynamicComposite.new(['IntegerType', [1].pack('N')], ['s', "elephant"]),
38
+ Cassandra::DynamicComposite.new(['IntegerType', [10].pack('N')], ['s', "kangaroo"]),
39
+ ]
40
+ end
41
+
42
+ def test_inspect
43
+ assert_nothing_raised do
44
+ @blogs.inspect
45
+ @twitter.inspect
46
+ end
47
+ end
48
+
49
+ def test_setting_default_consistency
50
+ assert_nothing_raised do
51
+ @twitter.default_read_consistency = Cassandra::Consistency::ALL
52
+ end
53
+ assert_equal(Cassandra::READ_DEFAULTS[:consistency], Cassandra::Consistency::ALL)
54
+
55
+ assert_nothing_raised do
56
+ @twitter.default_write_consistency = Cassandra::Consistency::ALL
57
+ end
58
+ assert_equal(Cassandra::WRITE_DEFAULTS[:consistency], Cassandra::Consistency::ALL)
59
+ end
60
+
61
+ def test_get_key
62
+
63
+ @twitter.insert(:Users, key, {'body' => 'v', 'user' => 'v'})
64
+ assert_equal({'body' => 'v', 'user' => 'v'}, @twitter.get(:Users, key))
65
+ assert_equal(['body', 'user'].sort, @twitter.get(:Users, key).timestamps.keys.sort)
66
+ assert_equal({}, @twitter.get(:Users, 'bogus'))
67
+ end
68
+
69
+ def test_get_single_column_returns_single_value
70
+ @twitter.insert(:Users, key, {'body' => 'body_text', 'user' => 'user_name'})
71
+ assert_equal('body_text', @twitter.get(:Users, key, 'body'))
72
+ assert_equal('user_name', @twitter.get(:Users, key, 'user'))
73
+
74
+ @blogs.insert(:Blogs, key,
75
+ {@uuids[0] => 'I like this cat', @uuids[1] => 'Buttons is cuter', @uuids[2] => 'I disagree'})
76
+
77
+ assert_equal('I like this cat', @blogs.get(:Blogs, key, @uuids[0]))
78
+ end
79
+
80
+ def test_get_key_preserving_order
81
+ # In-order hash is preserved
82
+ hash = OrderedHash['a', '', 'b', '', 'c', '', 'd', '',]
83
+ @twitter.insert(:Users, key, hash)
84
+ assert_equal(hash.keys, @twitter.get(:Users, key).keys)
85
+
86
+ @twitter.remove(:Users, key)
87
+
88
+ # Out-of-order hash is returned sorted
89
+ hash = OrderedHash['b', '', 'c', '', 'd', '', 'a', '']
90
+ @twitter.insert(:Users, key, hash)
91
+ assert_equal(hash.keys.sort, @twitter.get(:Users, key).keys)
92
+ assert_equal(hash.timestamps.keys.sort, @twitter.get(:Users, key).timestamps.keys)
93
+ assert_not_equal(hash.keys, @twitter.get(:Users, key).keys)
94
+ end
95
+
96
+ def test_ordered_hash_iteration_functions_return_values
97
+ hash = OrderedHash['a', '', 'b', '', 'c', '', 'd', '',]
98
+ assert_instance_of OrderedHash, hash.each{|_| true}
99
+ assert_instance_of OrderedHash, hash.each_value{|_| true}
100
+ assert_instance_of OrderedHash, hash.each_key{|_| true}
101
+ end
102
+
103
+ def test_get_first_time_uuid_column
104
+ @blogs.insert(:Blogs, key,
105
+ {@uuids[0] => 'I like this cat', @uuids[1] => 'Buttons is cuter', @uuids[2] => 'I disagree'})
106
+
107
+ assert_equal({@uuids[0] => 'I like this cat'}, @blogs.get(:Blogs, key, :count => 1))
108
+ assert_equal({@uuids[2] => 'I disagree'}, @blogs.get(:Blogs, key, :count => 1, :reversed => true))
109
+ assert_equal({}, @blogs.get(:Blogs, 'bogus'))
110
+ end
111
+
112
+ def test_get_multiple_time_uuid_columns
113
+ @blogs.insert(:Blogs, key,
114
+ {@uuids[0] => 'I like this cat', @uuids[1] => 'Buttons is cuter', @uuids[2] => 'I disagree'})
115
+
116
+ assert_equal(['I like this cat', 'Buttons is cuter'], @blogs.get_columns(:Blogs, key, @uuids[0..1]))
117
+ end
118
+
119
+ def test_get_first_long_column
120
+ @blogs_long.insert(:Blogs, key,
121
+ {@longs[0] => 'I like this cat', @longs[1] => 'Buttons is cuter', @longs[2] => 'I disagree'})
122
+
123
+ assert_equal({@longs[0] => 'I like this cat'}, @blogs_long.get(:Blogs, key, :count => 1))
124
+ assert_equal({@longs[2] => 'I disagree'}, @blogs_long.get(:Blogs, key, :count => 1, :reversed => true))
125
+ assert_equal({}, @blogs_long.get(:Blogs, 'bogus'))
126
+
127
+ assert_equal([@longs[0]], @blogs_long.get(:Blogs, key, :count => 1).timestamps.keys)
128
+ assert_equal([@longs[2]], @blogs_long.get(:Blogs, key, :count => 1, :reversed => true).timestamps.keys)
129
+ end
130
+
131
+ def test_long_remove_bug
132
+ @blogs_long.insert(:Blogs, key, {@longs[0] => 'I like this cat'})
133
+ @blogs_long.remove(:Blogs, key)
134
+ assert_equal({}, @blogs_long.get(:Blogs, key, :count => 1))
135
+
136
+ @blogs_long.insert(:Blogs, key, {@longs[0] => 'I really like this cat'})
137
+ assert_equal({@longs[0] => 'I really like this cat'}, @blogs_long.get(:Blogs, key, :count => 1))
138
+ assert_equal([@longs[0]], @blogs_long.get(:Blogs, key, :count => 1).timestamps.keys)
139
+ end
140
+
141
+ def test_get_with_count
142
+ @twitter.insert(:Statuses, key, {'1' => 'v', '2' => 'v', '3' => 'v'})
143
+ assert_equal 1, @twitter.get(:Statuses, key, :count => 1).size
144
+ assert_equal 2, @twitter.get(:Statuses, key, :count => 2).size
145
+ assert_equal 1, @twitter.get(:Statuses, key, :count => 1).timestamps.size
146
+ assert_equal 2, @twitter.get(:Statuses, key, :count => 2).timestamps.size
147
+ end
148
+
149
+ def test_get_value
150
+ @twitter.insert(:Statuses, key, {'body' => 'v'})
151
+ assert_equal 'v', @twitter.get(:Statuses, key, 'body')
152
+ assert_nil @twitter.get(:Statuses, 'bogus', 'body')
153
+
154
+ assert @twitter.exists?(:Statuses, key, 'body')
155
+ assert !@twitter.exists?(:Statuses, 'bogus', 'body')
156
+ end
157
+
158
+ def test_get_value_with_range
159
+ k = key
160
+
161
+ 10.times do |i|
162
+ @twitter.insert(:Statuses, k, {"body-#{i}" => 'v'})
163
+ end
164
+
165
+ assert_equal 5, @twitter.get(:Statuses, k, :count => 5).length
166
+ assert_equal 5, @twitter.get(:Statuses, k, :start => "body-5").length
167
+ assert_equal 5, @twitter.get(:Statuses, k, :finish => "body-4").length
168
+ assert_equal 5, @twitter.get(:Statuses, k, :start => "body-1", :count => 5).length
169
+ assert_equal 5, @twitter.get(:Statuses, k, :start => "body-0", :finish => "body-4", :count => 7).length
170
+ end
171
+
172
+ def test_exists
173
+ @twitter.insert(:Statuses, key, {'body' => 'v'})
174
+ assert_equal true, @twitter.exists?(:Statuses, key)
175
+ assert_equal false, @twitter.exists?(:Statuses, 'bogus')
176
+
177
+ columns = {@uuids[1] => 'v1', @uuids[2] => 'v2'}
178
+ @twitter.insert(:StatusRelationships, key, {'user_timelines' => columns})
179
+
180
+ # verify return value when searching by key
181
+ assert_equal true, @twitter.exists?(:StatusRelationships, key)
182
+ assert_equal false, @twitter.exists?(:StatusRelationships, 'bogus')
183
+
184
+ # verify return value when searching by key and column
185
+ assert_equal true, @twitter.exists?(:StatusRelationships, key, 'user_timelines')
186
+ assert_equal false, @twitter.exists?(:StatusRelationships, key, 'bogus')
187
+
188
+ # verify return value when searching by key and column and subcolumn
189
+ assert_equal true, @twitter.exists?(:StatusRelationships, key, 'user_timelines', @uuids[1])
190
+ assert_equal false, @twitter.exists?(:StatusRelationships, key, 'user_timelines', @uuids[3])
191
+ end
192
+
193
+ def test_get_super_key
194
+ columns = {'user_timelines' => {@uuids[4] => '4', @uuids[5] => '5'}}
195
+ @twitter.insert(:StatusRelationships, key, columns)
196
+ assert_equal(columns, @twitter.get(:StatusRelationships, key))
197
+ assert_equal(columns.keys, @twitter.get(:StatusRelationships, key).timestamps.keys)
198
+ assert_equal({}, @twitter.get(:StatusRelationships, 'bogus'))
199
+ end
200
+
201
+ def test_get_several_super_keys
202
+ columns = OrderedHash[
203
+ 'mentions_timelines', {@uuids[2] => 'v2'},
204
+ 'user_timelines', {@uuids[1] => 'v1'}
205
+ ]
206
+
207
+ @twitter.insert(:StatusRelationships, key, columns)
208
+
209
+ assert_equal(columns, @twitter.get(:StatusRelationships, key))
210
+ assert_equal(columns.keys, @twitter.get(:StatusRelationships, key).timestamps.keys)
211
+ assert_equal({}, @twitter.get(:StatusRelationships, 'bogus'))
212
+ end
213
+
214
+ def test_get_super_sub_keys_with_count
215
+ @twitter.insert(:StatusRelationships, key,
216
+ {'user_timelines' => {@uuids[1] => 'v1', @uuids[2] => 'v2', @uuids[3] => 'v3'}})
217
+ assert_equal({@uuids[1] => 'v1'},
218
+ @twitter.get(:StatusRelationships, key, "user_timelines", :count => 1))
219
+ assert_equal({@uuids[3] => 'v3'},
220
+ @twitter.get(:StatusRelationships, key, "user_timelines", :count => 1, :reversed => true))
221
+ assert_equal([@uuids[1]],
222
+ @twitter.get(:StatusRelationships, key, "user_timelines", :count => 1).timestamps.keys)
223
+ assert_equal([@uuids[3]],
224
+ @twitter.get(:StatusRelationships, key, "user_timelines", :count => 1, :reversed => true).timestamps.keys)
225
+ end
226
+
227
+ def test_get_super_sub_keys_with_ranges
228
+ @twitter.insert(:StatusRelationships, key,
229
+ {'user_timelines' => {
230
+ @uuids[1] => 'v1',
231
+ @uuids[2] => 'v2',
232
+ @uuids[3] => 'v3',
233
+ @uuids[4] => 'v4',
234
+ @uuids[5] => 'v5'}})
235
+
236
+ keys = @twitter.get(:StatusRelationships, key, "user_timelines").keys
237
+ assert_equal keys.sort, keys
238
+ assert_equal({@uuids[1] => 'v1'}, @twitter.get(:StatusRelationships, key, "user_timelines", :finish => @uuids[2], :count => 1))
239
+ assert_equal({@uuids[2] => 'v2'}, @twitter.get(:StatusRelationships, key, "user_timelines", :start => @uuids[2], :count => 1))
240
+ assert_equal 4, @twitter.get(:StatusRelationships, key, "user_timelines", :start => @uuids[2], :finish => @uuids[5]).size
241
+ assert_equal([@uuids[1]], @twitter.get(:StatusRelationships, key, "user_timelines", :finish => @uuids[2], :count => 1).timestamps.keys)
242
+ assert_equal([@uuids[2]], @twitter.get(:StatusRelationships, key, "user_timelines", :start => @uuids[2], :count => 1).timestamps.keys)
243
+ assert_equal 4, @twitter.get(:StatusRelationships, key, "user_timelines", :start => @uuids[2], :finish => @uuids[5]).timestamps.size
244
+ end
245
+
246
+ def test_get_super_sub_key
247
+ columns = {@uuids[1] => 'v1', @uuids[2] => 'v2'}
248
+ @twitter.insert(:StatusRelationships, key, {'user_timelines' => columns})
249
+ assert_equal(columns, @twitter.get(:StatusRelationships, key, 'user_timelines'))
250
+ assert_equal(columns.keys.sort, @twitter.get(:StatusRelationships, key, 'user_timelines').timestamps.keys.sort)
251
+ assert_equal({}, @twitter.get(:StatusRelationships, 'bogus', 'user_timelines'))
252
+ # FIXME Not sure if this is valid
253
+ assert_equal false, @twitter.exists?(:StatusRelationships, 'bogus', 'user_timelines')
254
+ end
255
+
256
+ def test_get_super_value
257
+ columns = {@uuids[1] => 'v1'}
258
+ @twitter.insert(:StatusRelationships, key, {'user_timelines' => columns})
259
+ assert_equal('v1', @twitter.get(:StatusRelationships, key, 'user_timelines', columns.keys.first))
260
+ assert_nil @twitter.get(:StatusRelationships, 'bogus', 'user_timelines', columns.keys.first)
261
+ end
262
+
263
+ # def test_get_range_with_key_range
264
+ # skip('This test requires the use of OrderPreservingPartitioner on the cluster to work properly.')
265
+ # k = key
266
+ # @twitter.insert(:Statuses, k + '2', {'body' => '1'})
267
+ # @twitter.insert(:Statuses, k + '3', {'body' => '1'})
268
+ # @twitter.insert(:Statuses, k + '4', {'body' => '1'})
269
+ # @twitter.insert(:Statuses, k + '5', {'body' => '1'})
270
+ # @twitter.insert(:Statuses, k + '6', {'body' => '1'})
271
+ # assert_equal([k + '3', k + '4', k + '5'], @twitter.get_range(:Statuses, :start_key => k + '3', :finish_key => k + '5').keys)
272
+ # end
273
+
274
+ def test_get_range
275
+ # make sure that deleted rows are not included in the iteration
276
+ 10.times do |i|
277
+ @twitter.insert(:Statuses, i.to_s, {'body' => '1'})
278
+ @twitter.insert(:Statuses, i.to_s + '_delete_me', {'test' => 'value'})
279
+ @twitter.remove(:Statuses, i.to_s + '_delete_me')
280
+ end
281
+
282
+ assert_equal(4, @twitter.get_range_keys(:Statuses, :key_count => 4).size)
283
+ end
284
+
285
+ def test_get_range_with_count
286
+ @twitter.insert(:Statuses, key + '1', {'test_column1' => '1', 'test_column2' => '2', 'test_column3' => '2', 'deleted_column' => '1'})
287
+ @twitter.insert(:Statuses, key + '2', {'test_column4' => '3', 'test_column5' => '4', 'test_column6' => '2', 'deleted_column' => '2'})
288
+
289
+ @twitter.get_range(:Statuses, :count => 3) do |key, columns|
290
+ assert_equal columns.count, 3
291
+ end
292
+
293
+ assert_equal 2, @twitter.get_range(:Statuses, :start_key => key + '1', :finish_key => key + '1', :count => 2)[key + '1'].count
294
+
295
+ @twitter.remove(:Statuses, key + '1', 'deleted_column')
296
+ @twitter.remove(:Statuses, key + '2', 'deleted_column')
297
+
298
+ @twitter.get_range(:Statuses, :count => 2) do |key, columns|
299
+ assert_equal columns.count, 2
300
+ end
301
+
302
+ end
303
+
304
+ def test_get_range_block
305
+ k = key
306
+
307
+ values = {}
308
+ 5.times do |i|
309
+ values[k+i.to_s] = {"body-#{i.to_s}" => 'v'}
310
+ end
311
+
312
+ values.each {|key, columns| @twitter.insert(:Statuses, key, columns) }
313
+
314
+ returned_value = @twitter.get_range(:Statuses, :start_key => k.to_s, :key_count => 5) do |key,columns|
315
+ expected = values.delete(key)
316
+ assert_equal expected, columns
317
+ end
318
+
319
+ assert values.length < 5
320
+ assert_nil returned_value
321
+ end
322
+
323
+ def test_get_range_reversed
324
+ data = 3.times.map { |i| ["body-#{i.to_s}", "v"] }
325
+ hash = Cassandra::OrderedHash[data]
326
+ reversed_hash = Cassandra::OrderedHash[data.reverse]
327
+
328
+ @twitter.insert(:Statuses, "all-keys", hash)
329
+
330
+ columns = @twitter.get_range(:Statuses, :reversed => true)["all-keys"]
331
+ columns.each do |column|
332
+ assert_equal reversed_hash.shift, column
333
+ end
334
+ end
335
+
336
+ def test_get_range_with_start_key_and_key_count
337
+ hash = {"name" => "value"}
338
+ @twitter.insert(:Statuses, "a-key", hash)
339
+ @twitter.insert(:Statuses, "b-key", hash)
340
+ @twitter.insert(:Statuses, "c-key", hash)
341
+
342
+ results = @twitter.get_range(:Statuses, :start_key => "b-key", :key_count => 1)
343
+ assert_equal ["b-key"], results.keys
344
+ end
345
+
346
+ def test_each_key
347
+ k = key
348
+ keys_yielded = []
349
+
350
+ 10.times do |i|
351
+ @twitter.insert(:Statuses, k + i.to_s, {"body-#{i.to_s}" => 'v'})
352
+ end
353
+
354
+ # make sure that deleted rows are not included in the iteration
355
+ @twitter.insert(:Statuses, k + '_delete_me', {'test' => 'value'})
356
+ @twitter.remove(:Statuses, k + '_delete_me')
357
+
358
+ @twitter.each_key(:Statuses) do |key|
359
+ keys_yielded << key
360
+ end
361
+
362
+ assert_equal 10, keys_yielded.length
363
+ end
364
+
365
+ def test_each
366
+ k = key
367
+ key_columns = {}
368
+
369
+ 10.times do |i|
370
+ key_columns[k + i.to_s] = {"body-#{i.to_s}" => 'v', 'single_column_lookup' => "value = #{i.to_s}"}
371
+ @twitter.insert(:Statuses, k + i.to_s, key_columns[k + i.to_s])
372
+ end
373
+
374
+ keys_yielded = []
375
+ @twitter.each(:Statuses, :batch_size => 5) do |key, columns|
376
+ assert_equal key_columns[key], columns
377
+ keys_yielded << key
378
+ end
379
+
380
+ assert_equal 10, keys_yielded.length
381
+
382
+ keys_yielded = []
383
+ @twitter.each(:Statuses, :key_count => 7, :batch_size => 5) do |key, columns|
384
+ assert_equal key_columns[key], columns
385
+ keys_yielded << key
386
+ end
387
+
388
+ assert_equal 7, keys_yielded.length, 'each limits to specified count'
389
+
390
+ keys_yielded = []
391
+ @twitter.each(:Statuses, :columns => ['single_column_lookup'], :batch_size => 5) do |key, columns|
392
+ assert_equal key_columns[key].reject {|k2,v| k2 != 'single_column_lookup'}, columns
393
+ keys_yielded << key
394
+ end
395
+
396
+ assert_equal 10, keys_yielded.length
397
+ end
398
+
399
+ def test_multi_get
400
+ @twitter.insert(:Users, key + '1', {'body' => 'v1', 'user' => 'v1'})
401
+ @twitter.insert(:Users, key + '2', {'body' => 'v2', 'user' => 'v2'})
402
+
403
+ expected = OrderedHash[key + '1', {'body' => 'v1', 'user' => 'v1'}, key + '2', {'body' => 'v2', 'user' => 'v2'}, 'bogus', {}]
404
+ result = @twitter.multi_get(:Users, [key + '1', key + '2', 'bogus'])
405
+ assert_equal expected, result
406
+ assert_equal expected.keys, result.keys
407
+ assert_equal expected.keys.sort, @twitter.multi_get(:Users, [key + '1', key + '2', 'bogus']).timestamps.keys.sort
408
+
409
+ expected = OrderedHash[key + '2', {'body' => 'v2', 'user' => 'v2'}, 'bogus', {}, key + '1', {'body' => 'v1', 'user' => 'v1'}]
410
+ result = @twitter.multi_get(:Users, [key + '2', 'bogus', key + '1'])
411
+ assert_equal expected, result
412
+ assert_equal expected.keys, result.keys
413
+ assert_equal expected.keys.sort, @twitter.multi_get(:Users, [key + '2', 'bogus', key + '1']).timestamps.keys.sort
414
+ end
415
+
416
+ def test_remove_key
417
+ @twitter.insert(:Statuses, key, {'body' => 'v'})
418
+ assert_equal({'body' => 'v'}, @twitter.get(:Statuses, key))
419
+
420
+ @twitter.remove(:Statuses, key)
421
+ assert_equal({}, @twitter.get(:Statuses, key))
422
+ end
423
+
424
+ def test_remove_super_sub_key_errors_for_normal_column_family
425
+ @twitter.insert(:Statuses, key, {'body' => 'v'})
426
+ assert_equal({'body' => 'v'}, @twitter.get(:Statuses, key))
427
+
428
+ assert_raise( ArgumentError) { @twitter.remove(:Statuses, key, 'body' , 'subcolumn') }
429
+ end
430
+
431
+ def test_remove_value
432
+ @twitter.insert(:Statuses, key, {'body' => 'v'})
433
+ @twitter.remove(:Statuses, key, 'body')
434
+ assert_nil @twitter.get(:Statuses, key, 'body')
435
+ assert_nil @twitter.get(:Statuses, key).timestamps['body']
436
+ end
437
+
438
+ def test_remove_values
439
+ @twitter.insert(:Statuses, key, {'body' => 'v', 'location' => 'v'})
440
+ @twitter.remove(:Statuses, key, ['body', 'location'])
441
+ assert_nil @twitter.get(:Statuses, key, 'body')
442
+ assert_nil @twitter.get(:Statuses, key, 'location')
443
+ end
444
+
445
+ def test_remove_super_key
446
+ @twitter.insert(:StatusRelationships, key, {'user_timelines' => {@uuids[1] => 'v1'}})
447
+ @twitter.remove(:StatusRelationships, key)
448
+ assert_equal({}, @twitter.get(:StatusRelationships, key))
449
+ end
450
+
451
+ def test_remove_super_sub_key
452
+ @twitter.insert(:StatusRelationships, key, {'user_timelines' => {@uuids[1] => 'v1'}})
453
+ @twitter.remove(:StatusRelationships, key, 'user_timelines')
454
+ assert_equal({}, @twitter.get(:StatusRelationships, key, 'user_timelines'))
455
+ end
456
+
457
+ def test_remove_super_value
458
+ columns = {@uuids[1] => 'v1', @uuids[2] => 'v2'}
459
+ column_name_to_remove = @uuids[2]
460
+ @twitter.insert(:StatusRelationships, key, {'user_timelines' => columns})
461
+ @twitter.remove(:StatusRelationships, key, 'user_timelines', column_name_to_remove)
462
+ assert_equal( columns.reject{|k,v| k == column_name_to_remove}, @twitter.get(:StatusRelationships, key, 'user_timelines') )
463
+ assert_nil @twitter.get(:StatusRelationships, key, 'user_timelines').timestamps[column_name_to_remove]
464
+ end
465
+
466
+ def test_clear_column_family
467
+ @twitter.insert(:Statuses, key + "1", {'body' => '1'})
468
+ @twitter.insert(:Statuses, key + "2", {'body' => '2'})
469
+ @twitter.insert(:Statuses, key + "3", {'body' => '3'})
470
+ @twitter.clear_column_family!(:Statuses)
471
+ assert_equal 0, @twitter.count_range(:Statuses)
472
+ end
473
+
474
+ def test_insert_key
475
+ @twitter.insert(:Statuses, key, {'body' => 'v', 'user' => 'v'})
476
+ assert_equal({'body' => 'v', 'user' => 'v'}, @twitter.get(:Statuses, key))
477
+ assert_equal(['body', 'user'], @twitter.get(:Statuses, key).timestamps.keys)
478
+ end
479
+
480
+ def test_insert_super_key
481
+ columns = {@uuids[1] => 'v1', @uuids[2] => 'v2'}
482
+ @twitter.insert(:StatusRelationships, key, {'user_timelines' => columns})
483
+ assert_equal(columns, @twitter.get(:StatusRelationships, key, 'user_timelines'))
484
+ assert_equal(columns.keys.sort, @twitter.get(:StatusRelationships, key, 'user_timelines').timestamps.keys.sort)
485
+ end
486
+
487
+ def test_get_columns
488
+ @twitter.insert(:Statuses, key, {'body' => 'v1', 'user' => 'v2'})
489
+ assert_equal(['v1' , 'v2'], @twitter.get_columns(:Statuses, key, ['body', 'user']))
490
+ end
491
+
492
+ def test_get_column_values_super
493
+ user_columns, mentions_columns = {@uuids[1] => 'v1'}, {@uuids[2] => 'v2'}
494
+ @twitter.insert(:StatusRelationships, key,
495
+ {'user_timelines' => user_columns, 'mentions_timelines' => mentions_columns})
496
+ assert_equal [user_columns, mentions_columns],
497
+ @twitter.get_columns(:StatusRelationships, key, ['user_timelines', 'mentions_timelines'])
498
+ end
499
+
500
+ def test_get_sub_column_values_super
501
+ user_columns = {@uuids[1] => 'v1', @uuids[2] => 'v2'}
502
+ @twitter.insert(:StatusRelationships, key, {'user_timelines' => user_columns})
503
+ assert_equal ['v1', 'v2'],
504
+ @twitter.get_columns(:StatusRelationships, key, 'user_timelines', @uuids[1..2])
505
+ end
506
+
507
+ def test_multi_get_columns
508
+ @twitter.insert(:Users, key + '1', {'body' => 'v1', 'user' => 'v1'})
509
+ @twitter.insert(:Users, key + '2', {'body' => 'v2', 'user' => 'v2'})
510
+ assert_equal(
511
+ OrderedHash[key + '1', ['v1', 'v1'], key + '2', ['v2', 'v2'], 'bogus', [nil, nil]],
512
+ @twitter.multi_get_columns(:Users, [key + '1', key + '2', 'bogus'], ['body', 'user']))
513
+ assert_equal(
514
+ OrderedHash[key + '2', ['v2', 'v2'], 'bogus', [nil, nil], key + '1', ['v1', 'v1']],
515
+ @twitter.multi_get_columns(:Users, [key + '2', 'bogus', key + '1'], ['body', 'user']))
516
+ assert_equal(
517
+ OrderedHash[key + '1', ['v1', 'v1'], key + '2', ['v2', 'v2'], 'bogus', [nil, nil]].keys.sort,
518
+ @twitter.multi_get_columns(:Users, [key + '1', key + '2', 'bogus'], ['body', 'user']).timestamps.keys.sort)
519
+ assert_equal(
520
+ OrderedHash[key + '2', ['v2', 'v2'], 'bogus', [nil, nil], key + '1', ['v1', 'v1']].keys.sort,
521
+ @twitter.multi_get_columns(:Users, [key + '2', 'bogus', key + '1'], ['body', 'user']).timestamps.keys.sort)
522
+ end
523
+
524
+ def test_count_keys
525
+ k = key
526
+ @twitter.insert(:Statuses, k + "1", {'body' => '1'})
527
+ @twitter.insert(:Statuses, k + "2", {'body' => '2'})
528
+ @twitter.insert(:Statuses, k + "3", {'body' => '3'})
529
+ assert_equal 3, @twitter.count_range(:Statuses)
530
+ end
531
+
532
+ def test_count_columns
533
+ columns = (1..200).inject(Hash.new){|h,v| h['column' + v.to_s] = v.to_s; h;}
534
+
535
+ @twitter.insert(:Statuses, key, columns)
536
+ assert_equal 200, @twitter.count_columns(:Statuses, key, :count => 200)
537
+ assert_equal 100, @twitter.count_columns(:Statuses, key) if CASSANDRA_VERSION.to_f >= 0.8
538
+ assert_equal 55, @twitter.count_columns(:Statuses, key, :count => 55) if CASSANDRA_VERSION.to_f >= 0.8
539
+ end
540
+
541
+ def test_count_super_columns
542
+ @twitter.insert(:StatusRelationships, key, {
543
+ 'user_timelines' => {@uuids[1] => 'v1'},
544
+ 'mentions_timelines' => {@uuids[2] => 'v2'}})
545
+ assert_equal 2, @twitter.count_columns(:StatusRelationships, key)
546
+ end
547
+
548
+ def test_count_super_sub_columns
549
+ @twitter.insert(:StatusRelationships, key, {'user_timelines' => {@uuids[1] => 'v1', @uuids[2] => 'v2'}})
550
+ assert_equal 2, @twitter.count_columns(:StatusRelationships, key, 'user_timelines')
551
+ end
552
+
553
+ def test_multi_count_columns
554
+ @twitter.insert(:Users, key + '1', {'body' => 'v1', 'user' => 'v1'})
555
+ @twitter.insert(:Users, key + '2', {'body' => 'v2', 'user' => 'v2'})
556
+ assert_equal(
557
+ OrderedHash[key + '1', 2, key + '2', 2, 'bogus', 0],
558
+ @twitter.multi_count_columns(:Users, [key + '1', key + '2', 'bogus']))
559
+ assert_equal(
560
+ OrderedHash[key + '2', 2, 'bogus', 0, key + '1', 2],
561
+ @twitter.multi_count_columns(:Users, [key + '2', 'bogus', key + '1']))
562
+ end
563
+
564
+ def test_batch_mutate
565
+ k = key
566
+
567
+ @twitter.insert(:Users, k + '0', {'delete_me' => 'v0', 'keep_me' => 'v0'})
568
+ @twitter.insert(:Users, k + '1', {'body' => 'v1', 'user' => 'v1'})
569
+ initial_subcolumns = {@uuids[1] => 'v1', @uuids[2] => 'v2'}
570
+ @twitter.insert(:StatusRelationships, k, {'user_timelines' => initial_subcolumns, 'dummy_supercolumn' => {@uuids[5] => 'value'}})
571
+ assert_equal(initial_subcolumns, @twitter.get(:StatusRelationships, k, 'user_timelines'))
572
+ assert_equal({@uuids[5] => 'value'}, @twitter.get(:StatusRelationships, k, 'dummy_supercolumn'))
573
+ new_subcolumns = {@uuids[3] => 'v3', @uuids[4] => 'v4'}
574
+ subcolumn_to_delete = initial_subcolumns.keys.first # the first column of the initial set
575
+
576
+ @twitter.batch do
577
+ # Normal Columns
578
+ @twitter.insert(:Users, k + '2', {'body' => 'v2', 'user' => 'v2'})
579
+ @twitter.insert(:Users, k + '3', {'body' => 'bogus', 'user' => 'v3'})
580
+ @twitter.insert(:Users, k + '3', {'body' => 'v3', 'location' => 'v3'})
581
+ @twitter.insert(:Statuses, k + '3', {'body' => 'v'})
582
+ @twitter.add(:UserCounters, 'bob', 5, 'tweet_count') if CASSANDRA_VERSION.to_f >= 0.8
583
+
584
+ assert_equal({'delete_me' => 'v0', 'keep_me' => 'v0'}, @twitter.get(:Users, k + '0')) # Written
585
+ assert_equal({'body' => 'v1', 'user' => 'v1'}, @twitter.get(:Users, k + '1')) # Written
586
+ assert_equal({}, @twitter.get(:Users, k + '2')) # Not yet written
587
+ assert_equal({}, @twitter.get(:Statuses, k + '3')) # Not yet written
588
+ assert_equal({}, @twitter.get(:UserCounters, 'bob')) if CASSANDRA_VERSION.to_f >= 0.8 # Written
589
+
590
+ @twitter.remove(:Users, k + '1') # Full row
591
+ assert_equal({'body' => 'v1', 'user' => 'v1'}, @twitter.get(:Users, k + '1')) # Not yet removed
592
+
593
+ @twitter.remove(:Users, k + '0', 'delete_me') # A single column of the row
594
+ assert_equal({'delete_me' => 'v0', 'keep_me' => 'v0'}, @twitter.get(:Users, k + '0')) # Not yet removed
595
+
596
+ @twitter.remove(:Users, k + '4')
597
+ @twitter.insert(:Users, k + '4', {'body' => 'v4', 'user' => 'v4'})
598
+ assert_equal({}, @twitter.get(:Users, k + '4')) # Not yet written
599
+
600
+ # SuperColumns
601
+ # Add and delete new sub columns to the user timeline supercolumn
602
+ @twitter.insert(:StatusRelationships, k, {'user_timelines' => new_subcolumns })
603
+ @twitter.remove(:StatusRelationships, k, 'user_timelines' , subcolumn_to_delete ) # Delete the first of the initial_subcolumns from the user_timeline supercolumn
604
+ assert_equal(initial_subcolumns, @twitter.get(:StatusRelationships, k, 'user_timelines')) # No additions or deletes reflected yet
605
+ # Delete a complete supercolumn
606
+ @twitter.remove(:StatusRelationships, k, 'dummy_supercolumn' ) # Delete the full dummy supercolumn
607
+ assert_equal({@uuids[5] => 'value'}, @twitter.get(:StatusRelationships, k, 'dummy_supercolumn')) # dummy supercolumn not yet deleted
608
+ end
609
+
610
+ assert_equal({'body' => 'v2', 'user' => 'v2'}, @twitter.get(:Users, k + '2')) # Written
611
+ assert_equal({'body' => 'v3', 'user' => 'v3', 'location' => 'v3'}, @twitter.get(:Users, k + '3')) # Written and compacted
612
+ assert_equal({'body' => 'v4', 'user' => 'v4'}, @twitter.get(:Users, k + '4')) # Written
613
+ assert_equal({'body' => 'v'}, @twitter.get(:Statuses, k + '3')) # Written
614
+ assert_equal({'tweet_count' => 5}, @twitter.get(:UserCounters, 'bob')) if CASSANDRA_VERSION.to_f >= 0.8 # Written
615
+ assert_equal({}, @twitter.get(:Users, k + '1')) # Removed
616
+
617
+ assert_equal({ 'keep_me' => 'v0'}, @twitter.get(:Users, k + '0')) # 'delete_me' column removed
618
+
619
+
620
+ assert_equal({'body' => 'v2', 'user' => 'v2'}.keys.sort, @twitter.get(:Users, k + '2').timestamps.keys.sort) # Written
621
+ assert_equal({'body' => 'v3', 'user' => 'v3', 'location' => 'v3'}.keys.sort, @twitter.get(:Users, k + '3').timestamps.keys.sort) # Written and compacted
622
+ assert_equal({'body' => 'v4', 'user' => 'v4'}.keys.sort, @twitter.get(:Users, k + '4').timestamps.keys.sort) # Written
623
+ assert_equal({'body' => 'v'}.keys.sort, @twitter.get(:Statuses, k + '3').timestamps.keys.sort) # Written
624
+
625
+ # Final result: initial_subcolumns - initial_subcolumns.first + new_subcolumns
626
+ resulting_subcolumns = initial_subcolumns.merge(new_subcolumns).reject{|k2,v| k2 == subcolumn_to_delete }
627
+ assert_equal(resulting_subcolumns, @twitter.get(:StatusRelationships, key, 'user_timelines'))
628
+ assert_equal({}, @twitter.get(:StatusRelationships, key, 'dummy_supercolumn')) # dummy supercolumn deleted
629
+
630
+ end
631
+
632
+ def test_batch_queue_size
633
+ k = key
634
+
635
+ @twitter.insert(:Users, k + '0', {'delete_me' => 'v0', 'keep_me' => 'v0'})
636
+ @twitter.insert(:Users, k + '1', {'body' => 'v1', 'user' => 'v1'})
637
+ initial_subcolumns = {@uuids[1] => 'v1', @uuids[2] => 'v2'}
638
+ @twitter.insert(:StatusRelationships, k, {'user_timelines' => initial_subcolumns, 'dummy_supercolumn' => {@uuids[5] => 'value'}})
639
+ assert_equal(initial_subcolumns, @twitter.get(:StatusRelationships, k, 'user_timelines'))
640
+ assert_equal({@uuids[5] => 'value'}, @twitter.get(:StatusRelationships, k, 'dummy_supercolumn'))
641
+ new_subcolumns = {@uuids[3] => 'v3', @uuids[4] => 'v4'}
642
+ subcolumn_to_delete = initial_subcolumns.keys.first # the first column of the initial set
643
+
644
+ @twitter.batch(:queue_size => 5) do
645
+ # Normal Columns
646
+ @twitter.insert(:Users, k + '2', {'body' => 'v2', 'user' => 'v2'})
647
+ @twitter.insert(:Users, k + '3', {'body' => 'bogus', 'user' => 'v3'})
648
+ @twitter.insert(:Users, k + '3', {'body' => 'v3', 'location' => 'v3'})
649
+ @twitter.insert(:Statuses, k + '3', {'body' => 'v'})
650
+
651
+ assert_equal({'delete_me' => 'v0', 'keep_me' => 'v0'}, @twitter.get(:Users, k + '0')) # Written
652
+ assert_equal({'body' => 'v1', 'user' => 'v1'}, @twitter.get(:Users, k + '1')) # Written
653
+ assert_equal({}, @twitter.get(:Users, k + '2')) # Not yet written
654
+ assert_equal({}, @twitter.get(:Statuses, k + '3')) # Not yet written
655
+ assert_equal({}, @twitter.get(:UserCounters, 'bob')) if CASSANDRA_VERSION.to_f >= 0.8 # Written
656
+
657
+ if CASSANDRA_VERSION.to_f >= 0.8
658
+ @twitter.add(:UserCounters, 'bob', 5, 'tweet_count')
659
+ else
660
+ @twitter.insert(:Users, k + '2', {'body' => 'v2', 'user' => 'v2'})
661
+ end
662
+ # Flush!
663
+
664
+ assert_equal({'body' => 'v2', 'user' => 'v2'}, @twitter.get(:Users, k + '2')) # Written
665
+ assert_equal({'body' => 'v3', 'user' => 'v3', 'location' => 'v3'}, @twitter.get(:Users, k + '3')) # Written and compacted
666
+ assert_equal({'body' => 'v'}, @twitter.get(:Statuses, k + '3')) # Written
667
+ assert_equal({'tweet_count' => 5}, @twitter.get(:UserCounters, 'bob')) if CASSANDRA_VERSION.to_f >= 0.8 # Written
668
+
669
+ @twitter.remove(:Users, k + '1') # Full row
670
+ @twitter.remove(:Users, k + '0', 'delete_me') # A single column of the row
671
+ @twitter.remove(:Users, k + '4')
672
+ @twitter.insert(:Users, k + '4', {'body' => 'v4', 'user' => 'v4'})
673
+
674
+ assert_equal({'body' => 'v1', 'user' => 'v1'}, @twitter.get(:Users, k + '1')) # Not yet removed
675
+ assert_equal({'delete_me' => 'v0', 'keep_me' => 'v0'}, @twitter.get(:Users, k + '0')) # Not yet removed
676
+ assert_equal({}, @twitter.get(:Users, k + '4')) # Not yet written
677
+
678
+ @twitter.insert(:Users, k + '5', {'body' => 'v5', 'user' => 'v5'})
679
+ # Flush!
680
+
681
+ assert_equal({'body' => 'v4', 'user' => 'v4'}, @twitter.get(:Users, k + '4')) # Written
682
+ assert_equal({}, @twitter.get(:Users, k + '1')) # Removed
683
+ assert_equal({ 'keep_me' => 'v0'}, @twitter.get(:Users, k + '0')) # 'delete_me' column removed
684
+
685
+ assert_equal({'body' => 'v2', 'user' => 'v2'}.keys.sort, @twitter.get(:Users, k + '2').timestamps.keys.sort) # Written
686
+ assert_equal({'body' => 'v3', 'user' => 'v3', 'location' => 'v3'}.keys.sort, @twitter.get(:Users, k + '3').timestamps.keys.sort) # Written and compacted
687
+ assert_equal({'body' => 'v4', 'user' => 'v4'}.keys.sort, @twitter.get(:Users, k + '4').timestamps.keys.sort) # Written
688
+ assert_equal({'body' => 'v'}.keys.sort, @twitter.get(:Statuses, k + '3').timestamps.keys.sort) # Written
689
+
690
+ # SuperColumns
691
+ # Add and delete new sub columns to the user timeline supercolumn
692
+ @twitter.insert(:StatusRelationships, k, {'user_timelines' => new_subcolumns })
693
+ @twitter.remove(:StatusRelationships, k, 'user_timelines' , subcolumn_to_delete ) # Delete the first of the initial_subcolumns from the user_timeline supercolumn
694
+ # Delete a complete supercolumn
695
+ @twitter.remove(:StatusRelationships, k, 'dummy_supercolumn' ) # Delete the full dummy supercolumn
696
+ end
697
+
698
+ # Final result: initial_subcolumns - initial_subcolumns.first + new_subcolumns
699
+ resulting_subcolumns = initial_subcolumns.merge(new_subcolumns).reject{|k2,v| k2 == subcolumn_to_delete }
700
+ assert_equal(resulting_subcolumns, @twitter.get(:StatusRelationships, key, 'user_timelines'))
701
+ assert_equal({}, @twitter.get(:StatusRelationships, key, 'dummy_supercolumn')) # dummy supercolumn deleted
702
+ end
703
+
704
+ def test_complain_about_nil_key
705
+ assert_raises(ArgumentError) do
706
+ @twitter.insert(:Statuses, nil, {'text' => 'crap'})
707
+ end
708
+ end
709
+
710
+ def test_nil_sub_column_value
711
+ @twitter.insert(:Indexes, 'asdf', {"thing" => {'jkl' => ''} })
712
+ end
713
+
714
+ def test_disconnect!
715
+ @twitter.disconnect!
716
+ assert_nil @twitter.instance_variable_get(:@client)
717
+ end
718
+
719
+ def test_disconnect_when_not_connected!
720
+ assert_nothing_raised do
721
+ @twitter = Cassandra.new('Twitter', "127.0.0.1:9160", :retries => 2, :exception_classes => [])
722
+ @twitter.disconnect!
723
+ end
724
+ end
725
+
726
+ def test_super_allows_for_non_string_values_while_normal_does_not
727
+ columns = {'user_timelines' => {@uuids[4] => '4', @uuids[5] => '5'}}
728
+
729
+ @twitter.insert(:StatusRelationships, key, columns)
730
+ @twitter.insert(:Statuses, key, { 'body' => '1' })
731
+ end
732
+
733
+ def test_batch_over_deletes
734
+ k = key
735
+
736
+ @twitter.batch do
737
+ @twitter.insert(:Users, k, {'body' => 'body', 'user' => 'user'})
738
+ @twitter.remove(:Users, k, 'body')
739
+ end
740
+
741
+ assert_equal({'user' => 'user'}, @twitter.get(:Users, k))
742
+ end
743
+
744
+ def test_each_key
745
+ num_users = rand(60)
746
+ num_users.times do |twit_counter|
747
+ @twitter.insert(:Users, "Twitter : #{twit_counter}", {'body' => 'v1', 'user' => 'v1'})
748
+ end
749
+ counter = 0
750
+ @twitter.each_key(:Users) do |_, _|
751
+ counter += 1
752
+ end
753
+ assert_equal num_users, counter
754
+ end
755
+
756
+ def test_each_with_column_predicate
757
+ num_users = rand(60)
758
+ num_users.times do |twit_counter|
759
+ @twitter.insert(:Users, "Twitter : #{twit_counter}", {'body' => 'v1', 'user' => 'v1'})
760
+ end
761
+ counter = 0
762
+ @twitter.each(:Users, :batch_size => 10, :start => 'body', :finish => 'body') do |key, columns|
763
+ assert_equal 1, columns.length
764
+ counter += 1
765
+ end
766
+ assert_equal num_users, counter
767
+ end
768
+
769
+ def test_each_with_super_column
770
+ num_users = rand(50)
771
+ block_name = key
772
+ num_users.times do |twit_counter|
773
+ @twitter.insert(:StatusRelationships, block_name + twit_counter.to_s, {
774
+ 'user_timelines' => {@uuids[1] => 'v1', @uuids[2] => 'v2'},
775
+ 'mentions_timelines' => {@uuids[3] => 'v3'}})
776
+ end
777
+
778
+ counter = 0
779
+ # Restrict to one super column ::
780
+ @twitter.each(:StatusRelationships, :batch_size => 10, :start => 'user_timelines', :finish => 'user_timelines') do |key, columns|
781
+ columns.each do |_, column_value|
782
+ assert_equal 2, column_value.length
783
+ end
784
+ counter += 1
785
+ end
786
+
787
+ #Both super columns
788
+ @twitter.each(:StatusRelationships, :batch_size => 10, :start => 'mentions_timelines', :finish => 'user_timelines') do |key,columns|
789
+ assert_equal 2, columns.length
790
+ counter += 1
791
+ end
792
+
793
+ assert_equal num_users*2, counter
794
+
795
+ end
796
+
797
+ def test_each_column_types
798
+ num_users = rand(60)
799
+ num_users.times do |twit_counter|
800
+ @type_conversions.insert(:UUIDColumnConversion, twit_counter.to_s, {@uuids[1] => 'v1'})
801
+ end
802
+ counter = 0
803
+ @type_conversions.each(:UUIDColumnConversion) do |_, columns|
804
+ counter += 1
805
+ columns.keys.each {|column_name| assert_equal SimpleUUID::UUID, column_name.class}
806
+ end
807
+ assert_equal num_users, counter
808
+ end
809
+
810
+
811
+ if CASSANDRA_VERSION.to_f >= 0.7
812
+ def test_creating_and_dropping_new_index
813
+ @twitter.create_index('Twitter', 'Statuses', 'column_name', 'BytesType')
814
+ assert_nil @twitter.create_index('Twitter', 'Statuses', 'column_name', 'BytesType')
815
+
816
+ @twitter.drop_index('Twitter', 'Statuses', 'column_name')
817
+ assert_nil @twitter.drop_index('Twitter', 'Statuses', 'column_name')
818
+
819
+ # Recreating and redropping the same index should not error either.
820
+ @twitter.create_index('Twitter', 'Statuses', 'column_name', 'BytesType')
821
+ @twitter.drop_index('Twitter', 'Statuses', 'column_name')
822
+ end
823
+
824
+ def test_get_indexed_slices
825
+ @twitter.insert(:Statuses, 'row_a', {
826
+ 'tags' => 'a',
827
+ 'y' => 'foo'
828
+ })
829
+ @twitter.insert(:Statuses, 'row_b', {
830
+ 'tags' => 'b',
831
+ 'y' => 'foo'
832
+ })
833
+ [1,2].each do |i|
834
+ @twitter.insert(:Statuses, "row_c_#{i}", {
835
+ 'tags' => 'c',
836
+ 'y' => 'a'
837
+ })
838
+ end
839
+ [3,4].each do |i|
840
+ @twitter.insert(:Statuses, "row_c_#{i}", {
841
+ 'tags' => 'c',
842
+ 'y' => 'b'
843
+ })
844
+ end
845
+ @twitter.insert(:Statuses, 'row_d', {
846
+ 'tags' => 'd',
847
+ 'y' => 'foo'
848
+ })
849
+ @twitter.insert(:Statuses, 'row_e', {
850
+ 'tags' => 'e',
851
+ 'y' => 'bar'
852
+ })
853
+
854
+ # Test == operator (single clause)
855
+ rows = @twitter.get_indexed_slices(:Statuses, [
856
+ {:column_name => 'tags',
857
+ :value => 'c',
858
+ :comparison => "=="}
859
+ ])
860
+ assert_has_keys %w[row_c_1 row_c_2 row_c_3 row_c_4], rows
861
+
862
+ # Test other operators
863
+ # Currently (as of Cassandra 1.1) you can't use anything but == as the
864
+ # primary query -- you must match on == first, and subsequent clauses are
865
+ # then applied as filters -- so that's what we are doing here.
866
+
867
+ # Test > operator
868
+ rows = @twitter.get_indexed_slices(:Statuses, [
869
+ {:column_name => 'tags',
870
+ :value => 'c',
871
+ :comparison => "=="},
872
+ {:column_name => 'y',
873
+ :value => 'a',
874
+ :comparison => ">"}
875
+ ])
876
+ assert_has_keys %w[row_c_3 row_c_4], rows
877
+
878
+ # Test >= operator
879
+ rows = @twitter.get_indexed_slices(:Statuses, [
880
+ {:column_name => 'tags',
881
+ :value => 'c',
882
+ :comparison => "=="},
883
+ {:column_name => 'y',
884
+ :value => 'a',
885
+ :comparison => ">="}
886
+ ])
887
+ assert_has_keys %w[row_c_1 row_c_2 row_c_3 row_c_4], rows
888
+
889
+ # Test < operator
890
+ rows = @twitter.get_indexed_slices(:Statuses, [
891
+ {:column_name => 'tags',
892
+ :value => 'c',
893
+ :comparison => "=="},
894
+ {:column_name => 'y',
895
+ :value => 'b',
896
+ :comparison => "<"}
897
+ ])
898
+ assert_has_keys %w[row_c_1 row_c_2], rows
899
+
900
+ # Test <= operator
901
+ rows = @twitter.get_indexed_slices(:Statuses, [
902
+ {:column_name => 'tags',
903
+ :value => 'c',
904
+ :comparison => "=="},
905
+ {:column_name => 'y',
906
+ :value => 'b',
907
+ :comparison => "<="}
908
+ ])
909
+ assert_has_keys %w[row_c_1 row_c_2 row_c_3 row_c_4], rows
910
+
911
+ # Test query on a non-indexed column
912
+ unless self.is_a?(CassandraMockTest)
913
+ assert_raises(CassandraThrift::InvalidRequestException) do
914
+ @twitter.get_indexed_slices(:Statuses, [
915
+ {:column_name => 'y',
916
+ :value => 'foo',
917
+ :comparison => "=="}
918
+ ])
919
+ end
920
+ end
921
+
922
+ # Test start key
923
+ rows = @twitter.get_indexed_slices(:Statuses, [
924
+ {:column_name => 'tags',
925
+ :value => 'c',
926
+ :comparison => "=="},
927
+ ], :start_key => 'row_c_2')
928
+ assert_equal 'row_c_2', rows.keys.first
929
+ # <- can't test any keys after that since it's going to be random
930
+
931
+ # Test key_start option
932
+ rows = @twitter.get_indexed_slices(:Statuses, [
933
+ {:column_name => 'tags',
934
+ :value => 'c',
935
+ :comparison => "=="},
936
+ ], :key_start => 'row_c_2')
937
+ assert_equal 'row_c_2', rows.keys.first
938
+ # <- can't test any keys after that since it's going to be random
939
+
940
+ # Test key count
941
+ rows = @twitter.get_indexed_slices(:Statuses, [
942
+ {:column_name => 'tags',
943
+ :value => 'c',
944
+ :comparison => "=="}
945
+ ], :key_count => 2)
946
+ assert_equal 2, rows.length
947
+ # <- can't test which keys are present since it's going to be random
948
+ end
949
+
950
+ def test_get_indexed_slices_with_IndexClause_objects
951
+ @twitter.insert(:Statuses, 'row_a', {
952
+ 'tags' => 'a',
953
+ 'y' => 'foo'
954
+ })
955
+ @twitter.insert(:Statuses, 'row_b', {
956
+ 'tags' => 'b',
957
+ 'y' => 'foo'
958
+ })
959
+ [1,2].each do |i|
960
+ @twitter.insert(:Statuses, "row_c_#{i}", {
961
+ 'tags' => 'c',
962
+ 'y' => 'a'
963
+ })
964
+ end
965
+ [3,4].each do |i|
966
+ @twitter.insert(:Statuses, "row_c_#{i}", {
967
+ 'tags' => 'c',
968
+ 'y' => 'b'
969
+ })
970
+ end
971
+ @twitter.insert(:Statuses, 'row_d', {
972
+ 'tags' => 'd',
973
+ 'y' => 'foo'
974
+ })
975
+ @twitter.insert(:Statuses, 'row_e', {
976
+ 'tags' => 'e',
977
+ 'y' => 'bar'
978
+ })
979
+
980
+ # Test == operator (single clause)
981
+ index_clause = @twitter.create_index_clause([
982
+ @twitter.create_index_expression('tags', 'c', '==')
983
+ ])
984
+ rows = @twitter.get_indexed_slices(:Statuses, index_clause)
985
+ assert_has_keys %w[row_c_1 row_c_2 row_c_3 row_c_4], rows
986
+
987
+ # Test other operators
988
+ # Currently (as of Cassandra 1.1) you can't use anything but == as the
989
+ # primary query -- you must match on == first, and subsequent clauses are
990
+ # then applied as filters -- so that's what we are doing here.
991
+
992
+ # Test > operator
993
+ index_clause = @twitter.create_index_clause([
994
+ @twitter.create_index_expression('tags', 'c', '=='),
995
+ @twitter.create_index_expression('y', 'a', '>'),
996
+ ])
997
+ rows = @twitter.get_indexed_slices(:Statuses, index_clause)
998
+ assert_has_keys %w[row_c_3 row_c_4], rows
999
+
1000
+ # Test >= operator
1001
+ index_clause = @twitter.create_index_clause([
1002
+ @twitter.create_index_expression('tags', 'c', '=='),
1003
+ @twitter.create_index_expression('y', 'a', '>=')
1004
+ ])
1005
+ rows = @twitter.get_indexed_slices(:Statuses, index_clause)
1006
+ assert_has_keys %w[row_c_1 row_c_2 row_c_3 row_c_4], rows
1007
+
1008
+ # Test < operator
1009
+ index_clause = @twitter.create_index_clause([
1010
+ @twitter.create_index_expression('tags', 'c', '=='),
1011
+ @twitter.create_index_expression('y', 'b', '<')
1012
+ ])
1013
+ rows = @twitter.get_indexed_slices(:Statuses, index_clause)
1014
+ assert_has_keys %w[row_c_1 row_c_2], rows
1015
+
1016
+ # Test <= operator
1017
+ index_clause = @twitter.create_index_clause([
1018
+ @twitter.create_index_expression('tags', 'c', '=='),
1019
+ @twitter.create_index_expression('y', 'b', '<=')
1020
+ ])
1021
+ rows = @twitter.get_indexed_slices(:Statuses, index_clause)
1022
+ assert_has_keys %w[row_c_1 row_c_2 row_c_3 row_c_4], rows
1023
+
1024
+ # Test query on a non-indexed column
1025
+ unless self.is_a?(CassandraMockTest)
1026
+ assert_raises(CassandraThrift::InvalidRequestException) do
1027
+ index_clause = @twitter.create_index_clause([
1028
+ @twitter.create_index_expression('y', 'foo', '==')
1029
+ ])
1030
+ @twitter.get_indexed_slices(:Statuses, index_clause)
1031
+ end
1032
+ end
1033
+
1034
+ # Test start key
1035
+ index_clause = @twitter.create_index_clause([
1036
+ @twitter.create_index_expression('tags', 'c', '==')
1037
+ ], 'row_c_2')
1038
+ rows = @twitter.get_indexed_slices(:Statuses, index_clause)
1039
+ assert_equal 'row_c_2', rows.keys.first
1040
+ # <- can't test any keys after that since it's going to be random
1041
+
1042
+ # Test key count
1043
+ index_clause = @twitter.create_index_clause([
1044
+ @twitter.create_index_expression('tags', 'c', '==')
1045
+ ], "", 2)
1046
+ rows = @twitter.get_indexed_slices(:Statuses, index_clause)
1047
+ assert_equal 2, rows.length
1048
+ # <- can't test which keys are present since it's going to be random
1049
+ end
1050
+
1051
+ def test_create_index_clause
1052
+ return if self.is_a?(CassandraMockTest)
1053
+
1054
+ ie = CassandraThrift::IndexExpression.new(
1055
+ :column_name => 'foo',
1056
+ :value => 'x',
1057
+ :op => '=='
1058
+ )
1059
+
1060
+ ic = @twitter.create_index_clause([ie], 'aaa', 250)
1061
+ assert_instance_of CassandraThrift::IndexClause, ic
1062
+ assert_equal 'aaa', ic.start_key
1063
+ assert_equal ie, ic.expressions[0]
1064
+ assert_equal 250, ic.count
1065
+
1066
+ # test alias
1067
+ ic = @twitter.create_idx_clause([ie], 'aaa', 250)
1068
+ assert_instance_of CassandraThrift::IndexClause, ic
1069
+ assert_equal 'aaa', ic.start_key
1070
+ assert_equal ie, ic.expressions[0]
1071
+ assert_equal 250, ic.count
1072
+ end
1073
+
1074
+ def test_create_index_expression
1075
+ return if self.is_a?(CassandraMockTest)
1076
+
1077
+ # EQ operator
1078
+ [nil, "EQ", "eq", "=="].each do |op|
1079
+ ie = @twitter.create_index_expression('foo', 'x', op)
1080
+ assert_instance_of CassandraThrift::IndexExpression, ie
1081
+ assert_equal 'foo', ie.column_name
1082
+ assert_equal 'x', ie.value
1083
+ assert_equal CassandraThrift::IndexOperator::EQ, ie.op
1084
+ end
1085
+ # alias
1086
+ [nil, "EQ", "eq", "=="].each do |op|
1087
+ ie = @twitter.create_idx_expr('foo', 'x', op)
1088
+ assert_instance_of CassandraThrift::IndexExpression, ie
1089
+ assert_equal 'foo', ie.column_name
1090
+ assert_equal 'x', ie.value
1091
+ assert_equal CassandraThrift::IndexOperator::EQ, ie.op
1092
+ end
1093
+
1094
+ # GTE operator
1095
+ ["GTE", "gte", ">="].each do |op|
1096
+ ie = @twitter.create_index_expression('foo', 'x', op)
1097
+ assert_instance_of CassandraThrift::IndexExpression, ie
1098
+ assert_equal 'foo', ie.column_name
1099
+ assert_equal 'x', ie.value
1100
+ assert_equal CassandraThrift::IndexOperator::GTE, ie.op
1101
+ end
1102
+ # alias
1103
+ ["GTE", "gte", ">="].each do |op|
1104
+ ie = @twitter.create_idx_expr('foo', 'x', op)
1105
+ assert_instance_of CassandraThrift::IndexExpression, ie
1106
+ assert_equal 'foo', ie.column_name
1107
+ assert_equal 'x', ie.value
1108
+ assert_equal CassandraThrift::IndexOperator::GTE, ie.op
1109
+ end
1110
+
1111
+ # GT operator
1112
+ ["GT", "gt", ">"].each do |op|
1113
+ ie = @twitter.create_index_expression('foo', 'x', op)
1114
+ assert_instance_of CassandraThrift::IndexExpression, ie
1115
+ assert_equal 'foo', ie.column_name
1116
+ assert_equal 'x', ie.value
1117
+ assert_equal CassandraThrift::IndexOperator::GT, ie.op
1118
+ end
1119
+ # alias
1120
+ ["GT", "gt", ">"].each do |op|
1121
+ ie = @twitter.create_idx_expr('foo', 'x', op)
1122
+ assert_instance_of CassandraThrift::IndexExpression, ie
1123
+ assert_equal 'foo', ie.column_name
1124
+ assert_equal 'x', ie.value
1125
+ assert_equal CassandraThrift::IndexOperator::GT, ie.op
1126
+ end
1127
+
1128
+ # LTE operator
1129
+ ["LTE", "lte", "<="].each do |op|
1130
+ ie = @twitter.create_index_expression('foo', 'x', op)
1131
+ assert_instance_of CassandraThrift::IndexExpression, ie
1132
+ assert_equal 'foo', ie.column_name
1133
+ assert_equal 'x', ie.value
1134
+ assert_equal CassandraThrift::IndexOperator::LTE, ie.op
1135
+ end
1136
+ # alias
1137
+ ["LTE", "lte", "<="].each do |op|
1138
+ ie = @twitter.create_idx_expr('foo', 'x', op)
1139
+ assert_instance_of CassandraThrift::IndexExpression, ie
1140
+ assert_equal 'foo', ie.column_name
1141
+ assert_equal 'x', ie.value
1142
+ assert_equal CassandraThrift::IndexOperator::LTE, ie.op
1143
+ end
1144
+
1145
+ # LT operator
1146
+ ["LT", "lt", "<"].each do |op|
1147
+ ie = @twitter.create_index_expression('foo', 'x', op)
1148
+ assert_instance_of CassandraThrift::IndexExpression, ie
1149
+ assert_equal 'foo', ie.column_name
1150
+ assert_equal 'x', ie.value
1151
+ assert_equal CassandraThrift::IndexOperator::LT, ie.op
1152
+ end
1153
+ # alias
1154
+ ["LT", "lt", "<"].each do |op|
1155
+ ie = @twitter.create_idx_expr('foo', 'x', op)
1156
+ assert_instance_of CassandraThrift::IndexExpression, ie
1157
+ assert_equal 'foo', ie.column_name
1158
+ assert_equal 'x', ie.value
1159
+ assert_equal CassandraThrift::IndexOperator::LT, ie.op
1160
+ end
1161
+
1162
+ # unknown operator
1163
+ ie = @twitter.create_index_expression('foo', 'x', '~$')
1164
+ assert_equal nil, ie.op
1165
+ # alias
1166
+ ie = @twitter.create_idx_expr('foo', 'x', '~$')
1167
+ assert_equal nil, ie.op
1168
+ end
1169
+
1170
+ def test_column_family_mutation
1171
+ k = key
1172
+
1173
+ if @twitter.column_families.include?(k)
1174
+ @twitter.drop_column_family(k)
1175
+ end
1176
+
1177
+ # Verify add_column_family works as desired.
1178
+ @twitter.add_column_family(
1179
+ Cassandra::ColumnFamily.new(
1180
+ :keyspace => 'Twitter',
1181
+ :name => k
1182
+ )
1183
+ )
1184
+ assert @twitter.column_families.include?(k)
1185
+
1186
+ if CASSANDRA_VERSION.to_f == 0.7
1187
+ # Verify rename_column_family works properly
1188
+ @twitter.rename_column_family(k, k + '_renamed')
1189
+ assert @twitter.column_families.include?(k + '_renamed')
1190
+
1191
+ # Change it back and validate
1192
+ @twitter.rename_column_family(k + '_renamed', k)
1193
+ assert @twitter.column_families.include?(k)
1194
+ end
1195
+
1196
+ temp_cf_def = @twitter.column_families[k]
1197
+ temp_cf_def.comment = k
1198
+ @twitter.update_column_family(temp_cf_def)
1199
+ assert @twitter.column_families.include?(k)
1200
+
1201
+ @twitter.drop_column_family(k)
1202
+ assert !@twitter.column_families.include?(k)
1203
+ end
1204
+ end
1205
+
1206
+ if CASSANDRA_VERSION.to_f >= 0.8
1207
+ def test_adding_getting_value_in_counter
1208
+ assert_nil @twitter.add(:UserCounters, 'bob', 5, 'tweet_count')
1209
+ assert_equal(5, @twitter.get(:UserCounters, 'bob', 'tweet_count'))
1210
+ assert_nil @twitter.get(:UserCounters, 'bogus', 'tweet_count')
1211
+ end
1212
+
1213
+ def test_get_counter_slice
1214
+ assert_nil @twitter.add(:UserCounters, 'bob', 5, 'tweet_count')
1215
+ assert_equal({'tweet_count' => 5}, @twitter.get(:UserCounters, 'bob', :start => "tweet_count", :finish => "tweet_count"))
1216
+ end
1217
+
1218
+ def test_adding_getting_value_in_multiple_counters
1219
+ assert_nil @twitter.add(:UserCounters, 'bob', 5, 'tweet_count')
1220
+ assert_nil @twitter.add(:UserCounters, 'bob', 7, 'follower_count')
1221
+ assert_equal(5, @twitter.get(:UserCounters, 'bob', 'tweet_count'))
1222
+ assert_nil @twitter.get(:UserCounters, 'bogus', 'tweet_count')
1223
+ assert_equal([5, 7], @twitter.get_columns(:UserCounters, 'bob', ['tweet_count', 'follower_count']))
1224
+ assert_equal([5, 7, nil], @twitter.get_columns(:UserCounters, 'bob', ['tweet_count', 'follower_count', 'bogus']))
1225
+ end
1226
+
1227
+ def test_adding_getting_value_in_multiple_counters_with_super_columns
1228
+ assert_nil @twitter.add(:UserCounterAggregates, 'bob', 1, 'DAU', 'today')
1229
+ assert_nil @twitter.add(:UserCounterAggregates, 'bob', 2, 'DAU', 'tomorrow')
1230
+ assert_equal(1, @twitter.get(:UserCounterAggregates, 'bob', 'DAU', 'today'))
1231
+ assert_equal(2, @twitter.get(:UserCounterAggregates, 'bob', 'DAU', 'tomorrow'))
1232
+ end
1233
+
1234
+ def test_reading_rows_with_super_column_counter
1235
+ assert_nil @twitter.add(:UserCounterAggregates, 'bob', 1, 'DAU', 'today')
1236
+ assert_nil @twitter.add(:UserCounterAggregates, 'bob', 2, 'DAU', 'tomorrow')
1237
+ result = @twitter.get(:UserCounterAggregates, 'bob')
1238
+ assert_equal(1, result.size)
1239
+ assert_equal(2, result.first.size)
1240
+ assert_equal("DAU", result.first[0])
1241
+ assert_equal(1, result.first[1]["today"])
1242
+ assert_equal(2, result.first[1]["tomorrow"])
1243
+ end
1244
+
1245
+ def test_composite_column_type_conversion
1246
+ columns = {}
1247
+ @composites.each_with_index do |c, index|
1248
+ columns[c] = "value-#{index}"
1249
+ end
1250
+ @type_conversions.insert(:CompositeColumnConversion, key, columns)
1251
+ columns_in_order = [
1252
+ Cassandra::Composite.new([1].pack('N'), "elephant"),
1253
+ Cassandra::Composite.new([5].pack('N'), "aardvark"),
1254
+ Cassandra::Composite.new([5].pack('N'), "zebra"),
1255
+ Cassandra::Composite.new([10].pack('N'), "kangaroo"),
1256
+ ]
1257
+ assert_equal(columns_in_order, @type_conversions.get(:CompositeColumnConversion, key).keys)
1258
+
1259
+ column_slice = @type_conversions.get(:CompositeColumnConversion, key,
1260
+ :start => Cassandra::Composite.new([1].pack('N')),
1261
+ :finish => Cassandra::Composite.new([10].pack('N'))
1262
+ ).keys
1263
+ assert_equal(columns_in_order[0..-2], column_slice)
1264
+
1265
+ column_slice = @type_conversions.get(:CompositeColumnConversion, key,
1266
+ :start => Cassandra::Composite.new([5].pack('N')),
1267
+ :finish => Cassandra::Composite.new([5].pack('N'), :slice => :after)
1268
+ ).keys
1269
+ assert_equal(columns_in_order[1..2], column_slice)
1270
+
1271
+ column_slice = @type_conversions.get(:CompositeColumnConversion, key,
1272
+ :start => Cassandra::Composite.new([5].pack('N'), :slice => :after).to_s
1273
+ ).keys
1274
+ assert_equal([columns_in_order[-1]], column_slice)
1275
+
1276
+ column_slice = @type_conversions.get(:CompositeColumnConversion, key,
1277
+ :finish => Cassandra::Composite.new([10].pack('N'), :slice => :before).to_s
1278
+ ).keys
1279
+ assert_equal(columns_in_order[0..-2], column_slice)
1280
+
1281
+ assert_equal('value-2', @type_conversions.get(:CompositeColumnConversion, key, columns_in_order.first))
1282
+ end
1283
+
1284
+ def test_dynamic_composite_column_type_conversion
1285
+ columns = {}
1286
+ @dynamic_composites.each_with_index do |c, index|
1287
+ columns[c] = "value-#{index}"
1288
+ end
1289
+ @type_conversions.insert(:DynamicComposite, key, columns)
1290
+
1291
+ columns_in_order = [
1292
+ Cassandra::DynamicComposite.new(['IntegerType', [1].pack('N')], ['s', "elephant"]),
1293
+ Cassandra::DynamicComposite.new(['i', [5].pack('N')], ['UTF8Type', "aardvark"]),
1294
+ Cassandra::DynamicComposite.new(['i', [5].pack('N')], ['UTF8Type', "zebra"]),
1295
+ Cassandra::DynamicComposite.new(['IntegerType', [10].pack('N')], ['s', "kangaroo"]),
1296
+ ]
1297
+ assert_equal(columns_in_order, @type_conversions.get(:DynamicComposite, key).keys)
1298
+
1299
+ column_slice = @type_conversions.get(:DynamicComposite, key,
1300
+ :start => Cassandra::DynamicComposite.new(['i', [1].pack('N')]),
1301
+ :finish => Cassandra::DynamicComposite.new(['i', [10].pack('N')])
1302
+ ).keys
1303
+ assert_equal(columns_in_order[0..-2], column_slice)
1304
+
1305
+ column_slice = @type_conversions.get(:DynamicComposite, key,
1306
+ :start => Cassandra::DynamicComposite.new(['IntegerType', [5].pack('N')]),
1307
+ :finish => Cassandra::DynamicComposite.new(['IntegerType', [5].pack('N')], :slice => :after)
1308
+ ).keys
1309
+ assert_equal(columns_in_order[1..2], column_slice)
1310
+
1311
+ column_slice = @type_conversions.get(:DynamicComposite, key,
1312
+ :start => Cassandra::DynamicComposite.new(['i', [5].pack('N')], :slice => :after).to_s
1313
+ ).keys
1314
+ assert_equal([columns_in_order[-1]], column_slice)
1315
+
1316
+ column_slice = @type_conversions.get(:DynamicComposite, key,
1317
+ :finish => Cassandra::DynamicComposite.new(['i', [10].pack('N')], :slice => :before).to_s
1318
+ ).keys
1319
+ assert_equal(columns_in_order[0..-2], column_slice)
1320
+
1321
+ assert_equal('value-2', @type_conversions.get(:DynamicComposite, key, columns_in_order.first))
1322
+ end
1323
+ end
1324
+
1325
+ def test_column_timestamps
1326
+ base_time = Time.now
1327
+ @twitter.insert(:Statuses, "time-key", { "body" => "value" })
1328
+
1329
+ results = @twitter.get(:Statuses, "time-key")
1330
+ assert(results.timestamps["body"] / 1000000 >= base_time.to_i)
1331
+ end
1332
+
1333
+ def test_supercolumn_timestamps
1334
+ base_time = Time.now
1335
+ @twitter.insert(:StatusRelationships, "time-key", { "super" => { @uuids[1] => "value" }})
1336
+
1337
+ results = @twitter.get(:StatusRelationships, "time-key")
1338
+ assert_nil(results.timestamps["super"])
1339
+
1340
+ columns = results["super"]
1341
+ assert(columns.timestamps[@uuids[1]] / 1000000 >= base_time.to_i)
1342
+ end
1343
+
1344
+ def test_keyspace_operations
1345
+ system = Cassandra.new 'system'
1346
+ keyspace_name = 'robots'
1347
+ keyspace_definition = Cassandra::Keyspace.new :name => keyspace_name,
1348
+ :strategy_class => 'SimpleStrategy',
1349
+ :strategy_options => { 'replication_factor' => '2' },
1350
+ :cf_defs => []
1351
+ system.add_keyspace keyspace_definition
1352
+ assert system.keyspaces.any? {|it| it == keyspace_name }
1353
+
1354
+ system.drop_keyspace keyspace_name
1355
+ assert system.keyspaces.none? {|it| it == keyspace_name }
1356
+
1357
+ system.add_keyspace keyspace_definition
1358
+ Cassandra.new(keyspace_name).drop_keyspace
1359
+ assert system.keyspaces.none? {|it| it == keyspace_name }
1360
+ end
1361
+
1362
+ private
1363
+
1364
+ def key
1365
+ caller.first[/`(.*?)'/, 1]
1366
+ end
1367
+ end