gilmour-em-hiredis 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +6 -0
- data/.rspec +1 -0
- data/CHANGELOG.md +35 -0
- data/Gemfile +3 -0
- data/LICENCE +19 -0
- data/README.md +178 -0
- data/Rakefile +11 -0
- data/em-hiredis.gemspec +28 -0
- data/examples/getting_started.rb +14 -0
- data/examples/lua/sum.lua +4 -0
- data/examples/lua_example.rb +35 -0
- data/examples/pubsub_basics.rb +24 -0
- data/examples/pubsub_more.rb +51 -0
- data/examples/pubsub_raw.rb +25 -0
- data/lib/em-hiredis.rb +65 -0
- data/lib/em-hiredis/base_client.rb +264 -0
- data/lib/em-hiredis/client.rb +110 -0
- data/lib/em-hiredis/connection.rb +69 -0
- data/lib/em-hiredis/event_emitter.rb +29 -0
- data/lib/em-hiredis/lock.rb +88 -0
- data/lib/em-hiredis/lock_lua/lock_acquire.lua +17 -0
- data/lib/em-hiredis/lock_lua/lock_release.lua +9 -0
- data/lib/em-hiredis/persistent_lock.rb +81 -0
- data/lib/em-hiredis/pubsub_client.rb +202 -0
- data/lib/em-hiredis/version.rb +5 -0
- data/spec/base_client_spec.rb +118 -0
- data/spec/connection_spec.rb +56 -0
- data/spec/inactivity_check_spec.rb +66 -0
- data/spec/live_redis_protocol_spec.rb +527 -0
- data/spec/lock_spec.rb +137 -0
- data/spec/pubsub_spec.rb +314 -0
- data/spec/redis_commands_spec.rb +931 -0
- data/spec/spec_helper.rb +17 -0
- data/spec/support/connection_helper.rb +11 -0
- data/spec/support/inprocess_redis_mock.rb +83 -0
- data/spec/support/redis_mock.rb +65 -0
- data/spec/url_param_spec.rb +43 -0
- metadata +163 -0
@@ -0,0 +1,931 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe EventMachine::Hiredis, "commands" do
|
4
|
+
it "pings" do
|
5
|
+
connect do |redis|
|
6
|
+
redis.ping { |r| r.should == 'PONG'; done }
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
it "SETs and GETs a key" do
|
11
|
+
connect do |redis|
|
12
|
+
redis.set('foo', 'nik')
|
13
|
+
redis.get('foo') { |r| r.should == 'nik'; done }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
it "handles trailing newline characters" do
|
18
|
+
connect do |redis|
|
19
|
+
redis.set('foo', "bar\n")
|
20
|
+
redis.get('foo') { |r| r.should == "bar\n"; done }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
it "stores and retrieves all possible characters at the beginning and the end of a string" do
|
25
|
+
connect do |redis|
|
26
|
+
(0..255).each do |char_idx|
|
27
|
+
string = "#{char_idx.chr}---#{char_idx.chr}"
|
28
|
+
if RUBY_VERSION > "1.9"
|
29
|
+
string.force_encoding("UTF-8")
|
30
|
+
end
|
31
|
+
redis.set('foo', string)
|
32
|
+
redis.get('foo') { |r| r.should == string }
|
33
|
+
end
|
34
|
+
redis.ping { done }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
it "SETs a key with an expiry" do
|
39
|
+
connect do |redis|
|
40
|
+
timeout(3)
|
41
|
+
|
42
|
+
redis.setex('foo', 1, 'bar')
|
43
|
+
redis.get('foo') { |r| r.should == 'bar' }
|
44
|
+
EventMachine.add_timer(2) do
|
45
|
+
redis.get('foo') { |r| r.should == nil }
|
46
|
+
redis.ping { done }
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
it "gets TTL for a key" do
|
52
|
+
connect do |redis|
|
53
|
+
redis.setex('foo', 1, 'bar')
|
54
|
+
redis.ttl('foo') { |r| r.should == 1; done }
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
it "can SETNX" do
|
59
|
+
connect do |redis|
|
60
|
+
redis.set('foo', 'nik')
|
61
|
+
redis.get('foo') { |r| r.should == 'nik' }
|
62
|
+
redis.setnx 'foo', 'bar'
|
63
|
+
redis.get('foo') { |r| r.should == 'nik' }
|
64
|
+
|
65
|
+
redis.ping { done }
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
it "can GETSET" do
|
70
|
+
connect do |redis|
|
71
|
+
redis.set('foo', 'bar')
|
72
|
+
redis.getset('foo', 'baz') { |r| r.should == 'bar' }
|
73
|
+
redis.get('foo') { |r| r.should == 'baz'; done }
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
it "can INCR a key" do
|
78
|
+
connect do |redis|
|
79
|
+
redis.del('counter')
|
80
|
+
redis.incr('counter') { |r| r.should == 1 }
|
81
|
+
redis.incr('counter') { |r| r.should == 2 }
|
82
|
+
redis.incr('counter') { |r| r.should == 3 }
|
83
|
+
|
84
|
+
redis.ping { done }
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
it "can INCRBY a key" do
|
89
|
+
connect do |redis|
|
90
|
+
redis.del('counter')
|
91
|
+
redis.incrby('counter', 1) { |r| r.should == 1 }
|
92
|
+
redis.incrby('counter', 2) { |r| r.should == 3 }
|
93
|
+
redis.incrby('counter', 3) { |r| r.should == 6 }
|
94
|
+
|
95
|
+
redis.ping { done }
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
it "can DECR a key" do
|
100
|
+
connect do |redis|
|
101
|
+
redis.del('counter')
|
102
|
+
redis.incr('counter') { |r| r.should == 1 }
|
103
|
+
redis.incr('counter') { |r| r.should == 2 }
|
104
|
+
redis.incr('counter') { |r| r.should == 3 }
|
105
|
+
redis.decr('counter') { |r| r.should == 2 }
|
106
|
+
redis.decrby('counter', 2) { |r| r.should == 0; done }
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
it "can RANDOMKEY" do
|
111
|
+
connect do |redis|
|
112
|
+
redis.set('foo', 'bar')
|
113
|
+
redis.randomkey { |r| r.should_not == nil; done }
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
it "can RENAME a key" do
|
118
|
+
connect do |redis|
|
119
|
+
redis.del 'foo'
|
120
|
+
redis.del 'bar'
|
121
|
+
redis.set('foo', 'hi')
|
122
|
+
redis.rename 'foo', 'bar'
|
123
|
+
redis.get('bar') { |r| r.should == 'hi' ; done }
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
it "can RENAMENX a key" do
|
128
|
+
connect do |redis|
|
129
|
+
redis.del 'foo'
|
130
|
+
redis.del 'bar'
|
131
|
+
redis.set('foo', 'hi')
|
132
|
+
redis.set('bar', 'ohai')
|
133
|
+
redis.renamenx 'foo', 'bar'
|
134
|
+
redis.get('bar') { |r| r.should == 'ohai' ; done }
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
it "can get DBSIZE of the database" do
|
139
|
+
connect do |redis|
|
140
|
+
redis.set('foo1', 'bar')
|
141
|
+
redis.set('foo2', 'baz')
|
142
|
+
redis.set('foo3', 'bat')
|
143
|
+
redis.dbsize do |r|
|
144
|
+
r.should == 3
|
145
|
+
done
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
it "can EXPIRE a key" do
|
151
|
+
connect do |redis|
|
152
|
+
timeout(3)
|
153
|
+
|
154
|
+
redis.set('foo', 'bar')
|
155
|
+
redis.expire 'foo', 1
|
156
|
+
redis.get('foo') { |r| r.should == "bar" }
|
157
|
+
EventMachine.add_timer(2) do
|
158
|
+
redis.get('foo') { |r| r.should == nil }
|
159
|
+
redis.ping { done }
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
|
165
|
+
it "can check if a key EXISTS" do
|
166
|
+
connect do |redis|
|
167
|
+
redis.set 'foo', 'nik'
|
168
|
+
redis.exists('foo') { |r| r.should == 1 }
|
169
|
+
redis.del 'foo'
|
170
|
+
redis.exists('foo') { |r| r.should == 0 ; done }
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
it "can list KEYS" do
|
175
|
+
connect do |redis|
|
176
|
+
redis.keys("f*") { |keys| keys.each { |key| @r.del key } }
|
177
|
+
redis.set('f', 'nik')
|
178
|
+
redis.set('fo', 'nak')
|
179
|
+
redis.set('foo', 'qux')
|
180
|
+
redis.keys("f*") { |r| r.sort.should == ['f', 'fo', 'foo'].sort }
|
181
|
+
|
182
|
+
redis.ping { done }
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
it "returns a random key (RANDOMKEY)" do
|
187
|
+
connect do |redis|
|
188
|
+
redis.set("foo", "bar")
|
189
|
+
redis.randomkey do |r|
|
190
|
+
redis.exists(r) do |e|
|
191
|
+
e.should == 1
|
192
|
+
done
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
it "should be able to check the TYPE of a key" do
|
199
|
+
connect do |redis|
|
200
|
+
redis.set('foo', 'nik')
|
201
|
+
redis.type('foo') { |r| r.should == "string" }
|
202
|
+
redis.del 'foo'
|
203
|
+
redis.type('foo') { |r| r.should == "none" ; done }
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
it "pushes to the head of a list (LPUSH)" do
|
208
|
+
connect do |redis|
|
209
|
+
redis.lpush "list", 'hello'
|
210
|
+
redis.lpush "list", 42
|
211
|
+
redis.type('list') { |r| r.should == "list" }
|
212
|
+
redis.llen('list') { |r| r.should == 2 }
|
213
|
+
redis.lpop('list') { |r| r.should == '42'; done }
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
it "pushes to the tail of a list (RPUSH)" do
|
218
|
+
connect do |redis|
|
219
|
+
redis.rpush "list", 'hello'
|
220
|
+
redis.type('list') { |r| r.should == "list" }
|
221
|
+
redis.llen('list') { |r| r.should == 1 ; done }
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
it "pops the tail of a list (RPOP)" do
|
226
|
+
connect do |redis|
|
227
|
+
redis.rpush "list", 'hello'
|
228
|
+
redis.rpush"list", 'goodbye'
|
229
|
+
redis.type('list') { |r| r.should == "list" }
|
230
|
+
redis.llen('list') { |r| r.should == 2 }
|
231
|
+
redis.rpop('list') { |r| r.should == 'goodbye'; done }
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
it "pop the head of a list (LPOP)" do
|
236
|
+
connect do |redis|
|
237
|
+
redis.rpush "list", 'hello'
|
238
|
+
redis.rpush "list", 'goodbye'
|
239
|
+
redis.type('list') { |r| r.should == "list" }
|
240
|
+
redis.llen('list') { |r| r.should == 2 }
|
241
|
+
redis.lpop('list') { |r| r.should == 'hello'; done }
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
it "gets the length of a list (LLEN)" do
|
246
|
+
connect do |redis|
|
247
|
+
redis.rpush "list", 'hello'
|
248
|
+
redis.rpush "list", 'goodbye'
|
249
|
+
redis.type('list') { |r| r.should == "list" }
|
250
|
+
redis.llen('list') { |r| r.should == 2 ; done }
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
it "gets a range of values from a list (LRANGE)" do
|
255
|
+
connect do |redis|
|
256
|
+
redis.rpush "list", 'hello'
|
257
|
+
redis.rpush "list", 'goodbye'
|
258
|
+
redis.rpush "list", '1'
|
259
|
+
redis.rpush "list", '2'
|
260
|
+
redis.rpush "list", '3'
|
261
|
+
redis.type('list') { |r| r.should == "list" }
|
262
|
+
redis.llen('list') { |r| r.should == 5 }
|
263
|
+
redis.lrange('list', 2, -1) { |r| r.should == ['1', '2', '3']; done }
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
it "trims a list (LTRIM)" do
|
268
|
+
connect do |redis|
|
269
|
+
redis.rpush "list", 'hello'
|
270
|
+
redis.rpush "list", 'goodbye'
|
271
|
+
redis.rpush "list", '1'
|
272
|
+
redis.rpush "list", '2'
|
273
|
+
redis.rpush "list", '3'
|
274
|
+
redis.type('list') { |r| r.should == "list" }
|
275
|
+
redis.llen('list') { |r| r.should == 5 }
|
276
|
+
redis.ltrim 'list', 0, 1
|
277
|
+
redis.llen('list') { |r| r.should == 2 }
|
278
|
+
redis.lrange('list', 0, -1) { |r| r.should == ['hello', 'goodbye']; done }
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
it "gets a value by indexing into a list (LINDEX)" do
|
283
|
+
connect do |redis|
|
284
|
+
redis.rpush "list", 'hello'
|
285
|
+
redis.rpush "list", 'goodbye'
|
286
|
+
redis.type('list') { |r| r.should == "list" }
|
287
|
+
redis.llen('list') { |r| r.should == 2 }
|
288
|
+
redis.lindex('list', 1) { |r| r.should == 'goodbye'; done }
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
it "sets a value by indexing into a list (LSET)" do
|
293
|
+
connect do |redis|
|
294
|
+
redis.rpush "list", 'hello'
|
295
|
+
redis.rpush "list", 'hello'
|
296
|
+
redis.type('list') { |r| r.should == "list" }
|
297
|
+
redis.llen('list') { |r| r.should == 2 }
|
298
|
+
redis.lset('list', 1, 'goodbye') { |r| r.should == 'OK' }
|
299
|
+
redis.lindex('list', 1) { |r| r.should == 'goodbye'; done }
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
it "removes values from a list (LREM)" do
|
304
|
+
connect do |redis|
|
305
|
+
redis.rpush "list", 'hello'
|
306
|
+
redis.rpush "list", 'goodbye'
|
307
|
+
redis.type('list') { |r| r.should == "list" }
|
308
|
+
redis.llen('list') { |r| r.should == 2 }
|
309
|
+
redis.lrem('list', 1, 'hello') { |r| r.should == 1 }
|
310
|
+
redis.lrange('list', 0, -1) { |r| r.should == ['goodbye']; done }
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
it "pops values from a list and push them onto a temp list(RPOPLPUSH)" do
|
315
|
+
connect do |redis|
|
316
|
+
redis.rpush "list", 'one'
|
317
|
+
redis.rpush "list", 'two'
|
318
|
+
redis.rpush "list", 'three'
|
319
|
+
redis.type('list') { |r| r.should == "list" }
|
320
|
+
redis.llen('list') { |r| r.should == 3 }
|
321
|
+
redis.lrange('list', 0, -1) { |r| r.should == ['one', 'two', 'three'] }
|
322
|
+
redis.lrange('tmp', 0, -1) { |r| r.should == [] }
|
323
|
+
redis.rpoplpush('list', 'tmp') { |r| r.should == 'three' }
|
324
|
+
redis.lrange('tmp', 0, -1) { |r| r.should == ['three'] }
|
325
|
+
redis.rpoplpush('list', 'tmp') { |r| r.should == 'two' }
|
326
|
+
redis.lrange('tmp', 0, -1) { |r| r.should == ['two', 'three'] }
|
327
|
+
redis.rpoplpush('list', 'tmp') { |r| r.should == 'one' }
|
328
|
+
redis.lrange('tmp', 0, -1) { |r| r.should == ['one', 'two', 'three']; done }
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
332
|
+
it "adds members to a set (SADD)" do
|
333
|
+
connect do |redis|
|
334
|
+
redis.sadd "set", 'key1'
|
335
|
+
redis.sadd "set", 'key2'
|
336
|
+
redis.type('set') { |r| r.should == "set" }
|
337
|
+
redis.scard('set') { |r| r.should == 2 }
|
338
|
+
redis.smembers('set') { |r| r.sort.should == ['key1', 'key2'].sort; done }
|
339
|
+
end
|
340
|
+
end
|
341
|
+
|
342
|
+
it "deletes members to a set (SREM)" do
|
343
|
+
connect do |redis|
|
344
|
+
redis.sadd "set", 'key1'
|
345
|
+
redis.sadd "set", 'key2'
|
346
|
+
redis.type('set') { |r| r.should == "set" }
|
347
|
+
redis.scard('set') { |r| r.should == 2 }
|
348
|
+
redis.smembers('set') { |r| r.sort.should == ['key1', 'key2'].sort }
|
349
|
+
redis.srem('set', 'key1')
|
350
|
+
redis.scard('set') { |r| r.should == 1 }
|
351
|
+
redis.smembers('set') { |r| r.should == ['key2']; done }
|
352
|
+
end
|
353
|
+
end
|
354
|
+
|
355
|
+
it "returns and remove random key from set (SPOP)" do
|
356
|
+
connect do |redis|
|
357
|
+
redis.sadd "set_pop", "key1"
|
358
|
+
redis.sadd "set_pop", "key2"
|
359
|
+
redis.spop("set_pop") { |r| r.should_not == nil }
|
360
|
+
redis.scard("set_pop") { |r| r.should == 1; done }
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
364
|
+
it "returns random key without delete the key from a set (SRANDMEMBER)" do
|
365
|
+
connect do |redis|
|
366
|
+
redis.sadd "set_srandmember", "key1"
|
367
|
+
redis.sadd "set_srandmember", "key2"
|
368
|
+
redis.srandmember("set_srandmember") { |r| r.should_not == nil }
|
369
|
+
redis.scard("set_srandmember") { |r| r.should == 2; done }
|
370
|
+
end
|
371
|
+
end
|
372
|
+
|
373
|
+
it "counts the members of a set (SCARD)" do
|
374
|
+
connect do |redis|
|
375
|
+
redis.sadd "set", 'key1'
|
376
|
+
redis.sadd "set", 'key2'
|
377
|
+
redis.type('set') { |r| r.should == "set" }
|
378
|
+
redis.scard('set') { |r| r.should == 2; done }
|
379
|
+
end
|
380
|
+
end
|
381
|
+
|
382
|
+
it "tests for set membership (SISMEMBER)" do
|
383
|
+
connect do |redis|
|
384
|
+
redis.sadd "set", 'key1'
|
385
|
+
redis.sadd "set", 'key2'
|
386
|
+
redis.type('set') { |r| r.should == "set" }
|
387
|
+
redis.scard('set') { |r| r.should == 2 }
|
388
|
+
redis.sismember('set', 'key1') { |r| r.should == 1 }
|
389
|
+
redis.sismember('set', 'key2') { |r| r.should == 1 }
|
390
|
+
redis.sismember('set', 'notthere') { |r| r.should == 0; done }
|
391
|
+
end
|
392
|
+
end
|
393
|
+
|
394
|
+
it "intersects sets (SINTER)" do
|
395
|
+
connect do |redis|
|
396
|
+
redis.sadd "set", 'key1'
|
397
|
+
redis.sadd "set", 'key2'
|
398
|
+
redis.sadd "set2", 'key2'
|
399
|
+
redis.sinter('set', 'set2') { |r| r.should == ['key2']; done }
|
400
|
+
end
|
401
|
+
end
|
402
|
+
|
403
|
+
it "intersects set and stores the results in a key (SINTERSTORE)" do
|
404
|
+
connect do |redis|
|
405
|
+
redis.sadd "set", 'key1'
|
406
|
+
redis.sadd "set", 'key2'
|
407
|
+
redis.sadd "set2", 'key2'
|
408
|
+
redis.sinterstore('newone', 'set', 'set2') { |r| r.should == 1 }
|
409
|
+
redis.smembers('newone') { |r| r.should == ['key2']; done }
|
410
|
+
end
|
411
|
+
end
|
412
|
+
|
413
|
+
it "performs set unions (SUNION)" do
|
414
|
+
connect do |redis|
|
415
|
+
redis.sadd "set", 'key1'
|
416
|
+
redis.sadd "set", 'key2'
|
417
|
+
redis.sadd "set2", 'key2'
|
418
|
+
redis.sadd "set2", 'key3'
|
419
|
+
redis.sunion('set', 'set2') { |r| r.sort.should == ['key1','key2','key3'].sort; done }
|
420
|
+
end
|
421
|
+
end
|
422
|
+
|
423
|
+
it "performs a set union and store the results in a key (SUNIONSTORE)" do
|
424
|
+
connect do |redis|
|
425
|
+
redis.sadd "set", 'key1'
|
426
|
+
redis.sadd "set", 'key2'
|
427
|
+
redis.sadd "set2", 'key2'
|
428
|
+
redis.sadd "set2", 'key3'
|
429
|
+
redis.sunionstore('newone', 'set', 'set2') { |r| r.should == 3 }
|
430
|
+
redis.smembers('newone') { |r| r.sort.should == ['key1','key2','key3'].sort; done }
|
431
|
+
end
|
432
|
+
end
|
433
|
+
|
434
|
+
it "takes a set difference (SDIFF)" do
|
435
|
+
connect do |redis|
|
436
|
+
redis.sadd "set", 'a'
|
437
|
+
redis.sadd "set", 'b'
|
438
|
+
redis.sadd "set2", 'b'
|
439
|
+
redis.sadd "set2", 'c'
|
440
|
+
redis.sdiff('set', 'set2') { |r| r.should == ['a']; done }
|
441
|
+
end
|
442
|
+
end
|
443
|
+
|
444
|
+
it "takes set difference and store the results in a key (SDIFFSTORE)" do
|
445
|
+
connect do |redis|
|
446
|
+
redis.sadd "set", 'a'
|
447
|
+
redis.sadd "set", 'b'
|
448
|
+
redis.sadd "set2", 'b'
|
449
|
+
redis.sadd "set2", 'c'
|
450
|
+
redis.sdiffstore('newone', 'set', 'set2')
|
451
|
+
redis.smembers('newone') { |r| r.should == ['a']; done }
|
452
|
+
end
|
453
|
+
end
|
454
|
+
|
455
|
+
it "moves elements from one set to another (SMOVE)" do
|
456
|
+
connect do |redis|
|
457
|
+
redis.sadd 'set1', 'a'
|
458
|
+
redis.sadd 'set1', 'b'
|
459
|
+
redis.sadd 'set2', 'x'
|
460
|
+
redis.smove('set1', 'set2', 'a') { |r| r.should == 1 }
|
461
|
+
redis.sismember('set2', 'a') { |r| r.should == 1 }
|
462
|
+
redis.del('set1') { done }
|
463
|
+
end
|
464
|
+
end
|
465
|
+
|
466
|
+
it "counts the members of a zset" do
|
467
|
+
connect do |redis|
|
468
|
+
redis.sadd "set", 'key1'
|
469
|
+
redis.sadd "set", 'key2'
|
470
|
+
redis.zadd 'zset', 1, 'set'
|
471
|
+
redis.zcount('zset') { |r| r.should == 1 }
|
472
|
+
redis.del('set')
|
473
|
+
redis.del('zset') { done }
|
474
|
+
end
|
475
|
+
end
|
476
|
+
|
477
|
+
it "adds members to a zset" do
|
478
|
+
connect do |redis|
|
479
|
+
redis.sadd "set", 'key1'
|
480
|
+
redis.sadd "set", 'key2'
|
481
|
+
redis.zadd 'zset', 1, 'set'
|
482
|
+
redis.zrange('zset', 0, 1) { |r| r.should == ['set'] }
|
483
|
+
redis.zcount('zset') { |r| r.should == 1 }
|
484
|
+
redis.del('set')
|
485
|
+
redis.del('zset') { done }
|
486
|
+
end
|
487
|
+
end
|
488
|
+
|
489
|
+
it "deletes members to a zset" do
|
490
|
+
connect do |redis|
|
491
|
+
redis.sadd "set", 'key1'
|
492
|
+
redis.sadd "set", 'key2'
|
493
|
+
redis.type?('set') { |r| r.should == "set" }
|
494
|
+
redis.sadd "set2", 'key3'
|
495
|
+
redis.sadd "set2", 'key4'
|
496
|
+
redis.type?('set2') { |r| r.should == "set" }
|
497
|
+
redis.zadd 'zset', 1, 'set'
|
498
|
+
redis.zcount('zset') { |r| r.should == 1 }
|
499
|
+
redis.zadd 'zset', 2, 'set2'
|
500
|
+
redis.zcount('zset') { |r| r.should == 2 }
|
501
|
+
redis.zset_delete 'zset', 'set'
|
502
|
+
redis.zcount('zset') { |r| r.should == 1 }
|
503
|
+
redis.del('set')
|
504
|
+
redis.del('set2')
|
505
|
+
redis.del('zset') { done }
|
506
|
+
end
|
507
|
+
end
|
508
|
+
|
509
|
+
it "gets a range of values from a zset" do
|
510
|
+
connect do |redis|
|
511
|
+
redis.sadd "set", 'key1'
|
512
|
+
redis.sadd "set", 'key2'
|
513
|
+
redis.sadd "set2", 'key3'
|
514
|
+
redis.sadd "set2", 'key4'
|
515
|
+
redis.sadd "set3", 'key1'
|
516
|
+
redis.type?('set') { |r| r.should == 'set' }
|
517
|
+
redis.type?('set2') { |r| r.should == 'set' }
|
518
|
+
redis.type?('set3') { |r| r.should == 'set' }
|
519
|
+
redis.zadd 'zset', 1, 'set'
|
520
|
+
redis.zadd 'zset', 2, 'set2'
|
521
|
+
redis.zadd 'zset', 3, 'set3'
|
522
|
+
redis.zcount('zset') { |r| r.should == 3 }
|
523
|
+
redis.zrange('zset', 0, 3) { |r| r.should == ['set', 'set2', 'set3'] }
|
524
|
+
redis.del('set')
|
525
|
+
redis.del('set2')
|
526
|
+
redis.del('set3')
|
527
|
+
redis.del('zset') { done }
|
528
|
+
end
|
529
|
+
end
|
530
|
+
|
531
|
+
it "gets a reverse range of values from a zset" do
|
532
|
+
connect do |redis|
|
533
|
+
redis.sadd "set", 'key1'
|
534
|
+
redis.sadd "set", 'key2'
|
535
|
+
redis.sadd "set2", 'key3'
|
536
|
+
redis.sadd "set2", 'key4'
|
537
|
+
redis.sadd "set3", 'key1'
|
538
|
+
redis.type?('set') { |r| r.should == 'set' }
|
539
|
+
redis.type?('set2') { |r| r.should == 'set' }
|
540
|
+
redis.type?('set3') { |r| r.should == 'set' }
|
541
|
+
redis.zadd 'zset', 1, 'set'
|
542
|
+
redis.zadd 'zset', 2, 'set2'
|
543
|
+
redis.zadd 'zset', 3, 'set3'
|
544
|
+
redis.zcount('zset') { |r| r.should == 3 }
|
545
|
+
redis.zrevrange('zset', 0, 3) { |r| r.should == ['set3', 'set2', 'set'] }
|
546
|
+
redis.del('set')
|
547
|
+
redis.del('set2')
|
548
|
+
redis.del('set3')
|
549
|
+
redis.del('zset') { done }
|
550
|
+
end
|
551
|
+
end
|
552
|
+
|
553
|
+
it "gets a range by score of values from a zset" do
|
554
|
+
connect do |redis|
|
555
|
+
redis.sadd "set", 'key1'
|
556
|
+
redis.sadd "set", 'key2'
|
557
|
+
redis.sadd "set2", 'key3'
|
558
|
+
redis.sadd "set2", 'key4'
|
559
|
+
redis.sadd "set3", 'key1'
|
560
|
+
redis.sadd "set4", 'key4'
|
561
|
+
redis.zadd 'zset', 1, 'set'
|
562
|
+
redis.zadd 'zset', 2, 'set2'
|
563
|
+
redis.zadd 'zset', 3, 'set3'
|
564
|
+
redis.zadd 'zset', 4, 'set4'
|
565
|
+
redis.zcount('zset') { |r| r.should == 4 }
|
566
|
+
redis.zrangebyscore('zset', 2, 3) { |r| r.should == ['set2', 'set3'] }
|
567
|
+
redis.del('set')
|
568
|
+
redis.del('set2')
|
569
|
+
redis.del('set3')
|
570
|
+
redis.del('set4')
|
571
|
+
redis.del('zset') { done }
|
572
|
+
end
|
573
|
+
end
|
574
|
+
|
575
|
+
it "gets a score for a specific value in a zset (ZSCORE)" do
|
576
|
+
connect do |redis|
|
577
|
+
redis.zadd "zset", 23, "value"
|
578
|
+
redis.zscore("zset", "value") { |r| r.should == "23" }
|
579
|
+
|
580
|
+
redis.zscore("zset", "value2") { |r| r.should == nil }
|
581
|
+
redis.zscore("unknown_zset", "value") { |r| r.should == nil }
|
582
|
+
|
583
|
+
redis.del("zset") { done }
|
584
|
+
end
|
585
|
+
end
|
586
|
+
|
587
|
+
it "increments a range score of a zset (ZINCRBY)" do
|
588
|
+
connect do |redis|
|
589
|
+
# create a new zset
|
590
|
+
redis.zincrby "hackers", 1965, "Yukihiro Matsumoto"
|
591
|
+
redis.zscore("hackers", "Yukihiro Matsumoto") { |r| r.should == "1965" }
|
592
|
+
|
593
|
+
# add a new element
|
594
|
+
redis.zincrby "hackers", 1912, "Alan Turing"
|
595
|
+
redis.zscore("hackers", "Alan Turing") { |r| r.should == "1912" }
|
596
|
+
|
597
|
+
# update the score
|
598
|
+
redis.zincrby "hackers", 100, "Alan Turing" # yeah, we are making Turing a bit younger
|
599
|
+
redis.zscore("hackers", "Alan Turing") { |r| r.should == "2012" }
|
600
|
+
|
601
|
+
# attempt to update a key that's not a zset
|
602
|
+
redis.set("i_am_not_a_zet", "value")
|
603
|
+
# shouldn't raise error anymore
|
604
|
+
redis.zincrby("i_am_not_a_zet", 23, "element") { |r| r.should == nil }
|
605
|
+
|
606
|
+
redis.del("hackers")
|
607
|
+
redis.del("i_am_not_a_zet") { done }
|
608
|
+
end
|
609
|
+
end
|
610
|
+
|
611
|
+
it "provides info (INFO)" do
|
612
|
+
connect do |redis|
|
613
|
+
redis.info do |r|
|
614
|
+
[:redis_version, :total_connections_received, :connected_clients, :total_commands_processed, :connected_slaves, :uptime_in_seconds, :used_memory, :uptime_in_days].each do |x|
|
615
|
+
r.keys.include?(x).should == true
|
616
|
+
end
|
617
|
+
done
|
618
|
+
end
|
619
|
+
end
|
620
|
+
end
|
621
|
+
|
622
|
+
it "provides commandstats (INFO COMMANDSTATS)" do
|
623
|
+
connect do |redis|
|
624
|
+
redis.info_commandstats do |r|
|
625
|
+
r[:get][:calls].should be_a_kind_of(Integer)
|
626
|
+
r[:get][:usec].should be_a_kind_of(Integer)
|
627
|
+
r[:get][:usec_per_call].should be_a_kind_of(Float)
|
628
|
+
done
|
629
|
+
end
|
630
|
+
end
|
631
|
+
end
|
632
|
+
|
633
|
+
it "flushes the database (FLUSHDB)" do
|
634
|
+
connect do |redis|
|
635
|
+
redis.set('key1', 'keyone')
|
636
|
+
redis.set('key2', 'keytwo')
|
637
|
+
redis.keys('*') { |r| r.sort.should == ['key1', 'key2'].sort }
|
638
|
+
redis.flushdb
|
639
|
+
redis.keys('*') { |r| r.should == []; done }
|
640
|
+
end
|
641
|
+
end
|
642
|
+
|
643
|
+
it "SELECTs database" do
|
644
|
+
connect do |redis|
|
645
|
+
redis.set("foo", "bar") do |set_response|
|
646
|
+
redis.select("10") do |select_response|
|
647
|
+
redis.get("foo") do |get_response|
|
648
|
+
get_response.should == nil; done
|
649
|
+
end
|
650
|
+
end
|
651
|
+
end
|
652
|
+
end
|
653
|
+
end
|
654
|
+
|
655
|
+
it "SELECTs database without a callback" do
|
656
|
+
connect do |redis|
|
657
|
+
redis.select("9")
|
658
|
+
redis.incr("foo") do |response|
|
659
|
+
response.should == 1
|
660
|
+
done
|
661
|
+
end
|
662
|
+
end
|
663
|
+
end
|
664
|
+
|
665
|
+
it "provides the last save time (LASTSAVE)" do
|
666
|
+
connect do |redis|
|
667
|
+
redis.lastsave do |savetime|
|
668
|
+
Time.at(savetime).class.should == Time
|
669
|
+
Time.at(savetime).should <= Time.now
|
670
|
+
done
|
671
|
+
end
|
672
|
+
end
|
673
|
+
end
|
674
|
+
|
675
|
+
it "can MGET keys" do
|
676
|
+
connect do |redis|
|
677
|
+
redis.set('foo', 1000)
|
678
|
+
redis.set('bar', 2000)
|
679
|
+
redis.mget('foo', 'bar') { |r| r.should == ['1000', '2000'] }
|
680
|
+
redis.mget('foo', 'bar', 'baz') { |r| r.should == ['1000', '2000', nil] }
|
681
|
+
redis.ping { done }
|
682
|
+
end
|
683
|
+
end
|
684
|
+
|
685
|
+
it "can MSET values" do
|
686
|
+
connect do |redis|
|
687
|
+
redis.mset "key1", "value1", "key2", "value2"
|
688
|
+
redis.get('key1') { |r| r.should == "value1" }
|
689
|
+
redis.get('key2') { |r| r.should == "value2"; done }
|
690
|
+
end
|
691
|
+
end
|
692
|
+
|
693
|
+
it "can MSETNX values" do
|
694
|
+
connect do |redis|
|
695
|
+
redis.msetnx "keynx1", "valuenx1", "keynx2", "valuenx2"
|
696
|
+
redis.mget('keynx1', 'keynx2') { |r| r.should == ["valuenx1", "valuenx2"] }
|
697
|
+
|
698
|
+
redis.set("keynx1", "value1")
|
699
|
+
redis.set("keynx2", "value2")
|
700
|
+
redis.msetnx "keynx1", "valuenx1", "keynx2", "valuenx2"
|
701
|
+
redis.mget('keynx1', 'keynx2') { |r| r.should == ["value1", "value2"]; done }
|
702
|
+
end
|
703
|
+
end
|
704
|
+
|
705
|
+
it "can BGSAVE" do
|
706
|
+
connect do |redis|
|
707
|
+
redis.bgsave do |r|
|
708
|
+
['OK', 'Background saving started'].include?(r).should == true
|
709
|
+
done
|
710
|
+
end
|
711
|
+
end
|
712
|
+
end
|
713
|
+
|
714
|
+
it "can ECHO" do
|
715
|
+
connect do |redis|
|
716
|
+
redis.echo("message in a bottle\n") { |r| r.should == "message in a bottle\n"; done }
|
717
|
+
end
|
718
|
+
end
|
719
|
+
|
720
|
+
it "runs MULTI without a block" do
|
721
|
+
connect do |redis|
|
722
|
+
redis.multi
|
723
|
+
redis.get("key1") { |r| r.should == "QUEUED" }
|
724
|
+
redis.discard { done }
|
725
|
+
end
|
726
|
+
end
|
727
|
+
|
728
|
+
it "runs MULTI/EXEC" do
|
729
|
+
connect do |redis|
|
730
|
+
redis.multi
|
731
|
+
redis.set "key1", "value1"
|
732
|
+
redis.exec
|
733
|
+
|
734
|
+
redis.get("key1") { |r| r.should == "value1" }
|
735
|
+
|
736
|
+
begin
|
737
|
+
redis.multi
|
738
|
+
redis.set "key2", "value2"
|
739
|
+
raise "Some error"
|
740
|
+
redis.set "key3", "value3"
|
741
|
+
redis.exec
|
742
|
+
rescue
|
743
|
+
redis.discard
|
744
|
+
end
|
745
|
+
|
746
|
+
redis.get("key2") { |r| r.should == nil }
|
747
|
+
redis.get("key3") { |r| r.should == nil; done}
|
748
|
+
end
|
749
|
+
end
|
750
|
+
|
751
|
+
it "sets and get hash values" do
|
752
|
+
connect do |redis|
|
753
|
+
redis.hset("rush", "signals", "1982") { |r| r.should == 1 }
|
754
|
+
redis.hexists("rush", "signals") { |r| r.should == 1 }
|
755
|
+
redis.hget("rush", "signals") { |r| r.should == "1982"; done }
|
756
|
+
end
|
757
|
+
end
|
758
|
+
|
759
|
+
it "deletes hash values" do
|
760
|
+
connect do |redis|
|
761
|
+
redis.hset("rush", "YYZ", "1981")
|
762
|
+
redis.hdel("rush", "YYZ") { |r| r.should == 1 }
|
763
|
+
redis.hexists("rush", "YYZ") { |r| r.should == 0; done }
|
764
|
+
end
|
765
|
+
end
|
766
|
+
end
|
767
|
+
|
768
|
+
describe EventMachine::Hiredis, "with hash values" do
|
769
|
+
def set(&blk)
|
770
|
+
connect do |redis|
|
771
|
+
redis.hset("rush", "permanent waves", "1980")
|
772
|
+
redis.hset("rush", "moving pictures", "1981")
|
773
|
+
redis.hset("rush", "signals", "1982")
|
774
|
+
blk.call(redis)
|
775
|
+
end
|
776
|
+
end
|
777
|
+
|
778
|
+
it "gets the length of the hash" do
|
779
|
+
set do |redis|
|
780
|
+
redis.hlen("rush") { |r| r.should == 3 }
|
781
|
+
redis.hlen("yyz") { |r| r.should == 0; done }
|
782
|
+
end
|
783
|
+
end
|
784
|
+
|
785
|
+
it "gets the keys and values of the hash" do
|
786
|
+
set do |redis|
|
787
|
+
redis.hkeys("rush") { |r| r.should == ["permanent waves", "moving pictures", "signals"] }
|
788
|
+
redis.hvals("rush") { |r| r.should == %w[1980 1981 1982] }
|
789
|
+
redis.hvals("yyz") { |r| r.should == []; done }
|
790
|
+
end
|
791
|
+
end
|
792
|
+
|
793
|
+
it "returns all hash values" do
|
794
|
+
set do |redis|
|
795
|
+
redis.hgetall("rush") do |r|
|
796
|
+
r.should == [
|
797
|
+
"permanent waves", "1980",
|
798
|
+
"moving pictures", "1981",
|
799
|
+
"signals" , "1982"
|
800
|
+
]
|
801
|
+
end
|
802
|
+
redis.hgetall("yyz") { |r| r.should == []; done }
|
803
|
+
end
|
804
|
+
end
|
805
|
+
end
|
806
|
+
|
807
|
+
describe EventMachine::Hiredis, "with nested multi-bulk response" do
|
808
|
+
def set(&blk)
|
809
|
+
connect do |redis|
|
810
|
+
redis.set 'user:one:id', 'id-one'
|
811
|
+
redis.set 'user:two:id', 'id-two'
|
812
|
+
redis.sadd "user:one:interests", "first-interest"
|
813
|
+
redis.sadd "user:one:interests", "second-interest"
|
814
|
+
redis.sadd "user:two:interests", "third-interest"
|
815
|
+
blk.call(redis)
|
816
|
+
end
|
817
|
+
end
|
818
|
+
|
819
|
+
it "returns array of arrays" do
|
820
|
+
set do |redis|
|
821
|
+
redis.multi
|
822
|
+
redis.smembers "user:one:interests"
|
823
|
+
redis.smembers "user:two:interests"
|
824
|
+
redis.exec do |interests_one, interests_two|
|
825
|
+
interests_one.sort.should == ["first-interest", "second-interest"]
|
826
|
+
interests_two.should == ['third-interest']
|
827
|
+
end
|
828
|
+
redis.mget("user:one:id", "user:two:id") do |user_ids|
|
829
|
+
user_ids.should == ['id-one', 'id-two']
|
830
|
+
done
|
831
|
+
end
|
832
|
+
end
|
833
|
+
end
|
834
|
+
end
|
835
|
+
|
836
|
+
describe EventMachine::Hiredis, "monitor" do
|
837
|
+
it "returns monitored commands" do
|
838
|
+
connect do |redis|
|
839
|
+
# 1. Create 2nd connection to send traffic to monitor
|
840
|
+
redis2 = EventMachine::Hiredis.connect("redis://localhost:6379/")
|
841
|
+
redis2.callback {
|
842
|
+
# 2. Monitor after command has connected
|
843
|
+
redis.monitor do |reply|
|
844
|
+
reply.should == "OK"
|
845
|
+
|
846
|
+
# 3. Command which should show up in monitor output
|
847
|
+
redis2.get('foo')
|
848
|
+
end
|
849
|
+
}
|
850
|
+
|
851
|
+
redis.on(:monitor) do |line|
|
852
|
+
line.should =~ /foo/
|
853
|
+
done
|
854
|
+
end
|
855
|
+
end
|
856
|
+
end
|
857
|
+
end
|
858
|
+
|
859
|
+
describe EventMachine::Hiredis, "sorting" do
|
860
|
+
context "with some simple sorting data" do
|
861
|
+
def set(&blk)
|
862
|
+
connect do |redis|
|
863
|
+
redis.set('dog_1', 'louie')
|
864
|
+
redis.rpush 'Dogs', 1
|
865
|
+
redis.set('dog_2', 'lucy')
|
866
|
+
redis.rpush 'Dogs', 2
|
867
|
+
redis.set('dog_3', 'max')
|
868
|
+
redis.rpush 'Dogs', 3
|
869
|
+
redis.set('dog_4', 'taj')
|
870
|
+
redis.rpush 'Dogs', 4
|
871
|
+
blk.call(redis)
|
872
|
+
end
|
873
|
+
end
|
874
|
+
|
875
|
+
it "sorts with a limit" do
|
876
|
+
set do |redis|
|
877
|
+
redis.sort('Dogs', "GET", 'dog_*', "LIMIT", "0", "1") do |r|
|
878
|
+
r.should == ['louie']
|
879
|
+
done
|
880
|
+
end
|
881
|
+
end
|
882
|
+
end
|
883
|
+
|
884
|
+
it "sorts with a limit and order" do
|
885
|
+
set do |redis|
|
886
|
+
redis.sort('Dogs', "GET", 'dog_*', "LIMIT", "0", "1", "desc", "alpha") do |r|
|
887
|
+
r.should == ['taj']
|
888
|
+
done
|
889
|
+
end
|
890
|
+
end
|
891
|
+
end
|
892
|
+
end
|
893
|
+
|
894
|
+
context "with more complex sorting data" do
|
895
|
+
def set(&blk)
|
896
|
+
connect do |redis|
|
897
|
+
redis.set('dog:1:name', 'louie')
|
898
|
+
redis.set('dog:1:breed', 'mutt')
|
899
|
+
redis.rpush 'dogs', 1
|
900
|
+
redis.set('dog:2:name', 'lucy')
|
901
|
+
redis.set('dog:2:breed', 'poodle')
|
902
|
+
redis.rpush 'dogs', 2
|
903
|
+
redis.set('dog:3:name', 'max')
|
904
|
+
redis.set('dog:3:breed', 'hound')
|
905
|
+
redis.rpush 'dogs', 3
|
906
|
+
redis.set('dog:4:name', 'taj')
|
907
|
+
redis.set('dog:4:breed', 'terrier')
|
908
|
+
redis.rpush 'dogs', 4
|
909
|
+
blk.call(redis)
|
910
|
+
end
|
911
|
+
end
|
912
|
+
|
913
|
+
it "handles multiple GETs" do
|
914
|
+
set do |redis|
|
915
|
+
redis.sort('dogs', 'GET', 'dog:*:name', 'GET', 'dog:*:breed', 'LIMIT', '0', '1') do |r|
|
916
|
+
r.should == ['louie', 'mutt']
|
917
|
+
done
|
918
|
+
end
|
919
|
+
end
|
920
|
+
end
|
921
|
+
|
922
|
+
it "handles multiple GETs with an order" do
|
923
|
+
set do |redis|
|
924
|
+
redis.sort('dogs', 'GET', 'dog:*:name', 'GET', 'dog:*:breed', 'LIMIT', '0', '1', 'desc', 'alpha') do |r|
|
925
|
+
r.should == ['taj', 'terrier']
|
926
|
+
done
|
927
|
+
end
|
928
|
+
end
|
929
|
+
end
|
930
|
+
end
|
931
|
+
end
|