Unverified Commit 76b9c13d authored by Oran Agra's avatar Oran Agra Committed by GitHub
Browse files

Merge pull request #10962 from oranagra/release-7.0.3

Release 7.0.3
parents 05833959 85abb7cf
......@@ -150,7 +150,7 @@ int checkOvercommit(sds *error_msg) {
}
fclose(fp);
if (atoi(buf)) {
if (strtol(buf, NULL, 10) == 0) {
*error_msg = sdsnew(
"overcommit_memory is set to 0! Background save may fail under low memory condition. "
"To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the "
......
......@@ -2952,7 +2952,9 @@ static void zrangeResultFinalizeClient(zrange_result_handler *handler,
/* Result handler methods for storing the ZRANGESTORE to a zset. */
static void zrangeResultBeginStore(zrange_result_handler *handler, long length)
{
UNUSED(length);
if (length > (long)server.zset_max_listpack_entries)
handler->dstobj = createZsetObject();
else
handler->dstobj = createZsetListpackObject();
}
......
......@@ -722,6 +722,8 @@ static void connTLSClose(connection *conn_) {
tls_connection *conn = (tls_connection *) conn_;
if (conn->ssl) {
if (conn->c.state == CONN_STATE_CONNECTED)
SSL_shutdown(conn->ssl);
SSL_free(conn->ssl);
conn->ssl = NULL;
}
......@@ -834,12 +836,12 @@ static int connTLSWritev(connection *conn_, const struct iovec *iov, int iovcnt)
* which is not worth doing so much memory copying to reduce system calls,
* therefore, invoke connTLSWrite() multiple times to avoid memory copies. */
if (iov_bytes_len > NET_MAX_WRITES_PER_EVENT) {
size_t tot_sent = 0;
ssize_t tot_sent = 0;
for (int i = 0; i < iovcnt; i++) {
size_t sent = connTLSWrite(conn_, iov[i].iov_base, iov[i].iov_len);
ssize_t sent = connTLSWrite(conn_, iov[i].iov_base, iov[i].iov_len);
if (sent <= 0) return tot_sent > 0 ? tot_sent : sent;
tot_sent += sent;
if (sent != iov[i].iov_len) break;
if ((size_t) sent != iov[i].iov_len) break;
}
return tot_sent;
}
......
......@@ -43,6 +43,7 @@
#include <sys/stat.h>
#include <dirent.h>
#include <fcntl.h>
#include <libgen.h>
#include "util.h"
#include "sha256.h"
......@@ -923,6 +924,54 @@ sds makePath(char *path, char *filename) {
return sdscatfmt(sdsempty(), "%s/%s", path, filename);
}
/* Given the filename, sync the corresponding directory.
*
* Usually a portable and safe pattern to overwrite existing files would be like:
* 1. create a new temp file (on the same file system!)
* 2. write data to the temp file
* 3. fsync() the temp file
* 4. rename the temp file to the appropriate name
* 5. fsync() the containing directory */
int fsyncFileDir(const char *filename) {
#ifdef _AIX
/* AIX is unable to fsync a directory */
return 0;
#endif
char temp_filename[PATH_MAX + 1];
char *dname;
int dir_fd;
if (strlen(filename) > PATH_MAX) {
errno = ENAMETOOLONG;
return -1;
}
/* In the glibc implementation dirname may modify their argument. */
memcpy(temp_filename, filename, strlen(filename) + 1);
dname = dirname(temp_filename);
dir_fd = open(dname, O_RDONLY);
if (dir_fd == -1) {
/* Some OSs don't allow us to open directories at all, just
* ignore the error in that case */
if (errno == EISDIR) {
return 0;
}
return -1;
}
/* Some OSs don't allow us to fsync directories at all, so we can ignore
* those errors. */
if (redis_fsync(dir_fd) == -1 && !(errno == EBADF || errno == EINVAL)) {
int save_errno = errno;
close(dir_fd);
errno = save_errno;
return -1;
}
close(dir_fd);
return 0;
}
#ifdef REDIS_TEST
#include <assert.h>
......
......@@ -85,6 +85,7 @@ int dirExists(char *dname);
int dirRemove(char *dname);
int fileExist(char *filename);
sds makePath(char *path, char *filename);
int fsyncFileDir(const char *filename);
#ifdef REDIS_TEST
int utilTest(int argc, char **argv, int flags);
......
#define REDIS_VERSION "7.0.2"
#define REDIS_VERSION_NUM 0x00070002
#define REDIS_VERSION "7.0.3"
#define REDIS_VERSION_NUM 0x00070003
......@@ -80,3 +80,16 @@ test "Script no-cluster flag" {
assert_match {*Can not run script on cluster, 'no-cluster' flag is set*} $e
}
test "CLUSTER RESET SOFT test" {
set last_epoch_node0 [get_info_field [R 0 cluster info] cluster_current_epoch]
R 0 FLUSHALL
R 0 CLUSTER RESET
assert {[get_info_field [R 0 cluster info] cluster_current_epoch] eq $last_epoch_node0}
set last_epoch_node1 [get_info_field [R 1 cluster info] cluster_current_epoch]
R 1 FLUSHALL
R 1 CLUSTER RESET SOFT
assert {[get_info_field [R 1 cluster info] cluster_current_epoch] eq $last_epoch_node1}
}
......@@ -183,3 +183,20 @@ test "Test the replica reports a loading state while it's loading" {
# Final sanity, the replica agrees it is online.
assert_equal "online" [dict get [get_node_info_from_shard $replica_cluster_id $replica_id "node"] health]
}
test "Regression test for a crash when calling SHARDS during handshake" {
# Reset forget a node, so we can use it to establish handshaking connections
set id [R 19 CLUSTER MYID]
R 19 CLUSTER RESET HARD
for {set i 0} {$i < 19} {incr i} {
R $i CLUSTER FORGET $id
}
R 19 cluster meet 127.0.0.1 [get_instance_attrib redis 0 port]
# This should line would previously crash, since all the outbound
# connections were in handshake state.
R 19 CLUSTER SHARDS
}
test "Cluster is up" {
assert_cluster_state ok
}
# Tests for the response of slot migrations.
source "../tests/includes/init-tests.tcl"
source "../tests/includes/utils.tcl"
test "Create a 2 nodes cluster" {
create_cluster 2 0
config_set_all_nodes cluster-allow-replica-migration no
}
test "Cluster is up" {
assert_cluster_state ok
}
set cluster [redis_cluster 127.0.0.1:[get_instance_attrib redis 0 port]]
catch {unset nodefrom}
catch {unset nodeto}
$cluster refresh_nodes_map
test "Set many keys in the cluster" {
for {set i 0} {$i < 5000} {incr i} {
$cluster set $i $i
assert { [$cluster get $i] eq $i }
}
}
test "Test cluster responses during migration of slot x" {
set slot 10
array set nodefrom [$cluster masternode_for_slot $slot]
array set nodeto [$cluster masternode_notfor_slot $slot]
$nodeto(link) cluster setslot $slot importing $nodefrom(id)
$nodefrom(link) cluster setslot $slot migrating $nodeto(id)
# Get a key from that slot
set key [$nodefrom(link) cluster GETKEYSINSLOT $slot "1"]
# MOVED REPLY
assert_error "*MOVED*" {$nodeto(link) set $key "newVal"}
# ASK REPLY
assert_error "*ASK*" {$nodefrom(link) set "abc{$key}" "newVal"}
# UNSTABLE REPLY
assert_error "*TRYAGAIN*" {$nodefrom(link) mset "a{$key}" "newVal" $key "newVal2"}
}
config_set_all_nodes cluster-allow-replica-migration yes
......@@ -117,6 +117,15 @@ start_server {tags {"benchmark network external:skip"}} {
assert_match {50} [scan [regexp -inline {keys\=([\d]*)} [r info keyspace]] keys=%d]
}
test {benchmark: clients idle mode should return error when reached maxclients limit} {
set cmd [redisbenchmark $master_host $master_port "-c 10 -I"]
set original_maxclients [lindex [r config get maxclients] 1]
r config set maxclients 5
catch { exec {*}$cmd } error
assert_match "*Error*" $error
r config set maxclients $original_maxclients
}
# tls specific tests
if {$::tls} {
test {benchmark: specific tls-ciphers} {
......
......@@ -7,6 +7,7 @@
#include <assert.h>
#include <stdio.h>
#include <pthread.h>
#include <strings.h>
#define UNUSED(V) ((void) V)
......@@ -119,8 +120,20 @@ void *bg_call_worker(void *arg) {
}
// Call the command
const char* cmd = RedisModule_StringPtrLen(bg->argv[1], NULL);
RedisModuleCallReply* rep = RedisModule_Call(ctx, cmd, "v", bg->argv + 2, bg->argc - 2);
const char *module_cmd = RedisModule_StringPtrLen(bg->argv[0], NULL);
int cmd_pos = 1;
RedisModuleString *format_redis_str = RedisModule_CreateString(NULL, "v", 1);
if (!strcasecmp(module_cmd, "do_bg_rm_call_format")) {
cmd_pos = 2;
size_t format_len;
const char *format = RedisModule_StringPtrLen(bg->argv[1], &format_len);
RedisModule_StringAppendBuffer(NULL, format_redis_str, format, format_len);
RedisModule_StringAppendBuffer(NULL, format_redis_str, "E", 1);
}
const char *format = RedisModule_StringPtrLen(format_redis_str, NULL);
const char *cmd = RedisModule_StringPtrLen(bg->argv[cmd_pos], NULL);
RedisModuleCallReply *rep = RedisModule_Call(ctx, cmd, format, bg->argv + cmd_pos + 1, bg->argc - cmd_pos - 1);
RedisModule_FreeString(NULL, format_redis_str);
// Release GIL
RedisModule_ThreadSafeContextUnlock(ctx);
......@@ -306,6 +319,9 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
if (RedisModule_CreateCommand(ctx, "do_bg_rm_call", do_bg_rm_call, "", 0, 0, 0) == REDISMODULE_ERR)
return REDISMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "do_bg_rm_call_format", do_bg_rm_call, "", 0, 0, 0) == REDISMODULE_ERR)
return REDISMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "do_fake_bg_true", do_fake_bg_true, "", 0, 0, 0) == REDISMODULE_ERR)
return REDISMODULE_ERR;
......
......@@ -4,6 +4,7 @@
#include <assert.h>
#include <unistd.h>
#include <errno.h>
#include <limits.h>
#define UNUSED(x) (void)(x)
......@@ -239,9 +240,17 @@ int test_clientinfo(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
(void) argv;
(void) argc;
RedisModuleClientInfo ci = { .version = REDISMODULE_CLIENTINFO_VERSION };
RedisModuleClientInfoV1 ci = REDISMODULE_CLIENTINFO_INITIALIZER_V1;
uint64_t client_id = RedisModule_GetClientId(ctx);
if (RedisModule_GetClientInfoById(&ci, RedisModule_GetClientId(ctx)) == REDISMODULE_ERR) {
/* Check expected result from the V1 initializer. */
assert(ci.version == 1);
/* Trying to populate a future version of the struct should fail. */
ci.version = REDISMODULE_CLIENTINFO_VERSION + 1;
assert(RedisModule_GetClientInfoById(&ci, client_id) == REDISMODULE_ERR);
ci.version = 1;
if (RedisModule_GetClientInfoById(&ci, client_id) == REDISMODULE_ERR) {
RedisModule_ReplyWithError(ctx, "failed to get client info");
return REDISMODULE_OK;
}
......@@ -270,6 +279,27 @@ int test_clientinfo(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
return REDISMODULE_OK;
}
int test_getname(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
(void)argv;
if (argc != 1) return RedisModule_WrongArity(ctx);
unsigned long long id = RedisModule_GetClientId(ctx);
RedisModuleString *name = RedisModule_GetClientNameById(ctx, id);
if (name == NULL)
return RedisModule_ReplyWithError(ctx, "-ERR No name");
RedisModule_ReplyWithString(ctx, name);
RedisModule_FreeString(ctx, name);
return REDISMODULE_OK;
}
int test_setname(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
if (argc != 2) return RedisModule_WrongArity(ctx);
unsigned long long id = RedisModule_GetClientId(ctx);
if (RedisModule_SetClientNameById(id, argv[1]) == REDISMODULE_OK)
return RedisModule_ReplyWithSimpleString(ctx, "OK");
else
return RedisModule_ReplyWithError(ctx, strerror(errno));
}
int test_log_tsctx(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
{
RedisModuleCtx *tsctx = RedisModule_GetDetachedThreadSafeContext(ctx);
......@@ -354,6 +384,68 @@ int test_rm_call_flags(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){
return REDISMODULE_OK;
}
int test_ull_conv(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
UNUSED(argv);
UNUSED(argc);
unsigned long long ull = 18446744073709551615ULL;
const char *ullstr = "18446744073709551615";
RedisModuleString *s1 = RedisModule_CreateStringFromULongLong(ctx, ull);
RedisModuleString *s2 =
RedisModule_CreateString(ctx, ullstr, strlen(ullstr));
if (RedisModule_StringCompare(s1, s2) != 0) {
char err[4096];
snprintf(err, 4096,
"Failed to convert unsigned long long to string ('%s' != '%s')",
RedisModule_StringPtrLen(s1, NULL),
RedisModule_StringPtrLen(s2, NULL));
RedisModule_ReplyWithError(ctx, err);
goto final;
}
unsigned long long ull2 = 0;
if (RedisModule_StringToULongLong(s2, &ull2) == REDISMODULE_ERR) {
RedisModule_ReplyWithError(ctx,
"Failed to convert string to unsigned long long");
goto final;
}
if (ull2 != ull) {
char err[4096];
snprintf(err, 4096,
"Failed to convert string to unsigned long long (%llu != %llu)",
ull2,
ull);
RedisModule_ReplyWithError(ctx, err);
goto final;
}
/* Make sure we can't convert a string more than ULLONG_MAX or less than 0 */
ullstr = "18446744073709551616";
RedisModuleString *s3 = RedisModule_CreateString(ctx, ullstr, strlen(ullstr));
unsigned long long ull3;
if (RedisModule_StringToULongLong(s3, &ull3) == REDISMODULE_OK) {
RedisModule_ReplyWithError(ctx, "Invalid string successfully converted to unsigned long long");
RedisModule_FreeString(ctx, s3);
goto final;
}
RedisModule_FreeString(ctx, s3);
ullstr = "-1";
RedisModuleString *s4 = RedisModule_CreateString(ctx, ullstr, strlen(ullstr));
unsigned long long ull4;
if (RedisModule_StringToULongLong(s4, &ull4) == REDISMODULE_OK) {
RedisModule_ReplyWithError(ctx, "Invalid string successfully converted to unsigned long long");
RedisModule_FreeString(ctx, s4);
goto final;
}
RedisModule_FreeString(ctx, s4);
RedisModule_ReplyWithSimpleString(ctx, "ok");
final:
RedisModule_FreeString(ctx, s1);
RedisModule_FreeString(ctx, s2);
return REDISMODULE_OK;
}
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc);
......@@ -366,6 +458,8 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
return REDISMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"test.ld_conversion", test_ld_conv, "",0,0,0) == REDISMODULE_ERR)
return REDISMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"test.ull_conversion", test_ull_conv, "",0,0,0) == REDISMODULE_ERR)
return REDISMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"test.flushall", test_flushall,"",0,0,0) == REDISMODULE_ERR)
return REDISMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"test.dbsize", test_dbsize,"",0,0,0) == REDISMODULE_ERR)
......@@ -384,6 +478,10 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
return REDISMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"test.clientinfo", test_clientinfo,"",0,0,0) == REDISMODULE_ERR)
return REDISMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"test.getname", test_getname,"",0,0,0) == REDISMODULE_ERR)
return REDISMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"test.setname", test_setname,"",0,0,0) == REDISMODULE_ERR)
return REDISMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"test.redisversion", test_redisversion,"",0,0,0) == REDISMODULE_ERR)
return REDISMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"test.getclientcert", test_getclientcert,"",0,0,0) == REDISMODULE_ERR)
......
......@@ -12,6 +12,13 @@ if {$::simulate_error} {
}
}
test "Sentinel commands sanity check" {
foreach_sentinel_id id {
assert_equal {72} [llength [S $id command list]]
assert_equal {15} [S $id command count]
}
}
test "Basic failover works if the master is down" {
set old_port [RPort $master_id]
set addr [S 0 SENTINEL GET-MASTER-ADDR-BY-NAME mymaster]
......
......@@ -126,7 +126,7 @@ test "Sentinels (re)connection following master ACL change" {
wait_for_condition 100 50 {
[string match "*disconnected*" [dict get [S $sent2re SENTINEL MASTER mymaster] flags]] != 0
} else {
fail "Expected: Sentinel to be disconnected from master due to wrong password"
fail "Expected: Restarted sentinel to be disconnected from master due to obsolete password"
}
# Verify sentinel with updated password managed to connect (wait for sentinelTimer to reconnect)
......@@ -137,8 +137,10 @@ test "Sentinels (re)connection following master ACL change" {
}
# Verify sentinel untouched gets failed to connect master
if {![string match "*disconnected*" [dict get [S $sent2un SENTINEL MASTER mymaster] flags]]} {
fail "Expected: Sentinel to be disconnected from master due to wrong password"
wait_for_condition 100 50 {
[string match "*disconnected*" [dict get [S $sent2un SENTINEL MASTER mymaster] flags]] != 0
} else {
fail "Expected: Sentinel to be disconnected from master due to obsolete password"
}
# Now update all sentinels with new password
......
......@@ -67,6 +67,33 @@ proc redis {{server 127.0.0.1} {port 6379} {defer 0} {tls 0} {tlsoptions {}} {re
interp alias {} ::redis::redisHandle$id {} ::redis::__dispatch__ $id
}
# On recent versions of tcl-tls/OpenSSL, reading from a dropped connection
# results with an error we need to catch and mimic the old behavior.
proc ::redis::redis_safe_read {fd len} {
if {$len == -1} {
set err [catch {set val [read $fd]} msg]
} else {
set err [catch {set val [read $fd $len]} msg]
}
if {!$err} {
return $val
}
if {[string match "*connection abort*" $msg]} {
return {}
}
error $msg
}
proc ::redis::redis_safe_gets {fd} {
if {[catch {set val [gets $fd]} msg]} {
if {[string match "*connection abort*" $msg]} {
return {}
}
error $msg
}
return $val
}
# This is a wrapper to the actual dispatching procedure that handles
# reconnection if needed.
proc ::redis::__dispatch__ {id method args} {
......@@ -148,8 +175,8 @@ proc ::redis::__method__read {id fd} {
::redis::redis_read_reply $id $fd
}
proc ::redis::__method__rawread {id fd len} {
return [read $fd $len]
proc ::redis::__method__rawread {id fd {len -1}} {
return [redis_safe_read $fd $len]
}
proc ::redis::__method__write {id fd buf} {
......@@ -207,8 +234,8 @@ proc ::redis::redis_writenl {fd buf} {
}
proc ::redis::redis_readnl {fd len} {
set buf [read $fd $len]
read $fd 2 ; # discard CR LF
set buf [redis_safe_read $fd $len]
redis_safe_read $fd 2 ; # discard CR LF
return $buf
}
......@@ -254,11 +281,11 @@ proc ::redis::redis_read_map {id fd} {
}
proc ::redis::redis_read_line fd {
string trim [gets $fd]
string trim [redis_safe_gets $fd]
}
proc ::redis::redis_read_null fd {
gets $fd
redis_safe_gets $fd
return {}
}
......@@ -281,7 +308,7 @@ proc ::redis::redis_read_reply {id fd} {
}
while {1} {
set type [read $fd 1]
set type [redis_safe_read $fd 1]
switch -exact -- $type {
_ {return [redis_read_null $fd]}
: -
......
......@@ -72,8 +72,8 @@ proc sanitizer_errors_from_file {filename} {
}
proc getInfoProperty {infostr property} {
if {[regexp "\r\n$property:(.*?)\r\n" $infostr _ value]} {
set _ $value
if {[regexp -lineanchor "^$property:(.*?)\r\n" $infostr _ value]} {
return $value
}
}
......
......@@ -156,13 +156,13 @@ start_server {} {
test "client evicted due to pubsub subscriptions" {
r flushdb
# Since pubsub subscriptions cause a small overheatd this test uses a minimal maxmemory-clients config
# Since pubsub subscriptions cause a small overhead this test uses a minimal maxmemory-clients config
set temp_maxmemory_clients 200000
r config set maxmemory-clients $temp_maxmemory_clients
# Test eviction due to pubsub patterns
set rr [redis_client]
# Add patterns until list maxes out maxmemroy clients and causes client eviction
# Add patterns until list maxes out maxmemory clients and causes client eviction
catch {
for {set j 0} {$j < $temp_maxmemory_clients} {incr j} {
$rr psubscribe $j
......@@ -173,7 +173,7 @@ start_server {} {
# Test eviction due to pubsub channels
set rr [redis_client]
# Add patterns until list maxes out maxmemroy clients and causes client eviction
# Subscribe to global channels until list maxes out maxmemory clients and causes client eviction
catch {
for {set j 0} {$j < $temp_maxmemory_clients} {incr j} {
$rr subscribe $j
......@@ -182,6 +182,17 @@ start_server {} {
assert_match {I/O error reading reply} $e
$rr close
# Test eviction due to sharded pubsub channels
set rr [redis_client]
# Subscribe to sharded pubsub channels until list maxes out maxmemory clients and causes client eviction
catch {
for {set j 0} {$j < $temp_maxmemory_clients} {incr j} {
$rr ssubscribe $j
}
} e
assert_match {I/O error reading reply} $e
$rr close
# Restore config for next tests
r config set maxmemory-clients $maxmemory_clients
}
......
......@@ -3,9 +3,7 @@
source tests/support/cli.tcl
proc cluster_info {r field} {
if {[regexp "^$field:(.*?)\r\n" [$r cluster info] _ value]} {
set _ $value
}
set _ [getInfoProperty [$r cluster info] $field]
}
# Provide easy access to CLUSTER INFO properties. Same semantic as "proc s".
......@@ -315,6 +313,86 @@ test {Migrate the last slot away from a node using redis-cli} {
}
}
# Test redis-cli --cluster create, add-node with cluster-port.
# Create five nodes, three with custom cluster_port and two with default values.
start_server [list overrides [list cluster-enabled yes cluster-node-timeout 1 cluster-port [find_available_port $::baseport $::portcount]]] {
start_server [list overrides [list cluster-enabled yes cluster-node-timeout 1]] {
start_server [list overrides [list cluster-enabled yes cluster-node-timeout 1 cluster-port [find_available_port $::baseport $::portcount]]] {
start_server [list overrides [list cluster-enabled yes cluster-node-timeout 1]] {
start_server [list overrides [list cluster-enabled yes cluster-node-timeout 1 cluster-port [find_available_port $::baseport $::portcount]]] {
# The first three are used to test --cluster create.
# The last two are used to test --cluster add-node
set node1_rd [redis_client 0]
set node2_rd [redis_client -1]
set node3_rd [redis_client -2]
set node4_rd [redis_client -3]
set node5_rd [redis_client -4]
test {redis-cli --cluster create with cluster-port} {
exec src/redis-cli --cluster-yes --cluster create \
127.0.0.1:[srv 0 port] \
127.0.0.1:[srv -1 port] \
127.0.0.1:[srv -2 port]
wait_for_condition 1000 50 {
[csi 0 cluster_state] eq {ok} &&
[csi -1 cluster_state] eq {ok} &&
[csi -2 cluster_state] eq {ok}
} else {
fail "Cluster doesn't stabilize"
}
# Make sure each node can meet other nodes
assert_equal 3 [csi 0 cluster_known_nodes]
assert_equal 3 [csi -1 cluster_known_nodes]
assert_equal 3 [csi -2 cluster_known_nodes]
}
test {redis-cli --cluster add-node with cluster-port} {
# Adding node to the cluster (without cluster-port)
exec src/redis-cli --cluster-yes --cluster add-node \
127.0.0.1:[srv -3 port] \
127.0.0.1:[srv 0 port]
wait_for_condition 1000 50 {
[csi 0 cluster_state] eq {ok} &&
[csi -1 cluster_state] eq {ok} &&
[csi -2 cluster_state] eq {ok} &&
[csi -3 cluster_state] eq {ok}
} else {
fail "Cluster doesn't stabilize"
}
# Adding node to the cluster (with cluster-port)
exec src/redis-cli --cluster-yes --cluster add-node \
127.0.0.1:[srv -4 port] \
127.0.0.1:[srv 0 port]
wait_for_condition 1000 50 {
[csi 0 cluster_state] eq {ok} &&
[csi -1 cluster_state] eq {ok} &&
[csi -2 cluster_state] eq {ok} &&
[csi -3 cluster_state] eq {ok} &&
[csi -4 cluster_state] eq {ok}
} else {
fail "Cluster doesn't stabilize"
}
# Make sure each node can meet other nodes
assert_equal 5 [csi 0 cluster_known_nodes]
assert_equal 5 [csi -1 cluster_known_nodes]
assert_equal 5 [csi -2 cluster_known_nodes]
assert_equal 5 [csi -3 cluster_known_nodes]
assert_equal 5 [csi -4 cluster_known_nodes]
}
# stop 5 servers
}
}
}
}
}
} ;# tags
set ::singledb $old_singledb
......@@ -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 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=2*}
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 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=2*}
test {CLIENT KILL with illegal arguments} {
assert_error "ERR wrong number of arguments for 'client|kill' command" {r client kill}
......@@ -503,6 +503,21 @@ start_server {tags {"introspection"}} {
assert_match {*'replicaof "--127.0.0.1"'*wrong number of arguments*} $err
} {} {external:skip}
test {redis-server command line arguments - allow passing option name and option value in the same arg} {
start_server {config "default.conf" args {"--maxmemory 700mb" "--maxmemory-policy volatile-lru"}} {
assert_match [r config get maxmemory] {maxmemory 734003200}
assert_match [r config get maxmemory-policy] {maxmemory-policy volatile-lru}
}
} {} {external:skip}
test {redis-server command line arguments - wrong usage that we support anyway} {
start_server {config "default.conf" args {loglevel verbose "--maxmemory '700mb'" "--maxmemory-policy 'volatile-lru'"}} {
assert_match [r config get loglevel] {loglevel verbose}
assert_match [r config get maxmemory] {maxmemory 734003200}
assert_match [r config get maxmemory-policy] {maxmemory-policy volatile-lru}
}
} {} {external:skip}
test {redis-server command line arguments - allow option value to use the `--` prefix} {
start_server {config "default.conf" args {--proc-title-template --my--title--template --loglevel verbose}} {
assert_match [r config get proc-title-template] {proc-title-template --my--title--template}
......@@ -510,15 +525,40 @@ start_server {tags {"introspection"}} {
}
} {} {external:skip}
test {redis-server command line arguments - option name and option value in the same arg and `--` prefix} {
start_server {config "default.conf" args {"--proc-title-template --my--title--template" "--loglevel verbose"}} {
assert_match [r config get proc-title-template] {proc-title-template --my--title--template}
assert_match [r config get loglevel] {loglevel verbose}
}
} {} {external:skip}
test {redis-server command line arguments - save with empty input} {
# Take `--loglevel` as the save option value.
catch {exec src/redis-server --save --loglevel verbose} err
assert_match {*'save "--loglevel" "verbose"'*Invalid save parameters*} $err
start_server {config "default.conf" args {--save --loglevel verbose}} {
assert_match [r config get save] {save {}}
assert_match [r config get loglevel] {loglevel verbose}
}
start_server {config "default.conf" args {--loglevel verbose --save}} {
assert_match [r config get save] {save {}}
assert_match [r config get loglevel] {loglevel verbose}
}
start_server {config "default.conf" args {--save {} --loglevel verbose}} {
assert_match [r config get save] {save {}}
assert_match [r config get loglevel] {loglevel verbose}
}
start_server {config "default.conf" args {--loglevel verbose --save {}}} {
assert_match [r config get save] {save {}}
assert_match [r config get loglevel] {loglevel verbose}
}
start_server {config "default.conf" args {--proc-title-template --save --save {} --loglevel verbose}} {
assert_match [r config get proc-title-template] {proc-title-template --save}
assert_match [r config get save] {save {}}
assert_match [r config get loglevel] {loglevel verbose}
}
} {} {external:skip}
test {redis-server command line arguments - take one bulk string with spaces for MULTI_ARG configs parsing} {
......
......@@ -76,6 +76,19 @@ start_server {tags {"modules"}} {
r do_bg_rm_call hgetall hash
} {foo bar}
test {RM_Call from blocked client with script mode} {
r do_bg_rm_call_format S hset k foo bar
} {1}
test {RM_Call from blocked client with oom mode} {
r config set maxmemory 1
# will set server.pre_command_oom_state to 1
assert_error {OOM command not allowed*} {r hset hash foo bar}
r config set maxmemory 0
# now its should be OK to call OOM commands
r do_bg_rm_call_format M hset k1 foo bar
} {1} {needs:config-maxmemory}
test {RESP version carries through to blocked client} {
for {set client_proto 2} {$client_proto <= 3} {incr client_proto} {
r hello $client_proto
......
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