diff options
author | Yossi Gottlieb <yossigo@gmail.com> | 2019-09-12 10:56:54 +0300 |
---|---|---|
committer | Yossi Gottlieb <yossigo@gmail.com> | 2019-10-07 21:06:13 +0300 |
commit | b087dd1db60ed23d9e59304deb0b1599437f6e23 (patch) | |
tree | 0533b9d4d626af5ab4b5fdb5d4a2eb500b12c163 /tests | |
parent | f4d37173fef8a020fe99a7b98e32a9201113cc09 (diff) | |
download | redis-b087dd1db60ed23d9e59304deb0b1599437f6e23.tar.gz |
TLS: Connections refactoring and TLS support.
* Introduce a connection abstraction layer for all socket operations and
integrate it across the code base.
* Provide an optional TLS connections implementation based on OpenSSL.
* Pull a newer version of hiredis with TLS support.
* Tests, redis-cli updates for TLS support.
Diffstat (limited to 'tests')
-rw-r--r-- | tests/cluster/run.tcl | 1 | ||||
-rw-r--r-- | tests/cluster/tests/04-resharding.tcl | 2 | ||||
-rw-r--r-- | tests/cluster/tests/12-replica-migration-2.tcl | 4 | ||||
-rw-r--r-- | tests/helpers/bg_block_op.tcl | 8 | ||||
-rw-r--r-- | tests/helpers/bg_complex_data.tcl | 8 | ||||
-rw-r--r-- | tests/helpers/gen_write_load.tcl | 8 | ||||
-rw-r--r-- | tests/instances.tcl | 26 | ||||
-rw-r--r-- | tests/integration/aof-race.tcl | 7 | ||||
-rw-r--r-- | tests/integration/aof.tcl | 12 | ||||
-rw-r--r-- | tests/integration/block-repl.tcl | 10 | ||||
-rw-r--r-- | tests/integration/psync2-reg.tcl | 3 | ||||
-rw-r--r-- | tests/integration/redis-cli.tcl | 9 | ||||
-rw-r--r-- | tests/integration/replication.tcl | 14 | ||||
-rw-r--r-- | tests/sentinel/tests/07-down-conditions.tcl | 3 | ||||
-rw-r--r-- | tests/support/cli.tcl | 19 | ||||
-rw-r--r-- | tests/support/cluster.tcl | 4 | ||||
-rw-r--r-- | tests/support/redis.tcl | 20 | ||||
-rw-r--r-- | tests/support/server.tcl | 32 | ||||
-rw-r--r-- | tests/support/util.tcl | 4 | ||||
-rw-r--r-- | tests/test_helper.tcl | 23 | ||||
-rw-r--r-- | tests/unit/limits.tcl | 7 | ||||
-rw-r--r-- | tests/unit/other.tcl | 6 | ||||
-rw-r--r-- | tests/unit/protocol.tcl | 6 | ||||
-rw-r--r-- | tests/unit/tls.tcl | 25 | ||||
-rw-r--r-- | tests/unit/wait.tcl | 5 |
25 files changed, 215 insertions, 51 deletions
diff --git a/tests/cluster/run.tcl b/tests/cluster/run.tcl index 93603ddc9..d9a7d7ee5 100644 --- a/tests/cluster/run.tcl +++ b/tests/cluster/run.tcl @@ -8,6 +8,7 @@ source ../instances.tcl source ../../support/cluster.tcl ; # Redis Cluster client. set ::instances_count 20 ; # How many instances we use at max. +set ::tlsdir "../../tls" proc main {} { parse_options diff --git a/tests/cluster/tests/04-resharding.tcl b/tests/cluster/tests/04-resharding.tcl index 68fba135e..33f861dc5 100644 --- a/tests/cluster/tests/04-resharding.tcl +++ b/tests/cluster/tests/04-resharding.tcl @@ -4,6 +4,7 @@ # are preseved across iterations. source "../tests/includes/init-tests.tcl" +source "../../../tests/support/cli.tcl" test "Create a 5 nodes cluster" { create_cluster 5 5 @@ -79,6 +80,7 @@ test "Cluster consistency during live resharding" { --cluster-to $target \ --cluster-slots 100 \ --cluster-yes \ + {*}[rediscli_tls_config "../../../tests"] \ | [info nameofexecutable] \ ../tests/helpers/onlydots.tcl \ &] 0] diff --git a/tests/cluster/tests/12-replica-migration-2.tcl b/tests/cluster/tests/12-replica-migration-2.tcl index 3d8b7b04b..dd18a979a 100644 --- a/tests/cluster/tests/12-replica-migration-2.tcl +++ b/tests/cluster/tests/12-replica-migration-2.tcl @@ -5,6 +5,7 @@ # other masters have slaves. source "../tests/includes/init-tests.tcl" +source "../../../tests/support/cli.tcl" # Create a cluster with 5 master and 15 slaves, to make sure there are no # empty masters and make rebalancing simpler to handle during the test. @@ -33,7 +34,9 @@ test "Resharding all the master #0 slots away from it" { set output [exec \ ../../../src/redis-cli --cluster rebalance \ 127.0.0.1:[get_instance_attrib redis 0 port] \ + {*}[rediscli_tls_config "../../../tests"] \ --cluster-weight ${master0_id}=0 >@ stdout ] + } test "Master #0 should lose its replicas" { @@ -51,6 +54,7 @@ test "Resharding back some slot to master #0" { set output [exec \ ../../../src/redis-cli --cluster rebalance \ 127.0.0.1:[get_instance_attrib redis 0 port] \ + {*}[rediscli_tls_config "../../../tests"] \ --cluster-weight ${master0_id}=.01 \ --cluster-use-empty-masters >@ stdout] } diff --git a/tests/helpers/bg_block_op.tcl b/tests/helpers/bg_block_op.tcl index 238d3874f..c8b323308 100644 --- a/tests/helpers/bg_block_op.tcl +++ b/tests/helpers/bg_block_op.tcl @@ -1,6 +1,8 @@ source tests/support/redis.tcl source tests/support/util.tcl +set ::tlsdir "tests/tls" + # This function sometimes writes sometimes blocking-reads from lists/sorted # sets. There are multiple processes like this executing at the same time # so that we have some chance to trap some corner condition if there is @@ -8,8 +10,8 @@ source tests/support/util.tcl # space to just a few elements, and balance the operations so that it is # unlikely that lists and zsets just get more data without ever causing # blocking. -proc bg_block_op {host port db ops} { - set r [redis $host $port] +proc bg_block_op {host port db ops tls} { + set r [redis $host $port 0 $tls] $r select $db for {set j 0} {$j < $ops} {incr j} { @@ -49,4 +51,4 @@ proc bg_block_op {host port db ops} { } } -bg_block_op [lindex $argv 0] [lindex $argv 1] [lindex $argv 2] [lindex $argv 3] +bg_block_op [lindex $argv 0] [lindex $argv 1] [lindex $argv 2] [lindex $argv 3] [lindex $argv 4] diff --git a/tests/helpers/bg_complex_data.tcl b/tests/helpers/bg_complex_data.tcl index dffd7c668..e888748a7 100644 --- a/tests/helpers/bg_complex_data.tcl +++ b/tests/helpers/bg_complex_data.tcl @@ -1,10 +1,12 @@ source tests/support/redis.tcl source tests/support/util.tcl -proc bg_complex_data {host port db ops} { - set r [redis $host $port] +set ::tlsdir "tests/tls" + +proc bg_complex_data {host port db ops tls} { + set r [redis $host $port 0 $tls] $r select $db createComplexDataset $r $ops } -bg_complex_data [lindex $argv 0] [lindex $argv 1] [lindex $argv 2] [lindex $argv 3] +bg_complex_data [lindex $argv 0] [lindex $argv 1] [lindex $argv 2] [lindex $argv 3] [lindex $argv 4] diff --git a/tests/helpers/gen_write_load.tcl b/tests/helpers/gen_write_load.tcl index 6d1a34516..fd6aad40c 100644 --- a/tests/helpers/gen_write_load.tcl +++ b/tests/helpers/gen_write_load.tcl @@ -1,8 +1,10 @@ source tests/support/redis.tcl -proc gen_write_load {host port seconds} { +set ::tlsdir "tests/tls" + +proc gen_write_load {host port seconds tls} { set start_time [clock seconds] - set r [redis $host $port 1] + set r [redis $host $port 0 $tls] $r select 9 while 1 { $r set [expr rand()] [expr rand()] @@ -12,4 +14,4 @@ proc gen_write_load {host port seconds} { } } -gen_write_load [lindex $argv 0] [lindex $argv 1] [lindex $argv 2] +gen_write_load [lindex $argv 0] [lindex $argv 1] [lindex $argv 2] [lindex $argv 3] diff --git a/tests/instances.tcl b/tests/instances.tcl index 357b34818..0a0cbab12 100644 --- a/tests/instances.tcl +++ b/tests/instances.tcl @@ -17,6 +17,7 @@ source ../support/test.tcl set ::verbose 0 set ::valgrind 0 +set ::tls 0 set ::pause_on_error 0 set ::simulate_error 0 set ::failed 0 @@ -69,7 +70,19 @@ proc spawn_instance {type base_port count {conf {}}} { # Write the instance config file. set cfgfile [file join $dirname $type.conf] set cfg [open $cfgfile w] - puts $cfg "port $port" + if {$::tls} { + puts $cfg "tls-port $port" + puts $cfg "tls-replication yes" + puts $cfg "tls-cluster yes" + puts $cfg "port 0" + puts $cfg [format "tls-cert-file %s/../../tls/redis.crt" [pwd]] + puts $cfg [format "tls-key-file %s/../../tls/redis.key" [pwd]] + puts $cfg [format "tls-dh-params-file %s/../../tls/redis.dh" [pwd]] + puts $cfg [format "tls-ca-cert-file %s/../../tls/ca.crt" [pwd]] + puts $cfg "loglevel debug" + } else { + puts $cfg "port $port" + } puts $cfg "dir ./$dirname" puts $cfg "logfile log.txt" # Add additional config files @@ -88,7 +101,7 @@ proc spawn_instance {type base_port count {conf {}}} { } # Push the instance into the right list - set link [redis 127.0.0.1 $port] + set link [redis 127.0.0.1 $port 0 $::tls] $link reconnect 1 lappend ::${type}_instances [list \ pid $pid \ @@ -148,6 +161,13 @@ proc parse_options {} { set ::simulate_error 1 } elseif {$opt eq {--valgrind}} { set ::valgrind 1 + } elseif {$opt eq {--tls}} { + package require tls 1.6 + ::tls::init \ + -cafile "$::tlsdir/ca.crt" \ + -certfile "$::tlsdir/redis.crt" \ + -keyfile "$::tlsdir/redis.key" + set ::tls 1 } elseif {$opt eq "--help"} { puts "Hello, I'm sentinel.tcl and I run Sentinel unit tests." puts "\nOptions:" @@ -492,7 +512,7 @@ proc restart_instance {type id} { } # Connect with it with a fresh link - set link [redis 127.0.0.1 $port] + set link [redis 127.0.0.1 $port 0 $::tls] $link reconnect 1 set_instance_attrib $type $id link $link diff --git a/tests/integration/aof-race.tcl b/tests/integration/aof-race.tcl index fb8d71083..2991e7962 100644 --- a/tests/integration/aof-race.tcl +++ b/tests/integration/aof-race.tcl @@ -13,8 +13,9 @@ tags {"aof"} { # cleaned after a child responsible for an AOF rewrite exited. This buffer # was subsequently appended to the new AOF, resulting in duplicate commands. start_server_aof [list dir $server_path] { - set client [redis [srv host] [srv port]] - set bench [open "|src/redis-benchmark -q -p [srv port] -c 20 -n 20000 incr foo" "r+"] + set client [redis [srv host] [srv port] 0 $::tls] + set bench [open "|src/redis-benchmark -q -s [srv unixsocket] -c 20 -n 20000 incr foo" "r+"] + after 100 # Benchmark should be running by now: start background rewrite @@ -29,7 +30,7 @@ tags {"aof"} { # Restart server to replay AOF start_server_aof [list dir $server_path] { - set client [redis [srv host] [srv port]] + set client [redis [srv host] [srv port] 0 $::tls] assert_equal 20000 [$client get foo] } } diff --git a/tests/integration/aof.tcl b/tests/integration/aof.tcl index e397faeeb..e276a6254 100644 --- a/tests/integration/aof.tcl +++ b/tests/integration/aof.tcl @@ -52,7 +52,7 @@ tags {"aof"} { assert_equal 1 [is_alive $srv] } - set client [redis [dict get $srv host] [dict get $srv port]] + set client [redis [dict get $srv host] [dict get $srv port] 0 $::tls] test "Truncated AOF loaded: we expect foo to be equal to 5" { assert {[$client get foo] eq "5"} @@ -69,7 +69,7 @@ tags {"aof"} { assert_equal 1 [is_alive $srv] } - set client [redis [dict get $srv host] [dict get $srv port]] + set client [redis [dict get $srv host] [dict get $srv port] 0 $::tls] test "Truncated AOF loaded: we expect foo to be equal to 6 now" { assert {[$client get foo] eq "6"} @@ -170,7 +170,7 @@ tags {"aof"} { } test "Fixed AOF: Keyspace should contain values that were parseable" { - set client [redis [dict get $srv host] [dict get $srv port]] + set client [redis [dict get $srv host] [dict get $srv port] 0 $::tls] wait_for_condition 50 100 { [catch {$client ping} e] == 0 } else { @@ -194,7 +194,7 @@ tags {"aof"} { } test "AOF+SPOP: Set should have 1 member" { - set client [redis [dict get $srv host] [dict get $srv port]] + set client [redis [dict get $srv host] [dict get $srv port] 0 $::tls] wait_for_condition 50 100 { [catch {$client ping} e] == 0 } else { @@ -218,7 +218,7 @@ tags {"aof"} { } test "AOF+SPOP: Set should have 1 member" { - set client [redis [dict get $srv host] [dict get $srv port]] + set client [redis [dict get $srv host] [dict get $srv port] 0 $::tls] wait_for_condition 50 100 { [catch {$client ping} e] == 0 } else { @@ -241,7 +241,7 @@ tags {"aof"} { } test "AOF+EXPIRE: List should be empty" { - set client [redis [dict get $srv host] [dict get $srv port]] + set client [redis [dict get $srv host] [dict get $srv port] 0 $::tls] wait_for_condition 50 100 { [catch {$client ping} e] == 0 } else { diff --git a/tests/integration/block-repl.tcl b/tests/integration/block-repl.tcl index c111b805b..07eceb228 100644 --- a/tests/integration/block-repl.tcl +++ b/tests/integration/block-repl.tcl @@ -2,9 +2,9 @@ # Unlike stream operations such operations are "pop" style, so they consume # the list or sorted set, and must be replicated correctly. -proc start_bg_block_op {host port db ops} { +proc start_bg_block_op {host port db ops tls} { set tclsh [info nameofexecutable] - exec $tclsh tests/helpers/bg_block_op.tcl $host $port $db $ops & + exec $tclsh tests/helpers/bg_block_op.tcl $host $port $db $ops $tls & } proc stop_bg_block_op {handle} { @@ -18,9 +18,9 @@ start_server {tags {"repl"}} { set master_port [srv -1 port] set slave [srv 0 client] - set load_handle0 [start_bg_block_op $master_host $master_port 9 100000] - set load_handle1 [start_bg_block_op $master_host $master_port 9 100000] - set load_handle2 [start_bg_block_op $master_host $master_port 9 100000] + set load_handle0 [start_bg_block_op $master_host $master_port 9 100000 $::tls] + set load_handle1 [start_bg_block_op $master_host $master_port 9 100000 $::tls] + set load_handle2 [start_bg_block_op $master_host $master_port 9 100000 $::tls] test {First server should have role slave after SLAVEOF} { $slave slaveof $master_host $master_port diff --git a/tests/integration/psync2-reg.tcl b/tests/integration/psync2-reg.tcl index 3d408368e..b5ad021e2 100644 --- a/tests/integration/psync2-reg.tcl +++ b/tests/integration/psync2-reg.tcl @@ -18,6 +18,7 @@ start_server {} { set R($j) [srv [expr 0-$j] client] set R_host($j) [srv [expr 0-$j] host] set R_port($j) [srv [expr 0-$j] port] + set R_unixsocket($j) [srv [expr 0-$j] unixsocket] if {$debug_msg} {puts "Log file: [srv [expr 0-$j] stdout]"} } @@ -36,7 +37,7 @@ start_server {} { } set cycle_start_time [clock milliseconds] - set bench_pid [exec src/redis-benchmark -p $R_port(0) -n 10000000 -r 1000 incr __rand_int__ > /dev/null &] + set bench_pid [exec src/redis-benchmark -s $R_unixsocket(0) -n 10000000 -r 1000 incr __rand_int__ > /dev/null &] while 1 { set elapsed [expr {[clock milliseconds]-$cycle_start_time}] if {$elapsed > $duration*1000} break diff --git a/tests/integration/redis-cli.tcl b/tests/integration/redis-cli.tcl index 40e4222e3..5d1635950 100644 --- a/tests/integration/redis-cli.tcl +++ b/tests/integration/redis-cli.tcl @@ -1,7 +1,10 @@ +source tests/support/cli.tcl + start_server {tags {"cli"}} { proc open_cli {} { set ::env(TERM) dumb - set fd [open [format "|src/redis-cli -p %d -n 9" [srv port]] "r+"] + set cmdline [rediscli [srv port] "-n 9"] + set fd [open "|$cmdline" "r+"] fconfigure $fd -buffering none fconfigure $fd -blocking false fconfigure $fd -translation binary @@ -54,8 +57,8 @@ start_server {tags {"cli"}} { } proc _run_cli {opts args} { - set cmd [format "src/redis-cli -p %d -n 9 $args" [srv port]] - foreach {key value} $opts { + set cmd [rediscli [srv port] [list -n 9 {*}$args]] + foreach {key value} $args { if {$key eq "pipe"} { set cmd "sh -c \"$value | $cmd\"" } diff --git a/tests/integration/replication.tcl b/tests/integration/replication.tcl index 5d32555b0..43bc684b4 100644 --- a/tests/integration/replication.tcl +++ b/tests/integration/replication.tcl @@ -29,6 +29,9 @@ start_server {tags {"repl"}} { $slave slaveof $master_host $master_port test {Slave enters handshake} { + if {$::tls} { + fail "TLS with repl-diskless-sync not supported yet." + } wait_for_condition 50 1000 { [string match *handshake* [$slave role]] } else { @@ -184,6 +187,10 @@ start_server {tags {"repl"}} { } foreach mdl {no yes} { + if {$::tls && $mdl eq "yes"} { + puts "** Skipping test: TLS with repl-diskless-sync not supported yet." + continue + } foreach sdl {disabled swapdb} { start_server {tags {"repl"}} { set master [srv 0 client] @@ -320,6 +327,9 @@ start_server {tags {"repl"}} { } test {slave fails full sync and diskless load swapdb recoveres it} { + if {$::tls} { + fail "" + } start_server {tags {"repl"}} { set slave [srv 0 client] set slave_host [srv 0 host] @@ -387,6 +397,10 @@ test {slave fails full sync and diskless load swapdb recoveres it} { } test {diskless loading short read} { + if {$::tls} { + fail "TLS with repl-diskless-sync not supported yet." + } + start_server {tags {"repl"}} { set replica [srv 0 client] set replica_host [srv 0 host] diff --git a/tests/sentinel/tests/07-down-conditions.tcl b/tests/sentinel/tests/07-down-conditions.tcl index fb2993b6f..a12ea3151 100644 --- a/tests/sentinel/tests/07-down-conditions.tcl +++ b/tests/sentinel/tests/07-down-conditions.tcl @@ -1,6 +1,7 @@ # Test conditions where an instance is considered to be down source "../tests/includes/init-tests.tcl" +source "../../../tests/support/cli.tcl" proc ensure_master_up {} { wait_for_condition 1000 50 { @@ -28,7 +29,7 @@ test "Crash the majority of Sentinels to prevent failovers for this unit" { test "SDOWN is triggered by non-responding but not crashed instance" { lassign [S 4 SENTINEL GET-MASTER-ADDR-BY-NAME mymaster] host port ensure_master_up - exec ../../../src/redis-cli -h $host -p $port debug sleep 10 > /dev/null & + exec ../../../src/redis-cli -h $host -p $port {*}[rediscli_tls_config "../../../tests"] debug sleep 10 > /dev/null & ensure_master_down ensure_master_up } diff --git a/tests/support/cli.tcl b/tests/support/cli.tcl new file mode 100644 index 000000000..37c902a50 --- /dev/null +++ b/tests/support/cli.tcl @@ -0,0 +1,19 @@ +proc rediscli_tls_config {testsdir} { + set tlsdir [file join $testsdir tls] + set cert [file join $tlsdir redis.crt] + set key [file join $tlsdir redis.key] + set cacert [file join $tlsdir ca.crt] + + if {$::tls} { + return [list --tls --cert $cert --key $key --cacert $cacert] + } else { + return {} + } +} + +proc rediscli {port {opts {}}} { + set cmd [list src/redis-cli -p $port] + lappend cmd {*}[rediscli_tls_config "tests"] + lappend cmd {*}$opts + return $cmd +} diff --git a/tests/support/cluster.tcl b/tests/support/cluster.tcl index 1576053b4..74587e1f7 100644 --- a/tests/support/cluster.tcl +++ b/tests/support/cluster.tcl @@ -62,7 +62,7 @@ proc ::redis_cluster::__method__refresh_nodes_map {id} { lassign [split $ip_port :] start_host start_port if {[catch { set r {} - set r [redis $start_host $start_port] + set r [redis $start_host $start_port 0 $::tls] set nodes_descr [$r cluster nodes] $r close } e]} { @@ -107,7 +107,7 @@ proc ::redis_cluster::__method__refresh_nodes_map {id} { # Connect to the node set link {} - catch {set link [redis $host $port]} + catch {set link [redis $host $port 0 $::tls]} # Build this node description as an hash. set node [dict create \ diff --git a/tests/support/redis.tcl b/tests/support/redis.tcl index cd8ae3a34..be6a11c7a 100644 --- a/tests/support/redis.tcl +++ b/tests/support/redis.tcl @@ -39,8 +39,17 @@ array set ::redis::callback {} array set ::redis::state {} ;# State in non-blocking reply reading array set ::redis::statestack {} ;# Stack of states, for nested mbulks -proc redis {{server 127.0.0.1} {port 6379} {defer 0}} { - set fd [socket $server $port] +proc redis {{server 127.0.0.1} {port 6379} {defer 0} {tls 0}} { + if {$tls} { + package require tls + ::tls::init \ + -cafile "$::tlsdir/ca.crt" \ + -certfile "$::tlsdir/redis.crt" \ + -keyfile "$::tlsdir/redis.key" + set fd [::tls::socket $server $port] + } else { + set fd [socket $server $port] + } fconfigure $fd -translation binary set id [incr ::redis::id] set ::redis::fd($id) $fd @@ -48,6 +57,7 @@ proc redis {{server 127.0.0.1} {port 6379} {defer 0}} { set ::redis::blocking($id) 1 set ::redis::deferred($id) $defer set ::redis::reconnect($id) 0 + set ::redis::tls $tls ::redis::redis_reset_state $id interp alias {} ::redis::redisHandle$id {} ::redis::__dispatch__ $id } @@ -72,7 +82,11 @@ proc ::redis::__dispatch__raw__ {id method argv} { # Reconnect the link if needed. if {$fd eq {}} { 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 set fd $::redis::fd($id) } diff --git a/tests/support/server.tcl b/tests/support/server.tcl index 0edb25d8a..b20f1ad36 100644 --- a/tests/support/server.tcl +++ b/tests/support/server.tcl @@ -92,7 +92,11 @@ proc is_alive config { proc ping_server {host port} { set retval 0 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 puts $fd "PING\r\n" flush $fd @@ -136,7 +140,6 @@ proc tags {tags code} { uplevel 1 $code set ::tags [lrange $::tags 0 end-[llength $tags]] } - proc start_server {options {code undefined}} { # If we are running against an external server, we just push the # host/port pair in the stack the first time @@ -145,7 +148,7 @@ proc start_server {options {code undefined}} { set srv {} dict set srv "host" $::host dict set srv "port" $::port - set client [redis $::host $::port] + set client [redis $::host $::port 0 $::tls] dict set srv "client" $client $client select 9 @@ -178,6 +181,13 @@ proc start_server {options {code undefined}} { set data [split [exec cat "tests/assets/$baseconfig"] "\n"] 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 { if {[string length $line] > 0 && [string index $line 0] ne "#"} { set elements [split $line " "] @@ -192,7 +202,17 @@ proc start_server {options {code undefined}} { # start every server on a different port 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 foreach {directive arguments} [concat $::global_overrides $overrides] { @@ -254,10 +274,11 @@ proc start_server {options {code undefined}} { } # setup properties to be able to initialize a client object + set port_param [expr $::tls ? {"tls-port"} : {"port"}] set host $::host set port $::port 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 dict set srv "config_file" $config_file @@ -267,6 +288,7 @@ proc start_server {options {code undefined}} { dict set srv "port" $port dict set srv "stdout" $stdout dict set srv "stderr" $stderr + dict set srv "unixsocket" $unixsocket # if a block of code is supplied, we wait for the server to become # available, create a client object and kill the server afterwards diff --git a/tests/support/util.tcl b/tests/support/util.tcl index c2e76afad..7ecf5b79c 100644 --- a/tests/support/util.tcl +++ b/tests/support/util.tcl @@ -395,7 +395,7 @@ proc colorstr {color str} { # of seconds to the specified Redis instance. proc start_write_load {host port seconds} { 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. @@ -423,7 +423,7 @@ proc lshuffle {list} { # of ops to the specified Redis instance. proc start_bg_complex_data {host port db ops} { 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. diff --git a/tests/test_helper.tcl b/tests/test_helper.tcl index 1442067f5..cb7e4e328 100644 --- a/tests/test_helper.tcl +++ b/tests/test_helper.tcl @@ -63,6 +63,7 @@ set ::all_tests { unit/lazyfree unit/wait unit/pendingquerybuf + unit/tls } # Index to the next test to run in the ::all_tests list. set ::next_test 0 @@ -71,6 +72,7 @@ set ::host 127.0.0.1 set ::port 21111 set ::traceleaks 0 set ::valgrind 0 +set ::tls 0 set ::stack_logging 0 set ::verbose 0 set ::quiet 0 @@ -92,6 +94,7 @@ set ::dont_clean 0 set ::wait_server 0 set ::stop_on_failure 0 set ::loop 0 +set ::tlsdir "tests/tls" # 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 @@ -146,7 +149,7 @@ proc reconnect {args} { set host [dict get $srv "host"] set port [dict get $srv "port"] set config [dict get $srv "config"] - set client [redis $host $port] + set client [redis $host $port 0 $::tls] dict set srv "client" $client # select the right db when we don't have to authenticate @@ -166,7 +169,7 @@ proc redis_deferring_client {args} { } # 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) $client select 9 @@ -204,7 +207,7 @@ proc test_server_main {} { if {!$::quiet} { 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 set ::clients_pids {} @@ -450,6 +453,7 @@ proc print_help_screen {} { "--stop Blocks once the first test fails." "--loop Execute the specified set of tests forever." "--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." } "\n"] } @@ -486,6 +490,13 @@ for {set j 0} {$j < [llength $argv]} {incr j} { } } elseif {$opt eq {--quiet}} { 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}} { set ::external 1 set ::host $arg @@ -565,7 +576,11 @@ if {[llength $::single_tests] > 0} { } 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 puts -nonewline $s "SYNC\r\n" flush $s diff --git a/tests/unit/limits.tcl b/tests/unit/limits.tcl index b37ea9b0f..38ba76208 100644 --- a/tests/unit/limits.tcl +++ b/tests/unit/limits.tcl @@ -1,4 +1,9 @@ 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} { set c 0 catch { @@ -12,5 +17,5 @@ start_server {tags {"limits"} overrides {maxclients 10}} { } e assert {$c > 8 && $c <= 10} set e - } {*ERR max*reached*} + } $expected_code } diff --git a/tests/unit/other.tcl b/tests/unit/other.tcl index 965902456..7720c055a 100644 --- a/tests/unit/other.tcl +++ b/tests/unit/other.tcl @@ -166,7 +166,11 @@ start_server {tags {"other"}} { tags {protocol} { 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 puts -nonewline $fd2 "SELECT 9\r\n" flush $fd2 diff --git a/tests/unit/protocol.tcl b/tests/unit/protocol.tcl index ac99c3abb..4dfdc6f59 100644 --- a/tests/unit/protocol.tcl +++ b/tests/unit/protocol.tcl @@ -72,7 +72,11 @@ start_server {tags {"protocol"}} { foreach seq [list "\x00" "*\x00" "$\x00"] { incr 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 set payload [string repeat A 1024]"\n" set test_start [clock seconds] diff --git a/tests/unit/tls.tcl b/tests/unit/tls.tcl new file mode 100644 index 000000000..58acdb6a9 --- /dev/null +++ b/tests/unit/tls.tcl @@ -0,0 +1,25 @@ +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 + + set resp [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 + } {} + } +} diff --git a/tests/unit/wait.tcl b/tests/unit/wait.tcl index e2f5d2942..c9cfa6ed4 100644 --- a/tests/unit/wait.tcl +++ b/tests/unit/wait.tcl @@ -1,3 +1,5 @@ +source tests/support/cli.tcl + start_server {tags {"wait"}} { start_server {} { set slave [srv 0 client] @@ -31,7 +33,8 @@ start_server {} { } test {WAIT should not acknowledge 1 additional copy if slave is blocked} { - exec src/redis-cli -h $slave_host -p $slave_port debug sleep 5 > /dev/null 2> /dev/null & + set cmd [rediscli $slave_port "-h $slave_host debug sleep 5"] + exec {*}$cmd > /dev/null 2> /dev/null & after 1000 ;# Give redis-cli the time to execute the command. $master set foo 0 $master incr foo |