Unverified Commit 2667c412 authored by Oran Agra's avatar Oran Agra Committed by GitHub
Browse files

Merge pull request #10829 from oranagra/release-7.0.1

Release 7.0.1
parents d375595d 595e725d
......@@ -632,4 +632,50 @@ tags {"aof external:skip"} {
} result
assert_match "*Failed to truncate AOF*to timestamp*because it is not the last file*" $result
}
start_server {overrides {appendonly yes appendfsync always}} {
test {FLUSHDB / FLUSHALL should persist in AOF} {
set aof [get_last_incr_aof_path r]
r set key value
r flushdb
r set key value2
r flushdb
# DB is empty
r flushdb
r flushdb
r flushdb
r set key value
r flushall
r set key value2
r flushall
# DBs are empty.
r flushall
r flushall
r flushall
# Assert that each FLUSHDB command is persisted even the DB is empty.
# Assert that each FLUSHALL command is persisted even the DBs are empty.
assert_aof_content $aof {
{select *}
{set key value}
{flushdb}
{set key value2}
{flushdb}
{flushdb}
{flushdb}
{flushdb}
{set key value}
{flushall}
{set key value2}
{flushall}
{flushall}
{flushall}
{flushall}
}
}
}
}
......@@ -9,7 +9,7 @@ if {$system_name eq {darwin}} {
} elseif {$system_name eq {linux}} {
# Avoid the test on libmusl, which does not support backtrace
set ldd [exec ldd src/redis-server]
if {![string match {*libc.musl*} $ldd]} {
if {![string match {*libc.*musl*} $ldd]} {
set backtrace_supported 1
}
}
......
......@@ -278,7 +278,7 @@ start_server {overrides {save ""}} {
set current_save_keys_total [s current_save_keys_total]
if {$::verbose} {
puts "Keys before bgsave start: current_save_keys_total"
puts "Keys before bgsave start: $current_save_keys_total"
}
# on each iteration, we will write some key to the server to trigger copy-on-write, and
......@@ -366,4 +366,49 @@ start_server [list overrides [list "dir" $server_path "dbfilename" "scriptbackup
}
}
start_server {} {
test "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}
# repeate with script
assert_error {MISCONF *} {r eval {
return redis.call('set','x',1)
} 1 x
}
assert_equal {x} [r eval {
return redis.call('get','x')
} 1 x
]
# again with script using shebang
assert_error {MISCONF *} {r eval {#!lua
return redis.call('set','x',1)
} 1 x
}
assert_equal {x} [r 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}
}
} ;# tags
......@@ -225,11 +225,45 @@ start_server {tags {"repl external:skip"}} {
}
}
test {FLUSHALL should replicate} {
test {FLUSHDB / FLUSHALL should replicate} {
set repl [attach_to_replication_stream]
r -1 set key value
r -1 flushdb
r -1 set key value2
r -1 flushall
wait_for_ofs_sync [srv 0 client] [srv -1 client]
assert_equal [r -1 dbsize] 0
assert_equal [r 0 dbsize] 0
# DB is empty.
r -1 flushdb
r -1 flushdb
r -1 flushdb
# DBs are empty.
r -1 flushall
r -1 flushall
r -1 flushall
if {$::valgrind} {after 2000}
list [r -1 dbsize] [r 0 dbsize]
} {0 0}
# Assert that each FLUSHDB command is replicated even the DB is empty.
# Assert that each FLUSHALL command is replicated even the DBs are empty.
assert_replication_stream $repl {
{set key value}
{flushdb}
{set key value2}
{flushall}
{flushdb}
{flushdb}
{flushdb}
{flushall}
{flushall}
{flushall}
}
close_replication_stream $repl
}
test {ROLE in master reports master with a slave} {
set res [r -1 role]
......
......@@ -23,7 +23,8 @@ void done_handler(int exitcode, int bysignal, void *user_data) {
int fork_create(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
{
long long code_to_exit_with;
if (argc != 2) {
long long usleep_us;
if (argc != 3) {
RedisModule_WrongArity(ctx);
return REDISMODULE_OK;
}
......@@ -34,20 +35,22 @@ int fork_create(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
}
RedisModule_StringToLongLong(argv[1], &code_to_exit_with);
RedisModule_StringToLongLong(argv[2], &usleep_us);
exitted_with_code = -1;
child_pid = RedisModule_Fork(done_handler, (void*)0xdeadbeef);
if (child_pid < 0) {
int fork_child_pid = RedisModule_Fork(done_handler, (void*)0xdeadbeef);
if (fork_child_pid < 0) {
RedisModule_ReplyWithError(ctx, "Fork failed");
return REDISMODULE_OK;
} else if (child_pid > 0) {
} else if (fork_child_pid > 0) {
/* parent */
child_pid = fork_child_pid;
RedisModule_ReplyWithLongLong(ctx, child_pid);
return REDISMODULE_OK;
}
/* child */
RedisModule_Log(ctx, "notice", "fork child started");
usleep(500000);
usleep(usleep_us);
RedisModule_Log(ctx, "notice", "fork child exiting");
RedisModule_ExitFromChild(code_to_exit_with);
/* unreachable */
......
......@@ -310,6 +310,50 @@ int test_monotonic_time(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
return REDISMODULE_OK;
}
/* wrapper for RM_Call */
int test_rm_call(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){
if(argc < 2){
return RedisModule_WrongArity(ctx);
}
const char* cmd = RedisModule_StringPtrLen(argv[1], NULL);
RedisModuleCallReply* rep = RedisModule_Call(ctx, cmd, "Ev", argv + 2, argc - 2);
if(!rep){
RedisModule_ReplyWithError(ctx, "NULL reply returned");
}else{
RedisModule_ReplyWithCallReply(ctx, rep);
RedisModule_FreeCallReply(rep);
}
return REDISMODULE_OK;
}
/* wrapper for RM_Call with flags */
int test_rm_call_flags(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){
if(argc < 3){
return RedisModule_WrongArity(ctx);
}
/* Append Ev to the provided flags. */
RedisModuleString *flags = RedisModule_CreateStringFromString(ctx, argv[1]);
RedisModule_StringAppendBuffer(ctx, flags, "Ev", 2);
const char* flg = RedisModule_StringPtrLen(flags, NULL);
const char* cmd = RedisModule_StringPtrLen(argv[2], NULL);
RedisModuleCallReply* rep = RedisModule_Call(ctx, cmd, flg, argv + 3, argc - 3);
if(!rep){
RedisModule_ReplyWithError(ctx, "NULL reply returned");
}else{
RedisModule_ReplyWithCallReply(ctx, rep);
RedisModule_FreeCallReply(rep);
}
RedisModule_FreeString(ctx, flags);
return REDISMODULE_OK;
}
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc);
......@@ -351,6 +395,10 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
return REDISMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"test.monotonic_time", test_monotonic_time,"",0,0,0) == REDISMODULE_ERR)
return REDISMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "test.rm_call", test_rm_call,"allow-stale", 0, 0, 0) == REDISMODULE_ERR)
return REDISMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "test.rm_call_flags", test_rm_call_flags,"allow-stale", 0, 0, 0) == REDISMODULE_ERR)
return REDISMODULE_ERR;
return REDISMODULE_OK;
}
......@@ -121,13 +121,13 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
}
/* On the stack to make sure we're copying them. */
const char *enum_vals[] = {"none", "one", "two", "three"};
const int int_vals[] = {0, 1, 2, 4};
const char *enum_vals[] = {"none", "five", "one", "two", "four"};
const int int_vals[] = {0, 5, 1, 2, 4};
if (RedisModule_RegisterEnumConfig(ctx, "enum", 1, REDISMODULE_CONFIG_DEFAULT, enum_vals, int_vals, 4, getEnumConfigCommand, setEnumConfigCommand, NULL, NULL) == REDISMODULE_ERR) {
if (RedisModule_RegisterEnumConfig(ctx, "enum", 1, REDISMODULE_CONFIG_DEFAULT, enum_vals, int_vals, 5, getEnumConfigCommand, setEnumConfigCommand, NULL, NULL) == REDISMODULE_ERR) {
return REDISMODULE_ERR;
}
if (RedisModule_RegisterEnumConfig(ctx, "flags", 3, REDISMODULE_CONFIG_DEFAULT | REDISMODULE_CONFIG_BITFLAGS, enum_vals, int_vals, 4, getFlagsConfigCommand, setFlagsConfigCommand, NULL, NULL) == REDISMODULE_ERR) {
if (RedisModule_RegisterEnumConfig(ctx, "flags", 3, REDISMODULE_CONFIG_DEFAULT | REDISMODULE_CONFIG_BITFLAGS, enum_vals, int_vals, 5, getFlagsConfigCommand, setFlagsConfigCommand, NULL, NULL) == REDISMODULE_ERR) {
return REDISMODULE_ERR;
}
/* Memory config here. */
......
......@@ -79,7 +79,9 @@ test "Sentinels (re)connection following SENTINEL SET mymaster auth-pass" {
restart_instance sentinel $sent2re
# Verify sentinel that restarted failed to connect master
if {![string match "*disconnected*" [dict get [S $sent2re SENTINEL MASTER mymaster] flags]]} {
wait_for_condition 100 50 {
[string match "*disconnected*" [dict get [S $sent2re SENTINEL MASTER mymaster] flags]] != 0
} else {
fail "Expected to be disconnected from master due to wrong password"
}
......
......@@ -262,16 +262,22 @@ proc create_server_config_file {filename config} {
close $fp
}
proc spawn_server {config_file stdout stderr} {
proc spawn_server {config_file stdout stderr args} {
set cmd [list src/redis-server $config_file]
set args {*}$args
if {[llength $args] > 0} {
lappend cmd {*}$args
}
if {$::valgrind} {
set pid [exec valgrind --track-origins=yes --trace-children=yes --suppressions=[pwd]/src/valgrind.sup --show-reachable=no --show-possibly-lost=no --leak-check=full src/redis-server $config_file >> $stdout 2>> $stderr &]
set pid [exec valgrind --track-origins=yes --trace-children=yes --suppressions=[pwd]/src/valgrind.sup --show-reachable=no --show-possibly-lost=no --leak-check=full {*}$cmd >> $stdout 2>> $stderr &]
} elseif ($::stack_logging) {
set pid [exec /usr/bin/env MallocStackLogging=1 MallocLogFile=/tmp/malloc_log.txt src/redis-server $config_file >> $stdout 2>> $stderr &]
set pid [exec /usr/bin/env MallocStackLogging=1 MallocLogFile=/tmp/malloc_log.txt {*}$cmd >> $stdout 2>> $stderr &]
} else {
# ASAN_OPTIONS environment variable is for address sanitizer. If a test
# tries to allocate huge memory area and expects allocator to return
# NULL, address sanitizer throws an error without this setting.
set pid [exec /usr/bin/env ASAN_OPTIONS=allocator_may_return_null=1 src/redis-server $config_file >> $stdout 2>> $stderr &]
set pid [exec /usr/bin/env ASAN_OPTIONS=allocator_may_return_null=1 {*}$cmd >> $stdout 2>> $stderr &]
}
if {$::wait_server} {
......@@ -398,6 +404,7 @@ proc start_server {options {code undefined}} {
set overrides {}
set omit {}
set tags {}
set args {}
set keep_persistence false
# parse options
......@@ -409,6 +416,9 @@ proc start_server {options {code undefined}} {
"overrides" {
set overrides $value
}
"args" {
set args $value
}
"omit" {
set omit $value
}
......@@ -518,7 +528,7 @@ proc start_server {options {code undefined}} {
send_data_packet $::test_server_fd "server-spawning" "port $port"
set pid [spawn_server $config_file $stdout $stderr]
set pid [spawn_server $config_file $stdout $stderr $args]
# check that the server actually started
set port_busy [wait_server_started $config_file $stdout $pid]
......@@ -721,7 +731,7 @@ proc restart_server {level wait_ready rotate_logs {reconnect 1} {shutdown sigter
set config_file [dict get $srv "config_file"]
set pid [spawn_server $config_file $stdout $stderr]
set pid [spawn_server $config_file $stdout $stderr {}]
# check that the server actually started
wait_server_started $config_file $stdout $pid
......
......@@ -126,28 +126,36 @@ proc wait_for_condition {maxtries delay e _else_ elsescript} {
}
}
# try to match a value to a list of patterns that is either regex, or plain sub-string
proc search_pattern_list {value pattern_list {substr false}} {
set n 0
# try to match a value to a list of patterns that are either regex (starts with "/") or plain string.
# The caller can specify to use only glob-pattern match
proc search_pattern_list {value pattern_list {glob_pattern false}} {
foreach el $pattern_list {
if {[string length $el] > 0 && ((!$substr && [regexp -- $el $value]) || ($substr && [string match $el $value]))} {
return $n
if {[string length $el] == 0} { continue }
if { $glob_pattern } {
if {[string match $el $value]} {
return 1
}
incr n
continue
}
return -1
if {[string equal / [string index $el 0]] && [regexp -- [string range $el 1 end] $value]} {
return 1
} elseif {[string equal $el $value]} {
return 1
}
}
return 0
}
proc test {name code {okpattern undefined} {tags {}}} {
# abort if test name in skiptests
if {[search_pattern_list $name $::skiptests] >= 0} {
if {[search_pattern_list $name $::skiptests]} {
incr ::num_skipped
send_data_packet $::test_server_fd skip $name
return
}
# abort if only_tests was set but test name is not included
if {[llength $::only_tests] > 0 && [search_pattern_list $name $::only_tests] < 0} {
if {[llength $::only_tests] > 0 && ![search_pattern_list $name $::only_tests]} {
incr ::num_skipped
send_data_packet $::test_server_fd skip $name
return
......
......@@ -588,15 +588,15 @@ proc print_help_screen {} {
"--single <unit> Just execute the specified unit (see next option). This option can be repeated."
"--verbose Increases verbosity."
"--list-tests List all the available test units."
"--only <test> Just execute tests that match <test> regexp. This option can be repeated."
"--only <test> Just execute the specified test by test name or tests that match <test> regexp (if <test> starts with '/'). This option can be repeated."
"--skip-till <unit> Skip all units until (and including) the specified one."
"--skipunit <unit> Skip one unit."
"--clients <num> Number of test clients (default 16)."
"--timeout <sec> Test timeout in seconds (default 20 min)."
"--force-failure Force the execution of a test that always fails."
"--config <k> <v> Extra config file argument."
"--skipfile <file> Name of a file containing test names or regexp patterns that should be skipped (one per line)."
"--skiptest <test> Test name or regexp pattern to skip. This option can be repeated."
"--skipfile <file> Name of a file containing test names or regexp patterns (if <test> starts with '/') that should be skipped (one per line)."
"--skiptest <test> Test name or regexp pattern (if <test> starts with '/') to skip. This option can be repeated."
"--tags <tags> Run only tests having specified tags or not having '-' prefixed tags."
"--dont-clean Don't delete redis log files after the run."
"--no-latency Skip latency measurements and validation by some tests."
......
......@@ -529,6 +529,13 @@ start_server {tags {"acl external:skip"}} {
assert_equal [lsearch [r acl cat stream] "get"] -1
}
test "ACL requires explicit permission for scripting for EVAL_RO, EVALSHA_RO and FCALL_RO" {
r ACL SETUSER scripter on nopass +readonly
assert_equal "This user has no permissions to run the 'eval_ro' command" [r ACL DRYRUN scripter EVAL_RO "" 0]
assert_equal "This user has no permissions to run the 'evalsha_ro' command" [r ACL DRYRUN scripter EVALSHA_RO "" 0]
assert_equal "This user has no permissions to run the 'fcall_ro' command" [r ACL DRYRUN scripter FCALL_RO "" 0]
}
test {ACL #5998 regression: memory leaks adding / removing subcommands} {
r AUTH default ""
r ACL setuser newuser reset -debug +debug|a +debug|b +debug|c
......@@ -926,3 +933,13 @@ start_server [list overrides [list "dir" $server_path "aclfile" "user.acl"] tags
assert_match {*Duplicate user*} $err
} {} {external:skip}
}
start_server {overrides {user "default on nopass ~* +@all -flushdb"} tags {acl external:skip}} {
test {ACL from config file and config rewrite} {
assert_error {NOPERM *} {r flushdb}
r config rewrite
restart_server 0 true false
assert_error {NOPERM *} {r flushdb}
}
}
......@@ -424,7 +424,7 @@ start_server {tags {"scripting repl external:skip"}} {
r -1 fcall test 0
} e
set _ $e
} {*Can not run script with write flag on readonly replica*}
} {READONLY You can't write against a read only replica.}
}
}
......@@ -1052,7 +1052,7 @@ start_server {tags {"scripting"}} {
r config set maxmemory 1
catch {[r fcall f1 1 k]} e
assert_match {*can not run it when used memory > 'maxmemory'*} $e
assert_match {OOM *when used memory > 'maxmemory'*} $e
r config set maxmemory 0
} {OK} {needs:config-maxmemory}
......@@ -1064,11 +1064,8 @@ start_server {tags {"scripting"}} {
r config set maxmemory 1
catch {r fcall f1 1 k} e
assert_match {*can not run it when used memory > 'maxmemory'*} $e
catch {r fcall_ro f1 1 k} e
assert_match {*can not run it when used memory > 'maxmemory'*} $e
assert_equal [r fcall f1 1 k] hello
assert_equal [r fcall_ro f1 1 k] hello
r config set maxmemory 0
} {OK} {needs:config-maxmemory}
......@@ -1085,12 +1082,12 @@ start_server {tags {"scripting"}} {
r replicaof 127.0.0.1 1
catch {[r fcall f1 0]} e
assert_match {*'allow-stale' flag is not set on the script*} $e
assert_match {MASTERDOWN *} $e
assert_equal {hello} [r fcall f2 0]
catch {[r fcall f3 0]} e
assert_match {*Can not execute the command on a stale replica*} $e
assert_match {ERR *Can not execute the command on a stale replica*} $e
assert_match {*redis_version*} [r fcall f4 0]
......@@ -1141,6 +1138,23 @@ start_server {tags {"scripting"}} {
r function stats
} {running_script {} engines {LUA {libraries_count 1 functions_count 1}}}
test {FUNCTION - test function stats on loading failure} {
r FUNCTION FLUSH
r FUNCTION load {#!lua name=test1
redis.register_function('f1', function() return 1 end)
redis.register_function('f2', function() return 1 end)
}
catch {r FUNCTION load {#!lua name=test1
redis.register_function('f3', function() return 1 end)
}} e
assert_match "*Library 'test1' already exists*" $e
r function stats
} {running_script {} engines {LUA {libraries_count 1 functions_count 2}}}
test {FUNCTION - function stats cleaned after flush} {
r function flush
r function stats
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -11,7 +11,7 @@ start_server {tags {"modules"}} {
assert_equal {1} [subscribe $rd2 {chan1}]
assert_equal 1 [r publish.shard chan1 hello]
assert_equal 1 [r publish.classic chan1 world]
assert_equal {message chan1 hello} [$rd1 read]
assert_equal {smessage chan1 hello} [$rd1 read]
assert_equal {message chan1 world} [$rd2 read]
}
}
This diff is collapsed.
This diff is collapsed.
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