xref: /redis-3.2.3/tests/unit/pubsub.tcl (revision d04afd62)
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 "PUBLISH/SUBSCRIBE basics" {
51        set rd1 [redis_deferring_client]
52
53        # subscribe to two channels
54        assert_equal {1 2} [subscribe $rd1 {chan1 chan2}]
55        assert_equal 1 [r publish chan1 hello]
56        assert_equal 1 [r publish chan2 world]
57        assert_equal {message chan1 hello} [$rd1 read]
58        assert_equal {message chan2 world} [$rd1 read]
59
60        # unsubscribe from one of the channels
61        unsubscribe $rd1 {chan1}
62        assert_equal 0 [r publish chan1 hello]
63        assert_equal 1 [r publish chan2 world]
64        assert_equal {message chan2 world} [$rd1 read]
65
66        # unsubscribe from the remaining channel
67        unsubscribe $rd1 {chan2}
68        assert_equal 0 [r publish chan1 hello]
69        assert_equal 0 [r publish chan2 world]
70
71        # clean up clients
72        $rd1 close
73    }
74
75    test "PUBLISH/SUBSCRIBE with two clients" {
76        set rd1 [redis_deferring_client]
77        set rd2 [redis_deferring_client]
78
79        assert_equal {1} [subscribe $rd1 {chan1}]
80        assert_equal {1} [subscribe $rd2 {chan1}]
81        assert_equal 2 [r publish chan1 hello]
82        assert_equal {message chan1 hello} [$rd1 read]
83        assert_equal {message chan1 hello} [$rd2 read]
84
85        # clean up clients
86        $rd1 close
87        $rd2 close
88    }
89
90    test "PUBLISH/SUBSCRIBE after UNSUBSCRIBE without arguments" {
91        set rd1 [redis_deferring_client]
92        assert_equal {1 2 3} [subscribe $rd1 {chan1 chan2 chan3}]
93        unsubscribe $rd1
94        assert_equal 0 [r publish chan1 hello]
95        assert_equal 0 [r publish chan2 hello]
96        assert_equal 0 [r publish chan3 hello]
97
98        # clean up clients
99        $rd1 close
100    }
101
102    test "SUBSCRIBE to one channel more than once" {
103        set rd1 [redis_deferring_client]
104        assert_equal {1 1 1} [subscribe $rd1 {chan1 chan1 chan1}]
105        assert_equal 1 [r publish chan1 hello]
106        assert_equal {message chan1 hello} [$rd1 read]
107
108        # clean up clients
109        $rd1 close
110    }
111
112    test "UNSUBSCRIBE from non-subscribed channels" {
113        set rd1 [redis_deferring_client]
114        assert_equal {0 0 0} [unsubscribe $rd1 {foo bar quux}]
115
116        # clean up clients
117        $rd1 close
118    }
119
120    test "PUBLISH/PSUBSCRIBE basics" {
121        set rd1 [redis_deferring_client]
122
123        # subscribe to two patterns
124        assert_equal {1 2} [psubscribe $rd1 {foo.* bar.*}]
125        assert_equal 1 [r publish foo.1 hello]
126        assert_equal 1 [r publish bar.1 hello]
127        assert_equal 0 [r publish foo1 hello]
128        assert_equal 0 [r publish barfoo.1 hello]
129        assert_equal 0 [r publish qux.1 hello]
130        assert_equal {pmessage foo.* foo.1 hello} [$rd1 read]
131        assert_equal {pmessage bar.* bar.1 hello} [$rd1 read]
132
133        # unsubscribe from one of the patterns
134        assert_equal {1} [punsubscribe $rd1 {foo.*}]
135        assert_equal 0 [r publish foo.1 hello]
136        assert_equal 1 [r publish bar.1 hello]
137        assert_equal {pmessage bar.* bar.1 hello} [$rd1 read]
138
139        # unsubscribe from the remaining pattern
140        assert_equal {0} [punsubscribe $rd1 {bar.*}]
141        assert_equal 0 [r publish foo.1 hello]
142        assert_equal 0 [r publish bar.1 hello]
143
144        # clean up clients
145        $rd1 close
146    }
147
148    test "PUBLISH/PSUBSCRIBE with two clients" {
149        set rd1 [redis_deferring_client]
150        set rd2 [redis_deferring_client]
151
152        assert_equal {1} [psubscribe $rd1 {chan.*}]
153        assert_equal {1} [psubscribe $rd2 {chan.*}]
154        assert_equal 2 [r publish chan.foo hello]
155        assert_equal {pmessage chan.* chan.foo hello} [$rd1 read]
156        assert_equal {pmessage chan.* chan.foo hello} [$rd2 read]
157
158        # clean up clients
159        $rd1 close
160        $rd2 close
161    }
162
163    test "PUBLISH/PSUBSCRIBE after PUNSUBSCRIBE without arguments" {
164        set rd1 [redis_deferring_client]
165        assert_equal {1 2 3} [psubscribe $rd1 {chan1.* chan2.* chan3.*}]
166        punsubscribe $rd1
167        assert_equal 0 [r publish chan1.hi hello]
168        assert_equal 0 [r publish chan2.hi hello]
169        assert_equal 0 [r publish chan3.hi hello]
170
171        # clean up clients
172        $rd1 close
173    }
174
175    test "PUNSUBSCRIBE from non-subscribed channels" {
176        set rd1 [redis_deferring_client]
177        assert_equal {0 0 0} [punsubscribe $rd1 {foo.* bar.* quux.*}]
178
179        # clean up clients
180        $rd1 close
181    }
182
183    test "Mix SUBSCRIBE and PSUBSCRIBE" {
184        set rd1 [redis_deferring_client]
185        assert_equal {1} [subscribe $rd1 {foo.bar}]
186        assert_equal {2} [psubscribe $rd1 {foo.*}]
187
188        assert_equal 2 [r publish foo.bar hello]
189        assert_equal {message foo.bar hello} [$rd1 read]
190        assert_equal {pmessage foo.* foo.bar hello} [$rd1 read]
191
192        # clean up clients
193        $rd1 close
194    }
195
196    test "PUNSUBSCRIBE and UNSUBSCRIBE should always reply" {
197        # Make sure we are not subscribed to any channel at all.
198        r punsubscribe
199        r unsubscribe
200        # Now check if the commands still reply correctly.
201        set reply1 [r punsubscribe]
202        set reply2 [r unsubscribe]
203        concat $reply1 $reply2
204    } {punsubscribe {} 0 unsubscribe {} 0}
205
206    ### Keyspace events notification tests
207
208    test "Keyspace notifications: we receive keyspace notifications" {
209        r config set notify-keyspace-events KA
210        set rd1 [redis_deferring_client]
211        assert_equal {1} [psubscribe $rd1 *]
212        r set foo bar
213        assert_equal {pmessage * __keyspace@9__:foo set} [$rd1 read]
214        $rd1 close
215    }
216
217    test "Keyspace notifications: we receive keyevent notifications" {
218        r config set notify-keyspace-events EA
219        set rd1 [redis_deferring_client]
220        assert_equal {1} [psubscribe $rd1 *]
221        r set foo bar
222        assert_equal {pmessage * __keyevent@9__:set foo} [$rd1 read]
223        $rd1 close
224    }
225
226    test "Keyspace notifications: we can receive both kind of events" {
227        r config set notify-keyspace-events KEA
228        set rd1 [redis_deferring_client]
229        assert_equal {1} [psubscribe $rd1 *]
230        r set foo bar
231        assert_equal {pmessage * __keyspace@9__:foo set} [$rd1 read]
232        assert_equal {pmessage * __keyevent@9__:set foo} [$rd1 read]
233        $rd1 close
234    }
235
236    test "Keyspace notifications: we are able to mask events" {
237        r config set notify-keyspace-events KEl
238        r del mylist
239        set rd1 [redis_deferring_client]
240        assert_equal {1} [psubscribe $rd1 *]
241        r set foo bar
242        r lpush mylist a
243        # No notification for set, because only list commands are enabled.
244        assert_equal {pmessage * __keyspace@9__:mylist lpush} [$rd1 read]
245        assert_equal {pmessage * __keyevent@9__:lpush mylist} [$rd1 read]
246        $rd1 close
247    }
248
249    test "Keyspace notifications: general events test" {
250        r config set notify-keyspace-events KEg
251        set rd1 [redis_deferring_client]
252        assert_equal {1} [psubscribe $rd1 *]
253        r set foo bar
254        r expire foo 1
255        r del foo
256        assert_equal {pmessage * __keyspace@9__:foo expire} [$rd1 read]
257        assert_equal {pmessage * __keyevent@9__:expire foo} [$rd1 read]
258        assert_equal {pmessage * __keyspace@9__:foo del} [$rd1 read]
259        assert_equal {pmessage * __keyevent@9__:del foo} [$rd1 read]
260        $rd1 close
261    }
262
263    test "Keyspace notifications: list events test" {
264        r config set notify-keyspace-events KEl
265        r del mylist
266        set rd1 [redis_deferring_client]
267        assert_equal {1} [psubscribe $rd1 *]
268        r lpush mylist a
269        r rpush mylist a
270        r rpop mylist
271        assert_equal {pmessage * __keyspace@9__:mylist lpush} [$rd1 read]
272        assert_equal {pmessage * __keyevent@9__:lpush mylist} [$rd1 read]
273        assert_equal {pmessage * __keyspace@9__:mylist rpush} [$rd1 read]
274        assert_equal {pmessage * __keyevent@9__:rpush mylist} [$rd1 read]
275        assert_equal {pmessage * __keyspace@9__:mylist rpop} [$rd1 read]
276        assert_equal {pmessage * __keyevent@9__:rpop mylist} [$rd1 read]
277        $rd1 close
278    }
279
280    test "Keyspace notifications: set events test" {
281        r config set notify-keyspace-events Ks
282        r del myset
283        set rd1 [redis_deferring_client]
284        assert_equal {1} [psubscribe $rd1 *]
285        r sadd myset a b c d
286        r srem myset x
287        r sadd myset x y z
288        r srem myset x
289        assert_equal {pmessage * __keyspace@9__:myset sadd} [$rd1 read]
290        assert_equal {pmessage * __keyspace@9__:myset sadd} [$rd1 read]
291        assert_equal {pmessage * __keyspace@9__:myset srem} [$rd1 read]
292        $rd1 close
293    }
294
295    test "Keyspace notifications: zset events test" {
296        r config set notify-keyspace-events Kz
297        r del myzset
298        set rd1 [redis_deferring_client]
299        assert_equal {1} [psubscribe $rd1 *]
300        r zadd myzset 1 a 2 b
301        r zrem myzset x
302        r zadd myzset 3 x 4 y 5 z
303        r zrem myzset x
304        assert_equal {pmessage * __keyspace@9__:myzset zadd} [$rd1 read]
305        assert_equal {pmessage * __keyspace@9__:myzset zadd} [$rd1 read]
306        assert_equal {pmessage * __keyspace@9__:myzset zrem} [$rd1 read]
307        $rd1 close
308    }
309
310    test "Keyspace notifications: hash events test" {
311        r config set notify-keyspace-events Kh
312        r del myhash
313        set rd1 [redis_deferring_client]
314        assert_equal {1} [psubscribe $rd1 *]
315        r hmset myhash yes 1 no 0
316        r hincrby myhash yes 10
317        assert_equal {pmessage * __keyspace@9__:myhash hset} [$rd1 read]
318        assert_equal {pmessage * __keyspace@9__:myhash hincrby} [$rd1 read]
319        $rd1 close
320    }
321
322    test "Keyspace notifications: expired events (triggered expire)" {
323        r config set notify-keyspace-events Ex
324        r del foo
325        set rd1 [redis_deferring_client]
326        assert_equal {1} [psubscribe $rd1 *]
327        r psetex foo 100 1
328        wait_for_condition 50 100 {
329            [r exists foo] == 0
330        } else {
331            fail "Key does not expire?!"
332        }
333        assert_equal {pmessage * __keyevent@9__:expired foo} [$rd1 read]
334        $rd1 close
335    }
336
337    test "Keyspace notifications: expired events (background expire)" {
338        r config set notify-keyspace-events Ex
339        r del foo
340        set rd1 [redis_deferring_client]
341        assert_equal {1} [psubscribe $rd1 *]
342        r psetex foo 100 1
343        assert_equal {pmessage * __keyevent@9__:expired foo} [$rd1 read]
344        $rd1 close
345    }
346
347    test "Keyspace notifications: evicted events" {
348        r config set notify-keyspace-events Ee
349        r config set maxmemory-policy allkeys-lru
350        r flushdb
351        set rd1 [redis_deferring_client]
352        assert_equal {1} [psubscribe $rd1 *]
353        r set foo bar
354        r config set maxmemory 1
355        assert_equal {pmessage * __keyevent@9__:evicted foo} [$rd1 read]
356        r config set maxmemory 0
357        $rd1 close
358    }
359}
360