Unverified Commit 3f14bfd8 authored by Loris Cro's avatar Loris Cro Committed by GitHub
Browse files

Merge pull request #1 from antirez/unstable

update to latest unstable
parents 8ea4bdd9 720d1fd3
...@@ -62,7 +62,7 @@ proc ::redis_cluster::__method__refresh_nodes_map {id} { ...@@ -62,7 +62,7 @@ proc ::redis_cluster::__method__refresh_nodes_map {id} {
lassign [split $ip_port :] start_host start_port lassign [split $ip_port :] start_host start_port
if {[catch { if {[catch {
set r {} set r {}
set r [redis $start_host $start_port] set r [redis $start_host $start_port 0 $::tls]
set nodes_descr [$r cluster nodes] set nodes_descr [$r cluster nodes]
$r close $r close
} e]} { } e]} {
...@@ -107,7 +107,7 @@ proc ::redis_cluster::__method__refresh_nodes_map {id} { ...@@ -107,7 +107,7 @@ proc ::redis_cluster::__method__refresh_nodes_map {id} {
# Connect to the node # Connect to the node
set link {} set link {}
catch {set link [redis $host $port]} catch {set link [redis $host $port 0 $::tls]}
# Build this node description as an hash. # Build this node description as an hash.
set node [dict create \ set node [dict create \
......
...@@ -39,8 +39,18 @@ array set ::redis::callback {} ...@@ -39,8 +39,18 @@ array set ::redis::callback {}
array set ::redis::state {} ;# State in non-blocking reply reading array set ::redis::state {} ;# State in non-blocking reply reading
array set ::redis::statestack {} ;# Stack of states, for nested mbulks array set ::redis::statestack {} ;# Stack of states, for nested mbulks
proc redis {{server 127.0.0.1} {port 6379} {defer 0}} { proc redis {{server 127.0.0.1} {port 6379} {defer 0} {tls 0} {tlsoptions {}}} {
set fd [socket $server $port] if {$tls} {
package require tls
::tls::init \
-cafile "$::tlsdir/ca.crt" \
-certfile "$::tlsdir/redis.crt" \
-keyfile "$::tlsdir/redis.key" \
{*}$tlsoptions
set fd [::tls::socket $server $port]
} else {
set fd [socket $server $port]
}
fconfigure $fd -translation binary fconfigure $fd -translation binary
set id [incr ::redis::id] set id [incr ::redis::id]
set ::redis::fd($id) $fd set ::redis::fd($id) $fd
...@@ -48,6 +58,7 @@ proc redis {{server 127.0.0.1} {port 6379} {defer 0}} { ...@@ -48,6 +58,7 @@ proc redis {{server 127.0.0.1} {port 6379} {defer 0}} {
set ::redis::blocking($id) 1 set ::redis::blocking($id) 1
set ::redis::deferred($id) $defer set ::redis::deferred($id) $defer
set ::redis::reconnect($id) 0 set ::redis::reconnect($id) 0
set ::redis::tls $tls
::redis::redis_reset_state $id ::redis::redis_reset_state $id
interp alias {} ::redis::redisHandle$id {} ::redis::__dispatch__ $id interp alias {} ::redis::redisHandle$id {} ::redis::__dispatch__ $id
} }
...@@ -72,7 +83,11 @@ proc ::redis::__dispatch__raw__ {id method argv} { ...@@ -72,7 +83,11 @@ proc ::redis::__dispatch__raw__ {id method argv} {
# Reconnect the link if needed. # Reconnect the link if needed.
if {$fd eq {}} { if {$fd eq {}} {
lassign $::redis::addr($id) host port lassign $::redis::addr($id) host port
set ::redis::fd($id) [socket $host $port] if {$::redis::tls} {
set ::redis::fd($id) [::tls::socket $host $port]
} else {
set ::redis::fd($id) [socket $host $port]
}
fconfigure $::redis::fd($id) -translation binary fconfigure $::redis::fd($id) -translation binary
set fd $::redis::fd($id) set fd $::redis::fd($id)
} }
......
...@@ -92,7 +92,11 @@ proc is_alive config { ...@@ -92,7 +92,11 @@ proc is_alive config {
proc ping_server {host port} { proc ping_server {host port} {
set retval 0 set retval 0
if {[catch { if {[catch {
set fd [socket $host $port] if {$::tls} {
set fd [::tls::socket $host $port]
} else {
set fd [socket $host $port]
}
fconfigure $fd -translation binary fconfigure $fd -translation binary
puts $fd "PING\r\n" puts $fd "PING\r\n"
flush $fd flush $fd
...@@ -136,7 +140,6 @@ proc tags {tags code} { ...@@ -136,7 +140,6 @@ proc tags {tags code} {
uplevel 1 $code uplevel 1 $code
set ::tags [lrange $::tags 0 end-[llength $tags]] set ::tags [lrange $::tags 0 end-[llength $tags]]
} }
proc start_server {options {code undefined}} { proc start_server {options {code undefined}} {
# If we are running against an external server, we just push the # If we are running against an external server, we just push the
# host/port pair in the stack the first time # host/port pair in the stack the first time
...@@ -145,7 +148,7 @@ proc start_server {options {code undefined}} { ...@@ -145,7 +148,7 @@ proc start_server {options {code undefined}} {
set srv {} set srv {}
dict set srv "host" $::host dict set srv "host" $::host
dict set srv "port" $::port dict set srv "port" $::port
set client [redis $::host $::port] set client [redis $::host $::port 0 $::tls]
dict set srv "client" $client dict set srv "client" $client
$client select 9 $client select 9
...@@ -178,6 +181,13 @@ proc start_server {options {code undefined}} { ...@@ -178,6 +181,13 @@ proc start_server {options {code undefined}} {
set data [split [exec cat "tests/assets/$baseconfig"] "\n"] set data [split [exec cat "tests/assets/$baseconfig"] "\n"]
set config {} set config {}
if {$::tls} {
dict set config "tls-cert-file" [format "%s/tests/tls/redis.crt" [pwd]]
dict set config "tls-key-file" [format "%s/tests/tls/redis.key" [pwd]]
dict set config "tls-dh-params-file" [format "%s/tests/tls/redis.dh" [pwd]]
dict set config "tls-ca-cert-file" [format "%s/tests/tls/ca.crt" [pwd]]
dict set config "loglevel" "debug"
}
foreach line $data { foreach line $data {
if {[string length $line] > 0 && [string index $line 0] ne "#"} { if {[string length $line] > 0 && [string index $line 0] ne "#"} {
set elements [split $line " "] set elements [split $line " "]
...@@ -192,7 +202,17 @@ proc start_server {options {code undefined}} { ...@@ -192,7 +202,17 @@ proc start_server {options {code undefined}} {
# start every server on a different port # start every server on a different port
set ::port [find_available_port [expr {$::port+1}]] set ::port [find_available_port [expr {$::port+1}]]
dict set config port $::port if {$::tls} {
dict set config "port" 0
dict set config "tls-port" $::port
dict set config "tls-cluster" "yes"
dict set config "tls-replication" "yes"
} else {
dict set config port $::port
}
set unixsocket [file normalize [format "%s/%s" [dict get $config "dir"] "socket"]]
dict set config "unixsocket" $unixsocket
# apply overrides from global space and arguments # apply overrides from global space and arguments
foreach {directive arguments} [concat $::global_overrides $overrides] { foreach {directive arguments} [concat $::global_overrides $overrides] {
...@@ -254,10 +274,11 @@ proc start_server {options {code undefined}} { ...@@ -254,10 +274,11 @@ proc start_server {options {code undefined}} {
} }
# setup properties to be able to initialize a client object # setup properties to be able to initialize a client object
set port_param [expr $::tls ? {"tls-port"} : {"port"}]
set host $::host set host $::host
set port $::port set port $::port
if {[dict exists $config bind]} { set host [dict get $config bind] } if {[dict exists $config bind]} { set host [dict get $config bind] }
if {[dict exists $config port]} { set port [dict get $config port] } if {[dict exists $config $port_param]} { set port [dict get $config $port_param] }
# setup config dict # setup config dict
dict set srv "config_file" $config_file dict set srv "config_file" $config_file
...@@ -267,6 +288,7 @@ proc start_server {options {code undefined}} { ...@@ -267,6 +288,7 @@ proc start_server {options {code undefined}} {
dict set srv "port" $port dict set srv "port" $port
dict set srv "stdout" $stdout dict set srv "stdout" $stdout
dict set srv "stderr" $stderr dict set srv "stderr" $stderr
dict set srv "unixsocket" $unixsocket
# if a block of code is supplied, we wait for the server to become # if a block of code is supplied, we wait for the server to become
# available, create a client object and kill the server afterwards # available, create a client object and kill the server afterwards
......
...@@ -15,6 +15,12 @@ proc assert {condition} { ...@@ -15,6 +15,12 @@ proc assert {condition} {
} }
} }
proc assert_no_match {pattern value} {
if {[string match $pattern $value]} {
error "assertion:Expected '$value' to not match '$pattern'"
}
}
proc assert_match {pattern value} { proc assert_match {pattern value} {
if {![string match $pattern $value]} { if {![string match $pattern $value]} {
error "assertion:Expected '$value' to match '$pattern'" error "assertion:Expected '$value' to match '$pattern'"
......
...@@ -395,7 +395,7 @@ proc colorstr {color str} { ...@@ -395,7 +395,7 @@ proc colorstr {color str} {
# of seconds to the specified Redis instance. # of seconds to the specified Redis instance.
proc start_write_load {host port seconds} { proc start_write_load {host port seconds} {
set tclsh [info nameofexecutable] set tclsh [info nameofexecutable]
exec $tclsh tests/helpers/gen_write_load.tcl $host $port $seconds & exec $tclsh tests/helpers/gen_write_load.tcl $host $port $seconds $::tls &
} }
# Stop a process generating write load executed with start_write_load. # Stop a process generating write load executed with start_write_load.
...@@ -423,7 +423,7 @@ proc lshuffle {list} { ...@@ -423,7 +423,7 @@ proc lshuffle {list} {
# of ops to the specified Redis instance. # of ops to the specified Redis instance.
proc start_bg_complex_data {host port db ops} { proc start_bg_complex_data {host port db ops} {
set tclsh [info nameofexecutable] set tclsh [info nameofexecutable]
exec $tclsh tests/helpers/bg_complex_data.tcl $host $port $db $ops & exec $tclsh tests/helpers/bg_complex_data.tcl $host $port $db $ops $::tls &
} }
# Stop a process generating write load executed with start_bg_complex_data. # Stop a process generating write load executed with start_bg_complex_data.
......
...@@ -63,6 +63,7 @@ set ::all_tests { ...@@ -63,6 +63,7 @@ set ::all_tests {
unit/lazyfree unit/lazyfree
unit/wait unit/wait
unit/pendingquerybuf unit/pendingquerybuf
unit/tls
} }
# Index to the next test to run in the ::all_tests list. # Index to the next test to run in the ::all_tests list.
set ::next_test 0 set ::next_test 0
...@@ -71,6 +72,7 @@ set ::host 127.0.0.1 ...@@ -71,6 +72,7 @@ set ::host 127.0.0.1
set ::port 21111 set ::port 21111
set ::traceleaks 0 set ::traceleaks 0
set ::valgrind 0 set ::valgrind 0
set ::tls 0
set ::stack_logging 0 set ::stack_logging 0
set ::verbose 0 set ::verbose 0
set ::quiet 0 set ::quiet 0
...@@ -92,6 +94,7 @@ set ::dont_clean 0 ...@@ -92,6 +94,7 @@ set ::dont_clean 0
set ::wait_server 0 set ::wait_server 0
set ::stop_on_failure 0 set ::stop_on_failure 0
set ::loop 0 set ::loop 0
set ::tlsdir "tests/tls"
# Set to 1 when we are running in client mode. The Redis test uses a # Set to 1 when we are running in client mode. The Redis test uses a
# server-client model to run tests simultaneously. The server instance # server-client model to run tests simultaneously. The server instance
...@@ -146,7 +149,7 @@ proc reconnect {args} { ...@@ -146,7 +149,7 @@ proc reconnect {args} {
set host [dict get $srv "host"] set host [dict get $srv "host"]
set port [dict get $srv "port"] set port [dict get $srv "port"]
set config [dict get $srv "config"] set config [dict get $srv "config"]
set client [redis $host $port] set client [redis $host $port 0 $::tls]
dict set srv "client" $client dict set srv "client" $client
# select the right db when we don't have to authenticate # select the right db when we don't have to authenticate
...@@ -166,7 +169,7 @@ proc redis_deferring_client {args} { ...@@ -166,7 +169,7 @@ proc redis_deferring_client {args} {
} }
# create client that defers reading reply # create client that defers reading reply
set client [redis [srv $level "host"] [srv $level "port"] 1] set client [redis [srv $level "host"] [srv $level "port"] 1 $::tls]
# select the right db and read the response (OK) # select the right db and read the response (OK)
$client select 9 $client select 9
...@@ -204,7 +207,7 @@ proc test_server_main {} { ...@@ -204,7 +207,7 @@ proc test_server_main {} {
if {!$::quiet} { if {!$::quiet} {
puts "Starting test server at port $port" puts "Starting test server at port $port"
} }
socket -server accept_test_clients -myaddr 127.0.0.1 $port socket -server accept_test_clients -myaddr 127.0.0.1 $port
# Start the client instances # Start the client instances
set ::clients_pids {} set ::clients_pids {}
...@@ -450,6 +453,7 @@ proc print_help_screen {} { ...@@ -450,6 +453,7 @@ proc print_help_screen {} {
"--stop Blocks once the first test fails." "--stop Blocks once the first test fails."
"--loop Execute the specified set of tests forever." "--loop Execute the specified set of tests forever."
"--wait-server Wait after server is started (so that you can attach a debugger)." "--wait-server Wait after server is started (so that you can attach a debugger)."
"--tls Run tests in TLS mode."
"--help Print this help screen." "--help Print this help screen."
} "\n"] } "\n"]
} }
...@@ -486,6 +490,13 @@ for {set j 0} {$j < [llength $argv]} {incr j} { ...@@ -486,6 +490,13 @@ for {set j 0} {$j < [llength $argv]} {incr j} {
} }
} elseif {$opt eq {--quiet}} { } elseif {$opt eq {--quiet}} {
set ::quiet 1 set ::quiet 1
} elseif {$opt eq {--tls}} {
package require tls 1.6
set ::tls 1
::tls::init \
-cafile "$::tlsdir/ca.crt" \
-certfile "$::tlsdir/redis.crt" \
-keyfile "$::tlsdir/redis.key"
} elseif {$opt eq {--host}} { } elseif {$opt eq {--host}} {
set ::external 1 set ::external 1
set ::host $arg set ::host $arg
...@@ -565,7 +576,11 @@ if {[llength $::single_tests] > 0} { ...@@ -565,7 +576,11 @@ if {[llength $::single_tests] > 0} {
} }
proc attach_to_replication_stream {} { proc attach_to_replication_stream {} {
set s [socket [srv 0 "host"] [srv 0 "port"]] if {$::tls} {
set s [::tls::socket [srv 0 "host"] [srv 0 "port"]]
} else {
set s [socket [srv 0 "host"] [srv 0 "port"]]
}
fconfigure $s -translation binary fconfigure $s -translation binary
puts -nonewline $s "SYNC\r\n" puts -nonewline $s "SYNC\r\n"
flush $s flush $s
......
...@@ -35,6 +35,32 @@ start_server {tags {"acl"}} { ...@@ -35,6 +35,32 @@ start_server {tags {"acl"}} {
set e set e
} {*WRONGPASS*} } {*WRONGPASS*}
test {Test password hashes can be added} {
r ACL setuser newuser #34344e4d60c2b6d639b7bd22e18f2b0b91bc34bf0ac5f9952744435093cfb4e6
catch {r AUTH newuser passwd4} e
assert {$e eq "OK"}
}
test {Test password hashes validate input} {
# Validate Length
catch {r ACL setuser newuser #34344e4d60c2b6d639b7bd22e18f2b0b91bc34bf0ac5f9952744435093cfb4e} e
# Validate character outside set
catch {r ACL setuser newuser #34344e4d60c2b6d639b7bd22e18f2b0b91bc34bf0ac5f9952744435093cfb4eq} e
set e
} {*Error in ACL SETUSER modifier*}
test {ACL GETUSER returns the password hash instead of the actual password} {
set passstr [dict get [r ACL getuser newuser] passwords]
assert_match {*34344e4d60c2b6d639b7bd22e18f2b0b91bc34bf0ac5f9952744435093cfb4e6*} $passstr
assert_no_match {*passwd4*} $passstr
}
test {Test hashed passwords removal} {
r ACL setuser newuser !34344e4d60c2b6d639b7bd22e18f2b0b91bc34bf0ac5f9952744435093cfb4e6
set passstr [dict get [r ACL getuser newuser] passwords]
assert_no_match {*34344e4d60c2b6d639b7bd22e18f2b0b91bc34bf0ac5f9952744435093cfb4e6*} $passstr
}
test {By default users are not able to access any command} { test {By default users are not able to access any command} {
catch {r SET foo bar} e catch {r SET foo bar} e
set e set e
...@@ -67,7 +93,7 @@ start_server {tags {"acl"}} { ...@@ -67,7 +93,7 @@ start_server {tags {"acl"}} {
set e set e
} {*NOPERM*} } {*NOPERM*}
test {ACLs can include or excluse whole classes of commands} { test {ACLs can include or exclude whole classes of commands} {
r ACL setuser newuser -@all +@set +acl r ACL setuser newuser -@all +@set +acl
r SADD myset a b c; # Should not raise an error r SADD myset a b c; # Should not raise an error
r ACL setuser newuser +@all -@string r ACL setuser newuser +@all -@string
......
...@@ -129,7 +129,7 @@ start_server {tags {"geo"}} { ...@@ -129,7 +129,7 @@ start_server {tags {"geo"}} {
r del points r del points
r geoadd points -5.6 42.6 test r geoadd points -5.6 42.6 test
lindex [r geohash points test] 0 lindex [r geohash points test] 0
} {ezs42e44yx0} } {ezs42e44yx}
test {GEOPOS simple} { test {GEOPOS simple} {
r del points r del points
......
start_server {tags {"limits"} overrides {maxclients 10}} { start_server {tags {"limits"} overrides {maxclients 10}} {
if {$::tls} {
set expected_code "*I/O error*"
} else {
set expected_code "*ERR max*reached*"
}
test {Check if maxclients works refusing connections} { test {Check if maxclients works refusing connections} {
set c 0 set c 0
catch { catch {
...@@ -12,5 +17,5 @@ start_server {tags {"limits"} overrides {maxclients 10}} { ...@@ -12,5 +17,5 @@ start_server {tags {"limits"} overrides {maxclients 10}} {
} e } e
assert {$c > 8 && $c <= 10} assert {$c > 8 && $c <= 10}
set e set e
} {*ERR max*reached*} } $expected_code
} }
set testmodule [file normalize tests/modules/blockonkeys.so]
start_server {tags {"modules"}} {
r module load $testmodule
test {Module client blocked on keys (no metadata): No block} {
r del k
r fsl.push k 33
r fsl.push k 34
r fsl.bpop2 k 0
} {34 33}
test {Module client blocked on keys (no metadata): Timeout} {
r del k
set rd [redis_deferring_client]
r fsl.push k 33
$rd fsl.bpop2 k 1
assert_equal {Request timedout} [$rd read]
}
test {Module client blocked on keys (no metadata): Blocked, case 1} {
r del k
set rd [redis_deferring_client]
r fsl.push k 33
$rd fsl.bpop2 k 0
r fsl.push k 34
assert_equal {34 33} [$rd read]
}
test {Module client blocked on keys (no metadata): Blocked, case 2} {
r del k
set rd [redis_deferring_client]
r fsl.push k 33
r fsl.push k 34
$rd fsl.bpop2 k 0
assert_equal {34 33} [$rd read]
}
test {Module client blocked on keys (with metadata): No block} {
r del k
r fsl.push k 34
r fsl.bpopgt k 30 0
} {34}
test {Module client blocked on keys (with metadata): Timeout} {
r del k
set rd [redis_deferring_client]
r fsl.push k 33
$rd fsl.bpopgt k 35 1
assert_equal {Request timedout} [$rd read]
}
test {Module client blocked on keys (with metadata): Blocked, case 1} {
r del k
set rd [redis_deferring_client]
r fsl.push k 33
$rd fsl.bpopgt k 33 0
r fsl.push k 34
assert_equal {34} [$rd read]
}
test {Module client blocked on keys (with metadata): Blocked, case 2} {
r del k
set rd [redis_deferring_client]
$rd fsl.bpopgt k 35 0
r fsl.push k 33
r fsl.push k 34
r fsl.push k 35
r fsl.push k 36
assert_equal {36} [$rd read]
}
test {Module client blocked on keys does not wake up on wrong type} {
r del k
set rd [redis_deferring_client]
$rd fsl.bpop2 k 0
r lpush k 12
r lpush k 13
r lpush k 14
r del k
r fsl.push k 33
r fsl.push k 34
assert_equal {34 33} [$rd read]
}
}
set testmodule [file normalize tests/modules/fork.so]
proc count_log_message {pattern} {
set result [exec grep -c $pattern < [srv 0 stdout]]
}
start_server {tags {"modules"}} {
r module load $testmodule
test {Module fork} {
# the argument to fork.create is the exitcode on termination
r fork.create 3
wait_for_condition 20 100 {
[r fork.exitcode] != -1
} else {
fail "fork didn't terminate"
}
r fork.exitcode
} {3}
test {Module fork kill} {
r fork.create 3
after 20
r fork.kill
after 100
assert {[count_log_message "fork child started"] eq "2"}
assert {[count_log_message "Received SIGUSR1 in child"] eq "1"}
assert {[count_log_message "fork child exiting"] eq "1"}
}
}
set testmodule [file normalize tests/modules/hooks.so]
tags "modules" {
start_server {} {
r module load $testmodule
r config set appendonly yes
test {Test clients connection / disconnection hooks} {
for {set j 0} {$j < 2} {incr j} {
set rd1 [redis_deferring_client]
$rd1 close
}
assert {[r hooks.event_count client-connected] > 1}
assert {[r hooks.event_count client-disconnected] > 1}
}
test {Test module cron hook} {
after 100
assert {[r hooks.event_count cron-loop] > 0}
set hz [r hooks.event_last cron-loop]
assert_equal $hz 10
}
test {Test module loaded / unloaded hooks} {
set othermodule [file normalize tests/modules/infotest.so]
r module load $othermodule
r module unload infotest
assert_equal [r hooks.event_last module-loaded] "infotest"
assert_equal [r hooks.event_last module-unloaded] "infotest"
}
test {Test module aofrw hook} {
r debug populate 1000 foo 10000 ;# 10mb worth of data
r config set rdbcompression no ;# rdb progress is only checked once in 2mb
r BGREWRITEAOF
waitForBgrewriteaof r
assert_equal [string match {*module-event-persistence-aof-start*} [exec tail -20 < [srv 0 stdout]]] 1
assert_equal [string match {*module-event-persistence-end*} [exec tail -20 < [srv 0 stdout]]] 1
}
test {Test module aof load and rdb/aof progress hooks} {
# create some aof tail (progress is checked only once in 1000 commands)
for {set j 0} {$j < 4000} {incr j} {
r set "bar$j" x
}
# set some configs that will cause many loading progress events during aof loading
r config set key-load-delay 1
r config set dynamic-hz no
r config set hz 500
r DEBUG LOADAOF
assert_equal [r hooks.event_last loading-aof-start] 0
assert_equal [r hooks.event_last loading-end] 0
assert {[r hooks.event_count loading-rdb-start] == 0}
assert {[r hooks.event_count loading-progress-rdb] >= 2} ;# comes from the preamble section
assert {[r hooks.event_count loading-progress-aof] >= 2}
}
# undo configs before next test
r config set dynamic-hz yes
r config set key-load-delay 0
test {Test module rdb save hook} {
# debug reload does: save, flush, load:
assert {[r hooks.event_count persistence-syncrdb-start] == 0}
assert {[r hooks.event_count loading-rdb-start] == 0}
r debug reload
assert {[r hooks.event_count persistence-syncrdb-start] == 1}
assert {[r hooks.event_count loading-rdb-start] == 1}
}
test {Test flushdb hooks} {
r flushdb
assert_equal [r hooks.event_last flush-start] 9
assert_equal [r hooks.event_last flush-end] 9
r flushall
assert_equal [r hooks.event_last flush-start] -1
assert_equal [r hooks.event_last flush-end] -1
}
# replication related tests
set master [srv 0 client]
set master_host [srv 0 host]
set master_port [srv 0 port]
start_server {} {
r module load $testmodule
set replica [srv 0 client]
set replica_host [srv 0 host]
set replica_port [srv 0 port]
$replica replicaof $master_host $master_port
wait_for_condition 50 100 {
[string match {*master_link_status:up*} [r info replication]]
} else {
fail "Can't turn the instance into a replica"
}
test {Test master link up hook} {
assert_equal [r hooks.event_count masterlink-up] 1
assert_equal [r hooks.event_count masterlink-down] 0
}
test {Test role-replica hook} {
assert_equal [r hooks.event_count role-replica] 1
assert_equal [r hooks.event_count role-master] 0
assert_equal [r hooks.event_last role-replica] [s 0 master_host]
}
test {Test replica-online hook} {
assert_equal [r -1 hooks.event_count replica-online] 1
assert_equal [r -1 hooks.event_count replica-offline] 0
}
test {Test master link down hook} {
r client kill type master
assert_equal [r hooks.event_count masterlink-down] 1
}
$replica replicaof no one
test {Test role-master hook} {
assert_equal [r hooks.event_count role-replica] 1
assert_equal [r hooks.event_count role-master] 1
assert_equal [r hooks.event_last role-master] {}
}
test {Test replica-offline hook} {
assert_equal [r -1 hooks.event_count replica-online] 1
assert_equal [r -1 hooks.event_count replica-offline] 1
}
# get the replica stdout, to be used by the next test
set replica_stdout [srv 0 stdout]
}
# look into the log file of the server that just exited
test {Test shutdown hook} {
assert_equal [string match {*module-event-shutdown*} [exec tail -5 < $replica_stdout]] 1
}
}
}
set testmodule [file normalize tests/modules/infotest.so]
# Return value for INFO property
proc field {info property} {
if {[regexp "\r\n$property:(.*?)\r\n" $info _ value]} {
set _ $value
}
}
start_server {tags {"modules"}} {
r module load $testmodule log-key 0
test {module info all} {
set info [r info all]
# info all does not contain modules
assert { ![string match "*Spanish*" $info] }
assert { ![string match "*infotest_*" $info] }
assert { [string match "*used_memory*" $info] }
}
test {module info everything} {
set info [r info everything]
# info everything contains all default sections, but not ones for crash report
assert { [string match "*infotest_global*" $info] }
assert { [string match "*Spanish*" $info] }
assert { [string match "*Italian*" $info] }
assert { [string match "*used_memory*" $info] }
assert { ![string match "*Klingon*" $info] }
field $info infotest_dos
} {2}
test {module info modules} {
set info [r info modules]
# info all does not contain modules
assert { [string match "*Spanish*" $info] }
assert { [string match "*infotest_global*" $info] }
assert { ![string match "*used_memory*" $info] }
}
test {module info one module} {
set info [r info INFOTEST]
# info all does not contain modules
assert { [string match "*Spanish*" $info] }
assert { ![string match "*used_memory*" $info] }
field $info infotest_global
} {-2}
test {module info one section} {
set info [r info INFOTEST_SPANISH]
assert { ![string match "*used_memory*" $info] }
assert { ![string match "*Italian*" $info] }
assert { ![string match "*infotest_global*" $info] }
field $info infotest_uno
} {one}
test {module info dict} {
set info [r info infotest_keyspace]
set keyspace [field $info infotest_db0]
set keys [scan [regexp -inline {keys\=([\d]*)} $keyspace] keys=%d]
} {3}
# TODO: test crash report.
}
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] }
}
}
set testmodule [file normalize tests/modules/propagate.so]
tags "modules" {
test {Modules can propagate in async and threaded contexts} {
start_server {} {
set replica [srv 0 client]
set replica_host [srv 0 host]
set replica_port [srv 0 port]
start_server [list overrides [list loadmodule "$testmodule"]] {
set master [srv 0 client]
set master_host [srv 0 host]
set master_port [srv 0 port]
# Start the replication process...
$replica replicaof $master_host $master_port
wait_for_sync $replica
after 1000
$master propagate-test
wait_for_condition 5000 10 {
([$replica get timer] eq "10") && \
([$replica get thread] eq "10")
} else {
fail "The two counters don't match the expected value."
}
}
}
}
}
set testmodule [file normalize tests/modules/testrdb.so] set testmodule [file normalize tests/modules/testrdb.so]
proc restart_and_wait {} {
catch {
r debug restart
}
# wait for the server to come back up
set retry 50
while {$retry} {
if {[catch { r ping }]} {
after 100
} else {
break
}
incr retry -1
}
}
tags "modules" { tags "modules" {
start_server [list overrides [list loadmodule "$testmodule"]] { test {modules are able to persist types} {
test {modules are able to persist types} { start_server [list overrides [list loadmodule "$testmodule"]] {
r testrdb.set.key key1 value1 r testrdb.set.key key1 value1
assert_equal "value1" [r testrdb.get.key key1] assert_equal "value1" [r testrdb.get.key key1]
r debug reload r debug reload
assert_equal "value1" [r testrdb.get.key key1] assert_equal "value1" [r testrdb.get.key key1]
} }
}
test {modules global are lost without aux} { test {modules global are lost without aux} {
set server_path [tmpdir "server.module-testrdb"]
start_server [list overrides [list loadmodule "$testmodule" "dir" $server_path]] {
r testrdb.set.before global1 r testrdb.set.before global1
assert_equal "global1" [r testrdb.get.before] assert_equal "global1" [r testrdb.get.before]
restart_and_wait }
start_server [list overrides [list loadmodule "$testmodule" "dir" $server_path]] {
assert_equal "" [r testrdb.get.before] assert_equal "" [r testrdb.get.before]
} }
} }
start_server [list overrides [list loadmodule "$testmodule 2"]] { test {modules are able to persist globals before and after} {
test {modules are able to persist globals before and after} { set server_path [tmpdir "server.module-testrdb"]
start_server [list overrides [list loadmodule "$testmodule 2" "dir" $server_path]] {
r testrdb.set.before global1 r testrdb.set.before global1
r testrdb.set.after global2 r testrdb.set.after global2
assert_equal "global1" [r testrdb.get.before] assert_equal "global1" [r testrdb.get.before]
assert_equal "global2" [r testrdb.get.after] assert_equal "global2" [r testrdb.get.after]
restart_and_wait }
start_server [list overrides [list loadmodule "$testmodule 2" "dir" $server_path]] {
assert_equal "global1" [r testrdb.get.before] assert_equal "global1" [r testrdb.get.before]
assert_equal "global2" [r testrdb.get.after] assert_equal "global2" [r testrdb.get.after]
} }
} }
start_server [list overrides [list loadmodule "$testmodule 1"]] { test {modules are able to persist globals just after} {
test {modules are able to persist globals just after} { set server_path [tmpdir "server.module-testrdb"]
start_server [list overrides [list loadmodule "$testmodule 1" "dir" $server_path]] {
r testrdb.set.after global2 r testrdb.set.after global2
assert_equal "global2" [r testrdb.get.after] assert_equal "global2" [r testrdb.get.after]
restart_and_wait }
start_server [list overrides [list loadmodule "$testmodule 1" "dir" $server_path]] {
assert_equal "global2" [r testrdb.get.after] assert_equal "global2" [r testrdb.get.after]
} }
} }
tags {repl} {
test {diskless loading short read with module} {
start_server [list overrides [list loadmodule "$testmodule"]] {
set replica [srv 0 client]
set replica_host [srv 0 host]
set replica_port [srv 0 port]
start_server [list overrides [list loadmodule "$testmodule"]] {
set master [srv 0 client]
set master_host [srv 0 host]
set master_port [srv 0 port]
# Set master and replica to use diskless replication
$master config set repl-diskless-sync yes
$master config set rdbcompression no
$replica config set repl-diskless-load swapdb
for {set k 0} {$k < 30} {incr k} {
r testrdb.set.key key$k [string repeat A [expr {int(rand()*1000000)}]]
}
# Start the replication process...
$master config set repl-diskless-sync-delay 0
$replica replicaof $master_host $master_port
# TODO: test short read handling # kill the replication at various points
set attempts 3
if {$::accurate} { set attempts 10 }
for {set i 0} {$i < $attempts} {incr i} {
# wait for the replica to start reading the rdb
# using the log file since the replica only responds to INFO once in 2mb
wait_for_log_message -1 "*Loading DB in memory*" 5 2000 1
# add some additional random sleep so that we kill the master on a different place each time
after [expr {int(rand()*100)}]
# kill the replica connection on the master
set killed [$master client kill type replica]
if {[catch {
set res [wait_for_log_message -1 "*Internal error in RDB*" 5 100 10]
if {$::verbose} {
puts $res
}
}]} {
puts "failed triggering short read"
# force the replica to try another full sync
$master client kill type replica
$master set asdf asdf
# the side effect of resizing the backlog is that it is flushed (16k is the min size)
$master config set repl-backlog-size [expr {16384 + $i}]
}
# wait for loading to stop (fail)
wait_for_condition 100 10 {
[s -1 loading] eq 0
} else {
fail "Replica didn't disconnect"
}
}
# enable fast shutdown
$master config set rdb-key-save-delay 0
}
}
}
}
} }
...@@ -306,4 +306,18 @@ start_server {tags {"multi"}} { ...@@ -306,4 +306,18 @@ start_server {tags {"multi"}} {
} }
close_replication_stream $repl close_replication_stream $repl
} }
test {DISCARD should not fail during OOM} {
set rd [redis_deferring_client]
$rd config set maxmemory 1
assert {[$rd read] eq {OK}}
r multi
catch {r set x 1} e
assert_match {OOM*} $e
r discard
$rd config set maxmemory 0
assert {[$rd read] eq {OK}}
$rd close
r ping
} {PONG}
} }
...@@ -166,7 +166,11 @@ start_server {tags {"other"}} { ...@@ -166,7 +166,11 @@ start_server {tags {"other"}} {
tags {protocol} { tags {protocol} {
test {PIPELINING stresser (also a regression for the old epoll bug)} { test {PIPELINING stresser (also a regression for the old epoll bug)} {
set fd2 [socket $::host $::port] if {$::tls} {
set fd2 [::tls::socket $::host $::port]
} else {
set fd2 [socket $::host $::port]
}
fconfigure $fd2 -encoding binary -translation binary fconfigure $fd2 -encoding binary -translation binary
puts -nonewline $fd2 "SELECT 9\r\n" puts -nonewline $fd2 "SELECT 9\r\n"
flush $fd2 flush $fd2
......
...@@ -72,7 +72,11 @@ start_server {tags {"protocol"}} { ...@@ -72,7 +72,11 @@ start_server {tags {"protocol"}} {
foreach seq [list "\x00" "*\x00" "$\x00"] { foreach seq [list "\x00" "*\x00" "$\x00"] {
incr c incr c
test "Protocol desync regression test #$c" { test "Protocol desync regression test #$c" {
set s [socket [srv 0 host] [srv 0 port]] if {$::tls} {
set s [::tls::socket [srv 0 host] [srv 0 port]]
} else {
set s [socket [srv 0 host] [srv 0 port]]
}
puts -nonewline $s $seq puts -nonewline $s $seq
set payload [string repeat A 1024]"\n" set payload [string repeat A 1024]"\n"
set test_start [clock seconds] set test_start [clock seconds]
......
start_server {tags {"tls"}} {
if {$::tls} {
package require tls
test {TLS: Not accepting non-TLS connections on a TLS port} {
set s [redis [srv 0 host] [srv 0 port]]
catch {$s PING} e
set e
} {*I/O error*}
test {TLS: Verify tls-auth-clients behaves as expected} {
set s [redis [srv 0 host] [srv 0 port]]
::tls::import [$s channel]
catch {$s PING} e
assert_match {*error*} $e
r CONFIG SET tls-auth-clients no
set s [redis [srv 0 host] [srv 0 port]]
::tls::import [$s channel]
catch {$s PING} e
assert_match {PONG} $e
r CONFIG SET tls-auth-clients yes
}
test {TLS: Verify tls-protocols behaves as expected} {
r CONFIG SET tls-protocols TLSv1
set s [redis [srv 0 host] [srv 0 port] 0 1 {-tls1 0}]
catch {$s PING} e
assert_match {*I/O error*} $e
set s [redis [srv 0 host] [srv 0 port] 0 1 {-tls1 1}]
catch {$s PING} e
assert_match {PONG} $e
r CONFIG SET tls-protocols TLSv1.1
set s [redis [srv 0 host] [srv 0 port] 0 1 {-tls1.1 0}]
catch {$s PING} e
assert_match {*I/O error*} $e
set s [redis [srv 0 host] [srv 0 port] 0 1 {-tls1.1 1}]
catch {$s PING} e
assert_match {PONG} $e
r CONFIG SET tls-protocols TLSv1.2
set s [redis [srv 0 host] [srv 0 port] 0 1 {-tls1.2 0}]
catch {$s PING} e
assert_match {*I/O error*} $e
set s [redis [srv 0 host] [srv 0 port] 0 1 {-tls1.2 1}]
catch {$s PING} e
assert_match {PONG} $e
r CONFIG SET tls-protocols ""
}
test {TLS: Verify tls-ciphers behaves as expected} {
r CONFIG SET tls-protocols TLSv1.2
r CONFIG SET tls-ciphers "DEFAULT:-AES128-SHA256"
set s [redis [srv 0 host] [srv 0 port] 0 1 {-cipher "-ALL:AES128-SHA256"}]
catch {$s PING} e
assert_match {*I/O error*} $e
set s [redis [srv 0 host] [srv 0 port] 0 1 {-cipher "-ALL:AES256-SHA256"}]
catch {$s PING} e
assert_match {PONG} $e
r CONFIG SET tls-ciphers "DEFAULT"
set s [redis [srv 0 host] [srv 0 port] 0 1 {-cipher "-ALL:AES128-SHA256"}]
catch {$s PING} e
assert_match {PONG} $e
r CONFIG SET tls-protocols ""
r CONFIG SET tls-ciphers "DEFAULT"
}
test {TLS: Verify tls-prefer-server-ciphers behaves as expected} {
r CONFIG SET tls-protocols TLSv1.2
r CONFIG SET tls-ciphers "AES128-SHA256:AES256-SHA256"
set s [redis [srv 0 host] [srv 0 port] 0 1 {-cipher "AES256-SHA256:AES128-SHA256"}]
catch {$s PING} e
assert_match {PONG} $e
assert_equal "AES256-SHA256" [dict get [::tls::status [$s channel]] cipher]
r CONFIG SET tls-prefer-server-ciphers yes
set s [redis [srv 0 host] [srv 0 port] 0 1 {-cipher "AES256-SHA256:AES128-SHA256"}]
catch {$s PING} e
assert_match {PONG} $e
assert_equal "AES128-SHA256" [dict get [::tls::status [$s channel]] cipher]
r CONFIG SET tls-protocols ""
r CONFIG SET tls-ciphers "DEFAULT"
}
}
}
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