diff options
Diffstat (limited to 'examples/redis-unstable/tests/unit/pubsub.tcl')
| -rw-r--r-- | examples/redis-unstable/tests/unit/pubsub.tcl | 1016 |
1 files changed, 0 insertions, 1016 deletions
diff --git a/examples/redis-unstable/tests/unit/pubsub.tcl b/examples/redis-unstable/tests/unit/pubsub.tcl deleted file mode 100644 index 24f779f..0000000 --- a/examples/redis-unstable/tests/unit/pubsub.tcl +++ /dev/null | |||
| @@ -1,1016 +0,0 @@ | |||
| 1 | start_server {tags {"pubsub network"}} { | ||
| 2 | if {$::singledb} { | ||
| 3 | set db 0 | ||
| 4 | } else { | ||
| 5 | set db 9 | ||
| 6 | } | ||
| 7 | |||
| 8 | foreach resp {2 3} { | ||
| 9 | set rd1 [redis_deferring_client] | ||
| 10 | if {[lsearch $::denytags "resp3"] >= 0} { | ||
| 11 | if {$resp == 3} {continue} | ||
| 12 | } elseif {$::force_resp3} { | ||
| 13 | if {$resp == 2} {continue} | ||
| 14 | } | ||
| 15 | |||
| 16 | $rd1 hello $resp | ||
| 17 | $rd1 read | ||
| 18 | |||
| 19 | test "Pub/Sub PING on RESP$resp" { | ||
| 20 | subscribe $rd1 somechannel | ||
| 21 | # While subscribed to non-zero channels PING works in Pub/Sub mode. | ||
| 22 | $rd1 ping | ||
| 23 | $rd1 ping "foo" | ||
| 24 | # In RESP3, the SUBSCRIBEd client can issue any command and get a reply, so the PINGs are standard | ||
| 25 | # In RESP2, only a handful of commands are allowed after a client is SUBSCRIBED (PING is one of them). | ||
| 26 | # For some reason, the reply in that case is an array with two elements: "pong" and argv[1] or an empty string | ||
| 27 | # God knows why. Done in commit 2264b981 | ||
| 28 | if {$resp == 3} { | ||
| 29 | assert_equal {PONG} [$rd1 read] | ||
| 30 | assert_equal {foo} [$rd1 read] | ||
| 31 | } else { | ||
| 32 | assert_equal {pong {}} [$rd1 read] | ||
| 33 | assert_equal {pong foo} [$rd1 read] | ||
| 34 | } | ||
| 35 | unsubscribe $rd1 somechannel | ||
| 36 | # Now we are unsubscribed, PING should just return PONG. | ||
| 37 | $rd1 ping | ||
| 38 | assert_equal {PONG} [$rd1 read] | ||
| 39 | |||
| 40 | } | ||
| 41 | $rd1 close | ||
| 42 | } | ||
| 43 | |||
| 44 | test "PUBLISH/SUBSCRIBE basics" { | ||
| 45 | set rd1 [redis_deferring_client] | ||
| 46 | |||
| 47 | # subscribe to two channels | ||
| 48 | assert_equal {1 2} [subscribe $rd1 {chan1 chan2}] | ||
| 49 | assert_equal 1 [r publish chan1 hello] | ||
| 50 | assert_equal 1 [r publish chan2 world] | ||
| 51 | assert_equal {message chan1 hello} [$rd1 read] | ||
| 52 | assert_equal {message chan2 world} [$rd1 read] | ||
| 53 | |||
| 54 | # unsubscribe from one of the channels | ||
| 55 | unsubscribe $rd1 {chan1} | ||
| 56 | assert_equal 0 [r publish chan1 hello] | ||
| 57 | assert_equal 1 [r publish chan2 world] | ||
| 58 | assert_equal {message chan2 world} [$rd1 read] | ||
| 59 | |||
| 60 | # unsubscribe from the remaining channel | ||
| 61 | unsubscribe $rd1 {chan2} | ||
| 62 | assert_equal 0 [r publish chan1 hello] | ||
| 63 | assert_equal 0 [r publish chan2 world] | ||
| 64 | |||
| 65 | # clean up clients | ||
| 66 | $rd1 close | ||
| 67 | } | ||
| 68 | |||
| 69 | test "PUBLISH/SUBSCRIBE with two clients" { | ||
| 70 | set rd1 [redis_deferring_client] | ||
| 71 | set rd2 [redis_deferring_client] | ||
| 72 | |||
| 73 | assert_equal {1} [subscribe $rd1 {chan1}] | ||
| 74 | assert_equal {1} [subscribe $rd2 {chan1}] | ||
| 75 | assert_equal 2 [r publish chan1 hello] | ||
| 76 | assert_equal {message chan1 hello} [$rd1 read] | ||
| 77 | assert_equal {message chan1 hello} [$rd2 read] | ||
| 78 | |||
| 79 | # clean up clients | ||
| 80 | $rd1 close | ||
| 81 | $rd2 close | ||
| 82 | } | ||
| 83 | |||
| 84 | test "PUBLISH/SUBSCRIBE after UNSUBSCRIBE without arguments" { | ||
| 85 | set rd1 [redis_deferring_client] | ||
| 86 | assert_equal {1 2 3} [subscribe $rd1 {chan1 chan2 chan3}] | ||
| 87 | unsubscribe $rd1 | ||
| 88 | wait_for_condition 100 10 { | ||
| 89 | [regexp {cmd=unsubscribe} [r client list]] eq 1 | ||
| 90 | } else { | ||
| 91 | fail "unsubscribe did not arrive" | ||
| 92 | } | ||
| 93 | assert_equal 0 [r publish chan1 hello] | ||
| 94 | assert_equal 0 [r publish chan2 hello] | ||
| 95 | assert_equal 0 [r publish chan3 hello] | ||
| 96 | |||
| 97 | # clean up clients | ||
| 98 | $rd1 close | ||
| 99 | } | ||
| 100 | |||
| 101 | test "SUBSCRIBE to one channel more than once" { | ||
| 102 | set rd1 [redis_deferring_client] | ||
| 103 | assert_equal {1 1 1} [subscribe $rd1 {chan1 chan1 chan1}] | ||
| 104 | assert_equal 1 [r publish chan1 hello] | ||
| 105 | assert_equal {message chan1 hello} [$rd1 read] | ||
| 106 | |||
| 107 | # clean up clients | ||
| 108 | $rd1 close | ||
| 109 | } | ||
| 110 | |||
| 111 | test "UNSUBSCRIBE from non-subscribed channels" { | ||
| 112 | set rd1 [redis_deferring_client] | ||
| 113 | assert_equal {0 0 0} [unsubscribe $rd1 {foo bar quux}] | ||
| 114 | |||
| 115 | # clean up clients | ||
| 116 | $rd1 close | ||
| 117 | } | ||
| 118 | |||
| 119 | test "PUBLISH/PSUBSCRIBE basics" { | ||
| 120 | set rd1 [redis_deferring_client] | ||
| 121 | |||
| 122 | # subscribe to two patterns | ||
| 123 | assert_equal {1 2} [psubscribe $rd1 {foo.* bar.*}] | ||
| 124 | assert_equal 1 [r publish foo.1 hello] | ||
| 125 | assert_equal 1 [r publish bar.1 hello] | ||
| 126 | assert_equal 0 [r publish foo1 hello] | ||
| 127 | assert_equal 0 [r publish barfoo.1 hello] | ||
| 128 | assert_equal 0 [r publish qux.1 hello] | ||
| 129 | assert_equal {pmessage foo.* foo.1 hello} [$rd1 read] | ||
| 130 | assert_equal {pmessage bar.* bar.1 hello} [$rd1 read] | ||
| 131 | |||
| 132 | # unsubscribe from one of the patterns | ||
| 133 | assert_equal {1} [punsubscribe $rd1 {foo.*}] | ||
| 134 | assert_equal 0 [r publish foo.1 hello] | ||
| 135 | assert_equal 1 [r publish bar.1 hello] | ||
| 136 | assert_equal {pmessage bar.* bar.1 hello} [$rd1 read] | ||
| 137 | |||
| 138 | # unsubscribe from the remaining pattern | ||
| 139 | assert_equal {0} [punsubscribe $rd1 {bar.*}] | ||
| 140 | assert_equal 0 [r publish foo.1 hello] | ||
| 141 | assert_equal 0 [r publish bar.1 hello] | ||
| 142 | |||
| 143 | # clean up clients | ||
| 144 | $rd1 close | ||
| 145 | } | ||
| 146 | |||
| 147 | test "PUBLISH/PSUBSCRIBE with two clients" { | ||
| 148 | set rd1 [redis_deferring_client] | ||
| 149 | set rd2 [redis_deferring_client] | ||
| 150 | |||
| 151 | assert_equal {1} [psubscribe $rd1 {chan.*}] | ||
| 152 | assert_equal {1} [psubscribe $rd2 {chan.*}] | ||
| 153 | assert_equal 2 [r publish chan.foo hello] | ||
| 154 | assert_equal {pmessage chan.* chan.foo hello} [$rd1 read] | ||
| 155 | assert_equal {pmessage chan.* chan.foo hello} [$rd2 read] | ||
| 156 | |||
| 157 | # clean up clients | ||
| 158 | $rd1 close | ||
| 159 | $rd2 close | ||
| 160 | } | ||
| 161 | |||
| 162 | test "PUBLISH/PSUBSCRIBE after PUNSUBSCRIBE without arguments" { | ||
| 163 | set rd1 [redis_deferring_client] | ||
| 164 | assert_equal {1 2 3} [psubscribe $rd1 {chan1.* chan2.* chan3.*}] | ||
| 165 | punsubscribe $rd1 | ||
| 166 | wait_for_condition 100 10 { | ||
| 167 | [regexp {cmd=punsubscribe} [r client list]] eq 1 | ||
| 168 | } else { | ||
| 169 | fail "punsubscribe did not arrive" | ||
| 170 | } | ||
| 171 | assert_equal 0 [r publish chan1.hi hello] | ||
| 172 | assert_equal 0 [r publish chan2.hi hello] | ||
| 173 | assert_equal 0 [r publish chan3.hi hello] | ||
| 174 | |||
| 175 | # clean up clients | ||
| 176 | $rd1 close | ||
| 177 | } | ||
| 178 | |||
| 179 | test "PubSub messages with CLIENT REPLY OFF" { | ||
| 180 | set rd [redis_deferring_client] | ||
| 181 | $rd hello 3 | ||
| 182 | $rd read ;# Discard the hello reply | ||
| 183 | |||
| 184 | # Test that the subscribe/psubscribe notification is ok | ||
| 185 | $rd client reply off | ||
| 186 | assert_equal {1} [subscribe $rd channel] | ||
| 187 | assert_equal {2} [psubscribe $rd ch*] | ||
| 188 | |||
| 189 | # Test that the publish notification is ok | ||
| 190 | $rd client reply off | ||
| 191 | assert_equal 2 [r publish channel hello] | ||
| 192 | assert_equal {message channel hello} [$rd read] | ||
| 193 | assert_equal {pmessage ch* channel hello} [$rd read] | ||
| 194 | |||
| 195 | # Test that the unsubscribe/punsubscribe notification is ok | ||
| 196 | $rd client reply off | ||
| 197 | assert_equal {1} [unsubscribe $rd channel] | ||
| 198 | assert_equal {0} [punsubscribe $rd ch*] | ||
| 199 | |||
| 200 | $rd close | ||
| 201 | } {0} {resp3} | ||
| 202 | |||
| 203 | test "PUNSUBSCRIBE from non-subscribed channels" { | ||
| 204 | set rd1 [redis_deferring_client] | ||
| 205 | assert_equal {0 0 0} [punsubscribe $rd1 {foo.* bar.* quux.*}] | ||
| 206 | |||
| 207 | # clean up clients | ||
| 208 | $rd1 close | ||
| 209 | } | ||
| 210 | |||
| 211 | test "NUMSUB returns numbers, not strings (#1561)" { | ||
| 212 | r pubsub numsub abc def | ||
| 213 | } {abc 0 def 0} | ||
| 214 | |||
| 215 | test "NUMPATs returns the number of unique patterns" { | ||
| 216 | set rd1 [redis_deferring_client] | ||
| 217 | set rd2 [redis_deferring_client] | ||
| 218 | |||
| 219 | # Three unique patterns and one that overlaps | ||
| 220 | psubscribe $rd1 "foo*" | ||
| 221 | psubscribe $rd2 "foo*" | ||
| 222 | psubscribe $rd1 "bar*" | ||
| 223 | psubscribe $rd2 "baz*" | ||
| 224 | |||
| 225 | set patterns [r pubsub numpat] | ||
| 226 | |||
| 227 | # clean up clients | ||
| 228 | punsubscribe $rd1 | ||
| 229 | punsubscribe $rd2 | ||
| 230 | assert_equal 3 $patterns | ||
| 231 | $rd1 close | ||
| 232 | $rd2 close | ||
| 233 | } | ||
| 234 | |||
| 235 | test "Mix SUBSCRIBE and PSUBSCRIBE" { | ||
| 236 | set rd1 [redis_deferring_client] | ||
| 237 | assert_equal {1} [subscribe $rd1 {foo.bar}] | ||
| 238 | assert_equal {2} [psubscribe $rd1 {foo.*}] | ||
| 239 | |||
| 240 | assert_equal 2 [r publish foo.bar hello] | ||
| 241 | assert_equal {message foo.bar hello} [$rd1 read] | ||
| 242 | assert_equal {pmessage foo.* foo.bar hello} [$rd1 read] | ||
| 243 | |||
| 244 | # clean up clients | ||
| 245 | $rd1 close | ||
| 246 | } | ||
| 247 | |||
| 248 | test "PUNSUBSCRIBE and UNSUBSCRIBE should always reply" { | ||
| 249 | # Make sure we are not subscribed to any channel at all. | ||
| 250 | r punsubscribe | ||
| 251 | r unsubscribe | ||
| 252 | # Now check if the commands still reply correctly. | ||
| 253 | set reply1 [r punsubscribe] | ||
| 254 | set reply2 [r unsubscribe] | ||
| 255 | concat $reply1 $reply2 | ||
| 256 | } {punsubscribe {} 0 unsubscribe {} 0} | ||
| 257 | |||
| 258 | ### Keyspace events notification tests | ||
| 259 | |||
| 260 | test "Keyspace notifications: we receive keyspace notifications" { | ||
| 261 | r config set notify-keyspace-events KA | ||
| 262 | set rd1 [redis_deferring_client] | ||
| 263 | $rd1 CLIENT REPLY OFF ;# Make sure it works even if replies are silenced | ||
| 264 | assert_equal {1} [psubscribe $rd1 *] | ||
| 265 | r set foo bar | ||
| 266 | assert_equal "pmessage * __keyspace@${db}__:foo set" [$rd1 read] | ||
| 267 | $rd1 close | ||
| 268 | } | ||
| 269 | |||
| 270 | test "Keyspace notifications: we receive keyevent notifications" { | ||
| 271 | r config set notify-keyspace-events EA | ||
| 272 | r del foo | ||
| 273 | set rd1 [redis_deferring_client] | ||
| 274 | $rd1 CLIENT REPLY SKIP ;# Make sure it works even if replies are silenced | ||
| 275 | assert_equal {1} [psubscribe $rd1 *] | ||
| 276 | r set foo bar | ||
| 277 | assert_equal "pmessage * __keyevent@${db}__:set foo" [$rd1 read] | ||
| 278 | $rd1 close | ||
| 279 | } | ||
| 280 | |||
| 281 | test "Keyspace notifications: we can receive both kind of events" { | ||
| 282 | r config set notify-keyspace-events KEA | ||
| 283 | r del foo | ||
| 284 | set rd1 [redis_deferring_client] | ||
| 285 | $rd1 CLIENT REPLY ON ;# Just coverage | ||
| 286 | assert_equal {OK} [$rd1 read] | ||
| 287 | assert_equal {1} [psubscribe $rd1 *] | ||
| 288 | r set foo bar | ||
| 289 | assert_equal "pmessage * __keyspace@${db}__:foo set" [$rd1 read] | ||
| 290 | assert_equal "pmessage * __keyevent@${db}__:set foo" [$rd1 read] | ||
| 291 | $rd1 close | ||
| 292 | } | ||
| 293 | |||
| 294 | test "Keyspace notifications: we are able to mask events" { | ||
| 295 | r config set notify-keyspace-events KEl | ||
| 296 | r del mylist | ||
| 297 | set rd1 [redis_deferring_client] | ||
| 298 | assert_equal {1} [psubscribe $rd1 *] | ||
| 299 | r set foo bar | ||
| 300 | r lpush mylist a | ||
| 301 | # No notification for set, because only list commands are enabled. | ||
| 302 | assert_equal "pmessage * __keyspace@${db}__:mylist lpush" [$rd1 read] | ||
| 303 | assert_equal "pmessage * __keyevent@${db}__:lpush mylist" [$rd1 read] | ||
| 304 | $rd1 close | ||
| 305 | } | ||
| 306 | |||
| 307 | test "Keyspace notifications: general events test" { | ||
| 308 | r config set notify-keyspace-events KEg | ||
| 309 | set rd1 [redis_deferring_client] | ||
| 310 | assert_equal {1} [psubscribe $rd1 *] | ||
| 311 | r set foo bar | ||
| 312 | r expire foo 1 | ||
| 313 | r del foo | ||
| 314 | assert_equal "pmessage * __keyspace@${db}__:foo expire" [$rd1 read] | ||
| 315 | assert_equal "pmessage * __keyevent@${db}__:expire foo" [$rd1 read] | ||
| 316 | assert_equal "pmessage * __keyspace@${db}__:foo del" [$rd1 read] | ||
| 317 | assert_equal "pmessage * __keyevent@${db}__:del foo" [$rd1 read] | ||
| 318 | $rd1 close | ||
| 319 | } | ||
| 320 | |||
| 321 | test "Keyspace notifications: list events test" { | ||
| 322 | r config set notify-keyspace-events KEl | ||
| 323 | r del mylist | ||
| 324 | set rd1 [redis_deferring_client] | ||
| 325 | assert_equal {1} [psubscribe $rd1 *] | ||
| 326 | r lpush mylist a | ||
| 327 | r rpush mylist a | ||
| 328 | r rpop mylist | ||
| 329 | assert_equal "pmessage * __keyspace@${db}__:mylist lpush" [$rd1 read] | ||
| 330 | assert_equal "pmessage * __keyevent@${db}__:lpush mylist" [$rd1 read] | ||
| 331 | assert_equal "pmessage * __keyspace@${db}__:mylist rpush" [$rd1 read] | ||
| 332 | assert_equal "pmessage * __keyevent@${db}__:rpush mylist" [$rd1 read] | ||
| 333 | assert_equal "pmessage * __keyspace@${db}__:mylist rpop" [$rd1 read] | ||
| 334 | assert_equal "pmessage * __keyevent@${db}__:rpop mylist" [$rd1 read] | ||
| 335 | $rd1 close | ||
| 336 | } | ||
| 337 | |||
| 338 | test "Keyspace notifications: set events test" { | ||
| 339 | r config set notify-keyspace-events Ks | ||
| 340 | r del myset | ||
| 341 | set rd1 [redis_deferring_client] | ||
| 342 | assert_equal {1} [psubscribe $rd1 *] | ||
| 343 | r sadd myset a b c d | ||
| 344 | r srem myset x | ||
| 345 | r sadd myset x y z | ||
| 346 | r srem myset x | ||
| 347 | assert_equal "pmessage * __keyspace@${db}__:myset sadd" [$rd1 read] | ||
| 348 | assert_equal "pmessage * __keyspace@${db}__:myset sadd" [$rd1 read] | ||
| 349 | assert_equal "pmessage * __keyspace@${db}__:myset srem" [$rd1 read] | ||
| 350 | $rd1 close | ||
| 351 | } | ||
| 352 | |||
| 353 | test "Keyspace notifications: zset events test" { | ||
| 354 | r config set notify-keyspace-events Kz | ||
| 355 | r del myzset | ||
| 356 | set rd1 [redis_deferring_client] | ||
| 357 | assert_equal {1} [psubscribe $rd1 *] | ||
| 358 | r zadd myzset 1 a 2 b | ||
| 359 | r zrem myzset x | ||
| 360 | r zadd myzset 3 x 4 y 5 z | ||
| 361 | r zrem myzset x | ||
| 362 | assert_equal "pmessage * __keyspace@${db}__:myzset zadd" [$rd1 read] | ||
| 363 | assert_equal "pmessage * __keyspace@${db}__:myzset zadd" [$rd1 read] | ||
| 364 | assert_equal "pmessage * __keyspace@${db}__:myzset zrem" [$rd1 read] | ||
| 365 | $rd1 close | ||
| 366 | } | ||
| 367 | |||
| 368 | foreach {type max_lp_entries} {listpackex 512 hashtable 0} { | ||
| 369 | test "Keyspace notifications: hash events test ($type)" { | ||
| 370 | r config set hash-max-listpack-entries $max_lp_entries | ||
| 371 | r config set notify-keyspace-events Khg | ||
| 372 | r del myhash | ||
| 373 | set rd1 [redis_deferring_client] | ||
| 374 | assert_equal {1} [psubscribe $rd1 *] | ||
| 375 | r hmset myhash yes 1 no 0 f1 1 f2 2 f3_hdel 3 | ||
| 376 | r hincrby myhash yes 10 | ||
| 377 | r hexpire myhash 999999 FIELDS 1 yes | ||
| 378 | r hexpireat myhash [expr {[clock seconds] + 999999}] NX FIELDS 1 no | ||
| 379 | r hpexpire myhash 999999 FIELDS 1 yes | ||
| 380 | r hpersist myhash FIELDS 1 yes | ||
| 381 | r hpexpire myhash 0 FIELDS 1 yes | ||
| 382 | assert_encoding $type myhash | ||
| 383 | assert_equal "pmessage * __keyspace@${db}__:myhash hset" [$rd1 read] | ||
| 384 | assert_equal "pmessage * __keyspace@${db}__:myhash hincrby" [$rd1 read] | ||
| 385 | assert_equal "pmessage * __keyspace@${db}__:myhash hexpire" [$rd1 read] | ||
| 386 | assert_equal "pmessage * __keyspace@${db}__:myhash hexpire" [$rd1 read] | ||
| 387 | assert_equal "pmessage * __keyspace@${db}__:myhash hexpire" [$rd1 read] | ||
| 388 | assert_equal "pmessage * __keyspace@${db}__:myhash hpersist" [$rd1 read] | ||
| 389 | assert_equal "pmessage * __keyspace@${db}__:myhash hdel" [$rd1 read] | ||
| 390 | |||
| 391 | # Test that we will get `hexpired` notification when | ||
| 392 | # a hash field is removed by active expire. | ||
| 393 | r hpexpire myhash 10 FIELDS 1 no | ||
| 394 | after 100 ;# Wait for active expire | ||
| 395 | assert_equal "pmessage * __keyspace@${db}__:myhash hexpire" [$rd1 read] | ||
| 396 | assert_equal "pmessage * __keyspace@${db}__:myhash hexpired" [$rd1 read] | ||
| 397 | |||
| 398 | # Test that when a field with TTL is deleted by commands like hdel without | ||
| 399 | # updating the global DS, active expire will not send a notification. | ||
| 400 | r hpexpire myhash 100 FIELDS 1 f3_hdel | ||
| 401 | r hdel myhash f3_hdel | ||
| 402 | after 200 ;# Wait for active expire | ||
| 403 | assert_equal "pmessage * __keyspace@${db}__:myhash hexpire" [$rd1 read] | ||
| 404 | assert_equal "pmessage * __keyspace@${db}__:myhash hdel" [$rd1 read] | ||
| 405 | |||
| 406 | # Test that we will get `hexpired` notification when | ||
| 407 | # a hash field is removed by lazy expire. | ||
| 408 | r debug set-active-expire 0 | ||
| 409 | r hpexpire myhash 10 FIELDS 2 f1 f2 | ||
| 410 | after 20 | ||
| 411 | r hmget myhash f1 f2 ;# Trigger lazy expire | ||
| 412 | assert_equal "pmessage * __keyspace@${db}__:myhash hexpire" [$rd1 read] | ||
| 413 | # We should get only one `hexpired` notification even two fields was expired. | ||
| 414 | assert_equal "pmessage * __keyspace@${db}__:myhash hexpired" [$rd1 read] | ||
| 415 | # We should get a `del` notification after all fields were expired. | ||
| 416 | assert_equal "pmessage * __keyspace@${db}__:myhash del" [$rd1 read] | ||
| 417 | r debug set-active-expire 1 | ||
| 418 | |||
| 419 | |||
| 420 | # Test HSETEX, HGETEX and HGETDEL notifications | ||
| 421 | r hsetex myhash FIELDS 3 f4 v4 f5 v5 f6 v6 | ||
| 422 | assert_equal "pmessage * __keyspace@${db}__:myhash hset" [$rd1 read] | ||
| 423 | |||
| 424 | # hgetex sets ttl in past | ||
| 425 | r hgetex myhash PX 0 FIELDS 1 f4 | ||
| 426 | assert_equal "pmessage * __keyspace@${db}__:myhash hdel" [$rd1 read] | ||
| 427 | |||
| 428 | # hgetex sets ttl | ||
| 429 | r hgetex myhash EXAT [expr {[clock seconds] + 999999}] FIELDS 1 f5 | ||
| 430 | assert_equal "pmessage * __keyspace@${db}__:myhash hexpire" [$rd1 read] | ||
| 431 | |||
| 432 | # hgetex persists field | ||
| 433 | r hgetex myhash PERSIST FIELDS 1 f5 | ||
| 434 | assert_equal "pmessage * __keyspace@${db}__:myhash hpersist" [$rd1 read] | ||
| 435 | |||
| 436 | # hgetex sets expiry for one field and lazy expiry deletes another field | ||
| 437 | # (KSN should be 1-hexpired 2-hexpire) | ||
| 438 | r debug set-active-expire 0 | ||
| 439 | r hsetex myhash PX 1 FIELDS 1 f5 v5 | ||
| 440 | assert_equal "pmessage * __keyspace@${db}__:myhash hset" [$rd1 read] | ||
| 441 | assert_equal "pmessage * __keyspace@${db}__:myhash hexpire" [$rd1 read] | ||
| 442 | after 10 | ||
| 443 | r hgetex myhash EX 100 FIELDS 2 f5 f6 | ||
| 444 | assert_equal "pmessage * __keyspace@${db}__:myhash hexpired" [$rd1 read] | ||
| 445 | assert_equal "pmessage * __keyspace@${db}__:myhash hexpire" [$rd1 read] | ||
| 446 | |||
| 447 | # hgetex lazy expiry deletes the only field and the key | ||
| 448 | # (KSN should be 1-hexpired 2-del) | ||
| 449 | r hsetex myhash PX 1 FIELDS 2 f5 v5 f6 v6 | ||
| 450 | assert_equal "pmessage * __keyspace@${db}__:myhash hset" [$rd1 read] | ||
| 451 | assert_equal "pmessage * __keyspace@${db}__:myhash hexpire" [$rd1 read] | ||
| 452 | after 10 | ||
| 453 | r hgetex myhash FIELDS 2 f5 f6 | ||
| 454 | assert_equal "pmessage * __keyspace@${db}__:myhash hexpired" [$rd1 read] | ||
| 455 | assert_equal "pmessage * __keyspace@${db}__:myhash del" [$rd1 read] | ||
| 456 | r debug set-active-expire 1 | ||
| 457 | |||
| 458 | # hgetex sets an expired ttl for the only field and deletes the key | ||
| 459 | # (KSN should be 1-hdel 2-del) | ||
| 460 | r hsetex myhash EX 100 FIELDS 1 f5 v5 | ||
| 461 | assert_equal "pmessage * __keyspace@${db}__:myhash hset" [$rd1 read] | ||
| 462 | assert_equal "pmessage * __keyspace@${db}__:myhash hexpire" [$rd1 read] | ||
| 463 | after 10 | ||
| 464 | r hgetex myhash PX 0 FIELDS 1 f5 | ||
| 465 | assert_equal "pmessage * __keyspace@${db}__:myhash hdel" [$rd1 read] | ||
| 466 | assert_equal "pmessage * __keyspace@${db}__:myhash del" [$rd1 read] | ||
| 467 | |||
| 468 | r hsetex myhash FIELDS 2 f5 v5 f6 v6 | ||
| 469 | assert_equal "pmessage * __keyspace@${db}__:myhash hset" [$rd1 read] | ||
| 470 | |||
| 471 | # hgetdel deletes a field | ||
| 472 | r hgetdel myhash FIELDS 1 f5 | ||
| 473 | assert_equal "pmessage * __keyspace@${db}__:myhash hdel" [$rd1 read] | ||
| 474 | |||
| 475 | # hsetex sets field and expiry time | ||
| 476 | r hsetex myhash EXAT [expr {[clock seconds] + 999999}] FIELDS 1 f6 v6 | ||
| 477 | assert_equal "pmessage * __keyspace@${db}__:myhash hset" [$rd1 read] | ||
| 478 | assert_equal "pmessage * __keyspace@${db}__:myhash hexpire" [$rd1 read] | ||
| 479 | |||
| 480 | # hsetex sets field and ttl in the past | ||
| 481 | r hsetex myhash PX 0 FIELDS 1 f6 v6 | ||
| 482 | assert_equal "pmessage * __keyspace@${db}__:myhash hset" [$rd1 read] | ||
| 483 | assert_equal "pmessage * __keyspace@${db}__:myhash hdel" [$rd1 read] | ||
| 484 | assert_equal "pmessage * __keyspace@${db}__:myhash del" [$rd1 read] | ||
| 485 | |||
| 486 | # Test that we will get `hexpired` notification when a hash field is | ||
| 487 | # removed by lazy expire using hgetdel command | ||
| 488 | r debug set-active-expire 0 | ||
| 489 | r hsetex myhash PX 10 FIELDS 1 f1 v1 | ||
| 490 | assert_equal "pmessage * __keyspace@${db}__:myhash hset" [$rd1 read] | ||
| 491 | assert_equal "pmessage * __keyspace@${db}__:myhash hexpire" [$rd1 read] | ||
| 492 | |||
| 493 | # Set another field | ||
| 494 | r hsetex myhash FIELDS 1 f2 v2 | ||
| 495 | assert_equal "pmessage * __keyspace@${db}__:myhash hset" [$rd1 read] | ||
| 496 | # Wait until field expires | ||
| 497 | after 20 | ||
| 498 | r hgetdel myhash FIELDS 1 f1 | ||
| 499 | assert_equal "pmessage * __keyspace@${db}__:myhash hexpired" [$rd1 read] | ||
| 500 | # Get and delete the only field | ||
| 501 | r hgetdel myhash FIELDS 1 f2 | ||
| 502 | assert_equal "pmessage * __keyspace@${db}__:myhash hdel" [$rd1 read] | ||
| 503 | assert_equal "pmessage * __keyspace@${db}__:myhash del" [$rd1 read] | ||
| 504 | |||
| 505 | # HGETDEL deletes one field and the other field is lazily expired | ||
| 506 | # (KSN should be 1-hexpired 2-hdel) | ||
| 507 | r hsetex myhash FIELDS 2 f1 v1 f2 v2 | ||
| 508 | assert_equal "pmessage * __keyspace@${db}__:myhash hset" [$rd1 read] | ||
| 509 | r hsetex myhash PX 1 FIELDS 1 f3 v3 | ||
| 510 | assert_equal "pmessage * __keyspace@${db}__:myhash hset" [$rd1 read] | ||
| 511 | assert_equal "pmessage * __keyspace@${db}__:myhash hexpire" [$rd1 read] | ||
| 512 | after 10 | ||
| 513 | r hgetdel myhash FIELDS 2 f1 f3 | ||
| 514 | assert_equal "pmessage * __keyspace@${db}__:myhash hexpired" [$rd1 read] | ||
| 515 | assert_equal "pmessage * __keyspace@${db}__:myhash hdel" [$rd1 read] | ||
| 516 | |||
| 517 | # HGETDEL, deletes one field and the last field lazily expires | ||
| 518 | # (KSN should be 1-hexpired 2-hdel 3-del) | ||
| 519 | r hsetex myhash FIELDS 1 f1 v1 | ||
| 520 | assert_equal "pmessage * __keyspace@${db}__:myhash hset" [$rd1 read] | ||
| 521 | r hsetex myhash PX 1 FIELDS 1 f2 v2 | ||
| 522 | assert_equal "pmessage * __keyspace@${db}__:myhash hset" [$rd1 read] | ||
| 523 | assert_equal "pmessage * __keyspace@${db}__:myhash hexpire" [$rd1 read] | ||
| 524 | after 10 | ||
| 525 | r hgetdel myhash FIELDS 2 f1 f2 | ||
| 526 | assert_equal "pmessage * __keyspace@${db}__:myhash hexpired" [$rd1 read] | ||
| 527 | assert_equal "pmessage * __keyspace@${db}__:myhash hdel" [$rd1 read] | ||
| 528 | assert_equal "pmessage * __keyspace@${db}__:myhash del" [$rd1 read] | ||
| 529 | r debug set-active-expire 1 | ||
| 530 | |||
| 531 | $rd1 close | ||
| 532 | } {0} {needs:debug} | ||
| 533 | } ;# foreach | ||
| 534 | |||
| 535 | test "Keyspace notifications: stream events test" { | ||
| 536 | r config set notify-keyspace-events Kt | ||
| 537 | r del mystream | ||
| 538 | set rd1 [redis_deferring_client] | ||
| 539 | assert_equal {1} [psubscribe $rd1 *] | ||
| 540 | r xgroup create mystream mygroup $ mkstream | ||
| 541 | r xgroup createconsumer mystream mygroup Bob | ||
| 542 | set id [r xadd mystream 1 field1 A] | ||
| 543 | r xreadgroup group mygroup Alice STREAMS mystream > | ||
| 544 | r xclaim mystream mygroup Mike 0 $id force | ||
| 545 | # Not notify because of "Lee" not exists. | ||
| 546 | r xgroup delconsumer mystream mygroup Lee | ||
| 547 | # Not notify because of "Bob" exists. | ||
| 548 | r xautoclaim mystream mygroup Bob 0 $id | ||
| 549 | r xgroup delconsumer mystream mygroup Bob | ||
| 550 | assert_equal "pmessage * __keyspace@${db}__:mystream xgroup-create" [$rd1 read] | ||
| 551 | assert_equal "pmessage * __keyspace@${db}__:mystream xgroup-createconsumer" [$rd1 read] | ||
| 552 | assert_equal "pmessage * __keyspace@${db}__:mystream xadd" [$rd1 read] | ||
| 553 | assert_equal "pmessage * __keyspace@${db}__:mystream xgroup-createconsumer" [$rd1 read] | ||
| 554 | assert_equal "pmessage * __keyspace@${db}__:mystream xgroup-createconsumer" [$rd1 read] | ||
| 555 | assert_equal "pmessage * __keyspace@${db}__:mystream xgroup-delconsumer" [$rd1 read] | ||
| 556 | $rd1 close | ||
| 557 | } | ||
| 558 | |||
| 559 | test "Keyspace notifications:FXX/FNX with HSETEX cmd" { | ||
| 560 | r config set notify-keyspace-events Khxg | ||
| 561 | r del myhash | ||
| 562 | set rd1 [redis_deferring_client] | ||
| 563 | assert_equal {1} [psubscribe $rd1 *] | ||
| 564 | r debug set-active-expire 0 | ||
| 565 | |||
| 566 | # FXX on logically expired field | ||
| 567 | r hset myhash f v | ||
| 568 | r hset myhash f2 v | ||
| 569 | assert_equal "pmessage * __keyspace@${db}__:myhash hset" [$rd1 read] | ||
| 570 | assert_equal "pmessage * __keyspace@${db}__:myhash hset" [$rd1 read] | ||
| 571 | r hpexpire myhash 10 FIELDS 1 f | ||
| 572 | assert_equal "pmessage * __keyspace@${db}__:myhash hexpire" [$rd1 read] | ||
| 573 | after 15 | ||
| 574 | assert_equal [r HSETEX myhash FXX PX 10 FIELDS 1 f v] 0 | ||
| 575 | assert_equal "pmessage * __keyspace@${db}__:myhash hexpired" [$rd1 read] | ||
| 576 | r hdel myhash f2 | ||
| 577 | assert_equal "pmessage * __keyspace@${db}__:myhash hdel" [$rd1 read] | ||
| 578 | assert_equal 0 [r exists myhash] | ||
| 579 | assert_equal "pmessage * __keyspace@${db}__:myhash del" [$rd1 read] | ||
| 580 | |||
| 581 | # FXX with past expiry | ||
| 582 | r HSET myhash f1 v1 | ||
| 583 | assert_equal "pmessage * __keyspace@${db}__:myhash hset" [$rd1 read] | ||
| 584 | set past [expr {[clock seconds] - 2}] | ||
| 585 | assert_equal [r hsetex myhash FXX EXAT $past FIELDS 1 f1 v1] 1 | ||
| 586 | assert_equal "pmessage * __keyspace@${db}__:myhash hset" [$rd1 read] | ||
| 587 | assert_equal "pmessage * __keyspace@${db}__:myhash hdel" [$rd1 read] | ||
| 588 | assert_equal "pmessage * __keyspace@${db}__:myhash del" [$rd1 read] | ||
| 589 | |||
| 590 | # FXX overwrite + full key expiry | ||
| 591 | r hset myhash f v | ||
| 592 | r hset myhash f2 v | ||
| 593 | assert_equal "pmessage * __keyspace@${db}__:myhash hset" [$rd1 read] | ||
| 594 | assert_equal "pmessage * __keyspace@${db}__:myhash hset" [$rd1 read] | ||
| 595 | r hpexpire myhash 10 FIELDS 1 f | ||
| 596 | assert_equal "pmessage * __keyspace@${db}__:myhash hexpire" [$rd1 read] | ||
| 597 | after 15 | ||
| 598 | set past [expr {[clock milliseconds] - 5000}] | ||
| 599 | assert_equal [r hsetex myhash FXX PXAT $past FIELDS 1 f v] 0 | ||
| 600 | assert_equal "pmessage * __keyspace@${db}__:myhash hexpired" [$rd1 read] | ||
| 601 | r hpexpire myhash 10 FIELDS 1 f2 | ||
| 602 | after 15 | ||
| 603 | r hget myhash f2 | ||
| 604 | assert_equal "pmessage * __keyspace@${db}__:myhash hexpire" [$rd1 read] | ||
| 605 | assert_equal "pmessage * __keyspace@${db}__:myhash hexpired" [$rd1 read] | ||
| 606 | assert_equal "pmessage * __keyspace@${db}__:myhash del" [$rd1 read] | ||
| 607 | |||
| 608 | # FNX on logically expired field | ||
| 609 | r del myhash | ||
| 610 | r hset myhash f v | ||
| 611 | assert_equal "pmessage * __keyspace@${db}__:myhash hset" [$rd1 read] | ||
| 612 | r hpexpire myhash 10 FIELDS 1 f | ||
| 613 | assert_equal "pmessage * __keyspace@${db}__:myhash hexpire" [$rd1 read] | ||
| 614 | after 15 | ||
| 615 | assert_equal [r HSETEX myhash FNX PX 1000 FIELDS 1 f v] 1 | ||
| 616 | assert_equal "pmessage * __keyspace@${db}__:myhash hexpired" [$rd1 read] | ||
| 617 | assert_equal "pmessage * __keyspace@${db}__:myhash hset" [$rd1 read] | ||
| 618 | assert_equal "pmessage * __keyspace@${db}__:myhash hexpire" [$rd1 read] | ||
| 619 | |||
| 620 | # FNX with past expiry | ||
| 621 | r del myhash | ||
| 622 | r hset myhash f v | ||
| 623 | assert_equal "pmessage * __keyspace@${db}__:myhash del" [$rd1 read] | ||
| 624 | assert_equal "pmessage * __keyspace@${db}__:myhash hset" [$rd1 read] | ||
| 625 | set past [expr {[clock seconds] - 2}] | ||
| 626 | assert_equal [r hsetex myhash FNX EXAT $past FIELDS 1 f1 v1] 1 | ||
| 627 | # f1 is created and immediately expired | ||
| 628 | assert_equal "pmessage * __keyspace@${db}__:myhash hset" [$rd1 read] | ||
| 629 | assert_equal "pmessage * __keyspace@${db}__:myhash hdel" [$rd1 read] | ||
| 630 | |||
| 631 | r debug set-active-expire 1 | ||
| 632 | $rd1 close | ||
| 633 | } {0} {needs:debug} | ||
| 634 | |||
| 635 | test "Keyspace notifications: expired events (triggered expire)" { | ||
| 636 | r config set notify-keyspace-events Ex | ||
| 637 | r del foo | ||
| 638 | set rd1 [redis_deferring_client] | ||
| 639 | assert_equal {1} [psubscribe $rd1 *] | ||
| 640 | r psetex foo 100 1 | ||
| 641 | wait_for_condition 50 100 { | ||
| 642 | [r exists foo] == 0 | ||
| 643 | } else { | ||
| 644 | fail "Key does not expire?!" | ||
| 645 | } | ||
| 646 | assert_equal "pmessage * __keyevent@${db}__:expired foo" [$rd1 read] | ||
| 647 | $rd1 close | ||
| 648 | } | ||
| 649 | |||
| 650 | test "Keyspace notifications: expired events (background expire)" { | ||
| 651 | r config set notify-keyspace-events Ex | ||
| 652 | r del foo | ||
| 653 | set rd1 [redis_deferring_client] | ||
| 654 | assert_equal {1} [psubscribe $rd1 *] | ||
| 655 | r psetex foo 100 1 | ||
| 656 | assert_equal "pmessage * __keyevent@${db}__:expired foo" [$rd1 read] | ||
| 657 | $rd1 close | ||
| 658 | } | ||
| 659 | |||
| 660 | test "Keyspace notifications: evicted events" { | ||
| 661 | r config set notify-keyspace-events Ee | ||
| 662 | r config set maxmemory-policy allkeys-lru | ||
| 663 | r flushdb | ||
| 664 | set rd1 [redis_deferring_client] | ||
| 665 | assert_equal {1} [psubscribe $rd1 *] | ||
| 666 | r set foo bar | ||
| 667 | r config set maxmemory 1 | ||
| 668 | assert_equal "pmessage * __keyevent@${db}__:evicted foo" [$rd1 read] | ||
| 669 | r config set maxmemory 0 | ||
| 670 | $rd1 close | ||
| 671 | r config set maxmemory-policy noeviction | ||
| 672 | } {OK} {needs:config-maxmemory} | ||
| 673 | |||
| 674 | test "Keyspace notifications: test CONFIG GET/SET of event flags" { | ||
| 675 | r config set notify-keyspace-events gKE | ||
| 676 | assert_equal {gKE} [lindex [r config get notify-keyspace-events] 1] | ||
| 677 | r config set notify-keyspace-events {$lshzxeKE} | ||
| 678 | assert_equal {$lshzxeKE} [lindex [r config get notify-keyspace-events] 1] | ||
| 679 | r config set notify-keyspace-events KA | ||
| 680 | assert_equal {AK} [lindex [r config get notify-keyspace-events] 1] | ||
| 681 | r config set notify-keyspace-events EA | ||
| 682 | assert_equal {AE} [lindex [r config get notify-keyspace-events] 1] | ||
| 683 | } | ||
| 684 | |||
| 685 | test "Keyspace notifications: new key test" { | ||
| 686 | r config set notify-keyspace-events En | ||
| 687 | set rd1 [redis_deferring_client] | ||
| 688 | assert_equal {1} [psubscribe $rd1 *] | ||
| 689 | r set foo bar | ||
| 690 | # second set of foo should not cause a 'new' event | ||
| 691 | r set foo baz | ||
| 692 | r set bar bar | ||
| 693 | assert_equal "pmessage * __keyevent@${db}__:new foo" [$rd1 read] | ||
| 694 | assert_equal "pmessage * __keyevent@${db}__:new bar" [$rd1 read] | ||
| 695 | $rd1 close | ||
| 696 | } | ||
| 697 | |||
| 698 | ### overwritten and type_changed events | ||
| 699 | |||
| 700 | test "Keyspace notifications: overwritten events - string to string" { | ||
| 701 | r config set notify-keyspace-events Eo | ||
| 702 | r del foo | ||
| 703 | set rd1 [redis_deferring_client] | ||
| 704 | assert_equal {1} [psubscribe $rd1 *] | ||
| 705 | |||
| 706 | # First set - should not trigger overwritten (new key) | ||
| 707 | r set foo bar | ||
| 708 | |||
| 709 | # Second set - should trigger overwritten (same type) | ||
| 710 | r set foo baz | ||
| 711 | |||
| 712 | assert_equal "pmessage * __keyevent@${db}__:overwritten foo" [$rd1 read] | ||
| 713 | $rd1 close | ||
| 714 | } | ||
| 715 | |||
| 716 | test "Keyspace notifications: type_changed events - hash to string" { | ||
| 717 | r config set notify-keyspace-events Ec | ||
| 718 | r del testkey | ||
| 719 | set rd1 [redis_deferring_client] | ||
| 720 | assert_equal {1} [psubscribe $rd1 *] | ||
| 721 | |||
| 722 | # Set as hash first | ||
| 723 | r hset testkey field "hash_value" | ||
| 724 | |||
| 725 | # Change to string - should trigger type_changed | ||
| 726 | r set testkey "string_value" | ||
| 727 | |||
| 728 | assert_equal "pmessage * __keyevent@${db}__:type_changed testkey" [$rd1 read] | ||
| 729 | $rd1 close | ||
| 730 | } | ||
| 731 | |||
| 732 | test "Keyspace notifications: both overwritten and type_changed events" { | ||
| 733 | r config set notify-keyspace-events Eoc | ||
| 734 | r del testkey3 | ||
| 735 | set rd1 [redis_deferring_client] | ||
| 736 | assert_equal {1} [psubscribe $rd1 *] | ||
| 737 | |||
| 738 | # Set as hash first | ||
| 739 | r hset testkey3 field "hash_value" | ||
| 740 | |||
| 741 | # Change to string - should trigger both overwritten and type_changed | ||
| 742 | r set testkey3 "string_value" | ||
| 743 | |||
| 744 | assert_equal "pmessage * __keyevent@${db}__:overwritten testkey3" [$rd1 read] | ||
| 745 | assert_equal "pmessage * __keyevent@${db}__:type_changed testkey3" [$rd1 read] | ||
| 746 | |||
| 747 | $rd1 close | ||
| 748 | } | ||
| 749 | |||
| 750 | test "Keyspace notifications: configuration flags work correctly" { | ||
| 751 | # Test that 'o' flag enables override notifications | ||
| 752 | r config set notify-keyspace-events o | ||
| 753 | set config [r config get notify-keyspace-events] | ||
| 754 | assert {[lindex $config 1] eq "o"} | ||
| 755 | |||
| 756 | # Test that 'c' flag enables type_changed notifications | ||
| 757 | r config set notify-keyspace-events c | ||
| 758 | set config [r config get notify-keyspace-events] | ||
| 759 | assert {[lindex $config 1] eq "c"} | ||
| 760 | |||
| 761 | # Test that both flags can be combined | ||
| 762 | r config set notify-keyspace-events oc | ||
| 763 | set config [r config get notify-keyspace-events] | ||
| 764 | assert {[lindex $config 1] eq "oc"} | ||
| 765 | } | ||
| 766 | |||
| 767 | ### RESTORE command tests for type_changed KSN types | ||
| 768 | |||
| 769 | test "Keyspace notifications: RESTORE REPLACE different type - restore, overwritten and type_changed events" { | ||
| 770 | r config set notify-keyspace-events Egoc | ||
| 771 | r del restore_test_key3 | ||
| 772 | |||
| 773 | # Create a string value and dump it (do this before subscribing) | ||
| 774 | r set temp_key "string_value" | ||
| 775 | set dump_data [r dump temp_key] | ||
| 776 | r del temp_key | ||
| 777 | |||
| 778 | set rd1 [redis_deferring_client] | ||
| 779 | assert_equal {1} [psubscribe $rd1 *] | ||
| 780 | |||
| 781 | # Create initial hash key | ||
| 782 | r hset restore_test_key3 field "hash_value" | ||
| 783 | |||
| 784 | # Restore with REPLACE - should emit restore, overwritten and type_changed events | ||
| 785 | r restore restore_test_key3 0 $dump_data REPLACE | ||
| 786 | |||
| 787 | assert_equal "pmessage * __keyevent@${db}__:restore restore_test_key3" [$rd1 read] | ||
| 788 | assert_equal "pmessage * __keyevent@${db}__:overwritten restore_test_key3" [$rd1 read] | ||
| 789 | assert_equal "pmessage * __keyevent@${db}__:type_changed restore_test_key3" [$rd1 read] | ||
| 790 | |||
| 791 | $rd1 close | ||
| 792 | } | ||
| 793 | |||
| 794 | ### SET command tests for overwritten and type_changed KSN types | ||
| 795 | |||
| 796 | test "Keyspace notifications: SET on existing string key - overwritten event" { | ||
| 797 | r config set notify-keyspace-events EAo | ||
| 798 | r del set_test_key1 | ||
| 799 | set rd1 [redis_deferring_client] | ||
| 800 | assert_equal {1} [psubscribe $rd1 *] | ||
| 801 | |||
| 802 | # Create initial string key | ||
| 803 | r set set_test_key1 "initial_value" | ||
| 804 | assert_equal "pmessage * __keyevent@${db}__:set set_test_key1" [$rd1 read] | ||
| 805 | |||
| 806 | # Set new value on existing string key - should emit overwritten event | ||
| 807 | r set set_test_key1 "new_value" | ||
| 808 | |||
| 809 | assert_equal "pmessage * __keyevent@${db}__:overwritten set_test_key1" [$rd1 read] | ||
| 810 | assert_equal "pmessage * __keyevent@${db}__:set set_test_key1" [$rd1 read] | ||
| 811 | |||
| 812 | $rd1 close | ||
| 813 | } | ||
| 814 | |||
| 815 | test "Keyspace notifications: setKey on existing different type key - overwritten and type_changed events" { | ||
| 816 | r config set notify-keyspace-events Eoc | ||
| 817 | |||
| 818 | set rd1 [redis_deferring_client] | ||
| 819 | assert_equal {1} [psubscribe $rd1 *] | ||
| 820 | |||
| 821 | r flushdb | ||
| 822 | r hset set_test_key2 field "hash_value" | ||
| 823 | r set set_test_key2 "string_value" | ||
| 824 | assert_equal "pmessage * __keyevent@${db}__:overwritten set_test_key2" [$rd1 read] | ||
| 825 | assert_equal "pmessage * __keyevent@${db}__:type_changed set_test_key2" [$rd1 read] | ||
| 826 | |||
| 827 | # overwritten and type_changed events should be emitted for any->any | ||
| 828 | # type conversion that uses the setKey command | ||
| 829 | r flushdb | ||
| 830 | r lpush l{t} 1 2 3 | ||
| 831 | r sadd s1{t} "A" | ||
| 832 | r sadd s2{t} "B" | ||
| 833 | r sunionstore l{t} s1{t} s2{t} | ||
| 834 | assert_equal "pmessage * __keyevent@${db}__:overwritten l{t}" [$rd1 read] | ||
| 835 | assert_equal "pmessage * __keyevent@${db}__:type_changed l{t}" [$rd1 read] | ||
| 836 | |||
| 837 | r flushdb | ||
| 838 | r sadd s1{t} "A" | ||
| 839 | r set x{t} "\x0f" | ||
| 840 | r set y{t} "\xff" | ||
| 841 | r bitop and s1{t} x{t} y{t} | ||
| 842 | assert_equal "pmessage * __keyevent@${db}__:overwritten s1{t}" [$rd1 read] | ||
| 843 | assert_equal "pmessage * __keyevent@${db}__:type_changed s1{t}" [$rd1 read] | ||
| 844 | |||
| 845 | $rd1 close | ||
| 846 | } | ||
| 847 | |||
| 848 | test "Keyspace notifications: overwritten and type_changed events for RENAME and COPY commands" { | ||
| 849 | r config set notify-keyspace-events Eoc | ||
| 850 | |||
| 851 | set rd1 [redis_deferring_client] | ||
| 852 | assert_equal {1} [psubscribe $rd1 *] | ||
| 853 | |||
| 854 | # test COPY events | ||
| 855 | r flushdb | ||
| 856 | r hset hs{t} 1 2 3 4 | ||
| 857 | r lpush l{t} 1 2 3 4 | ||
| 858 | r copy hs{t} l{t} replace | ||
| 859 | |||
| 860 | assert_equal "pmessage * __keyevent@${db}__:overwritten l{t}" [$rd1 read] | ||
| 861 | assert_equal "pmessage * __keyevent@${db}__:type_changed l{t}" [$rd1 read] | ||
| 862 | |||
| 863 | # test rename RENAME events | ||
| 864 | r flushdb | ||
| 865 | r hset hs{t} field "hash_value" | ||
| 866 | r sadd x{t} 1 2 3 | ||
| 867 | r rename x{t} hs{t} | ||
| 868 | |||
| 869 | assert_equal "pmessage * __keyevent@${db}__:overwritten hs{t}" [$rd1 read] | ||
| 870 | assert_equal "pmessage * __keyevent@${db}__:type_changed hs{t}" [$rd1 read] | ||
| 871 | |||
| 872 | $rd1 close | ||
| 873 | } | ||
| 874 | |||
| 875 | test "Keyspace notifications: overwritten and type_changed for *STORE* commands" { | ||
| 876 | r config set notify-keyspace-events Eoc | ||
| 877 | |||
| 878 | set rd1 [redis_deferring_client] | ||
| 879 | assert_equal {1} [psubscribe $rd1 *] | ||
| 880 | |||
| 881 | r flushdb | ||
| 882 | r set x{t} x | ||
| 883 | |||
| 884 | # SORT | ||
| 885 | r lpush l{t} 4 3 2 1 | ||
| 886 | r sort l{t} store x{t} | ||
| 887 | assert_equal "pmessage * __keyevent@${db}__:overwritten x{t}" [$rd1 read] | ||
| 888 | assert_equal "pmessage * __keyevent@${db}__:type_changed x{t}" [$rd1 read] | ||
| 889 | |||
| 890 | # SDIFFSTORE | ||
| 891 | r sadd s1{t} a b c d | ||
| 892 | r sadd s2{t} b e f | ||
| 893 | r sdiffstore x{t} s1{t} s2{t} | ||
| 894 | assert_equal "pmessage * __keyevent@${db}__:overwritten x{t}" [$rd1 read] | ||
| 895 | assert_equal "pmessage * __keyevent@${db}__:type_changed x{t}" [$rd1 read] | ||
| 896 | |||
| 897 | # SINTERSTORE | ||
| 898 | r set d1{t} x | ||
| 899 | r sinterstore d1{t} s1{t} s2{t} | ||
| 900 | assert_equal "pmessage * __keyevent@${db}__:overwritten d1{t}" [$rd1 read] | ||
| 901 | assert_equal "pmessage * __keyevent@${db}__:type_changed d1{t}" [$rd1 read] | ||
| 902 | |||
| 903 | # SUNIONSTORE | ||
| 904 | r set d2{t} x | ||
| 905 | r sunionstore d2{t} s1{t} s2{t} | ||
| 906 | assert_equal "pmessage * __keyevent@${db}__:overwritten d2{t}" [$rd1 read] | ||
| 907 | assert_equal "pmessage * __keyevent@${db}__:type_changed d2{t}" [$rd1 read] | ||
| 908 | |||
| 909 | # ZUNIONSTORE | ||
| 910 | r set d3{t} x | ||
| 911 | r zadd z1{t} 1 a 2 b | ||
| 912 | r zadd z2{t} 3 c 4 d | ||
| 913 | r zunionstore d3{t} 2 z1{t} z2{t} | ||
| 914 | assert_equal "pmessage * __keyevent@${db}__:overwritten d3{t}" [$rd1 read] | ||
| 915 | assert_equal "pmessage * __keyevent@${db}__:type_changed d3{t}" [$rd1 read] | ||
| 916 | |||
| 917 | # ZINTERSTORE | ||
| 918 | r set d4{t} x | ||
| 919 | r zadd z2{t} 2 a | ||
| 920 | r zinterstore d4{t} 2 z1{t} z2{t} | ||
| 921 | assert_equal "pmessage * __keyevent@${db}__:overwritten d4{t}" [$rd1 read] | ||
| 922 | assert_equal "pmessage * __keyevent@${db}__:type_changed d4{t}" [$rd1 read] | ||
| 923 | |||
| 924 | # ZDIFFSTORE | ||
| 925 | r set d5{t} x | ||
| 926 | r zdiffstore d5{t} 2 z1{t} z2{t} | ||
| 927 | assert_equal "pmessage * __keyevent@${db}__:overwritten d5{t}" [$rd1 read] | ||
| 928 | assert_equal "pmessage * __keyevent@${db}__:type_changed d5{t}" [$rd1 read] | ||
| 929 | |||
| 930 | # ZRANGESTORE | ||
| 931 | r set d6{t} x | ||
| 932 | r zadd zsrc{t} 1 a 2 b 3 c 4 d | ||
| 933 | r zrangestore d6{t} zsrc{t} 1 2 | ||
| 934 | assert_equal "pmessage * __keyevent@${db}__:overwritten d6{t}" [$rd1 read] | ||
| 935 | assert_equal "pmessage * __keyevent@${db}__:type_changed d6{t}" [$rd1 read] | ||
| 936 | |||
| 937 | # GEORADIUS with STORE | ||
| 938 | r set d7{t} x | ||
| 939 | r geoadd geo{t} 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania" | ||
| 940 | r georadius geo{t} 15 37 200 km store d7{t} | ||
| 941 | assert_equal "pmessage * __keyevent@${db}__:overwritten d7{t}" [$rd1 read] | ||
| 942 | assert_equal "pmessage * __keyevent@${db}__:type_changed d7{t}" [$rd1 read] | ||
| 943 | |||
| 944 | # GEORADIUS with STOREDIST | ||
| 945 | r set d8{t} x | ||
| 946 | r georadius geo{t} 15 37 200 km storedist d8{t} | ||
| 947 | assert_equal "pmessage * __keyevent@${db}__:overwritten d8{t}" [$rd1 read] | ||
| 948 | assert_equal "pmessage * __keyevent@${db}__:type_changed d8{t}" [$rd1 read] | ||
| 949 | |||
| 950 | # GEOSEARCHSTORE | ||
| 951 | r set d9{t} x | ||
| 952 | r geosearchstore d9{t} geo{t} fromlonlat 15 37 byradius 200 km | ||
| 953 | assert_equal "pmessage * __keyevent@${db}__:overwritten d9{t}" [$rd1 read] | ||
| 954 | assert_equal "pmessage * __keyevent@${db}__:type_changed d9{t}" [$rd1 read] | ||
| 955 | |||
| 956 | # GEOSEARCHSTORE with STOREDIST | ||
| 957 | r set d10{t} x | ||
| 958 | r geosearchstore d10{t} geo{t} fromlonlat 15 37 byradius 200 km storedist | ||
| 959 | assert_equal "pmessage * __keyevent@${db}__:overwritten d10{t}" [$rd1 read] | ||
| 960 | assert_equal "pmessage * __keyevent@${db}__:type_changed d10{t}" [$rd1 read] | ||
| 961 | |||
| 962 | $rd1 close | ||
| 963 | } | ||
| 964 | |||
| 965 | test "publish to self inside multi" { | ||
| 966 | r hello 3 | ||
| 967 | r subscribe foo | ||
| 968 | r multi | ||
| 969 | r ping abc | ||
| 970 | r publish foo bar | ||
| 971 | r publish foo vaz | ||
| 972 | r ping def | ||
| 973 | assert_equal [r exec] {abc 1 1 def} | ||
| 974 | assert_equal [r read] {message foo bar} | ||
| 975 | assert_equal [r read] {message foo vaz} | ||
| 976 | } {} {resp3} | ||
| 977 | |||
| 978 | test "publish to self inside script" { | ||
| 979 | r hello 3 | ||
| 980 | r subscribe foo | ||
| 981 | set res [r eval { | ||
| 982 | redis.call("ping","abc") | ||
| 983 | redis.call("publish","foo","bar") | ||
| 984 | redis.call("publish","foo","vaz") | ||
| 985 | redis.call("ping","def") | ||
| 986 | return "bla"} 0] | ||
| 987 | assert_equal $res {bla} | ||
| 988 | assert_equal [r read] {message foo bar} | ||
| 989 | assert_equal [r read] {message foo vaz} | ||
| 990 | } {} {resp3} | ||
| 991 | |||
| 992 | test "unsubscribe inside multi, and publish to self" { | ||
| 993 | r hello 3 | ||
| 994 | |||
| 995 | # Note: SUBSCRIBE and UNSUBSCRIBE with multiple channels in the same command, | ||
| 996 | # breaks the multi response, see https://github.com/redis/redis/issues/12207 | ||
| 997 | # this is just a temporary sanity test to detect unintended breakage. | ||
| 998 | |||
| 999 | # subscribe for 3 channels actually emits 3 "responses" | ||
| 1000 | assert_equal "subscribe foo 1" [r subscribe foo bar baz] | ||
| 1001 | assert_equal "subscribe bar 2" [r read] | ||
| 1002 | assert_equal "subscribe baz 3" [r read] | ||
| 1003 | |||
| 1004 | r multi | ||
| 1005 | r ping abc | ||
| 1006 | r unsubscribe bar | ||
| 1007 | r unsubscribe baz | ||
| 1008 | r ping def | ||
| 1009 | assert_equal [r exec] {abc {unsubscribe bar 2} {unsubscribe baz 1} def} | ||
| 1010 | |||
| 1011 | # published message comes after the publish command's response. | ||
| 1012 | assert_equal [r publish foo vaz] {1} | ||
| 1013 | assert_equal [r read] {message foo vaz} | ||
| 1014 | } {} {resp3} | ||
| 1015 | |||
| 1016 | } | ||
