kali-redis 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1 @@
1
+ require File.dirname(__FILE__) + "/../../tasks/redis.tasks"
@@ -0,0 +1,668 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+ require 'redis/raketasks'
3
+ require 'logger'
4
+
5
+ class Foo
6
+ attr_accessor :bar
7
+ def initialize(bar)
8
+ @bar = bar
9
+ end
10
+
11
+ def ==(other)
12
+ @bar == other.bar
13
+ end
14
+ end
15
+
16
+ describe "redis" do
17
+ before(:all) do
18
+ result = RedisRunner.start_detached
19
+ raise("Could not start redis-server, aborting") unless result
20
+
21
+ # yea, this sucks, but it seems like sometimes we try to connect too quickly w/o it
22
+ sleep 1
23
+
24
+ # use database 15 for testing so we dont accidentally step on you real data
25
+ @r = Redis.new :db => 15
26
+ end
27
+
28
+ before(:each) do
29
+ @r['foo'] = 'bar'
30
+ end
31
+
32
+ after(:each) do
33
+ @r.keys('*').each {|k| @r.del k}
34
+ end
35
+
36
+ after(:all) do
37
+ begin
38
+ @r.quit
39
+ ensure
40
+ RedisRunner.stop
41
+ end
42
+ end
43
+
44
+ it "should be able connect without a timeout" do
45
+ lambda { Redis.new :timeout => 0 }.should_not raise_error
46
+ end
47
+
48
+ it "should be able to provide a logger" do
49
+ log = StringIO.new
50
+ r = Redis.new :db => 15, :logger => Logger.new(log)
51
+ r.ping
52
+ log.string.should include("ping")
53
+ end
54
+
55
+ it "should be able to PING" do
56
+ @r.ping.should == 'PONG'
57
+ end
58
+
59
+ it "should be able to GET a key" do
60
+ @r['foo'].should == 'bar'
61
+ end
62
+
63
+ it "should be able to SET a key" do
64
+ @r['foo'] = 'nik'
65
+ @r['foo'].should == 'nik'
66
+ end
67
+
68
+ it "should properly handle trailing newline characters" do
69
+ @r['foo'] = "bar\n"
70
+ @r['foo'].should == "bar\n"
71
+ end
72
+
73
+ it "should store and retrieve all possible characters at the beginning and the end of a string" do
74
+ (0..255).each do |char_idx|
75
+ string = "#{char_idx.chr}---#{char_idx.chr}"
76
+ @r['foo'] = string
77
+ @r['foo'].should == string
78
+ end
79
+ end
80
+
81
+ it "should be able to SET a key with an expiry" do
82
+ @r.set('foo', 'bar', 1)
83
+ @r['foo'].should == 'bar'
84
+ sleep 2
85
+ @r['foo'].should == nil
86
+ end
87
+
88
+ it "should be able to return a TTL for a key" do
89
+ @r.set('foo', 'bar', 1)
90
+ @r.ttl('foo').should == 1
91
+ end
92
+
93
+ it "should be able to SETNX" do
94
+ @r['foo'] = 'nik'
95
+ @r['foo'].should == 'nik'
96
+ @r.setnx 'foo', 'bar'
97
+ @r['foo'].should == 'nik'
98
+ end
99
+ #
100
+ it "should be able to GETSET" do
101
+ @r.getset('foo', 'baz').should == 'bar'
102
+ @r['foo'].should == 'baz'
103
+ end
104
+ #
105
+ it "should be able to INCR a key" do
106
+ @r.del('counter')
107
+ @r.incr('counter').should == 1
108
+ @r.incr('counter').should == 2
109
+ @r.incr('counter').should == 3
110
+ end
111
+ #
112
+ it "should be able to INCRBY a key" do
113
+ @r.del('counter')
114
+ @r.incrby('counter', 1).should == 1
115
+ @r.incrby('counter', 2).should == 3
116
+ @r.incrby('counter', 3).should == 6
117
+ end
118
+ #
119
+ it "should be able to DECR a key" do
120
+ @r.del('counter')
121
+ @r.incr('counter').should == 1
122
+ @r.incr('counter').should == 2
123
+ @r.incr('counter').should == 3
124
+ @r.decr('counter').should == 2
125
+ @r.decr('counter', 2).should == 0
126
+ end
127
+ #
128
+ it "should be able to RANDKEY" do
129
+ @r.randkey.should_not be_nil
130
+ end
131
+ #
132
+ it "should be able to RENAME a key" do
133
+ @r.del 'foo'
134
+ @r.del'bar'
135
+ @r['foo'] = 'hi'
136
+ @r.rename 'foo', 'bar'
137
+ @r['bar'].should == 'hi'
138
+ end
139
+ #
140
+ it "should be able to RENAMENX a key" do
141
+ @r.del 'foo'
142
+ @r.del 'bar'
143
+ @r['foo'] = 'hi'
144
+ @r['bar'] = 'ohai'
145
+ @r.renamenx 'foo', 'bar'
146
+ @r['bar'].should == 'ohai'
147
+ end
148
+ #
149
+ it "should be able to get DBSIZE of the database" do
150
+ @r.delete 'foo'
151
+ dbsize_without_foo = @r.dbsize
152
+ @r['foo'] = 0
153
+ dbsize_with_foo = @r.dbsize
154
+
155
+ dbsize_with_foo.should == dbsize_without_foo + 1
156
+ end
157
+ #
158
+ it "should be able to EXPIRE a key" do
159
+ @r['foo'] = 'bar'
160
+ @r.expire 'foo', 1
161
+ @r['foo'].should == "bar"
162
+ sleep 2
163
+ @r['foo'].should == nil
164
+ end
165
+ #
166
+ it "should be able to EXISTS" do
167
+ @r['foo'] = 'nik'
168
+ @r.exists('foo').should be_true
169
+ @r.del 'foo'
170
+ @r.exists('foo').should be_false
171
+ end
172
+ #
173
+ it "should be able to KEYS" do
174
+ @r.keys("f*").each { |key| @r.del key }
175
+ @r['f'] = 'nik'
176
+ @r['fo'] = 'nak'
177
+ @r['foo'] = 'qux'
178
+ @r.keys("f*").sort.should == ['f','fo', 'foo'].sort
179
+ end
180
+ #
181
+ it "should be able to return a random key (RANDOMKEY)" do
182
+ 3.times { @r.exists(@r.randomkey).should be_true }
183
+ end
184
+ #
185
+ it "should be able to check the TYPE of a key" do
186
+ @r['foo'] = 'nik'
187
+ @r.type('foo').should == "string"
188
+ @r.del 'foo'
189
+ @r.type('foo').should == "none"
190
+ end
191
+ #
192
+ it "should be able to push to the head of a list (LPUSH)" do
193
+ @r.lpush "list", 'hello'
194
+ @r.lpush "list", 42
195
+ @r.type('list').should == "list"
196
+ @r.llen('list').should == 2
197
+ @r.lpop('list').should == '42'
198
+ end
199
+ #
200
+ it "should be able to push to the tail of a list (RPUSH)" do
201
+ @r.rpush "list", 'hello'
202
+ @r.type('list').should == "list"
203
+ @r.llen('list').should == 1
204
+ end
205
+ #
206
+ it "should be able to pop the tail of a list (RPOP)" do
207
+ @r.rpush "list", 'hello'
208
+ @r.rpush"list", 'goodbye'
209
+ @r.type('list').should == "list"
210
+ @r.llen('list').should == 2
211
+ @r.rpop('list').should == 'goodbye'
212
+ end
213
+ #
214
+ it "should be able to pop the head of a list (LPOP)" do
215
+ @r.rpush "list", 'hello'
216
+ @r.rpush "list", 'goodbye'
217
+ @r.type('list').should == "list"
218
+ @r.llen('list').should == 2
219
+ @r.lpop('list').should == 'hello'
220
+ end
221
+ #
222
+ it "should be able to get the length of a list (LLEN)" do
223
+ @r.rpush "list", 'hello'
224
+ @r.rpush "list", 'goodbye'
225
+ @r.type('list').should == "list"
226
+ @r.llen('list').should == 2
227
+ end
228
+ #
229
+ it "should be able to get a range of values from a list (LRANGE)" do
230
+ @r.rpush "list", 'hello'
231
+ @r.rpush "list", 'goodbye'
232
+ @r.rpush "list", '1'
233
+ @r.rpush "list", '2'
234
+ @r.rpush "list", '3'
235
+ @r.type('list').should == "list"
236
+ @r.llen('list').should == 5
237
+ @r.lrange('list', 2, -1).should == ['1', '2', '3']
238
+ end
239
+ #
240
+ it "should be able to trim a list (LTRIM)" do
241
+ @r.rpush "list", 'hello'
242
+ @r.rpush "list", 'goodbye'
243
+ @r.rpush "list", '1'
244
+ @r.rpush "list", '2'
245
+ @r.rpush "list", '3'
246
+ @r.type('list').should == "list"
247
+ @r.llen('list').should == 5
248
+ @r.ltrim 'list', 0, 1
249
+ @r.llen('list').should == 2
250
+ @r.lrange('list', 0, -1).should == ['hello', 'goodbye']
251
+ end
252
+ #
253
+ it "should be able to get a value by indexing into a list (LINDEX)" do
254
+ @r.rpush "list", 'hello'
255
+ @r.rpush "list", 'goodbye'
256
+ @r.type('list').should == "list"
257
+ @r.llen('list').should == 2
258
+ @r.lindex('list', 1).should == 'goodbye'
259
+ end
260
+ #
261
+ it "should be able to set a value by indexing into a list (LSET)" do
262
+ @r.rpush "list", 'hello'
263
+ @r.rpush "list", 'hello'
264
+ @r.type('list').should == "list"
265
+ @r.llen('list').should == 2
266
+ @r.lset('list', 1, 'goodbye').should == 'OK'
267
+ @r.lindex('list', 1).should == 'goodbye'
268
+ end
269
+ #
270
+ it "should be able to remove values from a list (LREM)" do
271
+ @r.rpush "list", 'hello'
272
+ @r.rpush "list", 'goodbye'
273
+ @r.type('list').should == "list"
274
+ @r.llen('list').should == 2
275
+ @r.lrem('list', 1, 'hello').should == 1
276
+ @r.lrange('list', 0, -1).should == ['goodbye']
277
+ end
278
+
279
+ it "should be able to pop values from a list and push them onto a temp list(RPOPLPUSH)" do
280
+ @r.rpush "list", 'one'
281
+ @r.rpush "list", 'two'
282
+ @r.rpush "list", 'three'
283
+ @r.type('list').should == "list"
284
+ @r.llen('list').should == 3
285
+ @r.lrange('list',0,-1).should == ['one', 'two', 'three']
286
+ @r.lrange('tmp',0,-1).should == []
287
+ @r.rpoplpush('list', 'tmp').should == 'three'
288
+ @r.lrange('tmp',0,-1).should == ['three']
289
+ @r.rpoplpush('list', 'tmp').should == 'two'
290
+ @r.lrange('tmp',0,-1).should == ['two', 'three']
291
+ @r.rpoplpush('list', 'tmp').should == 'one'
292
+ @r.lrange('tmp',0,-1).should == ['one','two','three']
293
+ end
294
+ #
295
+ it "should be able add members to a set (SADD)" do
296
+ @r.sadd "set", 'key1'
297
+ @r.sadd "set", 'key2'
298
+ @r.type('set').should == "set"
299
+ @r.scard('set').should == 2
300
+ @r.smembers('set').sort.should == ['key1', 'key2'].sort
301
+ end
302
+ #
303
+ it "should be able delete members to a set (SREM)" do
304
+ @r.sadd "set", 'key1'
305
+ @r.sadd "set", 'key2'
306
+ @r.type('set').should == "set"
307
+ @r.scard('set').should == 2
308
+ @r.smembers('set').sort.should == ['key1', 'key2'].sort
309
+ @r.srem('set', 'key1')
310
+ @r.scard('set').should == 1
311
+ @r.smembers('set').should == ['key2']
312
+ end
313
+ #
314
+ it "should be able to return and remove random key from set (SPOP)" do
315
+ @r.sadd "set_pop", "key1"
316
+ @r.sadd "set_pop", "key2"
317
+ @r.spop("set_pop").should_not be_nil
318
+ @r.scard("set_pop").should == 1
319
+ end
320
+ #
321
+ it "should be able to return random key without delete the key from a set (SRANDMEMBER)" do
322
+ @r.sadd "set_srandmember", "key1"
323
+ @r.sadd "set_srandmember", "key2"
324
+ @r.srandmember("set_srandmember").should_not be_nil
325
+ @r.scard("set_srandmember").should == 2
326
+ end
327
+ #
328
+ it "should be able count the members of a set (SCARD)" do
329
+ @r.sadd "set", 'key1'
330
+ @r.sadd "set", 'key2'
331
+ @r.type('set').should == "set"
332
+ @r.scard('set').should == 2
333
+ end
334
+ #
335
+ it "should be able test for set membership (SISMEMBER)" do
336
+ @r.sadd "set", 'key1'
337
+ @r.sadd "set", 'key2'
338
+ @r.type('set').should == "set"
339
+ @r.scard('set').should == 2
340
+ @r.sismember('set', 'key1').should be_true
341
+ @r.sismember('set', 'key2').should be_true
342
+ @r.sismember('set', 'notthere').should be_false
343
+ end
344
+ #
345
+ it "should be able to do set intersection (SINTER)" do
346
+ @r.sadd "set", 'key1'
347
+ @r.sadd "set", 'key2'
348
+ @r.sadd "set2", 'key2'
349
+ @r.sinter('set', 'set2').should == ['key2']
350
+ end
351
+ #
352
+ it "should be able to do set intersection and store the results in a key (SINTERSTORE)" do
353
+ @r.sadd "set", 'key1'
354
+ @r.sadd "set", 'key2'
355
+ @r.sadd "set2", 'key2'
356
+ @r.sinterstore('newone', 'set', 'set2').should == 1
357
+ @r.smembers('newone').should == ['key2']
358
+ end
359
+ #
360
+ it "should be able to do set union (SUNION)" do
361
+ @r.sadd "set", 'key1'
362
+ @r.sadd "set", 'key2'
363
+ @r.sadd "set2", 'key2'
364
+ @r.sadd "set2", 'key3'
365
+ @r.sunion('set', 'set2').sort.should == ['key1','key2','key3'].sort
366
+ end
367
+ #
368
+ it "should be able to do set union and store the results in a key (SUNIONSTORE)" do
369
+ @r.sadd "set", 'key1'
370
+ @r.sadd "set", 'key2'
371
+ @r.sadd "set2", 'key2'
372
+ @r.sadd "set2", 'key3'
373
+ @r.sunionstore('newone', 'set', 'set2').should == 3
374
+ @r.smembers('newone').sort.should == ['key1','key2','key3'].sort
375
+ end
376
+ #
377
+ it "should be able to do set difference (SDIFF)" do
378
+ @r.sadd "set", 'a'
379
+ @r.sadd "set", 'b'
380
+ @r.sadd "set2", 'b'
381
+ @r.sadd "set2", 'c'
382
+ @r.sdiff('set', 'set2').should == ['a']
383
+ end
384
+ #
385
+ it "should be able to do set difference and store the results in a key (SDIFFSTORE)" do
386
+ @r.sadd "set", 'a'
387
+ @r.sadd "set", 'b'
388
+ @r.sadd "set2", 'b'
389
+ @r.sadd "set2", 'c'
390
+ @r.sdiffstore('newone', 'set', 'set2')
391
+ @r.smembers('newone').should == ['a']
392
+ end
393
+ #
394
+ it "should be able move elements from one set to another (SMOVE)" do
395
+ @r.sadd 'set1', 'a'
396
+ @r.sadd 'set1', 'b'
397
+ @r.sadd 'set2', 'x'
398
+ @r.smove('set1', 'set2', 'a').should be_true
399
+ @r.sismember('set2', 'a').should be_true
400
+ @r.delete('set1')
401
+ end
402
+ #
403
+ it "should be able to do crazy SORT queries" do
404
+ # The 'Dogs' is capitialized on purpose
405
+ @r['dog_1'] = 'louie'
406
+ @r.rpush 'Dogs', 1
407
+ @r['dog_2'] = 'lucy'
408
+ @r.rpush 'Dogs', 2
409
+ @r['dog_3'] = 'max'
410
+ @r.rpush 'Dogs', 3
411
+ @r['dog_4'] = 'taj'
412
+ @r.rpush 'Dogs', 4
413
+ @r.sort('Dogs', :get => 'dog_*', :limit => [0,1]).should == ['louie']
414
+ @r.sort('Dogs', :get => 'dog_*', :limit => [0,1], :order => 'desc alpha').should == ['taj']
415
+ end
416
+
417
+ it "should be able to handle array of :get using SORT" do
418
+ @r['dog:1:name'] = 'louie'
419
+ @r['dog:1:breed'] = 'mutt'
420
+ @r.rpush 'dogs', 1
421
+ @r['dog:2:name'] = 'lucy'
422
+ @r['dog:2:breed'] = 'poodle'
423
+ @r.rpush 'dogs', 2
424
+ @r['dog:3:name'] = 'max'
425
+ @r['dog:3:breed'] = 'hound'
426
+ @r.rpush 'dogs', 3
427
+ @r['dog:4:name'] = 'taj'
428
+ @r['dog:4:breed'] = 'terrier'
429
+ @r.rpush 'dogs', 4
430
+ @r.sort('dogs', :get => ['dog:*:name', 'dog:*:breed'], :limit => [0,1]).should == ['louie', 'mutt']
431
+ @r.sort('dogs', :get => ['dog:*:name', 'dog:*:breed'], :limit => [0,1], :order => 'desc alpha').should == ['taj', 'terrier']
432
+ end
433
+ #
434
+ it "should be able count the members of a zset" do
435
+ @r.set_add "set", 'key1'
436
+ @r.set_add "set", 'key2'
437
+ @r.zset_add 'zset', 1, 'set'
438
+ @r.zset_count('zset').should == 1
439
+ @r.delete('set')
440
+ @r.delete('zset')
441
+ end
442
+ #
443
+ it "should be able add members to a zset" do
444
+ @r.set_add "set", 'key1'
445
+ @r.set_add "set", 'key2'
446
+ @r.zset_add 'zset', 1, 'set'
447
+ @r.zset_range('zset', 0, 1).should == ['set']
448
+ @r.zset_count('zset').should == 1
449
+ @r.delete('set')
450
+ @r.delete('zset')
451
+ end
452
+ #
453
+ it "should be able delete members to a zset" do
454
+ @r.set_add "set", 'key1'
455
+ @r.set_add "set", 'key2'
456
+ @r.type?('set').should == "set"
457
+ @r.set_add "set2", 'key3'
458
+ @r.set_add "set2", 'key4'
459
+ @r.type?('set2').should == "set"
460
+ @r.zset_add 'zset', 1, 'set'
461
+ @r.zset_count('zset').should == 1
462
+ @r.zset_add 'zset', 2, 'set2'
463
+ @r.zset_count('zset').should == 2
464
+ @r.zset_delete 'zset', 'set'
465
+ @r.zset_count('zset').should == 1
466
+ @r.delete('set')
467
+ @r.delete('set2')
468
+ @r.delete('zset')
469
+ end
470
+ #
471
+ it "should be able to get a range of values from a zset" do
472
+ @r.set_add "set", 'key1'
473
+ @r.set_add "set", 'key2'
474
+ @r.set_add "set2", 'key3'
475
+ @r.set_add "set2", 'key4'
476
+ @r.set_add "set3", 'key1'
477
+ @r.type?('set').should == 'set'
478
+ @r.type?('set2').should == 'set'
479
+ @r.type?('set3').should == 'set'
480
+ @r.zset_add 'zset', 1, 'set'
481
+ @r.zset_add 'zset', 2, 'set2'
482
+ @r.zset_add 'zset', 3, 'set3'
483
+ @r.zset_count('zset').should == 3
484
+ @r.zset_range('zset', 0, 3).should == ['set', 'set2', 'set3']
485
+ @r.delete('set')
486
+ @r.delete('set2')
487
+ @r.delete('set3')
488
+ @r.delete('zset')
489
+ end
490
+ #
491
+ it "should be able to get a reverse range of values from a zset" do
492
+ @r.set_add "set", 'key1'
493
+ @r.set_add "set", 'key2'
494
+ @r.set_add "set2", 'key3'
495
+ @r.set_add "set2", 'key4'
496
+ @r.set_add "set3", 'key1'
497
+ @r.type?('set').should == 'set'
498
+ @r.type?('set2').should == 'set'
499
+ @r.type?('set3').should == 'set'
500
+ @r.zset_add 'zset', 1, 'set'
501
+ @r.zset_add 'zset', 2, 'set2'
502
+ @r.zset_add 'zset', 3, 'set3'
503
+ @r.zset_count('zset').should == 3
504
+ @r.zset_reverse_range('zset', 0, 3).should == ['set3', 'set2', 'set']
505
+ @r.delete('set')
506
+ @r.delete('set2')
507
+ @r.delete('set3')
508
+ @r.delete('zset')
509
+ end
510
+ #
511
+ it "should be able to get a range by score of values from a zset" do
512
+ @r.set_add "set", 'key1'
513
+ @r.set_add "set", 'key2'
514
+ @r.set_add "set2", 'key3'
515
+ @r.set_add "set2", 'key4'
516
+ @r.set_add "set3", 'key1'
517
+ @r.set_add "set4", 'key4'
518
+ @r.zset_add 'zset', 1, 'set'
519
+ @r.zset_add 'zset', 2, 'set2'
520
+ @r.zset_add 'zset', 3, 'set3'
521
+ @r.zset_add 'zset', 4, 'set4'
522
+ @r.zset_count('zset').should == 4
523
+ @r.zset_range_by_score('zset', 2, 3).should == ['set2', 'set3']
524
+ @r.delete('set')
525
+ @r.delete('set2')
526
+ @r.delete('set3')
527
+ @r.delete('set4')
528
+ @r.delete('zset')
529
+ end
530
+ #
531
+ it "should be able to get a score for a specific value in a zset (ZSCORE)" do
532
+ @r.zset_add "zset", 23, "value"
533
+ @r.zset_score("zset", "value").should == "23"
534
+
535
+ @r.zset_score("zset", "value2").should be_nil
536
+ @r.zset_score("unknown_zset", "value").should be_nil
537
+
538
+ @r.delete("zset")
539
+ end
540
+ #
541
+ it "should be able to increment a range score of a zset (ZINCRBY)" do
542
+ # create a new zset
543
+ @r.zset_increment_by "hackers", 1965, "Yukihiro Matsumoto"
544
+ @r.zset_score("hackers", "Yukihiro Matsumoto").should == "1965"
545
+
546
+ # add a new element
547
+ @r.zset_increment_by "hackers", 1912, "Alan Turing"
548
+ @r.zset_score("hackers", "Alan Turing").should == "1912"
549
+
550
+ # update the score
551
+ @r.zset_increment_by "hackers", 100, "Alan Turing" # yeah, we are making Turing a bit younger
552
+ @r.zset_score("hackers", "Alan Turing").should == "2012"
553
+
554
+ # attempt to update a key that's not a zset
555
+ @r["i_am_not_a_zet"] = "value"
556
+ lambda { @r.zset_incr_by "i_am_not_a_zet", 23, "element" }.should raise_error
557
+
558
+ @r.delete("hackers")
559
+ @r.delete("i_am_not_a_zet")
560
+ end
561
+ #
562
+ it "should provide info (INFO)" do
563
+ [: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|
564
+ @r.info.keys.should include(x)
565
+ end
566
+ end
567
+ #
568
+ it "should be able to flush the database (FLUSHDB)" do
569
+ @r['key1'] = 'keyone'
570
+ @r['key2'] = 'keytwo'
571
+ @r.keys('*').sort.should == ['foo', 'key1', 'key2'].sort #foo from before
572
+ @r.flushdb
573
+ @r.keys('*').should == []
574
+ end
575
+ #
576
+ it "should raise exception when manually try to change the database" do
577
+ lambda { @r.select(0) }.should raise_error
578
+ end
579
+ #
580
+ it "should be able to provide the last save time (LASTSAVE)" do
581
+ savetime = @r.lastsave
582
+ Time.at(savetime).class.should == Time
583
+ Time.at(savetime).should <= Time.now
584
+ end
585
+
586
+ it "should be able to MGET keys" do
587
+ @r['foo'] = 1000
588
+ @r['bar'] = 2000
589
+ @r.mget('foo', 'bar').should == ['1000', '2000']
590
+ @r.mget('foo', 'bar', 'baz').should == ['1000', '2000', nil]
591
+ end
592
+
593
+ it "should be able to mapped MGET keys" do
594
+ @r['foo'] = 1000
595
+ @r['bar'] = 2000
596
+ @r.mapped_mget('foo', 'bar').should == { 'foo' => '1000', 'bar' => '2000'}
597
+ @r.mapped_mget('foo', 'baz', 'bar').should == { 'foo' => '1000', 'bar' => '2000'}
598
+ end
599
+
600
+ it "should be able to MSET values" do
601
+ @r.mset :key1 => "value1", :key2 => "value2"
602
+ @r['key1'].should == "value1"
603
+ @r['key2'].should == "value2"
604
+ end
605
+
606
+ it "should be able to MSETNX values" do
607
+ @r.msetnx :keynx1 => "valuenx1", :keynx2 => "valuenx2"
608
+ @r.mget('keynx1', 'keynx2').should == ["valuenx1", "valuenx2"]
609
+
610
+ @r["keynx1"] = "value1"
611
+ @r["keynx2"] = "value2"
612
+ @r.msetnx :keynx1 => "valuenx1", :keynx2 => "valuenx2"
613
+ @r.mget('keynx1', 'keynx2').should == ["value1", "value2"]
614
+ end
615
+
616
+ it "should bgsave" do
617
+ ['OK', 'Background saving started'].include?( @r.bgsave).should == true
618
+ end
619
+
620
+ it "should be able to ECHO" do
621
+ @r.echo("message in a bottle\n").should == "message in a bottle\n"
622
+ end
623
+
624
+ it "should raise error when invoke MONITOR" do
625
+ lambda { @r.monitor }.should raise_error
626
+ end
627
+
628
+ it "should raise error when invoke SYNC" do
629
+ lambda { @r.sync }.should raise_error
630
+ end
631
+
632
+ it "should handle multiple servers" do
633
+ require 'dist_redis'
634
+ @r = DistRedis.new(:hosts=> ['localhost:6379', '127.0.0.1:6379'], :db => 15)
635
+
636
+ 100.times do |idx|
637
+ @r[idx] = "foo#{idx}"
638
+ end
639
+
640
+ 100.times do |idx|
641
+ @r[idx].should == "foo#{idx}"
642
+ end
643
+ end
644
+
645
+ it "should be able to pipeline writes" do
646
+ @r.pipelined do |pipeline|
647
+ pipeline.lpush 'list', "hello"
648
+ pipeline.lpush 'list', 42
649
+ end
650
+
651
+ @r.type('list').should == "list"
652
+ @r.llen('list').should == 2
653
+ @r.lpop('list').should == '42'
654
+ end
655
+
656
+ it "should do nothing when pipelining no commands" do
657
+ @r.pipelined do |pipeline|
658
+ end
659
+ end
660
+
661
+ it "should AUTH when connecting with a password" do
662
+ r = Redis.new(:password => 'secret')
663
+ r.stub!(:connect_to)
664
+ r.should_receive(:call_command).with(['auth', 'secret'])
665
+ r.connect_to_server
666
+ end
667
+
668
+ end