summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authornitaicaro <42576749+nitaicaro@users.noreply.github.com>2020-11-09 22:54:47 +0200
committerGitHub <noreply@github.com>2020-11-09 22:54:47 +0200
commit19c29b600746b575a7e902b30633b735bbf67c55 (patch)
tree3c8ce6dfd3712d77425c005cc9086f3f30d8956e /tests
parent97d647a13920c230a27685992a23679b44b73550 (diff)
downloadredis-19c29b600746b575a7e902b30633b735bbf67c55.tar.gz
Extend client tracking tests (#7998)
Test support for the new map, null and push message types. Map objects are parsed as a list of lists of key value pairs. for instance: user => john password => 123 will be parsed to the following TCL list: {{user john} {password 123}} Also added the following tests: Redirection still works with RESP3 Able to use a RESP3 client as a redirection client No duplicate invalidation messages when turning BCAST mode on after normal tracking Server is able to evacuate enough keys when num of keys surpasses limit by more than defined initial effort Different clients using different protocols can track the same key OPTOUT tests OPTIN tests Clients can redirect to the same connection tracking-redir-broken test HELLO 3 checks Invalidation messages still work when using RESP3, with and without redirection Switching to RESP3 doesn't disturb previous tracked keys Tracking info is correct Flushall and flushdb produce invalidation messages These tests achieve 100% line coverage for tracking.c using lcov.
Diffstat (limited to 'tests')
-rw-r--r--tests/support/redis.tcl27
-rw-r--r--tests/unit/tracking.tcl337
2 files changed, 330 insertions, 34 deletions
diff --git a/tests/support/redis.tcl b/tests/support/redis.tcl
index a90ac7f29..847f68e63 100644
--- a/tests/support/redis.tcl
+++ b/tests/support/redis.tcl
@@ -210,18 +210,45 @@ proc ::redis::redis_multi_bulk_read {id fd} {
return $l
}
+proc ::redis::redis_read_map {id fd} {
+ set count [redis_read_line $fd]
+ if {$count == -1} return {}
+ set l {}
+ set err {}
+ for {set i 0} {$i < $count} {incr i} {
+ if {[catch {
+ set t {}
+ lappend t [redis_read_reply $id $fd] ; # key
+ lappend t [redis_read_reply $id $fd] ; # value
+ lappend l $t
+ } e] && $err eq {}} {
+ set err $e
+ }
+ }
+ if {$err ne {}} {return -code error $err}
+ return $l
+}
+
proc ::redis::redis_read_line fd {
string trim [gets $fd]
}
+proc ::redis::redis_read_null fd {
+ gets $fd
+ return {}
+}
+
proc ::redis::redis_read_reply {id fd} {
set type [read $fd 1]
switch -exact -- $type {
+ _ {redis_read_null $fd}
: -
+ {redis_read_line $fd}
- {return -code error [redis_read_line $fd]}
$ {redis_bulk_read $fd}
+ > -
* {redis_multi_bulk_read $id $fd}
+ % {redis_read_map $id $fd}
default {
if {$type eq {}} {
set ::redis::fd($id) {}
diff --git a/tests/unit/tracking.tcl b/tests/unit/tracking.tcl
index 839b894ea..fc2800791 100644
--- a/tests/unit/tracking.tcl
+++ b/tests/unit/tracking.tcl
@@ -1,26 +1,48 @@
start_server {tags {"tracking"}} {
# Create a deferred client we'll use to redirect invalidation
# messages to.
- set rd1 [redis_deferring_client]
- $rd1 client id
- set redir [$rd1 read]
- $rd1 subscribe __redis__:invalidate
- $rd1 read ; # Consume the SUBSCRIBE reply.
+ set rd_redirection [redis_deferring_client]
+ $rd_redirection client id
+ set redir_id [$rd_redirection read]
+ $rd_redirection subscribe __redis__:invalidate
+ $rd_redirection read ; # Consume the SUBSCRIBE reply.
- # Create another client as well in order to test NOLOOP
- set rd2 [redis_deferring_client]
+ # Create another client that's not used as a redirection client
+ # We should always keep this client's buffer clean
+ set rd [redis_deferring_client]
+
+ # Client to be used for SET and GET commands
+ # We don't read this client's buffer
+ set rd_sg [redis_client]
+
+ proc clean_all {} {
+ uplevel {
+ $rd QUIT
+ $rd_redirection QUIT
+ set rd [redis_deferring_client]
+ set rd_redirection [redis_deferring_client]
+ $rd_redirection client id
+ set redir_id [$rd_redirection read]
+ $rd_redirection subscribe __redis__:invalidate
+ $rd_redirection read ; # Consume the SUBSCRIBE reply.
+ r FLUSHALL
+ r CLIENT TRACKING off
+ r HELLO 2
+ r config set tracking-table-max-keys 1000000
+ }
+ }
test {Clients are able to enable tracking and redirect it} {
- r CLIENT TRACKING on REDIRECT $redir
+ r CLIENT TRACKING on REDIRECT $redir_id
} {*OK}
test {The other connection is able to get invalidations} {
r SET a 1
r SET b 1
r GET a
- r INCR b ; # This key should not be notified, since it wasn't fetched.
- r INCR a
- set keys [lindex [$rd1 read] 2]
+ r INCR b ; # This key should not be notified, since it wasn't fetched.
+ r INCR a
+ set keys [lindex [$rd_redirection read] 2]
assert {[llength $keys] == 1}
assert {[lindex $keys 0] eq {a}}
}
@@ -33,18 +55,18 @@ start_server {tags {"tracking"}} {
}
test {Clients can enable the BCAST mode with the empty prefix} {
- r CLIENT TRACKING on BCAST REDIRECT $redir
+ r CLIENT TRACKING on BCAST REDIRECT $redir_id
} {*OK*}
test {The connection gets invalidation messages about all the keys} {
r MSET a 1 b 2 c 3
- set keys [lsort [lindex [$rd1 read] 2]]
+ set keys [lsort [lindex [$rd_redirection read] 2]]
assert {$keys eq {a b c}}
}
test {Clients can enable the BCAST mode with prefixes} {
r CLIENT TRACKING off
- r CLIENT TRACKING on BCAST REDIRECT $redir PREFIX a: PREFIX b:
+ r CLIENT TRACKING on BCAST REDIRECT $redir_id PREFIX a: PREFIX b:
r MULTI
r INCR a:1
r INCR a:2
@@ -53,64 +75,243 @@ start_server {tags {"tracking"}} {
r EXEC
# Because of the internals, we know we are going to receive
# two separated notifications for the two different prefixes.
- set keys1 [lsort [lindex [$rd1 read] 2]]
- set keys2 [lsort [lindex [$rd1 read] 2]]
+ set keys1 [lsort [lindex [$rd_redirection read] 2]]
+ set keys2 [lsort [lindex [$rd_redirection read] 2]]
set keys [lsort [list {*}$keys1 {*}$keys2]]
assert {$keys eq {a:1 a:2 b:1 b:2}}
}
-
+
test {Adding prefixes to BCAST mode works} {
- r CLIENT TRACKING on BCAST REDIRECT $redir PREFIX c:
+ r CLIENT TRACKING on BCAST REDIRECT $redir_id PREFIX c:
r INCR c:1234
- set keys [lsort [lindex [$rd1 read] 2]]
+ set keys [lsort [lindex [$rd_redirection read] 2]]
assert {$keys eq {c:1234}}
}
test {Tracking NOLOOP mode in standard mode works} {
r CLIENT TRACKING off
- r CLIENT TRACKING on REDIRECT $redir NOLOOP
+ r CLIENT TRACKING on REDIRECT $redir_id NOLOOP
r MGET otherkey1 loopkey otherkey2
- $rd2 SET otherkey1 1; # We should get this
+ $rd_sg SET otherkey1 1; # We should get this
r SET loopkey 1 ; # We should not get this
- $rd2 SET otherkey2 1; # We should get this
+ $rd_sg SET otherkey2 1; # We should get this
# Because of the internals, we know we are going to receive
# two separated notifications for the two different prefixes.
- set keys1 [lsort [lindex [$rd1 read] 2]]
- set keys2 [lsort [lindex [$rd1 read] 2]]
+ set keys1 [lsort [lindex [$rd_redirection read] 2]]
+ set keys2 [lsort [lindex [$rd_redirection read] 2]]
set keys [lsort [list {*}$keys1 {*}$keys2]]
assert {$keys eq {otherkey1 otherkey2}}
}
test {Tracking NOLOOP mode in BCAST mode works} {
r CLIENT TRACKING off
- r CLIENT TRACKING on BCAST REDIRECT $redir NOLOOP
- $rd2 SET otherkey1 1; # We should get this
+ r CLIENT TRACKING on BCAST REDIRECT $redir_id NOLOOP
+ $rd_sg SET otherkey1 1; # We should get this
r SET loopkey 1 ; # We should not get this
- $rd2 SET otherkey2 1; # We should get this
+ $rd_sg SET otherkey2 1; # We should get this
# Because of the internals, we know we are going to receive
# two separated notifications for the two different prefixes.
- set keys1 [lsort [lindex [$rd1 read] 2]]
- set keys2 [lsort [lindex [$rd1 read] 2]]
+ set keys1 [lsort [lindex [$rd_redirection read] 2]]
+ set keys2 [lsort [lindex [$rd_redirection read] 2]]
set keys [lsort [list {*}$keys1 {*}$keys2]]
assert {$keys eq {otherkey1 otherkey2}}
}
test {Tracking gets notification of expired keys} {
r CLIENT TRACKING off
- r CLIENT TRACKING on BCAST REDIRECT $redir NOLOOP
+ r CLIENT TRACKING on BCAST REDIRECT $redir_id NOLOOP
r SET mykey myval px 1
r SET mykeyotherkey myval ; # We should not get it
after 1000
# Because of the internals, we know we are going to receive
# two separated notifications for the two different prefixes.
- set keys1 [lsort [lindex [$rd1 read] 2]]
+ set keys1 [lsort [lindex [$rd_redirection read] 2]]
set keys [lsort [list {*}$keys1]]
assert {$keys eq {mykey}}
}
+ test {HELLO 3 reply is correct} {
+ set reply [r HELLO 3]
+ assert {[lindex $reply 2] eq {proto 3}}
+ }
+
+ test {RESP3 based basic invalidation} {
+ r CLIENT TRACKING off
+ r CLIENT TRACKING on
+ $rd_sg SET key1 1
+ r GET key1
+ $rd_sg SET key1 2
+ r read
+ } {invalidate key1}
+
+ test {RESP3 tracking redirection} {
+ r CLIENT TRACKING off
+ r CLIENT TRACKING on REDIRECT $redir_id
+ $rd_sg SET key1 1
+ r GET key1
+ $rd_sg SET key1 2
+ set res [lindex [$rd_redirection read] 2]
+ assert {$res eq {key1}}
+ }
+
+ test {Invalidations of previous keys can be redirected after switching to RESP3} {
+ $rd_sg SET key1 1
+ r GET key1
+ r HELLO 3
+ $rd_sg SET key1 2
+ set res [lindex [$rd_redirection read] 2]
+ assert {$res eq {key1}}
+ }
+
+ test {Invalidations of new keys can be redirected after switching to RESP3} {
+ r HELLO 3
+ $rd_sg SET key1 1
+ r GET key1
+ $rd_sg SET key1 2
+ set res [lindex [$rd_redirection read] 2]
+ assert {$res eq {key1}}
+ }
+
+ test {RESP3 Client gets tracking-redir-broken push message after cached key changed when rediretion client is terminated} {
+ r CLIENT TRACKING on REDIRECT $redir_id
+ $rd_sg SET key1 1
+ r GET key1
+ $rd_redirection QUIT
+ $rd_sg SET key1 2
+ set MAX_TRIES 100
+ for {set i 0} {$i <= $MAX_TRIES && $res <= 0} {incr i} {
+ set res [lsearch -exact [r PING] "tracking-redir-broken"]
+ }
+ assert {$res >= 0}
+ }
+
+ test {Different clients can redirect to the same connection} {
+ # Reinstantiating after QUIT
+ set rd_redirection [redis_deferring_client]
+ $rd_redirection CLIENT ID
+ set redir_id [$rd_redirection read]
+ $rd_redirection SUBSCRIBE __redis__:invalidate
+ $rd_redirection read ; # Consume the SUBSCRIBE reply
+ r CLIENT TRACKING on REDIRECT $redir_id
+ $rd CLIENT TRACKING on REDIRECT $redir_id
+ $rd read ; # Consume the TRACKING reply
+ $rd_sg MSET key1 1 key2 1
+ r GET key1
+ $rd GET key2
+ $rd read ; # Consume the GET reply
+ $rd_sg INCR key1
+ $rd_sg INCR key2
+ set res1 [lindex [$rd_redirection read] 2]
+ set res2 [lindex [$rd_redirection read] 2]
+ assert {$res1 eq {key1}}
+ assert {$res2 eq {key2}}
+ }
+
+ test {Different clients using different protocols can track the same key} {
+ $rd HELLO 3
+ $rd read ; # Consume the HELLO reply
+ $rd CLIENT TRACKING on
+ $rd read ; # Consume the TRACKING reply
+ $rd_sg set key1 1
+ r GET key1
+ $rd GET key1
+ $rd read ; # Consume the GET reply
+ $rd_sg INCR key1
+ set res1 [lindex [$rd_redirection read] 2]
+ $rd PING ; # Non redirecting client has to talk to the server in order to get invalidation message
+ set res2 [lindex [split [$rd read] " "] 1]
+ $rd read ; # Consume the PING reply, which comes together with the invalidation message
+ assert {$res1 eq {key1}}
+ assert {$res2 eq {key1}}
+ }
+
+ test {No invalidation message when using OPTIN option} {
+ r CLIENT TRACKING on OPTIN REDIRECT $redir_id
+ $rd_sg SET key1 1
+ r GET key1 ; # This key should not be notified, since OPTIN is on and CLIENT CACHING yes wasn't called
+ $rd_sg SET key1 2
+ # Preparing some message to consume on $rd_redirection so we don't get blocked
+ r CLIENT TRACKING off
+ r CLIENT TRACKING on REDIRECT $redir_id
+ $rd_sg SET key2 1
+ r GET key2 ; # This key should be notified
+ $rd_sg SET key2 2
+ set res [lindex [$rd_redirection read] 2]
+ assert {$res eq {key2}}
+ }
+
+ test {Invalidation message sent when using OPTIN option with CLIENT CACHING yes} {
+ r CLIENT TRACKING on OPTIN REDIRECT $redir_id
+ $rd_sg SET key1 3
+ r CLIENT CACHING yes
+ r GET key1
+ $rd_sg SET key1 4
+ set res [lindex [$rd_redirection read] 2]
+ assert {$res eq {key1}}
+ }
+
+ test {Invalidation message sent when using OPTOUT option} {
+ r CLIENT TRACKING off
+ r CLIENT TRACKING on OPTOUT REDIRECT $redir_id
+ $rd_sg SET key1 1
+ r GET key1
+ $rd_sg SET key1 2
+ set res [lindex [$rd_redirection read] 2]
+ assert {$res eq {key1}}
+ }
+
+ test {No invalidation message when using OPTOUT option with CLIENT CACHING no} {
+ $rd_sg SET key1 1
+ r CLIENT CACHING no
+ r GET key1 ; # This key should not be notified, since OPTOUT is on and CLIENT CACHING no was called
+ $rd_sg SET key1 2
+ # Preparing some message to consume on $rd_redirection so we don't get blocked
+ $rd_sg SET key2 1
+ r GET key2 ; # This key should be notified
+ $rd_sg SET key2 2
+ set res [lindex [$rd_redirection read] 2]
+ assert {$res eq {key2}}
+ }
+
+ test {Able to redirect to a RESP3 client} {
+ $rd_redirection UNSUBSCRIBE __redis__:invalidate ; # Need to unsub first before we can do HELLO 3
+ $rd_redirection read ; # Consume the UNSUBSCRIBE reply
+ $rd_redirection HELLO 3
+ $rd_redirection read ; # Consume the HELLO reply
+ $rd_redirection SUBSCRIBE __redis__:invalidate
+ $rd_redirection read ; # Consume the SUBSCRIBE reply
+ r CLIENT TRACKING on REDIRECT $redir_id
+ $rd_sg SET key1 1
+ r GET key1
+ $rd_sg INCR key1
+ set res [lindex [$rd_redirection read] 1]
+ assert {$res eq {key1}}
+ }
+
+ test {After switching from normal tracking to BCAST mode, no invalidation message is produced for pre-BCAST keys} {
+ $rd HELLO 3
+ $rd read ; # Consume the HELLO reply
+ $rd CLIENT TRACKING on
+ $rd read ; # Consume the TRACKING reply
+ $rd_sg SET key1 1
+ $rd GET key1
+ $rd read ; # Consume the GET reply
+ $rd CLIENT TRACKING off
+ $rd read ; # Consume the TRACKING reply
+ $rd CLIENT TRACKING on BCAST
+ $rd read ; # Consume the TRACKING reply
+ $rd_sg INCR key1
+ $rd PING
+ set inv_msg [$rd read]
+ set ping_reply [$rd read]
+ assert {$inv_msg eq {invalidate key1}}
+ assert {$ping_reply eq {PONG}}
+ }
+
test {Tracking gets notification on tracking table key eviction} {
+ $rd_redirection HELLO 2
r CLIENT TRACKING off
- r CLIENT TRACKING on REDIRECT $redir NOLOOP
+ r CLIENT TRACKING on REDIRECT $redir_id NOLOOP
r MSET key1 1 key2 2
# Let the server track the two keys for us
r MGET key1 key2
@@ -122,7 +323,7 @@ start_server {tags {"tracking"}} {
# So we check that eventually we'll receive one or the other key,
# otherwise the test will die for timeout.
while 1 {
- set keys [lindex [$rd1 read] 2]
+ set keys [lindex [$rd_redirection read] 2]
if {$keys eq {key1} || $keys eq {key2}} break
}
# We should receive an expire notification for one of
@@ -130,5 +331,73 @@ start_server {tags {"tracking"}} {
assert {$keys eq {key1} || $keys eq {key2}}
}
- $rd1 close
+ test {Invalidation message received for flushall} {
+ clean_all
+ r CLIENT TRACKING off
+ r CLIENT TRACKING on REDIRECT $redir_id
+ $rd_sg SET key1 1
+ r GET key1
+ $rd_sg FLUSHALL
+ set msg [$rd_redirection read]
+ assert {[lindex msg 2] eq {} }
+ }
+
+ test {Invalidation message received for flushdb} {
+ clean_all
+ r CLIENT TRACKING off
+ r CLIENT TRACKING on REDIRECT $redir_id
+ $rd_sg SET key1 1
+ r GET key1
+ $rd_sg FLUSHDB
+ set msg [$rd_redirection read]
+ assert {[lindex msg 2] eq {} }
+ }
+
+ # Keys are defined to be evicted 100 at a time by default.
+ # If after eviction the number of keys still surpasses the limit
+ # defined in tracking-table-max-keys, we increases eviction
+ # effort to 200, and then 300, etc.
+ # This test tests this effort incrementation.
+ test {Server is able to evacuate enough keys when num of keys surpasses limit by more than defined initial effort} {
+ clean_all
+ set NUM_OF_KEYS_TO_TEST 250
+ set TRACKING_TABLE_MAX_KEYS 1
+ r CLIENT TRACKING on REDIRECT $redir_id
+ for {set i 0} {$i < $NUM_OF_KEYS_TO_TEST} {incr i} {
+ $rd_sg SET key$i $i
+ r GET key$i
+ }
+ r config set tracking-table-max-keys $TRACKING_TABLE_MAX_KEYS
+ # If not enough keys are evicted, we won't get enough invalidation
+ # messages, and "$rd_redirection read" will block.
+ # If too many keys are evicted, we will get too many invalidation
+ # messages, and the assert will fail.
+ for {set i 0} {$i < $NUM_OF_KEYS_TO_TEST - $TRACKING_TABLE_MAX_KEYS} {incr i} {
+ $rd_redirection read
+ }
+ $rd_redirection PING
+ assert {[$rd_redirection read] eq {pong {}}}
+ }
+
+ test {Tracking info is correct} {
+ clean_all
+ r CLIENT TRACKING on REDIRECT $redir_id
+ $rd_sg SET key1 1
+ $rd_sg SET key2 2
+ r GET key1
+ r GET key2
+ $rd CLIENT TRACKING on BCAST PREFIX prefix:
+ $rd_sg SET prefix:key1 1
+ $rd_sg SET prefix:key2 2
+ set info [r info]
+ regexp "\r\ntracking_total_items:(.*?)\r\n" $info _ total_items
+ regexp "\r\ntracking_total_keys:(.*?)\r\n" $info _ total_keys
+ regexp "\r\ntracking_total_prefixes:(.*?)\r\n" $info _ total_prefixes
+ assert {$total_items == 2}
+ assert {$total_keys == 2}
+ assert {$total_prefixes == 1}
+ }
+
+ $rd_redirection close
+ $rd close
}