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