xref: /redis-3.2.3/tests/unit/pubsub.tcl (revision 25791550)
1start_server {tags {"pubsub"}} {
2    proc __consume_subscribe_messages {client type channels} {
3        set numsub -1
4        set counts {}
5
6        for {set i [llength $channels]} {$i > 0} {incr i -1} {
7            set msg [$client read]
8            assert_equal $type [lindex $msg 0]
9
10            # when receiving subscribe messages the channels names
11            # are ordered. when receiving unsubscribe messages
12            # they are unordered
13            set idx [lsearch -exact $channels [lindex $msg 1]]
14            if {[string match "*unsubscribe" $type]} {
15                assert {$idx >= 0}
16            } else {
17                assert {$idx == 0}
18            }
19            set channels [lreplace $channels $idx $idx]
20
21            # aggregate the subscription count to return to the caller
22            lappend counts [lindex $msg 2]
23        }
24
25        # we should have received messages for channels
26        assert {[llength $channels] == 0}
27        return $counts
28    }
29
30    proc subscribe {client channels} {
31        $client subscribe {*}$channels
32        __consume_subscribe_messages $client subscribe $channels
33    }
34
35    proc unsubscribe {client {channels {}}} {
36        $client unsubscribe {*}$channels
37        __consume_subscribe_messages $client unsubscribe $channels
38    }
39
40    proc psubscribe {client channels} {
41        $client psubscribe {*}$channels
42        __consume_subscribe_messages $client psubscribe $channels
43    }
44
45    proc punsubscribe {client {channels {}}} {
46        $client punsubscribe {*}$channels
47        __consume_subscribe_messages $client punsubscribe $channels
48    }
49
50    test "Pub/Sub PING" {
51        set rd1 [redis_deferring_client]
52        subscribe $rd1 somechannel
53        # While subscribed to non-zero channels PING works in Pub/Sub mode.
54        $rd1 ping
55        $rd1 ping "foo"
56        set reply1 [$rd1 read]
57        set reply2 [$rd1 read]
58        unsubscribe $rd1 somechannel
59        # Now we are unsubscribed, PING should just return PONG.
60        $rd1 ping
61        set reply3 [$rd1 read]
62        $rd1 close
63        list $reply1 $reply2 $reply3
64    } {{pong {}} {pong foo} PONG}
65
66    test "PUBLISH/SUBSCRIBE basics" {
67        set rd1 [redis_deferring_client]
68
69        # subscribe to two channels
70        assert_equal {1 2} [subscribe $rd1 {chan1 chan2}]
71        assert_equal 1 [r publish chan1 hello]
72        assert_equal 1 [r publish chan2 world]
73        assert_equal {message chan1 hello} [$rd1 read]
74        assert_equal {message chan2 world} [$rd1 read]
75
76        # unsubscribe from one of the channels
77        unsubscribe $rd1 {chan1}
78        assert_equal 0 [r publish chan1 hello]
79        assert_equal 1 [r publish chan2 world]
80        assert_equal {message chan2 world} [$rd1 read]
81
82        # unsubscribe from the remaining channel
83        unsubscribe $rd1 {chan2}
84        assert_equal 0 [r publish chan1 hello]
85        assert_equal 0 [r publish chan2 world]
86
87        # clean up clients
88        $rd1 close
89    }
90
91    test "PUBLISH/SUBSCRIBE with two clients" {
92        set rd1 [redis_deferring_client]
93        set rd2 [redis_deferring_client]
94
95        assert_equal {1} [subscribe $rd1 {chan1}]
96        assert_equal {1} [subscribe $rd2 {chan1}]
97        assert_equal 2 [r publish chan1 hello]
98        assert_equal {message chan1 hello} [$rd1 read]
99        assert_equal {message chan1 hello} [$rd2 read]
100
101        # clean up clients
102        $rd1 close
103        $rd2 close
104    }
105
106    test "PUBLISH/SUBSCRIBE after UNSUBSCRIBE without arguments" {
107        set rd1 [redis_deferring_client]
108        assert_equal {1 2 3} [subscribe $rd1 {chan1 chan2 chan3}]
109        unsubscribe $rd1
110        assert_equal 0 [r publish chan1 hello]
111        assert_equal 0 [r publish chan2 hello]
112        assert_equal 0 [r publish chan3 hello]
113
114        # clean up clients
115        $rd1 close
116    }
117
118    test "SUBSCRIBE to one channel more than once" {
119        set rd1 [redis_deferring_client]
120        assert_equal {1 1 1} [subscribe $rd1 {chan1 chan1 chan1}]
121        assert_equal 1 [r publish chan1 hello]
122        assert_equal {message chan1 hello} [$rd1 read]
123
124        # clean up clients
125        $rd1 close
126    }
127
128    test "UNSUBSCRIBE from non-subscribed channels" {
129        set rd1 [redis_deferring_client]
130        assert_equal {0 0 0} [unsubscribe $rd1 {foo bar quux}]
131
132        # clean up clients
133        $rd1 close
134    }
135
136    test "PUBLISH/PSUBSCRIBE basics" {
137        set rd1 [redis_deferring_client]
138
139        # subscribe to two patterns
140        assert_equal {1 2} [psubscribe $rd1 {foo.* bar.*}]
141        assert_equal 1 [r publish foo.1 hello]
142        assert_equal 1 [r publish bar.1 hello]
143        assert_equal 0 [r publish foo1 hello]
144        assert_equal 0 [r publish barfoo.1 hello]
145        assert_equal 0 [r publish qux.1 hello]
146        assert_equal {pmessage foo.* foo.1 hello} [$rd1 read]
147        assert_equal {pmessage bar.* bar.1 hello} [$rd1 read]
148
149        # unsubscribe from one of the patterns
150        assert_equal {1} [punsubscribe $rd1 {foo.*}]
151        assert_equal 0 [r publish foo.1 hello]
152        assert_equal 1 [r publish bar.1 hello]
153        assert_equal {pmessage bar.* bar.1 hello} [$rd1 read]
154
155        # unsubscribe from the remaining pattern
156        assert_equal {0} [punsubscribe $rd1 {bar.*}]
157        assert_equal 0 [r publish foo.1 hello]
158        assert_equal 0 [r publish bar.1 hello]
159
160        # clean up clients
161        $rd1 close
162    }
163
164    test "PUBLISH/PSUBSCRIBE with two clients" {
165        set rd1 [redis_deferring_client]
166        set rd2 [redis_deferring_client]
167
168        assert_equal {1} [psubscribe $rd1 {chan.*}]
169        assert_equal {1} [psubscribe $rd2 {chan.*}]
170        assert_equal 2 [r publish chan.foo hello]
171        assert_equal {pmessage chan.* chan.foo hello} [$rd1 read]
172        assert_equal {pmessage chan.* chan.foo hello} [$rd2 read]
173
174        # clean up clients
175        $rd1 close
176        $rd2 close
177    }
178
179    test "PUBLISH/PSUBSCRIBE after PUNSUBSCRIBE without arguments" {
180        set rd1 [redis_deferring_client]
181        assert_equal {1 2 3} [psubscribe $rd1 {chan1.* chan2.* chan3.*}]
182        punsubscribe $rd1
183        assert_equal 0 [r publish chan1.hi hello]
184        assert_equal 0 [r publish chan2.hi hello]
185        assert_equal 0 [r publish chan3.hi hello]
186
187        # clean up clients
188        $rd1 close
189    }
190
191    test "PUNSUBSCRIBE from non-subscribed channels" {
192        set rd1 [redis_deferring_client]
193        assert_equal {0 0 0} [punsubscribe $rd1 {foo.* bar.* quux.*}]
194
195        # clean up clients
196        $rd1 close
197    }
198
199    test "NUMSUB returns numbers, not strings (#1561)" {
200        r pubsub numsub abc def
201    } {abc 0 def 0}
202
203    test "Mix SUBSCRIBE and PSUBSCRIBE" {
204        set rd1 [redis_deferring_client]
205        assert_equal {1} [subscribe $rd1 {foo.bar}]
206        assert_equal {2} [psubscribe $rd1 {foo.*}]
207
208        assert_equal 2 [r publish foo.bar hello]
209        assert_equal {message foo.bar hello} [$rd1 read]
210        assert_equal {pmessage foo.* foo.bar hello} [$rd1 read]
211
212        # clean up clients
213        $rd1 close
214    }
215
216    test "PUNSUBSCRIBE and UNSUBSCRIBE should always reply" {
217        # Make sure we are not subscribed to any channel at all.
218        r punsubscribe
219        r unsubscribe
220        # Now check if the commands still reply correctly.
221        set reply1 [r punsubscribe]
222        set reply2 [r unsubscribe]
223        concat $reply1 $reply2
224    } {punsubscribe {} 0 unsubscribe {} 0}
225
226    ### Keyspace events notification tests
227
228    test "Keyspace notifications: we receive keyspace notifications" {
229        r config set notify-keyspace-events KA
230        set rd1 [redis_deferring_client]
231        assert_equal {1} [psubscribe $rd1 *]
232        r set foo bar
233        assert_equal {pmessage * __keyspace@9__:foo set} [$rd1 read]
234        $rd1 close
235    }
236
237    test "Keyspace notifications: we receive keyevent notifications" {
238        r config set notify-keyspace-events EA
239        set rd1 [redis_deferring_client]
240        assert_equal {1} [psubscribe $rd1 *]
241        r set foo bar
242        assert_equal {pmessage * __keyevent@9__:set foo} [$rd1 read]
243        $rd1 close
244    }
245
246    test "Keyspace notifications: we can receive both kind of events" {
247        r config set notify-keyspace-events KEA
248        set rd1 [redis_deferring_client]
249        assert_equal {1} [psubscribe $rd1 *]
250        r set foo bar
251        assert_equal {pmessage * __keyspace@9__:foo set} [$rd1 read]
252        assert_equal {pmessage * __keyevent@9__:set foo} [$rd1 read]
253        $rd1 close
254    }
255
256    test "Keyspace notifications: we are able to mask events" {
257        r config set notify-keyspace-events KEl
258        r del mylist
259        set rd1 [redis_deferring_client]
260        assert_equal {1} [psubscribe $rd1 *]
261        r set foo bar
262        r lpush mylist a
263        # No notification for set, because only list commands are enabled.
264        assert_equal {pmessage * __keyspace@9__:mylist lpush} [$rd1 read]
265        assert_equal {pmessage * __keyevent@9__:lpush mylist} [$rd1 read]
266        $rd1 close
267    }
268
269    test "Keyspace notifications: general events test" {
270        r config set notify-keyspace-events KEg
271        set rd1 [redis_deferring_client]
272        assert_equal {1} [psubscribe $rd1 *]
273        r set foo bar
274        r expire foo 1
275        r del foo
276        assert_equal {pmessage * __keyspace@9__:foo expire} [$rd1 read]
277        assert_equal {pmessage * __keyevent@9__:expire foo} [$rd1 read]
278        assert_equal {pmessage * __keyspace@9__:foo del} [$rd1 read]
279        assert_equal {pmessage * __keyevent@9__:del foo} [$rd1 read]
280        $rd1 close
281    }
282
283    test "Keyspace notifications: list events test" {
284        r config set notify-keyspace-events KEl
285        r del mylist
286        set rd1 [redis_deferring_client]
287        assert_equal {1} [psubscribe $rd1 *]
288        r lpush mylist a
289        r rpush mylist a
290        r rpop mylist
291        assert_equal {pmessage * __keyspace@9__:mylist lpush} [$rd1 read]
292        assert_equal {pmessage * __keyevent@9__:lpush mylist} [$rd1 read]
293        assert_equal {pmessage * __keyspace@9__:mylist rpush} [$rd1 read]
294        assert_equal {pmessage * __keyevent@9__:rpush mylist} [$rd1 read]
295        assert_equal {pmessage * __keyspace@9__:mylist rpop} [$rd1 read]
296        assert_equal {pmessage * __keyevent@9__:rpop mylist} [$rd1 read]
297        $rd1 close
298    }
299
300    test "Keyspace notifications: set events test" {
301        r config set notify-keyspace-events Ks
302        r del myset
303        set rd1 [redis_deferring_client]
304        assert_equal {1} [psubscribe $rd1 *]
305        r sadd myset a b c d
306        r srem myset x
307        r sadd myset x y z
308        r srem myset x
309        assert_equal {pmessage * __keyspace@9__:myset sadd} [$rd1 read]
310        assert_equal {pmessage * __keyspace@9__:myset sadd} [$rd1 read]
311        assert_equal {pmessage * __keyspace@9__:myset srem} [$rd1 read]
312        $rd1 close
313    }
314
315    test "Keyspace notifications: zset events test" {
316        r config set notify-keyspace-events Kz
317        r del myzset
318        set rd1 [redis_deferring_client]
319        assert_equal {1} [psubscribe $rd1 *]
320        r zadd myzset 1 a 2 b
321        r zrem myzset x
322        r zadd myzset 3 x 4 y 5 z
323        r zrem myzset x
324        assert_equal {pmessage * __keyspace@9__:myzset zadd} [$rd1 read]
325        assert_equal {pmessage * __keyspace@9__:myzset zadd} [$rd1 read]
326        assert_equal {pmessage * __keyspace@9__:myzset zrem} [$rd1 read]
327        $rd1 close
328    }
329
330    test "Keyspace notifications: hash events test" {
331        r config set notify-keyspace-events Kh
332        r del myhash
333        set rd1 [redis_deferring_client]
334        assert_equal {1} [psubscribe $rd1 *]
335        r hmset myhash yes 1 no 0
336        r hincrby myhash yes 10
337        assert_equal {pmessage * __keyspace@9__:myhash hset} [$rd1 read]
338        assert_equal {pmessage * __keyspace@9__:myhash hincrby} [$rd1 read]
339        $rd1 close
340    }
341
342    test "Keyspace notifications: expired events (triggered expire)" {
343        r config set notify-keyspace-events Ex
344        r del foo
345        set rd1 [redis_deferring_client]
346        assert_equal {1} [psubscribe $rd1 *]
347        r psetex foo 100 1
348        wait_for_condition 50 100 {
349            [r exists foo] == 0
350        } else {
351            fail "Key does not expire?!"
352        }
353        assert_equal {pmessage * __keyevent@9__:expired foo} [$rd1 read]
354        $rd1 close
355    }
356
357    test "Keyspace notifications: expired events (background expire)" {
358        r config set notify-keyspace-events Ex
359        r del foo
360        set rd1 [redis_deferring_client]
361        assert_equal {1} [psubscribe $rd1 *]
362        r psetex foo 100 1
363        assert_equal {pmessage * __keyevent@9__:expired foo} [$rd1 read]
364        $rd1 close
365    }
366
367    test "Keyspace notifications: evicted events" {
368        r config set notify-keyspace-events Ee
369        r config set maxmemory-policy allkeys-lru
370        r flushdb
371        set rd1 [redis_deferring_client]
372        assert_equal {1} [psubscribe $rd1 *]
373        r set foo bar
374        r config set maxmemory 1
375        assert_equal {pmessage * __keyevent@9__:evicted foo} [$rd1 read]
376        r config set maxmemory 0
377        $rd1 close
378    }
379
380    test "Keyspace notifications: test CONFIG GET/SET of event flags" {
381        r config set notify-keyspace-events gKE
382        assert_equal {gKE} [lindex [r config get notify-keyspace-events] 1]
383        r config set notify-keyspace-events {$lshzxeKE}
384        assert_equal {$lshzxeKE} [lindex [r config get notify-keyspace-events] 1]
385        r config set notify-keyspace-events KA
386        assert_equal {AK} [lindex [r config get notify-keyspace-events] 1]
387        r config set notify-keyspace-events EA
388        assert_equal {AE} [lindex [r config get notify-keyspace-events] 1]
389    }
390}
391