Unverified Commit 8a86bca5 authored by Yossi Gottlieb's avatar Yossi Gottlieb Committed by GitHub
Browse files

Improve test suite to handle external servers better. (#9033)

This commit revives the improves the ability to run the test suite against
external servers, instead of launching and managing `redis-server` processes as
part of the test fixture.

This capability existed in the past, using the `--host` and `--port` options.
However, it was quite limited and mostly useful when running a specific tests.
Attempting to run larger chunks of the test suite experienced many issues:

* Many tests depend on being able to start and control `redis-server` themselves,
and there's no clear distinction between external server compatible and other
tests.
* Cluster mode is not supported (resulting with `CROSSSLOT` errors).

This PR cleans up many things and makes it possible to run the entire test suite
against an external server. It also provides more fine grained controls to
handle cases where the external server supports a subset of the Redis commands,
limited number of databases, cluster mode, etc.

The tests directory now contains a `README.md` file that describes how this
works.

This commit also includes additional cleanups and fixes:

* Tests can now be tagged.
* Tag-based selection is now unified across `start_server`, `tags` and `test`.
* More information is provided about skipped or ignored tests.
* Repeated patterns in tests have been extracted to common procedures, both at a
  global level and on a per-test file basis.
* Cleaned up some cases where test setup was based on a previous test executing
  (a major anti-pattern that repeats itself in many places).
* Cleaned up some cases where test teardown was not part of a test (in the
  future we should have dedicated teardown code that executes even when tests
  fail).
* Fixed some tests that were flaky running on external servers.
parent c396fd91
......@@ -5,7 +5,7 @@ proc log_file_matches {log pattern} {
string match $pattern $content
}
start_server {tags {"repl network"}} {
start_server {tags {"repl network external:skip"}} {
set slave [srv 0 client]
set slave_host [srv 0 host]
set slave_port [srv 0 port]
......@@ -51,7 +51,7 @@ start_server {tags {"repl network"}} {
}
}
start_server {tags {"repl"}} {
start_server {tags {"repl external:skip"}} {
set A [srv 0 client]
set A_host [srv 0 host]
set A_port [srv 0 port]
......@@ -187,7 +187,7 @@ start_server {tags {"repl"}} {
}
}
start_server {tags {"repl"}} {
start_server {tags {"repl external:skip"}} {
r set mykey foo
start_server {} {
......@@ -252,7 +252,7 @@ start_server {tags {"repl"}} {
foreach mdl {no yes} {
foreach sdl {disabled swapdb} {
start_server {tags {"repl"}} {
start_server {tags {"repl external:skip"}} {
set master [srv 0 client]
$master config set repl-diskless-sync $mdl
$master config set repl-diskless-sync-delay 1
......@@ -340,7 +340,7 @@ foreach mdl {no yes} {
}
}
start_server {tags {"repl"}} {
start_server {tags {"repl external:skip"}} {
set master [srv 0 client]
set master_host [srv 0 host]
set master_port [srv 0 port]
......@@ -448,7 +448,7 @@ test {slave fails full sync and diskless load swapdb recovers it} {
assert_equal [$slave dbsize] 2000
}
}
}
} {} {external:skip}
test {diskless loading short read} {
start_server {tags {"repl"}} {
......@@ -547,7 +547,7 @@ test {diskless loading short read} {
$master config set rdb-key-save-delay 0
}
}
}
} {} {external:skip}
# get current stime and utime metrics for a thread (since it's creation)
proc get_cpu_metrics { statfile } {
......@@ -581,7 +581,7 @@ proc compute_cpu_usage {start end} {
# test diskless rdb pipe with multiple replicas, which may drop half way
start_server {tags {"repl"}} {
start_server {tags {"repl external:skip"}} {
set master [srv 0 client]
$master config set repl-diskless-sync yes
$master config set repl-diskless-sync-delay 1
......@@ -769,7 +769,7 @@ test "diskless replication child being killed is collected" {
}
}
}
}
} {} {external:skip}
test "diskless replication read pipe cleanup" {
# In diskless replication, we create a read pipe for the RDB, between the child and the parent.
......@@ -808,7 +808,7 @@ test "diskless replication read pipe cleanup" {
$master ping
}
}
}
} {} {external:skip}
test {replicaof right after disconnection} {
# this is a rare race condition that was reproduced sporadically by the psync2 unit.
......@@ -860,7 +860,7 @@ test {replicaof right after disconnection} {
}
}
}
}
} {} {external:skip}
test {Kill rdb child process if its dumping RDB is not useful} {
start_server {tags {"repl"}} {
......@@ -925,4 +925,4 @@ test {Kill rdb child process if its dumping RDB is not useful} {
}
}
}
}
} {} {external:skip}
......@@ -158,14 +158,14 @@ proc server_is_up {host port retrynum} {
# there must be some intersection. If ::denytags are used, no intersection
# is allowed. Returns 1 if tags are acceptable or 0 otherwise, in which
# case err_return names a return variable for the message to be logged.
proc tags_acceptable {err_return} {
proc tags_acceptable {tags err_return} {
upvar $err_return err
# If tags are whitelisted, make sure there's match
if {[llength $::allowtags] > 0} {
set matched 0
foreach tag $::allowtags {
if {[lsearch $::tags $tag] >= 0} {
if {[lsearch $tags $tag] >= 0} {
incr matched
}
}
......@@ -176,12 +176,27 @@ proc tags_acceptable {err_return} {
}
foreach tag $::denytags {
if {[lsearch $::tags $tag] >= 0} {
if {[lsearch $tags $tag] >= 0} {
set err "Tag: $tag denied"
return 0
}
}
if {$::external && [lsearch $tags "external:skip"] >= 0} {
set err "Not supported on external server"
return 0
}
if {$::singledb && [lsearch $tags "singledb:skip"] >= 0} {
set err "Not supported on singledb"
return 0
}
if {$::cluster_mode && [lsearch $tags "cluster:skip"] >= 0} {
set err "Not supported in cluster mode"
return 0
}
return 1
}
......@@ -191,7 +206,7 @@ proc tags {tags code} {
# we want to get rid of the quotes in order to have a proper list
set tags [string map { \" "" } $tags]
set ::tags [concat $::tags $tags]
if {![tags_acceptable err]} {
if {![tags_acceptable $::tags err]} {
incr ::num_aborted
send_data_packet $::test_server_fd ignore $err
set ::tags [lrange $::tags 0 end-[llength $tags]]
......@@ -268,6 +283,68 @@ proc dump_server_log {srv} {
puts "===== End of server log (pid $pid) =====\n"
}
proc run_external_server_test {code overrides} {
set srv {}
dict set srv "host" $::host
dict set srv "port" $::port
set client [redis $::host $::port 0 $::tls]
dict set srv "client" $client
if {!$::singledb} {
$client select 9
}
set config {}
dict set config "port" $::port
dict set srv "config" $config
# append the server to the stack
lappend ::servers $srv
if {[llength $::servers] > 1} {
if {$::verbose} {
puts "Notice: nested start_server statements in external server mode, test must be aware of that!"
}
}
r flushall
# store overrides
set saved_config {}
foreach {param val} $overrides {
dict set saved_config $param [lindex [r config get $param] 1]
r config set $param $val
# If we enable appendonly, wait for for rewrite to complete. This is
# required for tests that begin with a bg* command which will fail if
# the rewriteaof operation is not completed at this point.
if {$param == "appendonly" && $val == "yes"} {
waitForBgrewriteaof r
}
}
if {[catch {set retval [uplevel 2 $code]} error]} {
if {$::durable} {
set msg [string range $error 10 end]
lappend details $msg
lappend details $::errorInfo
lappend ::tests_failed $details
incr ::num_failed
send_data_packet $::test_server_fd err [join $details "\n"]
} else {
# Re-raise, let handler up the stack take care of this.
error $error $::errorInfo
}
}
# restore overrides
dict for {param val} $saved_config {
r config set $param $val
}
lpop ::servers
}
proc start_server {options {code undefined}} {
# setup defaults
set baseconfig "default.conf"
......@@ -304,7 +381,7 @@ proc start_server {options {code undefined}} {
}
# We skip unwanted tags
if {![tags_acceptable err]} {
if {![tags_acceptable $::tags err]} {
incr ::num_aborted
send_data_packet $::test_server_fd ignore $err
set ::tags [lrange $::tags 0 end-[llength $tags]]
......@@ -314,36 +391,8 @@ 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
if {$::external} {
if {[llength $::servers] == 0} {
set srv {}
dict set srv "host" $::host
dict set srv "port" $::port
set client [redis $::host $::port 0 $::tls]
dict set srv "client" $client
$client select 9
set config {}
dict set config "port" $::port
dict set srv "config" $config
# append the server to the stack
lappend ::servers $srv
}
r flushall
if {[catch {set retval [uplevel 1 $code]} error]} {
if {$::durable} {
set msg [string range $error 10 end]
lappend details $msg
lappend details $::errorInfo
lappend ::tests_failed $details
run_external_server_test $code $overrides
incr ::num_failed
send_data_packet $::test_server_fd err [join $details "\n"]
} else {
# Re-raise, let handler up the stack take care of this.
error $error $::errorInfo
}
}
set ::tags [lrange $::tags 0 end-[llength $tags]]
return
}
......
......@@ -85,6 +85,9 @@ proc assert_error {pattern code} {
}
proc assert_encoding {enc key} {
if {$::ignoreencoding} {
return
}
set dbg [r debug object $key]
assert_match "* encoding:$enc *" $dbg
}
......@@ -112,7 +115,7 @@ proc wait_for_condition {maxtries delay e _else_ elsescript} {
}
}
proc test {name code {okpattern undefined} {options undefined}} {
proc test {name code {okpattern undefined} {tags {}}} {
# abort if test name in skiptests
if {[lsearch $::skiptests $name] >= 0} {
incr ::num_skipped
......@@ -127,20 +130,11 @@ proc test {name code {okpattern undefined} {options undefined}} {
return
}
# check if tagged with at least 1 tag to allow when there *is* a list
# of tags to allow, because default policy is to run everything
if {[llength $::allowtags] > 0} {
set matched 0
foreach tag $::allowtags {
if {[lsearch $::tags $tag] >= 0} {
incr matched
}
}
if {$matched < 1} {
incr ::num_aborted
send_data_packet $::test_server_fd ignore $name
return
}
set tags [concat $::tags $tags]
if {![tags_acceptable $tags err]} {
incr ::num_aborted
send_data_packet $::test_server_fd ignore "$name: $err"
return
}
incr ::num_tests
......
......@@ -250,13 +250,19 @@ proc findKeyWithType {r type} {
}
proc createComplexDataset {r ops {opt {}}} {
set useexpire [expr {[lsearch -exact $opt useexpire] != -1}]
if {[lsearch -exact $opt usetag] != -1} {
set tag "{t}"
} else {
set tag ""
}
for {set j 0} {$j < $ops} {incr j} {
set k [randomKey]
set k2 [randomKey]
set k [randomKey]$tag
set k2 [randomKey]$tag
set f [randomValue]
set v [randomValue]
if {[lsearch -exact $opt useexpire] != -1} {
if {$useexpire} {
if {rand() < 0.1} {
{*}$r expire [randomKey] [randomInt 2]
}
......@@ -353,8 +359,15 @@ proc formatCommand {args} {
proc csvdump r {
set o {}
for {set db 0} {$db < 16} {incr db} {
{*}$r select $db
if {$::singledb} {
set maxdb 1
} else {
set maxdb 16
}
for {set db 0} {$db < $maxdb} {incr db} {
if {!$::singledb} {
{*}$r select $db
}
foreach k [lsort [{*}$r keys *]] {
set type [{*}$r type $k]
append o [csvstring $db] , [csvstring $k] , [csvstring $type] ,
......@@ -396,7 +409,9 @@ proc csvdump r {
}
}
}
{*}$r select 9
if {!$::singledb} {
{*}$r select 9
}
return $o
}
......@@ -540,7 +555,7 @@ proc stop_bg_complex_data {handle} {
catch {exec /bin/kill -9 $handle}
}
proc populate {num prefix size} {
proc populate {num {prefix key:} {size 3}} {
set rd [redis_deferring_client]
for {set j 0} {$j < $num} {incr j} {
$rd set $prefix$j [string repeat A $size]
......@@ -777,6 +792,30 @@ proc punsubscribe {client {channels {}}} {
consume_subscribe_messages $client punsubscribe $channels
}
proc debug_digest_value {key} {
if {!$::ignoredigest} {
r debug digest-value $key
} else {
return "dummy-digest-value"
}
}
proc wait_for_blocked_client {} {
wait_for_condition 50 100 {
[s blocked_clients] ne 0
} else {
fail "no blocked clients"
}
}
proc wait_for_blocked_clients_count {count {maxtries 100} {delay 10}} {
wait_for_condition $maxtries $delay {
[s blocked_clients] == $count
} else {
fail "Timeout waiting for blocked clients"
}
}
proc read_from_aof {fp} {
# Input fp is a blocking binary file descriptor of an opened AOF file.
if {[gets $fp count] == -1} return ""
......@@ -802,3 +841,27 @@ proc assert_aof_content {aof_path patterns} {
assert_match [lindex $patterns $j] [read_from_aof $fp]
}
}
proc config_set {param value {options {}}} {
set mayfail 0
foreach option $options {
switch $option {
"mayfail" {
set mayfail 1
}
default {
error "Unknown option $option"
}
}
}
if {[catch {r config set $param $value} err]} {
if {!$mayfail} {
error $err
} else {
if {$::verbose} {
puts "Ignoring CONFIG SET $param $value failure: $err"
}
}
}
}
......@@ -114,6 +114,10 @@ set ::stop_on_failure 0
set ::dump_logs 0
set ::loop 0
set ::tlsdir "tests/tls"
set ::singledb 0
set ::cluster_mode 0
set ::ignoreencoding 0
set ::ignoredigest 0
# 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
......@@ -191,7 +195,7 @@ proc reconnect {args} {
dict set srv "client" $client
# select the right db when we don't have to authenticate
if {![dict exists $config "requirepass"]} {
if {![dict exists $config "requirepass"] && !$::singledb} {
$client select 9
}
......@@ -210,8 +214,14 @@ proc redis_deferring_client {args} {
set client [redis [srv $level "host"] [srv $level "port"] 1 $::tls]
# select the right db and read the response (OK)
$client select 9
$client read
if {!$::singledb} {
$client select 9
$client read
} else {
# For timing/symmetry with the above select
$client ping
$client read
}
return $client
}
......@@ -225,8 +235,13 @@ proc redis_client {args} {
# create client that defers reading reply
set client [redis [srv $level "host"] [srv $level "port"] 0 $::tls]
# select the right db and read the response (OK)
$client select 9
# select the right db and read the response (OK), or at least ping
# the server if we're in a singledb mode.
if {$::singledb} {
$client ping
} else {
$client select 9
}
return $client
}
......@@ -552,6 +567,7 @@ proc print_help_screen {} {
"--config <k> <v> Extra config file argument."
"--skipfile <file> Name of a file containing test names that should be skipped (one per line)."
"--skiptest <name> Name of a file containing test names that should be skipped (one per line)."
"--tags <tags> Run only tests having specified tags or not having '-' prefixed tags."
"--dont-clean Don't delete redis log files after the run."
"--no-latency Skip latency measurements and validation by some tests."
"--stop Blocks once the first test fails."
......@@ -563,6 +579,10 @@ proc print_help_screen {} {
"--port <port> TCP port to use against external host."
"--baseport <port> Initial port number for spawned redis servers."
"--portcount <num> Port range for spawned redis servers."
"--singledb Use a single database, avoid SELECT."
"--cluster-mode Run tests in cluster protocol compatible mode."
"--ignore-encoding Don't validate object encoding."
"--ignore-digest Don't use debug digest validations."
"--help Print this help screen."
} "\n"]
}
......@@ -669,6 +689,15 @@ for {set j 0} {$j < [llength $argv]} {incr j} {
} elseif {$opt eq {--timeout}} {
set ::timeout $arg
incr j
} elseif {$opt eq {--singledb}} {
set ::singledb 1
} elseif {$opt eq {--cluster-mode}} {
set ::cluster_mode 1
set ::singledb 1
} elseif {$opt eq {--ignore-encoding}} {
set ::ignoreencoding 1
} elseif {$opt eq {--ignore-digest}} {
set ::ignoredigest 1
} elseif {$opt eq {--help}} {
print_help_screen
exit 0
......@@ -782,6 +811,7 @@ proc assert_replication_stream {s patterns} {
proc close_replication_stream {s} {
close $s
r config set repl-ping-replica-period 10
return
}
# With the parallel test running multiple Redis instances at the same time
......
start_server {tags {"acl"}} {
start_server {tags {"acl external:skip"}} {
test {Connections start with the default user} {
r ACL WHOAMI
} {default}
......@@ -482,7 +482,7 @@ start_server {tags {"acl"}} {
set server_path [tmpdir "server.acl"]
exec cp -f tests/assets/user.acl $server_path
start_server [list overrides [list "dir" $server_path "aclfile" "user.acl"]] {
start_server [list overrides [list "dir" $server_path "aclfile" "user.acl"] tags [list "external:skip"]] {
# user alice on allcommands allkeys >alice
# user bob on -@all +@set +acl ~set* >bob
# user default on nopass ~* +@all
......@@ -570,7 +570,7 @@ start_server [list overrides [list "dir" $server_path "aclfile" "user.acl"]] {
set server_path [tmpdir "resetchannels.acl"]
exec cp -f tests/assets/nodefaultuser.acl $server_path
exec cp -f tests/assets/default.conf $server_path
start_server [list overrides [list "dir" $server_path "acl-pubsub-default" "resetchannels" "aclfile" "nodefaultuser.acl"]] {
start_server [list overrides [list "dir" $server_path "acl-pubsub-default" "resetchannels" "aclfile" "nodefaultuser.acl"] tags [list "external:skip"]] {
test {Default user has access to all channels irrespective of flag} {
set channelinfo [dict get [r ACL getuser default] channels]
......@@ -609,7 +609,7 @@ start_server [list overrides [list "dir" $server_path "acl-pubsub-default" "rese
set server_path [tmpdir "resetchannels.acl"]
exec cp -f tests/assets/nodefaultuser.acl $server_path
exec cp -f tests/assets/default.conf $server_path
start_server [list overrides [list "dir" $server_path "acl-pubsub-default" "resetchannels" "aclfile" "nodefaultuser.acl"]] {
start_server [list overrides [list "dir" $server_path "acl-pubsub-default" "resetchannels" "aclfile" "nodefaultuser.acl"] tags [list "external:skip"]] {
test {Only default user has access to all channels irrespective of flag} {
set channelinfo [dict get [r ACL getuser default] channels]
......@@ -620,7 +620,7 @@ start_server [list overrides [list "dir" $server_path "acl-pubsub-default" "rese
}
start_server {overrides {user "default on nopass ~* +@all"}} {
start_server {overrides {user "default on nopass ~* +@all"} tags {"external:skip"}} {
test {default: load from config file, can access any channels} {
r SUBSCRIBE foo
r PSUBSCRIBE bar*
......
start_server {tags {"aofrw"}} {
start_server {tags {"aofrw external:skip"}} {
# Enable the AOF
r config set appendonly yes
r config set auto-aof-rewrite-percentage 0 ; # Disable auto-rewrite.
......@@ -57,7 +57,7 @@ start_server {tags {"aofrw"}} {
}
}
start_server {tags {"aofrw"} overrides {aof-use-rdb-preamble no}} {
start_server {tags {"aofrw external:skip"} overrides {aof-use-rdb-preamble no}} {
test {Turning off AOF kills the background writing child if any} {
r config set appendonly yes
waitForBgrewriteaof r
......
start_server {tags {"auth"}} {
start_server {tags {"auth external:skip"}} {
test {AUTH fails if there is no password configured server side} {
catch {r auth foo} err
set _ $err
} {ERR*any password*}
}
start_server {tags {"auth"} overrides {requirepass foobar}} {
start_server {tags {"auth external:skip"} overrides {requirepass foobar}} {
test {AUTH fails when a wrong password is given} {
catch {r auth wrong!} err
set _ $err
......@@ -26,7 +26,7 @@ start_server {tags {"auth"} overrides {requirepass foobar}} {
} {101}
}
start_server {tags {"auth_binary_password"}} {
start_server {tags {"auth_binary_password external:skip"}} {
test {AUTH fails when binary password is wrong} {
r config set requirepass "abc\x00def"
catch {r auth abc} err
......
......@@ -200,7 +200,7 @@ start_server {tags {"bitops"}} {
}
}
start_server {tags {"repl"}} {
start_server {tags {"repl external:skip"}} {
start_server {} {
set master [srv -1 client]
set master_host [srv -1 host]
......
......@@ -121,15 +121,15 @@ start_server {tags {"bitops"}} {
} {74}
test {BITOP NOT (empty string)} {
r set s ""
r bitop not dest s
r get dest
r set s{t} ""
r bitop not dest{t} s{t}
r get dest{t}
} {}
test {BITOP NOT (known string)} {
r set s "\xaa\x00\xff\x55"
r bitop not dest s
r get dest
r set s{t} "\xaa\x00\xff\x55"
r bitop not dest{t} s{t}
r get dest{t}
} "\x55\xff\x00\xaa"
test {BITOP where dest and target are the same key} {
......@@ -139,28 +139,28 @@ start_server {tags {"bitops"}} {
} "\x55\xff\x00\xaa"
test {BITOP AND|OR|XOR don't change the string with single input key} {
r set a "\x01\x02\xff"
r bitop and res1 a
r bitop or res2 a
r bitop xor res3 a
list [r get res1] [r get res2] [r get res3]
r set a{t} "\x01\x02\xff"
r bitop and res1{t} a{t}
r bitop or res2{t} a{t}
r bitop xor res3{t} a{t}
list [r get res1{t}] [r get res2{t}] [r get res3{t}]
} [list "\x01\x02\xff" "\x01\x02\xff" "\x01\x02\xff"]
test {BITOP missing key is considered a stream of zero} {
r set a "\x01\x02\xff"
r bitop and res1 no-suck-key a
r bitop or res2 no-suck-key a no-such-key
r bitop xor res3 no-such-key a
list [r get res1] [r get res2] [r get res3]
r set a{t} "\x01\x02\xff"
r bitop and res1{t} no-suck-key{t} a{t}
r bitop or res2{t} no-suck-key{t} a{t} no-such-key{t}
r bitop xor res3{t} no-such-key{t} a{t}
list [r get res1{t}] [r get res2{t}] [r get res3{t}]
} [list "\x00\x00\x00" "\x01\x02\xff" "\x01\x02\xff"]
test {BITOP shorter keys are zero-padded to the key with max length} {
r set a "\x01\x02\xff\xff"
r set b "\x01\x02\xff"
r bitop and res1 a b
r bitop or res2 a b
r bitop xor res3 a b
list [r get res1] [r get res2] [r get res3]
r set a{t} "\x01\x02\xff\xff"
r set b{t} "\x01\x02\xff"
r bitop and res1{t} a{t} b{t}
r bitop or res2{t} a{t} b{t}
r bitop xor res3{t} a{t} b{t}
list [r get res1{t}] [r get res2{t}] [r get res3{t}]
} [list "\x01\x02\xff\x00" "\x01\x02\xff\xff" "\x00\x00\x00\xff"]
foreach op {and or xor} {
......@@ -173,11 +173,11 @@ start_server {tags {"bitops"}} {
for {set j 0} {$j < $numvec} {incr j} {
set str [randstring 0 1000]
lappend vec $str
lappend veckeys vector_$j
r set vector_$j $str
lappend veckeys vector_$j{t}
r set vector_$j{t} $str
}
r bitop $op target {*}$veckeys
assert_equal [r get target] [simulate_bit_op $op {*}$vec]
r bitop $op target{t} {*}$veckeys
assert_equal [r get target{t}] [simulate_bit_op $op {*}$vec]
}
}
}
......@@ -186,32 +186,32 @@ start_server {tags {"bitops"}} {
for {set i 0} {$i < 10} {incr i} {
r flushall
set str [randstring 0 1000]
r set str $str
r bitop not target str
assert_equal [r get target] [simulate_bit_op not $str]
r set str{t} $str
r bitop not target{t} str{t}
assert_equal [r get target{t}] [simulate_bit_op not $str]
}
}
test {BITOP with integer encoded source objects} {
r set a 1
r set b 2
r bitop xor dest a b a
r get dest
r set a{t} 1
r set b{t} 2
r bitop xor dest{t} a{t} b{t} a{t}
r get dest{t}
} {2}
test {BITOP with non string source key} {
r del c
r set a 1
r set b 2
r lpush c foo
catch {r bitop xor dest a b c d} e
r del c{t}
r set a{t} 1
r set b{t} 2
r lpush c{t} foo
catch {r bitop xor dest{t} a{t} b{t} c{t} d{t}} e
set e
} {WRONGTYPE*}
test {BITOP with empty string after non empty string (issue #529)} {
r flushdb
r set a "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
r bitop or x a b
r set a{t} "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
r bitop or x{t} a{t} b{t}
} {32}
test {BITPOS bit=0 with empty key returns 0} {
......
......@@ -46,7 +46,7 @@ start_server {tags {"dump"}} {
catch {r debug object foo} e
r debug set-active-expire 1
set e
} {ERR no such key}
} {ERR no such key} {needs:debug}
test {RESTORE can set LRU} {
r set foo bar
......@@ -56,8 +56,9 @@ start_server {tags {"dump"}} {
r restore foo 0 $encoded idletime 1000
set idle [r object idletime foo]
assert {$idle >= 1000 && $idle <= 1010}
r get foo
} {bar}
assert_equal [r get foo] {bar}
r config set maxmemory-policy noeviction
} {OK} {needs:config-maxmemory}
test {RESTORE can set LFU} {
r set foo bar
......@@ -68,7 +69,9 @@ start_server {tags {"dump"}} {
set freq [r object freq foo]
assert {$freq == 100}
r get foo
} {bar}
assert_equal [r get foo] {bar}
r config set maxmemory-policy noeviction
} {OK} {needs:config-maxmemory}
test {RESTORE returns an error of the key already exists} {
r set foo bar
......@@ -111,7 +114,7 @@ start_server {tags {"dump"}} {
r -1 migrate $second_host $second_port key 9 1000
assert_match {*migrate_cached_sockets:1*} [r -1 info]
}
}
} {} {external:skip}
test {MIGRATE cached connections are released after some time} {
after 15000
......@@ -135,7 +138,7 @@ start_server {tags {"dump"}} {
assert {[$second get key] eq {Some Value}}
assert {[$second ttl key] == -1}
}
}
} {} {external:skip}
test {MIGRATE is able to copy a key between two instances} {
set first [srv 0 client]
......@@ -154,7 +157,7 @@ start_server {tags {"dump"}} {
assert {[$second exists list] == 1}
assert {[$first lrange list 0 -1] eq [$second lrange list 0 -1]}
}
}
} {} {external:skip}
test {MIGRATE will not overwrite existing keys, unless REPLACE is used} {
set first [srv 0 client]
......@@ -176,7 +179,7 @@ start_server {tags {"dump"}} {
assert {[$second exists list] == 1}
assert {[$first lrange list 0 -1] eq [$second lrange list 0 -1]}
}
}
} {} {external:skip}
test {MIGRATE propagates TTL correctly} {
set first [srv 0 client]
......@@ -196,7 +199,7 @@ start_server {tags {"dump"}} {
assert {[$second get key] eq {Some Value}}
assert {[$second ttl key] >= 7 && [$second ttl key] <= 10}
}
}
} {} {external:skip}
test {MIGRATE can correctly transfer large values} {
set first [srv 0 client]
......@@ -221,7 +224,7 @@ start_server {tags {"dump"}} {
assert {[$second ttl key] == -1}
assert {[$second llen key] == 40000*20}
}
}
} {} {external:skip}
test {MIGRATE can correctly transfer hashes} {
set first [srv 0 client]
......@@ -241,7 +244,7 @@ start_server {tags {"dump"}} {
assert {[$second exists key] == 1}
assert {[$second ttl key] == -1}
}
}
} {} {external:skip}
test {MIGRATE timeout actually works} {
set first [srv 0 client]
......@@ -260,7 +263,7 @@ start_server {tags {"dump"}} {
catch {r -1 migrate $second_host $second_port key 9 500} e
assert_match {IOERR*} $e
}
}
} {} {external:skip}
test {MIGRATE can migrate multiple keys at once} {
set first [srv 0 client]
......@@ -283,12 +286,12 @@ start_server {tags {"dump"}} {
assert {[$second get key2] eq {v2}}
assert {[$second get key3] eq {v3}}
}
}
} {} {external:skip}
test {MIGRATE with multiple keys must have empty key arg} {
catch {r MIGRATE 127.0.0.1 6379 NotEmpty 9 5000 keys a b c} e
set e
} {*empty string*}
} {*empty string*} {external:skip}
test {MIGRATE with multiple keys migrate just existing ones} {
set first [srv 0 client]
......@@ -314,7 +317,7 @@ start_server {tags {"dump"}} {
assert {[$second get key2] eq {v2}}
assert {[$second get key3] eq {v3}}
}
}
} {} {external:skip}
test {MIGRATE with multiple keys: stress command rewriting} {
set first [srv 0 client]
......@@ -330,7 +333,7 @@ start_server {tags {"dump"}} {
assert {[$first dbsize] == 0}
assert {[$second dbsize] == 15}
}
}
} {} {external:skip}
test {MIGRATE with multiple keys: delete just ack keys} {
set first [srv 0 client]
......@@ -350,7 +353,7 @@ start_server {tags {"dump"}} {
assert {[$first exists c] == 1}
assert {[$first exists d] == 1}
}
}
} {} {external:skip}
test {MIGRATE AUTH: correct and wrong password cases} {
set first [srv 0 client]
......@@ -375,5 +378,5 @@ start_server {tags {"dump"}} {
catch {r -1 migrate $second_host $second_port list 9 5000 AUTH foobar} err
assert_match {*WRONGPASS*} $err
}
}
} {} {external:skip}
}
......@@ -96,7 +96,9 @@ start_server {tags {"expire"}} {
# server is under pressure, so if it does not work give it a few more
# chances.
for {set j 0} {$j < 30} {incr j} {
r del x y z
r del x
r del y
r del z
r psetex x 100 somevalue
after 80
set a [r get x]
......@@ -172,32 +174,34 @@ start_server {tags {"expire"}} {
r psetex key1 500 a
r psetex key2 500 a
r psetex key3 500 a
set size1 [r dbsize]
assert_equal 3 [r dbsize]
# Redis expires random keys ten times every second so we are
# fairly sure that all the three keys should be evicted after
# one second.
after 1000
set size2 [r dbsize]
list $size1 $size2
} {3 0}
# two seconds.
wait_for_condition 20 100 {
[r dbsize] eq 0
} fail {
"Keys did not actively expire."
}
}
test {Redis should lazy expire keys} {
r flushdb
r debug set-active-expire 0
r psetex key1 500 a
r psetex key2 500 a
r psetex key3 500 a
r psetex key1{t} 500 a
r psetex key2{t} 500 a
r psetex key3{t} 500 a
set size1 [r dbsize]
# Redis expires random keys ten times every second so we are
# fairly sure that all the three keys should be evicted after
# one second.
after 1000
set size2 [r dbsize]
r mget key1 key2 key3
r mget key1{t} key2{t} key3{t}
set size3 [r dbsize]
r debug set-active-expire 1
list $size1 $size2 $size3
} {3 3 0}
} {3 3 0} {needs:debug}
test {EXPIRE should not resurrect keys (issue #1026)} {
r debug set-active-expire 0
......@@ -207,7 +211,7 @@ start_server {tags {"expire"}} {
r expire foo 10
r debug set-active-expire 1
r exists foo
} {0}
} {0} {needs:debug}
test {5 keys in, 5 keys out} {
r flushdb
......@@ -279,7 +283,7 @@ start_server {tags {"expire"}} {
} {-2}
# Start a new server with empty data and AOF file.
start_server {overrides {appendonly {yes} appendfilename {appendonly.aof} appendfsync always}} {
start_server {overrides {appendonly {yes} appendfilename {appendonly.aof} appendfsync always} tags {external:skip}} {
test {All time-to-live(TTL) in commands are propagated as absolute timestamp in milliseconds in AOF} {
# This test makes sure that expire times are propagated as absolute
# times to the AOF file and not as relative time, so that when the AOF
......@@ -417,7 +421,7 @@ start_server {tags {"expire"}} {
assert_equal [r pexpiretime foo16] "-1" ; # foo16 has no TTL
assert_equal [r pexpiretime foo17] $ttl17
assert_equal [r pexpiretime foo18] $ttl18
}
} {} {needs:debug}
}
test {All TTL in commands are propagated as absolute timestamp in replication stream} {
......@@ -484,7 +488,7 @@ start_server {tags {"expire"}} {
}
# Start another server to test replication of TTLs
start_server {} {
start_server {tags {needs:repl external:skip}} {
# Set the outer layer server as primary
set primary [srv -1 client]
set primary_host [srv -1 host]
......@@ -566,7 +570,7 @@ start_server {tags {"expire"}} {
r debug loadaof
set ttl [r ttl foo]
assert {$ttl <= 98 && $ttl > 90}
}
} {} {needs:debug}
test {GETEX use of PERSIST option should remove TTL} {
r set foo bar EX 100
......@@ -580,7 +584,7 @@ start_server {tags {"expire"}} {
after 2000
r debug loadaof
r ttl foo
} {-1}
} {-1} {needs:debug}
test {GETEX propagate as to replica as PERSIST, DEL, or nothing} {
set repl [attach_to_replication_stream]
......@@ -594,5 +598,5 @@ start_server {tags {"expire"}} {
{persist foo}
{del foo}
}
}
} {} {needs:repl}
}
......@@ -325,74 +325,74 @@ start_server {tags {"geo"}} {
}
test {GEORADIUS STORE option: syntax error} {
r del points
r geoadd points 13.361389 38.115556 "Palermo" \
15.087269 37.502669 "Catania"
catch {r georadius points 13.361389 38.115556 50 km store} e
r del points{t}
r geoadd points{t} 13.361389 38.115556 "Palermo" \
15.087269 37.502669 "Catania"
catch {r georadius points{t} 13.361389 38.115556 50 km store} e
set e
} {*ERR*syntax*}
test {GEOSEARCHSTORE STORE option: syntax error} {
catch {r geosearchstore abc points fromlonlat 13.361389 38.115556 byradius 50 km store abc} e
catch {r geosearchstore abc{t} points{t} fromlonlat 13.361389 38.115556 byradius 50 km store abc{t}} e
set e
} {*ERR*syntax*}
test {GEORANGE STORE option: incompatible options} {
r del points
r geoadd points 13.361389 38.115556 "Palermo" \
15.087269 37.502669 "Catania"
catch {r georadius points 13.361389 38.115556 50 km store points2 withdist} e
r del points{t}
r geoadd points{t} 13.361389 38.115556 "Palermo" \
15.087269 37.502669 "Catania"
catch {r georadius points{t} 13.361389 38.115556 50 km store points2{t} withdist} e
assert_match {*ERR*} $e
catch {r georadius points 13.361389 38.115556 50 km store points2 withhash} e
catch {r georadius points{t} 13.361389 38.115556 50 km store points2{t} withhash} e
assert_match {*ERR*} $e
catch {r georadius points 13.361389 38.115556 50 km store points2 withcoords} e
catch {r georadius points{t} 13.361389 38.115556 50 km store points2{t} withcoords} e
assert_match {*ERR*} $e
}
test {GEORANGE STORE option: plain usage} {
r del points
r geoadd points 13.361389 38.115556 "Palermo" \
15.087269 37.502669 "Catania"
r georadius points 13.361389 38.115556 500 km store points2
assert_equal [r zrange points 0 -1] [r zrange points2 0 -1]
r del points{t}
r geoadd points{t} 13.361389 38.115556 "Palermo" \
15.087269 37.502669 "Catania"
r georadius points{t} 13.361389 38.115556 500 km store points2{t}
assert_equal [r zrange points{t} 0 -1] [r zrange points2{t} 0 -1]
}
test {GEOSEARCHSTORE STORE option: plain usage} {
r geosearchstore points2 points fromlonlat 13.361389 38.115556 byradius 500 km
assert_equal [r zrange points 0 -1] [r zrange points2 0 -1]
r geosearchstore points2{t} points{t} fromlonlat 13.361389 38.115556 byradius 500 km
assert_equal [r zrange points{t} 0 -1] [r zrange points2{t} 0 -1]
}
test {GEORANGE STOREDIST option: plain usage} {
r del points
r geoadd points 13.361389 38.115556 "Palermo" \
15.087269 37.502669 "Catania"
r georadius points 13.361389 38.115556 500 km storedist points2
set res [r zrange points2 0 -1 withscores]
r del points{t}
r geoadd points{t} 13.361389 38.115556 "Palermo" \
15.087269 37.502669 "Catania"
r georadius points{t} 13.361389 38.115556 500 km storedist points2{t}
set res [r zrange points2{t} 0 -1 withscores]
assert {[lindex $res 1] < 1}
assert {[lindex $res 3] > 166}
assert {[lindex $res 3] < 167}
}
test {GEOSEARCHSTORE STOREDIST option: plain usage} {
r geosearchstore points2 points fromlonlat 13.361389 38.115556 byradius 500 km storedist
set res [r zrange points2 0 -1 withscores]
r geosearchstore points2{t} points{t} fromlonlat 13.361389 38.115556 byradius 500 km storedist
set res [r zrange points2{t} 0 -1 withscores]
assert {[lindex $res 1] < 1}
assert {[lindex $res 3] > 166}
assert {[lindex $res 3] < 167}
}
test {GEORANGE STOREDIST option: COUNT ASC and DESC} {
r del points
r geoadd points 13.361389 38.115556 "Palermo" \
15.087269 37.502669 "Catania"
r georadius points 13.361389 38.115556 500 km storedist points2 asc count 1
assert {[r zcard points2] == 1}
set res [r zrange points2 0 -1 withscores]
r del points{t}
r geoadd points{t} 13.361389 38.115556 "Palermo" \
15.087269 37.502669 "Catania"
r georadius points{t} 13.361389 38.115556 500 km storedist points2{t} asc count 1
assert {[r zcard points2{t}] == 1}
set res [r zrange points2{t} 0 -1 withscores]
assert {[lindex $res 0] eq "Palermo"}
r georadius points 13.361389 38.115556 500 km storedist points2 desc count 1
assert {[r zcard points2] == 1}
set res [r zrange points2 0 -1 withscores]
r georadius points{t} 13.361389 38.115556 500 km storedist points2{t} desc count 1
assert {[r zcard points2{t}] == 1}
set res [r zrange points2{t} 0 -1 withscores]
assert {[lindex $res 0] eq "Catania"}
}
......
......@@ -2,7 +2,7 @@ start_server {tags {"hll"}} {
test {HyperLogLog self test passes} {
catch {r pfselftest} e
set e
} {OK}
} {OK} {needs:pfdebug}
test {PFADD without arguments creates an HLL value} {
r pfadd hll
......@@ -57,11 +57,12 @@ start_server {tags {"hll"}} {
assert {[r pfdebug encoding hll] eq {dense}}
}
}
}
} {} {needs:pfdebug}
test {HyperLogLog sparse encoding stress test} {
for {set x 0} {$x < 1000} {incr x} {
r del hll1 hll2
r del hll1
r del hll2
set numele [randomInt 100]
set elements {}
for {set j 0} {$j < $numele} {incr j} {
......@@ -77,7 +78,7 @@ start_server {tags {"hll"}} {
# Cardinality estimated should match exactly.
assert {[r pfcount hll1] eq [r pfcount hll2]}
}
}
} {} {needs:pfdebug}
test {Corrupted sparse HyperLogLogs are detected: Additional at tail} {
r del hll
......@@ -144,34 +145,34 @@ start_server {tags {"hll"}} {
}
test {PFADD, PFCOUNT, PFMERGE type checking works} {
r set foo bar
catch {r pfadd foo 1} e
r set foo{t} bar
catch {r pfadd foo{t} 1} e
assert_match {*WRONGTYPE*} $e
catch {r pfcount foo} e
catch {r pfcount foo{t}} e
assert_match {*WRONGTYPE*} $e
catch {r pfmerge bar foo} e
catch {r pfmerge bar{t} foo{t}} e
assert_match {*WRONGTYPE*} $e
catch {r pfmerge foo bar} e
catch {r pfmerge foo{t} bar{t}} e
assert_match {*WRONGTYPE*} $e
}
test {PFMERGE results on the cardinality of union of sets} {
r del hll hll1 hll2 hll3
r pfadd hll1 a b c
r pfadd hll2 b c d
r pfadd hll3 c d e
r pfmerge hll hll1 hll2 hll3
r pfcount hll
r del hll{t} hll1{t} hll2{t} hll3{t}
r pfadd hll1{t} a b c
r pfadd hll2{t} b c d
r pfadd hll3{t} c d e
r pfmerge hll{t} hll1{t} hll2{t} hll3{t}
r pfcount hll{t}
} {5}
test {PFCOUNT multiple-keys merge returns cardinality of union #1} {
r del hll1 hll2 hll3
r del hll1{t} hll2{t} hll3{t}
for {set x 1} {$x < 10000} {incr x} {
r pfadd hll1 "foo-$x"
r pfadd hll2 "bar-$x"
r pfadd hll3 "zap-$x"
r pfadd hll1{t} "foo-$x"
r pfadd hll2{t} "bar-$x"
r pfadd hll3{t} "zap-$x"
set card [r pfcount hll1 hll2 hll3]
set card [r pfcount hll1{t} hll2{t} hll3{t}]
set realcard [expr {$x*3}]
set err [expr {abs($card-$realcard)}]
assert {$err < (double($card)/100)*5}
......@@ -179,17 +180,17 @@ start_server {tags {"hll"}} {
}
test {PFCOUNT multiple-keys merge returns cardinality of union #2} {
r del hll1 hll2 hll3
r del hll1{t} hll2{t} hll3{t}
set elements {}
for {set x 1} {$x < 10000} {incr x} {
for {set j 1} {$j <= 3} {incr j} {
set rint [randomInt 20000]
r pfadd hll$j $rint
r pfadd hll$j{t} $rint
lappend elements $rint
}
}
set realcard [llength [lsort -unique $elements]]
set card [r pfcount hll1 hll2 hll3]
set card [r pfcount hll1{t} hll2{t} hll3{t}]
set err [expr {abs($card-$realcard)}]
assert {$err < (double($card)/100)*5}
}
......@@ -198,7 +199,7 @@ start_server {tags {"hll"}} {
r del hll
r pfadd hll 1 2 3
llength [r pfdebug getreg hll]
} {16384}
} {16384} {needs:pfdebug}
test {PFADD / PFCOUNT cache invalidation works} {
r del hll
......
......@@ -6,7 +6,7 @@ proc errorstat {cmd} {
return [errorrstat $cmd r]
}
start_server {tags {"info"}} {
start_server {tags {"info" "external:skip"}} {
start_server {} {
test {errorstats: failed call authentication error} {
......
......@@ -21,9 +21,9 @@ start_server {tags {"introspection"}} {
test {TOUCH returns the number of existing keys specified} {
r flushdb
r set key1 1
r set key2 2
r touch key0 key1 key2 key3
r set key1{t} 1
r set key2{t} 2
r touch key0{t} key1{t} key2{t} key3{t}
} 2
test {command stats for GEOADD} {
......@@ -31,7 +31,7 @@ start_server {tags {"introspection"}} {
r GEOADD foo 0 0 bar
assert_match {*calls=1,*} [cmdstat geoadd]
assert_match {} [cmdstat zadd]
}
} {} {needs:config-resetstat}
test {command stats for EXPIRE} {
r config resetstat
......@@ -39,7 +39,7 @@ start_server {tags {"introspection"}} {
r EXPIRE foo 0
assert_match {*calls=1,*} [cmdstat expire]
assert_match {} [cmdstat del]
}
} {} {needs:config-resetstat}
test {command stats for BRPOP} {
r config resetstat
......@@ -47,21 +47,21 @@ start_server {tags {"introspection"}} {
r BRPOP list 0
assert_match {*calls=1,*} [cmdstat brpop]
assert_match {} [cmdstat rpop]
}
} {} {needs:config-resetstat}
test {command stats for MULTI} {
r config resetstat
r MULTI
r set foo bar
r GEOADD foo2 0 0 bar
r EXPIRE foo2 0
r set foo{t} bar
r GEOADD foo2{t} 0 0 bar
r EXPIRE foo2{t} 0
r EXEC
assert_match {*calls=1,*} [cmdstat multi]
assert_match {*calls=1,*} [cmdstat exec]
assert_match {*calls=1,*} [cmdstat set]
assert_match {*calls=1,*} [cmdstat expire]
assert_match {*calls=1,*} [cmdstat geoadd]
}
} {} {needs:config-resetstat}
test {command stats for scripts} {
r config resetstat
......@@ -75,5 +75,5 @@ start_server {tags {"introspection"}} {
assert_match {*calls=2,*} [cmdstat set]
assert_match {*calls=1,*} [cmdstat expire]
assert_match {*calls=1,*} [cmdstat geoadd]
}
} {} {needs:config-resetstat}
}
start_server {tags {"introspection"}} {
test {CLIENT LIST} {
r client list
} {*addr=*:* fd=* age=* idle=* flags=N db=9 sub=0 psub=0 multi=-1 qbuf=26 qbuf-free=* argv-mem=* obl=0 oll=0 omem=0 tot-mem=* events=r cmd=client*}
} {*addr=*:* fd=* age=* idle=* flags=N db=* sub=0 psub=0 multi=-1 qbuf=26 qbuf-free=* argv-mem=* obl=0 oll=0 omem=0 tot-mem=* events=r cmd=client*}
test {CLIENT LIST with IDs} {
set myid [r client id]
......@@ -11,7 +11,7 @@ start_server {tags {"introspection"}} {
test {CLIENT INFO} {
r client info
} {*addr=*:* fd=* age=* idle=* flags=N db=9 sub=0 psub=0 multi=-1 qbuf=26 qbuf-free=* argv-mem=* obl=0 oll=0 omem=0 tot-mem=* events=r cmd=client*}
} {*addr=*:* fd=* age=* idle=* flags=N db=* sub=0 psub=0 multi=-1 qbuf=26 qbuf-free=* argv-mem=* obl=0 oll=0 omem=0 tot-mem=* events=r cmd=client*}
test {MONITOR can log executed commands} {
set rd [redis_deferring_client]
......@@ -50,7 +50,7 @@ start_server {tags {"introspection"}} {
assert_match {*"auth"*"(redacted)"*"(redacted)"*} [$rd read]
assert_match {*"hello"*"2"*"AUTH"*"(redacted)"*"(redacted)"*} [$rd read]
$rd close
}
} {0} {needs:repl}
test {MONITOR correctly handles multi-exec cases} {
set rd [redis_deferring_client]
......@@ -125,7 +125,7 @@ start_server {tags {"introspection"}} {
# Defaults
assert_match [r config get save] {save {100 100}}
}
}
} {} {external:skip}
test {CONFIG sanity} {
# Do CONFIG GET, CONFIG SET and then CONFIG GET again
......@@ -178,6 +178,11 @@ start_server {tags {"introspection"}} {
}
}
# TODO: Remove this when CONFIG SET bind "" is fixed.
if {$::external} {
append skip_configs bind
}
set configs {}
foreach {k v} [r config get *] {
if {[lsearch $skip_configs $k] != -1} {
......@@ -224,7 +229,7 @@ start_server {tags {"introspection"}} {
dict for {k v} $configs {
assert_equal $v [lindex [r config get $k] 1]
}
}
} {} {external:skip}
test {CONFIG REWRITE handles save properly} {
r config set save "3600 1 300 100 60 10000"
......@@ -244,7 +249,7 @@ start_server {tags {"introspection"}} {
restart_server 0 true false
assert_equal [r config get save] {save {}}
}
}
} {} {external:skip}
# Config file at this point is at a wierd state, and includes all
# known keywords. Might be a good idea to avoid adding tests here.
......
......@@ -7,12 +7,18 @@ start_server {tags {"keyspace"}} {
} {}
test {Vararg DEL} {
r set foo1 a
r set foo2 b
r set foo3 c
list [r del foo1 foo2 foo3 foo4] [r mget foo1 foo2 foo3]
r set foo1{t} a
r set foo2{t} b
r set foo3{t} c
list [r del foo1{t} foo2{t} foo3{t} foo4{t}] [r mget foo1{t} foo2{t} foo3{t}]
} {3 {{} {} {}}}
test {Untagged multi-key commands} {
r mset foo1 a foo2 b foo3 c
assert_equal {a b c {}} [r mget foo1 foo2 foo3 foo4]
r del foo1 foo2 foo3 foo4
} {3} {cluster:skip}
test {KEYS with pattern} {
foreach key {key_x key_y key_z foo_a foo_b foo_c} {
r set $key hello
......@@ -39,7 +45,7 @@ start_server {tags {"keyspace"}} {
after 1100
assert_equal 0 [r del keyExpire]
r debug set-active-expire 1
}
} {OK} {needs:debug}
test {EXISTS} {
set res {}
......@@ -74,10 +80,10 @@ start_server {tags {"keyspace"}} {
} {1}
test {RENAME basic usage} {
r set mykey hello
r rename mykey mykey1
r rename mykey1 mykey2
r get mykey2
r set mykey{t} hello
r rename mykey{t} mykey1{t}
r rename mykey1{t} mykey2{t}
r get mykey2{t}
} {hello}
test {RENAME source key should no longer exist} {
......@@ -85,35 +91,35 @@ start_server {tags {"keyspace"}} {
} {0}
test {RENAME against already existing key} {
r set mykey a
r set mykey2 b
r rename mykey2 mykey
set res [r get mykey]
append res [r exists mykey2]
r set mykey{t} a
r set mykey2{t} b
r rename mykey2{t} mykey{t}
set res [r get mykey{t}]
append res [r exists mykey2{t}]
} {b0}
test {RENAMENX basic usage} {
r del mykey
r del mykey2
r set mykey foobar
r renamenx mykey mykey2
set res [r get mykey2]
append res [r exists mykey]
r del mykey{t}
r del mykey2{t}
r set mykey{t} foobar
r renamenx mykey{t} mykey2{t}
set res [r get mykey2{t}]
append res [r exists mykey{t}]
} {foobar0}
test {RENAMENX against already existing key} {
r set mykey foo
r set mykey2 bar
r renamenx mykey mykey2
r set mykey{t} foo
r set mykey2{t} bar
r renamenx mykey{t} mykey2{t}
} {0}
test {RENAMENX against already existing key (2)} {
set res [r get mykey]
append res [r get mykey2]
set res [r get mykey{t}]
append res [r get mykey2{t}]
} {foobar}
test {RENAME against non existing source key} {
catch {r rename nokey foobar} err
catch {r rename nokey{t} foobar{t}} err
format $err
} {ERR*}
......@@ -134,22 +140,22 @@ start_server {tags {"keyspace"}} {
} {ERR*}
test {RENAME with volatile key, should move the TTL as well} {
r del mykey mykey2
r set mykey foo
r expire mykey 100
assert {[r ttl mykey] > 95 && [r ttl mykey] <= 100}
r rename mykey mykey2
assert {[r ttl mykey2] > 95 && [r ttl mykey2] <= 100}
r del mykey{t} mykey2{t}
r set mykey{t} foo
r expire mykey{t} 100
assert {[r ttl mykey{t}] > 95 && [r ttl mykey{t}] <= 100}
r rename mykey{t} mykey2{t}
assert {[r ttl mykey2{t}] > 95 && [r ttl mykey2{t}] <= 100}
}
test {RENAME with volatile key, should not inherit TTL of target key} {
r del mykey mykey2
r set mykey foo
r set mykey2 bar
r expire mykey2 100
assert {[r ttl mykey] == -1 && [r ttl mykey2] > 0}
r rename mykey mykey2
r ttl mykey2
r del mykey{t} mykey2{t}
r set mykey{t} foo
r set mykey2{t} bar
r expire mykey2{t} 100
assert {[r ttl mykey{t}] == -1 && [r ttl mykey2{t}] > 0}
r rename mykey{t} mykey2{t}
r ttl mykey2{t}
} {-1}
test {DEL all keys again (DB 0)} {
......@@ -167,212 +173,216 @@ start_server {tags {"keyspace"}} {
set res [r dbsize]
r select 9
format $res
} {0}
} {0} {singledb:skip}
test {COPY basic usage for string} {
r set mykey foobar
r set mykey{t} foobar
set res {}
r copy mykey mynewkey
lappend res [r get mynewkey]
r copy mykey{t} mynewkey{t}
lappend res [r get mynewkey{t}]
lappend res [r dbsize]
r copy mykey mynewkey DB 10
r select 10
lappend res [r get mynewkey]
lappend res [r dbsize]
r select 9
format $res
} [list foobar 2 foobar 1]
if {$::singledb} {
assert_equal [list foobar 2] [format $res]
} else {
r copy mykey{t} mynewkey{t} DB 10
r select 10
lappend res [r get mynewkey{t}]
lappend res [r dbsize]
r select 9
assert_equal [list foobar 2 foobar 1] [format $res]
}
}
test {COPY for string does not replace an existing key without REPLACE option} {
r set mykey2 hello
catch {r copy mykey2 mynewkey DB 10} e
r set mykey2{t} hello
catch {r copy mykey2{t} mynewkey{t} DB 10} e
set e
} {0}
} {0} {singledb:skip}
test {COPY for string can replace an existing key with REPLACE option} {
r copy mykey2 mynewkey DB 10 REPLACE
r copy mykey2{t} mynewkey{t} DB 10 REPLACE
r select 10
r get mynewkey
} {hello}
r get mynewkey{t}
} {hello} {singledb:skip}
test {COPY for string ensures that copied data is independent of copying data} {
r flushdb
r select 9
r set mykey foobar
r set mykey{t} foobar
set res {}
r copy mykey mynewkey DB 10
r copy mykey{t} mynewkey{t} DB 10
r select 10
lappend res [r get mynewkey]
r set mynewkey hoge
lappend res [r get mynewkey]
lappend res [r get mynewkey{t}]
r set mynewkey{t} hoge
lappend res [r get mynewkey{t}]
r select 9
lappend res [r get mykey]
lappend res [r get mykey{t}]
r select 10
r flushdb
r select 9
format $res
} [list foobar hoge foobar]
} [list foobar hoge foobar] {singledb:skip}
test {COPY for string does not copy data to no-integer DB} {
r set mykey foobar
catch {r copy mykey mynewkey DB notanumber} e
r set mykey{t} foobar
catch {r copy mykey{t} mynewkey{t} DB notanumber} e
set e
} {ERR value is not an integer or out of range}
test {COPY can copy key expire metadata as well} {
r set mykey foobar ex 100
r copy mykey mynewkey REPLACE
assert {[r ttl mynewkey] > 0 && [r ttl mynewkey] <= 100}
assert {[r get mynewkey] eq "foobar"}
r set mykey{t} foobar ex 100
r copy mykey{t} mynewkey{t} REPLACE
assert {[r ttl mynewkey{t}] > 0 && [r ttl mynewkey{t}] <= 100}
assert {[r get mynewkey{t}] eq "foobar"}
}
test {COPY does not create an expire if it does not exist} {
r set mykey foobar
assert {[r ttl mykey] == -1}
r copy mykey mynewkey REPLACE
assert {[r ttl mynewkey] == -1}
assert {[r get mynewkey] eq "foobar"}
r set mykey{t} foobar
assert {[r ttl mykey{t}] == -1}
r copy mykey{t} mynewkey{t} REPLACE
assert {[r ttl mynewkey{t}] == -1}
assert {[r get mynewkey{t}] eq "foobar"}
}
test {COPY basic usage for list} {
r del mylist mynewlist
r lpush mylist a b c d
r copy mylist mynewlist
set digest [r debug digest-value mylist]
assert_equal $digest [r debug digest-value mynewlist]
assert_equal 1 [r object refcount mylist]
assert_equal 1 [r object refcount mynewlist]
r del mylist
assert_equal $digest [r debug digest-value mynewlist]
r del mylist{t} mynewlist{t}
r lpush mylist{t} a b c d
r copy mylist{t} mynewlist{t}
set digest [debug_digest_value mylist{t}]
assert_equal $digest [debug_digest_value mynewlist{t}]
assert_equal 1 [r object refcount mylist{t}]
assert_equal 1 [r object refcount mynewlist{t}]
r del mylist{t}
assert_equal $digest [debug_digest_value mynewlist{t}]
}
test {COPY basic usage for intset set} {
r del set1 newset1
r sadd set1 1 2 3
assert_encoding intset set1
r copy set1 newset1
set digest [r debug digest-value set1]
assert_equal $digest [r debug digest-value newset1]
assert_equal 1 [r object refcount set1]
assert_equal 1 [r object refcount newset1]
r del set1
assert_equal $digest [r debug digest-value newset1]
r del set1{t} newset1{t}
r sadd set1{t} 1 2 3
assert_encoding intset set1{t}
r copy set1{t} newset1{t}
set digest [debug_digest_value set1{t}]
assert_equal $digest [debug_digest_value newset1{t}]
assert_equal 1 [r object refcount set1{t}]
assert_equal 1 [r object refcount newset1{t}]
r del set1{t}
assert_equal $digest [debug_digest_value newset1{t}]
}
test {COPY basic usage for hashtable set} {
r del set2 newset2
r sadd set2 1 2 3 a
assert_encoding hashtable set2
r copy set2 newset2
set digest [r debug digest-value set2]
assert_equal $digest [r debug digest-value newset2]
assert_equal 1 [r object refcount set2]
assert_equal 1 [r object refcount newset2]
r del set2
assert_equal $digest [r debug digest-value newset2]
r del set2{t} newset2{t}
r sadd set2{t} 1 2 3 a
assert_encoding hashtable set2{t}
r copy set2{t} newset2{t}
set digest [debug_digest_value set2{t}]
assert_equal $digest [debug_digest_value newset2{t}]
assert_equal 1 [r object refcount set2{t}]
assert_equal 1 [r object refcount newset2{t}]
r del set2{t}
assert_equal $digest [debug_digest_value newset2{t}]
}
test {COPY basic usage for ziplist sorted set} {
r del zset1 newzset1
r zadd zset1 123 foobar
assert_encoding ziplist zset1
r copy zset1 newzset1
set digest [r debug digest-value zset1]
assert_equal $digest [r debug digest-value newzset1]
assert_equal 1 [r object refcount zset1]
assert_equal 1 [r object refcount newzset1]
r del zset1
assert_equal $digest [r debug digest-value newzset1]
r del zset1{t} newzset1{t}
r zadd zset1{t} 123 foobar
assert_encoding ziplist zset1{t}
r copy zset1{t} newzset1{t}
set digest [debug_digest_value zset1{t}]
assert_equal $digest [debug_digest_value newzset1{t}]
assert_equal 1 [r object refcount zset1{t}]
assert_equal 1 [r object refcount newzset1{t}]
r del zset1{t}
assert_equal $digest [debug_digest_value newzset1{t}]
}
test {COPY basic usage for skiplist sorted set} {
r del zset2 newzset2
r del zset2{t} newzset2{t}
set original_max [lindex [r config get zset-max-ziplist-entries] 1]
r config set zset-max-ziplist-entries 0
for {set j 0} {$j < 130} {incr j} {
r zadd zset2 [randomInt 50] ele-[randomInt 10]
r zadd zset2{t} [randomInt 50] ele-[randomInt 10]
}
assert_encoding skiplist zset2
r copy zset2 newzset2
set digest [r debug digest-value zset2]
assert_equal $digest [r debug digest-value newzset2]
assert_equal 1 [r object refcount zset2]
assert_equal 1 [r object refcount newzset2]
r del zset2
assert_equal $digest [r debug digest-value newzset2]
assert_encoding skiplist zset2{t}
r copy zset2{t} newzset2{t}
set digest [debug_digest_value zset2{t}]
assert_equal $digest [debug_digest_value newzset2{t}]
assert_equal 1 [r object refcount zset2{t}]
assert_equal 1 [r object refcount newzset2{t}]
r del zset2{t}
assert_equal $digest [debug_digest_value newzset2{t}]
r config set zset-max-ziplist-entries $original_max
}
test {COPY basic usage for ziplist hash} {
r del hash1 newhash1
r hset hash1 tmp 17179869184
assert_encoding ziplist hash1
r copy hash1 newhash1
set digest [r debug digest-value hash1]
assert_equal $digest [r debug digest-value newhash1]
assert_equal 1 [r object refcount hash1]
assert_equal 1 [r object refcount newhash1]
r del hash1
assert_equal $digest [r debug digest-value newhash1]
r del hash1{t} newhash1{t}
r hset hash1{t} tmp 17179869184
assert_encoding ziplist hash1{t}
r copy hash1{t} newhash1{t}
set digest [debug_digest_value hash1{t}]
assert_equal $digest [debug_digest_value newhash1{t}]
assert_equal 1 [r object refcount hash1{t}]
assert_equal 1 [r object refcount newhash1{t}]
r del hash1{t}
assert_equal $digest [debug_digest_value newhash1{t}]
}
test {COPY basic usage for hashtable hash} {
r del hash2 newhash2
r del hash2{t} newhash2{t}
set original_max [lindex [r config get hash-max-ziplist-entries] 1]
r config set hash-max-ziplist-entries 0
for {set i 0} {$i < 64} {incr i} {
r hset hash2 [randomValue] [randomValue]
r hset hash2{t} [randomValue] [randomValue]
}
assert_encoding hashtable hash2
r copy hash2 newhash2
set digest [r debug digest-value hash2]
assert_equal $digest [r debug digest-value newhash2]
assert_equal 1 [r object refcount hash2]
assert_equal 1 [r object refcount newhash2]
r del hash2
assert_equal $digest [r debug digest-value newhash2]
assert_encoding hashtable hash2{t}
r copy hash2{t} newhash2{t}
set digest [debug_digest_value hash2{t}]
assert_equal $digest [debug_digest_value newhash2{t}]
assert_equal 1 [r object refcount hash2{t}]
assert_equal 1 [r object refcount newhash2{t}]
r del hash2{t}
assert_equal $digest [debug_digest_value newhash2{t}]
r config set hash-max-ziplist-entries $original_max
}
test {COPY basic usage for stream} {
r del mystream mynewstream
r del mystream{t} mynewstream{t}
for {set i 0} {$i < 1000} {incr i} {
r XADD mystream * item 2 value b
r XADD mystream{t} * item 2 value b
}
r copy mystream mynewstream
set digest [r debug digest-value mystream]
assert_equal $digest [r debug digest-value mynewstream]
assert_equal 1 [r object refcount mystream]
assert_equal 1 [r object refcount mynewstream]
r del mystream
assert_equal $digest [r debug digest-value mynewstream]
r copy mystream{t} mynewstream{t}
set digest [debug_digest_value mystream{t}]
assert_equal $digest [debug_digest_value mynewstream{t}]
assert_equal 1 [r object refcount mystream{t}]
assert_equal 1 [r object refcount mynewstream{t}]
r del mystream{t}
assert_equal $digest [debug_digest_value mynewstream{t}]
}
test {COPY basic usage for stream-cgroups} {
r del x
r XADD x 100 a 1
set id [r XADD x 101 b 1]
r XADD x 102 c 1
r XADD x 103 e 1
r XADD x 104 f 1
r XADD x 105 g 1
r XGROUP CREATE x g1 0
r XGROUP CREATE x g2 0
r XREADGROUP GROUP g1 Alice COUNT 1 STREAMS x >
r XREADGROUP GROUP g1 Bob COUNT 1 STREAMS x >
r XREADGROUP GROUP g1 Bob NOACK COUNT 1 STREAMS x >
r XREADGROUP GROUP g2 Charlie COUNT 4 STREAMS x >
r XGROUP SETID x g1 $id
r XREADGROUP GROUP g1 Dave COUNT 3 STREAMS x >
r XDEL x 103
r copy x newx
set info [r xinfo stream x full]
assert_equal $info [r xinfo stream newx full]
assert_equal 1 [r object refcount x]
assert_equal 1 [r object refcount newx]
r del x
assert_equal $info [r xinfo stream newx full]
r del x{t}
r XADD x{t} 100 a 1
set id [r XADD x{t} 101 b 1]
r XADD x{t} 102 c 1
r XADD x{t} 103 e 1
r XADD x{t} 104 f 1
r XADD x{t} 105 g 1
r XGROUP CREATE x{t} g1 0
r XGROUP CREATE x{t} g2 0
r XREADGROUP GROUP g1 Alice COUNT 1 STREAMS x{t} >
r XREADGROUP GROUP g1 Bob COUNT 1 STREAMS x{t} >
r XREADGROUP GROUP g1 Bob NOACK COUNT 1 STREAMS x{t} >
r XREADGROUP GROUP g2 Charlie COUNT 4 STREAMS x{t} >
r XGROUP SETID x{t} g1 $id
r XREADGROUP GROUP g1 Dave COUNT 3 STREAMS x{t} >
r XDEL x{t} 103
r copy x{t} newx{t}
set info [r xinfo stream x{t} full]
assert_equal $info [r xinfo stream newx{t} full]
assert_equal 1 [r object refcount x{t}]
assert_equal 1 [r object refcount newx{t}]
r del x{t}
assert_equal $info [r xinfo stream newx{t} full]
r flushdb
}
......@@ -387,18 +397,18 @@ start_server {tags {"keyspace"}} {
lappend res [r dbsize]
r select 9
format $res
} [list 0 0 foobar 1]
} [list 0 0 foobar 1] {singledb:skip}
test {MOVE against key existing in the target DB} {
r set mykey hello
r move mykey 10
} {0}
} {0} {singledb:skip}
test {MOVE against non-integer DB (#1428)} {
r set mykey hello
catch {r move mykey notanumber} e
set e
} {ERR value is not an integer or out of range}
} {ERR value is not an integer or out of range} {singledb:skip}
test {MOVE can move key expire metadata as well} {
r select 10
......@@ -411,7 +421,7 @@ start_server {tags {"keyspace"}} {
assert {[r ttl mykey] > 0 && [r ttl mykey] <= 100}
assert {[r get mykey] eq "foo"}
r select 9
}
} {OK} {singledb:skip}
test {MOVE does not create an expire if it does not exist} {
r select 10
......@@ -424,7 +434,7 @@ start_server {tags {"keyspace"}} {
assert {[r ttl mykey] == -1}
assert {[r get mykey] eq "foo"}
r select 9
}
} {OK} {singledb:skip}
test {SET/GET keys in different DBs} {
r set a hello
......@@ -441,7 +451,7 @@ start_server {tags {"keyspace"}} {
lappend res [r get b]
r select 9
format $res
} {hello world foo bared}
} {hello world foo bared} {singledb:skip}
test {RANDOMKEY} {
r flushdb
......
start_server {tags {"latency-monitor"}} {
start_server {tags {"latency-monitor needs:latency"}} {
# Set a threshold high enough to avoid spurious latency events.
r config set latency-monitor-threshold 200
r latency reset
......
......@@ -67,7 +67,7 @@ start_server {tags {"lazyfree"}} {
fail "lazyfree isn't done"
}
assert_equal [s lazyfreed_objects] 1
}
} {} {needs:config-resetstat}
test "lazy free a stream with deleted cgroup" {
r config resetstat
......@@ -83,5 +83,5 @@ start_server {tags {"lazyfree"}} {
fail "lazyfree isn't done"
}
assert_equal [s lazyfreed_objects] 0
}
} {} {needs:config-resetstat}
}
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