]> git.saurik.com Git - redis.git/blob - client-libraries/ruby/spec/redis_spec.rb
max inline request raised again to 1024*1024*256 bytes
[redis.git] / client-libraries / ruby / spec / redis_spec.rb
1 require File.dirname(__FILE__) + '/spec_helper'
2
3 class Foo
4 attr_accessor :bar
5 def initialize(bar)
6 @bar = bar
7 end
8
9 def ==(other)
10 @bar == other.bar
11 end
12 end
13
14 describe "redis" do
15 before(:all) do
16 # use database 15 for testing so we dont accidentally step on you real data
17 @r = Redis.new :db => 15
18 end
19
20 before(:each) do
21 @r['foo'] = 'bar'
22 end
23
24 after(:each) do
25 @r.keys('*').each {|k| @r.del k}
26 end
27
28 after(:all) do
29 @r.quit
30 end
31
32 it 'should be able to PING' do
33 @r.ping.should == 'PONG'
34 end
35
36 it "should be able to GET a key" do
37 @r['foo'].should == 'bar'
38 end
39
40 it "should be able to SET a key" do
41 @r['foo'] = 'nik'
42 @r['foo'].should == 'nik'
43 end
44
45 it "should properly handle trailing newline characters" do
46 @r['foo'] = "bar\n"
47 @r['foo'].should == "bar\n"
48 end
49
50 it "should store and retrieve all possible characters at the beginning and the end of a string" do
51 (0..255).each do |char_idx|
52 string = "#{char_idx.chr}---#{char_idx.chr}"
53 @r['foo'] = string
54 @r['foo'].should == string
55 end
56 end
57
58 it "should be able to SET a key with an expiry" do
59 @r.set('foo', 'bar', 1)
60 @r['foo'].should == 'bar'
61 sleep 2
62 @r['foo'].should == nil
63 end
64
65 it "should be able to SETNX" do
66 @r['foo'] = 'nik'
67 @r['foo'].should == 'nik'
68 @r.setnx 'foo', 'bar'
69 @r['foo'].should == 'nik'
70 end
71 #
72 it "should be able to INCR a key" do
73 @r.del('counter')
74 @r.incr('counter').should == 1
75 @r.incr('counter').should == 2
76 @r.incr('counter').should == 3
77 end
78 #
79 it "should be able to DECR a key" do
80 @r.del('counter')
81 @r.incr('counter').should == 1
82 @r.incr('counter').should == 2
83 @r.incr('counter').should == 3
84 @r.decr('counter').should == 2
85 @r.decr('counter', 2).should == 0
86 end
87 #
88 it "should be able to RANDKEY" do
89 @r.randkey.should_not be_nil
90 end
91 #
92 it "should be able to RENAME a key" do
93 @r.del 'foo'
94 @r.del'bar'
95 @r['foo'] = 'hi'
96 @r.rename 'foo', 'bar'
97 @r['bar'].should == 'hi'
98 end
99 #
100 it "should be able to RENAMENX a key" do
101 @r.del 'foo'
102 @r.del 'bar'
103 @r['foo'] = 'hi'
104 @r['bar'] = 'ohai'
105 @r.renamenx 'foo', 'bar'
106 @r['bar'].should == 'ohai'
107 end
108 #
109 it "should be able to get DBSIZE of the database" do
110 @r.delete 'foo'
111 dbsize_without_foo = @r.dbsize
112 @r['foo'] = 0
113 dbsize_with_foo = @r.dbsize
114
115 dbsize_with_foo.should == dbsize_without_foo + 1
116 end
117 #
118 it "should be able to EXPIRE a key" do
119 @r['foo'] = 'bar'
120 @r.expire 'foo', 1
121 @r['foo'].should == "bar"
122 sleep 2
123 @r['foo'].should == nil
124 end
125 #
126 it "should be able to EXISTS" do
127 @r['foo'] = 'nik'
128 @r.exists('foo').should be_true
129 @r.del 'foo'
130 @r.exists('foo').should be_false
131 end
132 #
133 it "should be able to KEYS" do
134 @r.keys("f*").each { |key| @r.del key }
135 @r['f'] = 'nik'
136 @r['fo'] = 'nak'
137 @r['foo'] = 'qux'
138 @r.keys("f*").sort.should == ['f','fo', 'foo'].sort
139 end
140 #BTM - TODO
141 it "should be able to check the TYPE of a key" do
142 @r['foo'] = 'nik'
143 @r.type('foo').should == "string"
144 @r.del 'foo'
145 @r.type('foo').should == "none"
146 end
147 #
148 it "should be able to push to the head of a list (LPUSH)" do
149 @r.lpush "list", 'hello'
150 @r.lpush "list", 42
151 @r.type('list').should == "list"
152 @r.llen('list').should == 2
153 @r.lpop('list').should == '42'
154 end
155 #
156 it "should be able to push to the tail of a list (RPUSH)" do
157 @r.rpush "list", 'hello'
158 @r.type('list').should == "list"
159 @r.llen('list').should == 1
160 end
161 #
162 it "should be able to pop the tail of a list (RPOP)" do
163 @r.rpush "list", 'hello'
164 @r.rpush"list", 'goodbye'
165 @r.type('list').should == "list"
166 @r.llen('list').should == 2
167 @r.rpop('list').should == 'goodbye'
168 end
169 #
170 it "should be able to pop the head of a list (LPOP)" do
171 @r.rpush "list", 'hello'
172 @r.rpush "list", 'goodbye'
173 @r.type('list').should == "list"
174 @r.llen('list').should == 2
175 @r.lpop('list').should == 'hello'
176 end
177 #
178 it "should be able to get the length of a list (LLEN)" do
179 @r.rpush "list", 'hello'
180 @r.rpush "list", 'goodbye'
181 @r.type('list').should == "list"
182 @r.llen('list').should == 2
183 end
184 #
185 it "should be able to get a range of values from a list (LRANGE)" do
186 @r.rpush "list", 'hello'
187 @r.rpush "list", 'goodbye'
188 @r.rpush "list", '1'
189 @r.rpush "list", '2'
190 @r.rpush "list", '3'
191 @r.type('list').should == "list"
192 @r.llen('list').should == 5
193 @r.lrange('list', 2, -1).should == ['1', '2', '3']
194 end
195 #
196 it "should be able to trim a list (LTRIM)" do
197 @r.rpush "list", 'hello'
198 @r.rpush "list", 'goodbye'
199 @r.rpush "list", '1'
200 @r.rpush "list", '2'
201 @r.rpush "list", '3'
202 @r.type('list').should == "list"
203 @r.llen('list').should == 5
204 @r.ltrim 'list', 0, 1
205 @r.llen('list').should == 2
206 @r.lrange('list', 0, -1).should == ['hello', 'goodbye']
207 end
208 #
209 it "should be able to get a value by indexing into a list (LINDEX)" do
210 @r.rpush "list", 'hello'
211 @r.rpush "list", 'goodbye'
212 @r.type('list').should == "list"
213 @r.llen('list').should == 2
214 @r.lindex('list', 1).should == 'goodbye'
215 end
216 #
217 it "should be able to set a value by indexing into a list (LSET)" do
218 @r.rpush "list", 'hello'
219 @r.rpush "list", 'hello'
220 @r.type('list').should == "list"
221 @r.llen('list').should == 2
222 @r.lset('list', 1, 'goodbye').should == 'OK'
223 @r.lindex('list', 1).should == 'goodbye'
224 end
225 #
226 it "should be able to remove values from a list (LREM)" do
227 @r.rpush "list", 'hello'
228 @r.rpush "list", 'goodbye'
229 @r.type('list').should == "list"
230 @r.llen('list').should == 2
231 @r.lrem('list', 1, 'hello').should == 1
232 @r.lrange('list', 0, -1).should == ['goodbye']
233 end
234 #
235 it "should be able add members to a set (SADD)" do
236 @r.sadd "set", 'key1'
237 @r.sadd "set", 'key2'
238 @r.type('set').should == "set"
239 @r.scard('set').should == 2
240 @r.smembers('set').sort.should == ['key1', 'key2'].sort
241 end
242 #
243 it "should be able delete members to a set (SREM)" do
244 @r.sadd "set", 'key1'
245 @r.sadd "set", 'key2'
246 @r.type('set').should == "set"
247 @r.scard('set').should == 2
248 @r.smembers('set').sort.should == ['key1', 'key2'].sort
249 @r.srem('set', 'key1')
250 @r.scard('set').should == 1
251 @r.smembers('set').should == ['key2']
252 end
253 #
254 it "should be able count the members of a set (SCARD)" do
255 @r.sadd "set", 'key1'
256 @r.sadd "set", 'key2'
257 @r.type('set').should == "set"
258 @r.scard('set').should == 2
259 end
260 #
261 it "should be able test for set membership (SISMEMBER)" do
262 @r.sadd "set", 'key1'
263 @r.sadd "set", 'key2'
264 @r.type('set').should == "set"
265 @r.scard('set').should == 2
266 @r.sismember('set', 'key1').should be_true
267 @r.sismember('set', 'key2').should be_true
268 @r.sismember('set', 'notthere').should be_false
269 end
270 #
271 it "should be able to do set intersection (SINTER)" do
272 @r.sadd "set", 'key1'
273 @r.sadd "set", 'key2'
274 @r.sadd "set2", 'key2'
275 @r.sinter('set', 'set2').should == ['key2']
276 end
277 #
278 it "should be able to do set intersection and store the results in a key (SINTERSTORE)" do
279 @r.sadd "set", 'key1'
280 @r.sadd "set", 'key2'
281 @r.sadd "set2", 'key2'
282 @r.sinterstore('newone', 'set', 'set2').should == 1
283 @r.smembers('newone').should == ['key2']
284 end
285 #
286 it "should be able to do set union (SUNION)" do
287 @r.sadd "set", 'key1'
288 @r.sadd "set", 'key2'
289 @r.sadd "set2", 'key2'
290 @r.sadd "set2", 'key3'
291 @r.sunion('set', 'set2').sort.should == ['key1','key2','key3'].sort
292 end
293 #
294 it "should be able to do set union and store the results in a key (SUNIONSTORE)" do
295 @r.sadd "set", 'key1'
296 @r.sadd "set", 'key2'
297 @r.sadd "set2", 'key2'
298 @r.sadd "set2", 'key3'
299 @r.sunionstore('newone', 'set', 'set2').should == 3
300 @r.smembers('newone').sort.should == ['key1','key2','key3'].sort
301 end
302 #
303 it "should be able to do set difference (SDIFF)" do
304 @r.sadd "set", 'a'
305 @r.sadd "set", 'b'
306 @r.sadd "set2", 'b'
307 @r.sadd "set2", 'c'
308 @r.sdiff('set', 'set2').should == ['a']
309 end
310 #
311 it "should be able to do set difference and store the results in a key (SDIFFSTORE)" do
312 @r.sadd "set", 'a'
313 @r.sadd "set", 'b'
314 @r.sadd "set2", 'b'
315 @r.sadd "set2", 'c'
316 @r.sdiffstore('newone', 'set', 'set2')
317 @r.smembers('newone').should == ['a']
318 end
319 #
320 it "should be able move elements from one set to another (SMOVE)" do
321 @r.sadd 'set1', 'a'
322 @r.sadd 'set1', 'b'
323 @r.sadd 'set2', 'x'
324 @r.smove('set1', 'set2', 'a').should be_true
325 @r.sismember('set2', 'a').should be_true
326 @r.delete('set1')
327 end
328 #
329 it "should be able to do crazy SORT queries" do
330 @r['dog_1'] = 'louie'
331 @r.rpush 'dogs', 1
332 @r['dog_2'] = 'lucy'
333 @r.rpush 'dogs', 2
334 @r['dog_3'] = 'max'
335 @r.rpush 'dogs', 3
336 @r['dog_4'] = 'taj'
337 @r.rpush 'dogs', 4
338 @r.sort('dogs', :get => 'dog_*', :limit => [0,1]).should == ['louie']
339 @r.sort('dogs', :get => 'dog_*', :limit => [0,1], :order => 'desc alpha').should == ['taj']
340 end
341
342 it "should be able to handle array of :get using SORT" do
343 @r['dog:1:name'] = 'louie'
344 @r['dog:1:breed'] = 'mutt'
345 @r.rpush 'dogs', 1
346 @r['dog:2:name'] = 'lucy'
347 @r['dog:2:breed'] = 'poodle'
348 @r.rpush 'dogs', 2
349 @r['dog:3:name'] = 'max'
350 @r['dog:3:breed'] = 'hound'
351 @r.rpush 'dogs', 3
352 @r['dog:4:name'] = 'taj'
353 @r['dog:4:breed'] = 'terrier'
354 @r.rpush 'dogs', 4
355 @r.sort('dogs', :get => ['dog:*:name', 'dog:*:breed'], :limit => [0,1]).should == ['louie', 'mutt']
356 @r.sort('dogs', :get => ['dog:*:name', 'dog:*:breed'], :limit => [0,1], :order => 'desc alpha').should == ['taj', 'terrier']
357 end
358 #
359 it "should provide info" do
360 [:last_save_time, :redis_version, :total_connections_received, :connected_clients, :total_commands_processed, :connected_slaves, :uptime_in_seconds, :used_memory, :uptime_in_days, :changes_since_last_save].each do |x|
361 @r.info.keys.should include(x)
362 end
363 end
364 #
365 it "should be able to flush the database" do
366 @r['key1'] = 'keyone'
367 @r['key2'] = 'keytwo'
368 @r.keys('*').sort.should == ['foo', 'key1', 'key2'].sort #foo from before
369 @r.flushdb
370 @r.keys('*').should == []
371 end
372 #
373 it "should be able to provide the last save time (LASTSAVE)" do
374 savetime = @r.lastsave
375 Time.at(savetime).class.should == Time
376 Time.at(savetime).should <= Time.now
377 end
378
379 it "should be able to MGET keys" do
380 @r['foo'] = 1000
381 @r['bar'] = 2000
382 @r.mget('foo', 'bar').should == ['1000', '2000']
383 @r.mget('foo', 'bar', 'baz').should == ['1000', '2000', nil]
384 end
385
386 it "should bgsave" do
387 @r.bgsave.should == 'OK'
388 end
389
390 it "should handle multiple servers" do
391 require 'dist_redis'
392 @r = DistRedis.new(:hosts=> ['localhost:6379', '127.0.0.1:6379'], :db => 15)
393
394 100.times do |idx|
395 @r[idx] = "foo#{idx}"
396 end
397
398 100.times do |idx|
399 @r[idx].should == "foo#{idx}"
400 end
401 end
402
403 it "should be able to pipeline writes" do
404 @r.pipelined do |pipeline|
405 pipeline.lpush 'list', "hello"
406 pipeline.lpush 'list', 42
407 end
408
409 @r.type('list').should == "list"
410 @r.llen('list').should == 2
411 @r.lpop('list').should == '42'
412 end
413
414 end