Commit 72935b9d authored by Vitaly Arbuzov's avatar Vitaly Arbuzov
Browse files

Merge branch 'unstable' into dict-split-by-slot

parents 6baf20af 6948daca
tags {"external:skip"} {
tags {"external:skip logreqres:skip"} {
# Get info about a redis client connection:
# name - name of client we want to query
......
......@@ -12,5 +12,16 @@ start_cluster 2 2 {tags {external:skip cluster}} {
assert_error {ASK*} {R 0 GET FOO}
R 0 ping
} {PONG}
test "Coverage: Basic cluster commands" {
assert_equal {OK} [R 0 CLUSTER saveconfig]
set id [R 0 CLUSTER MYID]
assert_equal {0} [R 0 CLUSTER count-failure-reports $id]
assert_match "*shard-id*" [R 0 CLUSTER slaves $id]
R 0 flushall
assert_equal {OK} [R 0 CLUSTER flushslots]
}
}
......@@ -628,6 +628,9 @@ start_server {tags {"expire"}} {
} {-1} {needs:debug}
test {GETEX propagate as to replica as PERSIST, DEL, or nothing} {
# In the above tests, many keys with random expiration times are set, flush
# the DBs to avoid active expiry kicking in and messing the replication streams.
r flushall
set repl [attach_to_replication_stream]
r set foo bar EX 100
r getex foo PERSIST
......
......@@ -222,6 +222,10 @@ start_server {tags {"geo"}} {
r georadius nyc -73.9798091 40.7598464 3 km asc
} {{central park n/q/r} 4545 {union square}}
test {GEORADIUS_RO simple (sorted)} {
r georadius_ro nyc -73.9798091 40.7598464 3 km asc
} {{central park n/q/r} 4545 {union square}}
test {GEOSEARCH simple (sorted)} {
r geosearch nyc fromlonlat -73.9798091 40.7598464 bybox 6 6 km asc
} {{central park n/q/r} 4545 {union square} {lic market}}
......@@ -263,6 +267,12 @@ start_server {tags {"geo"}} {
r georadius nyc -73.9798091 40.7598464 10 km COUNT 3
} {{central park n/q/r} 4545 {union square}}
test {GEORADIUS with multiple WITH* tokens} {
assert_match {{{central park n/q/r} 1791875761332224 {-73.97334* 40.76480*}} {4545 1791875796750882 {-73.95641* 40.74809*}}} [r georadius nyc -73.9798091 40.7598464 10 km WITHCOORD WITHHASH COUNT 2]
assert_match {{{central park n/q/r} 1791875761332224 {-73.97334* 40.76480*}} {4545 1791875796750882 {-73.95641* 40.74809*}}} [r georadius nyc -73.9798091 40.7598464 10 km WITHHASH WITHCOORD COUNT 2]
assert_match {{{central park n/q/r} 0.7750 1791875761332224 {-73.97334* 40.76480*}} {4545 2.3651 1791875796750882 {-73.95641* 40.74809*}}} [r georadius nyc -73.9798091 40.7598464 10 km WITHDIST WITHHASH WITHCOORD COUNT 2]
}
test {GEORADIUS with ANY not sorted by default} {
r georadius nyc -73.9798091 40.7598464 10 km COUNT 3 ANY
} {{wtc one} {union square} {central park n/q/r}}
......@@ -293,6 +303,10 @@ start_server {tags {"geo"}} {
test {GEORADIUSBYMEMBER simple (sorted)} {
r georadiusbymember nyc "wtc one" 7 km
} {{wtc one} {union square} {central park n/q/r} 4545 {lic market}}
test {GEORADIUSBYMEMBER_RO simple (sorted)} {
r georadiusbymember_ro nyc "wtc one" 7 km
} {{wtc one} {union square} {central park n/q/r} 4545 {lic market}}
test {GEORADIUSBYMEMBER search areas contain satisfied points in oblique direction} {
r del k1
......
......@@ -7,7 +7,7 @@ start_server {tags {"introspection"}} {
test {CLIENT LIST} {
r client list
} {id=* addr=*:* laddr=*:* fd=* name=* age=* idle=* flags=N db=* sub=0 psub=0 ssub=0 multi=-1 qbuf=26 qbuf-free=* argv-mem=* multi-mem=0 rbs=* rbp=* obl=0 oll=0 omem=0 tot-mem=* events=r cmd=client|list user=* redir=-1 resp=2*}
} {id=* addr=*:* laddr=*:* fd=* name=* age=* idle=* flags=N db=* sub=0 psub=0 ssub=0 multi=-1 qbuf=26 qbuf-free=* argv-mem=* multi-mem=0 rbs=* rbp=* obl=0 oll=0 omem=0 tot-mem=* events=r cmd=client|list user=* redir=-1 resp=*}
test {CLIENT LIST with IDs} {
set myid [r client id]
......@@ -17,7 +17,7 @@ start_server {tags {"introspection"}} {
test {CLIENT INFO} {
r client info
} {id=* addr=*:* laddr=*:* fd=* name=* age=* idle=* flags=N db=* sub=0 psub=0 ssub=0 multi=-1 qbuf=26 qbuf-free=* argv-mem=* multi-mem=0 rbs=* rbp=* obl=0 oll=0 omem=0 tot-mem=* events=r cmd=client|info user=* redir=-1 resp=2*}
} {id=* addr=*:* laddr=*:* fd=* name=* age=* idle=* flags=N db=* sub=0 psub=0 ssub=0 multi=-1 qbuf=26 qbuf-free=* argv-mem=* multi-mem=0 rbs=* rbp=* obl=0 oll=0 omem=0 tot-mem=* events=r cmd=client|info user=* redir=-1 resp=*}
test {CLIENT KILL with illegal arguments} {
assert_error "ERR wrong number of arguments for 'client|kill' command" {r client kill}
......@@ -94,6 +94,48 @@ start_server {tags {"introspection"}} {
}
} {} {needs:save}
test "CLIENT REPLY OFF/ON: disable all commands reply" {
set rd [redis_deferring_client]
# These replies were silenced.
$rd client reply off
$rd ping pong
$rd ping pong2
$rd client reply on
assert_equal {OK} [$rd read]
$rd ping pong3
assert_equal {pong3} [$rd read]
$rd close
}
test "CLIENT REPLY SKIP: skip the next command reply" {
set rd [redis_deferring_client]
# The first pong reply was silenced.
$rd client reply skip
$rd ping pong
$rd ping pong2
assert_equal {pong2} [$rd read]
$rd close
}
test "CLIENT REPLY ON: unset SKIP flag" {
set rd [redis_deferring_client]
$rd client reply skip
$rd client reply on
assert_equal {OK} [$rd read] ;# OK from CLIENT REPLY ON command
$rd ping
assert_equal {PONG} [$rd read]
$rd close
}
test {MONITOR can log executed commands} {
set rd [redis_deferring_client]
$rd monitor
......@@ -138,14 +180,22 @@ start_server {tags {"introspection"}} {
r migrate [srv 0 host] [srv 0 port] key 9 5000 AUTH2 user password
catch {r auth not-real} _
catch {r auth not-real not-a-password} _
catch {r hello 2 AUTH not-real not-a-password} _
assert_match {*"key"*"9"*"5000"*} [$rd read]
assert_match {*"key"*"9"*"5000"*"(redacted)"*} [$rd read]
assert_match {*"key"*"9"*"5000"*"(redacted)"*"(redacted)"*} [$rd read]
assert_match {*"auth"*"(redacted)"*} [$rd read]
assert_match {*"auth"*"(redacted)"*"(redacted)"*} [$rd read]
assert_match {*"hello"*"2"*"AUTH"*"(redacted)"*"(redacted)"*} [$rd read]
foreach resp {3 2} {
if {[lsearch $::denytags "resp3"] >= 0} {
if {$resp == 3} {continue}
} elseif {$::force_resp3} {
if {$resp == 2} {continue}
}
catch {r hello $resp AUTH not-real not-a-password} _
assert_match "*\"hello\"*\"$resp\"*\"AUTH\"*\"(redacted)\"*\"(redacted)\"*" [$rd read]
}
$rd close
} {0} {needs:repl}
......@@ -225,6 +275,27 @@ start_server {tags {"introspection"}} {
r client list
} {*name= *}
test {Coverage: Basic CLIENT CACHING} {
set rd_redirection [redis_deferring_client]
$rd_redirection client id
set redir_id [$rd_redirection read]
r CLIENT TRACKING on OPTIN REDIRECT $redir_id
r CLIENT CACHING yes
r CLIENT TRACKING off
} {OK}
test {Coverage: Basic CLIENT REPLY} {
r CLIENT REPLY on
} {OK}
test {Coverage: Basic CLIENT TRACKINGINFO} {
r CLIENT TRACKINGINFO
} {flags off redirect -1 prefixes {}}
test {Coverage: Basic CLIENT GETREDIR} {
r CLIENT GETREDIR
} {-1}
test {CLIENT SETNAME does not accept spaces} {
catch {r client setname "foo bar"} e
set e
......@@ -325,6 +396,8 @@ start_server {tags {"introspection"}} {
logfile
dir
socket-mark-id
req-res-logfile
client-default-resp
}
if {!$::tls} {
......
......@@ -71,6 +71,7 @@ start_server {tags {"latency-monitor needs:latency"}} {
assert {[string length [r latency histogram blabla set get]] > 0}
}
tags {"needs:debug"} {
test {Test latency events logging} {
r debug sleep 0.3
after 1100
......@@ -78,7 +79,7 @@ start_server {tags {"latency-monitor needs:latency"}} {
after 1100
r debug sleep 0.5
assert {[r latency history command] >= 3}
} {} {needs:debug}
}
test {LATENCY HISTORY output is ok} {
set min 250
......@@ -106,6 +107,18 @@ start_server {tags {"latency-monitor needs:latency"}} {
}
}
test {LATENCY GRAPH can output the event graph} {
set res [r latency graph command]
assert_match {*command*high*low*} $res
# These numbers are taken from the "Test latency events logging" test.
# (debug sleep 0.3) and (debug sleep 0.5), using range to prevent timing issue.
regexp "command - high (.*?) ms, low (.*?) ms" $res -> high low
assert_morethan_equal $high 500
assert_morethan_equal $low 300
}
} ;# tag
test {LATENCY of expire events are correctly collected} {
r config set latency-monitor-threshold 20
r flushdb
......@@ -124,6 +137,11 @@ start_server {tags {"latency-monitor needs:latency"}} {
fail "key wasn't expired"
}
assert_match {*expire-cycle*} [r latency latest]
test {LATENCY GRAPH can output the expire event graph} {
assert_match {*expire-cycle*high*low*} [r latency graph expire-cycle]
}
r config set latency-monitor-threshold 200
}
......
......@@ -92,6 +92,45 @@ start_server {tags {"modules acl"}} {
assert {[dict get $entry reason] eq {command}}
}
test {test blocking of Commands outside of OnLoad} {
assert_equal [r block.commands.outside.onload] OK
}
test {test users to have access to module commands having acl categories} {
r acl SETUSER j1 on >password -@all +@WRITE
r acl SETUSER j2 on >password -@all +@READ
assert_equal [r acl DRYRUN j1 aclcheck.module.command.aclcategories.write] OK
assert_equal [r acl DRYRUN j2 aclcheck.module.command.aclcategories.write.function.read.category] OK
assert_equal [r acl DRYRUN j2 aclcheck.module.command.aclcategories.read.only.category] OK
}
test {test existing users to have access to module commands loaded on runtime} {
assert_equal [r module unload aclcheck] OK
r acl SETUSER j3 on >password -@all +@WRITE
assert_equal [r module load $testmodule] OK
assert_equal [r acl DRYRUN j3 aclcheck.module.command.aclcategories.write] OK
}
test {test existing users without permissions, do not have access to module commands loaded on runtime.} {
assert_equal [r module unload aclcheck] OK
r acl SETUSER j4 on >password -@all +@READ
r acl SETUSER j5 on >password -@all +@WRITE
assert_equal [r module load $testmodule] OK
catch {r acl DRYRUN j4 aclcheck.module.command.aclcategories.write} e
assert_equal {User j4 has no permissions to run the 'aclcheck.module.command.aclcategories.write' command} $e
catch {r acl DRYRUN j5 aclcheck.module.command.aclcategories.write.function.read.category} e
assert_equal {User j5 has no permissions to run the 'aclcheck.module.command.aclcategories.write.function.read.category' command} $e
}
test {test users without permissions, do not have access to module commands.} {
r acl SETUSER j6 on >password -@all +@READ
catch {r acl DRYRUN j6 aclcheck.module.command.aclcategories.write} e
assert_equal {User j6 has no permissions to run the 'aclcheck.module.command.aclcategories.write' command} $e
r acl SETUSER j7 on >password -@all +@WRITE
catch {r acl DRYRUN j7 aclcheck.module.command.aclcategories.write.function.read.category} e
assert_equal {User j7 has no permissions to run the 'aclcheck.module.command.aclcategories.write.function.read.category' command} $e
}
test "Unload the module - aclcheck" {
assert_equal {OK} [r module unload aclcheck]
}
......
set testmodule [file normalize tests/modules/blockedclient.so]
set testmodule2 [file normalize tests/modules/postnotifications.so]
set testmodule3 [file normalize tests/modules/blockonkeys.so]
start_server {tags {"modules"}} {
r module load $testmodule
test {Locked GIL acquisition from async RM_Call} {
assert_equal {OK} [r do_rm_call_async acquire_gil]
}
test "Blpop on async RM_Call fire and forget" {
assert_equal {Blocked} [r do_rm_call_fire_and_forget blpop l 0]
r lpush l a
assert_equal {0} [r llen l]
}
foreach cmd {do_rm_call_async do_rm_call_async_script_mode} {
test "Blpop on async RM_Call using $cmd" {
set rd [redis_deferring_client]
$rd $cmd blpop l 0
wait_for_blocked_clients_count 1
r lpush l a
assert_equal [$rd read] {l a}
wait_for_blocked_clients_count 0
}
test "Brpop on async RM_Call using $cmd" {
set rd [redis_deferring_client]
$rd $cmd brpop l 0
wait_for_blocked_clients_count 1
r lpush l a
assert_equal [$rd read] {l a}
wait_for_blocked_clients_count 0
}
test "Brpoplpush on async RM_Call using $cmd" {
set rd [redis_deferring_client]
$rd $cmd brpoplpush l1 l2 0
wait_for_blocked_clients_count 1
r lpush l1 a
assert_equal [$rd read] {a}
wait_for_blocked_clients_count 0
r lpop l2
} {a}
test "Blmove on async RM_Call using $cmd" {
set rd [redis_deferring_client]
$rd $cmd blmove l1 l2 LEFT LEFT 0
wait_for_blocked_clients_count 1
r lpush l1 a
assert_equal [$rd read] {a}
wait_for_blocked_clients_count 0
r lpop l2
} {a}
test "Bzpopmin on async RM_Call using $cmd" {
set rd [redis_deferring_client]
$rd $cmd bzpopmin s 0
wait_for_blocked_clients_count 1
r zadd s 10 foo
assert_equal [$rd read] {s foo 10}
wait_for_blocked_clients_count 0
}
test "Bzpopmax on async RM_Call using $cmd" {
set rd [redis_deferring_client]
$rd $cmd bzpopmax s 0
wait_for_blocked_clients_count 1
r zadd s 10 foo
assert_equal [$rd read] {s foo 10}
wait_for_blocked_clients_count 0
}
}
test {Nested async RM_Call} {
set rd [redis_deferring_client]
$rd do_rm_call_async do_rm_call_async do_rm_call_async do_rm_call_async blpop l 0
wait_for_blocked_clients_count 1
r lpush l a
assert_equal [$rd read] {l a}
wait_for_blocked_clients_count 0
}
test {Test multiple async RM_Call waiting on the same event} {
set rd1 [redis_deferring_client]
set rd2 [redis_deferring_client]
$rd1 do_rm_call_async do_rm_call_async do_rm_call_async do_rm_call_async blpop l 0
$rd2 do_rm_call_async do_rm_call_async do_rm_call_async do_rm_call_async blpop l 0
wait_for_blocked_clients_count 2
r lpush l element element
assert_equal [$rd1 read] {l element}
assert_equal [$rd2 read] {l element}
wait_for_blocked_clients_count 0
}
test {async RM_Call calls RM_Call} {
assert_equal {PONG} [r do_rm_call_async do_rm_call ping]
}
test {async RM_Call calls background RM_Call calls RM_Call} {
assert_equal {PONG} [r do_rm_call_async do_bg_rm_call do_rm_call ping]
}
test {async RM_Call calls background RM_Call calls RM_Call calls async RM_Call} {
assert_equal {PONG} [r do_rm_call_async do_bg_rm_call do_rm_call do_rm_call_async ping]
}
test {async RM_Call inside async RM_Call callback} {
set rd [redis_deferring_client]
$rd wait_and_do_rm_call blpop l 0
wait_for_blocked_clients_count 1
start_server {} {
test "Connect a replica to the master instance" {
r slaveof [srv -1 host] [srv -1 port]
wait_for_condition 50 100 {
[s role] eq {slave} &&
[string match {*master_link_status:up*} [r info replication]]
} else {
fail "Can't turn the instance into a replica"
}
}
assert_equal {1} [r -1 lpush l a]
assert_equal [$rd read] {l a}
}
wait_for_blocked_clients_count 0
}
test {Become replica while having async RM_Call running} {
r flushall
set rd [redis_deferring_client]
$rd do_rm_call_async blpop l 0
wait_for_blocked_clients_count 1
#become a replica of a not existing redis
r replicaof localhost 30000
catch {[$rd read]} e
assert_match {UNBLOCKED force unblock from blocking operation*} $e
wait_for_blocked_clients_count 0
r replicaof no one
r lpush l 1
# make sure the async rm_call was aborted
assert_equal [r llen l] {1}
}
test {Pipeline with blocking RM_Call} {
r flushall
set rd [redis_deferring_client]
set buf ""
append buf "do_rm_call_async blpop l 0\r\n"
append buf "ping\r\n"
$rd write $buf
$rd flush
wait_for_blocked_clients_count 1
# release the blocked client
r lpush l 1
assert_equal [$rd read] {l 1}
assert_equal [$rd read] {PONG}
wait_for_blocked_clients_count 0
}
test {blocking RM_Call abort} {
r flushall
set rd [redis_deferring_client]
$rd client id
set client_id [$rd read]
$rd do_rm_call_async blpop l 0
wait_for_blocked_clients_count 1
r client kill ID $client_id
assert_error {*error reading reply*} {$rd read}
wait_for_blocked_clients_count 0
r lpush l 1
# make sure the async rm_call was aborted
assert_equal [r llen l] {1}
}
}
start_server {tags {"modules"}} {
r module load $testmodule
test {Test basic replication stream on unblock handler} {
r flushall
set repl [attach_to_replication_stream]
set rd [redis_deferring_client]
$rd do_rm_call_async blpop l 0
wait_for_blocked_clients_count 1
r lpush l a
assert_equal [$rd read] {l a}
assert_replication_stream $repl {
{select *}
{lpush l a}
{lpop l}
}
close_replication_stream $repl
wait_for_blocked_clients_count 0
}
test {Test unblock handler are executed as a unit} {
r flushall
set repl [attach_to_replication_stream]
set rd [redis_deferring_client]
$rd blpop_and_set_multiple_keys l x 1 y 2
wait_for_blocked_clients_count 1
r lpush l a
assert_equal [$rd read] {OK}
assert_replication_stream $repl {
{select *}
{lpush l a}
{multi}
{lpop l}
{set x 1}
{set y 2}
{exec}
}
close_replication_stream $repl
wait_for_blocked_clients_count 0
}
test {Test no propagation of blocking command} {
r flushall
set repl [attach_to_replication_stream]
set rd [redis_deferring_client]
$rd do_rm_call_async_no_replicate blpop l 0
wait_for_blocked_clients_count 1
r lpush l a
assert_equal [$rd read] {l a}
# make sure the lpop are not replicated
r set x 1
assert_replication_stream $repl {
{select *}
{lpush l a}
{set x 1}
}
close_replication_stream $repl
wait_for_blocked_clients_count 0
}
}
start_server {tags {"modules"}} {
r module load $testmodule
r module load $testmodule2
test {Test unblock handler are executed as a unit with key space notifications} {
r flushall
set repl [attach_to_replication_stream]
set rd [redis_deferring_client]
$rd blpop_and_set_multiple_keys l string_foo 1 string_bar 2
wait_for_blocked_clients_count 1
r lpush l a
assert_equal [$rd read] {OK}
assert_replication_stream $repl {
{select *}
{lpush l a}
{multi}
{lpop l}
{set string_foo 1}
{set string_bar 2}
{incr string_changed{string_foo}}
{incr string_changed{string_bar}}
{incr string_total}
{incr string_total}
{exec}
}
close_replication_stream $repl
wait_for_blocked_clients_count 0
}
test {Test unblock handler are executed as a unit with lazy expire} {
r flushall
r DEBUG SET-ACTIVE-EXPIRE 0
set repl [attach_to_replication_stream]
set rd [redis_deferring_client]
$rd blpop_and_set_multiple_keys l string_foo 1 string_bar 2
wait_for_blocked_clients_count 1
r lpush l a
assert_equal [$rd read] {OK}
# set expiration on string_foo
r pexpire string_foo 1
after 10
# now the key should have been expired
$rd blpop_and_set_multiple_keys l string_foo 1 string_bar 2
wait_for_blocked_clients_count 1
r lpush l a
assert_equal [$rd read] {OK}
assert_replication_stream $repl {
{select *}
{lpush l a}
{multi}
{lpop l}
{set string_foo 1}
{set string_bar 2}
{incr string_changed{string_foo}}
{incr string_changed{string_bar}}
{incr string_total}
{incr string_total}
{exec}
{pexpireat string_foo *}
{lpush l a}
{multi}
{lpop l}
{del string_foo}
{set string_foo 1}
{set string_bar 2}
{incr expired}
{incr string_changed{string_foo}}
{incr string_changed{string_bar}}
{incr string_total}
{incr string_total}
{exec}
}
close_replication_stream $repl
r DEBUG SET-ACTIVE-EXPIRE 1
}
wait_for_blocked_clients_count 0
}
start_server {tags {"modules"}} {
r module load $testmodule
r module load $testmodule3
test {Test unblock handler on module blocked on keys} {
set rd [redis_deferring_client]
r fsl.push l 1
$rd do_rm_call_async FSL.BPOPGT l 3 0
wait_for_blocked_clients_count 1
r fsl.push l 2
r fsl.push l 3
r fsl.push l 4
assert_equal [$rd read] {4}
wait_for_blocked_clients_count 0
}
}
\ No newline at end of file
......@@ -21,12 +21,17 @@ start_server {tags {"modules"}} {
}
test {test get resp} {
r hello 2
set reply [r test.getresp]
assert_equal $reply 2
r hello 3
set reply [r test.getresp]
assert_equal $reply 3
foreach resp {3 2} {
if {[lsearch $::denytags "resp3"] >= 0} {
if {$resp == 3} {continue}
} elseif {$::force_resp3} {
if {$resp == 2} {continue}
}
r hello $resp
set reply [r test.getresp]
assert_equal $reply $resp
r hello 2
}
}
test "Unload the module - test" {
......
......@@ -91,6 +91,11 @@ start_server {tags {"modules"}} {
test {RESP version carries through to blocked client} {
for {set client_proto 2} {$client_proto <= 3} {incr client_proto} {
if {[lsearch $::denytags "resp3"] >= 0} {
if {$client_proto == 3} {continue}
} elseif {$::force_resp3} {
if {$client_proto == 2} {continue}
}
r hello $client_proto
r readraw 1
set ret [r do_fake_bg_true]
......@@ -100,6 +105,7 @@ start_server {tags {"modules"}} {
assert_equal $ret "#t"
}
r readraw 0
r hello 2
}
}
......
......@@ -286,4 +286,21 @@ start_server {tags {"modules"}} {
assert_equal {gg ff ee dd cc} [$rd read]
$rd close
}
test {Module explicit unblock when blocked on keys} {
r del k
r set somekey someval
# Module client blocks to pop 5 elements from list
set rd [redis_deferring_client]
$rd blockonkeys.blpopn_or_unblock k 5 0
wait_for_blocked_clients_count 1
# will now cause the module to trigger pop but instead will unblock the client from the reply_callback
r lpush k dd
# we should still get unblocked as the command should not reprocess
wait_for_blocked_clients_count 0
assert_equal {Action aborted} [$rd read]
$rd get somekey
assert_equal {someval} [$rd read]
$rd close
}
}
......@@ -37,6 +37,9 @@ start_server {tags {"modules"}} {
dict unset redis_reply group
dict unset module_reply group
dict unset module_reply module
if {$::log_req_res} {
dict unset redis_reply reply_schema
}
assert_equal $redis_reply $module_reply
}
......
......@@ -116,3 +116,28 @@ test {RM_CommandFilterArgInsert and script argv caching} {
}
}
# previously, there was a bug that command filters would be rerun (which would cause args to swap back)
# this test is meant to protect against that bug
test {Blocking Commands don't run through command filter when reprocessed} {
start_server {tags {"modules"}} {
r module load $testmodule log-key 0
r del list1{t}
r del list2{t}
r lpush list2{t} a b c d e
set rd [redis_deferring_client]
# we're asking to pop from the left, but the command filter swaps the two arguments,
# if it didn't swap it, we would end up with e d c b a 5 (5 being the left most of the following lpush)
# but since we swap the arguments, we end up with 1 e d c b a (1 being the right most of it).
# if the command filter would run again on unblock, they would be swapped back.
$rd blmove list1{t} list2{t} left right 0
wait_for_blocked_client
r lpush list1{t} 1 2 3 4 5
# validate that we moved the correct element with the swapped args
assert_equal [$rd read] 1
# validate that we moved the correct elements to the correct side of the list
assert_equal [r lpop list2{t}] 1
}
}
......@@ -8,6 +8,10 @@ start_server {tags {"modules"}} {
assert {[r datatype.get dtkey] eq {100 stringval}}
}
test {test blocking of datatype creation outside of OnLoad} {
assert_equal [r block.create.datatype.outside.onload] OK
}
test {DataType: RM_SaveDataTypeToString(), RM_LoadDataTypeFromStringEncver() work} {
r datatype.set dtkey -1111 MyString
set encoded [r datatype.dump dtkey]
......
set testmodule [file normalize tests/modules/auth.so]
set testmoduletwo [file normalize tests/modules/moduleauthtwo.so]
set miscmodule [file normalize tests/modules/misc.so]
proc cmdstat {cmd} {
return [cmdrstat $cmd r]
}
start_server {tags {"modules"}} {
r module load $testmodule
r module load $testmoduletwo
set hello2_response [r HELLO 2]
set hello3_response [r HELLO 3]
test {test registering module auth callbacks} {
assert_equal {OK} [r testmoduleone.rm_register_blocking_auth_cb]
assert_equal {OK} [r testmoduletwo.rm_register_auth_cb]
assert_equal {OK} [r testmoduleone.rm_register_auth_cb]
}
test {test module AUTH for non existing / disabled users} {
r config resetstat
# Validate that an error is thrown for non existing users.
assert_error {*WRONGPASS*} {r AUTH foo pwd}
assert_match {*calls=1,*,rejected_calls=0,failed_calls=1} [cmdstat auth]
# Validate that an error is thrown for disabled users.
r acl setuser foo >pwd off ~* &* +@all
assert_error {*WRONGPASS*} {r AUTH foo pwd}
assert_match {*calls=2,*,rejected_calls=0,failed_calls=2} [cmdstat auth]
}
test {test non blocking module AUTH} {
r config resetstat
# Test for a fixed password user
r acl setuser foo >pwd on ~* &* +@all
assert_equal {OK} [r AUTH foo allow]
assert_error {*Auth denied by Misc Module*} {r AUTH foo deny}
assert_match {*calls=2,*,rejected_calls=0,failed_calls=1} [cmdstat auth]
assert_error {*WRONGPASS*} {r AUTH foo nomatch}
assert_match {*calls=3,*,rejected_calls=0,failed_calls=2} [cmdstat auth]
assert_equal {OK} [r AUTH foo pwd]
# Test for No Pass user
r acl setuser foo on ~* &* +@all nopass
assert_equal {OK} [r AUTH foo allow]
assert_error {*Auth denied by Misc Module*} {r AUTH foo deny}
assert_match {*calls=6,*,rejected_calls=0,failed_calls=3} [cmdstat auth]
assert_equal {OK} [r AUTH foo nomatch]
# Validate that the Module added an ACL Log entry.
set entry [lindex [r ACL LOG] 0]
assert {[dict get $entry username] eq {foo}}
assert {[dict get $entry context] eq {module}}
assert {[dict get $entry reason] eq {auth}}
assert {[dict get $entry object] eq {Module Auth}}
assert_match {*cmd=auth*} [dict get $entry client-info]
r ACL LOG RESET
}
test {test non blocking module HELLO AUTH} {
r config resetstat
r acl setuser foo >pwd on ~* &* +@all
# Validate proto 2 and 3 in case of success
assert_equal $hello2_response [r HELLO 2 AUTH foo pwd]
assert_equal $hello2_response [r HELLO 2 AUTH foo allow]
assert_equal $hello3_response [r HELLO 3 AUTH foo pwd]
assert_equal $hello3_response [r HELLO 3 AUTH foo allow]
# Validate denying AUTH for the HELLO cmd
assert_error {*Auth denied by Misc Module*} {r HELLO 2 AUTH foo deny}
assert_match {*calls=5,*,rejected_calls=0,failed_calls=1} [cmdstat hello]
assert_error {*WRONGPASS*} {r HELLO 2 AUTH foo nomatch}
assert_match {*calls=6,*,rejected_calls=0,failed_calls=2} [cmdstat hello]
assert_error {*Auth denied by Misc Module*} {r HELLO 3 AUTH foo deny}
assert_match {*calls=7,*,rejected_calls=0,failed_calls=3} [cmdstat hello]
assert_error {*WRONGPASS*} {r HELLO 3 AUTH foo nomatch}
assert_match {*calls=8,*,rejected_calls=0,failed_calls=4} [cmdstat hello]
# Validate that the Module added an ACL Log entry.
set entry [lindex [r ACL LOG] 1]
assert {[dict get $entry username] eq {foo}}
assert {[dict get $entry context] eq {module}}
assert {[dict get $entry reason] eq {auth}}
assert {[dict get $entry object] eq {Module Auth}}
assert_match {*cmd=hello*} [dict get $entry client-info]
r ACL LOG RESET
}
test {test non blocking module HELLO AUTH SETNAME} {
r config resetstat
r acl setuser foo >pwd on ~* &* +@all
# Validate clientname is set on success
assert_equal $hello2_response [r HELLO 2 AUTH foo pwd setname client1]
assert {[r client getname] eq {client1}}
assert_equal $hello2_response [r HELLO 2 AUTH foo allow setname client2]
assert {[r client getname] eq {client2}}
# Validate clientname is not updated on failure
r client setname client0
assert_error {*Auth denied by Misc Module*} {r HELLO 2 AUTH foo deny setname client1}
assert {[r client getname] eq {client0}}
assert_match {*calls=3,*,rejected_calls=0,failed_calls=1} [cmdstat hello]
assert_error {*WRONGPASS*} {r HELLO 2 AUTH foo nomatch setname client2}
assert {[r client getname] eq {client0}}
assert_match {*calls=4,*,rejected_calls=0,failed_calls=2} [cmdstat hello]
}
test {test blocking module AUTH} {
r config resetstat
# Test for a fixed password user
r acl setuser foo >pwd on ~* &* +@all
assert_equal {OK} [r AUTH foo block_allow]
assert_error {*Auth denied by Misc Module*} {r AUTH foo block_deny}
assert_match {*calls=2,*,rejected_calls=0,failed_calls=1} [cmdstat auth]
assert_error {*WRONGPASS*} {r AUTH foo nomatch}
assert_match {*calls=3,*,rejected_calls=0,failed_calls=2} [cmdstat auth]
assert_equal {OK} [r AUTH foo pwd]
# Test for No Pass user
r acl setuser foo on ~* &* +@all nopass
assert_equal {OK} [r AUTH foo block_allow]
assert_error {*Auth denied by Misc Module*} {r AUTH foo block_deny}
assert_match {*calls=6,*,rejected_calls=0,failed_calls=3} [cmdstat auth]
assert_equal {OK} [r AUTH foo nomatch]
# Validate that every Blocking AUTH command took at least 500000 usec.
set stats [cmdstat auth]
regexp "usec_per_call=(\[0-9]{1,})\.*," $stats all usec_per_call
assert {$usec_per_call >= 500000}
# Validate that the Module added an ACL Log entry.
set entry [lindex [r ACL LOG] 0]
assert {[dict get $entry username] eq {foo}}
assert {[dict get $entry context] eq {module}}
assert {[dict get $entry reason] eq {auth}}
assert {[dict get $entry object] eq {Module Auth}}
assert_match {*cmd=auth*} [dict get $entry client-info]
r ACL LOG RESET
}
test {test blocking module HELLO AUTH} {
r config resetstat
r acl setuser foo >pwd on ~* &* +@all
# validate proto 2 and 3 in case of success
assert_equal $hello2_response [r HELLO 2 AUTH foo pwd]
assert_equal $hello2_response [r HELLO 2 AUTH foo block_allow]
assert_equal $hello3_response [r HELLO 3 AUTH foo pwd]
assert_equal $hello3_response [r HELLO 3 AUTH foo block_allow]
# validate denying AUTH for the HELLO cmd
assert_error {*Auth denied by Misc Module*} {r HELLO 2 AUTH foo block_deny}
assert_match {*calls=5,*,rejected_calls=0,failed_calls=1} [cmdstat hello]
assert_error {*WRONGPASS*} {r HELLO 2 AUTH foo nomatch}
assert_match {*calls=6,*,rejected_calls=0,failed_calls=2} [cmdstat hello]
assert_error {*Auth denied by Misc Module*} {r HELLO 3 AUTH foo block_deny}
assert_match {*calls=7,*,rejected_calls=0,failed_calls=3} [cmdstat hello]
assert_error {*WRONGPASS*} {r HELLO 3 AUTH foo nomatch}
assert_match {*calls=8,*,rejected_calls=0,failed_calls=4} [cmdstat hello]
# Validate that every HELLO AUTH command took at least 500000 usec.
set stats [cmdstat hello]
regexp "usec_per_call=(\[0-9]{1,})\.*," $stats all usec_per_call
assert {$usec_per_call >= 500000}
# Validate that the Module added an ACL Log entry.
set entry [lindex [r ACL LOG] 1]
assert {[dict get $entry username] eq {foo}}
assert {[dict get $entry context] eq {module}}
assert {[dict get $entry reason] eq {auth}}
assert {[dict get $entry object] eq {Module Auth}}
assert_match {*cmd=hello*} [dict get $entry client-info]
r ACL LOG RESET
}
test {test blocking module HELLO AUTH SETNAME} {
r config resetstat
r acl setuser foo >pwd on ~* &* +@all
# Validate clientname is set on success
assert_equal $hello2_response [r HELLO 2 AUTH foo pwd setname client1]
assert {[r client getname] eq {client1}}
assert_equal $hello2_response [r HELLO 2 AUTH foo block_allow setname client2]
assert {[r client getname] eq {client2}}
# Validate clientname is not updated on failure
r client setname client0
assert_error {*Auth denied by Misc Module*} {r HELLO 2 AUTH foo block_deny setname client1}
assert {[r client getname] eq {client0}}
assert_match {*calls=3,*,rejected_calls=0,failed_calls=1} [cmdstat hello]
assert_error {*WRONGPASS*} {r HELLO 2 AUTH foo nomatch setname client2}
assert {[r client getname] eq {client0}}
assert_match {*calls=4,*,rejected_calls=0,failed_calls=2} [cmdstat hello]
# Validate that every HELLO AUTH SETNAME command took at least 500000 usec.
set stats [cmdstat hello]
regexp "usec_per_call=(\[0-9]{1,})\.*," $stats all usec_per_call
assert {$usec_per_call >= 500000}
}
test {test AUTH after registering multiple module auth callbacks} {
r config resetstat
# Register two more callbacks from the same module.
assert_equal {OK} [r testmoduleone.rm_register_blocking_auth_cb]
assert_equal {OK} [r testmoduleone.rm_register_auth_cb]
# Register another module auth callback from the second module.
assert_equal {OK} [r testmoduletwo.rm_register_auth_cb]
r acl setuser foo >pwd on ~* &* +@all
# Case 1 - Non Blocking Success
assert_equal {OK} [r AUTH foo allow]
# Case 2 - Non Blocking Deny
assert_error {*Auth denied by Misc Module*} {r AUTH foo deny}
assert_match {*calls=2,*,rejected_calls=0,failed_calls=1} [cmdstat auth]
r config resetstat
# Case 3 - Blocking Success
assert_equal {OK} [r AUTH foo block_allow]
# Case 4 - Blocking Deny
assert_error {*Auth denied by Misc Module*} {r AUTH foo block_deny}
assert_match {*calls=2,*,rejected_calls=0,failed_calls=1} [cmdstat auth]
# Validate that every Blocking AUTH command took at least 500000 usec.
set stats [cmdstat auth]
regexp "usec_per_call=(\[0-9]{1,})\.*," $stats all usec_per_call
assert {$usec_per_call >= 500000}
r config resetstat
# Case 5 - Non Blocking Success via the second module.
assert_equal {OK} [r AUTH foo allow_two]
# Case 6 - Non Blocking Deny via the second module.
assert_error {*Auth denied by Misc Module*} {r AUTH foo deny_two}
assert_match {*calls=2,*,rejected_calls=0,failed_calls=1} [cmdstat auth]
r config resetstat
# Case 7 - All four auth callbacks "Skip" by not explicitly allowing or denying.
assert_error {*WRONGPASS*} {r AUTH foo nomatch}
assert_match {*calls=1,*,rejected_calls=0,failed_calls=1} [cmdstat auth]
assert_equal {OK} [r AUTH foo pwd]
# Because we had to attempt all 4 callbacks, validate that the AUTH command took at least
# 1000000 usec (each blocking callback takes 500000 usec).
set stats [cmdstat auth]
regexp "usec_per_call=(\[0-9]{1,})\.*," $stats all usec_per_call
assert {$usec_per_call >= 1000000}
}
test {module auth during blocking module auth} {
r config resetstat
r acl setuser foo >pwd on ~* &* +@all
set rd [redis_deferring_client]
set rd_two [redis_deferring_client]
# Attempt blocking module auth. While this ongoing, attempt non blocking module auth from
# moduleone/moduletwo and start another blocking module auth from another deferring client.
$rd AUTH foo block_allow
wait_for_blocked_clients_count 1
assert_equal {OK} [r AUTH foo allow]
assert_equal {OK} [r AUTH foo allow_two]
# Validate that the non blocking module auth cmds finished before any blocking module auth.
set info_clients [r info clients]
assert_match "*blocked_clients:1*" $info_clients
$rd_two AUTH foo block_allow
# Validate that all of the AUTH commands succeeded.
wait_for_blocked_clients_count 0 500 10
$rd flush
assert_equal [$rd read] "OK"
$rd_two flush
assert_equal [$rd_two read] "OK"
assert_match {*calls=4,*,rejected_calls=0,failed_calls=0} [cmdstat auth]
}
test {module auth inside MULTI EXEC} {
r config resetstat
r acl setuser foo >pwd on ~* &* +@all
# Validate that non blocking module auth inside MULTI succeeds.
r multi
r AUTH foo allow
assert_equal {OK} [r exec]
# Validate that blocking module auth inside MULTI throws an err.
r multi
r AUTH foo block_allow
assert_error {*ERR Blocking module command called from transaction*} {r exec}
assert_match {*calls=2,*,rejected_calls=0,failed_calls=1} [cmdstat auth]
}
test {Disabling Redis User during blocking module auth} {
r config resetstat
r acl setuser foo >pwd on ~* &* +@all
set rd [redis_deferring_client]
# Attempt blocking module auth and disable the Redis user while module auth is in progress.
$rd AUTH foo pwd
wait_for_blocked_clients_count 1
r acl setuser foo >pwd off ~* &* +@all
# Validate that module auth failed.
wait_for_blocked_clients_count 0 500 10
$rd flush
assert_error {*WRONGPASS*} { $rd read }
assert_match {*calls=1,*,rejected_calls=0,failed_calls=1} [cmdstat auth]
}
test {Killing a client in the middle of blocking module auth} {
r config resetstat
r acl setuser foo >pwd on ~* &* +@all
set rd [redis_deferring_client]
$rd client id
set cid [$rd read]
# Attempt blocking module auth command on client `cid` and kill the client while module auth
# is in progress.
$rd AUTH foo pwd
wait_for_blocked_clients_count 1
r client kill id $cid
# Validate that the blocked client count goes to 0 and no AUTH command is tracked.
wait_for_blocked_clients_count 0 500 10
$rd flush
assert_error {*I/O error reading reply*} { $rd read }
assert_match {} [cmdstat auth]
}
test {test RM_AbortBlock Module API during blocking module auth} {
r config resetstat
r acl setuser foo >pwd on ~* &* +@all
# Attempt module auth. With the "block_abort" as the password, the "testacl.so" module
# blocks the client and uses the RM_AbortBlock API. This should result in module auth
# failing and the client being unblocked with the default AUTH err message.
assert_error {*WRONGPASS*} {r AUTH foo block_abort}
assert_match {*calls=1,*,rejected_calls=0,failed_calls=1} [cmdstat auth]
}
test {test RM_RegisterAuthCallback Module API during blocking module auth} {
r config resetstat
r acl setuser foo >defaultpwd on ~* &* +@all
set rd [redis_deferring_client]
# Start the module auth attempt with the standard Redis auth password for the user. This
# will result in all module auth cbs attempted and then standard Redis auth will be tried.
$rd AUTH foo defaultpwd
wait_for_blocked_clients_count 1
# Validate that we allow modules to register module auth cbs while module auth is already
# in progress.
assert_equal {OK} [r testmoduleone.rm_register_blocking_auth_cb]
assert_equal {OK} [r testmoduletwo.rm_register_auth_cb]
# Validate that blocking module auth succeeds.
wait_for_blocked_clients_count 0 500 10
$rd flush
assert_equal [$rd read] "OK"
set stats [cmdstat auth]
assert_match {*calls=1,*,rejected_calls=0,failed_calls=0} $stats
# Validate that even the new blocking module auth cb which was registered in the middle of
# blocking module auth is attempted - making it take twice the duration (2x 500000 us).
regexp "usec_per_call=(\[0-9]{1,})\.*," $stats all usec_per_call
assert {$usec_per_call >= 1000000}
}
test {Module unload during blocking module auth} {
r config resetstat
r module load $miscmodule
set rd [redis_deferring_client]
r acl setuser foo >pwd on ~* &* +@all
# Start a blocking module auth attempt.
$rd AUTH foo block_allow
wait_for_blocked_clients_count 1
# moduleone and moduletwo have module auth cbs registered. Because blocking module auth is
# ongoing, they cannot be unloaded.
catch {r module unload testacl} e
assert_match {*the module has blocked clients*} $e
# The moduleauthtwo module can be unregistered because no client is blocked on it.
assert_equal "OK" [r module unload moduleauthtwo]
# The misc module does not have module auth cbs registered, so it can be unloaded even when
# blocking module auth is ongoing.
assert_equal "OK" [r module unload misc]
# Validate that blocking module auth succeeds.
wait_for_blocked_clients_count 0 500 10
$rd flush
assert_equal [$rd read] "OK"
assert_match {*calls=1,*,rejected_calls=0,failed_calls=0} [cmdstat auth]
# Validate that unloading the moduleauthtwo module does not unregister module auth cbs of
# of the testacl module. Module based auth should succeed.
assert_equal {OK} [r AUTH foo allow]
# Validate that the testacl module can be unloaded since blocking module auth is done.
r module unload testacl
# Validate that since all module auth cbs are unregistered, module auth attempts fail.
assert_error {*WRONGPASS*} {r AUTH foo block_allow}
assert_error {*WRONGPASS*} {r AUTH foo allow_two}
assert_error {*WRONGPASS*} {r AUTH foo allow}
assert_match {*calls=5,*,rejected_calls=0,failed_calls=3} [cmdstat auth]
}
}
......@@ -77,6 +77,10 @@ start_server {tags {"modules"}} {
assert_match {*must be one of the following*} $e
}
test {test blocking of config registration and load outside of OnLoad} {
assert_equal [r block.register.configs.outside.onload] OK
}
test {Unload removes module configs} {
r module unload moduleconfigs
assert_equal [r config get moduleconfigs.*] ""
......
......@@ -5,6 +5,11 @@ start_server {tags {"modules"}} {
# test all with hello 2/3
for {set proto 2} {$proto <= 3} {incr proto} {
if {[lsearch $::denytags "resp3"] >= 0} {
if {$proto == 3} {continue}
} elseif {$::force_resp3} {
if {$proto == 2} {continue}
}
r hello $proto
test "RESP$proto: RM_ReplyWithString: an string reply" {
......@@ -120,6 +125,8 @@ start_server {tags {"modules"}} {
catch {r rw.error} e
assert_match "An error" $e
}
r hello 2
}
test "Unload the module - replywith" {
......
......@@ -121,7 +121,14 @@ start_server {config "minimal.conf" tags {"external:skip"}} {
# Make sure bind parameter is as expected and server handles binding
# accordingly.
assert_equal {bind {}} [rediscli_exec 0 config get bind]
# (it seems that rediscli_exec behaves differently in RESP3, possibly
# because CONFIG GET returns a dict instead of a list so redis-cli emits
# it in a single line)
if {$::force_resp3} {
assert_equal {{bind }} [rediscli_exec 0 config get bind]
} else {
assert_equal {bind {}} [rediscli_exec 0 config get bind]
}
catch {reconnect 0} err
assert_match {*connection refused*} $err
......
start_server {tags {"obuf-limits external:skip"}} {
start_server {tags {"obuf-limits external:skip logreqres:skip"}} {
test {CONFIG SET client-output-buffer-limit} {
set oldval [lindex [r config get client-output-buffer-limit] 1]
......
......@@ -6,6 +6,30 @@ start_server {tags {"other"}} {
} {ok}
}
test {Coverage: HELP commands} {
assert_match "*OBJECT <subcommand> *" [r OBJECT HELP]
assert_match "*MEMORY <subcommand> *" [r MEMORY HELP]
assert_match "*PUBSUB <subcommand> *" [r PUBSUB HELP]
assert_match "*SLOWLOG <subcommand> *" [r SLOWLOG HELP]
assert_match "*CLIENT <subcommand> *" [r CLIENT HELP]
assert_match "*COMMAND <subcommand> *" [r COMMAND HELP]
assert_match "*CONFIG <subcommand> *" [r CONFIG HELP]
assert_match "*FUNCTION <subcommand> *" [r FUNCTION HELP]
assert_match "*MODULE <subcommand> *" [r MODULE HELP]
}
test {Coverage: MEMORY MALLOC-STATS} {
if {[string match {*jemalloc*} [s mem_allocator]]} {
assert_match "*jemalloc*" [r memory malloc-stats]
}
}
test {Coverage: MEMORY PURGE} {
if {[string match {*jemalloc*} [s mem_allocator]]} {
assert_equal {OK} [r memory purge]
}
}
test {SAVE - make sure there are all the types as values} {
# Wait for a background saving in progress to terminate
waitForBgsave r
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment