2019-10-24 02:38:52 -04:00
|
|
|
set testmodule [file normalize tests/modules/misc.so]
|
|
|
|
|
|
|
|
start_server {tags {"modules"}} {
|
|
|
|
r module load $testmodule
|
|
|
|
|
|
|
|
test {test RM_Call} {
|
|
|
|
set info [r test.call_info commandstats]
|
|
|
|
# cmdstat is not in a default section, so we also test an argument was passed
|
|
|
|
assert { [string match "*cmdstat_module*" $info] }
|
|
|
|
}
|
|
|
|
|
|
|
|
test {test RM_Call args array} {
|
|
|
|
set info [r test.call_generic info commandstats]
|
|
|
|
# cmdstat is not in a default section, so we also test an argument was passed
|
|
|
|
assert { [string match "*cmdstat_module*" $info] }
|
|
|
|
}
|
|
|
|
|
2021-02-28 07:11:18 -05:00
|
|
|
test {test RM_Call recursive} {
|
|
|
|
set info [r test.call_generic test.call_generic info commandstats]
|
|
|
|
assert { [string match "*cmdstat_module*" $info] }
|
|
|
|
}
|
|
|
|
|
2020-10-11 10:21:58 -04:00
|
|
|
test {test redis version} {
|
|
|
|
set version [s redis_version]
|
|
|
|
assert_equal $version [r test.redisversion]
|
|
|
|
}
|
|
|
|
|
2019-11-04 12:04:35 -05:00
|
|
|
test {test long double conversions} {
|
|
|
|
set ld [r test.ld_conversion]
|
|
|
|
assert {[string match $ld "0.00000000000000001"]}
|
|
|
|
}
|
2022-06-26 08:02:52 -04:00
|
|
|
|
|
|
|
test {test unsigned long long conversions} {
|
|
|
|
set ret [r test.ull_conversion]
|
|
|
|
assert {[string match $ret "ok"]}
|
|
|
|
}
|
2019-11-04 12:04:35 -05:00
|
|
|
|
2019-11-04 12:30:31 -05:00
|
|
|
test {test module db commands} {
|
|
|
|
r set x foo
|
|
|
|
set key [r test.randomkey]
|
|
|
|
assert_equal $key "x"
|
|
|
|
assert_equal [r test.dbsize] 1
|
|
|
|
r test.flushall
|
|
|
|
assert_equal [r test.dbsize] 0
|
|
|
|
}
|
|
|
|
|
2021-10-18 15:21:19 -04:00
|
|
|
test {test module keyexists} {
|
|
|
|
r set x foo
|
|
|
|
assert_equal 1 [r test.keyexists x]
|
|
|
|
r del x
|
|
|
|
assert_equal 0 [r test.keyexists x]
|
|
|
|
}
|
|
|
|
|
2021-06-10 08:39:33 -04:00
|
|
|
test {test module lru api} {
|
2019-11-10 02:04:39 -05:00
|
|
|
r config set maxmemory-policy allkeys-lru
|
2019-11-04 12:30:31 -05:00
|
|
|
r set x foo
|
|
|
|
set lru [r test.getlru x]
|
2019-11-10 02:04:39 -05:00
|
|
|
assert { $lru <= 1000 }
|
|
|
|
set was_set [r test.setlru x 100000]
|
|
|
|
assert { $was_set == 1 }
|
2019-11-04 12:30:31 -05:00
|
|
|
set idle [r object idletime x]
|
|
|
|
assert { $idle >= 100 }
|
|
|
|
set lru [r test.getlru x]
|
2019-11-10 02:04:39 -05:00
|
|
|
assert { $lru >= 100000 }
|
|
|
|
r config set maxmemory-policy allkeys-lfu
|
|
|
|
set lru [r test.getlru x]
|
|
|
|
assert { $lru == -1 }
|
|
|
|
set was_set [r test.setlru x 100000]
|
|
|
|
assert { $was_set == 0 }
|
2019-11-04 12:30:31 -05:00
|
|
|
}
|
2019-11-10 02:04:39 -05:00
|
|
|
r config set maxmemory-policy allkeys-lru
|
|
|
|
|
2021-06-10 08:39:33 -04:00
|
|
|
test {test module lfu api} {
|
2019-11-10 02:04:39 -05:00
|
|
|
r config set maxmemory-policy allkeys-lfu
|
|
|
|
r set x foo
|
|
|
|
set lfu [r test.getlfu x]
|
|
|
|
assert { $lfu >= 1 }
|
|
|
|
set was_set [r test.setlfu x 100]
|
|
|
|
assert { $was_set == 1 }
|
|
|
|
set freq [r object freq x]
|
|
|
|
assert { $freq <= 100 }
|
|
|
|
set lfu [r test.getlfu x]
|
|
|
|
assert { $lfu <= 100 }
|
|
|
|
r config set maxmemory-policy allkeys-lru
|
|
|
|
set lfu [r test.getlfu x]
|
|
|
|
assert { $lfu == -1 }
|
|
|
|
set was_set [r test.setlfu x 100]
|
|
|
|
assert { $was_set == 0 }
|
|
|
|
}
|
|
|
|
|
2020-08-17 10:46:54 -04:00
|
|
|
test {test module clientinfo api} {
|
|
|
|
# Test basic sanity and SSL flag
|
|
|
|
set info [r test.clientinfo]
|
|
|
|
set ssl_flag [expr $::tls ? {"ssl:"} : {":"}]
|
|
|
|
|
|
|
|
assert { [dict get $info db] == 9 }
|
|
|
|
assert { [dict get $info flags] == "${ssl_flag}::::" }
|
|
|
|
|
|
|
|
# Test MULTI flag
|
|
|
|
r multi
|
|
|
|
r test.clientinfo
|
|
|
|
set info [lindex [r exec] 0]
|
|
|
|
assert { [dict get $info flags] == "${ssl_flag}::::multi" }
|
|
|
|
|
|
|
|
# Test TRACKING flag
|
|
|
|
r client tracking on
|
|
|
|
set info [r test.clientinfo]
|
|
|
|
assert { [dict get $info flags] == "${ssl_flag}::tracking::" }
|
|
|
|
}
|
2020-10-11 09:11:31 -04:00
|
|
|
|
2022-06-26 07:34:59 -04:00
|
|
|
test {test module get/set client name by id api} {
|
|
|
|
catch { r test.getname } e
|
|
|
|
assert_equal "-ERR No name" $e
|
|
|
|
r client setname nobody
|
|
|
|
catch { r test.setname "name with spaces" } e
|
|
|
|
assert_match "*Invalid argument*" $e
|
|
|
|
assert_equal nobody [r client getname]
|
|
|
|
assert_equal nobody [r test.getname]
|
|
|
|
r test.setname somebody
|
|
|
|
assert_equal somebody [r client getname]
|
|
|
|
}
|
|
|
|
|
2020-10-11 10:11:42 -04:00
|
|
|
test {test module getclientcert api} {
|
|
|
|
set cert [r test.getclientcert]
|
|
|
|
|
|
|
|
if {$::tls} {
|
|
|
|
assert {$cert != ""}
|
|
|
|
} else {
|
|
|
|
assert {$cert == ""}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-11 09:11:31 -04:00
|
|
|
test {test detached thread safe cnotext} {
|
|
|
|
r test.log_tsctx "info" "Test message"
|
|
|
|
verify_log_message 0 "*<misc> Test message*" 0
|
|
|
|
}
|
2021-03-01 01:18:14 -05:00
|
|
|
|
|
|
|
test {test RM_Call CLIENT INFO} {
|
|
|
|
assert_match "*fd=-1*" [r test.call_generic client info]
|
|
|
|
}
|
2021-11-23 03:38:25 -05:00
|
|
|
|
|
|
|
test {Unsafe command names are sanitized in INFO output} {
|
|
|
|
r test.weird:cmd
|
|
|
|
set info [r info commandstats]
|
|
|
|
assert_match {*cmdstat_test.weird_cmd:calls=1*} $info
|
|
|
|
}
|
2022-01-13 04:36:03 -05:00
|
|
|
|
|
|
|
test {test monotonic time} {
|
|
|
|
set x [r test.monotonic_time]
|
|
|
|
assert { [r test.monotonic_time] >= $x }
|
|
|
|
}
|
2022-01-23 03:05:06 -05:00
|
|
|
|
Fix broken protocol in MISCONF error, RM_Yield bugs, RM_Call(EVAL) OOM check bug, and new RM_Call checks. (#10786)
* Fix broken protocol when redis can't persist to RDB (general commands, not
modules), excessive newline. regression of #10372 (7.0 RC3)
* Fix broken protocol when Redis can't persist to AOF (modules and
scripts), missing newline.
* Fix bug in OOM check of EVAL scripts called from RM_Call.
set the cached OOM state for scripts before executing module commands too,
so that it can serve scripts that are executed by modules.
i.e. in the past EVAL executed by RM_Call could have either falsely
fail or falsely succeeded because of a wrong cached OOM state flag.
* Fix bugs with RM_Yield:
1. SHUTDOWN should only accept the NOSAVE mode
2. Avoid eviction during yield command processing.
3. Avoid processing master client commands while yielding from another client
* Add new two more checks to RM_Call script mode.
1. READONLY You can't write against a read only replica
2. MASTERDOWN Link with MASTER is down and `replica-serve-stale-data` is set to `no`
* Add new RM_Call flag to let redis automatically refuse `deny-oom` commands
while over the memory limit.
* Add tests to cover various errors from Scripts, Modules, Modules
calling scripts, and Modules calling commands in script mode.
Add tests:
* Looks like the MISCONF error was completely uncovered by the tests,
add tests for it, including from scripts, and modules
* Add tests for NOREPLICAS from scripts
* Add tests for the various errors in module RM_Call, including RM_Call that
calls EVAL, and RM_call in "eval mode". that includes:
NOREPLICAS, READONLY, MASTERDOWN, MISCONF
2022-06-01 06:04:22 -04:00
|
|
|
test {rm_call OOM} {
|
|
|
|
r config set maxmemory 1
|
|
|
|
r config set maxmemory-policy volatile-lru
|
|
|
|
|
|
|
|
# sanity test plain call
|
|
|
|
assert_equal {OK} [
|
|
|
|
r test.rm_call set x 1
|
|
|
|
]
|
|
|
|
|
|
|
|
# add the M flag
|
|
|
|
assert_error {OOM *} {
|
|
|
|
r test.rm_call_flags M set x 1
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
# test a non deny-oom command
|
|
|
|
assert_equal {1} [
|
|
|
|
r test.rm_call_flags M get x
|
|
|
|
]
|
|
|
|
|
|
|
|
r config set maxmemory 0
|
|
|
|
} {OK} {needs:config-maxmemory}
|
|
|
|
|
2022-08-28 06:10:10 -04:00
|
|
|
test {rm_call OOM Eval} {
|
|
|
|
r config set maxmemory 1
|
|
|
|
r config set maxmemory-policy volatile-lru
|
|
|
|
|
|
|
|
# use the M flag without allow-oom shebang flag
|
|
|
|
assert_error {OOM *} {
|
|
|
|
r test.rm_call_flags M eval {#!lua
|
|
|
|
redis.call('set','x',1)
|
|
|
|
return 1
|
|
|
|
} 1 x
|
|
|
|
}
|
|
|
|
|
|
|
|
# add the M flag with allow-oom shebang flag
|
|
|
|
assert_equal {1} [
|
|
|
|
r test.rm_call_flags M eval {#!lua flags=allow-oom
|
|
|
|
redis.call('set','x',1)
|
|
|
|
return 1
|
|
|
|
} 1 x
|
|
|
|
]
|
|
|
|
|
|
|
|
r config set maxmemory 0
|
|
|
|
} {OK} {needs:config-maxmemory}
|
|
|
|
|
Fix broken protocol in MISCONF error, RM_Yield bugs, RM_Call(EVAL) OOM check bug, and new RM_Call checks. (#10786)
* Fix broken protocol when redis can't persist to RDB (general commands, not
modules), excessive newline. regression of #10372 (7.0 RC3)
* Fix broken protocol when Redis can't persist to AOF (modules and
scripts), missing newline.
* Fix bug in OOM check of EVAL scripts called from RM_Call.
set the cached OOM state for scripts before executing module commands too,
so that it can serve scripts that are executed by modules.
i.e. in the past EVAL executed by RM_Call could have either falsely
fail or falsely succeeded because of a wrong cached OOM state flag.
* Fix bugs with RM_Yield:
1. SHUTDOWN should only accept the NOSAVE mode
2. Avoid eviction during yield command processing.
3. Avoid processing master client commands while yielding from another client
* Add new two more checks to RM_Call script mode.
1. READONLY You can't write against a read only replica
2. MASTERDOWN Link with MASTER is down and `replica-serve-stale-data` is set to `no`
* Add new RM_Call flag to let redis automatically refuse `deny-oom` commands
while over the memory limit.
* Add tests to cover various errors from Scripts, Modules, Modules
calling scripts, and Modules calling commands in script mode.
Add tests:
* Looks like the MISCONF error was completely uncovered by the tests,
add tests for it, including from scripts, and modules
* Add tests for NOREPLICAS from scripts
* Add tests for the various errors in module RM_Call, including RM_Call that
calls EVAL, and RM_call in "eval mode". that includes:
NOREPLICAS, READONLY, MASTERDOWN, MISCONF
2022-06-01 06:04:22 -04:00
|
|
|
test {rm_call write flag} {
|
|
|
|
# add the W flag
|
|
|
|
assert_error {ERR Write command 'set' was called while write is not allowed.} {
|
|
|
|
r test.rm_call_flags W set x 1
|
|
|
|
}
|
|
|
|
|
|
|
|
# test a non deny-oom command
|
|
|
|
r test.rm_call_flags W get x
|
|
|
|
} {1}
|
|
|
|
|
|
|
|
test {rm_call EVAL} {
|
|
|
|
r test.rm_call eval {
|
|
|
|
redis.call('set','x',1)
|
|
|
|
return 1
|
|
|
|
} 1 x
|
|
|
|
|
|
|
|
assert_error {ERR Write commands are not allowed from read-only scripts.*} {
|
|
|
|
r test.rm_call eval {#!lua flags=no-writes
|
|
|
|
redis.call('set','x',1)
|
|
|
|
return 1
|
|
|
|
} 1 x
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
test {rm_call EVAL - OOM} {
|
|
|
|
r config set maxmemory 1
|
|
|
|
|
|
|
|
assert_error {OOM command not allowed when used memory > 'maxmemory'. script*} {
|
|
|
|
r test.rm_call eval {
|
|
|
|
redis.call('set','x',1)
|
|
|
|
return 1
|
|
|
|
} 1 x
|
|
|
|
}
|
|
|
|
|
|
|
|
r test.rm_call eval {#!lua flags=no-writes
|
|
|
|
redis.call('get','x')
|
|
|
|
return 2
|
|
|
|
} 1 x
|
|
|
|
|
|
|
|
assert_error {OOM allow-oom flag is not set on the script,*} {
|
|
|
|
r test.rm_call eval {#!lua
|
|
|
|
redis.call('get','x')
|
|
|
|
return 3
|
|
|
|
} 1 x
|
|
|
|
}
|
|
|
|
|
|
|
|
r test.rm_call eval {
|
|
|
|
redis.call('get','x')
|
|
|
|
return 4
|
|
|
|
} 1 x
|
|
|
|
|
|
|
|
r config set maxmemory 0
|
|
|
|
} {OK} {needs:config-maxmemory}
|
|
|
|
|
|
|
|
test "not enough good replicas" {
|
|
|
|
r set x "some value"
|
|
|
|
r config set min-replicas-to-write 1
|
|
|
|
|
|
|
|
# rm_call in script mode
|
|
|
|
assert_error {NOREPLICAS *} {r test.rm_call_flags S set x s}
|
|
|
|
|
|
|
|
assert_equal [
|
|
|
|
r test.rm_call eval {#!lua flags=no-writes
|
|
|
|
return redis.call('get','x')
|
|
|
|
} 1 x
|
|
|
|
] "some value"
|
|
|
|
|
|
|
|
assert_equal [
|
|
|
|
r test.rm_call eval {
|
|
|
|
return redis.call('get','x')
|
|
|
|
} 1 x
|
|
|
|
] "some value"
|
|
|
|
|
|
|
|
assert_error {NOREPLICAS *} {
|
|
|
|
r test.rm_call eval {#!lua
|
|
|
|
return redis.call('get','x')
|
|
|
|
} 1 x
|
|
|
|
}
|
|
|
|
|
|
|
|
assert_error {NOREPLICAS *} {
|
|
|
|
r test.rm_call eval {
|
|
|
|
return redis.call('set','x', 1)
|
|
|
|
} 1 x
|
|
|
|
}
|
|
|
|
|
|
|
|
r config set min-replicas-to-write 0
|
|
|
|
}
|
|
|
|
|
|
|
|
test {rm_call EVAL - read-only replica} {
|
|
|
|
r replicaof 127.0.0.1 1
|
|
|
|
|
|
|
|
# rm_call in script mode
|
|
|
|
assert_error {READONLY *} {r test.rm_call_flags S set x 1}
|
|
|
|
|
|
|
|
assert_error {READONLY You can't write against a read only replica. script*} {
|
|
|
|
r test.rm_call eval {
|
|
|
|
redis.call('set','x',1)
|
|
|
|
return 1
|
|
|
|
} 1 x
|
|
|
|
}
|
|
|
|
|
|
|
|
r test.rm_call eval {#!lua flags=no-writes
|
|
|
|
redis.call('get','x')
|
|
|
|
return 2
|
|
|
|
} 1 x
|
|
|
|
|
Expose script flags to processCommand for better handling (#10744)
The important part is that read-only scripts (not just EVAL_RO
and FCALL_RO, but also ones with `no-writes` executed by normal EVAL or
FCALL), will now be permitted to run during CLIENT PAUSE WRITE (unlike
before where only the _RO commands would be processed).
Other than that, some errors like OOM, READONLY, MASTERDOWN are now
handled by processCommand, rather than the command itself affects the
error string (and even error code in some cases), and command stats.
Besides that, now the `may-replicate` commands, PFCOUNT and PUBLISH, will
be considered `write` commands in scripts and will be blocked in all
read-only scripts just like other write commands.
They'll also be blocked in EVAL_RO (i.e. even for scripts without the
`no-writes` shebang flag.
This commit also hides the `may_replicate` flag from the COMMAND command
output. this is a **breaking change**.
background about may_replicate:
We don't want to expose a no-may-replicate flag or alike to scripts, since we
consider the may-replicate thing an internal concern of redis, that we may
some day get rid of.
In fact, the may-replicate flag was initially introduced to flag EVAL: since
we didn't know what it's gonna do ahead of execution, before function-flags
existed). PUBLISH and PFCOUNT, both of which because they have side effects
which may some day be fixed differently.
code changes:
The changes in eval.c are mostly code re-ordering:
- evalCalcFunctionName is extracted out of evalGenericCommand
- evalExtractShebangFlags is extracted luaCreateFunction
- evalGetCommandFlags is new code
2022-06-01 07:09:40 -04:00
|
|
|
assert_error {READONLY Can not run script with write flag on readonly replica*} {
|
Fix broken protocol in MISCONF error, RM_Yield bugs, RM_Call(EVAL) OOM check bug, and new RM_Call checks. (#10786)
* Fix broken protocol when redis can't persist to RDB (general commands, not
modules), excessive newline. regression of #10372 (7.0 RC3)
* Fix broken protocol when Redis can't persist to AOF (modules and
scripts), missing newline.
* Fix bug in OOM check of EVAL scripts called from RM_Call.
set the cached OOM state for scripts before executing module commands too,
so that it can serve scripts that are executed by modules.
i.e. in the past EVAL executed by RM_Call could have either falsely
fail or falsely succeeded because of a wrong cached OOM state flag.
* Fix bugs with RM_Yield:
1. SHUTDOWN should only accept the NOSAVE mode
2. Avoid eviction during yield command processing.
3. Avoid processing master client commands while yielding from another client
* Add new two more checks to RM_Call script mode.
1. READONLY You can't write against a read only replica
2. MASTERDOWN Link with MASTER is down and `replica-serve-stale-data` is set to `no`
* Add new RM_Call flag to let redis automatically refuse `deny-oom` commands
while over the memory limit.
* Add tests to cover various errors from Scripts, Modules, Modules
calling scripts, and Modules calling commands in script mode.
Add tests:
* Looks like the MISCONF error was completely uncovered by the tests,
add tests for it, including from scripts, and modules
* Add tests for NOREPLICAS from scripts
* Add tests for the various errors in module RM_Call, including RM_Call that
calls EVAL, and RM_call in "eval mode". that includes:
NOREPLICAS, READONLY, MASTERDOWN, MISCONF
2022-06-01 06:04:22 -04:00
|
|
|
r test.rm_call eval {#!lua
|
|
|
|
redis.call('get','x')
|
|
|
|
return 3
|
|
|
|
} 1 x
|
|
|
|
}
|
|
|
|
|
|
|
|
r test.rm_call eval {
|
|
|
|
redis.call('get','x')
|
|
|
|
return 4
|
|
|
|
} 1 x
|
|
|
|
|
|
|
|
r replicaof no one
|
|
|
|
} {OK} {needs:config-maxmemory}
|
|
|
|
|
|
|
|
test {rm_call EVAL - stale replica} {
|
|
|
|
r replicaof 127.0.0.1 1
|
|
|
|
r config set replica-serve-stale-data no
|
|
|
|
|
|
|
|
# rm_call in script mode
|
|
|
|
assert_error {MASTERDOWN *} {
|
|
|
|
r test.rm_call_flags S get x
|
|
|
|
}
|
|
|
|
|
|
|
|
assert_error {MASTERDOWN *} {
|
|
|
|
r test.rm_call eval {#!lua flags=no-writes
|
|
|
|
redis.call('get','x')
|
|
|
|
return 2
|
|
|
|
} 1 x
|
|
|
|
}
|
|
|
|
|
|
|
|
assert_error {MASTERDOWN *} {
|
|
|
|
r test.rm_call eval {
|
|
|
|
redis.call('get','x')
|
|
|
|
return 4
|
|
|
|
} 1 x
|
|
|
|
}
|
|
|
|
|
|
|
|
r replicaof no one
|
|
|
|
r config set replica-serve-stale-data yes
|
|
|
|
} {OK} {needs:config-maxmemory}
|
|
|
|
|
|
|
|
test "rm_call EVAL - failed bgsave prevents writes" {
|
|
|
|
r config set rdb-key-save-delay 10000000
|
|
|
|
populate 1000
|
|
|
|
r set x x
|
|
|
|
r bgsave
|
|
|
|
set pid1 [get_child_pid 0]
|
|
|
|
catch {exec kill -9 $pid1}
|
|
|
|
waitForBgsave r
|
|
|
|
|
|
|
|
# make sure a read command succeeds
|
|
|
|
assert_equal [r get x] x
|
|
|
|
|
|
|
|
# make sure a write command fails
|
|
|
|
assert_error {MISCONF *} {r set x y}
|
|
|
|
|
|
|
|
# rm_call in script mode
|
|
|
|
assert_error {MISCONF *} {r test.rm_call_flags S set x 1}
|
|
|
|
|
|
|
|
# repeate with script
|
|
|
|
assert_error {MISCONF *} {r test.rm_call eval {
|
|
|
|
return redis.call('set','x',1)
|
|
|
|
} 1 x
|
|
|
|
}
|
|
|
|
assert_equal {x} [r test.rm_call eval {
|
|
|
|
return redis.call('get','x')
|
|
|
|
} 1 x
|
|
|
|
]
|
|
|
|
|
|
|
|
# again with script using shebang
|
|
|
|
assert_error {MISCONF *} {r test.rm_call eval {#!lua
|
|
|
|
return redis.call('set','x',1)
|
|
|
|
} 1 x
|
|
|
|
}
|
|
|
|
assert_equal {x} [r test.rm_call eval {#!lua flags=no-writes
|
|
|
|
return redis.call('get','x')
|
|
|
|
} 1 x
|
|
|
|
]
|
|
|
|
|
|
|
|
r config set rdb-key-save-delay 0
|
|
|
|
r bgsave
|
|
|
|
waitForBgsave r
|
|
|
|
|
|
|
|
# server is writable again
|
|
|
|
r set x y
|
|
|
|
} {OK}
|
|
|
|
|
2022-01-23 03:05:06 -05:00
|
|
|
test "Unload the module - misc" {
|
|
|
|
assert_equal {OK} [r module unload misc]
|
|
|
|
}
|
2019-10-24 02:38:52 -04:00
|
|
|
}
|