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