2
0

pubsub.tcl 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. start_server {tags {"pubsub"}} {
  2. proc __consume_subscribe_messages {client type channels} {
  3. set numsub -1
  4. set counts {}
  5. for {set i [llength $channels]} {$i > 0} {incr i -1} {
  6. set msg [$client read]
  7. assert_equal $type [lindex $msg 0]
  8. # when receiving subscribe messages the channels names
  9. # are ordered. when receiving unsubscribe messages
  10. # they are unordered
  11. set idx [lsearch -exact $channels [lindex $msg 1]]
  12. if {[string match "*unsubscribe" $type]} {
  13. assert {$idx >= 0}
  14. } else {
  15. assert {$idx == 0}
  16. }
  17. set channels [lreplace $channels $idx $idx]
  18. # aggregate the subscription count to return to the caller
  19. lappend counts [lindex $msg 2]
  20. }
  21. # we should have received messages for channels
  22. assert {[llength $channels] == 0}
  23. return $counts
  24. }
  25. proc subscribe {client channels} {
  26. $client subscribe {*}$channels
  27. __consume_subscribe_messages $client subscribe $channels
  28. }
  29. proc unsubscribe {client {channels {}}} {
  30. $client unsubscribe {*}$channels
  31. __consume_subscribe_messages $client unsubscribe $channels
  32. }
  33. proc psubscribe {client channels} {
  34. $client psubscribe {*}$channels
  35. __consume_subscribe_messages $client psubscribe $channels
  36. }
  37. proc punsubscribe {client {channels {}}} {
  38. $client punsubscribe {*}$channels
  39. __consume_subscribe_messages $client punsubscribe $channels
  40. }
  41. test "Pub/Sub PING" {
  42. set rd1 [redis_deferring_client]
  43. subscribe $rd1 somechannel
  44. # While subscribed to non-zero channels PING works in Pub/Sub mode.
  45. $rd1 ping
  46. $rd1 ping "foo"
  47. set reply1 [$rd1 read]
  48. set reply2 [$rd1 read]
  49. unsubscribe $rd1 somechannel
  50. # Now we are unsubscribed, PING should just return PONG.
  51. $rd1 ping
  52. set reply3 [$rd1 read]
  53. $rd1 close
  54. list $reply1 $reply2 $reply3
  55. } {{pong {}} {pong foo} PONG}
  56. test "PUBLISH/SUBSCRIBE basics" {
  57. set rd1 [redis_deferring_client]
  58. # subscribe to two channels
  59. assert_equal {1 2} [subscribe $rd1 {chan1 chan2}]
  60. assert_equal 1 [r publish chan1 hello]
  61. assert_equal 1 [r publish chan2 world]
  62. assert_equal {message chan1 hello} [$rd1 read]
  63. assert_equal {message chan2 world} [$rd1 read]
  64. # unsubscribe from one of the channels
  65. unsubscribe $rd1 {chan1}
  66. assert_equal 0 [r publish chan1 hello]
  67. assert_equal 1 [r publish chan2 world]
  68. assert_equal {message chan2 world} [$rd1 read]
  69. # unsubscribe from the remaining channel
  70. unsubscribe $rd1 {chan2}
  71. assert_equal 0 [r publish chan1 hello]
  72. assert_equal 0 [r publish chan2 world]
  73. # clean up clients
  74. $rd1 close
  75. }
  76. test "PUBLISH/SUBSCRIBE with two clients" {
  77. set rd1 [redis_deferring_client]
  78. set rd2 [redis_deferring_client]
  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. # clean up clients
  85. $rd1 close
  86. $rd2 close
  87. }
  88. test "PUBLISH/SUBSCRIBE after UNSUBSCRIBE without arguments" {
  89. set rd1 [redis_deferring_client]
  90. assert_equal {1 2 3} [subscribe $rd1 {chan1 chan2 chan3}]
  91. unsubscribe $rd1
  92. assert_equal 0 [r publish chan1 hello]
  93. assert_equal 0 [r publish chan2 hello]
  94. assert_equal 0 [r publish chan3 hello]
  95. # clean up clients
  96. $rd1 close
  97. }
  98. test "SUBSCRIBE to one channel more than once" {
  99. set rd1 [redis_deferring_client]
  100. assert_equal {1 1 1} [subscribe $rd1 {chan1 chan1 chan1}]
  101. assert_equal 1 [r publish chan1 hello]
  102. assert_equal {message chan1 hello} [$rd1 read]
  103. # clean up clients
  104. $rd1 close
  105. }
  106. test "UNSUBSCRIBE from non-subscribed channels" {
  107. set rd1 [redis_deferring_client]
  108. assert_equal {0 0 0} [unsubscribe $rd1 {foo bar quux}]
  109. # clean up clients
  110. $rd1 close
  111. }
  112. test "PUBLISH/PSUBSCRIBE basics" {
  113. set rd1 [redis_deferring_client]
  114. # subscribe to two patterns
  115. assert_equal {1 2} [psubscribe $rd1 {foo.* bar.*}]
  116. assert_equal 1 [r publish foo.1 hello]
  117. assert_equal 1 [r publish bar.1 hello]
  118. assert_equal 0 [r publish foo1 hello]
  119. assert_equal 0 [r publish barfoo.1 hello]
  120. assert_equal 0 [r publish qux.1 hello]
  121. assert_equal {pmessage foo.* foo.1 hello} [$rd1 read]
  122. assert_equal {pmessage bar.* bar.1 hello} [$rd1 read]
  123. # unsubscribe from one of the patterns
  124. assert_equal {1} [punsubscribe $rd1 {foo.*}]
  125. assert_equal 0 [r publish foo.1 hello]
  126. assert_equal 1 [r publish bar.1 hello]
  127. assert_equal {pmessage bar.* bar.1 hello} [$rd1 read]
  128. # unsubscribe from the remaining pattern
  129. assert_equal {0} [punsubscribe $rd1 {bar.*}]
  130. assert_equal 0 [r publish foo.1 hello]
  131. assert_equal 0 [r publish bar.1 hello]
  132. # clean up clients
  133. $rd1 close
  134. }
  135. test "PUBLISH/PSUBSCRIBE with two clients" {
  136. set rd1 [redis_deferring_client]
  137. set rd2 [redis_deferring_client]
  138. assert_equal {1} [psubscribe $rd1 {chan.*}]
  139. assert_equal {1} [psubscribe $rd2 {chan.*}]
  140. assert_equal 2 [r publish chan.foo hello]
  141. assert_equal {pmessage chan.* chan.foo hello} [$rd1 read]
  142. assert_equal {pmessage chan.* chan.foo hello} [$rd2 read]
  143. # clean up clients
  144. $rd1 close
  145. $rd2 close
  146. }
  147. test "PUBLISH/PSUBSCRIBE after PUNSUBSCRIBE without arguments" {
  148. set rd1 [redis_deferring_client]
  149. assert_equal {1 2 3} [psubscribe $rd1 {chan1.* chan2.* chan3.*}]
  150. punsubscribe $rd1
  151. assert_equal 0 [r publish chan1.hi hello]
  152. assert_equal 0 [r publish chan2.hi hello]
  153. assert_equal 0 [r publish chan3.hi hello]
  154. # clean up clients
  155. $rd1 close
  156. }
  157. test "PUNSUBSCRIBE from non-subscribed channels" {
  158. set rd1 [redis_deferring_client]
  159. assert_equal {0 0 0} [punsubscribe $rd1 {foo.* bar.* quux.*}]
  160. # clean up clients
  161. $rd1 close
  162. }
  163. test "NUMSUB returns numbers, not strings (#1561)" {
  164. r pubsub numsub abc def
  165. } {abc 0 def 0}
  166. test "Mix SUBSCRIBE and PSUBSCRIBE" {
  167. set rd1 [redis_deferring_client]
  168. assert_equal {1} [subscribe $rd1 {foo.bar}]
  169. assert_equal {2} [psubscribe $rd1 {foo.*}]
  170. assert_equal 2 [r publish foo.bar hello]
  171. assert_equal {message foo.bar hello} [$rd1 read]
  172. assert_equal {pmessage foo.* foo.bar hello} [$rd1 read]
  173. # clean up clients
  174. $rd1 close
  175. }
  176. test "PUNSUBSCRIBE and UNSUBSCRIBE should always reply" {
  177. # Make sure we are not subscribed to any channel at all.
  178. r punsubscribe
  179. r unsubscribe
  180. # Now check if the commands still reply correctly.
  181. set reply1 [r punsubscribe]
  182. set reply2 [r unsubscribe]
  183. concat $reply1 $reply2
  184. } {punsubscribe {} 0 unsubscribe {} 0}
  185. ### Keyspace events notification tests
  186. test "Keyspace notifications: we receive keyspace notifications" {
  187. r config set notify-keyspace-events KA
  188. set rd1 [redis_deferring_client]
  189. assert_equal {1} [psubscribe $rd1 *]
  190. r set foo bar
  191. assert_equal {pmessage * __keyspace@9__:foo set} [$rd1 read]
  192. $rd1 close
  193. }
  194. test "Keyspace notifications: we receive keyevent notifications" {
  195. r config set notify-keyspace-events EA
  196. set rd1 [redis_deferring_client]
  197. assert_equal {1} [psubscribe $rd1 *]
  198. r set foo bar
  199. assert_equal {pmessage * __keyevent@9__:set foo} [$rd1 read]
  200. $rd1 close
  201. }
  202. test "Keyspace notifications: we can receive both kind of events" {
  203. r config set notify-keyspace-events KEA
  204. set rd1 [redis_deferring_client]
  205. assert_equal {1} [psubscribe $rd1 *]
  206. r set foo bar
  207. assert_equal {pmessage * __keyspace@9__:foo set} [$rd1 read]
  208. assert_equal {pmessage * __keyevent@9__:set foo} [$rd1 read]
  209. $rd1 close
  210. }
  211. test "Keyspace notifications: we are able to mask events" {
  212. r config set notify-keyspace-events KEl
  213. r del mylist
  214. set rd1 [redis_deferring_client]
  215. assert_equal {1} [psubscribe $rd1 *]
  216. r set foo bar
  217. r lpush mylist a
  218. # No notification for set, because only list commands are enabled.
  219. assert_equal {pmessage * __keyspace@9__:mylist lpush} [$rd1 read]
  220. assert_equal {pmessage * __keyevent@9__:lpush mylist} [$rd1 read]
  221. $rd1 close
  222. }
  223. test "Keyspace notifications: general events test" {
  224. r config set notify-keyspace-events KEg
  225. set rd1 [redis_deferring_client]
  226. assert_equal {1} [psubscribe $rd1 *]
  227. r set foo bar
  228. r expire foo 1
  229. r del foo
  230. assert_equal {pmessage * __keyspace@9__:foo expire} [$rd1 read]
  231. assert_equal {pmessage * __keyevent@9__:expire foo} [$rd1 read]
  232. assert_equal {pmessage * __keyspace@9__:foo del} [$rd1 read]
  233. assert_equal {pmessage * __keyevent@9__:del foo} [$rd1 read]
  234. $rd1 close
  235. }
  236. test "Keyspace notifications: list events test" {
  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 lpush mylist a
  242. r rpush mylist a
  243. r rpop mylist
  244. assert_equal {pmessage * __keyspace@9__:mylist lpush} [$rd1 read]
  245. assert_equal {pmessage * __keyevent@9__:lpush mylist} [$rd1 read]
  246. assert_equal {pmessage * __keyspace@9__:mylist rpush} [$rd1 read]
  247. assert_equal {pmessage * __keyevent@9__:rpush mylist} [$rd1 read]
  248. assert_equal {pmessage * __keyspace@9__:mylist rpop} [$rd1 read]
  249. assert_equal {pmessage * __keyevent@9__:rpop mylist} [$rd1 read]
  250. $rd1 close
  251. }
  252. test "Keyspace notifications: set events test" {
  253. r config set notify-keyspace-events Ks
  254. r del myset
  255. set rd1 [redis_deferring_client]
  256. assert_equal {1} [psubscribe $rd1 *]
  257. r sadd myset a b c d
  258. r srem myset x
  259. r sadd myset x y z
  260. r srem myset x
  261. assert_equal {pmessage * __keyspace@9__:myset sadd} [$rd1 read]
  262. assert_equal {pmessage * __keyspace@9__:myset sadd} [$rd1 read]
  263. assert_equal {pmessage * __keyspace@9__:myset srem} [$rd1 read]
  264. $rd1 close
  265. }
  266. test "Keyspace notifications: zset events test" {
  267. r config set notify-keyspace-events Kz
  268. r del myzset
  269. set rd1 [redis_deferring_client]
  270. assert_equal {1} [psubscribe $rd1 *]
  271. r zadd myzset 1 a 2 b
  272. r zrem myzset x
  273. r zadd myzset 3 x 4 y 5 z
  274. r zrem myzset x
  275. assert_equal {pmessage * __keyspace@9__:myzset zadd} [$rd1 read]
  276. assert_equal {pmessage * __keyspace@9__:myzset zadd} [$rd1 read]
  277. assert_equal {pmessage * __keyspace@9__:myzset zrem} [$rd1 read]
  278. $rd1 close
  279. }
  280. test "Keyspace notifications: hash events test" {
  281. r config set notify-keyspace-events Kh
  282. r del myhash
  283. set rd1 [redis_deferring_client]
  284. assert_equal {1} [psubscribe $rd1 *]
  285. r hmset myhash yes 1 no 0
  286. r hincrby myhash yes 10
  287. assert_equal {pmessage * __keyspace@9__:myhash hset} [$rd1 read]
  288. assert_equal {pmessage * __keyspace@9__:myhash hincrby} [$rd1 read]
  289. $rd1 close
  290. }
  291. test "Keyspace notifications: expired events (triggered expire)" {
  292. r config set notify-keyspace-events Ex
  293. r del foo
  294. set rd1 [redis_deferring_client]
  295. assert_equal {1} [psubscribe $rd1 *]
  296. r psetex foo 100 1
  297. wait_for_condition 50 100 {
  298. [r exists foo] == 0
  299. } else {
  300. fail "Key does not expire?!"
  301. }
  302. assert_equal {pmessage * __keyevent@9__:expired foo} [$rd1 read]
  303. $rd1 close
  304. }
  305. test "Keyspace notifications: expired events (background expire)" {
  306. r config set notify-keyspace-events Ex
  307. r del foo
  308. set rd1 [redis_deferring_client]
  309. assert_equal {1} [psubscribe $rd1 *]
  310. r psetex foo 100 1
  311. assert_equal {pmessage * __keyevent@9__:expired foo} [$rd1 read]
  312. $rd1 close
  313. }
  314. test "Keyspace notifications: evicted events" {
  315. r config set notify-keyspace-events Ee
  316. r config set maxmemory-policy allkeys-lru
  317. r flushdb
  318. set rd1 [redis_deferring_client]
  319. assert_equal {1} [psubscribe $rd1 *]
  320. r set foo bar
  321. r config set maxmemory 1
  322. assert_equal {pmessage * __keyevent@9__:evicted foo} [$rd1 read]
  323. r config set maxmemory 0
  324. $rd1 close
  325. }
  326. test "Keyspace notifications: test CONFIG GET/SET of event flags" {
  327. r config set notify-keyspace-events gKE
  328. assert_equal {gKE} [lindex [r config get notify-keyspace-events] 1]
  329. r config set notify-keyspace-events {$lshzxeKE}
  330. assert_equal {$lshzxeKE} [lindex [r config get notify-keyspace-events] 1]
  331. r config set notify-keyspace-events KA
  332. assert_equal {AK} [lindex [r config get notify-keyspace-events] 1]
  333. r config set notify-keyspace-events EA
  334. assert_equal {AE} [lindex [r config get notify-keyspace-events] 1]
  335. }
  336. }