diff --git a/tests/cluster/cluster.tcl b/tests/cluster/cluster.tcl index 0647914d..f9a0e180 100644 --- a/tests/cluster/cluster.tcl +++ b/tests/cluster/cluster.tcl @@ -42,6 +42,16 @@ proc get_myself id { return {} } +# Get a specific node by ID by parsing the CLUSTER NODES output +# of the instance Number 'instance_id' +proc get_node_by_id {instance_id node_id} { + set nodes [get_cluster_nodes $instance_id] + foreach n $nodes { + if {[dict get $n id] eq $node_id} {return $n} + } + return {} +} + # Return the value of the specified CLUSTER INFO field. proc CI {n field} { get_info_field [R $n cluster info] $field diff --git a/tests/integration/aof.tcl b/tests/integration/aof.tcl index 0e006e81..8b1527ff 100644 --- a/tests/integration/aof.tcl +++ b/tests/integration/aof.tcl @@ -87,7 +87,6 @@ tags {"aof"} { test "Bad format: Server should have logged an error" { set pattern "*Bad file format reading the append only file*" set retry 10 - #WIN_PORT_FIX 'tail -n1' -> 'tail -1' while {$retry} { set result [exec tail -1 < [dict get $srv stdout]] if {[string match $pattern $result]} { @@ -113,7 +112,6 @@ tags {"aof"} { test "Unfinished MULTI: Server should have logged an error" { set pattern "*Unexpected end of file reading the append only file*" set retry 10 - #WIN_PORT_FIX 'tail -n1' -> 'tail -1' while {$retry} { set result [exec tail -1 < [dict get $srv stdout]] if {[string match $pattern $result]} { @@ -138,7 +136,6 @@ tags {"aof"} { test "Short read: Server should have logged an error" { set pattern "*Unexpected end of file reading the append only file*" set retry 10 - #WIN_PORT_FIX 'tail -n1' -> 'tail -1' while {$retry} { set result [exec tail -1 < [dict get $srv stdout]] if {[string match $pattern $result]} { diff --git a/tests/integration/psync2.tcl b/tests/integration/psync2.tcl index d91969e3..3d9e5527 100644 --- a/tests/integration/psync2.tcl +++ b/tests/integration/psync2.tcl @@ -10,7 +10,7 @@ start_server {} { # Config set debug_msg 0 ; # Enable additional debug messages - set no_exit 0; ; # Do not exit at end of the test + set no_exit 0 ; # Do not exit at end of the test set duration 20 ; # Total test seconds @@ -175,6 +175,69 @@ start_server {} { assert {$sync_count == $new_sync_count} } + test "PSYNC2: Slave RDB restart with EVALSHA in backlog issue #4483" { + # Pick a random slave + set slave_id [expr {($master_id+1)%5}] + set sync_count [status $R($master_id) sync_full] + + # Make sure to replicate the first EVAL while the salve is online + # so that it's part of the scripts the master believes it's safe + # to propagate as EVALSHA. + $R($master_id) EVAL {return redis.call("incr","__mycounter")} 0 + $R($master_id) EVALSHA e6e0b547500efcec21eddb619ac3724081afee89 0 + + # Wait for the two to sync + wait_for_condition 50 1000 { + [$R($master_id) debug digest] == [$R($slave_id) debug digest] + } else { + fail "Slave not reconnecting" + } + + # Prevent the slave from receiving master updates, and at + # the same time send a new script several times to the + # master, so that we'll end with EVALSHA into the backlog. + $R($slave_id) slaveof 127.0.0.1 0 + + $R($master_id) EVALSHA e6e0b547500efcec21eddb619ac3724081afee89 0 + $R($master_id) EVALSHA e6e0b547500efcec21eddb619ac3724081afee89 0 + $R($master_id) EVALSHA e6e0b547500efcec21eddb619ac3724081afee89 0 + + catch { + $R($slave_id) config rewrite + $R($slave_id) debug restart + } + + # Reconfigure the slave correctly again, when it's back online. + set retry 50 + while {$retry} { + if {[catch { + $R($slave_id) slaveof $master_host $master_port + }]} { + after 1000 + } else { + break + } + incr retry -1 + } + + # The master should be back at 4 slaves eventually + wait_for_condition 50 1000 { + [status $R($master_id) connected_slaves] == 4 + } else { + fail "Slave not reconnecting" + } + set new_sync_count [status $R($master_id) sync_full] + assert {$sync_count == $new_sync_count} + + # However if the slave started with the full state of the + # scripting engine, we should now have the same digest. + wait_for_condition 50 1000 { + [$R($master_id) debug digest] == [$R($slave_id) debug digest] + } else { + fail "Debug digest mismatch between master and slave in post-restart handshake" + } + } + if {$no_exit} { while 1 { puts -nonewline .; flush stdout; after 1000} } diff --git a/tests/integration/replication-2.tcl b/tests/integration/replication-2.tcl index 9446e5cd..2ff19c3c 100644 --- a/tests/integration/replication-2.tcl +++ b/tests/integration/replication-2.tcl @@ -2,9 +2,12 @@ start_server {tags {"repl"}} { start_server {} { test {First server should have role slave after SLAVEOF} { r -1 slaveof [srv 0 host] [srv 0 port] - after 1000 - s -1 role - } {slave} + wait_for_condition 50 100 { + [s -1 master_link_status] eq {up} + } else { + fail "Replication not started." + } + } test {If min-slaves-to-write is honored, write is accepted} { r config set min-slaves-to-write 1 diff --git a/tests/integration/replication-3.tcl b/tests/integration/replication-3.tcl index 50dcb9a9..580be760 100644 --- a/tests/integration/replication-3.tcl +++ b/tests/integration/replication-3.tcl @@ -100,7 +100,6 @@ start_server {tags {"repl"}} { close $fd puts "Master - Slave inconsistency" puts "Run diff -u against /tmp/repldump*.txt for more info" - } set old_digest [r debug digest] @@ -109,5 +108,27 @@ start_server {tags {"repl"}} { set new_digest [r debug digest] assert {$old_digest eq $new_digest} } + + test {SLAVE can reload "lua" AUX RDB fields of duplicated scripts} { + # Force a Slave full resynchronization + r debug change-repl-id + r -1 client kill type master + + # Check that after a full resync the slave can still load + # correctly the RDB file: such file will contain "lua" AUX + # sections with scripts already in the memory of the master. + + wait_for_condition 50 100 { + [s -1 master_link_status] eq {up} + } else { + fail "Replication not started." + } + + wait_for_condition 50 100 { + [r debug digest] eq [r -1 debug digest] + } else { + fail "DEBUG DIGEST mismatch after full SYNC with many scripts" + } + } } } diff --git a/tests/sentinel/tests/05-manual.tcl b/tests/sentinel/tests/05-manual.tcl index 1a60d814..5214fdce 100644 --- a/tests/sentinel/tests/05-manual.tcl +++ b/tests/sentinel/tests/05-manual.tcl @@ -6,7 +6,8 @@ test "Manual failover works" { set old_port [RI $master_id tcp_port] set addr [S 0 SENTINEL GET-MASTER-ADDR-BY-NAME mymaster] assert {[lindex $addr 1] == $old_port} - S 0 SENTINEL FAILOVER mymaster + catch {S 0 SENTINEL FAILOVER mymaster} reply + assert {$reply eq "OK"} foreach_sentinel_id id { wait_for_condition 1000 50 { [lindex [S $id SENTINEL GET-MASTER-ADDR-BY-NAME mymaster] 1] != $old_port diff --git a/tests/unit/dump.tcl b/tests/unit/dump.tcl index f5a29a09..8bb0165c 100644 --- a/tests/unit/dump.tcl +++ b/tests/unit/dump.tcl @@ -308,4 +308,28 @@ start_server {tags {"dump"}} { } } + test {MIGRATE AUTH: correct and wrong password cases} { + set first [srv 0 client] + r del list + r lpush list a b c d + start_server {tags {"repl"}} { + set second [srv 0 client] + set second_host [srv 0 host] + set second_port [srv 0 port] + $second config set requirepass foobar + $second auth foobar + + assert {[$first exists list] == 1} + assert {[$second exists list] == 0} + set ret [r -1 migrate $second_host $second_port list 9 5000 AUTH foobar] + assert {$ret eq {OK}} + assert {[$second exists list] == 1} + assert {[$second lrange list 0 -1] eq {d c b a}} + + r -1 lpush list a b c d + $second config set requirepass foobar2 + catch {r -1 migrate $second_host $second_port list 9 5000 AUTH foobar} err + assert_match {*invalid password*} $err + } + } } diff --git a/tests/unit/latency-monitor.tcl b/tests/unit/latency-monitor.tcl index b736cad9..69da13f0 100644 --- a/tests/unit/latency-monitor.tcl +++ b/tests/unit/latency-monitor.tcl @@ -47,4 +47,18 @@ start_server {tags {"latency-monitor"}} { assert {[r latency reset] > 0} assert {[r latency latest] eq {}} } + + test {LATENCY of expire events are correctly collected} { + r config set latency-monitor-threshold 20 + r eval { + local i = 0 + while (i < 1000000) do + redis.call('sadd','mybigkey',i) + i = i+1 + end + } 0 + r pexpire mybigkey 1 + after 500 + assert_match {*expire-cycle*} [r latency latest] + } } diff --git a/tests/unit/protocol.tcl b/tests/unit/protocol.tcl index e8be6a52..68a8f76b 100644 --- a/tests/unit/protocol.tcl +++ b/tests/unit/protocol.tcl @@ -85,10 +85,9 @@ start_server {tags {"protocol"}} { flush $s incr payload_size [string length $payload] }]} { - #windows - don't read after reset set retval [gets $s] close $s - break + break } else { #windows - if data available, read line if {[read $s 1] ne ""} { diff --git a/tests/unit/type/hash.tcl b/tests/unit/type/hash.tcl index 0ddc22b9..deed6419 100644 --- a/tests/unit/type/hash.tcl +++ b/tests/unit/type/hash.tcl @@ -515,4 +515,22 @@ start_server {tags {"hash"}} { assert {[r object encoding myhash] eq {hashtable}} } } + + # The following test can only be executed if we don't use Valgrind, and if + # we are using x86_64 architecture, because: + # + # 1) Valgrind has floating point limitations, no support for 80 bits math. + # 2) Other archs may have the same limits. + # + # 1.23 cannot be represented correctly with 64 bit doubles, so we skip + # the test, since we are only testing pretty printing here and is not + # a bug if the program outputs things like 1.299999... +# if {!$::valgrind && [string match *x86_64* [exec uname -a]]} { +# test {Test HINCRBYFLOAT for correct float representation (issue #2846)} { +# r del myhash +# assert {[r hincrbyfloat myhash float 1.23] eq {1.23}} +# assert {[r hincrbyfloat myhash float 0.77] eq {2}} +# assert {[r hincrbyfloat myhash float -0.1] eq {1.9}} +# } +# } } diff --git a/tests/unit/type/incr.tcl b/tests/unit/type/incr.tcl index 2287aaae..a58710d3 100644 --- a/tests/unit/type/incr.tcl +++ b/tests/unit/type/incr.tcl @@ -144,4 +144,11 @@ start_server {tags {"incr"}} { r set foo 1 roundFloat [r incrbyfloat foo -1.1] } {-0.1} + + test {string to double with null terminator} { + r set foo 1 + r setrange foo 2 2 + catch {r incrbyfloat foo 1} err + format $err + } {ERR*valid*} } diff --git a/tests/unit/type/zset.tcl b/tests/unit/type/zset.tcl index 82f76bef..d8f3cfa5 100644 --- a/tests/unit/type/zset.tcl +++ b/tests/unit/type/zset.tcl @@ -388,7 +388,7 @@ start_server {tags {"zset"}} { 0 omega} } - test "ZRANGEBYLEX/ZREVRANGEBYLEX/ZCOUNT basics" { + test "ZRANGEBYLEX/ZREVRANGEBYLEX/ZLEXCOUNT basics" { create_default_lex_zset # inclusive range @@ -416,6 +416,22 @@ start_server {tags {"zset"}} { assert_equal {} [r zrevrangebylex zset \[elez \[elex] assert_equal {} [r zrevrangebylex zset (hill (omega] } + + test "ZLEXCOUNT advanced" { + create_default_lex_zset + + assert_equal 9 [r zlexcount zset - +] + assert_equal 0 [r zlexcount zset + -] + assert_equal 0 [r zlexcount zset + \[c] + assert_equal 0 [r zlexcount zset \[c -] + assert_equal 8 [r zlexcount zset \[bar +] + assert_equal 5 [r zlexcount zset \[bar \[foo] + assert_equal 4 [r zlexcount zset \[bar (foo] + assert_equal 4 [r zlexcount zset (bar \[foo] + assert_equal 3 [r zlexcount zset (bar (foo] + assert_equal 5 [r zlexcount zset - (foo] + assert_equal 1 [r zlexcount zset (maxstring +] + } test "ZRANGEBYSLEX with LIMIT" { create_default_lex_zset @@ -696,6 +712,10 @@ start_server {tags {"zset"}} { } } + test "ZSET commands don't accept the empty strings as valid score" { + assert_error "*not*float*" {r zadd myzset "" abc} + } + proc stressers {encoding} { if {$encoding == "ziplist"} { # Little extra to allow proper fuzzing in the sorting stresser