cassandra-mavericks 0.21.1

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 (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