sessionm-cassandra 1.0.0

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