]> git.saurik.com Git - redis.git/blob - client-libraries/ruby/spec/redis_spec.rb
__P completely removed from pqsort.c/h
[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.delete 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 == true
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(set_unless_exists)" do
66 @r['foo'] = 'nik'
67 @r['foo'].should == 'nik'
68 @r.set_unless_exists 'foo', 'bar'
69 @r['foo'].should == 'nik'
70 end
71 #
72 it "should be able to INCR(increment) a key" do
73 @r.delete('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(decrement) a key" do
80 @r.delete('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(return a random key)" do
89 @r.randkey.should_not be_nil
90 end
91 #
92 it "should be able to RENAME a key" do
93 @r.delete 'foo'
94 @r.delete '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(rename unless the new key already exists) a key" do
101 @r.delete 'foo'
102 @r.delete 'bar'
103 @r['foo'] = 'hi'
104 @r['bar'] = 'ohai'
105 lambda {@r.rename 'foo', 'bar'}.should raise_error(RedisRenameError)
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(check if key exists)" do
127 @r['foo'] = 'nik'
128 @r.key?('foo').should be_true
129 @r.delete 'foo'
130 @r.key?('foo').should be_false
131 end
132 #
133 it "should be able to KEYS(glob for keys)" do
134 @r.keys("f*").each do |key|
135 @r.delete key
136 end
137 @r['f'] = 'nik'
138 @r['fo'] = 'nak'
139 @r['foo'] = 'qux'
140 @r.keys("f*").sort.should == ['f','fo', 'foo'].sort
141 end
142 #
143 it "should be able to check the TYPE of a key" do
144 @r['foo'] = 'nik'
145 @r.type?('foo').should == "string"
146 @r.delete 'foo'
147 @r.type?('foo').should == "none"
148 end
149 #
150 it "should be able to push to the head of a list" do
151 @r.push_head "list", 'hello'
152 @r.push_head "list", 42
153 @r.type?('list').should == "list"
154 @r.list_length('list').should == 2
155 @r.pop_head('list').should == '42'
156 @r.delete('list')
157 end
158 #
159 it "should be able to push to the tail of a list" do
160 @r.push_tail "list", 'hello'
161 @r.type?('list').should == "list"
162 @r.list_length('list').should == 1
163 @r.delete('list')
164 end
165 #
166 it "should be able to pop the tail of a list" do
167 @r.push_tail "list", 'hello'
168 @r.push_tail "list", 'goodbye'
169 @r.type?('list').should == "list"
170 @r.list_length('list').should == 2
171 @r.pop_tail('list').should == 'goodbye'
172 @r.delete('list')
173 end
174 #
175 it "should be able to pop the head of a list" do
176 @r.push_tail "list", 'hello'
177 @r.push_tail "list", 'goodbye'
178 @r.type?('list').should == "list"
179 @r.list_length('list').should == 2
180 @r.pop_head('list').should == 'hello'
181 @r.delete('list')
182 end
183 #
184 it "should be able to get the length of a list" do
185 @r.push_tail "list", 'hello'
186 @r.push_tail "list", 'goodbye'
187 @r.type?('list').should == "list"
188 @r.list_length('list').should == 2
189 @r.delete('list')
190 end
191 #
192 it "should be able to get a range of values from a list" do
193 @r.push_tail "list", 'hello'
194 @r.push_tail "list", 'goodbye'
195 @r.push_tail "list", '1'
196 @r.push_tail "list", '2'
197 @r.push_tail "list", '3'
198 @r.type?('list').should == "list"
199 @r.list_length('list').should == 5
200 @r.list_range('list', 2, -1).should == ['1', '2', '3']
201 @r.delete('list')
202 end
203 #
204 it "should be able to trim a list" do
205 @r.push_tail "list", 'hello'
206 @r.push_tail "list", 'goodbye'
207 @r.push_tail "list", '1'
208 @r.push_tail "list", '2'
209 @r.push_tail "list", '3'
210 @r.type?('list').should == "list"
211 @r.list_length('list').should == 5
212 @r.list_trim 'list', 0, 1
213 @r.list_length('list').should == 2
214 @r.list_range('list', 0, -1).should == ['hello', 'goodbye']
215 @r.delete('list')
216 end
217 #
218 it "should be able to get a value by indexing into a list" do
219 @r.push_tail "list", 'hello'
220 @r.push_tail "list", 'goodbye'
221 @r.type?('list').should == "list"
222 @r.list_length('list').should == 2
223 @r.list_index('list', 1).should == 'goodbye'
224 @r.delete('list')
225 end
226 #
227 it "should be able to set a value by indexing into a list" do
228 @r.push_tail "list", 'hello'
229 @r.push_tail "list", 'hello'
230 @r.type?('list').should == "list"
231 @r.list_length('list').should == 2
232 @r.list_set('list', 1, 'goodbye').should be_true
233 @r.list_index('list', 1).should == 'goodbye'
234 @r.delete('list')
235 end
236 #
237 it "should be able to remove values from a list LREM" do
238 @r.push_tail "list", 'hello'
239 @r.push_tail "list", 'goodbye'
240 @r.type?('list').should == "list"
241 @r.list_length('list').should == 2
242 @r.list_rm('list', 1, 'hello').should == 1
243 @r.list_range('list', 0, -1).should == ['goodbye']
244 @r.delete('list')
245 end
246 #
247 it "should be able add members to a set" do
248 @r.set_add "set", 'key1'
249 @r.set_add "set", 'key2'
250 @r.type?('set').should == "set"
251 @r.set_count('set').should == 2
252 @r.set_members('set').sort.should == ['key1', 'key2'].sort
253 @r.delete('set')
254 end
255 #
256 it "should be able delete members to a set" do
257 @r.set_add "set", 'key1'
258 @r.set_add "set", 'key2'
259 @r.type?('set').should == "set"
260 @r.set_count('set').should == 2
261 @r.set_members('set').should == Set.new(['key1', 'key2'])
262 @r.set_delete('set', 'key1')
263 @r.set_count('set').should == 1
264 @r.set_members('set').should == Set.new(['key2'])
265 @r.delete('set')
266 end
267 #
268 it "should be able count the members of a set" do
269 @r.set_add "set", 'key1'
270 @r.set_add "set", 'key2'
271 @r.type?('set').should == "set"
272 @r.set_count('set').should == 2
273 @r.delete('set')
274 end
275 #
276 it "should be able test for set membership" do
277 @r.set_add "set", 'key1'
278 @r.set_add "set", 'key2'
279 @r.type?('set').should == "set"
280 @r.set_count('set').should == 2
281 @r.set_member?('set', 'key1').should be_true
282 @r.set_member?('set', 'key2').should be_true
283 @r.set_member?('set', 'notthere').should be_false
284 @r.delete('set')
285 end
286 #
287 it "should be able to do set intersection" do
288 @r.set_add "set", 'key1'
289 @r.set_add "set", 'key2'
290 @r.set_add "set2", 'key2'
291 @r.set_intersect('set', 'set2').should == Set.new(['key2'])
292 @r.delete('set')
293 end
294 #
295 it "should be able to do set intersection and store the results in a key" do
296 @r.set_add "set", 'key1'
297 @r.set_add "set", 'key2'
298 @r.set_add "set2", 'key2'
299 @r.set_inter_store('newone', 'set', 'set2').should == 'OK'
300 @r.set_members('newone').should == Set.new(['key2'])
301 @r.delete('set')
302 @r.delete('set2')
303 end
304 #
305 it "should be able to do set union" do
306 @r.set_add "set", 'key1'
307 @r.set_add "set", 'key2'
308 @r.set_add "set2", 'key2'
309 @r.set_add "set2", 'key3'
310 @r.set_union('set', 'set2').should == Set.new(['key1','key2','key3'])
311 @r.delete('set')
312 @r.delete('set2')
313 end
314 #
315 it "should be able to do set union and store the results in a key" do
316 @r.set_add "set", 'key1'
317 @r.set_add "set", 'key2'
318 @r.set_add "set2", 'key2'
319 @r.set_add "set2", 'key3'
320 @r.set_union_store('newone', 'set', 'set2').should == 'OK'
321 @r.set_members('newone').should == Set.new(['key1','key2','key3'])
322 @r.delete('set')
323 @r.delete('set2')
324 end
325 #
326 it "should be able to do set difference" do
327 @r.set_add "set", 'a'
328 @r.set_add "set", 'b'
329 @r.set_add "set2", 'b'
330 @r.set_add "set2", 'c'
331 @r.set_diff('set', 'set2').should == Set.new(['a'])
332 @r.delete('set')
333 @r.delete('set2')
334 end
335 #
336 it "should be able to do set difference and store the results in a key" do
337 @r.set_add "set", 'a'
338 @r.set_add "set", 'b'
339 @r.set_add "set2", 'b'
340 @r.set_add "set2", 'c'
341 @r.set_diff_store('newone', 'set', 'set2')
342 @r.set_members('newone').should == Set.new(['a'])
343 @r.delete('set')
344 @r.delete('set2')
345 end
346 #
347 it "should be able move elements from one set to another" do
348 @r.set_add 'set1', 'a'
349 @r.set_add 'set1', 'b'
350 @r.set_add 'set2', 'x'
351 @r.set_move('set1', 'set2', 'a').should == true
352 @r.set_member?('set2', 'a').should == true
353 @r.delete('set1')
354 end
355 #
356 it "should be able to do crazy SORT queries" do
357 @r['dog_1'] = 'louie'
358 @r.push_tail 'dogs', 1
359 @r['dog_2'] = 'lucy'
360 @r.push_tail 'dogs', 2
361 @r['dog_3'] = 'max'
362 @r.push_tail 'dogs', 3
363 @r['dog_4'] = 'taj'
364 @r.push_tail 'dogs', 4
365 @r.sort('dogs', :get => 'dog_*', :limit => [0,1]).should == ['louie']
366 @r.sort('dogs', :get => 'dog_*', :limit => [0,1], :order => 'desc alpha').should == ['taj']
367 end
368
369 it "should be able to handle array of :get using SORT" do
370 @r['dog:1:name'] = 'louie'
371 @r['dog:1:breed'] = 'mutt'
372 @r.push_tail 'dogs', 1
373 @r['dog:2:name'] = 'lucy'
374 @r['dog:2:breed'] = 'poodle'
375 @r.push_tail 'dogs', 2
376 @r['dog:3:name'] = 'max'
377 @r['dog:3:breed'] = 'hound'
378 @r.push_tail 'dogs', 3
379 @r['dog:4:name'] = 'taj'
380 @r['dog:4:breed'] = 'terrier'
381 @r.push_tail 'dogs', 4
382 @r.sort('dogs', :get => ['dog:*:name', 'dog:*:breed'], :limit => [0,1]).should == ['louie', 'mutt']
383 @r.sort('dogs', :get => ['dog:*:name', 'dog:*:breed'], :limit => [0,1], :order => 'desc alpha').should == ['taj', 'terrier']
384 end
385 #
386 it "should provide info" do
387 [: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|
388 @r.info.keys.should include(x)
389 end
390 end
391 #
392 it "should be able to flush the database" do
393 @r['key1'] = 'keyone'
394 @r['key2'] = 'keytwo'
395 @r.keys('*').sort.should == ['foo', 'key1', 'key2'] #foo from before
396 @r.flush_db
397 @r.keys('*').should == []
398 end
399 #
400 it "should be able to provide the last save time" do
401 savetime = @r.last_save
402 Time.at(savetime).class.should == Time
403 Time.at(savetime).should <= Time.now
404 end
405
406 it "should be able to MGET keys" do
407 @r['foo'] = 1000
408 @r['bar'] = 2000
409 @r.mget('foo', 'bar').should == ['1000', '2000']
410 @r.mget('foo', 'bar', 'baz').should == ['1000', '2000', nil]
411 end
412
413 it "should bgsave" do
414 lambda {@r.bgsave}.should_not raise_error(RedisError)
415 end
416
417 it "should handle multiple servers" do
418 require 'dist_redis'
419 @r = DistRedis.new('localhost:6379', '127.0.0.1:6379')
420 @r.select_db(15) # use database 15 for testing so we dont accidentally step on you real data
421
422 100.times do |idx|
423 @r[idx] = "foo#{idx}"
424 end
425
426 100.times do |idx|
427 @r[idx].should == "foo#{idx}"
428 end
429 end
430
431 it "should be able to pipeline writes" do
432 @r.pipelined do |pipeline|
433 pipeline.push_head "list", "hello"
434 pipeline.push_head "list", 42
435 end
436
437 @r.type?('list').should == "list"
438 @r.list_length('list').should == 2
439 @r.pop_head('list').should == '42'
440 @r.delete('list')
441 end
442
443 it "should select db on connection"
444 it "should re-select db on reconnection"
445 end