]> git.saurik.com Git - redis.git/blobdiff - tests/unit/pubsub.tcl
Make an EXEC test more latency proof.
[redis.git] / tests / unit / pubsub.tcl
index 10af8585647f1baa94cad4d271b13bbe741a1eaa..c8b547b4f1b35984159dca072ddb6424f2539b16 100644 (file)
 start_server {tags {"pubsub"}} {
-    test "PUBLISH when no one is listening" {
-        assert_equal 0 [r publish chan hello]
+    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
     }
 
-    test "SUBSCRIBE basics" {
-        set rd1 [redis_deferring_client]
-        set rd2 [redis_deferring_client]
+    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
+    }
 
-        # subscribe first client to two channels
-        $rd1 subscribe chan1 chan2
-        assert_equal {subscribe chan1 1} [$rd1 read]
-        assert_equal {subscribe chan2 2} [$rd1 read]
+    test "PUBLISH/SUBSCRIBE basics" {
+        set rd1 [redis_deferring_client]
 
-        # publish on both channels
+        # 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]
 
-        # subscribe second client to one channel
-        $rd2 subscribe chan1
-        assert_equal {subscribe chan1 1} [$rd2 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]
 
-        # publish on channel with two subscribers
+        # 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]
 
-        # unsubscribe first client from all channels
-        $rd1 unsubscribe
-        set msg [$rd1 read]
-        assert_equal "unsubscribe" [lindex $msg 0]
-        assert_match "chan*" [lindex $msg 1]
-        assert_match 1 [lindex $msg 2]
-        set msg [$rd1 read]
-        assert_equal "unsubscribe" [lindex $msg 0]
-        assert_match "chan*" [lindex $msg 1]
-        assert_match 0 [lindex $msg 2]
-
-        # publish on channel with only remaining subscriber
+        # 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} [$rd2 read]
+        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
     }
 }
\ No newline at end of file