em-redis 0.2.2 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -3,8 +3,7 @@ require File.expand_path(File.dirname(__FILE__) + "/test_helper.rb")
3
3
  EM.describe EM::Protocols::Redis, "connected to an empty db" do
4
4
 
5
5
  before do
6
- @c = EM::Protocols::Redis.connect
7
- @c.select "14"
6
+ @c = EM::Protocols::Redis.connect :db => 14
8
7
  @c.flushdb
9
8
  end
10
9
 
@@ -54,14 +53,14 @@ EM.describe EM::Protocols::Redis, "connected to an empty db" do
54
53
 
55
54
  should "be able to 'lpush' to a nonexistent list" do
56
55
  @c.lpush("foo", "bar") do |r|
57
- r.should == "OK"
56
+ r.should == 1
58
57
  done
59
58
  end
60
59
  end
61
60
 
62
61
  should "be able to 'rpush' to a nonexistent list" do
63
62
  @c.rpush("foo", "bar") do |r|
64
- r.should == "OK"
63
+ r.should == 1
65
64
  done
66
65
  end
67
66
  end
@@ -107,8 +106,7 @@ end
107
106
  EM.describe EM::Protocols::Redis, "connected to a db containing some simple string-valued keys" do
108
107
 
109
108
  before do
110
- @c = EM::Protocols::Redis.connect
111
- @c.select "14"
109
+ @c = EM::Protocols::Redis.connect :db => 14
112
110
  @c.flushdb
113
111
  @c.set "a", "b"
114
112
  @c.set "x", "y"
@@ -206,8 +204,7 @@ end
206
204
  EM.describe EM::Protocols::Redis, "connected to a db containing a list" do
207
205
 
208
206
  before do
209
- @c = EM::Protocols::Redis.connect
210
- @c.select "14"
207
+ @c = EM::Protocols::Redis.connect :db => 14
211
208
  @c.flushdb
212
209
  @c.lpush "foo", "c"
213
210
  @c.lpush "foo", "b"
@@ -225,7 +222,7 @@ EM.describe EM::Protocols::Redis, "connected to a db containing a list" do
225
222
 
226
223
  should "be able to 'rpush' onto the tail of the list" do
227
224
  @c.rpush "foo", "d" do |r|
228
- r.should == "OK"
225
+ r.should == 4
229
226
  @c.rpop "foo" do |r|
230
227
  r.should == "d"
231
228
  done
@@ -235,7 +232,7 @@ EM.describe EM::Protocols::Redis, "connected to a db containing a list" do
235
232
 
236
233
  should "be able to 'lpush' onto the head of the list" do
237
234
  @c.lpush "foo", "d" do |r|
238
- r.should == "OK"
235
+ r.should == 4
239
236
  @c.lpop "foo" do |r|
240
237
  r.should == "d"
241
238
  done
@@ -295,8 +292,7 @@ end
295
292
 
296
293
  EM.describe EM::Protocols::Redis, "connected to a db containing two sets" do
297
294
  before do
298
- @c = EM::Protocols::Redis.connect
299
- @c.select "14"
295
+ @c = EM::Protocols::Redis.connect :db => 14
300
296
  @c.flushdb
301
297
  @c.sadd "foo", "a"
302
298
  @c.sadd "foo", "b"
@@ -402,8 +398,7 @@ end
402
398
 
403
399
  EM.describe EM::Protocols::Redis, "connected to a db containing three linked lists" do
404
400
  before do
405
- @c = EM::Protocols::Redis.connect
406
- @c.select "14"
401
+ @c = EM::Protocols::Redis.connect :db => 14
407
402
  @c.flushdb
408
403
  @c.rpush "foo", "a"
409
404
  @c.rpush "foo", "b"
@@ -422,7 +417,7 @@ EM.describe EM::Protocols::Redis, "connected to a db containing three linked lis
422
417
 
423
418
  should "be able to get keys selectively" do
424
419
  @c.keys "a_*" do |r|
425
- r.should == ["a_sort", "a_data"]
420
+ r.should == ["a_sort", "a_data"].sort
426
421
  done
427
422
  end
428
423
  end
@@ -430,8 +425,7 @@ end
430
425
 
431
426
  EM.describe EM::Protocols::Redis, "when reconnecting" do
432
427
  before do
433
- @c = EM::Protocols::Redis.connect
434
- @c.select "14"
428
+ @c = EM::Protocols::Redis.connect :db => 14
435
429
  @c.flushdb
436
430
  end
437
431
 
@@ -449,4 +443,4 @@ EM.describe EM::Protocols::Redis, "when reconnecting" do
449
443
  end
450
444
  end
451
445
  end
452
- end
446
+ end
@@ -0,0 +1,761 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/test_helper.rb")
2
+ require 'logger'
3
+
4
+ EM.describe EM::Protocols::Redis do
5
+ default_timeout 1
6
+
7
+ before do
8
+ @r = EM::Protocols::Redis.connect :db => 14
9
+ @r.flushdb
10
+ @r['foo'] = 'bar'
11
+ end
12
+
13
+ after { @r.close_connection }
14
+
15
+ should "be able to provide a logger" do
16
+ log = StringIO.new
17
+ r = EM::Protocols::Redis.connect :db => 14, :logger => Logger.new(log)
18
+ r.ping do
19
+ log.string.should.include "ping"
20
+ done
21
+ end
22
+ end
23
+
24
+ it "should be able to PING" do
25
+ @r.ping { |r| r.should == 'PONG'; done }
26
+ end
27
+
28
+ it "should be able to GET a key" do
29
+ @r.get('foo') { |r| r.should == 'bar'; done }
30
+ end
31
+
32
+ it "should be able to SET a key" do
33
+ @r['foo'] = 'nik'
34
+ @r.get('foo') { |r| r.should == 'nik'; done }
35
+ end
36
+
37
+ it "should properly handle trailing newline characters" do
38
+ @r['foo'] = "bar\n"
39
+ @r.get('foo') { |r| r.should == "bar\n"; done }
40
+ end
41
+
42
+ it "should store and retrieve all possible characters at the beginning and the end of a string" do
43
+ (0..255).each do |char_idx|
44
+ string = "#{char_idx.chr}---#{char_idx.chr}"
45
+ @r['foo'] = string
46
+ @r.get('foo') { |r| r.should == string }
47
+ end
48
+ @r.ping { done }
49
+ end
50
+
51
+ it "should be able to SET a key with an expiry" do
52
+ timeout(3)
53
+
54
+ @r.set('foo', 'bar', 1)
55
+ @r.get('foo') { |r| r.should == 'bar' }
56
+ EM.add_timer(2) do
57
+ @r.get('foo') { |r| r.should == nil }
58
+ @r.ping { done }
59
+ end
60
+ end
61
+
62
+ it "should be able to return a TTL for a key" do
63
+ @r.set('foo', 'bar', 1)
64
+ @r.ttl('foo') { |r| r.should == 1; done }
65
+ end
66
+
67
+ it "should be able to SETNX" do
68
+ @r['foo'] = 'nik'
69
+ @r.get('foo') { |r| r.should == 'nik' }
70
+ @r.setnx 'foo', 'bar'
71
+ @r.get('foo') { |r| r.should == 'nik' }
72
+
73
+ @r.ping { done }
74
+ end
75
+ #
76
+ it "should be able to GETSET" do
77
+ @r.getset('foo', 'baz') { |r| r.should == 'bar' }
78
+ @r.get('foo') { |r| r.should == 'baz'; done }
79
+ end
80
+ #
81
+ it "should be able to INCR a key" do
82
+ @r.del('counter')
83
+ @r.incr('counter') { |r| r.should == 1 }
84
+ @r.incr('counter') { |r| r.should == 2 }
85
+ @r.incr('counter') { |r| r.should == 3 }
86
+
87
+ @r.ping { done }
88
+ end
89
+ #
90
+ it "should be able to INCRBY a key" do
91
+ @r.del('counter')
92
+ @r.incrby('counter', 1) { |r| r.should == 1 }
93
+ @r.incrby('counter', 2) { |r| r.should == 3 }
94
+ @r.incrby('counter', 3) { |r| r.should == 6 }
95
+
96
+ @r.ping { done }
97
+ end
98
+ #
99
+ it "should be able to DECR a key" do
100
+ @r.del('counter')
101
+ @r.incr('counter') { |r| r.should == 1 }
102
+ @r.incr('counter') { |r| r.should == 2 }
103
+ @r.incr('counter') { |r| r.should == 3 }
104
+ @r.decr('counter') { |r| r.should == 2 }
105
+ @r.decr('counter', 2) { |r| r.should == 0; done }
106
+ end
107
+ #
108
+ it "should be able to RANDKEY" do
109
+ @r.randkey { |r| r.should.not == nil; done }
110
+ end
111
+ #
112
+ it "should be able to RENAME a key" do
113
+ @r.del 'foo'
114
+ @r.del 'bar'
115
+ @r['foo'] = 'hi'
116
+ @r.rename 'foo', 'bar'
117
+ @r.get('bar') { |r| r.should == 'hi' ; done }
118
+ end
119
+ #
120
+ it "should be able to RENAMENX a key" do
121
+ @r.del 'foo'
122
+ @r.del 'bar'
123
+ @r['foo'] = 'hi'
124
+ @r['bar'] = 'ohai'
125
+ @r.renamenx 'foo', 'bar'
126
+ @r.get('bar') { |r| r.should == 'ohai' ; done }
127
+ end
128
+ #
129
+ it "should be able to get DBSIZE of the database" do
130
+ dbsize_without_foo, dbsize_with_foo = nil
131
+ @r.delete 'foo'
132
+ @r.dbsize { |r| dbsize_without_foo = r }
133
+ @r['foo'] = 0
134
+ @r.dbsize { |r| dbsize_with_foo = r }
135
+
136
+ @r.ping do
137
+ dbsize_with_foo.should == dbsize_without_foo + 1
138
+ done
139
+ end
140
+ end
141
+ #
142
+ it "should be able to EXPIRE a key" do
143
+ timeout(3)
144
+
145
+ @r['foo'] = 'bar'
146
+ @r.expire 'foo', 1
147
+ @r.get('foo') { |r| r.should == "bar" }
148
+ EM.add_timer(2) do
149
+ @r.get('foo') { |r| r.should == nil }
150
+ @r.ping { done }
151
+ end
152
+ end
153
+ #
154
+ it "should be able to EXISTS" do
155
+ @r['foo'] = 'nik'
156
+ @r.exists('foo') { |r| r.should == true }
157
+ @r.del 'foo'
158
+ @r.exists('foo') { |r| r.should == false ; done }
159
+ end
160
+ #
161
+ it "should be able to KEYS" do
162
+ @r.keys("f*") { |keys| keys.each { |key| @r.del key } }
163
+ @r['f'] = 'nik'
164
+ @r['fo'] = 'nak'
165
+ @r['foo'] = 'qux'
166
+ @r.keys("f*") { |r| r.sort.should == ['f', 'fo', 'foo'].sort }
167
+
168
+ @r.ping { done }
169
+ end
170
+ #
171
+ it "should be able to return a random key (RANDOMKEY)" do
172
+ 3.times do |i|
173
+ @r.randomkey do |r|
174
+ @r.exists(r) do |e|
175
+ e.should == true
176
+ done if i == 2
177
+ end
178
+ end
179
+ end
180
+ end
181
+ #
182
+ it "should be able to check the TYPE of a key" do
183
+ @r['foo'] = 'nik'
184
+ @r.type('foo') { |r| r.should == "string" }
185
+ @r.del 'foo'
186
+ @r.type('foo') { |r| r.should == "none" ; done }
187
+ end
188
+ #
189
+ it "should be able to push to the head of a list (LPUSH)" do
190
+ @r.lpush "list", 'hello'
191
+ @r.lpush "list", 42
192
+ @r.type('list') { |r| r.should == "list" }
193
+ @r.llen('list') { |r| r.should == 2 }
194
+ @r.lpop('list') { |r| r.should == '42'; done }
195
+ end
196
+ #
197
+ it "should be able to push to the tail of a list (RPUSH)" do
198
+ @r.rpush "list", 'hello'
199
+ @r.type('list') { |r| r.should == "list" }
200
+ @r.llen('list') { |r| r.should == 1 ; done }
201
+ end
202
+ #
203
+ it "should be able to pop the tail of a list (RPOP)" do
204
+ @r.rpush "list", 'hello'
205
+ @r.rpush"list", 'goodbye'
206
+ @r.type('list') { |r| r.should == "list" }
207
+ @r.llen('list') { |r| r.should == 2 }
208
+ @r.rpop('list') { |r| r.should == 'goodbye'; done }
209
+ end
210
+ #
211
+ it "should be able to pop the head of a list (LPOP)" do
212
+ @r.rpush "list", 'hello'
213
+ @r.rpush "list", 'goodbye'
214
+ @r.type('list') { |r| r.should == "list" }
215
+ @r.llen('list') { |r| r.should == 2 }
216
+ @r.lpop('list') { |r| r.should == 'hello'; done }
217
+ end
218
+ #
219
+ it "should be able to get the length of a list (LLEN)" do
220
+ @r.rpush "list", 'hello'
221
+ @r.rpush "list", 'goodbye'
222
+ @r.type('list') { |r| r.should == "list" }
223
+ @r.llen('list') { |r| r.should == 2 ; done }
224
+ end
225
+ #
226
+ it "should be able to get a range of values from a list (LRANGE)" do
227
+ @r.rpush "list", 'hello'
228
+ @r.rpush "list", 'goodbye'
229
+ @r.rpush "list", '1'
230
+ @r.rpush "list", '2'
231
+ @r.rpush "list", '3'
232
+ @r.type('list') { |r| r.should == "list" }
233
+ @r.llen('list') { |r| r.should == 5 }
234
+ @r.lrange('list', 2, -1) { |r| r.should == ['1', '2', '3']; done }
235
+ end
236
+ #
237
+ it "should be able to trim a list (LTRIM)" do
238
+ @r.rpush "list", 'hello'
239
+ @r.rpush "list", 'goodbye'
240
+ @r.rpush "list", '1'
241
+ @r.rpush "list", '2'
242
+ @r.rpush "list", '3'
243
+ @r.type('list') { |r| r.should == "list" }
244
+ @r.llen('list') { |r| r.should == 5 }
245
+ @r.ltrim 'list', 0, 1
246
+ @r.llen('list') { |r| r.should == 2 }
247
+ @r.lrange('list', 0, -1) { |r| r.should == ['hello', 'goodbye']; done }
248
+ end
249
+ #
250
+ it "should be able to get a value by indexing into a list (LINDEX)" do
251
+ @r.rpush "list", 'hello'
252
+ @r.rpush "list", 'goodbye'
253
+ @r.type('list') { |r| r.should == "list" }
254
+ @r.llen('list') { |r| r.should == 2 }
255
+ @r.lindex('list', 1) { |r| r.should == 'goodbye'; done }
256
+ end
257
+ #
258
+ it "should be able to set a value by indexing into a list (LSET)" do
259
+ @r.rpush "list", 'hello'
260
+ @r.rpush "list", 'hello'
261
+ @r.type('list') { |r| r.should == "list" }
262
+ @r.llen('list') { |r| r.should == 2 }
263
+ @r.lset('list', 1, 'goodbye') { |r| r.should == 'OK' }
264
+ @r.lindex('list', 1) { |r| r.should == 'goodbye'; done }
265
+ end
266
+ #
267
+ it "should be able to remove values from a list (LREM)" do
268
+ @r.rpush "list", 'hello'
269
+ @r.rpush "list", 'goodbye'
270
+ @r.type('list') { |r| r.should == "list" }
271
+ @r.llen('list') { |r| r.should == 2 }
272
+ @r.lrem('list', 1, 'hello') { |r| r.should == 1 }
273
+ @r.lrange('list', 0, -1) { |r| r.should == ['goodbye']; done }
274
+ end
275
+
276
+ it "should be able to pop values from a list and push them onto a temp list(RPOPLPUSH)" do
277
+ @r.rpush "list", 'one'
278
+ @r.rpush "list", 'two'
279
+ @r.rpush "list", 'three'
280
+ @r.type('list') { |r| r.should == "list" }
281
+ @r.llen('list') { |r| r.should == 3 }
282
+ @r.lrange('list', 0, -1) { |r| r.should == ['one', 'two', 'three'] }
283
+ @r.lrange('tmp', 0, -1) { |r| r.should == [] }
284
+ @r.rpoplpush('list', 'tmp') { |r| r.should == 'three' }
285
+ @r.lrange('tmp', 0, -1) { |r| r.should == ['three'] }
286
+ @r.rpoplpush('list', 'tmp') { |r| r.should == 'two' }
287
+ @r.lrange('tmp', 0, -1) { |r| r.should == ['two', 'three'] }
288
+ @r.rpoplpush('list', 'tmp') { |r| r.should == 'one' }
289
+ @r.lrange('tmp', 0, -1) { |r| r.should == ['one', 'two', 'three']; done }
290
+ end
291
+ #
292
+ it "should be able add members to a set (SADD)" do
293
+ @r.sadd "set", 'key1'
294
+ @r.sadd "set", 'key2'
295
+ @r.type('set') { |r| r.should == "set" }
296
+ @r.scard('set') { |r| r.should == 2 }
297
+ @r.smembers('set') { |r| r.sort.should == ['key1', 'key2'].sort; done }
298
+ end
299
+ #
300
+ it "should be able delete members to a set (SREM)" do
301
+ @r.sadd "set", 'key1'
302
+ @r.sadd "set", 'key2'
303
+ @r.type('set') { |r| r.should == "set" }
304
+ @r.scard('set') { |r| r.should == 2 }
305
+ @r.smembers('set') { |r| r.sort.should == ['key1', 'key2'].sort }
306
+ @r.srem('set', 'key1')
307
+ @r.scard('set') { |r| r.should == 1 }
308
+ @r.smembers('set') { |r| r.should == ['key2']; done }
309
+ end
310
+ #
311
+ it "should be able to return and remove random key from set (SPOP)" do
312
+ @r.sadd "set_pop", "key1"
313
+ @r.sadd "set_pop", "key2"
314
+ @r.spop("set_pop") { |r| r.should.not == nil }
315
+ @r.scard("set_pop") { |r| r.should == 1; done }
316
+ end
317
+ #
318
+ it "should be able to return random key without delete the key from a set (SRANDMEMBER)" do
319
+ @r.sadd "set_srandmember", "key1"
320
+ @r.sadd "set_srandmember", "key2"
321
+ @r.srandmember("set_srandmember") { |r| r.should.not == nil }
322
+ @r.scard("set_srandmember") { |r| r.should == 2; done }
323
+ end
324
+ #
325
+ it "should be able count the members of a set (SCARD)" do
326
+ @r.sadd "set", 'key1'
327
+ @r.sadd "set", 'key2'
328
+ @r.type('set') { |r| r.should == "set" }
329
+ @r.scard('set') { |r| r.should == 2; done }
330
+ end
331
+ #
332
+ it "should be able test for set membership (SISMEMBER)" do
333
+ @r.sadd "set", 'key1'
334
+ @r.sadd "set", 'key2'
335
+ @r.type('set') { |r| r.should == "set" }
336
+ @r.scard('set') { |r| r.should == 2 }
337
+ @r.sismember('set', 'key1') { |r| r.should == true }
338
+ @r.sismember('set', 'key2') { |r| r.should == true }
339
+ @r.sismember('set', 'notthere') { |r| r.should == false; done }
340
+ end
341
+ #
342
+ it "should be able to do set intersection (SINTER)" do
343
+ @r.sadd "set", 'key1'
344
+ @r.sadd "set", 'key2'
345
+ @r.sadd "set2", 'key2'
346
+ @r.sinter('set', 'set2') { |r| r.should == ['key2']; done }
347
+ end
348
+ #
349
+ it "should be able to do set intersection and store the results in a key (SINTERSTORE)" do
350
+ @r.sadd "set", 'key1'
351
+ @r.sadd "set", 'key2'
352
+ @r.sadd "set2", 'key2'
353
+ @r.sinterstore('newone', 'set', 'set2') { |r| r.should == 1 }
354
+ @r.smembers('newone') { |r| r.should == ['key2']; done }
355
+ end
356
+ #
357
+ it "should be able to do set union (SUNION)" do
358
+ @r.sadd "set", 'key1'
359
+ @r.sadd "set", 'key2'
360
+ @r.sadd "set2", 'key2'
361
+ @r.sadd "set2", 'key3'
362
+ @r.sunion('set', 'set2') { |r| r.sort.should == ['key1','key2','key3'].sort; done }
363
+ end
364
+ #
365
+ it "should be able to do set union and store the results in a key (SUNIONSTORE)" do
366
+ @r.sadd "set", 'key1'
367
+ @r.sadd "set", 'key2'
368
+ @r.sadd "set2", 'key2'
369
+ @r.sadd "set2", 'key3'
370
+ @r.sunionstore('newone', 'set', 'set2') { |r| r.should == 3 }
371
+ @r.smembers('newone') { |r| r.sort.should == ['key1','key2','key3'].sort; done }
372
+ end
373
+ #
374
+ it "should be able to do set difference (SDIFF)" do
375
+ @r.sadd "set", 'a'
376
+ @r.sadd "set", 'b'
377
+ @r.sadd "set2", 'b'
378
+ @r.sadd "set2", 'c'
379
+ @r.sdiff('set', 'set2') { |r| r.should == ['a']; done }
380
+ end
381
+ #
382
+ it "should be able to do set difference and store the results in a key (SDIFFSTORE)" do
383
+ @r.sadd "set", 'a'
384
+ @r.sadd "set", 'b'
385
+ @r.sadd "set2", 'b'
386
+ @r.sadd "set2", 'c'
387
+ @r.sdiffstore('newone', 'set', 'set2')
388
+ @r.smembers('newone') { |r| r.should == ['a']; done }
389
+ end
390
+ #
391
+ it "should be able move elements from one set to another (SMOVE)" do
392
+ @r.sadd 'set1', 'a'
393
+ @r.sadd 'set1', 'b'
394
+ @r.sadd 'set2', 'x'
395
+ @r.smove('set1', 'set2', 'a') { |r| r.should == true }
396
+ @r.sismember('set2', 'a') { |r| r.should == true }
397
+ @r.delete('set1') { done }
398
+ end
399
+ #
400
+ it "should be able to do crazy SORT queries" do
401
+ # The 'Dogs' is capitialized on purpose
402
+ @r['dog_1'] = 'louie'
403
+ @r.rpush 'Dogs', 1
404
+ @r['dog_2'] = 'lucy'
405
+ @r.rpush 'Dogs', 2
406
+ @r['dog_3'] = 'max'
407
+ @r.rpush 'Dogs', 3
408
+ @r['dog_4'] = 'taj'
409
+ @r.rpush 'Dogs', 4
410
+ @r.sort('Dogs', :get => 'dog_*', :limit => [0,1]) { |r| r.should == ['louie'] }
411
+ @r.sort('Dogs', :get => 'dog_*', :limit => [0,1], :order => 'desc alpha') { |r| r.should == ['taj'] }
412
+ @r.ping { done }
413
+ end
414
+
415
+ it "should be able to handle array of :get using SORT" do
416
+ @r['dog:1:name'] = 'louie'
417
+ @r['dog:1:breed'] = 'mutt'
418
+ @r.rpush 'dogs', 1
419
+ @r['dog:2:name'] = 'lucy'
420
+ @r['dog:2:breed'] = 'poodle'
421
+ @r.rpush 'dogs', 2
422
+ @r['dog:3:name'] = 'max'
423
+ @r['dog:3:breed'] = 'hound'
424
+ @r.rpush 'dogs', 3
425
+ @r['dog:4:name'] = 'taj'
426
+ @r['dog:4:breed'] = 'terrier'
427
+ @r.rpush 'dogs', 4
428
+ @r.sort('dogs', :get => ['dog:*:name', 'dog:*:breed'], :limit => [0,1]) { |r| r.should == ['louie', 'mutt'] }
429
+ @r.sort('dogs', :get => ['dog:*:name', 'dog:*:breed'], :limit => [0,1], :order => 'desc alpha') { |r| r.should == ['taj', 'terrier'] }
430
+ @r.ping { done }
431
+ end
432
+ #
433
+ it "should be able count the members of a zset" do
434
+ @r.set_add "set", 'key1'
435
+ @r.set_add "set", 'key2'
436
+ @r.zset_add 'zset', 1, 'set'
437
+ @r.zset_count('zset') { |r| r.should == 1 }
438
+ @r.delete('set')
439
+ @r.delete('zset') { done }
440
+ end
441
+ #
442
+ it "should be able add members to a zset" do
443
+ @r.set_add "set", 'key1'
444
+ @r.set_add "set", 'key2'
445
+ @r.zset_add 'zset', 1, 'set'
446
+ @r.zset_range('zset', 0, 1) { |r| r.should == ['set'] }
447
+ @r.zset_count('zset') { |r| r.should == 1 }
448
+ @r.delete('set')
449
+ @r.delete('zset') { done }
450
+ end
451
+ #
452
+ it "should be able delete members to a zset" do
453
+ @r.set_add "set", 'key1'
454
+ @r.set_add "set", 'key2'
455
+ @r.type?('set') { |r| r.should == "set" }
456
+ @r.set_add "set2", 'key3'
457
+ @r.set_add "set2", 'key4'
458
+ @r.type?('set2') { |r| r.should == "set" }
459
+ @r.zset_add 'zset', 1, 'set'
460
+ @r.zset_count('zset') { |r| r.should == 1 }
461
+ @r.zset_add 'zset', 2, 'set2'
462
+ @r.zset_count('zset') { |r| r.should == 2 }
463
+ @r.zset_delete 'zset', 'set'
464
+ @r.zset_count('zset') { |r| r.should == 1 }
465
+ @r.delete('set')
466
+ @r.delete('set2')
467
+ @r.delete('zset') { done }
468
+ end
469
+ #
470
+ it "should be able to get a range of values from a zset" do
471
+ @r.set_add "set", 'key1'
472
+ @r.set_add "set", 'key2'
473
+ @r.set_add "set2", 'key3'
474
+ @r.set_add "set2", 'key4'
475
+ @r.set_add "set3", 'key1'
476
+ @r.type?('set') { |r| r.should == 'set' }
477
+ @r.type?('set2') { |r| r.should == 'set' }
478
+ @r.type?('set3') { |r| r.should == 'set' }
479
+ @r.zset_add 'zset', 1, 'set'
480
+ @r.zset_add 'zset', 2, 'set2'
481
+ @r.zset_add 'zset', 3, 'set3'
482
+ @r.zset_count('zset') { |r| r.should == 3 }
483
+ @r.zset_range('zset', 0, 3) { |r| r.should == ['set', 'set2', 'set3'] }
484
+ @r.delete('set')
485
+ @r.delete('set2')
486
+ @r.delete('set3')
487
+ @r.delete('zset') { done }
488
+ end
489
+ #
490
+ it "should be able to get a reverse range of values from a zset" do
491
+ @r.set_add "set", 'key1'
492
+ @r.set_add "set", 'key2'
493
+ @r.set_add "set2", 'key3'
494
+ @r.set_add "set2", 'key4'
495
+ @r.set_add "set3", 'key1'
496
+ @r.type?('set') { |r| r.should == 'set' }
497
+ @r.type?('set2') { |r| r.should == 'set' }
498
+ @r.type?('set3') { |r| r.should == 'set' }
499
+ @r.zset_add 'zset', 1, 'set'
500
+ @r.zset_add 'zset', 2, 'set2'
501
+ @r.zset_add 'zset', 3, 'set3'
502
+ @r.zset_count('zset') { |r| r.should == 3 }
503
+ @r.zset_reverse_range('zset', 0, 3) { |r| r.should == ['set3', 'set2', 'set'] }
504
+ @r.delete('set')
505
+ @r.delete('set2')
506
+ @r.delete('set3')
507
+ @r.delete('zset') { done }
508
+ end
509
+ #
510
+ it "should be able to get a range by score of values from a zset" do
511
+ @r.set_add "set", 'key1'
512
+ @r.set_add "set", 'key2'
513
+ @r.set_add "set2", 'key3'
514
+ @r.set_add "set2", 'key4'
515
+ @r.set_add "set3", 'key1'
516
+ @r.set_add "set4", 'key4'
517
+ @r.zset_add 'zset', 1, 'set'
518
+ @r.zset_add 'zset', 2, 'set2'
519
+ @r.zset_add 'zset', 3, 'set3'
520
+ @r.zset_add 'zset', 4, 'set4'
521
+ @r.zset_count('zset') { |r| r.should == 4 }
522
+ @r.zset_range_by_score('zset', 2, 3) { |r| r.should == ['set2', 'set3'] }
523
+ @r.delete('set')
524
+ @r.delete('set2')
525
+ @r.delete('set3')
526
+ @r.delete('set4')
527
+ @r.delete('zset') { done }
528
+ end
529
+ #
530
+ it "should be able to get a score for a specific value in a zset (ZSCORE)" do
531
+ @r.zset_add "zset", 23, "value"
532
+ @r.zset_score("zset", "value") { |r| r.should == "23" }
533
+
534
+ @r.zset_score("zset", "value2") { |r| r.should == nil }
535
+ @r.zset_score("unknown_zset", "value") { |r| r.should == nil }
536
+
537
+ @r.delete("zset") { done }
538
+ end
539
+ #
540
+ it "should be able to increment a range score of a zset (ZINCRBY)" do
541
+ # create a new zset
542
+ @r.zset_increment_by "hackers", 1965, "Yukihiro Matsumoto"
543
+ @r.zset_score("hackers", "Yukihiro Matsumoto") { |r| r.should == "1965" }
544
+
545
+ # add a new element
546
+ @r.zset_increment_by "hackers", 1912, "Alan Turing"
547
+ @r.zset_score("hackers", "Alan Turing") { |r| r.should == "1912" }
548
+
549
+ # update the score
550
+ @r.zset_increment_by "hackers", 100, "Alan Turing" # yeah, we are making Turing a bit younger
551
+ @r.zset_score("hackers", "Alan Turing") { |r| r.should == "2012" }
552
+
553
+ # attempt to update a key that's not a zset
554
+ @r["i_am_not_a_zet"] = "value"
555
+ # should raise error
556
+ @r.on_error { true.should == true }
557
+ @r.zset_incr_by("i_am_not_a_zet", 23, "element") { false.should == true }
558
+
559
+ @r.delete("hackers")
560
+ @r.delete("i_am_not_a_zet") { done }
561
+ end
562
+ #
563
+ it "should provide info (INFO)" do
564
+ @r.info do |r|
565
+ [: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|
566
+ r.keys.include?(x).should == true
567
+ end
568
+ done
569
+ end
570
+ end
571
+ #
572
+ it "should be able to flush the database (FLUSHDB)" do
573
+ @r['key1'] = 'keyone'
574
+ @r['key2'] = 'keytwo'
575
+ @r.keys('*') { |r| r.sort.should == ['foo', 'key1', 'key2'].sort } #foo from before
576
+ @r.flushdb
577
+ @r.keys('*') { |r| r.should == []; done }
578
+ end
579
+ #
580
+ it "should be able to SELECT database" do
581
+ @r.select(15)
582
+ @r.get('foo') { |r| r.should == nil; done }
583
+ end
584
+ #
585
+ it "should be able to provide the last save time (LASTSAVE)" do
586
+ @r.lastsave do |savetime|
587
+ Time.at(savetime).class.should == Time
588
+ Time.at(savetime).should <= Time.now
589
+ done
590
+ end
591
+ end
592
+
593
+ it "should be able to MGET keys" do
594
+ @r['foo'] = 1000
595
+ @r['bar'] = 2000
596
+ @r.mget('foo', 'bar') { |r| r.should == ['1000', '2000'] }
597
+ @r.mget('foo', 'bar', 'baz') { |r| r.should == ['1000', '2000', nil] }
598
+ @r.ping { done }
599
+ end
600
+
601
+ it "should be able to mapped MGET keys" do
602
+ @r['foo'] = 1000
603
+ @r['bar'] = 2000
604
+ @r.mapped_mget('foo', 'bar') { |r| r.should == { 'foo' => '1000', 'bar' => '2000'} }
605
+ @r.mapped_mget('foo', 'baz', 'bar') { |r| r.should == { 'foo' => '1000', 'bar' => '2000'} }
606
+ @r.ping { done }
607
+ end
608
+
609
+ it "should be able to MSET values" do
610
+ @r.mset :key1 => "value1", :key2 => "value2"
611
+ @r.get('key1') { |r| r.should == "value1" }
612
+ @r.get('key2') { |r| r.should == "value2"; done }
613
+ end
614
+
615
+ it "should be able to MSETNX values" do
616
+ @r.msetnx :keynx1 => "valuenx1", :keynx2 => "valuenx2"
617
+ @r.mget('keynx1', 'keynx2') { |r| r.should == ["valuenx1", "valuenx2"] }
618
+
619
+ @r["keynx1"] = "value1"
620
+ @r["keynx2"] = "value2"
621
+ @r.msetnx :keynx1 => "valuenx1", :keynx2 => "valuenx2"
622
+ @r.mget('keynx1', 'keynx2') { |r| r.should == ["value1", "value2"]; done }
623
+ end
624
+
625
+ it "should bgsave" do
626
+ @r.bgsave do |r|
627
+ ['OK', 'Background saving started'].include?(r).should == true
628
+ done
629
+ end
630
+ end
631
+
632
+ it "should be able to ECHO" do
633
+ @r.echo("message in a bottle\n") { |r| r.should == "message in a bottle\n"; done }
634
+ end
635
+
636
+ # Tests are disabled due uncatchable exceptions. We should use on_error callback,
637
+ # intead of raising exceptions in random places.
638
+ #
639
+ # it "should raise error when invoke MONITOR" do
640
+ # # lambda { @r.monitor }.should.raise
641
+ # done
642
+ # end
643
+ #
644
+ # it "should raise error when invoke SYNC" do
645
+ # # lambda { @r.sync }.should.raise
646
+ # done
647
+ # end
648
+
649
+ it "should run MULTI without a block" do
650
+ @r.multi
651
+ @r.get("key1") { |r| r.should == "QUEUED" }
652
+ @r.discard { done }
653
+ end
654
+
655
+ it "should run MULTI/EXEC with a block" do
656
+ @r.multi do
657
+ @r.set "key1", "value1"
658
+ end
659
+
660
+ @r.get("key1") { |r| r.should == "value1" }
661
+
662
+ begin
663
+ @r.multi do
664
+ @r.set "key2", "value2"
665
+ raise "Some error"
666
+ @r.set "key3", "value3"
667
+ end
668
+ rescue
669
+ end
670
+
671
+ @r.get("key2") { |r| r.should == nil }
672
+ @r.get("key3") { |r| r.should == nil; done}
673
+ end
674
+
675
+ it "should yield the Redis object when using #multi with a block" do
676
+ @r.multi do |multi|
677
+ multi.set "key1", "value1"
678
+ end
679
+
680
+ @r.get("key1") { |r| r.should == "value1"; done }
681
+ end
682
+
683
+ it "can set and get hash values" do
684
+ @r.hset("rush", "signals", "1982") { |r| r.should == true }
685
+ @r.hexists("rush", "signals") { |r| r.should == true }
686
+ @r.hget("rush", "signals") { |r| r.should == "1982"; done }
687
+ end
688
+
689
+ it "can delete hash values" do
690
+ @r.hset("rush", "YYZ", "1981")
691
+ @r.hdel("rush", "YYZ") { |r| r.should == true }
692
+ @r.hexists("rush", "YYZ") { |r| r.should == false; done }
693
+ end
694
+ end
695
+
696
+ # Yup, bacon can't handle nested describe blocks properly
697
+ EM.describe EM::Protocols::Redis, "with some hash values" do
698
+ default_timeout 1
699
+
700
+ before do
701
+ @r = EM::Protocols::Redis.connect :db => 14
702
+ @r.flushdb
703
+ @r['foo'] = 'bar'
704
+ @r.hset("rush", "permanent waves", "1980")
705
+ @r.hset("rush", "moving pictures", "1981")
706
+ @r.hset("rush", "signals", "1982")
707
+ end
708
+
709
+ after { @r.close_connection }
710
+
711
+ it "can get the length of the hash" do
712
+ @r.hlen("rush") { |r| r.should == 3 }
713
+ @r.hlen("yyz") { |r| r.should == 0; done }
714
+ end
715
+
716
+ it "can get the keys and values of the hash" do
717
+ @r.hkeys("rush") { |r| r.should == ["permanent waves", "moving pictures", "signals"] }
718
+ @r.hvals("rush") { |r| r.should == %w[1980 1981 1982] }
719
+ @r.hvals("yyz") { |r| r.should == []; done }
720
+ end
721
+
722
+ it "returns a hash for HGETALL" do
723
+ @r.hgetall("rush") do |r|
724
+ r.should == {
725
+ "permanent waves" => "1980",
726
+ "moving pictures" => "1981",
727
+ "signals" => "1982"
728
+ }
729
+ end
730
+ @r.hgetall("yyz") { |r| r.should == {}; done }
731
+ end
732
+ end
733
+
734
+ EM.describe EM::Protocols::Redis, "with nested multi-bulk response" do
735
+ default_timeout 1
736
+
737
+ before do
738
+ @r = EM::Protocols::Redis.connect :db => 14
739
+ @r.flushdb
740
+ @r.set 'user:one:id', 'id-one'
741
+ @r.set 'user:two:id', 'id-two'
742
+ @r.sadd "user:one:interests", "first-interest"
743
+ @r.sadd "user:one:interests", "second-interest"
744
+ @r.sadd "user:two:interests", "third-interest"
745
+ end
746
+
747
+ after { @r.close_connection }
748
+
749
+ it "returns array of arrays" do
750
+ @r.multi
751
+ @r.smembers "user:one:interests"
752
+ @r.smembers "user:two:interests"
753
+ @r.exec do |user_interests|
754
+ user_interests.should == [["second-interest", "first-interest"], ['third-interest']]
755
+ end
756
+ @r.mget("user:one:id", "user:two:id") do |user_ids|
757
+ user_ids.should == ['id-one', 'id-two']
758
+ done
759
+ end
760
+ end
761
+ end