summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/assets/default.conf2
-rw-r--r--tests/integration/aof-multi-part.tcl168
-rw-r--r--tests/integration/corrupt-dump.tcl12
-rw-r--r--tests/integration/replication-4.tcl45
-rw-r--r--tests/modules/Makefile6
-rw-r--r--tests/modules/aclcheck.c2
-rw-r--r--tests/modules/basics.c4
-rw-r--r--tests/modules/keyspace_events.c15
-rw-r--r--tests/modules/mallocsize.c237
-rw-r--r--tests/modules/moduleconfigs.c26
-rw-r--r--tests/modules/publish.c42
-rw-r--r--tests/modules/subcommands.c5
-rw-r--r--tests/sentinel/tests/05-manual.tcl6
-rw-r--r--tests/sentinel/tests/includes/init-tests.tcl3
-rw-r--r--tests/support/util.tcl16
-rw-r--r--tests/test_helper.tcl11
-rw-r--r--tests/unit/acl-v2.tcl2
-rw-r--r--tests/unit/acl.tcl2
-rw-r--r--tests/unit/auth.tcl2
-rw-r--r--tests/unit/bitops.tcl8
-rw-r--r--tests/unit/cluster-scripting.tcl64
-rw-r--r--tests/unit/functions.tcl81
-rw-r--r--tests/unit/geo.tcl18
-rw-r--r--tests/unit/introspection.tcl27
-rw-r--r--tests/unit/moduleapi/aclcheck.tcl3
-rw-r--r--tests/unit/moduleapi/basics.tcl2
-rw-r--r--tests/unit/moduleapi/blockedclient.tcl47
-rw-r--r--tests/unit/moduleapi/cluster.tcl16
-rw-r--r--tests/unit/moduleapi/cmdintrospection.tcl1
-rw-r--r--tests/unit/moduleapi/keyspace_events.tcl11
-rw-r--r--tests/unit/moduleapi/mallocsize.tcl21
-rw-r--r--tests/unit/moduleapi/moduleconfigs.tcl14
-rw-r--r--tests/unit/moduleapi/propagate.tcl6
-rw-r--r--tests/unit/moduleapi/publish.tcl17
-rw-r--r--tests/unit/moduleapi/subcommands.tcl8
-rw-r--r--tests/unit/oom-score-adj.tcl5
-rw-r--r--tests/unit/other.tcl2
-rw-r--r--tests/unit/pubsub.tcl13
-rw-r--r--tests/unit/pubsubshard.tcl76
-rw-r--r--tests/unit/scripting.tcl114
-rw-r--r--tests/unit/slowlog.tcl25
-rw-r--r--tests/unit/type/hash.tcl43
-rw-r--r--tests/unit/type/incr.tcl10
-rw-r--r--tests/unit/type/list.tcl10
-rw-r--r--tests/unit/type/set.tcl2
-rw-r--r--tests/unit/type/stream.tcl8
-rw-r--r--tests/unit/type/zset.tcl23
-rw-r--r--tests/unit/violations.tcl3
48 files changed, 1048 insertions, 236 deletions
diff --git a/tests/assets/default.conf b/tests/assets/default.conf
index 42297903f..227ab5e7f 100644
--- a/tests/assets/default.conf
+++ b/tests/assets/default.conf
@@ -30,3 +30,5 @@ activerehashing yes
enable-protected-configs yes
enable-debug-command yes
enable-module-command yes
+
+propagation-error-behavior panic \ No newline at end of file
diff --git a/tests/integration/aof-multi-part.tcl b/tests/integration/aof-multi-part.tcl
index 982b6907b..74f6b4949 100644
--- a/tests/integration/aof-multi-part.tcl
+++ b/tests/integration/aof-multi-part.tcl
@@ -1104,7 +1104,11 @@ tags {"external:skip"} {
# Set a key so that AOFRW can be delayed
r set k v
- # Let AOFRW fail two times, this will trigger AOFRW limit
+ # Let AOFRW fail 3 times, this will trigger AOFRW limit
+ r bgrewriteaof
+ catch {exec kill -9 [get_child_pid 0]}
+ waitForBgrewriteaof r
+
r bgrewriteaof
catch {exec kill -9 [get_child_pid 0]}
waitForBgrewriteaof r
@@ -1118,6 +1122,7 @@ tags {"external:skip"} {
{file appendonly.aof.6.incr.aof seq 6 type i}
{file appendonly.aof.7.incr.aof seq 7 type i}
{file appendonly.aof.8.incr.aof seq 8 type i}
+ {file appendonly.aof.9.incr.aof seq 9 type i}
}
# Write 1KB data to trigger AOFRW
@@ -1137,6 +1142,7 @@ tags {"external:skip"} {
{file appendonly.aof.6.incr.aof seq 6 type i}
{file appendonly.aof.7.incr.aof seq 7 type i}
{file appendonly.aof.8.incr.aof seq 8 type i}
+ {file appendonly.aof.9.incr.aof seq 9 type i}
}
# Turn off auto rewrite
@@ -1154,11 +1160,11 @@ tags {"external:skip"} {
waitForBgrewriteaof r
# Can create New INCR AOF
- assert_equal 1 [check_file_exist $aof_dirpath "${aof_basename}.9${::incr_aof_sufix}${::aof_format_suffix}"]
+ assert_equal 1 [check_file_exist $aof_dirpath "${aof_basename}.10${::incr_aof_sufix}${::aof_format_suffix}"]
assert_aof_manifest_content $aof_manifest_file {
{file appendonly.aof.11.base.rdb seq 11 type b}
- {file appendonly.aof.9.incr.aof seq 9 type i}
+ {file appendonly.aof.10.incr.aof seq 10 type i}
}
set d1 [r debug digest]
@@ -1166,5 +1172,161 @@ tags {"external:skip"} {
set d2 [r debug digest]
assert {$d1 eq $d2}
}
+
+ start_server {overrides {aof-use-rdb-preamble {yes} appendonly {no}}} {
+ set dir [get_redis_dir]
+ set aof_basename "appendonly.aof"
+ set aof_dirname "appendonlydir"
+ set aof_dirpath "$dir/$aof_dirname"
+ set aof_manifest_name "$aof_basename$::manifest_suffix"
+ set aof_manifest_file "$dir/$aof_dirname/$aof_manifest_name"
+
+ set master [srv 0 client]
+ set master_host [srv 0 host]
+ set master_port [srv 0 port]
+
+ test "AOF will open a temporary INCR AOF to accumulate data until the first AOFRW success when AOF is dynamically enabled" {
+ r config set save ""
+ # Increase AOFRW execution time to give us enough time to kill it
+ r config set rdb-key-save-delay 10000000
+
+ # Start write load
+ set load_handle0 [start_write_load $master_host $master_port 10]
+
+ wait_for_condition 50 100 {
+ [r dbsize] > 0
+ } else {
+ fail "No write load detected."
+ }
+
+ # Enable AOF will trigger an initialized AOFRW
+ r config set appendonly yes
+ # Let AOFRW fail
+ assert_equal 1 [s aof_rewrite_in_progress]
+ set pid1 [get_child_pid 0]
+ catch {exec kill -9 $pid1}
+
+ # Wait for AOFRW to exit and delete temp incr aof
+ wait_for_condition 1000 100 {
+ [count_log_message 0 "Removing the temp incr aof file"] == 1
+ } else {
+ fail "temp aof did not delete"
+ }
+
+ # Make sure manifest file is not created
+ assert_equal 0 [check_file_exist $aof_dirpath $aof_manifest_name]
+ # Make sure BASE AOF is not created
+ assert_equal 0 [check_file_exist $aof_dirpath "${aof_basename}.1${::base_aof_sufix}${::rdb_format_suffix}"]
+
+ # Make sure the next AOFRW has started
+ wait_for_condition 1000 50 {
+ [s aof_rewrite_in_progress] == 1
+ } else {
+ fail "aof rewrite did not scheduled"
+ }
+
+ # Do a successful AOFRW
+ set total_forks [s total_forks]
+ r config set rdb-key-save-delay 0
+ catch {exec kill -9 [get_child_pid 0]}
+
+ # Make sure the next AOFRW has started
+ wait_for_condition 1000 10 {
+ [s total_forks] == [expr $total_forks + 1]
+ } else {
+ fail "aof rewrite did not scheduled"
+ }
+ waitForBgrewriteaof r
+
+ assert_equal 2 [count_log_message 0 "Removing the temp incr aof file"]
+
+ # BASE and INCR AOF are successfully created
+ assert_aof_manifest_content $aof_manifest_file {
+ {file appendonly.aof.1.base.rdb seq 1 type b}
+ {file appendonly.aof.1.incr.aof seq 1 type i}
+ }
+
+ stop_write_load $load_handle0
+ wait_load_handlers_disconnected
+
+ set d1 [r debug digest]
+ r debug loadaof
+ set d2 [r debug digest]
+ assert {$d1 eq $d2}
+
+ # Dynamic disable AOF again
+ r config set appendonly no
+
+ # Disabling AOF does not delete previous AOF files
+ r debug loadaof
+ set d2 [r debug digest]
+ assert {$d1 eq $d2}
+
+ assert_equal 0 [s rdb_changes_since_last_save]
+ r config set rdb-key-save-delay 10000000
+ set load_handle0 [start_write_load $master_host $master_port 10]
+ wait_for_condition 50 100 {
+ [s rdb_changes_since_last_save] > 0
+ } else {
+ fail "No write load detected."
+ }
+
+ # Re-enable AOF
+ r config set appendonly yes
+
+ # Let AOFRW fail
+ assert_equal 1 [s aof_rewrite_in_progress]
+ set pid1 [get_child_pid 0]
+ catch {exec kill -9 $pid1}
+
+ # Wait for AOFRW to exit and delete temp incr aof
+ wait_for_condition 1000 100 {
+ [count_log_message 0 "Removing the temp incr aof file"] == 3
+ } else {
+ fail "temp aof did not delete 3 times"
+ }
+
+ # Make sure no new incr AOF was created
+ assert_aof_manifest_content $aof_manifest_file {
+ {file appendonly.aof.1.base.rdb seq 1 type b}
+ {file appendonly.aof.1.incr.aof seq 1 type i}
+ }
+
+ # Make sure the next AOFRW has started
+ wait_for_condition 1000 50 {
+ [s aof_rewrite_in_progress] == 1
+ } else {
+ fail "aof rewrite did not scheduled"
+ }
+
+ # Do a successful AOFRW
+ set total_forks [s total_forks]
+ r config set rdb-key-save-delay 0
+ catch {exec kill -9 [get_child_pid 0]}
+
+ wait_for_condition 1000 10 {
+ [s total_forks] == [expr $total_forks + 1]
+ } else {
+ fail "aof rewrite did not scheduled"
+ }
+ waitForBgrewriteaof r
+
+ assert_equal 4 [count_log_message 0 "Removing the temp incr aof file"]
+
+ # New BASE and INCR AOF are successfully created
+ assert_aof_manifest_content $aof_manifest_file {
+ {file appendonly.aof.2.base.rdb seq 2 type b}
+ {file appendonly.aof.2.incr.aof seq 2 type i}
+ }
+
+ stop_write_load $load_handle0
+ wait_load_handlers_disconnected
+
+ set d1 [r debug digest]
+ r debug loadaof
+ set d2 [r debug digest]
+ assert {$d1 eq $d2}
+ }
+ }
}
}
diff --git a/tests/integration/corrupt-dump.tcl b/tests/integration/corrupt-dump.tcl
index d2491306a..1e54f26a1 100644
--- a/tests/integration/corrupt-dump.tcl
+++ b/tests/integration/corrupt-dump.tcl
@@ -632,7 +632,6 @@ test {corrupt payload: fuzzer findings - stream PEL without consumer} {
r debug set-skip-checksum-validation 1
catch {r restore _stream 0 "\x0F\x01\x10\x00\x00\x01\x7B\x08\xF0\xB2\x34\x00\x00\x00\x00\x00\x00\x00\x00\xC3\x3B\x40\x42\x19\x42\x00\x00\x00\x18\x00\x02\x01\x01\x01\x02\x01\x84\x69\x74\x65\x6D\x05\x85\x76\x61\x6C\x75\x65\x06\x00\x20\x10\x00\x00\x20\x01\x00\x01\x20\x03\x02\x05\x01\x03\x20\x05\x40\x00\x04\x82\x5F\x31\x03\x05\x60\x19\x80\x32\x02\x05\x01\xFF\x02\x81\x00\x00\x01\x7B\x08\xF0\xB2\x34\x02\x01\x07\x6D\x79\x67\x72\x6F\x75\x70\x81\x00\x00\x01\x7B\x08\xF0\xB2\x34\x01\x01\x00\x00\x01\x7B\x08\xF0\xB2\x34\x00\x00\x00\x00\x00\x00\x00\x01\x35\xB2\xF0\x08\x7B\x01\x00\x00\x01\x01\x13\x41\x6C\x69\x63\x65\x35\xB2\xF0\x08\x7B\x01\x00\x00\x01\x00\x00\x01\x7B\x08\xF0\xB2\x34\x00\x00\x00\x00\x00\x00\x00\x01\x09\x00\x28\x2F\xE0\xC5\x04\xBB\xA7\x31"} err
assert_match "*Bad data format*" $err
- #catch {r XINFO STREAM _stream FULL }
r ping
}
}
@@ -674,7 +673,6 @@ test {corrupt payload: fuzzer findings - stream with non-integer entry id} {
r config set sanitize-dump-payload yes
r debug set-skip-checksum-validation 1
catch {r restore _streambig 0 "\x0F\x03\x10\x00\x00\x01\x7B\x13\x34\xC3\xB2\x00\x00\x00\x00\x00\x00\x00\x00\xC3\x40\x4F\x40\x5C\x18\x5C\x00\x00\x00\x24\x00\x05\x01\x00\x01\x02\x01\x84\x69\x74\x65\x6D\x05\x85\x76\x61\x6C\x75\x65\x06\x40\x10\x00\x80\x20\x01\x00\x01\x20\x03\x00\x05\x20\x1C\x40\x09\x05\x01\x01\x82\x5F\x31\x03\x80\x0D\x00\x02\x20\x0D\x00\x02\xA0\x19\x00\x03\x20\x0B\x02\x82\x5F\x33\xA0\x19\x00\x04\x20\x0D\x00\x04\x20\x19\x00\xFF\x10\x00\x00\x01\x7B\x13\x34\xC3\xB2\x00\x00\x00\x00\x00\x00\x00\x05\xC3\x40\x56\x40\x61\x18\x61\x00\x00\x00\x24\x00\x05\x01\x00\x01\x02\x01\x84\x69\x74\x65\x6D\x05\x85\x76\x61\x6C\x75\x65\x06\x40\x10\x00\x00\x20\x01\x06\x01\x01\x82\x5F\x35\x03\x05\x20\x1E\x40\x0B\x03\x01\x01\x06\x01\x40\x0B\x03\x01\x01\xDF\xFB\x20\x05\x02\x82\x5F\x37\x60\x1A\x20\x0E\x00\xFC\x20\x05\x00\x08\xC0\x1B\x00\xFD\x20\x0C\x02\x82\x5F\x39\x20\x1B\x00\xFF\x10\x00\x00\x01\x7B\x13\x34\xC3\xB3\x00\x00\x00\x00\x00\x00\x00\x03\xC3\x3D\x40\x4A\x18\x4A\x00\x00\x00\x15\x00\x02\x01\x00\x01\x02\x01\x84\x69\x74\x65\x6D\x05\x85\x76\x61\x6C\x75\x65\x06\x40\x10\x00\x00\x20\x01\x40\x00\x00\x05\x60\x07\x02\xDF\xFD\x02\xC0\x23\x09\x01\x01\x86\x75\x6E\x69\x71\x75\x65\x07\xA0\x2D\x02\x08\x01\xFF\x0C\x81\x00\x00\x01\x7B\x13\x34\xC3\xB4\x00\x00\x09\x00\x9D\xBD\xD5\xB9\x33\xC4\xC5\xFF"} err
- #catch {r XINFO STREAM _streambig FULL }
assert_match "*Bad data format*" $err
r ping
}
@@ -782,5 +780,15 @@ test {corrupt payload: fuzzer findings - zset zslInsert with a NAN score} {
}
}
+test {corrupt payload: fuzzer findings - streamLastValidID panic} {
+ start_server [list overrides [list loglevel verbose use-exit-on-panic yes crash-memcheck-enabled no] ] {
+ r config set sanitize-dump-payload yes
+ r debug set-skip-checksum-validation 1
+ catch {r restore _streambig 0 "\x13\xC0\x10\x00\x00\x01\x80\x20\x48\xA0\x33\x00\x00\x00\x00\x00\x00\x00\x00\xC3\x40\x4F\x40\x5C\x18\x5C\x00\x00\x00\x24\x00\x05\x01\x00\x01\x02\x01\x84\x69\x74\x65\x6D\x05\x85\x76\x61\x6C\x75\x65\x06\x40\x10\x00\x00\x20\x01\x00\x01\x20\x03\x00\x05\x20\x1C\x40\x09\x05\x01\x01\x82\x5F\x31\x03\x80\x0D\x00\x02\x20\x0D\x00\x02\xA0\x19\x00\x03\x20\x0B\x02\x82\x5F\x33\x60\x19\x40\x2F\x02\x01\x01\x04\x20\x19\x00\xFF\x10\x00\x00\x01\x80\x20\x48\xA0\x34\x00\x00\x00\x00\x00\x00\x00\x01\xC3\x40\x51\x40\x5E\x18\x5E\x00\x00\x00\x24\x00\x05\x01\x00\x01\x02\x01\x84\x69\x74\x65\x6D\x05\x85\x76\x61\x6C\x75\x65\x06\x40\x10\x00\x00\x20\x01\x06\x01\x01\x82\x5F\x35\x03\x05\x20\x1E\x40\x0B\x03\x01\x01\x06\x01\x80\x0B\x00\x02\x20\x0B\x02\x82\x5F\x37\xA0\x19\x00\x03\x20\x0D\x00\x08\xA0\x19\x00\x04\x20\x0B\x02\x82\x5F\x39\x20\x19\x00\xFF\x10\x00\x00\x01\x80\x20\x48\xA0\x34\x00\x00\x00\x00\x00\x00\x00\x06\xC3\x3D\x40\x4A\x18\x4A\x00\x00\x00\x15\x00\x02\x01\x00\x01\x02\x01\x84\x69\x74\x65\x6D\x05\x85\x76\x61\x6C\x75\x65\x06\x40\x10\x00\x00\x20\x01\x40\x00\x00\x05\x60\x07\x02\xDF\xFA\x02\xC0\x23\x09\x01\x01\x86\x75\x6E\x69\x71\x75\x65\x07\xA0\x2D\x02\x08\x01\xFF\x0C\x81\x00\x00\x01\x80\x20\x48\xA0\x35\x00\x81\x00\x00\x01\x80\x20\x48\xA0\x33\x00\x00\x00\x0C\x00\x0A\x00\x34\x8B\x0E\x5B\x42\xCD\xD6\x08"} err
+ assert_match "*Bad data format*" $err
+ r ping
+ }
+}
+
} ;# tags
diff --git a/tests/integration/replication-4.tcl b/tests/integration/replication-4.tcl
index 281d5a8eb..9f4281f7c 100644
--- a/tests/integration/replication-4.tcl
+++ b/tests/integration/replication-4.tcl
@@ -195,3 +195,48 @@ start_server {tags {"repl external:skip"}} {
}
}
}
+
+start_server {tags {"repl external:skip"}} {
+ start_server {} {
+ set master [srv -1 client]
+ set master_host [srv -1 host]
+ set master_port [srv -1 port]
+ set replica [srv 0 client]
+
+ test {First server should have role slave after SLAVEOF} {
+ $replica slaveof $master_host $master_port
+ wait_for_condition 50 100 {
+ [s 0 role] eq {slave}
+ } else {
+ fail "Replication not started."
+ }
+ wait_for_sync $replica
+ }
+
+ test {Data divergence can happen under default conditions} {
+ $replica config set propagation-error-behavior ignore
+ $master debug replicate fake-command-1
+
+ # Wait for replication to normalize
+ $master set foo bar2
+ $master wait 1 2000
+
+ # Make sure we triggered the error, by finding the critical
+ # message and the fake command.
+ assert_equal [count_log_message 0 "fake-command-1"] 1
+ assert_equal [count_log_message 0 "== CRITICAL =="] 1
+ }
+
+ test {Data divergence is allowed on writable replicas} {
+ $replica config set replica-read-only no
+ $replica set number2 foo
+ $master incrby number2 1
+ $master wait 1 2000
+
+ assert_equal [$master get number2] 1
+ assert_equal [$replica get number2] foo
+
+ assert_equal [count_log_message 0 "incrby"] 1
+ }
+ }
+}
diff --git a/tests/modules/Makefile b/tests/modules/Makefile
index 1b7159c89..ac4c3e27b 100644
--- a/tests/modules/Makefile
+++ b/tests/modules/Makefile
@@ -49,6 +49,7 @@ TEST_MODULES = \
hash.so \
zset.so \
stream.so \
+ mallocsize.so \
aclcheck.so \
list.so \
subcommands.so \
@@ -56,7 +57,8 @@ TEST_MODULES = \
cmdintrospection.so \
eventloop.so \
moduleconfigs.so \
- moduleconfigstwo.so
+ moduleconfigstwo.so \
+ publish.so
.PHONY: all
@@ -69,7 +71,7 @@ all: $(TEST_MODULES)
$(CC) -I../../src $(CFLAGS) $(SHOBJ_CFLAGS) -fPIC -c $< -o $@
%.so: %.xo
- $(LD) -o $@ $< $(SHOBJ_LDFLAGS) $(LDFLAGS) $(LIBS)
+ $(LD) -o $@ $^ $(SHOBJ_LDFLAGS) $(LDFLAGS) $(LIBS)
.PHONY: clean
diff --git a/tests/modules/aclcheck.c b/tests/modules/aclcheck.c
index 8a9d468a6..9f4564d27 100644
--- a/tests/modules/aclcheck.c
+++ b/tests/modules/aclcheck.c
@@ -92,7 +92,7 @@ int rm_call_aclcheck_cmd(RedisModuleCtx *ctx, RedisModuleUser *user, RedisModule
if (ret != 0) {
RedisModule_ReplyWithError(ctx, "DENIED CMD");
/* Add entry to ACL log */
- RedisModule_ACLAddLogEntry(ctx, user, argv[1]);
+ RedisModule_ACLAddLogEntry(ctx, user, argv[1], REDISMODULE_ACL_LOG_CMD);
return REDISMODULE_OK;
}
diff --git a/tests/modules/basics.c b/tests/modules/basics.c
index ecd1b8852..9dbb5a9d4 100644
--- a/tests/modules/basics.c
+++ b/tests/modules/basics.c
@@ -866,10 +866,10 @@ int TestBasics(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
if (!TestAssertStringReply(ctx,RedisModule_CallReplyArrayElement(reply, 1),"1234",4)) goto fail;
T("foo", "E");
- if (!TestAssertErrorReply(ctx,reply,"ERR Unknown Redis command 'foo'.",32)) goto fail;
+ if (!TestAssertErrorReply(ctx,reply,"ERR unknown command 'foo', with args beginning with: ",53)) goto fail;
T("set", "Ec", "x");
- if (!TestAssertErrorReply(ctx,reply,"ERR Wrong number of args calling Redis command 'set'.",53)) goto fail;
+ if (!TestAssertErrorReply(ctx,reply,"ERR wrong number of arguments for 'set' command",47)) goto fail;
T("shutdown", "SE");
if (!TestAssertErrorReply(ctx,reply,"ERR command 'shutdown' is not allowed on script mode",52)) goto fail;
diff --git a/tests/modules/keyspace_events.c b/tests/modules/keyspace_events.c
index 152a2c48c..58670164d 100644
--- a/tests/modules/keyspace_events.c
+++ b/tests/modules/keyspace_events.c
@@ -79,6 +79,17 @@ static int KeySpace_NotificationGeneric(RedisModuleCtx *ctx, int type, const cha
return REDISMODULE_OK;
}
+static int KeySpace_NotificationExpired(RedisModuleCtx *ctx, int type, const char *event, RedisModuleString *key) {
+ REDISMODULE_NOT_USED(type);
+ REDISMODULE_NOT_USED(event);
+ REDISMODULE_NOT_USED(key);
+
+ RedisModuleCallReply* rep = RedisModule_Call(ctx, "INCR", "c!", "testkeyspace:expired");
+ RedisModule_FreeCallReply(rep);
+
+ return REDISMODULE_OK;
+}
+
static int KeySpace_NotificationModule(RedisModuleCtx *ctx, int type, const char *event, RedisModuleString *key) {
REDISMODULE_NOT_USED(ctx);
REDISMODULE_NOT_USED(type);
@@ -233,6 +244,10 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
return REDISMODULE_ERR;
}
+ if(RedisModule_SubscribeToKeyspaceEvents(ctx, REDISMODULE_NOTIFY_EXPIRED, KeySpace_NotificationExpired) != REDISMODULE_OK){
+ return REDISMODULE_ERR;
+ }
+
if(RedisModule_SubscribeToKeyspaceEvents(ctx, REDISMODULE_NOTIFY_MODULE, KeySpace_NotificationModule) != REDISMODULE_OK){
return REDISMODULE_ERR;
}
diff --git a/tests/modules/mallocsize.c b/tests/modules/mallocsize.c
new file mode 100644
index 000000000..a1d31c136
--- /dev/null
+++ b/tests/modules/mallocsize.c
@@ -0,0 +1,237 @@
+#include "redismodule.h"
+#include <string.h>
+#include <assert.h>
+#include <unistd.h>
+
+#define UNUSED(V) ((void) V)
+
+/* Registered type */
+RedisModuleType *mallocsize_type = NULL;
+
+typedef enum {
+ UDT_RAW,
+ UDT_STRING,
+ UDT_DICT
+} udt_type_t;
+
+typedef struct {
+ void *ptr;
+ size_t len;
+} raw_t;
+
+typedef struct {
+ udt_type_t type;
+ union {
+ raw_t raw;
+ RedisModuleString *str;
+ RedisModuleDict *dict;
+ } data;
+} udt_t;
+
+void udt_free(void *value) {
+ udt_t *udt = value;
+ switch (udt->type) {
+ case (UDT_RAW): {
+ RedisModule_Free(udt->data.raw.ptr);
+ break;
+ }
+ case (UDT_STRING): {
+ RedisModule_FreeString(NULL, udt->data.str);
+ break;
+ }
+ case (UDT_DICT): {
+ RedisModuleString *dk, *dv;
+ RedisModuleDictIter *iter = RedisModule_DictIteratorStartC(udt->data.dict, "^", NULL, 0);
+ while((dk = RedisModule_DictNext(NULL, iter, (void **)&dv)) != NULL) {
+ RedisModule_FreeString(NULL, dk);
+ RedisModule_FreeString(NULL, dv);
+ }
+ RedisModule_DictIteratorStop(iter);
+ RedisModule_FreeDict(NULL, udt->data.dict);
+ break;
+ }
+ }
+ RedisModule_Free(udt);
+}
+
+void udt_rdb_save(RedisModuleIO *rdb, void *value) {
+ udt_t *udt = value;
+ RedisModule_SaveUnsigned(rdb, udt->type);
+ switch (udt->type) {
+ case (UDT_RAW): {
+ RedisModule_SaveStringBuffer(rdb, udt->data.raw.ptr, udt->data.raw.len);
+ break;
+ }
+ case (UDT_STRING): {
+ RedisModule_SaveString(rdb, udt->data.str);
+ break;
+ }
+ case (UDT_DICT): {
+ RedisModule_SaveUnsigned(rdb, RedisModule_DictSize(udt->data.dict));
+ RedisModuleString *dk, *dv;
+ RedisModuleDictIter *iter = RedisModule_DictIteratorStartC(udt->data.dict, "^", NULL, 0);
+ while((dk = RedisModule_DictNext(NULL, iter, (void **)&dv)) != NULL) {
+ RedisModule_SaveString(rdb, dk);
+ RedisModule_SaveString(rdb, dv);
+ RedisModule_FreeString(NULL, dk); /* Allocated by RedisModule_DictNext */
+ }
+ RedisModule_DictIteratorStop(iter);
+ break;
+ }
+ }
+}
+
+void *udt_rdb_load(RedisModuleIO *rdb, int encver) {
+ if (encver != 0)
+ return NULL;
+ udt_t *udt = RedisModule_Alloc(sizeof(*udt));
+ udt->type = RedisModule_LoadUnsigned(rdb);
+ switch (udt->type) {
+ case (UDT_RAW): {
+ udt->data.raw.ptr = RedisModule_LoadStringBuffer(rdb, &udt->data.raw.len);
+ break;
+ }
+ case (UDT_STRING): {
+ udt->data.str = RedisModule_LoadString(rdb);
+ break;
+ }
+ case (UDT_DICT): {
+ long long dict_len = RedisModule_LoadUnsigned(rdb);
+ udt->data.dict = RedisModule_CreateDict(NULL);
+ for (int i = 0; i < dict_len; i += 2) {
+ RedisModuleString *key = RedisModule_LoadString(rdb);
+ RedisModuleString *val = RedisModule_LoadString(rdb);
+ RedisModule_DictSet(udt->data.dict, key, val);
+ }
+ break;
+ }
+ }
+
+ return udt;
+}
+
+size_t udt_mem_usage(RedisModuleKeyOptCtx *ctx, const void *value, size_t sample_size) {
+ UNUSED(ctx);
+ UNUSED(sample_size);
+
+ const udt_t *udt = value;
+ size_t size = sizeof(*udt);
+
+ switch (udt->type) {
+ case (UDT_RAW): {
+ size += RedisModule_MallocSize(udt->data.raw.ptr);
+ break;
+ }
+ case (UDT_STRING): {
+ size += RedisModule_MallocSizeString(udt->data.str);
+ break;
+ }
+ case (UDT_DICT): {
+ void *dk;
+ size_t keylen;
+ RedisModuleString *dv;
+ RedisModuleDictIter *iter = RedisModule_DictIteratorStartC(udt->data.dict, "^", NULL, 0);
+ while((dk = RedisModule_DictNextC(iter, &keylen, (void **)&dv)) != NULL) {
+ size += keylen;
+ size += RedisModule_MallocSizeString(dv);
+ }
+ RedisModule_DictIteratorStop(iter);
+ break;
+ }
+ }
+
+ return size;
+}
+
+/* MALLOCSIZE.SETRAW key len */
+int cmd_setraw(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
+ if (argc != 3)
+ return RedisModule_WrongArity(ctx);
+
+ RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_WRITE);
+
+ udt_t *udt = RedisModule_Alloc(sizeof(*udt));
+ udt->type = UDT_RAW;
+
+ long long raw_len;
+ RedisModule_StringToLongLong(argv[2], &raw_len);
+ udt->data.raw.ptr = RedisModule_Alloc(raw_len);
+ udt->data.raw.len = raw_len;
+
+ RedisModule_ModuleTypeSetValue(key, mallocsize_type, udt);
+ RedisModule_CloseKey(key);
+
+ return RedisModule_ReplyWithSimpleString(ctx, "OK");
+}
+
+/* MALLOCSIZE.SETSTR key string */
+int cmd_setstr(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
+ if (argc != 3)
+ return RedisModule_WrongArity(ctx);
+
+ RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_WRITE);
+
+ udt_t *udt = RedisModule_Alloc(sizeof(*udt));
+ udt->type = UDT_STRING;
+
+ udt->data.str = argv[2];
+ RedisModule_RetainString(ctx, argv[2]);
+
+ RedisModule_ModuleTypeSetValue(key, mallocsize_type, udt);
+ RedisModule_CloseKey(key);
+
+ return RedisModule_ReplyWithSimpleString(ctx, "OK");
+}
+
+/* MALLOCSIZE.SETDICT key field value [field value ...] */
+int cmd_setdict(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
+ if (argc < 4 || argc % 2)
+ return RedisModule_WrongArity(ctx);
+
+ RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_WRITE);
+
+ udt_t *udt = RedisModule_Alloc(sizeof(*udt));
+ udt->type = UDT_DICT;
+
+ udt->data.dict = RedisModule_CreateDict(ctx);
+ for (int i = 2; i < argc; i += 2) {
+ RedisModule_DictSet(udt->data.dict, argv[i], argv[i+1]);
+ /* No need to retain argv[i], it is copied as the rax key */
+ RedisModule_RetainString(ctx, argv[i+1]);
+ }
+
+ RedisModule_ModuleTypeSetValue(key, mallocsize_type, udt);
+ RedisModule_CloseKey(key);
+
+ return RedisModule_ReplyWithSimpleString(ctx, "OK");
+}
+
+int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
+ UNUSED(argv);
+ UNUSED(argc);
+ if (RedisModule_Init(ctx,"mallocsize",1,REDISMODULE_APIVER_1)== REDISMODULE_ERR)
+ return REDISMODULE_ERR;
+
+ RedisModuleTypeMethods tm = {
+ .version = REDISMODULE_TYPE_METHOD_VERSION,
+ .rdb_load = udt_rdb_load,
+ .rdb_save = udt_rdb_save,
+ .free = udt_free,
+ .mem_usage2 = udt_mem_usage,
+ };
+
+ mallocsize_type = RedisModule_CreateDataType(ctx, "allocsize", 0, &tm);
+ if (mallocsize_type == NULL)
+ return REDISMODULE_ERR;
+
+ if (RedisModule_CreateCommand(ctx, "mallocsize.setraw", cmd_setraw, "", 1, 1, 1) == REDISMODULE_ERR)
+ return REDISMODULE_ERR;
+
+ if (RedisModule_CreateCommand(ctx, "mallocsize.setstr", cmd_setstr, "", 1, 1, 1) == REDISMODULE_ERR)
+ return REDISMODULE_ERR;
+
+ if (RedisModule_CreateCommand(ctx, "mallocsize.setdict", cmd_setdict, "", 1, 1, 1) == REDISMODULE_ERR)
+ return REDISMODULE_ERR;
+
+ return REDISMODULE_OK;
+}
diff --git a/tests/modules/moduleconfigs.c b/tests/modules/moduleconfigs.c
index a9e434a7b..0a6380461 100644
--- a/tests/modules/moduleconfigs.c
+++ b/tests/modules/moduleconfigs.c
@@ -6,6 +6,7 @@ long long longval;
long long memval;
RedisModuleString *strval = NULL;
int enumval;
+int flagsval;
/* Series of get and set callbacks for each type of config, these rely on the privdata ptr
* to point to the config, and they register the configs as such. Note that one could also just
@@ -68,6 +69,20 @@ int setEnumConfigCommand(const char *name, int val, void *privdata, RedisModuleS
return REDISMODULE_OK;
}
+int getFlagsConfigCommand(const char *name, void *privdata) {
+ REDISMODULE_NOT_USED(name);
+ REDISMODULE_NOT_USED(privdata);
+ return flagsval;
+}
+
+int setFlagsConfigCommand(const char *name, int val, void *privdata, RedisModuleString **err) {
+ REDISMODULE_NOT_USED(name);
+ REDISMODULE_NOT_USED(err);
+ REDISMODULE_NOT_USED(privdata);
+ flagsval = val;
+ return REDISMODULE_OK;
+}
+
int boolApplyFunc(RedisModuleCtx *ctx, void *privdata, RedisModuleString **err) {
REDISMODULE_NOT_USED(ctx);
REDISMODULE_NOT_USED(privdata);
@@ -106,10 +121,13 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
}
/* On the stack to make sure we're copying them. */
- const char *enum_vals[3] = {"one", "two", "three"};
- const int int_vals[3] = {0, 2, 4};
+ const char *enum_vals[] = {"none", "one", "two", "three"};
+ const int int_vals[] = {0, 1, 2, 4};
- if (RedisModule_RegisterEnumConfig(ctx, "enum", 0, REDISMODULE_CONFIG_DEFAULT, enum_vals, int_vals, 3, getEnumConfigCommand, setEnumConfigCommand, NULL, NULL) == REDISMODULE_ERR) {
+ if (RedisModule_RegisterEnumConfig(ctx, "enum", 1, REDISMODULE_CONFIG_DEFAULT, enum_vals, int_vals, 4, getEnumConfigCommand, setEnumConfigCommand, NULL, NULL) == REDISMODULE_ERR) {
+ return REDISMODULE_ERR;
+ }
+ if (RedisModule_RegisterEnumConfig(ctx, "flags", 3, REDISMODULE_CONFIG_DEFAULT | REDISMODULE_CONFIG_BITFLAGS, enum_vals, int_vals, 4, getFlagsConfigCommand, setFlagsConfigCommand, NULL, NULL) == REDISMODULE_ERR) {
return REDISMODULE_ERR;
}
/* Memory config here. */
@@ -139,4 +157,4 @@ int RedisModule_OnUnload(RedisModuleCtx *ctx) {
strval = NULL;
}
return REDISMODULE_OK;
-} \ No newline at end of file
+}
diff --git a/tests/modules/publish.c b/tests/modules/publish.c
new file mode 100644
index 000000000..eee96d689
--- /dev/null
+++ b/tests/modules/publish.c
@@ -0,0 +1,42 @@
+#include "redismodule.h"
+#include <string.h>
+#include <assert.h>
+#include <unistd.h>
+
+#define UNUSED(V) ((void) V)
+
+int cmd_publish_classic(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
+{
+ if (argc != 3)
+ return RedisModule_WrongArity(ctx);
+
+ int receivers = RedisModule_PublishMessage(ctx, argv[1], argv[2]);
+ RedisModule_ReplyWithLongLong(ctx, receivers);
+ return REDISMODULE_OK;
+}
+
+int cmd_publish_shard(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
+{
+ if (argc != 3)
+ return RedisModule_WrongArity(ctx);
+
+ int receivers = RedisModule_PublishMessageShard(ctx, argv[1], argv[2]);
+ RedisModule_ReplyWithLongLong(ctx, receivers);
+ return REDISMODULE_OK;
+}
+
+int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
+ UNUSED(argv);
+ UNUSED(argc);
+
+ if (RedisModule_Init(ctx,"publish",1,REDISMODULE_APIVER_1)== REDISMODULE_ERR)
+ return REDISMODULE_ERR;
+
+ if (RedisModule_CreateCommand(ctx,"publish.classic",cmd_publish_classic,"",0,0,0) == REDISMODULE_ERR)
+ return REDISMODULE_ERR;
+
+ if (RedisModule_CreateCommand(ctx,"publish.shard",cmd_publish_shard,"",0,0,0) == REDISMODULE_ERR)
+ return REDISMODULE_ERR;
+
+ return REDISMODULE_OK;
+}
diff --git a/tests/modules/subcommands.c b/tests/modules/subcommands.c
index 7cb337331..3486e86b4 100644
--- a/tests/modules/subcommands.c
+++ b/tests/modules/subcommands.c
@@ -11,7 +11,10 @@ int cmd_set(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
int cmd_get(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
UNUSED(argv);
- UNUSED(argc);
+
+ if (argc > 4) /* For testing */
+ return RedisModule_WrongArity(ctx);
+
RedisModule_ReplyWithSimpleString(ctx, "OK");
return REDISMODULE_OK;
}
diff --git a/tests/sentinel/tests/05-manual.tcl b/tests/sentinel/tests/05-manual.tcl
index 28c5560a6..a0004eb75 100644
--- a/tests/sentinel/tests/05-manual.tcl
+++ b/tests/sentinel/tests/05-manual.tcl
@@ -3,9 +3,9 @@
source "../tests/includes/init-tests.tcl"
foreach_sentinel_id id {
- S $id sentinel debug info-period 1000
- S $id sentinel debug default-down-after 3000
- S $id sentinel debug publish-period 500
+ S $id sentinel debug info-period 2000
+ S $id sentinel debug default-down-after 6000
+ S $id sentinel debug publish-period 1000
}
test "Manual failover works" {
diff --git a/tests/sentinel/tests/includes/init-tests.tcl b/tests/sentinel/tests/includes/init-tests.tcl
index fe9a61815..ddb131903 100644
--- a/tests/sentinel/tests/includes/init-tests.tcl
+++ b/tests/sentinel/tests/includes/init-tests.tcl
@@ -28,7 +28,8 @@ test "(init) Sentinels can start monitoring a master" {
foreach_sentinel_id id {
assert {[S $id sentinel master mymaster] ne {}}
S $id SENTINEL SET mymaster down-after-milliseconds 2000
- S $id SENTINEL SET mymaster failover-timeout 20000
+ S $id SENTINEL SET mymaster failover-timeout 10000
+ S $id SENTINEL debug tilt-period 5000
S $id SENTINEL SET mymaster parallel-syncs 10
if {$::leaked_fds_file != "" && [exec uname] == "Linux"} {
S $id SENTINEL SET mymaster notification-script ../../tests/helpers/check_leaked_fds.tcl
diff --git a/tests/support/util.tcl b/tests/support/util.tcl
index 4ad96ab10..6741b719a 100644
--- a/tests/support/util.tcl
+++ b/tests/support/util.tcl
@@ -77,6 +77,12 @@ proc getInfoProperty {infostr property} {
}
}
+proc cluster_info {r field} {
+ if {[regexp "^$field:(.*?)\r\n" [$r cluster info] _ value]} {
+ set _ $value
+ }
+}
+
# Return value for INFO property
proc status {r property} {
set _ [getInfoProperty [{*}$r info] $property]
@@ -823,11 +829,21 @@ proc subscribe {client channels} {
consume_subscribe_messages $client subscribe $channels
}
+proc ssubscribe {client channels} {
+ $client ssubscribe {*}$channels
+ consume_subscribe_messages $client ssubscribe $channels
+}
+
proc unsubscribe {client {channels {}}} {
$client unsubscribe {*}$channels
consume_subscribe_messages $client unsubscribe $channels
}
+proc sunsubscribe {client {channels {}}} {
+ $client sunsubscribe {*}$channels
+ consume_subscribe_messages $client sunsubscribe $channels
+}
+
proc psubscribe {client channels} {
$client psubscribe {*}$channels
consume_subscribe_messages $client psubscribe $channels
diff --git a/tests/test_helper.tcl b/tests/test_helper.tcl
index 277fa3803..134c5c46b 100644
--- a/tests/test_helper.tcl
+++ b/tests/test_helper.tcl
@@ -94,6 +94,7 @@ set ::all_tests {
unit/client-eviction
unit/violations
unit/replybufsize
+ unit/cluster-scripting
}
# Index to the next test to run in the ::all_tests list.
set ::next_test 0
@@ -274,6 +275,16 @@ proc s {args} {
status [srv $level "client"] [lindex $args 0]
}
+# Provide easy access to CLUSTER INFO properties. Same semantic as "proc s".
+proc csi {args} {
+ set level 0
+ if {[string is integer [lindex $args 0]]} {
+ set level [lindex $args 0]
+ set args [lrange $args 1 end]
+ }
+ cluster_info [srv $level "client"] [lindex $args 0]
+}
+
# Test wrapped into run_solo are sent back from the client to the
# test server, so that the test server will send them again to
# clients once the clients are idle.
diff --git a/tests/unit/acl-v2.tcl b/tests/unit/acl-v2.tcl
index 12eb5a3be..500a7c729 100644
--- a/tests/unit/acl-v2.tcl
+++ b/tests/unit/acl-v2.tcl
@@ -173,7 +173,7 @@ start_server {tags {"acl external:skip"}} {
assert_equal PONG [$r2 PING]
assert_equal {} [$r2 get readwrite_str]
- assert_error {ERR* not an integer *} {$r2 set readwrite_str bar ex get}
+ assert_error {ERR * not an integer *} {$r2 set readwrite_str bar ex get}
assert_equal {OK} [$r2 set readwrite_str bar]
assert_equal {bar} [$r2 get readwrite_str]
diff --git a/tests/unit/acl.tcl b/tests/unit/acl.tcl
index 0a9ffb250..c252de031 100644
--- a/tests/unit/acl.tcl
+++ b/tests/unit/acl.tcl
@@ -511,7 +511,7 @@ start_server {tags {"acl external:skip"}} {
test "ACL CAT with illegal arguments" {
assert_error {*Unknown category 'NON_EXISTS'} {r ACL CAT NON_EXISTS}
- assert_error {*Unknown subcommand or wrong number of arguments for 'CAT'*} {r ACL CAT NON_EXISTS NON_EXISTS2}
+ assert_error {*unknown subcommand or wrong number of arguments for 'CAT'*} {r ACL CAT NON_EXISTS NON_EXISTS2}
}
test "ACL CAT without category - list all categories" {
diff --git a/tests/unit/auth.tcl b/tests/unit/auth.tcl
index 4a4d7564c..26d125579 100644
--- a/tests/unit/auth.tcl
+++ b/tests/unit/auth.tcl
@@ -2,7 +2,7 @@ start_server {tags {"auth external:skip"}} {
test {AUTH fails if there is no password configured server side} {
catch {r auth foo} err
set _ $err
- } {ERR*any password*}
+ } {ERR *any password*}
test {Arity check for auth command} {
catch {r auth a b c} err
diff --git a/tests/unit/bitops.tcl b/tests/unit/bitops.tcl
index ec08a060d..1b7db407a 100644
--- a/tests/unit/bitops.tcl
+++ b/tests/unit/bitops.tcl
@@ -133,12 +133,12 @@ start_server {tags {"bitops"}} {
test {BITCOUNT syntax error #1} {
catch {r bitcount s 0} e
set e
- } {ERR*syntax*}
+ } {ERR *syntax*}
test {BITCOUNT syntax error #2} {
catch {r bitcount s 0 1 hello} e
set e
- } {ERR*syntax*}
+ } {ERR *syntax*}
test {BITCOUNT regression test for github issue #582} {
r del foo
@@ -546,7 +546,10 @@ start_server {tags {"bitops"}} {
}
}
}
+}
+run_solo {bitops-large-memory} {
+start_server {tags {"bitops"}} {
test "BIT pos larger than UINT_MAX" {
set bytes [expr (1 << 29) + 1]
set bitpos [expr (1 << 32)]
@@ -587,3 +590,4 @@ start_server {tags {"bitops"}} {
r del mykey
} {1} {large-memory needs:debug}
}
+} ;#run_solo
diff --git a/tests/unit/cluster-scripting.tcl b/tests/unit/cluster-scripting.tcl
new file mode 100644
index 000000000..72fc028c3
--- /dev/null
+++ b/tests/unit/cluster-scripting.tcl
@@ -0,0 +1,64 @@
+# make sure the test infra won't use SELECT
+set old_singledb $::singledb
+set ::singledb 1
+
+start_server {overrides {cluster-enabled yes} tags {external:skip cluster}} {
+ r 0 cluster addslotsrange 0 16383
+ wait_for_condition 50 100 {
+ [csi 0 cluster_state] eq "ok"
+ } else {
+ fail "Cluster never became 'ok'"
+ }
+
+ test {Eval scripts with shebangs and functions default to no cross slots} {
+ # Test that scripts with shebang block cross slot operations
+ assert_error "ERR Script attempted to access keys that do not hash to the same slot*" {
+ r 0 eval {#!lua
+ redis.call('set', 'foo', 'bar')
+ redis.call('set', 'bar', 'foo')
+ return 'OK'
+ } 0}
+
+ # Test the functions by default block cross slot operations
+ r 0 function load REPLACE {#!lua name=crossslot
+ local function test_cross_slot(keys, args)
+ redis.call('set', 'foo', 'bar')
+ redis.call('set', 'bar', 'foo')
+ return 'OK'
+ end
+
+ redis.register_function('test_cross_slot', test_cross_slot)}
+ assert_error "ERR Script attempted to access keys that do not hash to the same slot*" {r FCALL test_cross_slot 0}
+ }
+
+ test {Cross slot commands are allowed by default for eval scripts and with allow-cross-slot-keys flag} {
+ # Old style lua scripts are allowed to access cross slot operations
+ r 0 eval "redis.call('set', 'foo', 'bar'); redis.call('set', 'bar', 'foo')" 0
+
+ # scripts with allow-cross-slot-keys flag are allowed
+ r 0 eval {#!lua flags=allow-cross-slot-keys
+ redis.call('set', 'foo', 'bar'); redis.call('set', 'bar', 'foo')
+ } 0
+
+ # Functions with allow-cross-slot-keys flag are allowed
+ r 0 function load REPLACE {#!lua name=crossslot
+ local function test_cross_slot(keys, args)
+ redis.call('set', 'foo', 'bar')
+ redis.call('set', 'bar', 'foo')
+ return 'OK'
+ end
+
+ redis.register_function{function_name='test_cross_slot', callback=test_cross_slot, flags={ 'allow-cross-slot-keys' }}}
+ r FCALL test_cross_slot 0
+ }
+
+ test {Cross slot commands are also blocked if they disagree with pre-declared keys} {
+ assert_error "ERR Script attempted to access keys that do not hash to the same slot*" {
+ r 0 eval {#!lua
+ redis.call('set', 'foo', 'bar')
+ return 'OK'
+ } 1 bar}
+ }
+}
+
+set ::singledb $old_singledb
diff --git a/tests/unit/functions.tcl b/tests/unit/functions.tcl
index 4c08261ed..62c070f90 100644
--- a/tests/unit/functions.tcl
+++ b/tests/unit/functions.tcl
@@ -117,7 +117,7 @@ start_server {tags {"scripting"}} {
r function bad_subcommand
} e
set _ $e
- } {*Unknown subcommand*}
+ } {*unknown subcommand*}
test {FUNCTION - test loading from rdb} {
r debug reload
@@ -205,7 +205,7 @@ start_server {tags {"scripting"}} {
test {FUNCTION - test function restore with wrong number of arguments} {
catch {r function restore arg1 args2 arg3} e
set _ $e
- } {*Unknown subcommand or wrong number of arguments for 'restore'. Try FUNCTION HELP.}
+ } {*unknown subcommand or wrong number of arguments for 'restore'. Try FUNCTION HELP.}
test {FUNCTION - test fcall_ro with write command} {
r function load REPLACE [get_no_writes_function_code lua test test {return redis.call('set', 'x', '1')}]
@@ -298,7 +298,7 @@ start_server {tags {"scripting"}} {
assert_match {*only supports SYNC|ASYNC*} $e
catch {r function flush sync extra_arg} e
- assert_match {*Unknown subcommand or wrong number of arguments for 'flush'. Try FUNCTION HELP.} $e
+ assert_match {*unknown subcommand or wrong number of arguments for 'flush'. Try FUNCTION HELP.} $e
}
}
@@ -624,16 +624,16 @@ start_server {tags {"scripting"}} {
}
} e
set _ $e
- } {*attempt to call field 'call' (a nil value)*}
+ } {*attempted to access nonexistent global variable 'call'*}
- test {LIBRARIES - redis.call from function load} {
+ test {LIBRARIES - redis.setresp from function load} {
catch {
r function load replace {#!lua name=lib2
return redis.setresp(3)
}
} e
set _ $e
- } {*attempt to call field 'setresp' (a nil value)*}
+ } {*attempted to access nonexistent global variable 'setresp'*}
test {LIBRARIES - redis.set_repl from function load} {
catch {
@@ -642,7 +642,7 @@ start_server {tags {"scripting"}} {
}
} e
set _ $e
- } {*attempt to call field 'set_repl' (a nil value)*}
+ } {*attempted to access nonexistent global variable 'set_repl'*}
test {LIBRARIES - malicious access test} {
# the 'library' API is not exposed inside a
@@ -669,37 +669,18 @@ start_server {tags {"scripting"}} {
end)
end)
}
- assert_equal {OK} [r fcall f1 0]
+ catch {[r fcall f1 0]} e
+ assert_match {*Attempt to modify a readonly table*} $e
catch {[r function load {#!lua name=lib2
redis.math.random()
}]} e
- assert_match {*can only be called inside a script invocation*} $e
-
- catch {[r function load {#!lua name=lib2
- redis.math.randomseed()
- }]} e
- assert_match {*can only be called inside a script invocation*} $e
+ assert_match {*Script attempted to access nonexistent global variable 'math'*} $e
catch {[r function load {#!lua name=lib2
redis.redis.call('ping')
}]} e
- assert_match {*can only be called inside a script invocation*} $e
-
- catch {[r function load {#!lua name=lib2
- redis.redis.pcall('ping')
- }]} e
- assert_match {*can only be called inside a script invocation*} $e
-
- catch {[r function load {#!lua name=lib2
- redis.redis.setresp(3)
- }]} e
- assert_match {*can only be called inside a script invocation*} $e
-
- catch {[r function load {#!lua name=lib2
- redis.redis.set_repl(redis.redis.REPL_NONE)
- }]} e
- assert_match {*can only be called inside a script invocation*} $e
+ assert_match {*Script attempted to access nonexistent global variable 'redis'*} $e
catch {[r fcall f2 0]} e
assert_match {*can only be called on FUNCTION LOAD command*} $e
@@ -756,7 +737,7 @@ start_server {tags {"scripting"}} {
}
} e
set _ $e
- } {*attempted to create global variable 'a'*}
+ } {*Attempt to modify a readonly table*}
test {LIBRARIES - named arguments} {
r function load {#!lua name=lib
@@ -986,7 +967,7 @@ start_server {tags {"scripting"}} {
assert_match {*command not allowed when used memory*} $e
r config set maxmemory 0
- }
+ } {OK} {needs:config-maxmemory}
test {FUNCTION - verify allow-omm allows running any command} {
r FUNCTION load replace {#!lua name=f1
@@ -999,11 +980,11 @@ start_server {tags {"scripting"}} {
r config set maxmemory 1
- assert_match {OK} [r fcall f1 1 k]
+ assert_match {OK} [r fcall f1 1 x]
assert_match {1} [r get x]
r config set maxmemory 0
- }
+ } {OK} {needs:config-maxmemory}
}
start_server {tags {"scripting"}} {
@@ -1074,7 +1055,7 @@ start_server {tags {"scripting"}} {
assert_match {*can not run it when used memory > 'maxmemory'*} $e
r config set maxmemory 0
- }
+ } {OK} {needs:config-maxmemory}
test {FUNCTION - deny oom on no-writes function} {
r FUNCTION load replace {#!lua name=test
@@ -1090,7 +1071,7 @@ start_server {tags {"scripting"}} {
assert_match {*can not run it when used memory > 'maxmemory'*} $e
r config set maxmemory 0
- }
+ } {OK} {needs:config-maxmemory}
test {FUNCTION - allow stale} {
r FUNCTION load replace {#!lua name=test
@@ -1198,4 +1179,32 @@ start_server {tags {"scripting"}} {
redis.register_function('foo', function() return 1 end)
}
} {foo}
+
+ test {FUNCTION - trick global protection 1} {
+ r FUNCTION FLUSH
+
+ r FUNCTION load {#!lua name=test1
+ redis.register_function('f1', function()
+ mt = getmetatable(_G)
+ original_globals = mt.__index
+ original_globals['redis'] = function() return 1 end
+ end)
+ }
+
+ catch {[r fcall f1 0]} e
+ set _ $e
+ } {*Attempt to modify a readonly table*}
+
+ test {FUNCTION - test getmetatable on script load} {
+ r FUNCTION FLUSH
+
+ catch {
+ r FUNCTION load {#!lua name=test1
+ mt = getmetatable(_G)
+ }
+ } e
+
+ set _ $e
+ } {*Script attempted to access nonexistent global variable 'getmetatable'*}
+
}
diff --git a/tests/unit/geo.tcl b/tests/unit/geo.tcl
index e6afb211b..1c7564430 100644
--- a/tests/unit/geo.tcl
+++ b/tests/unit/geo.tcl
@@ -193,14 +193,14 @@ start_server {tags {"geo"}} {
r geoadd nyc xx nx -73.9454966 40.747533 "lic market"
} err
set err
- } {ERR*syntax*}
+ } {ERR *syntax*}
test {GEOADD update with invalid option} {
catch {
r geoadd nyc ch xx foo -73.9454966 40.747533 "lic market"
} err
set err
- } {ERR*syntax*}
+ } {ERR *syntax*}
test {GEOADD invalid coordinates} {
catch {
@@ -229,27 +229,27 @@ start_server {tags {"geo"}} {
test {GEOSEARCH FROMLONLAT and FROMMEMBER cannot exist at the same time} {
catch {r geosearch nyc fromlonlat -73.9798091 40.7598464 frommember xxx bybox 6 6 km asc} e
set e
- } {ERR*syntax*}
+ } {ERR *syntax*}
test {GEOSEARCH FROMLONLAT and FROMMEMBER one must exist} {
catch {r geosearch nyc bybox 3 3 km asc desc withhash withdist withcoord} e
set e
- } {ERR*exactly one of FROMMEMBER or FROMLONLAT*}
+ } {ERR *exactly one of FROMMEMBER or FROMLONLAT*}
test {GEOSEARCH BYRADIUS and BYBOX cannot exist at the same time} {
catch {r geosearch nyc fromlonlat -73.9798091 40.7598464 byradius 3 km bybox 3 3 km asc} e
set e
- } {ERR*syntax*}
+ } {ERR *syntax*}
test {GEOSEARCH BYRADIUS and BYBOX one must exist} {
catch {r geosearch nyc fromlonlat -73.9798091 40.7598464 asc desc withhash withdist withcoord} e
set e
- } {ERR*exactly one of BYRADIUS and BYBOX*}
+ } {ERR *exactly one of BYRADIUS and BYBOX*}
test {GEOSEARCH with STOREDIST option} {
catch {r geosearch nyc fromlonlat -73.9798091 40.7598464 bybox 6 6 km asc storedist} e
set e
- } {ERR*syntax*}
+ } {ERR *syntax*}
test {GEORADIUS withdist (sorted)} {
r georadius nyc -73.9798091 40.7598464 3 km withdist asc
@@ -274,12 +274,12 @@ start_server {tags {"geo"}} {
test {GEORADIUS with ANY but no COUNT} {
catch {r georadius nyc -73.9798091 40.7598464 10 km ANY ASC} e
set e
- } {ERR*ANY*requires*COUNT*}
+ } {ERR *ANY*requires*COUNT*}
test {GEORADIUS with COUNT but missing integer argument} {
catch {r georadius nyc -73.9798091 40.7598464 10 km COUNT} e
set e
- } {ERR*syntax*}
+ } {ERR *syntax*}
test {GEORADIUS with COUNT DESC} {
r georadius nyc -73.9798091 40.7598464 10 km COUNT 2 DESC
diff --git a/tests/unit/introspection.tcl b/tests/unit/introspection.tcl
index c530a31d3..4b4b8f56b 100644
--- a/tests/unit/introspection.tcl
+++ b/tests/unit/introspection.tcl
@@ -23,9 +23,9 @@ start_server {tags {"introspection"}} {
assert_error "ERR wrong number of arguments for 'client|kill' command" {r client kill}
assert_error "ERR syntax error*" {r client kill id 10 wrong_arg}
- assert_error "ERR*greater than 0*" {r client kill id str}
- assert_error "ERR*greater than 0*" {r client kill id -1}
- assert_error "ERR*greater than 0*" {r client kill id 0}
+ assert_error "ERR *greater than 0*" {r client kill id str}
+ assert_error "ERR *greater than 0*" {r client kill id -1}
+ assert_error "ERR *greater than 0*" {r client kill id 0}
assert_error "ERR Unknown client type*" {r client kill type wrong_type}
@@ -215,6 +215,7 @@ start_server {tags {"introspection"}} {
dbfilename
logfile
dir
+ socket-mark-id
}
if {!$::tls} {
@@ -285,16 +286,22 @@ start_server {tags {"introspection"}} {
}
} {} {external:skip}
- test {CONFIG REWRITE handles save properly} {
+ test {CONFIG REWRITE handles save and shutdown properly} {
r config set save "3600 1 300 100 60 10000"
+ r config set shutdown-on-sigterm "nosave now"
+ r config set shutdown-on-sigint "save"
r config rewrite
restart_server 0 true false
assert_equal [r config get save] {save {3600 1 300 100 60 10000}}
+ assert_equal [r config get shutdown-on-sigterm] {shutdown-on-sigterm {nosave now}}
+ assert_equal [r config get shutdown-on-sigint] {shutdown-on-sigint save}
r config set save ""
+ r config set shutdown-on-sigterm "default"
r config rewrite
restart_server 0 true false
assert_equal [r config get save] {save {}}
+ assert_equal [r config get shutdown-on-sigterm] {shutdown-on-sigterm default}
start_server {config "minimal.conf"} {
assert_equal [r config get save] {save {3600 1 300 100 60 10000}}
@@ -409,11 +416,11 @@ start_server {tags {"introspection"}} {
}
test {CONFIG SET duplicate configs} {
- assert_error "ERR*duplicate*" {r config set maxmemory 10000001 maxmemory 10000002}
+ assert_error "ERR *duplicate*" {r config set maxmemory 10000001 maxmemory 10000002}
}
test {CONFIG SET set immutable} {
- assert_error "ERR*immutable*" {r config set daemonize yes}
+ assert_error "ERR *immutable*" {r config set daemonize yes}
}
test {CONFIG GET hidden configs} {
@@ -448,8 +455,8 @@ start_server {tags {"introspection"}} {
start_server {tags {"introspection external:skip"} overrides {enable-protected-configs {no} enable-debug-command {no}}} {
test {cannot modify protected configuration - no} {
- assert_error "ERR*protected*" {r config set dir somedir}
- assert_error "ERR*DEBUG command not allowed*" {r DEBUG HELP}
+ assert_error "ERR *protected*" {r config set dir somedir}
+ assert_error "ERR *DEBUG command not allowed*" {r DEBUG HELP}
} {} {needs:debug}
}
@@ -464,8 +471,8 @@ start_server {config "minimal.conf" tags {"introspection external:skip"} overrid
if {$myaddr != "" && ![string match {127.*} $myaddr]} {
# Non-loopback client should fail
set r2 [get_nonloopback_client]
- assert_error "ERR*protected*" {$r2 config set dir somedir}
- assert_error "ERR*DEBUG command not allowed*" {$r2 DEBUG HELP}
+ assert_error "ERR *protected*" {$r2 config set dir somedir}
+ assert_error "ERR *DEBUG command not allowed*" {$r2 DEBUG HELP}
}
} {} {needs:debug}
}
diff --git a/tests/unit/moduleapi/aclcheck.tcl b/tests/unit/moduleapi/aclcheck.tcl
index 5adf65371..d96ea89cf 100644
--- a/tests/unit/moduleapi/aclcheck.tcl
+++ b/tests/unit/moduleapi/aclcheck.tcl
@@ -16,6 +16,7 @@ start_server {tags {"modules acl"}} {
assert {[dict get $entry username] eq {default}}
assert {[dict get $entry context] eq {module}}
assert {[dict get $entry object] eq {set}}
+ assert {[dict get $entry reason] eq {command}}
}
test {test module check acl for key perm} {
@@ -75,6 +76,7 @@ start_server {tags {"modules acl"}} {
assert {[dict get $entry username] eq {default}}
assert {[dict get $entry context] eq {module}}
assert {[dict get $entry object] eq {z}}
+ assert {[dict get $entry reason] eq {key}}
# rm call check for command permission
r acl setuser default -set
@@ -88,6 +90,7 @@ start_server {tags {"modules acl"}} {
assert {[dict get $entry username] eq {default}}
assert {[dict get $entry context] eq {module}}
assert {[dict get $entry object] eq {set}}
+ assert {[dict get $entry reason] eq {command}}
}
test "Unload the module - aclcheck" {
diff --git a/tests/unit/moduleapi/basics.tcl b/tests/unit/moduleapi/basics.tcl
index b858c344a..040d9eb3c 100644
--- a/tests/unit/moduleapi/basics.tcl
+++ b/tests/unit/moduleapi/basics.tcl
@@ -36,6 +36,6 @@ start_server {tags {"modules"}} {
start_server {tags {"modules external:skip"} overrides {enable-module-command no}} {
test {module command disabled} {
- assert_error "ERR*MODULE command not allowed*" {r module load $testmodule}
+ assert_error "ERR *MODULE command not allowed*" {r module load $testmodule}
}
} \ No newline at end of file
diff --git a/tests/unit/moduleapi/blockedclient.tcl b/tests/unit/moduleapi/blockedclient.tcl
index de3cf5946..dd6085c81 100644
--- a/tests/unit/moduleapi/blockedclient.tcl
+++ b/tests/unit/moduleapi/blockedclient.tcl
@@ -90,7 +90,8 @@ start_server {tags {"modules"}} {
}
}
- test {Busy module command} {
+foreach call_type {nested normal} {
+ test "Busy module command - $call_type" {
set busy_time_limit 50
set old_time_limit [lindex [r config get busy-reply-threshold] 1]
r config set busy-reply-threshold $busy_time_limit
@@ -98,7 +99,15 @@ start_server {tags {"modules"}} {
# run command that blocks until released
set start [clock clicks -milliseconds]
- $rd slow_fg_command 0
+ if {$call_type == "nested"} {
+ $rd do_rm_call slow_fg_command 0
+ } else {
+ $rd slow_fg_command 0
+ }
+ $rd flush
+
+ # send another command after the blocked one, to make sure we don't attempt to process it
+ $rd ping
$rd flush
# make sure we get BUSY error, and that we didn't get it too early
@@ -112,11 +121,16 @@ start_server {tags {"modules"}} {
} else {
fail "Failed waiting for busy command to end"
}
- $rd read
+ assert_equal [$rd read] "1"
+ assert_equal [$rd read] "PONG"
- #run command that blocks for 200ms
+ # run command that blocks for 200ms
set start [clock clicks -milliseconds]
- $rd slow_fg_command 200000
+ if {$call_type == "nested"} {
+ $rd do_rm_call slow_fg_command 200000
+ } else {
+ $rd slow_fg_command 200000
+ }
$rd flush
after 10 ;# try to make sure redis started running the command before we proceed
@@ -128,6 +142,7 @@ start_server {tags {"modules"}} {
$rd close
r config set busy-reply-threshold $old_time_limit
}
+}
test {RM_Call from blocked client} {
set busy_time_limit 50
@@ -141,6 +156,10 @@ start_server {tags {"modules"}} {
set start [clock clicks -milliseconds]
$rd do_bg_rm_call hgetall hash
+ # send another command after the blocked one, to make sure we don't attempt to process it
+ $rd ping
+ $rd flush
+
# wait till we know we're blocked inside the module
wait_for_condition 50 100 {
[r is_in_slow_bg_operation] eq 1
@@ -162,10 +181,10 @@ start_server {tags {"modules"}} {
assert_equal [r ping] {PONG}
r config set busy-reply-threshold $old_time_limit
- set res [$rd read]
+ assert_equal [$rd read] {foo bar}
+ assert_equal [$rd read] {PONG}
$rd close
- set _ $res
- } {foo bar}
+ }
test {blocked client reaches client output buffer limit} {
r hset hash big [string repeat x 50000]
@@ -184,9 +203,13 @@ start_server {tags {"modules"}} {
r config resetstat
# simple module command that replies with string error
- assert_error "ERR Unknown Redis command 'hgetalllll'." {r do_rm_call hgetalllll}
+ assert_error "ERR unknown command 'hgetalllll', with args beginning with:" {r do_rm_call hgetalllll}
assert_equal [errorrstat ERR r] {count=1}
+ # simple module command that replies with string error
+ assert_error "ERR unknown subcommand 'bla'. Try CONFIG HELP." {r do_rm_call config bla}
+ assert_equal [errorrstat ERR r] {count=2}
+
# module command that replies with string error from bg thread
assert_error "NULL reply returned" {r do_bg_rm_call hgetalllll}
assert_equal [errorrstat NULL r] {count=1}
@@ -194,7 +217,7 @@ start_server {tags {"modules"}} {
# module command that returns an arity error
r do_rm_call set x x
assert_error "ERR wrong number of arguments for 'do_rm_call' command" {r do_rm_call}
- assert_equal [errorrstat ERR r] {count=2}
+ assert_equal [errorrstat ERR r] {count=3}
# RM_Call that propagates an error
assert_error "WRONGTYPE*" {r do_rm_call hgetall x}
@@ -206,8 +229,8 @@ start_server {tags {"modules"}} {
assert_equal [errorrstat WRONGTYPE r] {count=2}
assert_match {*calls=2,*,rejected_calls=0,failed_calls=2} [cmdrstat hgetall r]
- assert_equal [s total_error_replies] 5
- assert_match {*calls=4,*,rejected_calls=0,failed_calls=3} [cmdrstat do_rm_call r]
+ assert_equal [s total_error_replies] 6
+ assert_match {*calls=5,*,rejected_calls=0,failed_calls=4} [cmdrstat do_rm_call r]
assert_match {*calls=2,*,rejected_calls=0,failed_calls=2} [cmdrstat do_bg_rm_call r]
}
diff --git a/tests/unit/moduleapi/cluster.tcl b/tests/unit/moduleapi/cluster.tcl
index f1238992d..f4ebaab1b 100644
--- a/tests/unit/moduleapi/cluster.tcl
+++ b/tests/unit/moduleapi/cluster.tcl
@@ -2,22 +2,6 @@
source tests/support/cli.tcl
-proc cluster_info {r field} {
- if {[regexp "^$field:(.*?)\r\n" [$r cluster info] _ value]} {
- set _ $value
- }
-}
-
-# Provide easy access to CLUSTER INFO properties. Same semantic as "proc s".
-proc csi {args} {
- set level 0
- if {[string is integer [lindex $args 0]]} {
- set level [lindex $args 0]
- set args [lrange $args 1 end]
- }
- cluster_info [srv $level "client"] [lindex $args 0]
-}
-
set testmodule [file normalize tests/modules/blockonkeys.so]
set testmodule_nokey [file normalize tests/modules/blockonbackground.so]
set testmodule_blockedclient [file normalize tests/modules/blockedclient.so]
diff --git a/tests/unit/moduleapi/cmdintrospection.tcl b/tests/unit/moduleapi/cmdintrospection.tcl
index 375b3e406..8ac49ed9f 100644
--- a/tests/unit/moduleapi/cmdintrospection.tcl
+++ b/tests/unit/moduleapi/cmdintrospection.tcl
@@ -36,6 +36,7 @@ start_server {tags {"modules"}} {
# Compare the maps. We need to pop "group" first.
dict unset redis_reply group
dict unset module_reply group
+ dict unset module_reply module
assert_equal $redis_reply $module_reply
}
diff --git a/tests/unit/moduleapi/keyspace_events.tcl b/tests/unit/moduleapi/keyspace_events.tcl
index 39350e518..ceec6fdf3 100644
--- a/tests/unit/moduleapi/keyspace_events.tcl
+++ b/tests/unit/moduleapi/keyspace_events.tcl
@@ -83,6 +83,17 @@ tags "modules" {
$rd1 close
}
+ test {Test expired key space event} {
+ set prev_expired [s expired_keys]
+ r set exp 1 PX 10
+ wait_for_condition 100 10 {
+ [s expired_keys] eq $prev_expired + 1
+ } else {
+ fail "key not expired"
+ }
+ assert_equal [r get testkeyspace:expired] 1
+ }
+
test "Unload the module - testkeyspace" {
assert_equal {OK} [r module unload testkeyspace]
}
diff --git a/tests/unit/moduleapi/mallocsize.tcl b/tests/unit/moduleapi/mallocsize.tcl
new file mode 100644
index 000000000..359a7ae44
--- /dev/null
+++ b/tests/unit/moduleapi/mallocsize.tcl
@@ -0,0 +1,21 @@
+set testmodule [file normalize tests/modules/mallocsize.so]
+
+
+start_server {tags {"modules"}} {
+ r module load $testmodule
+
+ test {MallocSize of raw bytes} {
+ assert_equal [r mallocsize.setraw key 40] {OK}
+ assert_morethan [r memory usage key] 40
+ }
+
+ test {MallocSize of string} {
+ assert_equal [r mallocsize.setstr key abcdefg] {OK}
+ assert_morethan [r memory usage key] 7 ;# Length of "abcdefg"
+ }
+
+ test {MallocSize of dict} {
+ assert_equal [r mallocsize.setdict key f1 v1 f2 v2] {OK}
+ assert_morethan [r memory usage key] 8 ;# Length of "f1v1f2v2"
+ }
+}
diff --git a/tests/unit/moduleapi/moduleconfigs.tcl b/tests/unit/moduleapi/moduleconfigs.tcl
index 01aa1e88e..f731d1bd9 100644
--- a/tests/unit/moduleapi/moduleconfigs.tcl
+++ b/tests/unit/moduleapi/moduleconfigs.tcl
@@ -11,6 +11,7 @@ start_server {tags {"modules"}} {
assert_equal [r config get moduleconfigs.memory_numeric] "moduleconfigs.memory_numeric 1024"
assert_equal [r config get moduleconfigs.string] "moduleconfigs.string {secret password}"
assert_equal [r config get moduleconfigs.enum] "moduleconfigs.enum one"
+ assert_equal [r config get moduleconfigs.flags] "moduleconfigs.flags {one two}"
assert_equal [r config get moduleconfigs.numeric] "moduleconfigs.numeric -1"
}
@@ -29,6 +30,10 @@ start_server {tags {"modules"}} {
assert_equal [r config get moduleconfigs.string] "moduleconfigs.string {super \0secret password}"
r config set moduleconfigs.enum two
assert_equal [r config get moduleconfigs.enum] "moduleconfigs.enum two"
+ r config set moduleconfigs.flags two
+ assert_equal [r config get moduleconfigs.flags] "moduleconfigs.flags two"
+ r config set moduleconfigs.flags "two three"
+ assert_equal [r config get moduleconfigs.flags] "moduleconfigs.flags {two three}"
r config set moduleconfigs.numeric -2
assert_equal [r config get moduleconfigs.numeric] "moduleconfigs.numeric -2"
}
@@ -54,7 +59,7 @@ start_server {tags {"modules"}} {
test {Enums only able to be set to passed in values} {
# Module authors specify what values are valid for enums, check that only those values are ok on a set
catch {[r config set moduleconfigs.enum four]} e
- assert_match {*argument must be one of the following*} $e
+ assert_match {*must be one of the following*} $e
}
test {Unload removes module configs} {
@@ -67,6 +72,7 @@ start_server {tags {"modules"}} {
assert_equal [r config get moduleconfigs.memory_numeric] "moduleconfigs.memory_numeric 1024"
assert_equal [r config get moduleconfigs.string] "moduleconfigs.string {secret password}"
assert_equal [r config get moduleconfigs.enum] "moduleconfigs.enum one"
+ assert_equal [r config get moduleconfigs.flags] "moduleconfigs.flags {one two}"
assert_equal [r config get moduleconfigs.numeric] "moduleconfigs.numeric -1"
r module unload moduleconfigs
}
@@ -80,6 +86,7 @@ start_server {tags {"modules"}} {
assert_equal [r config get moduleconfigs.string] "moduleconfigs.string tclortickle"
# Configs that were not changed should still be their module specified value
assert_equal [r config get moduleconfigs.enum] "moduleconfigs.enum one"
+ assert_equal [r config get moduleconfigs.flags] "moduleconfigs.flags {one two}"
assert_equal [r config get moduleconfigs.numeric] "moduleconfigs.numeric -1"
}
@@ -140,6 +147,7 @@ start_server {tags {"modules"}} {
r config set moduleconfigs.mutable_bool yes
r config set moduleconfigs.memory_numeric 750
r config set moduleconfigs.enum two
+ r config set moduleconfigs.flags "two three"
r config rewrite
restart_server 0 true false
# Ensure configs we rewrote are present and that the conf file is readable
@@ -147,6 +155,7 @@ start_server {tags {"modules"}} {
assert_equal [r config get moduleconfigs.memory_numeric] "moduleconfigs.memory_numeric 750"
assert_equal [r config get moduleconfigs.string] "moduleconfigs.string {super \0secret password}"
assert_equal [r config get moduleconfigs.enum] "moduleconfigs.enum two"
+ assert_equal [r config get moduleconfigs.flags] "moduleconfigs.flags {two three}"
assert_equal [r config get moduleconfigs.numeric] "moduleconfigs.numeric -1"
r module unload moduleconfigs
}
@@ -221,11 +230,12 @@ start_server {tags {"modules"}} {
set stdout [dict get $noload stdout]
assert_equal [count_message_lines $stdout "Module Configurations were not set, likely a missing LoadConfigs call. Unloading the module."] 1
- start_server [list overrides [list loadmodule "$testmodule" moduleconfigs.string "bootedup" moduleconfigs.enum two]] {
+ start_server [list overrides [list loadmodule "$testmodule" moduleconfigs.string "bootedup" moduleconfigs.enum two moduleconfigs.flags "two three"]] {
assert_equal [r config get moduleconfigs.string] "moduleconfigs.string bootedup"
assert_equal [r config get moduleconfigs.mutable_bool] "moduleconfigs.mutable_bool yes"
assert_equal [r config get moduleconfigs.immutable_bool] "moduleconfigs.immutable_bool no"
assert_equal [r config get moduleconfigs.enum] "moduleconfigs.enum two"
+ assert_equal [r config get moduleconfigs.flags] "moduleconfigs.flags {two three}"
assert_equal [r config get moduleconfigs.numeric] "moduleconfigs.numeric -1"
assert_equal [r config get moduleconfigs.memory_numeric] "moduleconfigs.memory_numeric 1024"
}
diff --git a/tests/unit/moduleapi/propagate.tcl b/tests/unit/moduleapi/propagate.tcl
index bbc9d3800..846d938fb 100644
--- a/tests/unit/moduleapi/propagate.tcl
+++ b/tests/unit/moduleapi/propagate.tcl
@@ -108,10 +108,16 @@ tags "modules" {
{set asdf3 3 PXAT *}
{exec}
{incr notifications}
+ {incr notifications}
+ {incr testkeyspace:expired}
{del asdf*}
{incr notifications}
+ {incr notifications}
+ {incr testkeyspace:expired}
{del asdf*}
{incr notifications}
+ {incr notifications}
+ {incr testkeyspace:expired}
{del asdf*}
}
close_replication_stream $repl
diff --git a/tests/unit/moduleapi/publish.tcl b/tests/unit/moduleapi/publish.tcl
new file mode 100644
index 000000000..ab3611093
--- /dev/null
+++ b/tests/unit/moduleapi/publish.tcl
@@ -0,0 +1,17 @@
+set testmodule [file normalize tests/modules/publish.so]
+
+start_server {tags {"modules"}} {
+ r module load $testmodule
+
+ test {PUBLISH and SPUBLISH via a module} {
+ set rd1 [redis_deferring_client]
+ set rd2 [redis_deferring_client]
+
+ assert_equal {1} [ssubscribe $rd1 {chan1}]
+ assert_equal {1} [subscribe $rd2 {chan1}]
+ assert_equal 1 [r publish.shard chan1 hello]
+ assert_equal 1 [r publish.classic chan1 world]
+ assert_equal {message chan1 hello} [$rd1 read]
+ assert_equal {message chan1 world} [$rd2 read]
+ }
+}
diff --git a/tests/unit/moduleapi/subcommands.tcl b/tests/unit/moduleapi/subcommands.tcl
index 11d243243..62de593e7 100644
--- a/tests/unit/moduleapi/subcommands.tcl
+++ b/tests/unit/moduleapi/subcommands.tcl
@@ -15,8 +15,8 @@ start_server {tags {"modules"}} {
set docs_reply [r command docs subcommands.bitarray]
set docs [dict create {*}[lindex $docs_reply 1]]
set subcmds_in_cmd_docs [dict create {*}[dict get $docs subcommands]]
- assert_equal [dict get $subcmds_in_cmd_docs "subcommands.bitarray|get"] {group module}
- assert_equal [dict get $subcmds_in_cmd_docs "subcommands.bitarray|set"] {group module}
+ assert_equal [dict get $subcmds_in_cmd_docs "subcommands.bitarray|get"] {group module module subcommands}
+ assert_equal [dict get $subcmds_in_cmd_docs "subcommands.bitarray|set"] {group module module subcommands}
}
test "Module pure-container command fails on arity error" {
@@ -25,6 +25,10 @@ start_server {tags {"modules"}} {
# Subcommands can be called
assert_equal [r subcommands.bitarray get k1] {OK}
+
+ # Subcommand arity error
+ catch {r subcommands.bitarray get k1 8 90} e
+ assert_match {*wrong number of arguments for 'subcommands.bitarray|get' command} $e
}
test "Module get current command fullname" {
diff --git a/tests/unit/oom-score-adj.tcl b/tests/unit/oom-score-adj.tcl
index b226a266a..6c7b71392 100644
--- a/tests/unit/oom-score-adj.tcl
+++ b/tests/unit/oom-score-adj.tcl
@@ -122,5 +122,10 @@ if {$system_name eq {linux}} {
r config set oom-score-adj absolute
assert_equal [get_oom_score_adj] $custom_oom
}
+
+ test {CONFIG SET out-of-range oom score} {
+ assert_error {ERR *must be between -2000 and 2000*} {r config set oom-score-adj-values "-2001 -2001 -2001"}
+ assert_error {ERR *must be between -2000 and 2000*} {r config set oom-score-adj-values "2001 2001 2001"}
+ }
}
}
diff --git a/tests/unit/other.tcl b/tests/unit/other.tcl
index 258ef2f6e..bd220a145 100644
--- a/tests/unit/other.tcl
+++ b/tests/unit/other.tcl
@@ -311,7 +311,7 @@ start_server {tags {"other"}} {
assert_error {*unknown command*} {r GET|SET}
assert_error {*unknown command*} {r GET|SET|OTHER}
assert_error {*unknown command*} {r CONFIG|GET GET_XX}
- assert_error {*Unknown subcommand*} {r CONFIG GET_XX}
+ assert_error {*unknown subcommand*} {r CONFIG GET_XX}
}
}
diff --git a/tests/unit/pubsub.tcl b/tests/unit/pubsub.tcl
index 4435a9b1d..ea8964cf3 100644
--- a/tests/unit/pubsub.tcl
+++ b/tests/unit/pubsub.tcl
@@ -390,4 +390,17 @@ start_server {tags {"pubsub network"}} {
r config set notify-keyspace-events EA
assert_equal {AE} [lindex [r config get notify-keyspace-events] 1]
}
+
+ test "Keyspace notifications: new key test" {
+ r config set notify-keyspace-events En
+ set rd1 [redis_deferring_client]
+ assert_equal {1} [psubscribe $rd1 *]
+ r set foo bar
+ # second set of foo should not cause a 'new' event
+ r set foo baz
+ r set bar bar
+ assert_equal "pmessage * __keyevent@${db}__:new foo" [$rd1 read]
+ assert_equal "pmessage * __keyevent@${db}__:new bar" [$rd1 read]
+ $rd1 close
+ }
}
diff --git a/tests/unit/pubsubshard.tcl b/tests/unit/pubsubshard.tcl
index 5c3564afe..d0023a841 100644
--- a/tests/unit/pubsubshard.tcl
+++ b/tests/unit/pubsubshard.tcl
@@ -1,80 +1,4 @@
start_server {tags {"pubsubshard external:skip"}} {
- proc __consume_ssubscribe_messages {client type channels} {
- set numsub -1
- set counts {}
-
- for {set i [llength $channels]} {$i > 0} {incr i -1} {
- set msg [$client read]
- assert_equal $type [lindex $msg 0]
-
- # when receiving subscribe messages the channels names
- # are ordered. when receiving unsubscribe messages
- # they are unordered
- set idx [lsearch -exact $channels [lindex $msg 1]]
- if {[string match "sunsubscribe" $type]} {
- assert {$idx >= 0}
- } else {
- assert {$idx == 0}
- }
- set channels [lreplace $channels $idx $idx]
-
- # aggregate the subscription count to return to the caller
- lappend counts [lindex $msg 2]
- }
-
- # we should have received messages for channels
- assert {[llength $channels] == 0}
- return $counts
- }
-
- proc __consume_subscribe_messages {client type channels} {
- set numsub -1
- set counts {}
-
- for {set i [llength $channels]} {$i > 0} {incr i -1} {
- set msg [$client read]
- assert_equal $type [lindex $msg 0]
-
- # when receiving subscribe messages the channels names
- # are ordered. when receiving unsubscribe messages
- # they are unordered
- set idx [lsearch -exact $channels [lindex $msg 1]]
- if {[string match "unsubscribe" $type]} {
- assert {$idx >= 0}
- } else {
- assert {$idx == 0}
- }
- set channels [lreplace $channels $idx $idx]
-
- # aggregate the subscription count to return to the caller
- lappend counts [lindex $msg 2]
- }
-
- # we should have received messages for channels
- assert {[llength $channels] == 0}
- return $counts
- }
-
- proc ssubscribe {client channels} {
- $client ssubscribe {*}$channels
- __consume_ssubscribe_messages $client ssubscribe $channels
- }
-
- proc subscribe {client channels} {
- $client subscribe {*}$channels
- __consume_subscribe_messages $client subscribe $channels
- }
-
- proc sunsubscribe {client {channels {}}} {
- $client sunsubscribe {*}$channels
- __consume_subscribe_messages $client sunsubscribe $channels
- }
-
- proc unsubscribe {client {channels {}}} {
- $client unsubscribe {*}$channels
- __consume_subscribe_messages $client unsubscribe $channels
- }
-
test "SPUBLISH/SSUBSCRIBE basics" {
set rd1 [redis_deferring_client]
diff --git a/tests/unit/scripting.tcl b/tests/unit/scripting.tcl
index d9729b7bd..439a1e71a 100644
--- a/tests/unit/scripting.tcl
+++ b/tests/unit/scripting.tcl
@@ -52,7 +52,7 @@ start_server {tags {"scripting"}} {
assert_match {*command not allowed when used memory*} $e
r config set maxmemory 0
- }
+ } {OK} {needs:config-maxmemory}
} ;# is_eval
test {EVAL - Does Lua interpreter replies to our requests?} {
@@ -447,12 +447,12 @@ start_server {tags {"scripting"}} {
test {Globals protection reading an undeclared global variable} {
catch {run_script {return a} 0} e
set e
- } {ERR*attempted to access * global*}
+ } {ERR *attempted to access * global*}
test {Globals protection setting an undeclared global*} {
catch {run_script {a=10} 0} e
set e
- } {ERR*attempted to create global*}
+ } {ERR *Attempt to modify a readonly table*}
test {Test an example script DECR_IF_GT} {
set decr_if_gt {
@@ -735,6 +735,112 @@ start_server {tags {"scripting"}} {
return redis.acl_check_cmd('invalid-cmd','arg')
} 0}
}
+
+ test "Binary code loading failed" {
+ assert_error {ERR *attempt to call a nil value*} {run_script {
+ return loadstring(string.dump(function() return 1 end))()
+ } 0}
+ }
+
+ test "Try trick global protection 1" {
+ catch {
+ run_script {
+ setmetatable(_G, {})
+ } 0
+ } e
+ set _ $e
+ } {*Attempt to modify a readonly table*}
+
+ test "Try trick global protection 2" {
+ catch {
+ run_script {
+ local g = getmetatable(_G)
+ g.__index = {}
+ } 0
+ } e
+ set _ $e
+ } {*Attempt to modify a readonly table*}
+
+ test "Try trick global protection 3" {
+ catch {
+ run_script {
+ redis = function() return 1 end
+ } 0
+ } e
+ set _ $e
+ } {*Attempt to modify a readonly table*}
+
+ test "Try trick global protection 4" {
+ catch {
+ run_script {
+ _G = {}
+ } 0
+ } e
+ set _ $e
+ } {*Attempt to modify a readonly table*}
+
+ test "Try trick readonly table on redis table" {
+ catch {
+ run_script {
+ redis.call = function() return 1 end
+ } 0
+ } e
+ set _ $e
+ } {*Attempt to modify a readonly table*}
+
+ test "Try trick readonly table on json table" {
+ catch {
+ run_script {
+ cjson.encode = function() return 1 end
+ } 0
+ } e
+ set _ $e
+ } {*Attempt to modify a readonly table*}
+
+ test "Try trick readonly table on cmsgpack table" {
+ catch {
+ run_script {
+ cmsgpack.pack = function() return 1 end
+ } 0
+ } e
+ set _ $e
+ } {*Attempt to modify a readonly table*}
+
+ test "Try trick readonly table on bit table" {
+ catch {
+ run_script {
+ bit.lshift = function() return 1 end
+ } 0
+ } e
+ set _ $e
+ } {*Attempt to modify a readonly table*}
+
+ test "Test loadfile are not available" {
+ catch {
+ run_script {
+ loadfile('some file')
+ } 0
+ } e
+ set _ $e
+ } {*Script attempted to access nonexistent global variable 'loadfile'*}
+
+ test "Test dofile are not available" {
+ catch {
+ run_script {
+ dofile('some file')
+ } 0
+ } e
+ set _ $e
+ } {*Script attempted to access nonexistent global variable 'dofile'*}
+
+ test "Test print are not available" {
+ catch {
+ run_script {
+ print('some data')
+ } 0
+ } e
+ set _ $e
+ } {*Script attempted to access nonexistent global variable 'print'*}
}
# Start a new server since the last test in this stanza will kill the
@@ -1324,7 +1430,7 @@ start_server {tags {"scripting"}} {
] 1
r config set maxmemory 0
- }
+ } {OK} {needs:config-maxmemory}
test "no-writes shebang flag" {
assert_error {ERR Write commands are not allowed from read-only scripts*} {
diff --git a/tests/unit/slowlog.tcl b/tests/unit/slowlog.tcl
index 2f4fb35e3..8ce1b1c27 100644
--- a/tests/unit/slowlog.tcl
+++ b/tests/unit/slowlog.tcl
@@ -53,17 +53,17 @@ start_server {tags {"slowlog"} overrides {slowlog-log-slower-than 1000000}} {
r config set masterauth ""
r acl setuser slowlog-test-user +get +set
r config set slowlog-log-slower-than 0
- r config set slowlog-log-slower-than 10000
+ r config set slowlog-log-slower-than -1
set slowlog_resp [r slowlog get]
# Make sure normal configs work, but the two sensitive
# commands are omitted or redacted
assert_equal 5 [llength $slowlog_resp]
- assert_equal {slowlog reset} [lindex [lindex [r slowlog get] 4] 3]
- assert_equal {acl setuser (redacted) (redacted) (redacted)} [lindex [lindex [r slowlog get] 3] 3]
- assert_equal {config set masterauth (redacted)} [lindex [lindex [r slowlog get] 2] 3]
- assert_equal {acl setuser (redacted) (redacted) (redacted)} [lindex [lindex [r slowlog get] 1] 3]
- assert_equal {config set slowlog-log-slower-than 0} [lindex [lindex [r slowlog get] 0] 3]
+ assert_equal {slowlog reset} [lindex [lindex $slowlog_resp 4] 3]
+ assert_equal {acl setuser (redacted) (redacted) (redacted)} [lindex [lindex $slowlog_resp 3] 3]
+ assert_equal {config set masterauth (redacted)} [lindex [lindex $slowlog_resp 2] 3]
+ assert_equal {acl setuser (redacted) (redacted) (redacted)} [lindex [lindex $slowlog_resp 1] 3]
+ assert_equal {config set slowlog-log-slower-than 0} [lindex [lindex $slowlog_resp 0] 3]
} {} {needs:repl}
test {SLOWLOG - Some commands can redact sensitive fields} {
@@ -72,13 +72,14 @@ start_server {tags {"slowlog"} overrides {slowlog-log-slower-than 1000000}} {
r migrate [srv 0 host] [srv 0 port] key 9 5000
r migrate [srv 0 host] [srv 0 port] key 9 5000 AUTH user
r migrate [srv 0 host] [srv 0 port] key 9 5000 AUTH2 user password
+ r config set slowlog-log-slower-than -1
+ set slowlog_resp [r slowlog get]
- r config set slowlog-log-slower-than 10000
# Make sure all 3 commands were logged, but the sensitive fields are omitted
- assert_equal 4 [llength [r slowlog get]]
- assert_match {* key 9 5000} [lindex [lindex [r slowlog get] 2] 3]
- assert_match {* key 9 5000 AUTH (redacted)} [lindex [lindex [r slowlog get] 1] 3]
- assert_match {* key 9 5000 AUTH2 (redacted) (redacted)} [lindex [lindex [r slowlog get] 0] 3]
+ assert_equal 4 [llength $slowlog_resp]
+ assert_match {* key 9 5000} [lindex [lindex $slowlog_resp 2] 3]
+ assert_match {* key 9 5000 AUTH (redacted)} [lindex [lindex $slowlog_resp 1] 3]
+ assert_match {* key 9 5000 AUTH2 (redacted) (redacted)} [lindex [lindex $slowlog_resp 0] 3]
} {} {needs:repl}
test {SLOWLOG - Rewritten commands are logged as their original command} {
@@ -199,4 +200,4 @@ start_server {tags {"slowlog"} overrides {slowlog-log-slower-than 1000000}} {
assert_equal 3 [llength [r slowlog get -1]]
assert_equal 3 [llength [r slowlog get 3]]
}
-} \ No newline at end of file
+}
diff --git a/tests/unit/type/hash.tcl b/tests/unit/type/hash.tcl
index 75ba29f77..ae5677383 100644
--- a/tests/unit/type/hash.tcl
+++ b/tests/unit/type/hash.tcl
@@ -507,8 +507,8 @@ start_server {tags {"hash"}} {
catch {r hincrby smallhash str 1} smallerr
catch {r hincrby bighash str 1} bigerr
set rv {}
- lappend rv [string match "ERR*not an integer*" $smallerr]
- lappend rv [string match "ERR*not an integer*" $bigerr]
+ lappend rv [string match "ERR *not an integer*" $smallerr]
+ lappend rv [string match "ERR *not an integer*" $bigerr]
} {1 1}
test {HINCRBY fails against hash value with spaces (right)} {
@@ -517,8 +517,8 @@ start_server {tags {"hash"}} {
catch {r hincrby smallhash str 1} smallerr
catch {r hincrby bighash str 1} bigerr
set rv {}
- lappend rv [string match "ERR*not an integer*" $smallerr]
- lappend rv [string match "ERR*not an integer*" $bigerr]
+ lappend rv [string match "ERR *not an integer*" $smallerr]
+ lappend rv [string match "ERR *not an integer*" $bigerr]
} {1 1}
test {HINCRBY can detect overflows} {
@@ -579,8 +579,8 @@ start_server {tags {"hash"}} {
catch {r hincrbyfloat smallhash str 1} smallerr
catch {r hincrbyfloat bighash str 1} bigerr
set rv {}
- lappend rv [string match "ERR*not*float*" $smallerr]
- lappend rv [string match "ERR*not*float*" $bigerr]
+ lappend rv [string match "ERR *not*float*" $smallerr]
+ lappend rv [string match "ERR *not*float*" $bigerr]
} {1 1}
test {HINCRBYFLOAT fails against hash value with spaces (right)} {
@@ -589,15 +589,15 @@ start_server {tags {"hash"}} {
catch {r hincrbyfloat smallhash str 1} smallerr
catch {r hincrbyfloat bighash str 1} bigerr
set rv {}
- lappend rv [string match "ERR*not*float*" $smallerr]
- lappend rv [string match "ERR*not*float*" $bigerr]
+ lappend rv [string match "ERR *not*float*" $smallerr]
+ lappend rv [string match "ERR *not*float*" $bigerr]
} {1 1}
test {HINCRBYFLOAT fails against hash value that contains a null-terminator in the middle} {
r hset h f "1\x002"
catch {r hincrbyfloat h f 1} err
set rv {}
- lappend rv [string match "ERR*not*float*" $err]
+ lappend rv [string match "ERR *not*float*" $err]
} {1}
test {HSTRLEN against the small hash} {
@@ -648,6 +648,31 @@ start_server {tags {"hash"}} {
}
}
+ test {HINCRBYFLOAT over hash-max-listpack-value encoded with a listpack} {
+ set original_max_value [lindex [r config get hash-max-ziplist-value] 1]
+ r config set hash-max-listpack-value 8
+
+ # hash's value exceeds hash-max-listpack-value
+ r del smallhash
+ r del bighash
+ r hset smallhash tmp 0
+ r hset bighash tmp 0
+ r hincrbyfloat smallhash tmp 0.000005
+ r hincrbyfloat bighash tmp 0.0000005
+ assert_encoding listpack smallhash
+ assert_encoding hashtable bighash
+
+ # hash's field exceeds hash-max-listpack-value
+ r del smallhash
+ r del bighash
+ r hincrbyfloat smallhash abcdefgh 1
+ r hincrbyfloat bighash abcdefghi 1
+ assert_encoding listpack smallhash
+ assert_encoding hashtable bighash
+
+ r config set hash-max-listpack-value $original_max_value
+ }
+
test {Hash ziplist regression test for large keys} {
r hset hash kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk a
r hset hash kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk b
diff --git a/tests/unit/type/incr.tcl b/tests/unit/type/incr.tcl
index b6aaa1112..b7446850e 100644
--- a/tests/unit/type/incr.tcl
+++ b/tests/unit/type/incr.tcl
@@ -111,21 +111,21 @@ start_server {tags {"incr"}} {
r set novar " 11"
catch {r incrbyfloat novar 1.0} err
format $err
- } {ERR*valid*}
+ } {ERR *valid*}
test {INCRBYFLOAT fails against key with spaces (right)} {
set err {}
r set novar "11 "
catch {r incrbyfloat novar 1.0} err
format $err
- } {ERR*valid*}
+ } {ERR *valid*}
test {INCRBYFLOAT fails against key with spaces (both)} {
set err {}
r set novar " 11 "
catch {r incrbyfloat novar 1.0} err
format $err
- } {ERR*valid*}
+ } {ERR *valid*}
test {INCRBYFLOAT fails against a key holding a list} {
r del mylist
@@ -146,7 +146,7 @@ start_server {tags {"incr"}} {
# p.s. no way I can force NaN to test it from the API because
# there is no way to increment / decrement by infinity nor to
# perform divisions.
- } {ERR*would produce*}
+ } {ERR *would produce*}
}
test {INCRBYFLOAT decrement} {
@@ -159,7 +159,7 @@ start_server {tags {"incr"}} {
r setrange foo 2 2
catch {r incrbyfloat foo 1} err
format $err
- } {ERR*valid*}
+ } {ERR *valid*}
test {No negative zero} {
r del foo
diff --git a/tests/unit/type/list.tcl b/tests/unit/type/list.tcl
index 8cff56c6a..ecf23bdac 100644
--- a/tests/unit/type/list.tcl
+++ b/tests/unit/type/list.tcl
@@ -252,6 +252,7 @@ start_server [list overrides [list save ""] ] {
} {} {needs:debug}
}
+run_solo {list-large-memory} {
start_server [list overrides [list save ""] ] {
# test if the server supports such large configs (avoid 32 bit builds)
@@ -349,6 +350,7 @@ if {[lindex [r config get proto-max-bulk-len] 1] == 10000000000} {
} {} {large-memory}
} ;# skip 32bit builds
}
+} ;# run_solo
start_server {
tags {"list"}
@@ -510,7 +512,11 @@ start_server {
}
foreach resp {3 2} {
- r hello $resp
+ if {[lsearch $::denytags "resp3"] >= 0} {
+ if {$resp == 3} {continue}
+ } else {
+ r hello $resp
+ }
# Make sure we can distinguish between an empty array and a null response
r readraw 1
@@ -1173,7 +1179,7 @@ foreach {pop} {BLPOP BLMPOP_LEFT} {
test "$pop: with negative timeout" {
set rd [redis_deferring_client]
bpop_command $rd $pop blist1 -1
- assert_error "ERR*is negative*" {$rd read}
+ assert_error "ERR *is negative*" {$rd read}
$rd close
}
diff --git a/tests/unit/type/set.tcl b/tests/unit/type/set.tcl
index 93f7311b1..4f207b727 100644
--- a/tests/unit/type/set.tcl
+++ b/tests/unit/type/set.tcl
@@ -935,6 +935,7 @@ start_server {
}
}
+run_solo {set-large-memory} {
start_server [list overrides [list save ""] ] {
# test if the server supports such large configs (avoid 32 bit builds)
@@ -969,3 +970,4 @@ if {[lindex [r config get proto-max-bulk-len] 1] == 10000000000} {
} {} {large-memory}
} ;# skip 32bit builds
}
+} ;# run_solo
diff --git a/tests/unit/type/stream.tcl b/tests/unit/type/stream.tcl
index bd689cd29..83d29bbbf 100644
--- a/tests/unit/type/stream.tcl
+++ b/tests/unit/type/stream.tcl
@@ -770,7 +770,7 @@ start_server {tags {"stream xsetid"}} {
catch {r XSETID mystream "1-1"} err
r XADD mystream MAXLEN 0 * a b
set err
- } {ERR*smaller*}
+ } {ERR *smaller*}
test {XSETID cannot SETID on non-existent key} {
catch {r XSETID stream 1-1} err
@@ -790,7 +790,7 @@ start_server {tags {"stream xsetid"}} {
test {XSETID errors on negstive offset} {
catch {r XSETID stream 1-1 ENTRIESADDED -1 MAXDELETEDID 0-0} err
set _ $err
- } {ERR*must be positive}
+ } {ERR *must be positive}
test {XSETID cannot set the maximal tombstone with larger ID} {
r DEL x
@@ -799,7 +799,7 @@ start_server {tags {"stream xsetid"}} {
catch {r XSETID x "1-0" ENTRIESADDED 1 MAXDELETEDID "2-0" } err
r XADD mystream MAXLEN 0 * a b
set err
- } {ERR*smaller*}
+ } {ERR *smaller*}
test {XSETID cannot set the offset to less than the length} {
r DEL x
@@ -808,7 +808,7 @@ start_server {tags {"stream xsetid"}} {
catch {r XSETID x "1-0" ENTRIESADDED 0 MAXDELETEDID "0-0" } err
r XADD mystream MAXLEN 0 * a b
set err
- } {ERR*smaller*}
+ } {ERR *smaller*}
}
start_server {tags {"stream offset"}} {
diff --git a/tests/unit/type/zset.tcl b/tests/unit/type/zset.tcl
index 3ccfa61ab..6df856e31 100644
--- a/tests/unit/type/zset.tcl
+++ b/tests/unit/type/zset.tcl
@@ -1223,11 +1223,20 @@ start_server {tags {"zset"}} {
} {} {needs:repl}
foreach resp {3 2} {
+ set rd [redis_deferring_client]
+
+ if {[lsearch $::denytags "resp3"] >= 0} {
+ if {$resp == 3} {continue}
+ } else {
+ r hello $resp
+ $rd hello $resp
+ $rd read
+ }
+
test "ZPOPMIN/ZPOPMAX readraw in RESP$resp" {
r del zset{t}
create_zset zset2{t} {1 a 2 b 3 c 4 d 5 e}
- r hello $resp
r readraw 1
# ZPOP against non existing key.
@@ -1260,9 +1269,6 @@ start_server {tags {"zset"}} {
r del zset{t}
create_zset zset2{t} {1 a 2 b 3 c 4 d 5 e}
- set rd [redis_deferring_client]
- $rd hello $resp
- $rd read
$rd readraw 1
# BZPOP released on timeout.
@@ -1291,7 +1297,7 @@ start_server {tags {"zset"}} {
assert_equal [$rd read] {a}
verify_score_response $rd $resp 1
- $rd close
+ $rd readraw 0
}
test "ZMPOP readraw in RESP$resp" {
@@ -1299,7 +1305,6 @@ start_server {tags {"zset"}} {
create_zset zset3{t} {1 a}
create_zset zset4{t} {1 a 2 b 3 c 4 d 5 e}
- r hello $resp
r readraw 1
# ZMPOP against non existing key.
@@ -1339,9 +1344,6 @@ start_server {tags {"zset"}} {
r del zset{t} zset2{t}
create_zset zset3{t} {1 a 2 b 3 c 4 d 5 e}
- set rd [redis_deferring_client]
- $rd hello $resp
- $rd read
$rd readraw 1
# BZMPOP released on timeout.
@@ -1380,8 +1382,9 @@ start_server {tags {"zset"}} {
assert_equal [$rd read] {b}
verify_score_response $rd $resp 2
- $rd close
}
+
+ $rd close
}
test {ZINTERSTORE regression with two sets, intset+hashtable} {
diff --git a/tests/unit/violations.tcl b/tests/unit/violations.tcl
index 716edf8ac..783f306d1 100644
--- a/tests/unit/violations.tcl
+++ b/tests/unit/violations.tcl
@@ -1,5 +1,6 @@
# One XADD with one huge 5GB field
# Expected to fail resulting in an empty stream
+run_solo {violations} {
start_server [list overrides [list save ""] ] {
test {XADD one huge field} {
r config set proto-max-bulk-len 10000000000 ;#10gb
@@ -85,7 +86,7 @@ start_server [list overrides [list save ""] ] {
r object encoding H1
} {hashtable} {large-memory}
}
-
+} ;# run_solo
# SORT which stores an integer encoded element into a list.
# Just for coverage, no news here.