start_server {tags {"pubsub"}} { proc __consume_subscribe_messages {client type channels} { set numsub -1 set counts {} for {set i [llength $channels]} {$i > 0} {incr i -1} { set msg [$client read] assert_equal $type [lindex $msg 0] # when receiving subscribe messages the channels names # are ordered. when receiving unsubscribe messages # they are unordered set idx [lsearch -exact $channels [lindex $msg 1]] if {[string match "*unsubscribe" $type]} { assert {$idx >= 0} } else { assert {$idx == 0} } set channels [lreplace $channels $idx $idx] # aggregate the subscription count to return to the caller lappend counts [lindex $msg 2] } # we should have received messages for channels assert {[llength $channels] == 0} return $counts } proc subscribe {client channels} { $client subscribe {*}$channels __consume_subscribe_messages $client subscribe $channels } proc unsubscribe {client {channels {}}} { $client unsubscribe {*}$channels __consume_subscribe_messages $client unsubscribe $channels } proc psubscribe {client channels} { $client psubscribe {*}$channels __consume_subscribe_messages $client psubscribe $channels } proc punsubscribe {client {channels {}}} { $client punsubscribe {*}$channels __consume_subscribe_messages $client punsubscribe $channels } test "PUBLISH/SUBSCRIBE basics" { set rd1 [redis_deferring_client] # subscribe to two channels assert_equal {1 2} [subscribe $rd1 {chan1 chan2}] assert_equal 1 [r publish chan1 hello] assert_equal 1 [r publish chan2 world] assert_equal {message chan1 hello} [$rd1 read] assert_equal {message chan2 world} [$rd1 read] # unsubscribe from one of the channels unsubscribe $rd1 {chan1} assert_equal 0 [r publish chan1 hello] assert_equal 1 [r publish chan2 world] assert_equal {message chan2 world} [$rd1 read] # unsubscribe from the remaining channel unsubscribe $rd1 {chan2} assert_equal 0 [r publish chan1 hello] assert_equal 0 [r publish chan2 world] # clean up clients $rd1 close } test "PUBLISH/SUBSCRIBE with two clients" { set rd1 [redis_deferring_client] set rd2 [redis_deferring_client] assert_equal {1} [subscribe $rd1 {chan1}] assert_equal {1} [subscribe $rd2 {chan1}] assert_equal 2 [r publish chan1 hello] assert_equal {message chan1 hello} [$rd1 read] assert_equal {message chan1 hello} [$rd2 read] # clean up clients $rd1 close $rd2 close } test "PUBLISH/SUBSCRIBE after UNSUBSCRIBE without arguments" { set rd1 [redis_deferring_client] assert_equal {1 2 3} [subscribe $rd1 {chan1 chan2 chan3}] unsubscribe $rd1 assert_equal 0 [r publish chan1 hello] assert_equal 0 [r publish chan2 hello] assert_equal 0 [r publish chan3 hello] # clean up clients $rd1 close } test "SUBSCRIBE to one channel more than once" { set rd1 [redis_deferring_client] assert_equal {1 1 1} [subscribe $rd1 {chan1 chan1 chan1}] assert_equal 1 [r publish chan1 hello] assert_equal {message chan1 hello} [$rd1 read] # clean up clients $rd1 close } test "UNSUBSCRIBE from non-subscribed channels" { set rd1 [redis_deferring_client] assert_equal {0 0 0} [unsubscribe $rd1 {foo bar quux}] # clean up clients $rd1 close } test "PUBLISH/PSUBSCRIBE basics" { set rd1 [redis_deferring_client] # subscribe to two patterns assert_equal {1 2} [psubscribe $rd1 {foo.* bar.*}] assert_equal 1 [r publish foo.1 hello] assert_equal 1 [r publish bar.1 hello] assert_equal 0 [r publish foo1 hello] assert_equal 0 [r publish barfoo.1 hello] assert_equal 0 [r publish qux.1 hello] assert_equal {pmessage foo.* foo.1 hello} [$rd1 read] assert_equal {pmessage bar.* bar.1 hello} [$rd1 read] # unsubscribe from one of the patterns assert_equal {1} [punsubscribe $rd1 {foo.*}] assert_equal 0 [r publish foo.1 hello] assert_equal 1 [r publish bar.1 hello] assert_equal {pmessage bar.* bar.1 hello} [$rd1 read] # unsubscribe from the remaining pattern assert_equal {0} [punsubscribe $rd1 {bar.*}] assert_equal 0 [r publish foo.1 hello] assert_equal 0 [r publish bar.1 hello] # clean up clients $rd1 close } test "PUBLISH/PSUBSCRIBE with two clients" { set rd1 [redis_deferring_client] set rd2 [redis_deferring_client] assert_equal {1} [psubscribe $rd1 {chan.*}] assert_equal {1} [psubscribe $rd2 {chan.*}] assert_equal 2 [r publish chan.foo hello] assert_equal {pmessage chan.* chan.foo hello} [$rd1 read] assert_equal {pmessage chan.* chan.foo hello} [$rd2 read] # clean up clients $rd1 close $rd2 close } test "PUBLISH/PSUBSCRIBE after PUNSUBSCRIBE without arguments" { set rd1 [redis_deferring_client] assert_equal {1 2 3} [psubscribe $rd1 {chan1.* chan2.* chan3.*}] punsubscribe $rd1 assert_equal 0 [r publish chan1.hi hello] assert_equal 0 [r publish chan2.hi hello] assert_equal 0 [r publish chan3.hi hello] # clean up clients $rd1 close } test "PUNSUBSCRIBE from non-subscribed channels" { set rd1 [redis_deferring_client] assert_equal {0 0 0} [punsubscribe $rd1 {foo.* bar.* quux.*}] # clean up clients $rd1 close } test "Mix SUBSCRIBE and PSUBSCRIBE" { set rd1 [redis_deferring_client] assert_equal {1} [subscribe $rd1 {foo.bar}] assert_equal {2} [psubscribe $rd1 {foo.*}] assert_equal 2 [r publish foo.bar hello] assert_equal {message foo.bar hello} [$rd1 read] assert_equal {pmessage foo.* foo.bar hello} [$rd1 read] # clean up clients $rd1 close } }