summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/assets/default.conf8
-rw-r--r--tests/assets/test_cli_hint_suite.txt111
-rw-r--r--tests/cluster/run.tcl1
-rw-r--r--tests/integration/aof-multi-part.tcl4
-rw-r--r--tests/integration/block-repl.tcl2
-rw-r--r--tests/integration/failover.tcl30
-rw-r--r--tests/integration/psync2-master-restart.tcl44
-rw-r--r--tests/integration/psync2.tcl2
-rw-r--r--tests/integration/rdb.tcl5
-rw-r--r--tests/integration/redis-cli.tcl21
-rw-r--r--tests/integration/replication-2.tcl4
-rw-r--r--tests/integration/replication-4.tcl12
-rw-r--r--tests/integration/replication-buffer.tcl4
-rw-r--r--tests/integration/replication-psync.tcl4
-rw-r--r--tests/integration/replication.tcl44
-rw-r--r--tests/integration/shutdown.tcl36
-rw-r--r--tests/modules/Makefile3
-rw-r--r--tests/modules/blockonkeys.c2
-rw-r--r--tests/modules/cmdintrospection.c2
-rw-r--r--tests/modules/rdbloadsave.c162
-rw-r--r--tests/modules/reply.c10
-rw-r--r--tests/modules/zset.c73
-rw-r--r--tests/sentinel/run.tcl1
-rw-r--r--tests/sentinel/tests/00-base.tcl51
-rw-r--r--tests/sentinel/tests/05-manual.tcl25
-rw-r--r--tests/sentinel/tests/07-down-conditions.tcl4
-rw-r--r--tests/support/cluster_util.tcl2
-rw-r--r--tests/support/server.tcl3
-rw-r--r--tests/support/test.tcl9
-rw-r--r--tests/support/util.tcl39
-rw-r--r--tests/test_helper.tcl9
-rw-r--r--tests/unit/acl.tcl14
-rw-r--r--tests/unit/aofrw.tcl2
-rw-r--r--tests/unit/client-eviction.tcl4
-rw-r--r--tests/unit/cluster/cli.tcl6
-rw-r--r--tests/unit/cluster/links.tcl4
-rw-r--r--tests/unit/expire.tcl14
-rw-r--r--tests/unit/info.tcl63
-rw-r--r--tests/unit/introspection-2.tcl4
-rw-r--r--tests/unit/introspection.tcl15
-rw-r--r--tests/unit/maxmemory.tcl4
-rw-r--r--tests/unit/moduleapi/cluster.tcl4
-rw-r--r--tests/unit/moduleapi/misc.tcl2
-rw-r--r--tests/unit/moduleapi/rdbloadsave.tcl200
-rw-r--r--tests/unit/moduleapi/reply.tcl11
-rw-r--r--tests/unit/moduleapi/stream.tcl17
-rw-r--r--tests/unit/moduleapi/testrdb.tcl8
-rw-r--r--tests/unit/moduleapi/zset.tcl20
-rw-r--r--tests/unit/multi.tcl6
-rw-r--r--tests/unit/querybuf.tcl32
-rw-r--r--tests/unit/shutdown.tcl30
-rw-r--r--tests/unit/slowlog.tcl9
-rw-r--r--tests/unit/type/hash.tcl11
-rw-r--r--tests/unit/type/incr.tcl11
-rw-r--r--tests/unit/type/list.tcl10
-rw-r--r--tests/unit/type/string.tcl16
-rw-r--r--tests/unit/type/zset.tcl40
-rw-r--r--tests/unit/wait.tcl66
58 files changed, 1191 insertions, 159 deletions
diff --git a/tests/assets/default.conf b/tests/assets/default.conf
index 4ae420790..de460cc08 100644
--- a/tests/assets/default.conf
+++ b/tests/assets/default.conf
@@ -13,8 +13,9 @@ databases 16
latency-monitor-threshold 1
repl-diskless-sync-delay 0
+# Turn off RDB by default (to speedup tests)
# Note the infrastructure in server.tcl uses a dict, we can't provide several save directives
-save 900 1
+save ''
rdbcompression yes
dbfilename dump.rdb
@@ -30,4 +31,7 @@ enable-protected-configs yes
enable-debug-command yes
enable-module-command yes
-propagation-error-behavior panic \ No newline at end of file
+propagation-error-behavior panic
+
+# Make sure shutdown doesn't fail if there's an initial AOFRW
+shutdown-on-sigterm force
diff --git a/tests/assets/test_cli_hint_suite.txt b/tests/assets/test_cli_hint_suite.txt
new file mode 100644
index 000000000..18c1fe07a
--- /dev/null
+++ b/tests/assets/test_cli_hint_suite.txt
@@ -0,0 +1,111 @@
+# Test suite for redis-cli command-line hinting mechanism.
+# Each test case consists of two strings: a (partial) input command line, and the expected hint string.
+
+# Command with one arg: GET key
+"GET " "key"
+"GET abc " ""
+
+# Command with two args: DECRBY key decrement
+"DECRBY xyz 2 " ""
+"DECRBY xyz " "decrement"
+"DECRBY " "key decrement"
+
+# Command with optional arg: LPOP key [count]
+"LPOP key " "[count]"
+"LPOP key 3 " ""
+
+# Command with optional token arg: XRANGE key start end [COUNT count]
+"XRANGE " "key start end [COUNT count]"
+"XRANGE k 4 2 " "[COUNT count]"
+"XRANGE k 4 2 COU" "[COUNT count]"
+"XRANGE k 4 2 COUNT" "[COUNT count]"
+"XRANGE k 4 2 COUNT " "count"
+
+# Command with optional token block arg: BITFIELD_RO key [GET encoding offset [GET encoding offset ...]]
+"BITFIELD_RO k " "[GET encoding offset [GET encoding offset ...]]"
+"BITFIELD_RO k GE" "[GET encoding offset [GET encoding offset ...]]"
+"BITFIELD_RO k GET" "[GET encoding offset [GET encoding offset ...]]"
+# TODO: The following hints end with an unbalanced "]" which shouldn't be there.
+"BITFIELD_RO k GET " "encoding offset [GET encoding offset ...]]"
+"BITFIELD_RO k GET xyz " "offset [GET encoding offset ...]]"
+"BITFIELD_RO k GET xyz 12 " "[GET encoding offset ...]]"
+"BITFIELD_RO k GET xyz 12 GET " "encoding offset [GET encoding offset ...]]"
+"BITFIELD_RO k GET enc1 12 GET enc2 " "offset [GET encoding offset ...]]"
+"BITFIELD_RO k GET enc1 12 GET enc2 34 " "[GET encoding offset ...]]"
+
+# Two-word command with multiple non-token block args: CONFIG SET parameter value [parameter value ...]
+"CONFIG SET param " "value [parameter value ...]"
+"CONFIG SET param val " "[parameter value ...]"
+"CONFIG SET param val parm2 val2 " "[parameter value ...]"
+
+# Command with nested optional args: ZRANDMEMBER key [count [WITHSCORES]]
+"ZRANDMEMBER k " "[count [WITHSCORES]]"
+"ZRANDMEMBER k 3 " "[WITHSCORES]"
+"ZRANDMEMBER k 3 WI" "[WITHSCORES]"
+"ZRANDMEMBER k 3 WITHSCORES " ""
+# Wrong data type: count must be an integer. Hinting fails.
+"ZRANDMEMBER k cnt " ""
+
+# Command ends with repeated arg: MGET key [key ...]
+"MGET " "key [key ...]"
+"MGET k " "[key ...]"
+"MGET k k " "[key ...]"
+
+# Optional args can be in any order: SCAN cursor [MATCH pattern] [COUNT count] [TYPE type]
+"SCAN 2 MATCH " "pattern [COUNT count] [TYPE type]"
+"SCAN 2 COUNT " "count [MATCH pattern] [TYPE type]"
+
+# One-of choices: BLMOVE source destination LEFT|RIGHT LEFT|RIGHT timeout
+"BLMOVE src dst LEFT " "LEFT|RIGHT timeout"
+
+# Optional args can be in any order: ZRANGE key min max [BYSCORE|BYLEX] [REV] [LIMIT offset count] [WITHSCORES]
+"ZRANGE k 1 2 " "[BYSCORE|BYLEX] [REV] [LIMIT offset count] [WITHSCORES]"
+"ZRANGE k 1 2 bylex " "[REV] [LIMIT offset count] [WITHSCORES]"
+"ZRANGE k 1 2 bylex rev " "[LIMIT offset count] [WITHSCORES]"
+"ZRANGE k 1 2 limit 2 4 " "[BYSCORE|BYLEX] [REV] [WITHSCORES]"
+"ZRANGE k 1 2 bylex rev limit 2 4 WITHSCORES " ""
+"ZRANGE k 1 2 rev " "[BYSCORE|BYLEX] [LIMIT offset count] [WITHSCORES]"
+"ZRANGE k 1 2 WITHSCORES " "[BYSCORE|BYLEX] [REV] [LIMIT offset count]"
+
+# Optional one-of args with parameters: SET key value [NX|XX] [GET] [EX seconds|PX milliseconds|EXAT unix-time-seconds|PXAT unix-time-milliseconds|KEEPTTL]
+"SET key value " "[NX|XX] [GET] [EX seconds|PX milliseconds|EXAT unix-time-seconds|PXAT unix-time-milliseconds|KEEPTTL]"
+"SET key value EX" "[NX|XX] [GET] [EX seconds|PX milliseconds|EXAT unix-time-seconds|PXAT unix-time-milliseconds|KEEPTTL]"
+"SET key value EX " "seconds [NX|XX] [GET]"
+"SET key value EX 23 " "[NX|XX] [GET]"
+"SET key value EXAT" "[NX|XX] [GET] [EX seconds|PX milliseconds|EXAT unix-time-seconds|PXAT unix-time-milliseconds|KEEPTTL]"
+"SET key value EXAT " "unix-time-seconds [NX|XX] [GET]"
+"SET key value PX" "[NX|XX] [GET] [EX seconds|PX milliseconds|EXAT unix-time-seconds|PXAT unix-time-milliseconds|KEEPTTL]"
+"SET key value PX " "milliseconds [NX|XX] [GET]"
+"SET key value PXAT" "[NX|XX] [GET] [EX seconds|PX milliseconds|EXAT unix-time-seconds|PXAT unix-time-milliseconds|KEEPTTL]"
+"SET key value PXAT " "unix-time-milliseconds [NX|XX] [GET]"
+"SET key value KEEPTTL " "[NX|XX] [GET]"
+"SET key value XX " "[GET] [EX seconds|PX milliseconds|EXAT unix-time-seconds|PXAT unix-time-milliseconds|KEEPTTL]"
+
+# If an input word can't be matched, stop hinting.
+"SET key value FOOBAR " ""
+# Incorrect type for EX 'seconds' parameter - stop hinting.
+"SET key value EX sec " ""
+
+# Reordering partially-matched optional argument: GEORADIUS key longitude latitude radius M|KM|FT|MI [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count [ANY]] [ASC|DESC] [STORE key|STOREDIST key]
+"GEORADIUS key " "longitude latitude radius M|KM|FT|MI [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count [ANY]] [ASC|DESC] [STORE key|STOREDIST key]"
+"GEORADIUS key 1 2 3 M " "[WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count [ANY]] [ASC|DESC] [STORE key|STOREDIST key]"
+"GEORADIUS key 1 2 3 M COUNT " "count [ANY] [WITHCOORD] [WITHDIST] [WITHHASH] [ASC|DESC] [STORE key|STOREDIST key]"
+"GEORADIUS key 1 2 3 M COUNT 12 " "[ANY] [WITHCOORD] [WITHDIST] [WITHHASH] [ASC|DESC] [STORE key|STOREDIST key]"
+"GEORADIUS key 1 2 3 M COUNT 12 " "[ANY] [WITHCOORD] [WITHDIST] [WITHHASH] [ASC|DESC] [STORE key|STOREDIST key]"
+"GEORADIUS key 1 -2.345 3 M COUNT 12 " "[ANY] [WITHCOORD] [WITHDIST] [WITHHASH] [ASC|DESC] [STORE key|STOREDIST key]"" ""
+# Wrong data type: latitude must be a double. Hinting fails.
+"GEORADIUS key 1 X " ""
+# Once the next optional argument is started, the [ANY] hint completing the COUNT argument disappears.
+"GEORADIUS key 1 2 3 M COUNT 12 ASC " "[WITHCOORD] [WITHDIST] [WITHHASH] [STORE key|STOREDIST key]"
+
+# Incorrect argument type for double-valued token parameter.
+"GEOSEARCH k FROMLONLAT " "longitude latitude BYRADIUS radius M|KM|FT|MI|BYBOX width height M|KM|FT|MI [ASC|DESC] [COUNT count [ANY]] [WITHCOORD] [WITHDIST] [WITHHASH]"
+"GEOSEARCH k FROMLONLAT 2.34 4.45 BYRADIUS badvalue " ""
+
+# Optional parameters followed by mandatory params: ZADD key [NX|XX] [GT|LT] [CH] [INCR] score member [score member ...]
+"ZADD key " "[NX|XX] [GT|LT] [CH] [INCR] score member [score member ...]"
+"ZADD key CH LT " "[NX|XX] [INCR] score member [score member ...]"
+"ZADD key 0 " "member [score member ...]"
+
+# Empty-valued token argument represented as a pair of double-quotes.
+"MIGRATE " "host port key|\"\" destination-db timeout [COPY] [REPLACE] [AUTH password|AUTH2 username password] [KEYS key [key ...]]"
diff --git a/tests/cluster/run.tcl b/tests/cluster/run.tcl
index c81d8f39d..86c5f589b 100644
--- a/tests/cluster/run.tcl
+++ b/tests/cluster/run.tcl
@@ -17,6 +17,7 @@ proc main {} {
"appendonly yes"
"enable-protected-configs yes"
"enable-debug-command yes"
+ "save ''"
}
run_tests
cleanup
diff --git a/tests/integration/aof-multi-part.tcl b/tests/integration/aof-multi-part.tcl
index 74f6b4949..1d41a8a83 100644
--- a/tests/integration/aof-multi-part.tcl
+++ b/tests/integration/aof-multi-part.tcl
@@ -755,7 +755,7 @@ tags {"external:skip"} {
# writing pressure, etc.
- start_server {tags {"Multi Part AOF"} overrides {aof-use-rdb-preamble {yes} appendonly {no}}} {
+ start_server {tags {"Multi Part AOF"} overrides {aof-use-rdb-preamble {yes} appendonly {no} save {}}} {
set dir [get_redis_dir]
set aof_basename "appendonly.aof"
set aof_dirname "appendonlydir"
@@ -1173,7 +1173,7 @@ tags {"external:skip"} {
assert {$d1 eq $d2}
}
- start_server {overrides {aof-use-rdb-preamble {yes} appendonly {no}}} {
+ start_server {overrides {aof-use-rdb-preamble {yes} appendonly {no} save {}}} {
set dir [get_redis_dir]
set aof_basename "appendonly.aof"
set aof_dirname "appendonlydir"
diff --git a/tests/integration/block-repl.tcl b/tests/integration/block-repl.tcl
index 3f3a86ed8..52b4a53ea 100644
--- a/tests/integration/block-repl.tcl
+++ b/tests/integration/block-repl.tcl
@@ -12,7 +12,7 @@ proc stop_bg_block_op {handle} {
}
start_server {tags {"repl" "external:skip"}} {
- start_server {} {
+ start_server {overrides {save {}}} {
set master [srv -1 client]
set master_host [srv -1 host]
set master_port [srv -1 port]
diff --git a/tests/integration/failover.tcl b/tests/integration/failover.tcl
index 2cd944851..21fa3d281 100644
--- a/tests/integration/failover.tcl
+++ b/tests/integration/failover.tcl
@@ -1,6 +1,6 @@
-start_server {tags {"failover external:skip"}} {
-start_server {} {
-start_server {} {
+start_server {tags {"failover external:skip"} overrides {save {}}} {
+start_server {overrides {save {}}} {
+start_server {overrides {save {}}} {
set node_0 [srv 0 client]
set node_0_host [srv 0 host]
set node_0_port [srv 0 port]
@@ -66,13 +66,13 @@ start_server {} {
# Generate a delta between primary and replica
set load_handler [start_write_load $node_0_host $node_0_port 5]
- exec kill -SIGSTOP [srv -1 pid]
+ pause_process [srv -1 pid]
wait_for_condition 50 100 {
[s 0 total_commands_processed] > 100
} else {
fail "Node 0 did not accept writes"
}
- exec kill -SIGCONT [srv -1 pid]
+ resume_process [srv -1 pid]
# Execute the failover
$node_0 failover to $node_1_host $node_1_port
@@ -108,7 +108,7 @@ start_server {} {
wait_for_ofs_sync $node_1 $node_2
# We stop node 0 to and make sure node 2 is selected
- exec kill -SIGSTOP $node_0_pid
+ pause_process $node_0_pid
$node_1 set CASE 1
$node_1 FAILOVER
@@ -118,7 +118,7 @@ start_server {} {
} else {
fail "Failover from node 1 to node 2 did not finish"
}
- exec kill -SIGCONT $node_0_pid
+ resume_process $node_0_pid
$node_0 replicaof $node_2_host $node_2_port
wait_for_sync $node_0
@@ -138,7 +138,7 @@ start_server {} {
set initial_psyncs [s 0 sync_partial_ok]
set initial_syncs [s 0 sync_full]
- exec kill -SIGSTOP $node_0_pid
+ pause_process $node_0_pid
# node 0 will never acknowledge this write
$node_2 set case 2
$node_2 failover to $node_0_host $node_0_port TIMEOUT 100 FORCE
@@ -155,7 +155,7 @@ start_server {} {
assert_match *slave* [$node_1 role]
assert_match *slave* [$node_2 role]
- exec kill -SIGCONT $node_0_pid
+ resume_process $node_0_pid
# Wait for failover to end
wait_for_condition 50 100 {
@@ -186,7 +186,7 @@ start_server {} {
set initial_syncs [s 0 sync_full]
# Stop replica so it never catches up
- exec kill -SIGSTOP [srv -1 pid]
+ pause_process [srv -1 pid]
$node_0 SET CASE 1
$node_0 failover to [srv -1 host] [srv -1 port] TIMEOUT 500
@@ -197,7 +197,7 @@ start_server {} {
fail "Failover from node_0 to replica did not finish"
}
- exec kill -SIGCONT [srv -1 pid]
+ resume_process [srv -1 pid]
# We need to make sure the nodes actually sync back up
wait_for_ofs_sync $node_0 $node_1
@@ -218,7 +218,7 @@ start_server {} {
set initial_syncs [s 0 sync_full]
# Stop replica so it never catches up
- exec kill -SIGSTOP [srv -1 pid]
+ pause_process [srv -1 pid]
$node_0 SET CASE 2
$node_0 failover to [srv -1 host] [srv -1 port] TIMEOUT 60000
@@ -230,7 +230,7 @@ start_server {} {
$node_0 failover abort
assert_match [s 0 master_failover_state] "no-failover"
- exec kill -SIGCONT [srv -1 pid]
+ resume_process [srv -1 pid]
# Just make sure everything is still synced
wait_for_ofs_sync $node_0 $node_1
@@ -255,11 +255,11 @@ start_server {} {
# We pause the target long enough to send a write command
# during the pause. This write will not be interrupted.
- exec kill -SIGSTOP [srv -1 pid]
+ pause_process [srv -1 pid]
set rd [redis_deferring_client]
$rd SET FOO BAR
$node_0 failover to $node_1_host $node_1_port
- exec kill -SIGCONT [srv -1 pid]
+ resume_process [srv -1 pid]
# Wait for failover to end
wait_for_condition 50 100 {
diff --git a/tests/integration/psync2-master-restart.tcl b/tests/integration/psync2-master-restart.tcl
index 03470bf81..a9e21d12d 100644
--- a/tests/integration/psync2-master-restart.tcl
+++ b/tests/integration/psync2-master-restart.tcl
@@ -11,6 +11,9 @@ start_server {} {
set sub_replica [srv -2 client]
+ # Make sure the server saves an RDB on shutdown
+ $master config set save "3600 1"
+
# Because we will test partial resync later, we don’t want a timeout to cause
# the master-replica disconnect, then the extra reconnections will break the
# sync_partial_ok stat test
@@ -18,6 +21,10 @@ start_server {} {
$replica config set repl-timeout 3600
$sub_replica config set repl-timeout 3600
+ # Avoid PINGs
+ $master config set repl-ping-replica-period 3600
+ $master config rewrite
+
# Build replication chain
$replica replicaof $master_host $master_port
$sub_replica replicaof $replica_host $replica_port
@@ -29,14 +36,43 @@ start_server {} {
fail "Replication not started."
}
- # Avoid PINGs
- $master config set repl-ping-replica-period 3600
- $master config rewrite
+ test "PSYNC2: Partial resync after Master restart using RDB aux fields when offset is 0" {
+ assert {[status $master master_repl_offset] == 0}
+
+ set replid [status $master master_replid]
+ $replica config resetstat
+
+ catch {
+ restart_server 0 true false true now
+ set master [srv 0 client]
+ }
+ wait_for_condition 50 1000 {
+ [status $replica master_link_status] eq {up} &&
+ [status $sub_replica master_link_status] eq {up}
+ } else {
+ fail "Replicas didn't sync after master restart"
+ }
+
+ # Make sure master restore replication info correctly
+ assert {[status $master master_replid] != $replid}
+ assert {[status $master master_repl_offset] == 0}
+ assert {[status $master master_replid2] eq $replid}
+ assert {[status $master second_repl_offset] == 1}
+
+ # Make sure master set replication backlog correctly
+ assert {[status $master repl_backlog_active] == 1}
+ assert {[status $master repl_backlog_first_byte_offset] == 1}
+ assert {[status $master repl_backlog_histlen] == 0}
+
+ # Partial resync after Master restart
+ assert {[status $master sync_partial_ok] == 1}
+ assert {[status $replica sync_partial_ok] == 1}
+ }
# Generate some data
createComplexDataset $master 1000
- test "PSYNC2: Partial resync after Master restart using RDB aux fields" {
+ test "PSYNC2: Partial resync after Master restart using RDB aux fields with data" {
wait_for_condition 500 100 {
[status $master master_repl_offset] == [status $replica master_repl_offset] &&
[status $master master_repl_offset] == [status $sub_replica master_repl_offset]
diff --git a/tests/integration/psync2.tcl b/tests/integration/psync2.tcl
index a258f1b83..4abe059b1 100644
--- a/tests/integration/psync2.tcl
+++ b/tests/integration/psync2.tcl
@@ -355,6 +355,8 @@ start_server {} {
set sync_partial [status $R($master_id) sync_partial_ok]
set sync_partial_err [status $R($master_id) sync_partial_err]
catch {
+ # Make sure the server saves an RDB on shutdown
+ $R($slave_id) config set save "900 1"
$R($slave_id) config rewrite
restart_server [expr {0-$slave_id}] true false
set R($slave_id) [srv [expr {0-$slave_id}] client]
diff --git a/tests/integration/rdb.tcl b/tests/integration/rdb.tcl
index 2362ef079..cce21671f 100644
--- a/tests/integration/rdb.tcl
+++ b/tests/integration/rdb.tcl
@@ -173,7 +173,7 @@ start_server {} {
}
test {client freed during loading} {
- start_server [list overrides [list key-load-delay 50 loading-process-events-interval-bytes 1024 rdbcompression no]] {
+ start_server [list overrides [list key-load-delay 50 loading-process-events-interval-bytes 1024 rdbcompression no save "900 1"]] {
# create a big rdb that will take long to load. it is important
# for keys to be big since the server processes events only once in 2mb.
# 100mb of rdb, 100k keys will load in more than 5 seconds
@@ -370,6 +370,9 @@ start_server [list overrides [list "dir" $server_path "dbfilename" "scriptbackup
start_server {} {
test "failed bgsave prevents writes" {
+ # Make sure the server saves an RDB on shutdown
+ r config set save "900 1"
+
r config set rdb-key-save-delay 10000000
populate 1000
r set x x
diff --git a/tests/integration/redis-cli.tcl b/tests/integration/redis-cli.tcl
index 2c39d720a..da82dda65 100644
--- a/tests/integration/redis-cli.tcl
+++ b/tests/integration/redis-cli.tcl
@@ -423,6 +423,27 @@ if {!$::tls} { ;# fake_redis_node doesn't support TLS
file delete $tmpfile
}
+ test_nontty_cli "Test command-line hinting - latest server" {
+ # cli will connect to the running server and will use COMMAND DOCS
+ catch {run_cli --test_hint_file tests/assets/test_cli_hint_suite.txt} output
+ assert_match "*SUCCESS*" $output
+ }
+
+ test_nontty_cli "Test command-line hinting - no server" {
+ # cli will fail to connect to the server and will use the cached commands.c
+ catch {run_cli -p 123 --test_hint_file tests/assets/test_cli_hint_suite.txt} output
+ assert_match "*SUCCESS*" $output
+ }
+
+ test_nontty_cli "Test command-line hinting - old server" {
+ # cli will connect to the server but will not use COMMAND DOCS,
+ # and complete the missing info from the cached commands.c
+ r ACL setuser clitest on nopass +@all -command|docs
+ catch {run_cli --user clitest -a nopass --no-auth-warning --test_hint_file tests/assets/test_cli_hint_suite.txt} output
+ assert_match "*SUCCESS*" $output
+ r acl deluser clitest
+ }
+
proc test_redis_cli_rdb_dump {functions_only} {
r flushdb
r function flush
diff --git a/tests/integration/replication-2.tcl b/tests/integration/replication-2.tcl
index f9f259211..c18ff24fc 100644
--- a/tests/integration/replication-2.tcl
+++ b/tests/integration/replication-2.tcl
@@ -42,7 +42,7 @@ start_server {tags {"repl external:skip"}} {
test {No write if min-slaves-max-lag is > of the slave lag} {
r config set min-slaves-to-write 1
r config set min-slaves-max-lag 2
- exec kill -SIGSTOP [srv -1 pid]
+ pause_process [srv -1 pid]
assert {[r set foo 12345] eq {OK}}
wait_for_condition 100 100 {
[catch {r set foo 12345}] != 0
@@ -52,7 +52,7 @@ start_server {tags {"repl external:skip"}} {
catch {r set foo 12345} err
assert_match {NOREPLICAS*} $err
}
- exec kill -SIGCONT [srv -1 pid]
+ resume_process [srv -1 pid]
test {min-slaves-to-write is ignored by slaves} {
r config set min-slaves-to-write 1
diff --git a/tests/integration/replication-4.tcl b/tests/integration/replication-4.tcl
index f772eccb2..867ef364e 100644
--- a/tests/integration/replication-4.tcl
+++ b/tests/integration/replication-4.tcl
@@ -1,5 +1,5 @@
-start_server {tags {"repl network external:skip singledb:skip"}} {
- start_server {} {
+start_server {tags {"repl network external:skip singledb:skip"} overrides {save {}}} {
+ start_server { overrides {save {}}} {
set master [srv -1 client]
set master_host [srv -1 host]
@@ -104,7 +104,7 @@ start_server {tags {"repl external:skip"}} {
assert_equal OK [$master set foo 123]
assert_equal OK [$master eval "return redis.call('set','foo',12345)" 0]
# Killing a slave to make it become a lagged slave.
- exec kill -SIGSTOP [srv 0 pid]
+ pause_process [srv 0 pid]
# Waiting for slave kill.
wait_for_condition 100 100 {
[catch {$master set foo 123}] != 0
@@ -113,7 +113,7 @@ start_server {tags {"repl external:skip"}} {
}
assert_error "*NOREPLICAS*" {$master set foo 123}
assert_error "*NOREPLICAS*" {$master eval "return redis.call('set','foo',12345)" 0}
- exec kill -SIGCONT [srv 0 pid]
+ resume_process [srv 0 pid]
}
}
}
@@ -146,12 +146,12 @@ start_server {tags {"repl external:skip"}} {
$master debug set-active-expire 0
$master set k 1 px $px_ms
wait_for_ofs_sync $master $slave
- exec kill -SIGSTOP [srv 0 pid]
+ pause_process [srv 0 pid]
$master incr k
after [expr $px_ms + 1]
# Stopping the replica for one second to makes sure the INCR arrives
# to the replica after the key is logically expired.
- exec kill -SIGCONT [srv 0 pid]
+ resume_process [srv 0 pid]
wait_for_ofs_sync $master $slave
# Check that k is logically expired but is present in the replica.
set res [$slave exists k]
diff --git a/tests/integration/replication-buffer.tcl b/tests/integration/replication-buffer.tcl
index 2e402480d..143dc74aa 100644
--- a/tests/integration/replication-buffer.tcl
+++ b/tests/integration/replication-buffer.tcl
@@ -159,7 +159,7 @@ start_server {} {
assert {[s repl_backlog_histlen] > [expr 2*10000*10000]}
assert_equal [s connected_slaves] {2}
- exec kill -SIGSTOP $replica2_pid
+ pause_process $replica2_pid
r config set client-output-buffer-limit "replica 128k 0 0"
# trigger output buffer limit check
r set key [string repeat A [expr 64*1024]]
@@ -178,7 +178,7 @@ start_server {} {
} else {
fail "Replication backlog memory is not smaller"
}
- exec kill -SIGCONT $replica2_pid
+ resume_process $replica2_pid
}
# speed up termination
$master config set shutdown-timeout 0
diff --git a/tests/integration/replication-psync.tcl b/tests/integration/replication-psync.tcl
index 16f3b8889..dc1df0fa6 100644
--- a/tests/integration/replication-psync.tcl
+++ b/tests/integration/replication-psync.tcl
@@ -9,8 +9,8 @@
# reconnect with the master, otherwise just the initial synchronization is
# checked for consistency.
proc test_psync {descr duration backlog_size backlog_ttl delay cond mdl sdl reconnect} {
- start_server {tags {"repl"}} {
- start_server {} {
+ start_server {tags {"repl"} overrides {save {}}} {
+ start_server {overrides {save {}}} {
set master [srv -1 client]
set master_host [srv -1 host]
diff --git a/tests/integration/replication.tcl b/tests/integration/replication.tcl
index b4e9ee673..de4d527f4 100644
--- a/tests/integration/replication.tcl
+++ b/tests/integration/replication.tcl
@@ -302,7 +302,7 @@ start_server {tags {"repl external:skip"}} {
foreach mdl {no yes} {
foreach sdl {disabled swapdb} {
- start_server {tags {"repl external:skip"}} {
+ start_server {tags {"repl external:skip"} overrides {save {}}} {
set master [srv 0 client]
$master config set repl-diskless-sync $mdl
$master config set repl-diskless-sync-delay 5
@@ -310,11 +310,11 @@ foreach mdl {no yes} {
set master_host [srv 0 host]
set master_port [srv 0 port]
set slaves {}
- start_server {} {
+ start_server {overrides {save {}}} {
lappend slaves [srv 0 client]
- start_server {} {
+ start_server {overrides {save {}}} {
lappend slaves [srv 0 client]
- start_server {} {
+ start_server {overrides {save {}}} {
lappend slaves [srv 0 client]
test "Connect multiple replicas at the same time (issue #141), master diskless=$mdl, replica diskless=$sdl" {
# start load handles only inside the test, so that the test can be skipped
@@ -391,11 +391,11 @@ foreach mdl {no yes} {
}
}
-start_server {tags {"repl external:skip"}} {
+start_server {tags {"repl external:skip"} overrides {save {}}} {
set master [srv 0 client]
set master_host [srv 0 host]
set master_port [srv 0 port]
- start_server {} {
+ start_server {overrides {save {}}} {
test "Master stream is correctly processed while the replica has a script in -BUSY state" {
set load_handle0 [start_write_load $master_host $master_port 3]
set slave [srv 0 client]
@@ -705,11 +705,11 @@ foreach testType {Successful Aborted} {
}
test {diskless loading short read} {
- start_server {tags {"repl"}} {
+ start_server {tags {"repl"} overrides {save ""}} {
set replica [srv 0 client]
set replica_host [srv 0 host]
set replica_port [srv 0 port]
- start_server {} {
+ start_server {overrides {save ""}} {
set master [srv 0 client]
set master_host [srv 0 host]
set master_port [srv 0 port]
@@ -847,7 +847,7 @@ proc compute_cpu_usage {start end} {
# test diskless rdb pipe with multiple replicas, which may drop half way
-start_server {tags {"repl external:skip"}} {
+start_server {tags {"repl external:skip"} overrides {save ""}} {
set master [srv 0 client]
$master config set repl-diskless-sync yes
$master config set repl-diskless-sync-delay 5
@@ -868,10 +868,10 @@ start_server {tags {"repl external:skip"}} {
set replicas {}
set replicas_alive {}
# start one replica that will read the rdb fast, and one that will be slow
- start_server {} {
+ start_server {overrides {save ""}} {
lappend replicas [srv 0 client]
lappend replicas_alive [srv 0 client]
- start_server {} {
+ start_server {overrides {save ""}} {
lappend replicas [srv 0 client]
lappend replicas_alive [srv 0 client]
@@ -913,7 +913,7 @@ start_server {tags {"repl external:skip"}} {
if {$all_drop == "timeout"} {
$master config set repl-timeout 2
# we want the slow replica to hang on a key for very long so it'll reach repl-timeout
- exec kill -SIGSTOP [srv -1 pid]
+ pause_process [srv -1 pid]
after 2000
}
@@ -940,7 +940,7 @@ start_server {tags {"repl external:skip"}} {
# master disconnected the slow replica, remove from array
set replicas_alive [lreplace $replicas_alive 0 0]
# release it
- exec kill -SIGCONT [srv -1 pid]
+ resume_process [srv -1 pid]
}
# make sure we don't have a busy loop going thought epoll_wait
@@ -1000,7 +1000,7 @@ test "diskless replication child being killed is collected" {
# when diskless master is waiting for the replica to become writable
# it removes the read event from the rdb pipe so if the child gets killed
# the replica will hung. and the master may not collect the pid with waitpid
- start_server {tags {"repl"}} {
+ start_server {tags {"repl"} overrides {save ""}} {
set master [srv 0 client]
set master_host [srv 0 host]
set master_port [srv 0 port]
@@ -1010,7 +1010,7 @@ test "diskless replication child being killed is collected" {
# put enough data in the db that the rdb file will be bigger than the socket buffers
$master debug populate 20000 test 10000
$master config set rdbcompression no
- start_server {} {
+ start_server {overrides {save ""}} {
set replica [srv 0 client]
set loglines [count_log_lines 0]
$replica config set repl-diskless-load swapdb
@@ -1044,7 +1044,7 @@ test "diskless replication child being killed is collected" {
foreach mdl {yes no} {
test "replication child dies when parent is killed - diskless: $mdl" {
# when master is killed, make sure the fork child can detect that and exit
- start_server {tags {"repl"}} {
+ start_server {tags {"repl"} overrides {save ""}} {
set master [srv 0 client]
set master_host [srv 0 host]
set master_port [srv 0 port]
@@ -1054,7 +1054,7 @@ foreach mdl {yes no} {
# create keys that will take 10 seconds to save
$master config set rdb-key-save-delay 1000
$master debug populate 10000
- start_server {} {
+ start_server {overrides {save ""}} {
set replica [srv 0 client]
$replica replicaof $master_host $master_port
@@ -1085,7 +1085,7 @@ test "diskless replication read pipe cleanup" {
# When we close this pipe (fd), the read handler also needs to be removed from the event loop (if it still registered).
# Otherwise, next time we will use the same fd, the registration will be fail (panic), because
# we will use EPOLL_CTL_MOD (the fd still register in the event loop), on fd that already removed from epoll_ctl
- start_server {tags {"repl"}} {
+ start_server {tags {"repl"} overrides {save ""}} {
set master [srv 0 client]
set master_host [srv 0 host]
set master_port [srv 0 port]
@@ -1097,7 +1097,7 @@ test "diskless replication read pipe cleanup" {
$master config set rdb-key-save-delay 100000
$master debug populate 20000 test 10000
$master config set rdbcompression no
- start_server {} {
+ start_server {overrides {save ""}} {
set replica [srv 0 client]
set loglines [count_log_lines 0]
$replica config set repl-diskless-load swapdb
@@ -1122,17 +1122,17 @@ test "diskless replication read pipe cleanup" {
test {replicaof right after disconnection} {
# this is a rare race condition that was reproduced sporadically by the psync2 unit.
# see details in #7205
- start_server {tags {"repl"}} {
+ start_server {tags {"repl"} overrides {save ""}} {
set replica1 [srv 0 client]
set replica1_host [srv 0 host]
set replica1_port [srv 0 port]
set replica1_log [srv 0 stdout]
- start_server {} {
+ start_server {overrides {save ""}} {
set replica2 [srv 0 client]
set replica2_host [srv 0 host]
set replica2_port [srv 0 port]
set replica2_log [srv 0 stdout]
- start_server {} {
+ start_server {overrides {save ""}} {
set master [srv 0 client]
set master_host [srv 0 host]
set master_port [srv 0 port]
diff --git a/tests/integration/shutdown.tcl b/tests/integration/shutdown.tcl
index 60afc5c7f..b2ec32cbd 100644
--- a/tests/integration/shutdown.tcl
+++ b/tests/integration/shutdown.tcl
@@ -19,8 +19,8 @@ proc fill_up_os_socket_send_buffer_for_repl {idx} {
foreach how {sigterm shutdown} {
test "Shutting down master waits for replica to catch up ($how)" {
- start_server {} {
- start_server {} {
+ start_server {overrides {save ""}} {
+ start_server {overrides {save ""}} {
set master [srv -1 client]
set master_host [srv -1 host]
set master_port [srv -1 port]
@@ -42,8 +42,7 @@ foreach how {sigterm shutdown} {
wait_for_ofs_sync $master $replica
# Pause the replica.
- exec kill -SIGSTOP $replica_pid
- after 10
+ pause_process $replica_pid
# Fill up the OS socket send buffer for the replica connection
# to prevent the following INCR from reaching the replica via
@@ -69,7 +68,7 @@ foreach how {sigterm shutdown} {
# Wake up replica and check if master has waited for it.
after 20; # 2 cron intervals
- exec kill -SIGCONT $replica_pid
+ resume_process $replica_pid
wait_for_condition 300 1000 {
[$replica get k] eq 2
} else {
@@ -86,8 +85,8 @@ foreach how {sigterm shutdown} {
}
test {Shutting down master waits for replica timeout} {
- start_server {} {
- start_server {} {
+ start_server {overrides {save ""}} {
+ start_server {overrides {save ""}} {
set master [srv -1 client]
set master_host [srv -1 host]
set master_port [srv -1 port]
@@ -107,8 +106,7 @@ test {Shutting down master waits for replica timeout} {
wait_for_ofs_sync $master $replica
# Pause the replica.
- exec kill -SIGSTOP $replica_pid
- after 10
+ pause_process $replica_pid
# Fill up the OS socket send buffer for the replica connection to
# prevent the following INCR k from reaching the replica via the OS.
@@ -129,15 +127,15 @@ test {Shutting down master waits for replica timeout} {
verify_log_message -1 "*0 of 1 replicas are in sync*" 0
# Wake up replica.
- exec kill -SIGCONT $replica_pid
+ resume_process $replica_pid
assert_equal 1 [$replica get k]
}
}
} {} {repl external:skip}
test "Shutting down master waits for replica then fails" {
- start_server {} {
- start_server {} {
+ start_server {overrides {save ""}} {
+ start_server {overrides {save ""}} {
set master [srv -1 client]
set master_host [srv -1 host]
set master_port [srv -1 port]
@@ -150,8 +148,7 @@ test "Shutting down master waits for replica then fails" {
wait_for_sync $replica
# Pause the replica and write a key on master.
- exec kill -SIGSTOP $replica_pid
- after 10
+ pause_process $replica_pid
$master incr k
# Two clients call blocking SHUTDOWN in parallel.
@@ -168,7 +165,7 @@ test "Shutting down master waits for replica then fails" {
$master config set appendonly yes
# Wake up replica, causing master to continue shutting down.
- exec kill -SIGCONT $replica_pid
+ resume_process $replica_pid
# SHUTDOWN returns an error to both clients blocking on SHUTDOWN.
catch { $rd1 read } e1
@@ -190,8 +187,8 @@ test "Shutting down master waits for replica then fails" {
} {} {repl external:skip}
test "Shutting down master waits for replica then aborted" {
- start_server {} {
- start_server {} {
+ start_server {overrides {save ""}} {
+ start_server {overrides {save ""}} {
set master [srv -1 client]
set master_host [srv -1 host]
set master_port [srv -1 port]
@@ -204,8 +201,7 @@ test "Shutting down master waits for replica then aborted" {
wait_for_sync $replica
# Pause the replica and write a key on master.
- exec kill -SIGSTOP $replica_pid
- after 10
+ pause_process $replica_pid
$master incr k
# Two clients call blocking SHUTDOWN in parallel.
@@ -221,7 +217,7 @@ test "Shutting down master waits for replica then aborted" {
$master shutdown abort
# Wake up replica, causing master to continue shutting down.
- exec kill -SIGCONT $replica_pid
+ resume_process $replica_pid
# SHUTDOWN returns an error to both clients blocking on SHUTDOWN.
catch { $rd1 read } e1
diff --git a/tests/modules/Makefile b/tests/modules/Makefile
index a1f5b074b..d63c8548d 100644
--- a/tests/modules/Makefile
+++ b/tests/modules/Makefile
@@ -61,7 +61,8 @@ TEST_MODULES = \
publish.so \
usercall.so \
postnotifications.so \
- moduleauthtwo.so
+ moduleauthtwo.so \
+ rdbloadsave.so
.PHONY: all
diff --git a/tests/modules/blockonkeys.c b/tests/modules/blockonkeys.c
index 8f4353a55..bc3b6b1a4 100644
--- a/tests/modules/blockonkeys.c
+++ b/tests/modules/blockonkeys.c
@@ -21,7 +21,7 @@ typedef struct {
static RedisModuleType *fsltype = NULL;
-fsl_t *fsl_type_create() {
+fsl_t *fsl_type_create(void) {
fsl_t *o;
o = RedisModule_Alloc(sizeof(*o));
o->length = 0;
diff --git a/tests/modules/cmdintrospection.c b/tests/modules/cmdintrospection.c
index dd9fb7f60..1a5e4863b 100644
--- a/tests/modules/cmdintrospection.c
+++ b/tests/modules/cmdintrospection.c
@@ -23,7 +23,7 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
RedisModuleCommandInfo info = {
.version = REDISMODULE_COMMAND_INFO_VERSION,
.arity = -5,
- .summary = "Appends a new entry to a stream",
+ .summary = "Appends a new message to a stream. Creates the key if it doesn't exist.",
.since = "5.0.0",
.complexity = "O(1) when adding a new entry, O(N) when trimming where N being the number of entries evicted.",
.tips = "nondeterministic_output",
diff --git a/tests/modules/rdbloadsave.c b/tests/modules/rdbloadsave.c
new file mode 100644
index 000000000..687269a5a
--- /dev/null
+++ b/tests/modules/rdbloadsave.c
@@ -0,0 +1,162 @@
+#include "redismodule.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <memory.h>
+#include <errno.h>
+
+/* Sanity tests to verify inputs and return values. */
+int sanity(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
+ REDISMODULE_NOT_USED(argv);
+ REDISMODULE_NOT_USED(argc);
+
+ RedisModuleRdbStream *s = RedisModule_RdbStreamCreateFromFile("dbnew.rdb");
+
+ /* NULL stream should fail. */
+ if (RedisModule_RdbLoad(ctx, NULL, 0) == REDISMODULE_OK || errno != EINVAL) {
+ RedisModule_ReplyWithError(ctx, strerror(errno));
+ goto out;
+ }
+
+ /* Invalid flags should fail. */
+ if (RedisModule_RdbLoad(ctx, s, 188) == REDISMODULE_OK || errno != EINVAL) {
+ RedisModule_ReplyWithError(ctx, strerror(errno));
+ goto out;
+ }
+
+ /* Missing file should fail. */
+ if (RedisModule_RdbLoad(ctx, s, 0) == REDISMODULE_OK || errno != ENOENT) {
+ RedisModule_ReplyWithError(ctx, strerror(errno));
+ goto out;
+ }
+
+ /* Save RDB file. */
+ if (RedisModule_RdbSave(ctx, s, 0) != REDISMODULE_OK || errno != 0) {
+ RedisModule_ReplyWithError(ctx, strerror(errno));
+ goto out;
+ }
+
+ /* Load the saved RDB file. */
+ if (RedisModule_RdbLoad(ctx, s, 0) != REDISMODULE_OK || errno != 0) {
+ RedisModule_ReplyWithError(ctx, strerror(errno));
+ goto out;
+ }
+
+ RedisModule_ReplyWithSimpleString(ctx, "OK");
+
+ out:
+ RedisModule_RdbStreamFree(s);
+ return REDISMODULE_OK;
+}
+
+int cmd_rdbsave(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
+ if (argc != 2) {
+ RedisModule_WrongArity(ctx);
+ return REDISMODULE_OK;
+ }
+
+ size_t len;
+ const char *filename = RedisModule_StringPtrLen(argv[1], &len);
+
+ char tmp[len + 1];
+ memcpy(tmp, filename, len);
+ tmp[len] = '\0';
+
+ RedisModuleRdbStream *stream = RedisModule_RdbStreamCreateFromFile(tmp);
+
+ if (RedisModule_RdbSave(ctx, stream, 0) != REDISMODULE_OK || errno != 0) {
+ RedisModule_ReplyWithError(ctx, strerror(errno));
+ goto out;
+ }
+
+ RedisModule_ReplyWithSimpleString(ctx, "OK");
+
+out:
+ RedisModule_RdbStreamFree(stream);
+ return REDISMODULE_OK;
+}
+
+/* Fork before calling RM_RdbSave(). */
+int cmd_rdbsave_fork(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
+ if (argc != 2) {
+ RedisModule_WrongArity(ctx);
+ return REDISMODULE_OK;
+ }
+
+ size_t len;
+ const char *filename = RedisModule_StringPtrLen(argv[1], &len);
+
+ char tmp[len + 1];
+ memcpy(tmp, filename, len);
+ tmp[len] = '\0';
+
+ int fork_child_pid = RedisModule_Fork(NULL, NULL);
+ if (fork_child_pid < 0) {
+ RedisModule_ReplyWithError(ctx, strerror(errno));
+ return REDISMODULE_OK;
+ } else if (fork_child_pid > 0) {
+ /* parent */
+ RedisModule_ReplyWithSimpleString(ctx, "OK");
+ return REDISMODULE_OK;
+ }
+
+ RedisModuleRdbStream *stream = RedisModule_RdbStreamCreateFromFile(tmp);
+
+ int ret = 0;
+ if (RedisModule_RdbSave(ctx, stream, 0) != REDISMODULE_OK) {
+ ret = errno;
+ }
+ RedisModule_RdbStreamFree(stream);
+
+ RedisModule_ExitFromChild(ret);
+ return REDISMODULE_OK;
+}
+
+int cmd_rdbload(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
+ if (argc != 2) {
+ RedisModule_WrongArity(ctx);
+ return REDISMODULE_OK;
+ }
+
+ size_t len;
+ const char *filename = RedisModule_StringPtrLen(argv[1], &len);
+
+ char tmp[len + 1];
+ memcpy(tmp, filename, len);
+ tmp[len] = '\0';
+
+ RedisModuleRdbStream *stream = RedisModule_RdbStreamCreateFromFile(tmp);
+
+ if (RedisModule_RdbLoad(ctx, stream, 0) != REDISMODULE_OK || errno != 0) {
+ RedisModule_RdbStreamFree(stream);
+ RedisModule_ReplyWithError(ctx, strerror(errno));
+ return REDISMODULE_OK;
+ }
+
+ RedisModule_RdbStreamFree(stream);
+ RedisModule_ReplyWithSimpleString(ctx, "OK");
+ return REDISMODULE_OK;
+}
+
+int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
+ REDISMODULE_NOT_USED(argv);
+ REDISMODULE_NOT_USED(argc);
+
+ if (RedisModule_Init(ctx, "rdbloadsave", 1, REDISMODULE_APIVER_1) == REDISMODULE_ERR)
+ return REDISMODULE_ERR;
+
+ if (RedisModule_CreateCommand(ctx, "test.sanity", sanity, "", 0, 0, 0) == REDISMODULE_ERR)
+ return REDISMODULE_ERR;
+
+ if (RedisModule_CreateCommand(ctx, "test.rdbsave", cmd_rdbsave, "", 0, 0, 0) == REDISMODULE_ERR)
+ return REDISMODULE_ERR;
+
+ if (RedisModule_CreateCommand(ctx, "test.rdbsave_fork", cmd_rdbsave_fork, "", 0, 0, 0) == REDISMODULE_ERR)
+ return REDISMODULE_ERR;
+
+ if (RedisModule_CreateCommand(ctx, "test.rdbload", cmd_rdbload, "", 0, 0, 0) == REDISMODULE_ERR)
+ return REDISMODULE_ERR;
+
+ return REDISMODULE_OK;
+}
diff --git a/tests/modules/reply.c b/tests/modules/reply.c
index f890560e0..c5baa6635 100644
--- a/tests/modules/reply.c
+++ b/tests/modules/reply.c
@@ -156,6 +156,14 @@ int rw_error(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
return RedisModule_ReplyWithError(ctx, "An error");
}
+int rw_error_format(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
+ if (argc != 3) return RedisModule_WrongArity(ctx);
+
+ return RedisModule_ReplyWithErrorFormat(ctx,
+ RedisModule_StringPtrLen(argv[1], NULL),
+ RedisModule_StringPtrLen(argv[2], NULL));
+}
+
int rw_verbatim(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
if (argc != 2) return RedisModule_WrongArity(ctx);
@@ -197,6 +205,8 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
return REDISMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"rw.error",rw_error,"",0,0,0) != REDISMODULE_OK)
return REDISMODULE_ERR;
+ if (RedisModule_CreateCommand(ctx,"rw.error_format",rw_error_format,"",0,0,0) != REDISMODULE_OK)
+ return REDISMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"rw.verbatim",rw_verbatim,"",0,0,0) != REDISMODULE_OK)
return REDISMODULE_ERR;
diff --git a/tests/modules/zset.c b/tests/modules/zset.c
index 91791f907..13f2ab3b6 100644
--- a/tests/modules/zset.c
+++ b/tests/modules/zset.c
@@ -1,4 +1,6 @@
#include "redismodule.h"
+#include <math.h>
+#include <errno.h>
/* ZSET.REM key element
*
@@ -17,14 +19,73 @@ int zset_rem(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
return RedisModule_ReplyWithError(ctx, "ERR ZsetRem failed");
}
+/* ZSET.ADD key score member
+ *
+ * Adds a specified member with the specified score to the sorted
+ * set stored at key.
+ */
+int zset_add(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
+ if (argc != 4) return RedisModule_WrongArity(ctx);
+ RedisModule_AutoMemory(ctx);
+ int keymode = REDISMODULE_READ | REDISMODULE_WRITE;
+ RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], keymode);
+
+ size_t len;
+ double score;
+ char *endptr;
+ const char *str = RedisModule_StringPtrLen(argv[2], &len);
+ score = strtod(str, &endptr);
+ if (*endptr != '\0' || errno == ERANGE)
+ return RedisModule_ReplyWithError(ctx, "value is not a valid float");
+
+ if (RedisModule_ZsetAdd(key, score, argv[3], NULL) == REDISMODULE_OK)
+ return RedisModule_ReplyWithSimpleString(ctx, "OK");
+ else
+ return RedisModule_ReplyWithError(ctx, "ERR ZsetAdd failed");
+}
+
+/* ZSET.INCRBY key member increment
+ *
+ * Increments the score stored at member in the sorted set stored at key by increment.
+ * Replies with the new score of this element.
+ */
+int zset_incrby(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
+ if (argc != 4) return RedisModule_WrongArity(ctx);
+ RedisModule_AutoMemory(ctx);
+ int keymode = REDISMODULE_READ | REDISMODULE_WRITE;
+ RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], keymode);
+
+ size_t len;
+ double score, newscore;
+ char *endptr;
+ const char *str = RedisModule_StringPtrLen(argv[3], &len);
+ score = strtod(str, &endptr);
+ if (*endptr != '\0' || errno == ERANGE)
+ return RedisModule_ReplyWithError(ctx, "value is not a valid float");
+
+ if (RedisModule_ZsetIncrby(key, score, argv[2], NULL, &newscore) == REDISMODULE_OK)
+ return RedisModule_ReplyWithDouble(ctx, newscore);
+ else
+ return RedisModule_ReplyWithError(ctx, "ERR ZsetIncrby failed");
+}
+
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc);
- if (RedisModule_Init(ctx, "zset", 1, REDISMODULE_APIVER_1) ==
- REDISMODULE_OK &&
- RedisModule_CreateCommand(ctx, "zset.rem", zset_rem, "write",
- 1, 1, 1) == REDISMODULE_OK)
- return REDISMODULE_OK;
- else
+ if (RedisModule_Init(ctx, "zset", 1, REDISMODULE_APIVER_1) == REDISMODULE_ERR)
return REDISMODULE_ERR;
+
+ if (RedisModule_CreateCommand(ctx, "zset.rem", zset_rem, "write",
+ 1, 1, 1) == REDISMODULE_ERR)
+ return REDISMODULE_ERR;
+
+ if (RedisModule_CreateCommand(ctx, "zset.add", zset_add, "write",
+ 1, 1, 1) == REDISMODULE_ERR)
+ return REDISMODULE_ERR;
+
+ if (RedisModule_CreateCommand(ctx, "zset.incrby", zset_incrby, "write",
+ 1, 1, 1) == REDISMODULE_ERR)
+ return REDISMODULE_ERR;
+
+ return REDISMODULE_OK;
}
diff --git a/tests/sentinel/run.tcl b/tests/sentinel/run.tcl
index 98c4c118b..6d3db324d 100644
--- a/tests/sentinel/run.tcl
+++ b/tests/sentinel/run.tcl
@@ -22,6 +22,7 @@ proc main {} {
spawn_instance redis $::redis_base_port $::instances_count {
"enable-protected-configs yes"
"enable-debug-command yes"
+ "save ''"
}
run_tests
cleanup
diff --git a/tests/sentinel/tests/00-base.tcl b/tests/sentinel/tests/00-base.tcl
index 1b33ca7a3..b4d65751b 100644
--- a/tests/sentinel/tests/00-base.tcl
+++ b/tests/sentinel/tests/00-base.tcl
@@ -31,6 +31,50 @@ test "Sentinel command flag infrastructure works correctly" {
}
}
+test "SENTINEL HELP output the sentinel subcommand help" {
+ assert_match "*SENTINEL <subcommand> *" [S 0 SENTINEL HELP]
+}
+
+test "SENTINEL MYID return the sentinel instance ID" {
+ assert_equal 40 [string length [S 0 SENTINEL MYID]]
+ assert_equal [S 0 SENTINEL MYID] [S 0 SENTINEL MYID]
+}
+
+test "SENTINEL INFO CACHE returns the cached info" {
+ set res [S 0 SENTINEL INFO-CACHE mymaster]
+ assert_morethan_equal [llength $res] 2
+ assert_equal "mymaster" [lindex $res 0]
+
+ set res [lindex $res 1]
+ assert_morethan_equal [llength $res] 2
+ assert_morethan [lindex $res 0] 0
+ assert_match "*# Server*" [lindex $res 1]
+}
+
+test "SENTINEL PENDING-SCRIPTS returns the information about pending scripts" {
+ # may or may not have a value, so assert greater than or equal to 0.
+ assert_morethan_equal [llength [S 0 SENTINEL PENDING-SCRIPTS]] 0
+}
+
+test "SENTINEL MASTERS returns a list of monitored masters" {
+ assert_match "*mymaster*" [S 0 SENTINEL MASTERS]
+ assert_morethan_equal [llength [S 0 SENTINEL MASTERS]] 1
+}
+
+test "SENTINEL SENTINELS returns a list of sentinel instances" {
+ assert_morethan_equal [llength [S 0 SENTINEL SENTINELS mymaster]] 1
+}
+
+test "SENTINEL SLAVES returns a list of the monitored replicas" {
+ assert_morethan_equal [llength [S 0 SENTINEL SLAVES mymaster]] 1
+}
+
+test "SENTINEL SIMULATE-FAILURE HELP list supported flags" {
+ set res [S 0 SENTINEL SIMULATE-FAILURE HELP]
+ assert_morethan_equal [llength $res] 2
+ assert_equal {crash-after-election crash-after-promotion} $res
+}
+
test "Basic failover works if the master is down" {
set old_port [RPort $master_id]
set addr [S 0 SENTINEL GET-MASTER-ADDR-BY-NAME mymaster]
@@ -149,3 +193,10 @@ test "Failover works if we configure for absolute agreement" {
test "New master [join $addr {:}] role matches" {
assert {[RI $master_id role] eq {master}}
}
+
+test "SENTINEL RESET can resets the master" {
+ assert_equal 1 [S 0 SENTINEL RESET mymaster]
+ assert_equal 0 [llength [S 0 SENTINEL SENTINELS mymaster]]
+ assert_equal 0 [llength [S 0 SENTINEL SLAVES mymaster]]
+ assert_equal 0 [llength [S 0 SENTINEL REPLICAS mymaster]]
+}
diff --git a/tests/sentinel/tests/05-manual.tcl b/tests/sentinel/tests/05-manual.tcl
index 72d80fdf8..7e050b0dc 100644
--- a/tests/sentinel/tests/05-manual.tcl
+++ b/tests/sentinel/tests/05-manual.tcl
@@ -61,3 +61,28 @@ test "The old master eventually gets reconfigured as a slave" {
fail "Old master not reconfigured as slave of new master"
}
}
+
+foreach flag {crash-after-election crash-after-promotion} {
+ test "SENTINEL SIMULATE-FAILURE $flag works" {
+ assert_equal {OK} [S 0 SENTINEL SIMULATE-FAILURE $flag]
+
+ # Trigger a failover, failover will trigger leader election, replica promotion
+ wait_for_condition 300 50 {
+ [catch {S 0 SENTINEL FAILOVER mymaster}] == 0
+ } else {
+ catch {S 0 SENTINEL FAILOVER mymaster} reply
+ puts [S 0 SENTINEL REPLICAS mymaster]
+ fail "Sentinel manual failover did not work, got: $reply"
+ }
+
+ # Wait for sentinel to exit (due to simulate-failure flags)
+ wait_for_condition 1000 50 {
+ [catch {S 0 PING}] == 1
+ } else {
+ fail "Sentinel set $flag but did not exit"
+ }
+ assert_error {*couldn't open socket: connection refused*} {S 0 PING}
+
+ restart_instance sentinel 0
+ }
+}
diff --git a/tests/sentinel/tests/07-down-conditions.tcl b/tests/sentinel/tests/07-down-conditions.tcl
index 403f81e73..dabbc14c5 100644
--- a/tests/sentinel/tests/07-down-conditions.tcl
+++ b/tests/sentinel/tests/07-down-conditions.tcl
@@ -49,9 +49,9 @@ test "SDOWN is triggered by non-responding but not crashed instance" {
set master_id [get_instance_id_by_port redis [lindex $master_addr 1]]
set pid [get_instance_attrib redis $master_id pid]
- exec kill -SIGSTOP $pid
+ pause_process $pid
ensure_master_down
- exec kill -SIGCONT $pid
+ resume_process $pid
ensure_master_up
}
diff --git a/tests/support/cluster_util.tcl b/tests/support/cluster_util.tcl
index 8a58a4fa9..d80dcf062 100644
--- a/tests/support/cluster_util.tcl
+++ b/tests/support/cluster_util.tcl
@@ -36,7 +36,7 @@ proc wait_for_cluster_propagation {} {
# Wait for cluster size to be consistent across nodes.
proc wait_for_cluster_size {cluster_size} {
- wait_for_condition 50 100 {
+ wait_for_condition 1000 50 {
[cluster_size_consistent $cluster_size] eq 1
} else {
fail "cluster size did not reach a consistent size $cluster_size"
diff --git a/tests/support/server.tcl b/tests/support/server.tcl
index 4c596290d..9a3733b61 100644
--- a/tests/support/server.tcl
+++ b/tests/support/server.tcl
@@ -537,6 +537,9 @@ proc start_server {options {code undefined}} {
set fd [open $stdout "a+"]
puts $fd "### Starting server for test $::cur_test"
close $fd
+ if {$::verbose > 1} {
+ puts "### Starting server $stdout for test - $::cur_test"
+ }
}
# We may have a stdout left over from the previous tests, so we need
diff --git a/tests/support/test.tcl b/tests/support/test.tcl
index 68180bea4..b7cd38b38 100644
--- a/tests/support/test.tcl
+++ b/tests/support/test.tcl
@@ -168,7 +168,9 @@ proc test {name code {okpattern undefined} {tags {}}} {
send_data_packet $::test_server_fd skip $name
return
}
-
+ if {$::verbose > 1} {
+ puts "starting test $name"
+ }
# abort if only_tests was set but test name is not included
if {[llength $::only_tests] > 0 && ![search_pattern_list $name $::only_tests]} {
incr ::num_skipped
@@ -200,11 +202,16 @@ proc test {name code {okpattern undefined} {tags {}}} {
$r close
}
} else {
+ set servers {}
foreach srv $::servers {
set stdout [dict get $srv stdout]
set fd [open $stdout "a+"]
puts $fd "### Starting test $::cur_test"
close $fd
+ lappend servers $stdout
+ }
+ if {$::verbose > 1} {
+ puts "### Starting test $::cur_test - with servers: $servers"
}
}
diff --git a/tests/support/util.tcl b/tests/support/util.tcl
index 236fad314..a36003029 100644
--- a/tests/support/util.tcl
+++ b/tests/support/util.tcl
@@ -602,15 +602,24 @@ proc stop_bg_complex_data {handle} {
# Write num keys with the given key prefix and value size (in bytes). If idx is
# given, it's the index (AKA level) used with the srv procedure and it specifies
# to which Redis instance to write the keys.
-proc populate {num {prefix key:} {size 3} {idx 0}} {
- set rd [redis_deferring_client $idx]
- for {set j 0} {$j < $num} {incr j} {
- $rd set $prefix$j [string repeat A $size]
+proc populate {num {prefix key:} {size 3} {idx 0} {prints false}} {
+ r $idx deferred 1
+ if {$num > 16} {set pipeline 16} else {set pipeline $num}
+ set val [string repeat A $size]
+ for {set j 0} {$j < $pipeline} {incr j} {
+ r $idx set $prefix$j $val
+ if {$prints} {puts $j}
}
- for {set j 0} {$j < $num} {incr j} {
- $rd read
+ for {} {$j < $num} {incr j} {
+ r $idx set $prefix$j $val
+ r $idx read
+ if {$prints} {puts $j}
}
- $rd close
+ for {set j 0} {$j < $pipeline} {incr j} {
+ r $idx read
+ if {$prints} {puts $j}
+ }
+ r $idx deferred 0
}
proc get_child_pid {idx} {
@@ -628,7 +637,7 @@ proc get_child_pid {idx} {
}
proc process_is_alive pid {
- if {[catch {exec ps -p $pid} err]} {
+ if {[catch {exec ps -p $pid -f} err]} {
return 0
} else {
if {[string match "*<defunct>*" $err]} { return 0 }
@@ -636,6 +645,20 @@ proc process_is_alive pid {
}
}
+proc pause_process pid {
+ exec kill -SIGSTOP $pid
+ wait_for_condition 50 100 {
+ [string match {*T*} [lindex [exec ps j $pid] 16]]
+ } else {
+ puts [exec ps j $pid]
+ fail "process didn't stop"
+ }
+}
+
+proc resume_process pid {
+ exec kill -SIGCONT $pid
+}
+
proc cmdrstat {cmd r} {
if {[regexp "\r\ncmdstat_$cmd:(.*?)\r\n" [$r info commandstats] _ value]} {
set _ $value
diff --git a/tests/test_helper.tcl b/tests/test_helper.tcl
index 922cb438d..6ec2ae1fc 100644
--- a/tests/test_helper.tcl
+++ b/tests/test_helper.tcl
@@ -526,6 +526,7 @@ proc signal_idle_client fd {
incr ::next_test
if {$::loop && $::next_test == [llength $::all_tests]} {
set ::next_test 0
+ incr ::loop -1
}
} elseif {[llength $::run_solo_tests] != 0 && [llength $::active_clients] == 0} {
if {!$::quiet} {
@@ -620,6 +621,7 @@ proc print_help_screen {} {
"--no-latency Skip latency measurements and validation by some tests."
"--stop Blocks once the first test fails."
"--loop Execute the specified set of tests forever."
+ "--loops <count> Execute the specified set of tests several times."
"--wait-server Wait after server is started (so that you can attach a debugger)."
"--dump-logs Dump server log on test failure."
"--tls Run tests in TLS mode."
@@ -721,7 +723,7 @@ for {set j 0} {$j < [llength $argv]} {incr j} {
}
exit 0
} elseif {$opt eq {--verbose}} {
- set ::verbose 1
+ incr ::verbose
} elseif {$opt eq {--client}} {
set ::client 1
set ::test_server_port $arg
@@ -744,7 +746,10 @@ for {set j 0} {$j < [llength $argv]} {incr j} {
} elseif {$opt eq {--stop}} {
set ::stop_on_failure 1
} elseif {$opt eq {--loop}} {
- set ::loop 1
+ set ::loop 2147483647
+ } elseif {$opt eq {--loops}} {
+ set ::loop $arg
+ incr j
} elseif {$opt eq {--timeout}} {
set ::timeout $arg
incr j
diff --git a/tests/unit/acl.tcl b/tests/unit/acl.tcl
index 555fb5a34..4d8c77b9f 100644
--- a/tests/unit/acl.tcl
+++ b/tests/unit/acl.tcl
@@ -289,6 +289,20 @@ start_server {tags {"acl external:skip"}} {
$rd close
} {0}
+ test {Subscribers are killed when revoked of allchannels permission} {
+ set rd [redis_deferring_client]
+ r ACL setuser psuser allchannels
+ $rd AUTH psuser pspass
+ $rd read
+ $rd CLIENT SETNAME deathrow
+ $rd read
+ $rd PSUBSCRIBE foo
+ $rd read
+ r ACL setuser psuser resetchannels
+ assert_no_match {*deathrow*} [r CLIENT LIST]
+ $rd close
+ } {0}
+
test {Subscribers are pardoned if literal permissions are retained and/or gaining allchannels} {
set rd [redis_deferring_client]
r ACL setuser psuser resetchannels &foo:1 &bar:* &orders
diff --git a/tests/unit/aofrw.tcl b/tests/unit/aofrw.tcl
index fe07351a3..cc7545265 100644
--- a/tests/unit/aofrw.tcl
+++ b/tests/unit/aofrw.tcl
@@ -1,6 +1,6 @@
# This unit has the potential to create huge .reqres files, causing log-req-res-validator.py to run for a very long time...
# Since this unit doesn't do anything worth validating, reply_schema-wise, we decided to skip it
-start_server {tags {"aofrw external:skip logreqres:skip"}} {
+start_server {tags {"aofrw external:skip logreqres:skip"} overrides {save {}}} {
# Enable the AOF
r config set appendonly yes
r config set auto-aof-rewrite-percentage 0 ; # Disable auto-rewrite.
diff --git a/tests/unit/client-eviction.tcl b/tests/unit/client-eviction.tcl
index 76f7bf0f2..1fc7c02ca 100644
--- a/tests/unit/client-eviction.tcl
+++ b/tests/unit/client-eviction.tcl
@@ -347,12 +347,12 @@ start_server {} {
# We use two obuf-clients to make sure that even if client eviction is attempted
# between two command processing (with no sleep) we don't perform any client eviction
# because the obuf limit is enforced with precedence.
- exec kill -SIGSTOP $server_pid
+ pause_process $server_pid
$rr2 get k
$rr2 flush
$rr3 get k
$rr3 flush
- exec kill -SIGCONT $server_pid
+ resume_process $server_pid
r ping ;# make sure a full event loop cycle is processed before issuing CLIENT LIST
# Validate obuf-clients were disconnected (because of obuf limit)
diff --git a/tests/unit/cluster/cli.tcl b/tests/unit/cluster/cli.tcl
index 7131ee20f..5b7f24927 100644
--- a/tests/unit/cluster/cli.tcl
+++ b/tests/unit/cluster/cli.tcl
@@ -64,7 +64,7 @@ start_multiple_servers 3 [list overrides $base_conf] {
}
test "Wait for cluster to be stable" {
- # Cluster check just verifies the the config state is self-consistent,
+ # Cluster check just verifies the config state is self-consistent,
# waiting for cluster_state to be okay is an independent check that all the
# nodes actually believe each other are healthy, prevent cluster down error.
wait_for_condition 1000 50 {
@@ -116,7 +116,7 @@ start_multiple_servers 3 [list overrides $base_conf] {
test "Kill a cluster node and wait for fail state" {
# kill node3 in cluster
- exec kill -SIGSTOP $node3_pid
+ pause_process $node3_pid
wait_for_condition 1000 50 {
[CI 0 cluster_state] eq {fail} &&
@@ -134,7 +134,7 @@ start_multiple_servers 3 [list overrides $base_conf] {
assert_equal [s -1 blocked_clients] {0}
}
- exec kill -SIGCONT $node3_pid
+ resume_process $node3_pid
$node1_rd close
} ;# stop servers
diff --git a/tests/unit/cluster/links.tcl b/tests/unit/cluster/links.tcl
index 63c2b143c..a202c378b 100644
--- a/tests/unit/cluster/links.tcl
+++ b/tests/unit/cluster/links.tcl
@@ -200,7 +200,7 @@ start_cluster 3 0 {tags {external:skip cluster}} {
# To manufacture an ever-growing send buffer from primary1 to primary2,
# make primary2 unresponsive.
set primary2_pid [srv [expr -1*$primary2_id] pid]
- exec kill -SIGSTOP $primary2_pid
+ pause_process $primary2_pid
# On primary1, send 128KB Pubsub messages in a loop until the send buffer of the link from
# primary1 to primary2 exceeds buffer limit therefore be dropped.
@@ -226,7 +226,7 @@ start_cluster 3 0 {tags {external:skip cluster}} {
assert {[dict get $same_link_p1_from_p2 create-time] eq [dict get $orig_link_p1_from_p2 create-time]}
# Revive primary2
- exec kill -SIGCONT $primary2_pid
+ resume_process $primary2_pid
# Reset configs on primary1 so config changes don't leak out to other tests
$primary1 CONFIG set cluster-node-timeout $oldtimeout
diff --git a/tests/unit/expire.tcl b/tests/unit/expire.tcl
index 5ee4488b3..ec9d73cc2 100644
--- a/tests/unit/expire.tcl
+++ b/tests/unit/expire.tcl
@@ -76,20 +76,22 @@ start_server {tags {"expire"}} {
# This test is very likely to do a false positive if the
# server is under pressure, so if it does not work give it a few more
# chances.
- for {set j 0} {$j < 10} {incr j} {
+ for {set j 0} {$j < 30} {incr j} {
r del x
r setex x 1 somevalue
- after 900
+ after 800
set a [r get x]
- after 1100
+ if {$a ne {somevalue}} continue
+ after 300
set b [r get x]
- if {$a eq {somevalue} && $b eq {}} break
+ if {$b eq {}} break
}
if {$::verbose} {
puts "millisecond expire test attempts: $j"
}
- list $a $b
- } {somevalue {}}
+ assert_equal $a {somevalue}
+ assert_equal $b {}
+ }
test "PSETEX can set sub-second expires" {
# This test is very likely to do a false positive if the server is
diff --git a/tests/unit/info.tcl b/tests/unit/info.tcl
index 759e5bc0b..2f3ad8d6f 100644
--- a/tests/unit/info.tcl
+++ b/tests/unit/info.tcl
@@ -274,5 +274,68 @@ start_server {tags {"info" "external:skip"}} {
$rd close
}
+ test {stats: eventloop metrics} {
+ set info1 [r info stats]
+ set cycle1 [getInfoProperty $info1 eventloop_cycles]
+ set el_sum1 [getInfoProperty $info1 eventloop_duration_sum]
+ set cmd_sum1 [getInfoProperty $info1 eventloop_duration_cmd_sum]
+ assert_morethan $cycle1 0
+ assert_morethan $el_sum1 0
+ assert_morethan $cmd_sum1 0
+ after 110 ;# default hz is 10, wait for a cron tick.
+ set info2 [r info stats]
+ set cycle2 [getInfoProperty $info2 eventloop_cycles]
+ set el_sum2 [getInfoProperty $info2 eventloop_duration_sum]
+ set cmd_sum2 [getInfoProperty $info2 eventloop_duration_cmd_sum]
+ assert_morethan $cycle2 $cycle1
+ assert_lessthan $cycle2 [expr $cycle1+10] ;# we expect 2 or 3 cycles here, but allow some tolerance
+ assert_morethan $el_sum2 $el_sum1
+ assert_lessthan $el_sum2 [expr $el_sum1+5000] ;# we expect roughly 100ms here, but allow some tolerance
+ assert_morethan $cmd_sum2 $cmd_sum1
+ assert_lessthan $cmd_sum2 [expr $cmd_sum1+3000] ;# we expect about tens of ms here, but allow some tolerance
+ }
+
+ test {stats: instantaneous metrics} {
+ r config resetstat
+ after 1600 ;# hz is 10, wait for 16 cron tick so that sample array is fulfilled
+ set value [s instantaneous_eventloop_cycles_per_sec]
+ assert_morethan $value 0
+ assert_lessthan $value 15 ;# default hz is 10
+ set value [s instantaneous_eventloop_duration_usec]
+ assert_morethan $value 0
+ assert_lessthan $value 22000 ;# default hz is 10, so duration < 1000 / 10, allow some tolerance
+ }
+
+ test {stats: debug metrics} {
+ # make sure debug info is hidden
+ set info [r info]
+ assert_equal [getInfoProperty $info eventloop_duration_aof_sum] {}
+ set info_all [r info all]
+ assert_equal [getInfoProperty $info_all eventloop_duration_aof_sum] {}
+
+ set info1 [r info debug]
+
+ set aof1 [getInfoProperty $info1 eventloop_duration_aof_sum]
+ assert {$aof1 >= 0}
+ set cron1 [getInfoProperty $info1 eventloop_duration_cron_sum]
+ assert {$cron1 > 0}
+ set cycle_max1 [getInfoProperty $info1 eventloop_cmd_per_cycle_max]
+ assert {$cycle_max1 > 0}
+ set duration_max1 [getInfoProperty $info1 eventloop_duration_max]
+ assert {$duration_max1 > 0}
+
+ after 110 ;# hz is 10, wait for a cron tick.
+ set info2 [r info debug]
+
+ set aof2 [getInfoProperty $info2 eventloop_duration_aof_sum]
+ assert {$aof2 >= $aof1} ;# AOF is disabled, we expect $aof2 == $aof1, but allow some tolerance.
+ set cron2 [getInfoProperty $info2 eventloop_duration_cron_sum]
+ assert_morethan $cron2 $cron1
+ set cycle_max2 [getInfoProperty $info2 eventloop_cmd_per_cycle_max]
+ assert {$cycle_max2 >= $cycle_max1}
+ set duration_max2 [getInfoProperty $info2 eventloop_duration_max]
+ assert {$duration_max2 >= $duration_max1}
+ }
+
}
}
diff --git a/tests/unit/introspection-2.tcl b/tests/unit/introspection-2.tcl
index a0cf0c30f..52a13edf7 100644
--- a/tests/unit/introspection-2.tcl
+++ b/tests/unit/introspection-2.tcl
@@ -118,6 +118,10 @@ start_server {tags {"introspection"}} {
assert_match {*calls=1,*} [cmdstat geoadd]
} {} {needs:config-resetstat}
+ test {COMMAND COUNT get total number of Redis commands} {
+ assert_morethan [r command count] 0
+ }
+
test {COMMAND GETKEYS GET} {
assert_equal {key} [r command getkeys get key]
}
diff --git a/tests/unit/introspection.tcl b/tests/unit/introspection.tcl
index 4452de6b1..76d56ee65 100644
--- a/tests/unit/introspection.tcl
+++ b/tests/unit/introspection.tcl
@@ -340,10 +340,10 @@ start_server {tags {"introspection"}} {
r client info
} {*lib-name=redis.py lib-ver=1.2.3*}
- test {RESET doesn NOT clean library name} {
+ test {RESET does NOT clean library name} {
r reset
r client info
- } {*lib-name=redis.py*}
+ } {*lib-name=redis.py*} {needs:reset}
test {CLIENT SETINFO can clear library name} {
r CLIENT SETINFO lib-name ""
@@ -362,18 +362,13 @@ start_server {tags {"introspection"}} {
assert_match [r config get save] {save {100 100}}
}
- # First "save" keyword in default config file
- start_server {config "default.conf"} {
- assert_match [r config get save] {save {900 1}}
- }
-
# First "save" keyword appends default from config file
- start_server {config "default.conf" args {--save 100 100}} {
+ start_server {config "default.conf" overrides {save {900 1}} args {--save 100 100}} {
assert_match [r config get save] {save {900 1 100 100}}
}
# Empty "save" keyword resets all
- start_server {config "default.conf" args {--save {}}} {
+ start_server {config "default.conf" overrides {save {900 1}} args {--save {}}} {
assert_match [r config get save] {save {}}
}
} {} {external:skip}
@@ -789,7 +784,7 @@ start_server {config "minimal.conf" tags {"introspection external:skip"} overrid
}
test {config during loading} {
- start_server [list overrides [list key-load-delay 50 loading-process-events-interval-bytes 1024 rdbcompression no]] {
+ start_server [list overrides [list key-load-delay 50 loading-process-events-interval-bytes 1024 rdbcompression no save "900 1"]] {
# create a big rdb that will take long to load. it is important
# for keys to be big since the server processes events only once in 2mb.
# 100mb of rdb, 100k keys will load in more than 5 seconds
diff --git a/tests/unit/maxmemory.tcl b/tests/unit/maxmemory.tcl
index 564250f2e..54aba6715 100644
--- a/tests/unit/maxmemory.tcl
+++ b/tests/unit/maxmemory.tcl
@@ -350,7 +350,7 @@ proc test_slave_buffers {test_name cmd_count payload_len limit_memory pipeline}
# put the slave to sleep
set rd_slave [redis_deferring_client]
- exec kill -SIGSTOP $slave_pid
+ pause_process $slave_pid
# send some 10mb worth of commands that don't increase the memory usage
if {$pipeline == 1} {
@@ -399,7 +399,7 @@ proc test_slave_buffers {test_name cmd_count payload_len limit_memory pipeline}
}
# unfreeze slave process (after the 'test' succeeded or failed, but before we attempt to terminate the server
- exec kill -SIGCONT $slave_pid
+ resume_process $slave_pid
}
}
}
diff --git a/tests/unit/moduleapi/cluster.tcl b/tests/unit/moduleapi/cluster.tcl
index 43356f77d..807508387 100644
--- a/tests/unit/moduleapi/cluster.tcl
+++ b/tests/unit/moduleapi/cluster.tcl
@@ -132,7 +132,7 @@ start_cluster 3 0 [list config_lines $modules] {
test "Kill a cluster node and wait for fail state" {
# kill node3 in cluster
- exec kill -SIGSTOP $node3_pid
+ pause_process $node3_pid
wait_for_condition 1000 50 {
[CI 0 cluster_state] eq {fail} &&
@@ -158,7 +158,7 @@ start_cluster 3 0 [list config_lines $modules] {
assert_error "ERR Can not execute a command 'set' while the cluster is down" {$node1 do_rm_call set x 1}
}
- exec kill -SIGCONT $node3_pid
+ resume_process $node3_pid
$node1_rd close
$node2_rd close
}
diff --git a/tests/unit/moduleapi/misc.tcl b/tests/unit/moduleapi/misc.tcl
index 6bf7b8c2a..9b0989149 100644
--- a/tests/unit/moduleapi/misc.tcl
+++ b/tests/unit/moduleapi/misc.tcl
@@ -1,6 +1,6 @@
set testmodule [file normalize tests/modules/misc.so]
-start_server {tags {"modules"}} {
+start_server {overrides {save {900 1}} tags {"modules"}} {
r module load $testmodule
test {test RM_Call} {
diff --git a/tests/unit/moduleapi/rdbloadsave.tcl b/tests/unit/moduleapi/rdbloadsave.tcl
new file mode 100644
index 000000000..9319c9385
--- /dev/null
+++ b/tests/unit/moduleapi/rdbloadsave.tcl
@@ -0,0 +1,200 @@
+set testmodule [file normalize tests/modules/rdbloadsave.so]
+
+start_server {tags {"modules"}} {
+ r module load $testmodule
+
+ test "Module rdbloadsave sanity" {
+ r test.sanity
+
+ # Try to load non-existing file
+ assert_error {*No such file or directory*} {r test.rdbload sanity.rdb}
+
+ r set x 1
+ assert_equal OK [r test.rdbsave sanity.rdb]
+
+ r flushdb
+ assert_equal OK [r test.rdbload sanity.rdb]
+ assert_equal 1 [r get x]
+ }
+
+ test "Module rdbloadsave test with pipelining" {
+ r config set save ""
+ r config set loading-process-events-interval-bytes 1024
+ r config set key-load-delay 50
+ r flushdb
+
+ populate 3000 a 1024
+ r set x 111
+ assert_equal [r dbsize] 3001
+
+ assert_equal OK [r test.rdbsave blabla.rdb]
+ r flushdb
+ assert_equal [r dbsize] 0
+
+ # Send commands with pipeline. First command will call RM_RdbLoad() in
+ # the command callback. While loading RDB, Redis can go to networking to
+ # reply -LOADING. By sending commands in pipeline, we verify it doesn't
+ # cause a problem.
+ # e.g. Redis won't try to process next message of the current client
+ # while it is in the command callback for that client .
+ set rd1 [redis_deferring_client]
+ $rd1 test.rdbload blabla.rdb
+
+ wait_for_condition 50 100 {
+ [s loading] eq 1
+ } else {
+ fail "Redis did not start loading or loaded RDB too fast"
+ }
+
+ $rd1 get x
+ $rd1 dbsize
+
+ assert_equal OK [$rd1 read]
+ assert_equal 111 [$rd1 read]
+ assert_equal 3001 [$rd1 read]
+ r flushdb
+ r config set key-load-delay 0
+ }
+
+ test "Module rdbloadsave with aof" {
+ r config set save ""
+
+ # Enable the AOF
+ r config set appendonly yes
+ r config set auto-aof-rewrite-percentage 0 ; # Disable auto-rewrite.
+ waitForBgrewriteaof r
+
+ r set k v1
+ assert_equal OK [r test.rdbsave aoftest.rdb]
+
+ r set k v2
+ r config set rdb-key-save-delay 10000000
+ r bgrewriteaof
+
+ # RM_RdbLoad() should kill aof fork
+ assert_equal OK [r test.rdbload aoftest.rdb]
+
+ wait_for_condition 50 100 {
+ [string match {*Killing*AOF*child*} [exec tail -20 < [srv 0 stdout]]]
+ } else {
+ fail "Can't find 'Killing AOF child' in recent log lines"
+ }
+
+ # Verify the value in the loaded rdb
+ assert_equal v1 [r get k]
+
+ r flushdb
+ r config set rdb-key-save-delay 0
+ r config set appendonly no
+ }
+
+ test "Module rdbloadsave with bgsave" {
+ r flushdb
+ r config set save ""
+
+ r set k v1
+ assert_equal OK [r test.rdbsave bgsave.rdb]
+
+ r set k v2
+ r config set rdb-key-save-delay 500000
+ r bgsave
+
+ # RM_RdbLoad() should kill RDB fork
+ assert_equal OK [r test.rdbload bgsave.rdb]
+
+ wait_for_condition 10 1000 {
+ [string match {*Background*saving*terminated*} [exec tail -20 < [srv 0 stdout]]]
+ } else {
+ fail "Can't find 'Background saving terminated' in recent log lines"
+ }
+
+ assert_equal v1 [r get k]
+ r flushall
+ waitForBgsave r
+ r config set rdb-key-save-delay 0
+ }
+
+ test "Module rdbloadsave calls rdbsave in a module fork" {
+ r flushdb
+ r config set save ""
+ r config set rdb-key-save-delay 500000
+
+ r set k v1
+
+ # Module will call RM_Fork() before calling RM_RdbSave()
+ assert_equal OK [r test.rdbsave_fork rdbfork.rdb]
+ assert_equal [s module_fork_in_progress] 1
+
+ wait_for_condition 10 1000 {
+ [status r module_fork_in_progress] == "0"
+ } else {
+ fail "Module fork didn't finish"
+ }
+
+ r set k v2
+ assert_equal OK [r test.rdbload rdbfork.rdb]
+ assert_equal v1 [r get k]
+
+ r config set rdb-key-save-delay 0
+ }
+
+ test "Unload the module - rdbloadsave" {
+ assert_equal {OK} [r module unload rdbloadsave]
+ }
+
+ tags {repl} {
+ test {Module rdbloadsave on master and replica} {
+ 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]
+
+ $master set x 10000
+
+ # Start the replication process...
+ $replica replicaof $master_host $master_port
+
+ wait_for_condition 100 100 {
+ [status $master sync_full] == 1
+ } else {
+ fail "Master <-> Replica didn't start the full sync"
+ }
+
+ # RM_RdbSave() is allowed on replicas
+ assert_equal OK [$replica test.rdbsave rep.rdb]
+
+ # RM_RdbLoad() is not allowed on replicas
+ assert_error {*supported*} {$replica test.rdbload rep.rdb}
+
+ assert_equal OK [$master test.rdbsave master.rdb]
+ $master set x 20000
+
+ wait_for_condition 100 100 {
+ [$replica get x] == 20000
+ } else {
+ fail "Replica didn't get the update"
+ }
+
+ # Loading RDB on master will drop replicas
+ assert_equal OK [$master test.rdbload master.rdb]
+
+ wait_for_condition 100 100 {
+ [status $master sync_full] == 2
+ } else {
+ fail "Master <-> Replica didn't start the full sync"
+ }
+
+ wait_for_condition 100 100 {
+ [$replica get x] == 10000
+ } else {
+ fail "Replica didn't get the update"
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/tests/unit/moduleapi/reply.tcl b/tests/unit/moduleapi/reply.tcl
index 291253d3c..547be21c0 100644
--- a/tests/unit/moduleapi/reply.tcl
+++ b/tests/unit/moduleapi/reply.tcl
@@ -126,6 +126,17 @@ start_server {tags {"modules"}} {
assert_match "An error" $e
}
+ test "RESP$proto: RM_ReplyWithErrorFormat: error format reply" {
+ catch {r rw.error_format "An error: %s" foo} e
+ assert_match "ERR An error: foo" $e
+
+ catch {r rw.error_format "-ERR An error: %s" foo2} e
+ assert_match "ERR An error: foo2" $e
+
+ catch {r rw.error_format "-WRONGTYPE A type error: %s" foo3} e
+ assert_match "WRONGTYPE A type error: foo3" $e
+ }
+
r hello 2
}
diff --git a/tests/unit/moduleapi/stream.tcl b/tests/unit/moduleapi/stream.tcl
index 80c24ff6c..7ad1a3059 100644
--- a/tests/unit/moduleapi/stream.tcl
+++ b/tests/unit/moduleapi/stream.tcl
@@ -61,6 +61,23 @@ start_server {tags {"modules"}} {
assert_equal $result $n
}
+ test {Module stream XADD big fields doesn't create empty key} {
+ set original_proto [config_get_set proto-max-bulk-len 2147483647] ;#2gb
+ set original_query [config_get_set client-query-buffer-limit 2147483647] ;#2gb
+
+ r del mystream
+ r write "*4\r\n\$10\r\nstream.add\r\n\$8\r\nmystream\r\n\$5\r\nfield\r\n"
+ catch {
+ write_big_bulk 1073741824 ;#1gb
+ } err
+ assert {$err eq "ERR StreamAdd failed"}
+ assert_equal 0 [r exists mystream]
+
+ # restore defaults
+ r config set proto-max-bulk-len $original_proto
+ r config set client-query-buffer-limit $original_query
+ } {OK} {large-memory}
+
test {Module stream iterator} {
r del mystream
set streamid1 [r xadd mystream * item 1 value a]
diff --git a/tests/unit/moduleapi/testrdb.tcl b/tests/unit/moduleapi/testrdb.tcl
index 2545a8ad2..ae3036f70 100644
--- a/tests/unit/moduleapi/testrdb.tcl
+++ b/tests/unit/moduleapi/testrdb.tcl
@@ -61,13 +61,13 @@ tags "modules" {
# 7 == 0111 - use aux_save2 before and after key space with data
test {modules are able to persist globals before and after} {
set server_path [tmpdir "server.module-testrdb"]
- start_server [list overrides [list loadmodule "$testmodule $test_case" "dir" $server_path] keep_persistence true] {
+ start_server [list overrides [list loadmodule "$testmodule $test_case" "dir" $server_path "save" "900 1"] keep_persistence true] {
r testrdb.set.before global1
r testrdb.set.after global2
assert_equal "global1" [r testrdb.get.before]
assert_equal "global2" [r testrdb.get.after]
}
- start_server [list overrides [list loadmodule "$testmodule $test_case" "dir" $server_path]] {
+ start_server [list overrides [list loadmodule "$testmodule $test_case" "dir" $server_path "save" "900 1"]] {
assert_equal "global1" [r testrdb.get.before]
assert_equal "global2" [r testrdb.get.after]
}
@@ -80,11 +80,11 @@ tags "modules" {
# 5 == 0101 - use aux_save2 after key space with data
test {modules are able to persist globals just after} {
set server_path [tmpdir "server.module-testrdb"]
- start_server [list overrides [list loadmodule "$testmodule $test_case" "dir" $server_path] keep_persistence true] {
+ start_server [list overrides [list loadmodule "$testmodule $test_case" "dir" $server_path "save" "900 1"] keep_persistence true] {
r testrdb.set.after global2
assert_equal "global2" [r testrdb.get.after]
}
- start_server [list overrides [list loadmodule "$testmodule $test_case" "dir" $server_path]] {
+ start_server [list overrides [list loadmodule "$testmodule $test_case" "dir" $server_path "save" "900 1"]] {
assert_equal "global2" [r testrdb.get.after]
}
}
diff --git a/tests/unit/moduleapi/zset.tcl b/tests/unit/moduleapi/zset.tcl
index 1c146eaf4..b6ab41d5f 100644
--- a/tests/unit/moduleapi/zset.tcl
+++ b/tests/unit/moduleapi/zset.tcl
@@ -14,6 +14,26 @@ start_server {tags {"modules"}} {
assert_equal 0 [r exists k]
}
+ test {Module zset add} {
+ r del k
+ # Check that failure does not create empty key
+ assert_error "ERR ZsetAdd failed" {r zset.add k nan hello}
+ assert_equal 0 [r exists k]
+
+ r zset.add k 100 hello
+ assert_equal {hello 100} [r zrange k 0 -1 withscores]
+ }
+
+ test {Module zset incrby} {
+ r del k
+ # Check that failure does not create empty key
+ assert_error "ERR ZsetIncrby failed" {r zset.incrby k hello nan}
+ assert_equal 0 [r exists k]
+
+ r zset.incrby k hello 100
+ assert_equal {hello 100} [r zrange k 0 -1 withscores]
+ }
+
test "Unload the module - zset" {
assert_equal {OK} [r module unload zset]
}
diff --git a/tests/unit/multi.tcl b/tests/unit/multi.tcl
index bdf398150..851e02247 100644
--- a/tests/unit/multi.tcl
+++ b/tests/unit/multi.tcl
@@ -891,14 +891,14 @@ start_server {tags {"multi"}} {
set res [r read]
assert_equal $res "+OK"
set res [r read]
- r readraw 1
+ r readraw 0
set _ $res
} {*CONFIG SET failed*}
test "Flushall while watching several keys by one client" {
r flushall
- r mset a a b b
- r watch b a
+ r mset a{t} a b{t} b
+ r watch b{t} a{t}
r flushall
r ping
}
diff --git a/tests/unit/querybuf.tcl b/tests/unit/querybuf.tcl
index bbbea12f4..f4859dd27 100644
--- a/tests/unit/querybuf.tcl
+++ b/tests/unit/querybuf.tcl
@@ -5,7 +5,7 @@ proc client_idle_sec {name} {
return $idle
}
-# Calculate query buffer memory of slave
+# Calculate query buffer memory of client
proc client_query_buffer {name} {
set clients [split [r client list] "\r\n"]
set c [lsearch -inline $clients *name=$name*]
@@ -18,6 +18,9 @@ proc client_query_buffer {name} {
}
start_server {tags {"querybuf slow"}} {
+ # increase the execution frequency of clientsCron
+ r config set hz 100
+
# The test will run at least 2s to check if client query
# buffer will be resized when client idle 2s.
test "query buffer resized correctly" {
@@ -38,6 +41,9 @@ start_server {tags {"querybuf slow"}} {
}
test "query buffer resized correctly when not idle" {
+ # Pause cron to prevent premature shrinking (timing issue).
+ r debug pause-cron 1
+
# Memory will increase by more than 32k due to client query buffer.
set rd [redis_client]
$rd client setname test_client
@@ -49,6 +55,8 @@ start_server {tags {"querybuf slow"}} {
set orig_test_client_qbuf [client_query_buffer test_client]
assert {$orig_test_client_qbuf > 32768}
+ r debug pause-cron 0
+
# Wait for qbuf to shrink due to lower peak
set t [clock milliseconds]
while true {
@@ -62,5 +70,27 @@ start_server {tags {"querybuf slow"}} {
# Validate qbuf shrunk but isn't 0 since we maintain room based on latest peak
assert {[client_query_buffer test_client] > 0 && [client_query_buffer test_client] < $orig_test_client_qbuf}
$rd close
+ } {0} {needs:debug}
+
+ test "query buffer resized correctly with fat argv" {
+ set rd [redis_client]
+ $rd client setname test_client
+ $rd write "*3\r\n\$3\r\nset\r\n\$1\r\na\r\n\$1000000\r\n"
+ $rd flush
+
+ after 20
+ if {[client_query_buffer test_client] < 1000000} {
+ fail "query buffer should not be resized when client idle time smaller than 2s"
+ }
+
+ # Check that the query buffer is resized after 2 sec
+ wait_for_condition 1000 10 {
+ [client_idle_sec test_client] >= 3 && [client_query_buffer test_client] < 1000000
+ } else {
+ fail "query buffer should be resized when client idle time bigger than 2s"
+ }
+
+ $rd close
}
+
}
diff --git a/tests/unit/shutdown.tcl b/tests/unit/shutdown.tcl
index b419c83a1..7504851a1 100644
--- a/tests/unit/shutdown.tcl
+++ b/tests/unit/shutdown.tcl
@@ -30,7 +30,7 @@ start_server {tags {"shutdown external:skip"}} {
}
}
-start_server {tags {"shutdown external:skip"}} {
+start_server {tags {"shutdown external:skip"} overrides {save {900 1}}} {
test {SHUTDOWN ABORT can cancel SIGTERM} {
r debug pause-cron 1
set pid [s process_id]
@@ -48,7 +48,7 @@ start_server {tags {"shutdown external:skip"}} {
}
# It will cost 2s (20 * 100ms) to dump rdb
r config set rdb-key-save-delay 100000
-
+
set pid [s process_id]
set temp_rdb [file join [lindex [r config get dir] 1] temp-${pid}.rdb]
@@ -72,7 +72,7 @@ start_server {tags {"shutdown external:skip"}} {
}
}
-start_server {tags {"shutdown external:skip"}} {
+start_server {tags {"shutdown external:skip"} overrides {save {900 1}}} {
set pid [s process_id]
set dump_rdb [file join [lindex [r config get dir] 1] dump.rdb]
@@ -107,3 +107,27 @@ start_server {tags {"shutdown external:skip"}} {
exec rm -r $dump_rdb
}
}
+
+
+start_server {tags {"shutdown external:skip"} overrides {appendonly no}} {
+ test {SHUTDOWN SIGTERM will abort if there's an initial AOFRW - default} {
+ r config set shutdown-on-sigterm default
+ r config set rdb-key-save-delay 10000000
+ for {set i 0} {$i < 10} {incr i} {
+ r set $i $i
+ }
+
+ r config set appendonly yes
+ wait_for_condition 1000 10 {
+ [s aof_rewrite_in_progress] eq 1
+ } else {
+ fail "aof rewrite did not start in time"
+ }
+
+ set pid [s process_id]
+ exec kill -SIGTERM $pid
+ wait_for_log_messages 0 {"*Writing initial AOF, can't exit*"} 0 1000 10
+
+ r config set shutdown-on-sigterm force
+ }
+}
diff --git a/tests/unit/slowlog.tcl b/tests/unit/slowlog.tcl
index bc15c6411..3c547b924 100644
--- a/tests/unit/slowlog.tcl
+++ b/tests/unit/slowlog.tcl
@@ -24,8 +24,11 @@ start_server {tags {"slowlog"} overrides {slowlog-log-slower-than 1000000}} {
} {10}
test {SLOWLOG - GET optional argument to limit output len works} {
- llength [r slowlog get 5]
- } {5}
+
+ assert_equal 5 [llength [r slowlog get 5]]
+ assert_equal 10 [llength [r slowlog get -1]]
+ assert_equal 10 [llength [r slowlog get 20]]
+ }
test {SLOWLOG - RESET subcommand works} {
r config set slowlog-log-slower-than 100000
@@ -39,7 +42,7 @@ start_server {tags {"slowlog"} overrides {slowlog-log-slower-than 1000000}} {
set e [lindex [r slowlog get] 0]
assert_equal [llength $e] 6
if {!$::external} {
- assert_equal [lindex $e 0] 105
+ assert_equal [lindex $e 0] 107
}
assert_equal [expr {[lindex $e 2] > 100000}] 1
assert_equal [lindex $e 3] {debug sleep 0.2}
diff --git a/tests/unit/type/hash.tcl b/tests/unit/type/hash.tcl
index 17e3ba40b..4cff0f244 100644
--- a/tests/unit/type/hash.tcl
+++ b/tests/unit/type/hash.tcl
@@ -350,9 +350,16 @@ start_server {tags {"hash"}} {
set _ $rv
} {{{} {}} {{} {}} {{} {}}}
- test {HMGET against wrong type} {
+ test {HMGET HRANDFIELD HGET HGETALL HDEL HINCRBY HINCRBYFLOAT HSTRLEN against wrong type} {
r set wrongtype somevalue
- assert_error "*wrong*" {r hmget wrongtype field1 field2}
+ assert_error "WRONGTYPE Operation against a key*" {r hmget wrongtype field1 field2}
+ assert_error "WRONGTYPE Operation against a key*" {r hrandfield wrongtype}
+ assert_error "WRONGTYPE Operation against a key*" {r hget wrongtype field1}
+ assert_error "WRONGTYPE Operation against a key*" {r hgetall wrongtype}
+ assert_error "WRONGTYPE Operation against a key*" {r hdel wrongtype field1}
+ assert_error "WRONGTYPE Operation against a key*" {r hincrby wrongtype field1 2}
+ assert_error "WRONGTYPE Operation against a key*" {r hincrbyfloat wrongtype field1 2.5}
+ assert_error "WRONGTYPE Operation against a key*" {r hstrlen wrongtype field1}
}
test {HMGET - small hash} {
diff --git a/tests/unit/type/incr.tcl b/tests/unit/type/incr.tcl
index a64f357ae..c09f2e8b2 100644
--- a/tests/unit/type/incr.tcl
+++ b/tests/unit/type/incr.tcl
@@ -13,6 +13,12 @@ start_server {tags {"incr"}} {
r decr novar
} {1}
+ test {DECR against key is not exist and incr} {
+ r del novar_not_exist
+ assert_equal {-1} [r decr novar_not_exist]
+ assert_equal {0} [r incr novar_not_exist]
+ }
+
test {INCR against key originally set with SET} {
r set novar 100
r incr novar
@@ -64,6 +70,11 @@ start_server {tags {"incr"}} {
r decrby novar 17179869185
} {-1}
+ test {DECRBY against key is not exist} {
+ r del key_not_exist
+ assert_equal {-1} [r decrby key_not_exist 1]
+ }
+
test {INCR uses shared objects in the 0-9999 range} {
r set foo -1
r incr foo
diff --git a/tests/unit/type/list.tcl b/tests/unit/type/list.tcl
index d970b0278..a57e5df3e 100644
--- a/tests/unit/type/list.tcl
+++ b/tests/unit/type/list.tcl
@@ -464,6 +464,7 @@ foreach {type large} [array get largevalue] {
assert {[r LPOS mylist c RANK -1] == 7}
assert {[r LPOS mylist c RANK -2] == 6}
assert_error "*RANK can't be zero: use 1 to start from the first match, 2 from the second ... or use negative to start*" {r LPOS mylist c RANK 0}
+ assert_error "*value is out of range*" {r LPOS mylist c RANK -9223372036854775808}
}
test {LPOS COUNT option} {
@@ -1416,6 +1417,15 @@ foreach {pop} {BLPOP BLMPOP_LEFT} {
set e
} {*ERR*syntax*error*}
+ test {LINSERT against non-list value error} {
+ r set k1 v1
+ assert_error {WRONGTYPE Operation against a key holding the wrong kind of value*} {r linsert k1 after 0 0}
+ }
+
+ test {LINSERT against non existing key} {
+ assert_equal 0 [r linsert not-a-key before 0 0]
+ }
+
foreach type {listpack quicklist} {
foreach {num} {250 500} {
if {$type == "quicklist"} {
diff --git a/tests/unit/type/string.tcl b/tests/unit/type/string.tcl
index b25a14f4c..68c360b97 100644
--- a/tests/unit/type/string.tcl
+++ b/tests/unit/type/string.tcl
@@ -151,6 +151,14 @@ start_server {tags {"string"}} {
set ex
} {*syntax*}
+ test "GETEX and GET expired key or not exist" {
+ r del foo
+ r set foo bar px 1
+ after 2
+ assert_equal {} [r getex foo]
+ assert_equal {} [r get foo]
+ }
+
test "GETEX no arguments" {
set ex {}
catch {r getex} ex
@@ -438,6 +446,11 @@ start_server {tags {"string"}} {
assert_equal "" [r getrange mykey 0 -1]
}
+ test "GETRANGE against wrong key type" {
+ r lpush lkey1 "list"
+ assert_error {WRONGTYPE Operation against a key holding the wrong kind of value*} {r getrange lkey1 0 -1}
+ }
+
test "GETRANGE against string value" {
r set mykey "Hello World"
assert_equal "Hell" [r getrange mykey 0 3]
@@ -474,6 +487,9 @@ start_server {tags {"string"}} {
assert_equal "a" [r substr key 0 0]
assert_equal "abcd" [r substr key 0 3]
assert_equal "bcde" [r substr key -4 -1]
+ assert_equal "" [r substr key -1 -3]
+ assert_equal "" [r substr key 7 8]
+ assert_equal "" [r substr nokey 0 1]
}
if {[string match {*jemalloc*} [s mem_allocator]]} {
diff --git a/tests/unit/type/zset.tcl b/tests/unit/type/zset.tcl
index a52a77f24..d1da02778 100644
--- a/tests/unit/type/zset.tcl
+++ b/tests/unit/type/zset.tcl
@@ -755,6 +755,46 @@ start_server {tags {"zset"}} {
assert_equal 0 [r exists zset]
}
+ test "ZREMRANGEBYLEX basics - $encoding" {
+ proc remrangebylex {min max} {
+ create_default_lex_zset
+ assert_equal 1 [r exists zset]
+ r zremrangebylex zset $min $max
+ }
+
+ # inclusive range
+ assert_equal 3 [remrangebylex - \[cool]
+ assert_equal {down elephant foo great hill omega} [r zrange zset 0 -1]
+ assert_equal 3 [remrangebylex \[bar \[down]
+ assert_equal {alpha elephant foo great hill omega} [r zrange zset 0 -1]
+ assert_equal 3 [remrangebylex \[g +]
+ assert_equal {alpha bar cool down elephant foo} [r zrange zset 0 -1]
+ assert_equal 6 [r zcard zset]
+
+ # exclusive range
+ assert_equal 2 [remrangebylex - (cool]
+ assert_equal {cool down elephant foo great hill omega} [r zrange zset 0 -1]
+ assert_equal 1 [remrangebylex (bar (down]
+ assert_equal {alpha bar down elephant foo great hill omega} [r zrange zset 0 -1]
+ assert_equal 2 [remrangebylex (great +]
+ assert_equal {alpha bar cool down elephant foo great} [r zrange zset 0 -1]
+ assert_equal 7 [r zcard zset]
+
+ # inclusive and exclusive
+ assert_equal 0 [remrangebylex (az (b]
+ assert_equal {alpha bar cool down elephant foo great hill omega} [r zrange zset 0 -1]
+ assert_equal 0 [remrangebylex (z +]
+ assert_equal {alpha bar cool down elephant foo great hill omega} [r zrange zset 0 -1]
+ assert_equal 0 [remrangebylex - \[aaaa]
+ assert_equal {alpha bar cool down elephant foo great hill omega} [r zrange zset 0 -1]
+ assert_equal 9 [r zcard zset]
+
+ # destroy when empty
+ assert_equal 9 [remrangebylex - +]
+ assert_equal 0 [r zcard zset]
+ assert_equal 0 [r exists zset]
+ }
+
test "ZUNIONSTORE against non-existing key doesn't set destination - $encoding" {
r del zseta{t}
assert_equal 0 [r zunionstore dst_key{t} 1 zseta{t}]
diff --git a/tests/unit/wait.tcl b/tests/unit/wait.tcl
index 08a7a71f6..8c6010afb 100644
--- a/tests/unit/wait.tcl
+++ b/tests/unit/wait.tcl
@@ -47,25 +47,25 @@ start_server {} {
}
test {WAIT should not acknowledge 1 additional copy if slave is blocked} {
- exec kill -SIGSTOP $slave_pid
+ pause_process $slave_pid
$master set foo 0
$master incr foo
$master incr foo
$master incr foo
assert {[$master wait 1 1000] == 0}
- exec kill -SIGCONT $slave_pid
+ resume_process $slave_pid
assert {[$master wait 1 1000] == 1}
}
test {WAIT implicitly blocks on client pause since ACKs aren't sent} {
- exec kill -SIGSTOP $slave_pid
+ pause_process $slave_pid
$master multi
$master incr foo
$master client pause 10000 write
$master exec
assert {[$master wait 1 1000] == 0}
$master client unpause
- exec kill -SIGCONT $slave_pid
+ resume_process $slave_pid
assert {[$master wait 1 1000] == 1}
}
@@ -73,7 +73,7 @@ start_server {} {
set rd [redis_deferring_client -1]
set rd2 [redis_deferring_client -1]
- exec kill -SIGSTOP $slave_pid
+ pause_process $slave_pid
$rd incr foo
$rd read
@@ -85,7 +85,7 @@ start_server {} {
$rd2 wait 1 0
wait_for_blocked_clients_count 2 100 10 -1
- exec kill -SIGCONT $slave_pid
+ resume_process $slave_pid
assert_equal [$rd read] {1}
assert_equal [$rd2 read] {1}
@@ -175,7 +175,49 @@ tags {"wait aof network external:skip"} {
$replica config set appendfsync everysec
test {WAITAOF replica copy everysec} {
+ $replica config set appendfsync everysec
+ waitForBgrewriteaof $replica ;# Make sure there is no AOFRW
+
+ $master incr foo
+ assert_equal [$master waitaof 0 1 0] {1 1}
+ }
+
+ test {WAITAOF replica copy everysec with AOFRW} {
+ $replica config set appendfsync everysec
+
+ # When we trigger an AOFRW, a fsync is triggered when closing the old INCR file,
+ # so with the everysec, we will skip that second of fsync, and in the next second
+ # after that, we will eventually do the fsync.
+ $replica bgrewriteaof
+ waitForBgrewriteaof $replica
+
+ $master incr foo
+ assert_equal [$master waitaof 0 1 0] {1 1}
+ }
+
+ test {WAITAOF replica copy everysec with slow AOFRW} {
+ $replica config set appendfsync everysec
+ $replica config set rdb-key-save-delay 1000000 ;# 1 sec
+
+ $replica bgrewriteaof
+
+ $master incr foo
+ assert_equal [$master waitaof 0 1 0] {1 1}
+
+ $replica config set rdb-key-save-delay 0
+ waitForBgrewriteaof $replica
+ }
+
+ test {WAITAOF replica copy everysec->always with AOFRW} {
+ $replica config set appendfsync everysec
+
+ # Try to fit all of them in the same round second, although there's no way to guarantee
+ # that, it can be done on fast machine. In any case, the test shouldn't fail either.
+ $replica bgrewriteaof
$master incr foo
+ waitForBgrewriteaof $replica
+ $replica config set appendfsync always
+
assert_equal [$master waitaof 0 1 0] {1 1}
}
@@ -187,10 +229,10 @@ tags {"wait aof network external:skip"} {
}
test {WAITAOF replica copy if replica is blocked} {
- exec kill -SIGSTOP $replica_pid
+ pause_process $replica_pid
$master incr foo
assert_equal [$master waitaof 0 1 50] {1 0} ;# exits on timeout
- exec kill -SIGCONT $replica_pid
+ resume_process $replica_pid
assert_equal [$master waitaof 0 1 0] {1 1}
}
@@ -198,7 +240,7 @@ tags {"wait aof network external:skip"} {
set rd [redis_deferring_client -1]
set rd2 [redis_deferring_client -1]
- exec kill -SIGSTOP $replica_pid
+ pause_process $replica_pid
$rd incr foo
$rd read
@@ -210,7 +252,7 @@ tags {"wait aof network external:skip"} {
$rd2 waitaof 0 1 0
wait_for_blocked_clients_count 2 100 10 -1
- exec kill -SIGCONT $replica_pid
+ resume_process $replica_pid
assert_equal [$rd read] {1 1}
assert_equal [$rd2 read] {1 1}
@@ -396,7 +438,7 @@ start_server {} {
waitForBgrewriteaof $replica1
waitForBgrewriteaof $replica2
- exec kill -SIGSTOP $replica1_pid
+ pause_process $replica1_pid
$rd incr foo
$rd read
@@ -409,7 +451,7 @@ start_server {} {
wait_for_blocked_clients_count 2
- exec kill -SIGCONT $replica1_pid
+ resume_process $replica1_pid
# WAIT will unblock the client first.
assert_equal [$rd2 read] {2}