yapplabs-em-hiredis 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,527 @@
1
+ require 'spec_helper'
2
+
3
+ describe EventMachine::Hiredis, "connected to an empty db" do
4
+ it "sets a string value" do
5
+ connect do |redis|
6
+ redis.set("foo", "bar") do |r|
7
+ r.should == "OK"
8
+ done
9
+ end
10
+ end
11
+ end
12
+
13
+ it "increments the value of a string" do
14
+ connect do |redis|
15
+ redis.incr "foo" do |r|
16
+ r.should == 1
17
+ redis.incr "foo" do |r|
18
+ r.should == 2
19
+ done
20
+ end
21
+ end
22
+ end
23
+ end
24
+
25
+ it "increments the value of a string by an amount" do
26
+ connect do |redis|
27
+ redis.incrby "foo", 10 do |r|
28
+ r.should == 10
29
+ done
30
+ end
31
+ end
32
+ end
33
+
34
+ it "decrements the value of a string" do
35
+ connect do |redis|
36
+ redis.incr "foo" do |r|
37
+ r.should == 1
38
+ redis.decr "foo" do |r|
39
+ r.should == 0
40
+ done
41
+ end
42
+ end
43
+ end
44
+ end
45
+
46
+ it "decrement the value of a string by an amount" do
47
+ connect do |redis|
48
+ redis.incrby "foo", 20 do |r|
49
+ r.should == 20
50
+ redis.decrby "foo", 10 do |r|
51
+ r.should == 10
52
+ done
53
+ end
54
+ end
55
+ end
56
+ end
57
+
58
+ it "can 'lpush' to a nonexistent list" do
59
+ connect do |redis|
60
+ redis.lpush("foo", "bar") do |r|
61
+ r.should == 1
62
+ done
63
+ end
64
+ end
65
+ end
66
+
67
+ it "can 'rpush' to a nonexistent list" do
68
+ connect do |redis|
69
+ redis.rpush("foo", "bar") do |r|
70
+ r.should == 1
71
+ done
72
+ end
73
+ end
74
+ end
75
+
76
+
77
+ it "gets the size of the database" do
78
+ connect do |redis|
79
+ redis.dbsize do |r|
80
+ r.should == 0
81
+ done
82
+ end
83
+ end
84
+ end
85
+
86
+ it "adds a member to a nonexistent set" do
87
+ connect do |redis|
88
+ redis.sadd("set_foo", "bar") do |r|
89
+ r.should == 1
90
+ done
91
+ end
92
+ end
93
+ end
94
+
95
+ it "reads info about the db" do
96
+ connect do |redis|
97
+ redis.info do |info|
98
+ info[:redis_version].should_not be_nil
99
+ done
100
+ end
101
+ end
102
+ end
103
+
104
+ it "can save the db" do
105
+ connect do |redis|
106
+ redis.save do |r|
107
+ r.should == "OK"
108
+ done
109
+ end
110
+ end
111
+ end
112
+
113
+ it "can save the db in the background" do
114
+ connect do |redis|
115
+ redis.bgsave do |r|
116
+ r.should == "Background saving started"
117
+ done
118
+ end
119
+ end
120
+ end
121
+ end
122
+
123
+ describe EventMachine::Hiredis, "connected to a db containing some simple string-valued keys" do
124
+ def set(&blk)
125
+ connect do |redis|
126
+ redis.flushdb
127
+ redis.set "a", "b"
128
+ redis.set "x", "y"
129
+ blk.call(redis)
130
+ end
131
+ end
132
+
133
+ it "fetches the values of multiple keys" do
134
+ set do |redis|
135
+ redis.mget "a", "x" do |r|
136
+ r.should == ["b", "y"]
137
+ done
138
+ end
139
+ end
140
+ end
141
+
142
+ it "fetches all the keys" do
143
+ set do |redis|
144
+ redis.keys "*" do |r|
145
+ r.sort.should == ["a", "x"]
146
+ done
147
+ end
148
+ end
149
+ end
150
+
151
+ it "sets a value if a key doesn't exist" do
152
+ set do |redis|
153
+ redis.setnx "a", "foo" do |r|
154
+ r.should == 0
155
+ redis.setnx "zzz", "foo" do |r|
156
+ r.should == 1
157
+ done
158
+ end
159
+ end
160
+ end
161
+ end
162
+
163
+ it "tests for the existence of a key" do
164
+ set do |redis|
165
+ redis.exists "a" do |r|
166
+ r.should == 1
167
+ redis.exists "zzz" do |r|
168
+ r.should == 0
169
+ done
170
+ end
171
+ end
172
+ end
173
+ end
174
+
175
+ it "deletes a key" do
176
+ set do |redis|
177
+ redis.del "a" do |r|
178
+ r.should == 1
179
+ redis.exists "a" do |r|
180
+ r.should == 0
181
+ redis.del "a" do |r|
182
+ r.should == 0
183
+ done
184
+ end
185
+ end
186
+ end
187
+ end
188
+ end
189
+
190
+ it "detects the type of a key, existing or not" do
191
+ set do |redis|
192
+ redis.type "a" do |r|
193
+ r.should == "string"
194
+ redis.type "zzz" do |r|
195
+ r.should == "none"
196
+ done
197
+ end
198
+ end
199
+ end
200
+ end
201
+
202
+ it "renames a key" do
203
+ set do |redis|
204
+ redis.rename "a", "x" do |r|
205
+ redis.get "x" do |r|
206
+ r.should == "b"
207
+ done
208
+ end
209
+ end
210
+ end
211
+ end
212
+
213
+ it "renames a key unless it exists" do
214
+ set do |redis|
215
+ redis.renamenx "a", "x" do |r|
216
+ r.should == 0
217
+ redis.renamenx "a", "zzz" do |r|
218
+ r.should == 1
219
+ redis.get "zzz" do |r|
220
+ r.should == "b"
221
+ done
222
+ end
223
+ end
224
+ end
225
+ end
226
+ end
227
+ end
228
+
229
+ describe EventMachine::Hiredis, "connected to a db containing a list" do
230
+ def set(&blk)
231
+ connect do |redis|
232
+ redis.flushdb
233
+ redis.lpush "foo", "c"
234
+ redis.lpush "foo", "b"
235
+ redis.lpush "foo", "a"
236
+ blk.call(redis)
237
+ end
238
+ end
239
+
240
+ it "sets a list member and 'lindex' to retrieve it" do
241
+ set do |redis|
242
+ redis.lset("foo", 1, "bar") do |r|
243
+ redis.lindex("foo", 1) do |r|
244
+ r.should == "bar"
245
+ done
246
+ end
247
+ end
248
+ end
249
+ end
250
+
251
+ it "pushes onto tail of the list" do
252
+ set do |redis|
253
+ redis.rpush "foo", "d" do |r|
254
+ r.should == 4
255
+ redis.rpop "foo" do |r|
256
+ r.should == "d"
257
+ done
258
+ end
259
+ end
260
+ end
261
+ end
262
+
263
+ it "pushes onto the head of the list" do
264
+ set do |redis|
265
+ redis.lpush "foo", "d" do |r|
266
+ r.should == 4
267
+ redis.lpop "foo" do |r|
268
+ r.should == "d"
269
+ done
270
+ end
271
+ end
272
+ end
273
+ end
274
+
275
+ it "pops off the tail of the list" do
276
+ set do |redis|
277
+ redis.rpop("foo") do |r|
278
+ r.should == "c"
279
+ done
280
+ end
281
+ end
282
+ end
283
+
284
+ it "pops off the tail of the list" do
285
+ set do |redis|
286
+ redis.lpop("foo") do |r|
287
+ r.should == "a"
288
+ done
289
+ end
290
+ end
291
+ end
292
+
293
+ it "gets a range of values from a list" do
294
+ set do |redis|
295
+ redis.lrange("foo", 0, 1) do |r|
296
+ r.should == ["a", "b"]
297
+ done
298
+ end
299
+ end
300
+ end
301
+
302
+ it "trims a list" do
303
+ set do |redis|
304
+ redis.ltrim("foo", 0, 1) do |r|
305
+ r.should == "OK"
306
+ redis.llen("foo") do |r|
307
+ r.should == 2
308
+ done
309
+ end
310
+ end
311
+ end
312
+ end
313
+
314
+ it "removes a list element" do
315
+ set do |redis|
316
+ redis.lrem("foo", 0, "a") do |r|
317
+ r.should == 1
318
+ redis.llen("foo") do |r|
319
+ r.should == 2
320
+ done
321
+ end
322
+ end
323
+ end
324
+ end
325
+
326
+ it "detects the type of a list" do
327
+ set do |redis|
328
+ redis.type "foo" do |r|
329
+ r.should == "list"
330
+ done
331
+ end
332
+ end
333
+ end
334
+ end
335
+
336
+ describe EventMachine::Hiredis, "connected to a db containing two sets" do
337
+ def set(&blk)
338
+ connect do |redis|
339
+ redis.flushdb
340
+ redis.sadd "foo", "a"
341
+ redis.sadd "foo", "b"
342
+ redis.sadd "foo", "c"
343
+ redis.sadd "bar", "c"
344
+ redis.sadd "bar", "d"
345
+ redis.sadd "bar", "e"
346
+ blk.call(redis)
347
+ end
348
+ end
349
+
350
+ it "finds a set's cardinality" do
351
+ set do |redis|
352
+ redis.scard("foo") do |r|
353
+ r.should == 3
354
+ done
355
+ end
356
+ end
357
+ end
358
+
359
+ it "adds a new member to a set unless it is a duplicate" do
360
+ set do |redis|
361
+ redis.sadd("foo", "d") do |r|
362
+ r.should == 1 # success
363
+ redis.sadd("foo", "a") do |r|
364
+ r.should == 0 # failure
365
+ redis.scard("foo") do |r|
366
+ r.should == 4
367
+ done
368
+ end
369
+ end
370
+ end
371
+ end
372
+ end
373
+
374
+ it "removes a set member if it exists" do
375
+ set do |redis|
376
+ redis.srem("foo", "a") do |r|
377
+ r.should == 1
378
+ redis.srem("foo", "z") do |r|
379
+ r.should == 0
380
+ redis.scard("foo") do |r|
381
+ r.should == 2
382
+ done
383
+ end
384
+ end
385
+ end
386
+ end
387
+ end
388
+
389
+ it "retrieves a set's members" do
390
+ set do |redis|
391
+ redis.smembers("foo") do |r|
392
+ r.sort.should == ["a", "b", "c"]
393
+ done
394
+ end
395
+ end
396
+ end
397
+
398
+ it "detects set membership" do
399
+ set do |redis|
400
+ redis.sismember("foo", "a") do |r|
401
+ r.should == 1
402
+ redis.sismember("foo", "z") do |r|
403
+ r.should == 0
404
+ done
405
+ end
406
+ end
407
+ end
408
+ end
409
+
410
+ it "finds the sets' intersection" do
411
+ set do |redis|
412
+ redis.sinter("foo", "bar") do |r|
413
+ r.should == ["c"]
414
+ done
415
+ end
416
+ end
417
+ end
418
+
419
+ it "finds and stores the sets' intersection" do
420
+ set do |redis|
421
+ redis.sinterstore("baz", "foo", "bar") do |r|
422
+ r.should == 1
423
+ redis.smembers("baz") do |r|
424
+ r.should == ["c"]
425
+ done
426
+ end
427
+ end
428
+ end
429
+ end
430
+
431
+ it "finds the sets' union" do
432
+ set do |redis|
433
+ redis.sunion("foo", "bar") do |r|
434
+ r.sort.should == ["a","b","c","d","e"]
435
+ done
436
+ end
437
+ end
438
+ end
439
+
440
+ it "finds and stores the sets' union" do
441
+ set do |redis|
442
+ redis.sunionstore("baz", "foo", "bar") do |r|
443
+ r.should == 5
444
+ redis.smembers("baz") do |r|
445
+ r.sort.should == ["a","b","c","d","e"]
446
+ done
447
+ end
448
+ end
449
+ end
450
+ end
451
+
452
+ it "detects the type of a set" do
453
+ set do |redis|
454
+ redis.type "foo" do |r|
455
+ r.should == "set"
456
+ done
457
+ end
458
+ end
459
+ end
460
+ end
461
+
462
+ describe EventMachine::Hiredis, "connected to a db containing three linked lists" do
463
+ def set(&blk)
464
+ connect do |redis|
465
+ redis.flushdb
466
+ redis.rpush "foo", "a"
467
+ redis.rpush "foo", "b"
468
+ redis.set "a_sort", "2"
469
+ redis.set "b_sort", "1"
470
+ redis.set "a_data", "foo"
471
+ redis.set "b_data", "bar"
472
+ blk.call(redis)
473
+ end
474
+ end
475
+
476
+ it "collates a sorted set of data" do
477
+ set do |redis|
478
+ redis.sort("foo", "BY", "*_sort", "GET", "*_data") do |r|
479
+ r.should == ["bar", "foo"]
480
+ done
481
+ end
482
+ end
483
+ end
484
+
485
+ it "gets keys selectively" do
486
+ set do |redis|
487
+ redis.keys "a_*" do |r|
488
+ r.sort.should == ["a_sort", "a_data"].sort
489
+ done
490
+ end
491
+ end
492
+ end
493
+ end
494
+
495
+ describe EventMachine::Hiredis, "when reconnecting" do
496
+ it "select previously selected dataset" do
497
+ connect(3) do |redis|
498
+ #simulate disconnect
499
+ redis.set('foo', 'a') { redis.close_connection_after_writing }
500
+
501
+ EventMachine.add_timer(2) do
502
+ redis.get('foo') do |r|
503
+ r.should == 'a'
504
+ redis.get('non_existing') do |r|
505
+ r.should == nil
506
+ done
507
+ end
508
+ end
509
+ end
510
+ end
511
+ end
512
+ end
513
+
514
+ describe EventMachine::Hiredis, "when closing_connection" do
515
+ it "should fail deferred commands" do
516
+ errored = false
517
+ connect do |redis|
518
+ op = redis.blpop 'empty_list'
519
+ op.callback { fail }
520
+ op.errback { EM.stop }
521
+
522
+ redis.close_connection
523
+
524
+ EM.add_timer(1) { fail }
525
+ end
526
+ end
527
+ end
data/spec/lock_spec.rb ADDED
@@ -0,0 +1,137 @@
1
+ require 'spec_helper'
2
+
3
+ describe EventMachine::Hiredis::Lock do
4
+
5
+ def start(timeout = 1)
6
+ connect(timeout) do |redis|
7
+ @redis = redis
8
+ yield
9
+ end
10
+ end
11
+
12
+ def new_lock
13
+ EventMachine::Hiredis::Lock.new(@redis, "test-lock", 2)
14
+ end
15
+
16
+ it "can be acquired" do
17
+ start {
18
+ new_lock.acquire.callback {
19
+ done
20
+ }.errback { |e|
21
+ fail e
22
+ }
23
+ }
24
+ end
25
+
26
+ it "is re-entrant" do
27
+ start {
28
+ lock = new_lock
29
+ lock.acquire.callback {
30
+ lock.acquire.callback {
31
+ done
32
+ }.errback { |e|
33
+ fail e
34
+ }
35
+ }.errback { |e|
36
+ fail e
37
+ }
38
+ }
39
+ end
40
+
41
+ it "is exclusive" do
42
+ start {
43
+ new_lock.acquire.callback {
44
+ new_lock.acquire.errback {
45
+ done
46
+ }.callback {
47
+ fail "Should not be able to acquire lock from different client"
48
+ }
49
+ }.errback { |e|
50
+ fail e
51
+ }
52
+ }
53
+ end
54
+
55
+ it "can be released and taken by another instance" do
56
+ start {
57
+ lock = new_lock
58
+ lock.acquire.callback {
59
+ lock.unlock.callback {
60
+ new_lock.acquire.callback {
61
+ done
62
+ }.errback { |e|
63
+ fail e
64
+ }
65
+ }.errback { |e|
66
+ fail e
67
+ }
68
+ }.errback { |e|
69
+ fail e
70
+ }
71
+ }
72
+ end
73
+
74
+ it "times out" do
75
+ start(3) {
76
+ new_lock.acquire.callback {
77
+ EM.add_timer(2) {
78
+ new_lock.acquire.callback {
79
+ done
80
+ }.errback { |e|
81
+ fail e
82
+ }
83
+ }
84
+ }.errback { |e|
85
+ fail e
86
+ }
87
+ }
88
+ end
89
+
90
+ it "extends timeout on re-entry" do
91
+ start(4) {
92
+ lock = new_lock
93
+ lock.acquire.callback {
94
+ EM.add_timer(1) {
95
+ lock.acquire.callback {
96
+ EM.add_timer(1.5) {
97
+ # Check it's still locked by initial instance
98
+ new_lock.acquire.errback {
99
+ done
100
+ }.callback { |e|
101
+ fail e
102
+ }
103
+ }
104
+ }.errback { |e|
105
+ fail e
106
+ }
107
+ }
108
+ }.errback { |e|
109
+ fail e
110
+ }
111
+ }
112
+ end
113
+
114
+ it "fails to release if it has not been taken" do
115
+ start {
116
+ new_lock.unlock.errback {
117
+ done
118
+ }.callback {
119
+ fail "Released lock which had not been taken"
120
+ }
121
+ }
122
+ end
123
+
124
+ it "fails to release if taken by another instance" do
125
+ start {
126
+ new_lock.acquire.callback {
127
+ new_lock.unlock.errback {
128
+ done
129
+ }.callback {
130
+ fail "Released lock belonging to another instance"
131
+ }
132
+ }.errback { |e|
133
+ fail e
134
+ }
135
+ }
136
+ end
137
+ end