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,314 @@
1
+ require 'spec_helper'
2
+
3
+ describe EventMachine::Hiredis::PubsubClient, '(un)subscribe' do
4
+ describe "subscribing" do
5
+ it "should return deferrable which succeeds with subscribe call result" do
6
+ connect do |redis|
7
+ df = redis.pubsub.subscribe("channel") { }
8
+ df.should be_kind_of(EventMachine::DefaultDeferrable)
9
+ df.callback { |subscription_count|
10
+ # Subscribe response from redis - indicates that subscription has
11
+ # succeeded and that the current connection has a single
12
+ # subscription
13
+ subscription_count.should == 1
14
+ done
15
+ }
16
+ end
17
+ end
18
+
19
+ it "should run the passed block when message received" do
20
+ connect do |redis|
21
+ redis.pubsub.subscribe("channel") { |message|
22
+ message.should == 'hello'
23
+ done
24
+ }.callback {
25
+ redis.publish('channel', 'hello')
26
+ }
27
+ end
28
+ end
29
+
30
+ it "should run the passed proc when message received on channel" do
31
+ connect do |redis|
32
+ proc = Proc.new { |message|
33
+ message.should == 'hello'
34
+ done
35
+ }
36
+ redis.pubsub.subscribe("channel", proc).callback {
37
+ redis.publish('channel', 'hello')
38
+ }
39
+ end
40
+ end
41
+ end
42
+
43
+ describe "unsubscribing" do
44
+ it "should allow unsubscribing a single callback without unsubscribing from redis" do
45
+ connect do |redis|
46
+ proc1 = Proc.new { |message| fail }
47
+ proc2 = Proc.new { |message|
48
+ message.should == 'hello'
49
+ done
50
+ }
51
+ redis.pubsub.subscribe("channel", proc1)
52
+ redis.pubsub.subscribe("channel", proc2).callback {
53
+ redis.pubsub.unsubscribe_proc("channel", proc1)
54
+ redis.publish("channel", "hello")
55
+ }
56
+ end
57
+ end
58
+
59
+ it "should unsubscribe from redis on last proc unsubscription" do
60
+ connect do |redis|
61
+ proc = Proc.new { |message| }
62
+ redis.pubsub.subscribe("channel", proc).callback { |subs_count|
63
+ subs_count.should == 1
64
+ redis.pubsub.unsubscribe_proc("channel", proc).callback {
65
+ # Slightly awkward way to check that unsubscribe happened:
66
+ redis.pubsub.subscribe('channel2').callback { |count|
67
+ # If count is 1 this implies that channel unsubscribed
68
+ count.should == 1
69
+ done
70
+ }
71
+ }
72
+ }
73
+ end
74
+ end
75
+
76
+ it "should allow unsubscribing from redis channel, including all callbacks, and return deferrable for redis unsubscribe" do
77
+ connect do |redis|
78
+ # Raw pubsub event
79
+ redis.pubsub.on('message') { |channel, message| fail }
80
+ # Block subscription
81
+ redis.pubsub.subscribe("channel") { |m| fail } # block
82
+ # Proc example
83
+ df = redis.pubsub.subscribe("channel", Proc.new { |m| fail })
84
+
85
+ df.callback {
86
+ redis.pubsub.unsubscribe("channel").callback { |remaining_subs|
87
+ remaining_subs.should == 0
88
+ redis.publish("channel", "hello") {
89
+ done
90
+ }
91
+ }
92
+ }
93
+ end
94
+ end
95
+ end
96
+
97
+ it "should expose raw pubsub events from redis" do
98
+ channel = "channel"
99
+ callback_count = 0
100
+ connect do |redis|
101
+ redis.pubsub.on(:subscribe) { |channel, subscription_count|
102
+ # 2. Get subscribe callback
103
+ callback_count += 1
104
+ channel.should == channel
105
+ subscription_count.should == 1
106
+
107
+ # 3. Publish on channel
108
+ redis.publish(channel, 'foo')
109
+ }
110
+
111
+ redis.pubsub.on(:message) { |channel, message|
112
+ # 4. Get message callback
113
+ callback_count += 1
114
+ channel.should == channel
115
+ message.should == 'foo'
116
+
117
+ callback_count.should == 2
118
+ done
119
+ }
120
+
121
+ # 1. Subscribe to channel
122
+ redis.pubsub.subscribe(channel)
123
+ end
124
+ end
125
+
126
+ it "should resubscribe to all channels on reconnect" do
127
+ callback_count = 0
128
+ connect do |redis|
129
+ # 1. Subscribe to channels
130
+ redis.pubsub.subscribe('channel1') {
131
+ callback_count += 1
132
+ }
133
+ redis.pubsub.subscribe('channel2') {
134
+ callback_count += 1
135
+ EM.next_tick {
136
+ # 4. Success if both messages have been received
137
+ callback_count.should == 2
138
+ done
139
+ }
140
+ }.callback { |subscription_count|
141
+ subscription_count.should == 2
142
+ # 2. Subscriptions complete. Now force disconnect
143
+ redis.pubsub.instance_variable_get(:@connection).close_connection
144
+
145
+ EM.add_timer(0.1) {
146
+ # 3. After giving time to reconnect publish to both channels
147
+ redis.publish('channel1', 'foo')
148
+ redis.publish('channel2', 'bar')
149
+ }
150
+
151
+ }
152
+
153
+ end
154
+ end
155
+ end
156
+
157
+ describe EventMachine::Hiredis::PubsubClient, 'p(un)subscribe' do
158
+ describe "psubscribing" do
159
+ it "should return deferrable which succeeds with psubscribe call result" do
160
+ connect do |redis|
161
+ df = redis.pubsub.psubscribe("channel") { }
162
+ df.should be_kind_of(EventMachine::DefaultDeferrable)
163
+ df.callback { |subscription_count|
164
+ # Subscribe response from redis - indicates that subscription has
165
+ # succeeded and that the current connection has a single
166
+ # subscription
167
+ subscription_count.should == 1
168
+ done
169
+ }
170
+ end
171
+ end
172
+
173
+ it "should run the passed block when message received" do
174
+ connect do |redis|
175
+ redis.pubsub.psubscribe("channel:*") { |channel, message|
176
+ channel.should == 'channel:foo'
177
+ message.should == 'hello'
178
+ done
179
+ }.callback {
180
+ redis.publish('channel:foo', 'hello')
181
+ }
182
+ end
183
+ end
184
+
185
+ it "should run the passed proc when message received on channel" do
186
+ connect do |redis|
187
+ proc = Proc.new { |channel, message|
188
+ channel.should == 'channel:foo'
189
+ message.should == 'hello'
190
+ done
191
+ }
192
+ redis.pubsub.psubscribe("channel:*", proc).callback {
193
+ redis.publish('channel:foo', 'hello')
194
+ }
195
+ end
196
+ end
197
+ end
198
+
199
+ describe "punsubscribing" do
200
+ it "should allow punsubscribing a single callback without punsubscribing from redis" do
201
+ connect do |redis|
202
+ proc1 = Proc.new { |channel, message| fail }
203
+ proc2 = Proc.new { |channel, message|
204
+ channel.should == 'channel:foo'
205
+ message.should == 'hello'
206
+ done
207
+ }
208
+ redis.pubsub.psubscribe("channel:*", proc1)
209
+ redis.pubsub.psubscribe("channel:*", proc2).callback {
210
+ redis.pubsub.punsubscribe_proc("channel:*", proc1)
211
+ redis.publish("channel:foo", "hello")
212
+ }
213
+ end
214
+ end
215
+
216
+ it "should punsubscribe from redis on last proc punsubscription" do
217
+ connect do |redis|
218
+ proc = Proc.new { |message| }
219
+ redis.pubsub.psubscribe("channel:*", proc).callback { |subs_count|
220
+ subs_count.should == 1
221
+ redis.pubsub.punsubscribe_proc("channel:*", proc).callback {
222
+ # Slightly awkward way to check that unsubscribe happened:
223
+ redis.pubsub.psubscribe('channel2').callback { |count|
224
+ # If count is 1 this implies that channel unsubscribed
225
+ count.should == 1
226
+ done
227
+ }
228
+ }
229
+ }
230
+ end
231
+ end
232
+
233
+ it "should allow punsubscribing from redis channel, including all callbacks, and return deferrable for redis punsubscribe" do
234
+ connect do |redis|
235
+ # Raw pubsub event
236
+ redis.pubsub.on('pmessage') { |pattern, channel, message| fail }
237
+ # Block subscription
238
+ redis.pubsub.psubscribe("channel") { |c, m| fail } # block
239
+ # Proc example
240
+ df = redis.pubsub.psubscribe("channel", Proc.new { |c, m| fail })
241
+
242
+ df.callback {
243
+ redis.pubsub.punsubscribe("channel").callback { |remaining_subs|
244
+ remaining_subs.should == 0
245
+ redis.publish("channel", "hello") {
246
+ done
247
+ }
248
+ }
249
+ }
250
+ end
251
+ end
252
+ end
253
+
254
+ it "should expose raw pattern pubsub events from redis" do
255
+ callback_count = 0
256
+ connect do |redis|
257
+ redis.pubsub.on(:psubscribe) { |pattern, subscription_count|
258
+ # 2. Get subscribe callback
259
+ callback_count += 1
260
+ pattern.should == "channel:*"
261
+ subscription_count.should == 1
262
+
263
+ # 3. Publish on channel
264
+ redis.publish('channel:foo', 'foo')
265
+ }
266
+
267
+ redis.pubsub.on(:pmessage) { |pattern, channel, message|
268
+ # 4. Get message callback
269
+ callback_count += 1
270
+ pattern.should == 'channel:*'
271
+ channel.should == 'channel:foo'
272
+ message.should == 'foo'
273
+
274
+ callback_count.should == 2
275
+ done
276
+ }
277
+
278
+ # 1. Subscribe to channel
279
+ redis.pubsub.psubscribe('channel:*')
280
+ end
281
+ end
282
+
283
+ it "should resubscribe to all pattern subscriptions on reconnect" do
284
+ callback_count = 0
285
+ connect do |redis|
286
+ # 1. Subscribe to channels
287
+ redis.pubsub.psubscribe('foo:*') { |channel, message|
288
+ channel.should == 'foo:a'
289
+ message.should == 'hello foo'
290
+ callback_count += 1
291
+ }
292
+ redis.pubsub.psubscribe('bar:*') { |channel, message|
293
+ channel.should == 'bar:b'
294
+ message.should == 'hello bar'
295
+ callback_count += 1
296
+ EM.next_tick {
297
+ # 4. Success if both messages have been received
298
+ callback_count.should == 2
299
+ done
300
+ }
301
+ }.callback { |subscription_count|
302
+ subscription_count.should == 2
303
+ # 2. Subscriptions complete. Now force disconnect
304
+ redis.pubsub.instance_variable_get(:@connection).close_connection
305
+
306
+ EM.add_timer(0.1) {
307
+ # 3. After giving time to reconnect publish to both channels
308
+ redis.publish('foo:a', 'hello foo')
309
+ redis.publish('bar:b', 'hello bar')
310
+ }
311
+ }
312
+ end
313
+ end
314
+ end