Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ruanhaishen
redis
Commits
fb4e0d40
Unverified
Commit
fb4e0d40
authored
Apr 05, 2022
by
Oran Agra
Committed by
GitHub
Apr 05, 2022
Browse files
Merge pull request #10532 from oranagra/7.0-rc3
Release 7.0 rc3
parents
d2b5a579
8b242ef9
Changes
171
Hide whitespace changes
Inline
Side-by-side
tests/cluster/tests/11-manual-takeover.tcl
View file @
fb4e0d40
...
@@ -14,20 +14,32 @@ test "Cluster is writable" {
...
@@ -14,20 +14,32 @@ test "Cluster is writable" {
cluster_write_test 0
cluster_write_test 0
}
}
# For this test, disable replica failover until
# all of the primaries are confirmed killed. Otherwise
# there might be enough time to elect a replica.
set replica_ids
{
5 6 7
}
foreach id $replica_ids
{
R $id config set cluster-replica-no-failover yes
}
test
"Killing majority of master nodes"
{
test
"Killing majority of master nodes"
{
kill_instance redis 0
kill_instance redis 0
kill_instance redis 1
kill_instance redis 1
kill_instance redis 2
kill_instance redis 2
}
}
foreach id $replica_ids
{
R $id config set cluster-replica-no-failover no
}
test
"Cluster should eventually be down"
{
test
"Cluster should eventually be down"
{
assert_cluster_state fail
assert_cluster_state fail
}
}
test
"Use takeover to bring slaves back"
{
test
"Use takeover to bring slaves back"
{
R 5 cluster failover takeover
foreach id $replica_ids
{
R
6
cluster failover takeover
R
$id
cluster failover takeover
R 7 cluster failover takeover
}
}
}
test
"Cluster should eventually be up again"
{
test
"Cluster should eventually be up again"
{
...
@@ -39,9 +51,9 @@ test "Cluster is writable" {
...
@@ -39,9 +51,9 @@ test "Cluster is writable" {
}
}
test
"Instance #5, #6, #7 are now masters"
{
test
"Instance #5, #6, #7 are now masters"
{
assert
{[
RI 5 role
]
eq
{
master
}}
foreach id $replica_ids
{
assert
{[
RI
6
role
]
eq
{
master
}}
assert
{[
RI
$id
role
]
eq
{
master
}}
assert
{[
RI 7 role
]
eq
{
master
}
}
}
}
}
test
"Restarting the previously killed master nodes"
{
test
"Restarting the previously killed master nodes"
{
...
...
tests/cluster/tests/12-replica-migration-2.tcl
View file @
fb4e0d40
...
@@ -45,11 +45,12 @@ test "Resharding all the master #0 slots away from it" {
...
@@ -45,11 +45,12 @@ test "Resharding all the master #0 slots away from it" {
}
}
test
"Master #0
should lose its
replicas"
{
test
"Master #0
who lost all slots should turn into a replica without
replicas"
{
wait_for_condition 1000 50
{
wait_for_condition 1000 50
{
[
llength
[
lindex
[
R 0
role
]
2
]
]
== 0
[
RI 0 role
]
==
"slave"
&&
[
R
I
0
connected_slaves
]
== 0
}
else
{
}
else
{
fail
"Master #0 still has replicas"
puts
[
R 0 info replication
]
fail
"Master #0 didn't turn itself into a replica"
}
}
}
}
...
...
tests/cluster/tests/27-endpoints.tcl
View file @
fb4e0d40
source
"../tests/includes/init-tests.tcl"
source
"../tests/includes/init-tests.tcl"
# Check if cluster's view of hostnames is consistent
proc are_hostnames_propagated
{
match_string
}
{
for
{
set j 0
}
{
$j
< $::cluster_master_nodes + $::cluster_replica_nodes
}
{
incr j
}
{
set cfg
[
R $j cluster slots
]
foreach node $cfg
{
for
{
set i 2
}
{
$i
<
[
llength $node
]}
{
incr i
}
{
if
{
!
[
string match $match_string
[
lindex
[
lindex
[
lindex $node $i
]
3
]
1
]]
}
{
return 0
}
}
}
}
return 1
}
# Isolate a node from the cluster and give it a new nodeid
# Isolate a node from the cluster and give it a new nodeid
proc isolate_node
{
id
}
{
proc isolate_node
{
id
}
{
set node_id
[
R $id CLUSTER MYID
]
set node_id
[
R $id CLUSTER MYID
]
...
@@ -212,6 +197,9 @@ test "Verify the nodes configured with prefer hostname only show hostname for ne
...
@@ -212,6 +197,9 @@ test "Verify the nodes configured with prefer hostname only show hostname for ne
test
"Test restart will keep hostname information"
{
test
"Test restart will keep hostname information"
{
# Set a new hostname, reboot and make sure it sticks
# Set a new hostname, reboot and make sure it sticks
R 0 config set cluster-announce-hostname
"restart-1.com"
R 0 config set cluster-announce-hostname
"restart-1.com"
# Store the hostname in the config
R 0 config rewrite
kill_instance redis 0
restart_instance redis 0
restart_instance redis 0
set slot_result
[
R 0 CLUSTER SLOTS
]
set slot_result
[
R 0 CLUSTER SLOTS
]
assert_equal
[
lindex
[
get_slot_field $slot_result 0 2 3
]
1
]
"restart-1.com"
assert_equal
[
lindex
[
get_slot_field $slot_result 0 2 3
]
1
]
"restart-1.com"
...
...
tests/cluster/tests/28-cluster-shards.tcl
0 → 100644
View file @
fb4e0d40
source
"../tests/includes/init-tests.tcl"
# Initial slot distribution.
set ::slot0
[
list 0 1000 1002 5459 5461 5461 10926 10926
]
set ::slot1
[
list 5460 5460 5462 10922 10925 10925
]
set ::slot2
[
list 10923 10924 10927 16383
]
set ::slot3
[
list 1001 1001
]
proc cluster_create_with_split_slots
{
masters replicas
}
{
for
{
set j 0
}
{
$j
< $masters
}
{
incr j
}
{
R $j cluster ADDSLOTSRANGE
{*}
[
set ::slot$
{
j
}]
}
if
{
$replicas
}
{
cluster_allocate_slaves $masters $replicas
}
set ::cluster_master_nodes $masters
set ::cluster_replica_nodes $replicas
}
# Get the node info with the specific node_id from the
# given reference node. Valid type options are
"node"
and
"shard"
proc get_node_info_from_shard
{
id reference
{
type node
}}
{
set shards_response
[
R $reference CLUSTER SHARDS
]
foreach shard_response $shards_response
{
set nodes
[
dict get $shard_response nodes
]
foreach node $nodes
{
if
{[
dict get $node id
]
eq $id
}
{
if
{
$type
eq
"node"
}
{
return $node
}
elseif
{
$type
eq
"shard"
}
{
return $shard_response
}
else
{
return
{}
}
}
}
}
# No shard found, return nothing
return
{}
}
test
"Create a 8 nodes cluster with 4 shards"
{
cluster_create_with_split_slots 4 4
}
test
"Cluster should start ok"
{
assert_cluster_state ok
}
test
"Set cluster hostnames and verify they are propagated"
{
for
{
set j 0
}
{
$j
< $::cluster_master_nodes + $::cluster_replica_nodes
}
{
incr j
}
{
R $j config set cluster-announce-hostname
"host-
$j.com
"
}
# Wait for everyone to agree about the state
wait_for_cluster_propagation
}
test
"Verify information about the shards"
{
set ids
{}
for
{
set j 0
}
{
$j
< $::cluster_master_nodes + $::cluster_replica_nodes
}
{
incr j
}
{
lappend ids
[
R $j CLUSTER MYID
]
}
set slots
[
list $::slot0 $::slot1 $::slot2 $::slot3 $::slot0 $::slot1 $::slot2 $::slot3
]
# Verify on each node
(
primary/replica
)
, the response of the `CLUSTER SLOTS` command is consistent.
for
{
set ref 0
}
{
$ref
< $::cluster_master_nodes + $::cluster_replica_nodes
}
{
incr ref
}
{
for
{
set i 0
}
{
$i
< $::cluster_master_nodes + $::cluster_replica_nodes
}
{
incr i
}
{
assert_equal
[
lindex $slots $i
]
[
dict get
[
get_node_info_from_shard
[
lindex $ids $i
]
$ref
"shard"
]
slots
]
assert_equal
"host-
$i.com
"
[
dict get
[
get_node_info_from_shard
[
lindex $ids $i
]
$ref
"node"
]
hostname
]
assert_equal
"127.0.0.1"
[
dict get
[
get_node_info_from_shard
[
lindex $ids $i
]
$ref
"node"
]
ip
]
# Default value of 'cluster-preferred-endpoint-type' is ip.
assert_equal
"127.0.0.1"
[
dict get
[
get_node_info_from_shard
[
lindex $ids $i
]
$ref
"node"
]
endpoint
]
if
{
$::tls
}
{
assert_equal
[
get_instance_attrib redis $i plaintext-port
]
[
dict get
[
get_node_info_from_shard
[
lindex $ids $i
]
$ref
"node"
]
port
]
assert_equal
[
get_instance_attrib redis $i port
]
[
dict get
[
get_node_info_from_shard
[
lindex $ids $i
]
$ref
"node"
]
tls-port
]
}
else
{
assert_equal
[
get_instance_attrib redis $i port
]
[
dict get
[
get_node_info_from_shard
[
lindex $ids $i
]
$ref
"node"
]
port
]
}
if
{
$i
< 4
}
{
assert_equal
"master"
[
dict get
[
get_node_info_from_shard
[
lindex $ids $i
]
$ref
"node"
]
role
]
assert_equal
"online"
[
dict get
[
get_node_info_from_shard
[
lindex $ids $i
]
$ref
"node"
]
health
]
}
else
{
assert_equal
"replica"
[
dict get
[
get_node_info_from_shard
[
lindex $ids $i
]
$ref
"node"
]
role
]
# Replica could be in online or loading
}
}
}
}
test
"Verify no slot shard"
{
# Node 8 has no slots assigned
set node_8_id
[
R 8 CLUSTER MYID
]
assert_equal
{}
[
dict get
[
get_node_info_from_shard $node_8_id 8
"shard"
]
slots
]
assert_equal
{}
[
dict get
[
get_node_info_from_shard $node_8_id 0
"shard"
]
slots
]
}
set node_0_id
[
R 0 CLUSTER MYID
]
test
"Kill a node and tell the replica to immediately takeover"
{
kill_instance redis 0
R 4 cluster failover force
}
# Primary 0 node should report as fail, wait until the new primary acknowledges it.
test
"Verify health as fail for killed node"
{
wait_for_condition 50 100
{
"fail"
eq
[
dict get
[
get_node_info_from_shard $node_0_id 4
"node"
]
"health"
]
}
else
{
fail
"New primary never detected the node failed"
}
}
set primary_id 4
set replica_id 0
test
"Restarting primary node"
{
restart_instance redis $replica_id
}
test
"Instance #0 gets converted into a replica"
{
wait_for_condition 1000 50
{
[
RI $replica_id role
]
eq
{
slave
}
}
else
{
fail
"Old primary was not converted into replica"
}
}
test
"Test the replica reports a loading state while it's loading"
{
# Test the command is good for verifying everything moves to a happy state
set replica_cluster_id
[
R $replica_id CLUSTER MYID
]
wait_for_condition 50 1000
{
[
dict get
[
get_node_info_from_shard $replica_cluster_id $primary_id
"node"
]
health
]
eq
"online"
}
else
{
fail
"Replica never transitioned to online"
}
# Set 1 MB of data, so there is something to load on full sync
R $primary_id debug populate 1000 key 1000
# Kill replica client for primary and load new data to the primary
R $primary_id config set repl-backlog-size 100
# Set the key load delay so that it will take at least
# 2 seconds to fully load the data.
R $replica_id config set key-load-delay 4000
# Trigger event loop processing every 1024 bytes, this trigger
# allows us to send and receive cluster messages, so we are setting
# it low so that the cluster messages are sent more frequently.
R $replica_id config set loading-process-events-interval-bytes 1024
R $primary_id multi
R $primary_id client kill type replica
# populate the correct data
set num 100
set value
[
string repeat A 1024
]
for
{
set j 0
}
{
$j
< $num
}
{
incr j
}
{
# Use hashtag valid for shard #0
set key
"{ch3}
$j
"
R $primary_id set $key $value
}
R $primary_id exec
# The replica should reconnect and start a full sync, it will gossip about it's health to the primary.
wait_for_condition 50 1000
{
"loading"
eq
[
dict get
[
get_node_info_from_shard $replica_cluster_id $primary_id
"node"
]
health
]
}
else
{
fail
"Replica never transitioned to loading"
}
# Speed up the key loading and verify everything resumes
R $replica_id config set key-load-delay 0
wait_for_condition 50 1000
{
"online"
eq
[
dict get
[
get_node_info_from_shard $replica_cluster_id $primary_id
"node"
]
health
]
}
else
{
fail
"Replica never transitioned to online"
}
# Final sanity, the replica agrees it is online.
assert_equal
"online"
[
dict get
[
get_node_info_from_shard $replica_cluster_id $replica_id
"node"
]
health
]
}
\ No newline at end of file
tests/integration/redis-cli.tcl
View file @
fb4e0d40
...
@@ -228,6 +228,30 @@ start_server {tags {"cli"}} {
...
@@ -228,6 +228,30 @@ start_server {tags {"cli"}} {
file delete $tmpfile
file delete $tmpfile
}
}
test_tty_cli
"Escape character in JSON mode"
{
# reverse solidus
r hset solidus
\/
\/
assert_equal
\/
\/
[
run_cli hgetall solidus
]
set escaped_reverse_solidus
\"\\
"
assert_equal
$escaped
_reverse_solidus
$escaped
_reverse_solidus
[
run_cli --json hgetall
\/
]
# non printable (0xF0 in ISO-8859-1, not UTF-8(0xC3 0xB0))
set eth "
\u00f0\u0065
"
r hset eth test
$eth
assert_equal
\"\\
xf0e
\"
[
run_cli hget eth test
]
assert_equal
\"\u00f0
e
\"
[
run_cli --json hget eth test
]
assert_equal
\"\\\\
xf0e
\"
[
run_cli --quoted-json hget eth test
]
# control characters
r hset control test "
Hello
\x00\x01\x02\x03
World
"
assert_equal
\"
Hello
\\
u0000
\\
u0001
\\
u0002
\\
u0003World"
[
run_cli --json hget control test
]
# non-string keys
r hset numkey 1 One
assert_equal
\{\"
1
\"
:
\"
One
\"\}
[
run_cli --json hgetall numkey
]
# non-string, non-printable keys
r hset npkey
"K
\u0000\u0001
ey"
"V
\u0000\u0001
alue"
assert_equal
\{\"
K
\\
u0000
\\
u0001ey
\"
:
\"
V
\\
u0000
\\
u0001alue
\"\}
[
run_cli --json hgetall npkey
]
assert_equal
\{\"
K
\\\\
x00
\\\\
x01ey
\"
:
\"
V
\\\\
x00
\\\\
x01alue
\"\}
[
run_cli --quoted-json hgetall npkey
]
}
test_nontty_cli
"Status reply"
{
test_nontty_cli
"Status reply"
{
assert_equal
"OK"
[
run_cli set key bar
]
assert_equal
"OK"
[
run_cli set key bar
]
assert_equal
"bar"
[
r get key
]
assert_equal
"bar"
[
r get key
]
...
@@ -322,7 +346,7 @@ if {!$::tls} { ;# fake_redis_node doesn't support TLS
...
@@ -322,7 +346,7 @@ if {!$::tls} { ;# fake_redis_node doesn't support TLS
set dir
[
lindex
[
r config get dir
]
1
]
set dir
[
lindex
[
r config get dir
]
1
]
assert_equal
"OK"
[
r debug populate 100000 key 1000
]
assert_equal
"OK"
[
r debug populate 100000 key 1000
]
assert_equal
"
OK
"
[
r function load lua lib1
"
redis.register_function('func1', function() return 123 end)"
]
assert_equal
"
lib1
"
[
r function load
"#!
lua
name=
lib1
\n
redis.register_function('func1', function() return 123 end)"
]
if
{
$functions
_only
}
{
if
{
$functions
_only
}
{
set args
"--functions-rdb
$dir
/cli.rdb"
set args
"--functions-rdb
$dir
/cli.rdb"
}
else
{
}
else
{
...
@@ -335,10 +359,10 @@ if {!$::tls} { ;# fake_redis_node doesn't support TLS
...
@@ -335,10 +359,10 @@ if {!$::tls} { ;# fake_redis_node doesn't support TLS
file rename
"
$dir
/cli.rdb"
"
$dir
/dump.rdb"
file rename
"
$dir
/cli.rdb"
"
$dir
/dump.rdb"
assert_equal
"OK"
[
r set should-not-exist 1
]
assert_equal
"OK"
[
r set should-not-exist 1
]
assert_equal
"
OK
"
[
r function load lua should_not_exist_func
"
redis.register_function('should_not_exist_func', function() return 456 end)"
]
assert_equal
"
should_not_exist_func
"
[
r function load
"#!
lua
name=
should_not_exist_func
\n
redis.register_function('should_not_exist_func', function() return 456 end)"
]
assert_equal
"OK"
[
r debug reload nosave
]
assert_equal
"OK"
[
r debug reload nosave
]
assert_equal
{}
[
r get should-not-exist
]
assert_equal
{}
[
r get should-not-exist
]
assert_equal
{{
library_name lib1 engine LUA
description
{}
functions
{{
name func1 description
{}
flags
{}}}}}
[
r function list
]
assert_equal
{{
library_name lib1 engine LUA functions
{{
name func1 description
{}
flags
{}}}}}
[
r function list
]
if
{
$functions
_only
}
{
if
{
$functions
_only
}
{
assert_equal 0
[
r dbsize
]
assert_equal 0
[
r dbsize
]
}
else
{
}
else
{
...
...
tests/integration/replication-4.tcl
View file @
fb4e0d40
...
@@ -47,7 +47,7 @@ start_server {tags {"repl external:skip"}} {
...
@@ -47,7 +47,7 @@ start_server {tags {"repl external:skip"}} {
set slave
[
srv 0 client
]
set slave
[
srv 0 client
]
# Load some functions to be used later
# Load some functions to be used later
$master FUNCTION load
lua test
replace
{
$master FUNCTION load replace
{
#!lua name=test
redis.register_function
{
function_name='f_default_flags', callback=function
(
keys, args
)
return redis.call
(
'get',keys
[
1
])
end, flags=
{}}
redis.register_function
{
function_name='f_default_flags', callback=function
(
keys, args
)
return redis.call
(
'get',keys
[
1
])
end, flags=
{}}
redis.register_function
{
function_name='f_no_writes', callback=function
(
keys, args
)
return redis.call
(
'get',keys
[
1
])
end, flags=
{
'no-writes'
}}
redis.register_function
{
function_name='f_no_writes', callback=function
(
keys, args
)
return redis.call
(
'get',keys
[
1
])
end, flags=
{
'no-writes'
}}
}
}
...
...
tests/integration/replication.tcl
View file @
fb4e0d40
...
@@ -523,10 +523,14 @@ foreach testType {Successful Aborted} {
...
@@ -523,10 +523,14 @@ foreach testType {Successful Aborted} {
$replica set mykey myvalue
$replica set mykey myvalue
# Set a function value on replica to check status during loading, on failure and after swapping db
# Set a function value on replica to check status during loading, on failure and after swapping db
$replica function load LUA test
{
redis.register_function
(
'test', function
()
return 'hello1' end
)}
$replica function load
{
#!lua name=test
redis.register_function
(
'test', function
()
return 'hello1' end
)
}
# Set a function value on master to check it reaches the replica when replication ends
# Set a function value on master to check it reaches the replica when replication ends
$master function load LUA test
{
redis.register_function
(
'test', function
()
return 'hello2' end
)}
$master function load
{
#!lua name=test
redis.register_function
(
'test', function
()
return 'hello2' end
)
}
# Force the replica to try another full sync
(
this time it will have matching master replid
)
# Force the replica to try another full sync
(
this time it will have matching master replid
)
$master multi
$master multi
...
@@ -659,7 +663,9 @@ test {diskless loading short read} {
...
@@ -659,7 +663,9 @@ test {diskless loading short read} {
set start
[
clock clicks -milliseconds
]
set start
[
clock clicks -milliseconds
]
# Set a function value to check short read handling on functions
# Set a function value to check short read handling on functions
r function load LUA test
{
redis.register_function
(
'test', function
()
return 'hello1' end
)}
r function load
{
#!lua name=test
redis.register_function
(
'test', function
()
return 'hello1' end
)
}
for
{
set k 0
}
{
$k
< 3
}
{
incr k
}
{
for
{
set k 0
}
{
$k
< 3
}
{
incr k
}
{
for
{
set i 0
}
{
$i
< 10
}
{
incr i
}
{
for
{
set i 0
}
{
$i
< 10
}
{
incr i
}
{
...
...
tests/modules/Makefile
View file @
fb4e0d40
...
@@ -54,7 +54,9 @@ TEST_MODULES = \
...
@@ -54,7 +54,9 @@ TEST_MODULES = \
subcommands.so
\
subcommands.so
\
reply.so
\
reply.so
\
cmdintrospection.so
\
cmdintrospection.so
\
eventloop.so
eventloop.so
\
moduleconfigs.so
\
moduleconfigstwo.so
.PHONY
:
all
.PHONY
:
all
...
...
tests/modules/aclcheck.c
View file @
fb4e0d40
...
@@ -136,6 +136,22 @@ int rm_call_aclcheck_cmd_module_user(RedisModuleCtx *ctx, RedisModuleString **ar
...
@@ -136,6 +136,22 @@ int rm_call_aclcheck_cmd_module_user(RedisModuleCtx *ctx, RedisModuleString **ar
return
res
;
return
res
;
}
}
int
rm_call_aclcheck_with_errors
(
RedisModuleCtx
*
ctx
,
RedisModuleString
**
argv
,
int
argc
){
REDISMODULE_NOT_USED
(
argv
);
REDISMODULE_NOT_USED
(
argc
);
if
(
argc
<
2
){
return
RedisModule_WrongArity
(
ctx
);
}
const
char
*
cmd
=
RedisModule_StringPtrLen
(
argv
[
1
],
NULL
);
RedisModuleCallReply
*
rep
=
RedisModule_Call
(
ctx
,
cmd
,
"vEC"
,
argv
+
2
,
argc
-
2
);
RedisModule_ReplyWithCallReply
(
ctx
,
rep
);
RedisModule_FreeCallReply
(
rep
);
return
REDISMODULE_OK
;
}
/* A wrap for RM_Call that pass the 'C' flag to do ACL check on the command. */
/* A wrap for RM_Call that pass the 'C' flag to do ACL check on the command. */
int
rm_call_aclcheck
(
RedisModuleCtx
*
ctx
,
RedisModuleString
**
argv
,
int
argc
){
int
rm_call_aclcheck
(
RedisModuleCtx
*
ctx
,
RedisModuleString
**
argv
,
int
argc
){
REDISMODULE_NOT_USED
(
argv
);
REDISMODULE_NOT_USED
(
argv
);
...
@@ -190,5 +206,9 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
...
@@ -190,5 +206,9 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
"write"
,
0
,
0
,
0
)
==
REDISMODULE_ERR
)
"write"
,
0
,
0
,
0
)
==
REDISMODULE_ERR
)
return
REDISMODULE_ERR
;
return
REDISMODULE_ERR
;
if
(
RedisModule_CreateCommand
(
ctx
,
"aclcheck.rm_call_with_errors"
,
rm_call_aclcheck_with_errors
,
"write"
,
0
,
0
,
0
)
==
REDISMODULE_ERR
)
return
REDISMODULE_ERR
;
return
REDISMODULE_OK
;
return
REDISMODULE_OK
;
}
}
tests/modules/auth.c
View file @
fb4e0d40
...
@@ -54,6 +54,16 @@ int Auth_AuthRealUser(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
...
@@ -54,6 +54,16 @@ int Auth_AuthRealUser(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
return
RedisModule_ReplyWithLongLong
(
ctx
,
(
uint64_t
)
client_id
);
return
RedisModule_ReplyWithLongLong
(
ctx
,
(
uint64_t
)
client_id
);
}
}
/* This command redacts every other arguments and returns OK */
int
Auth_RedactedAPI
(
RedisModuleCtx
*
ctx
,
RedisModuleString
**
argv
,
int
argc
)
{
REDISMODULE_NOT_USED
(
argv
);
for
(
int
i
=
argc
-
1
;
i
>
0
;
i
-=
2
)
{
int
result
=
RedisModule_RedactClientCommandArgument
(
ctx
,
i
);
RedisModule_Assert
(
result
==
REDISMODULE_OK
);
}
return
RedisModule_ReplyWithSimpleString
(
ctx
,
"OK"
);
}
int
Auth_ChangeCount
(
RedisModuleCtx
*
ctx
,
RedisModuleString
**
argv
,
int
argc
)
{
int
Auth_ChangeCount
(
RedisModuleCtx
*
ctx
,
RedisModuleString
**
argv
,
int
argc
)
{
REDISMODULE_NOT_USED
(
argv
);
REDISMODULE_NOT_USED
(
argv
);
REDISMODULE_NOT_USED
(
argc
);
REDISMODULE_NOT_USED
(
argc
);
...
@@ -87,6 +97,10 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
...
@@ -87,6 +97,10 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
Auth_ChangeCount
,
""
,
0
,
0
,
0
)
==
REDISMODULE_ERR
)
Auth_ChangeCount
,
""
,
0
,
0
,
0
)
==
REDISMODULE_ERR
)
return
REDISMODULE_ERR
;
return
REDISMODULE_ERR
;
if
(
RedisModule_CreateCommand
(
ctx
,
"auth.redact"
,
Auth_RedactedAPI
,
""
,
0
,
0
,
0
)
==
REDISMODULE_ERR
)
return
REDISMODULE_ERR
;
return
REDISMODULE_OK
;
return
REDISMODULE_OK
;
}
}
...
...
tests/modules/basics.c
View file @
fb4e0d40
...
@@ -718,6 +718,25 @@ end:
...
@@ -718,6 +718,25 @@ end:
/* Return 1 if the reply matches the specified string, otherwise log errors
/* Return 1 if the reply matches the specified string, otherwise log errors
* in the server log and return 0. */
* in the server log and return 0. */
int
TestAssertErrorReply
(
RedisModuleCtx
*
ctx
,
RedisModuleCallReply
*
reply
,
char
*
str
,
size_t
len
)
{
RedisModuleString
*
mystr
,
*
expected
;
if
(
RedisModule_CallReplyType
(
reply
)
!=
REDISMODULE_REPLY_ERROR
)
{
return
0
;
}
mystr
=
RedisModule_CreateStringFromCallReply
(
reply
);
expected
=
RedisModule_CreateString
(
ctx
,
str
,
len
);
if
(
RedisModule_StringCompare
(
mystr
,
expected
)
!=
0
)
{
const
char
*
mystr_ptr
=
RedisModule_StringPtrLen
(
mystr
,
NULL
);
const
char
*
expected_ptr
=
RedisModule_StringPtrLen
(
expected
,
NULL
);
RedisModule_Log
(
ctx
,
"warning"
,
"Unexpected Error reply reply '%s' (instead of '%s')"
,
mystr_ptr
,
expected_ptr
);
return
0
;
}
return
1
;
}
int
TestAssertStringReply
(
RedisModuleCtx
*
ctx
,
RedisModuleCallReply
*
reply
,
char
*
str
,
size_t
len
)
{
int
TestAssertStringReply
(
RedisModuleCtx
*
ctx
,
RedisModuleCallReply
*
reply
,
char
*
str
,
size_t
len
)
{
RedisModuleString
*
mystr
,
*
expected
;
RedisModuleString
*
mystr
,
*
expected
;
...
@@ -846,6 +865,18 @@ int TestBasics(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
...
@@ -846,6 +865,18 @@ int TestBasics(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
if
(
!
TestAssertStringReply
(
ctx
,
RedisModule_CallReplyArrayElement
(
reply
,
0
),
"test"
,
4
))
goto
fail
;
if
(
!
TestAssertStringReply
(
ctx
,
RedisModule_CallReplyArrayElement
(
reply
,
0
),
"test"
,
4
))
goto
fail
;
if
(
!
TestAssertStringReply
(
ctx
,
RedisModule_CallReplyArrayElement
(
reply
,
1
),
"1234"
,
4
))
goto
fail
;
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
;
T
(
"set"
,
"Ec"
,
"x"
);
if
(
!
TestAssertErrorReply
(
ctx
,
reply
,
"ERR Wrong number of args calling Redis command 'set'."
,
53
))
goto
fail
;
T
(
"shutdown"
,
"SE"
);
if
(
!
TestAssertErrorReply
(
ctx
,
reply
,
"ERR command 'shutdown' is not allowed on script mode"
,
52
))
goto
fail
;
T
(
"set"
,
"WEcc"
,
"x"
,
"1"
);
if
(
!
TestAssertErrorReply
(
ctx
,
reply
,
"ERR Write command 'set' was called while write is not allowed."
,
62
))
goto
fail
;
RedisModule_ReplyWithSimpleString
(
ctx
,
"ALL TESTS PASSED"
);
RedisModule_ReplyWithSimpleString
(
ctx
,
"ALL TESTS PASSED"
);
return
REDISMODULE_OK
;
return
REDISMODULE_OK
;
...
...
tests/modules/blockedclient.c
View file @
fb4e0d40
...
@@ -195,7 +195,7 @@ int do_rm_call(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){
...
@@ -195,7 +195,7 @@ int do_rm_call(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){
const
char
*
cmd
=
RedisModule_StringPtrLen
(
argv
[
1
],
NULL
);
const
char
*
cmd
=
RedisModule_StringPtrLen
(
argv
[
1
],
NULL
);
RedisModuleCallReply
*
rep
=
RedisModule_Call
(
ctx
,
cmd
,
"v"
,
argv
+
2
,
argc
-
2
);
RedisModuleCallReply
*
rep
=
RedisModule_Call
(
ctx
,
cmd
,
"
E
v"
,
argv
+
2
,
argc
-
2
);
if
(
!
rep
){
if
(
!
rep
){
RedisModule_ReplyWithError
(
ctx
,
"NULL reply returned"
);
RedisModule_ReplyWithError
(
ctx
,
"NULL reply returned"
);
}
else
{
}
else
{
...
...
tests/modules/blockonkeys.c
View file @
fb4e0d40
...
@@ -135,22 +135,29 @@ int bpop_timeout_callback(RedisModuleCtx *ctx, RedisModuleString **argv, int arg
...
@@ -135,22 +135,29 @@ int bpop_timeout_callback(RedisModuleCtx *ctx, RedisModuleString **argv, int arg
return
RedisModule_ReplyWithSimpleString
(
ctx
,
"Request timedout"
);
return
RedisModule_ReplyWithSimpleString
(
ctx
,
"Request timedout"
);
}
}
/* FSL.BPOP <key> <timeout> - Block clients until list has two or more elements.
/* FSL.BPOP <key> <timeout>
[NO_TO_CB]
- Block clients until list has two or more elements.
* When that happens, unblock client and pop the last two elements (from the right). */
* When that happens, unblock client and pop the last two elements (from the right). */
int
fsl_bpop
(
RedisModuleCtx
*
ctx
,
RedisModuleString
**
argv
,
int
argc
)
{
int
fsl_bpop
(
RedisModuleCtx
*
ctx
,
RedisModuleString
**
argv
,
int
argc
)
{
if
(
argc
!=
3
)
if
(
argc
<
3
)
return
RedisModule_WrongArity
(
ctx
);
return
RedisModule_WrongArity
(
ctx
);
long
long
timeout
;
long
long
timeout
;
if
(
RedisModule_StringToLongLong
(
argv
[
2
],
&
timeout
)
!=
REDISMODULE_OK
||
timeout
<
0
)
if
(
RedisModule_StringToLongLong
(
argv
[
2
],
&
timeout
)
!=
REDISMODULE_OK
||
timeout
<
0
)
return
RedisModule_ReplyWithError
(
ctx
,
"ERR invalid timeout"
);
return
RedisModule_ReplyWithError
(
ctx
,
"ERR invalid timeout"
);
int
to_cb
=
1
;
if
(
argc
==
4
)
{
if
(
strcasecmp
(
"NO_TO_CB"
,
RedisModule_StringPtrLen
(
argv
[
3
],
NULL
)))
return
RedisModule_ReplyWithError
(
ctx
,
"ERR invalid argument"
);
to_cb
=
0
;
}
fsl_t
*
fsl
;
fsl_t
*
fsl
;
if
(
!
get_fsl
(
ctx
,
argv
[
1
],
REDISMODULE_READ
,
0
,
&
fsl
,
1
))
if
(
!
get_fsl
(
ctx
,
argv
[
1
],
REDISMODULE_READ
,
0
,
&
fsl
,
1
))
return
REDISMODULE_OK
;
return
REDISMODULE_OK
;
if
(
!
fsl
)
{
if
(
!
fsl
)
{
RedisModule_BlockClientOnKeys
(
ctx
,
bpop_reply_callback
,
bpop_timeout_callback
,
RedisModule_BlockClientOnKeys
(
ctx
,
bpop_reply_callback
,
to_cb
?
bpop_timeout_callback
:
NULL
,
NULL
,
timeout
,
&
argv
[
1
],
1
,
NULL
);
NULL
,
timeout
,
&
argv
[
1
],
1
,
NULL
);
}
else
{
}
else
{
RedisModule_ReplyWithLongLong
(
ctx
,
fsl
->
list
[
--
fsl
->
length
]);
RedisModule_ReplyWithLongLong
(
ctx
,
fsl
->
list
[
--
fsl
->
length
]);
...
...
tests/modules/eventloop.c
View file @
fb4e0d40
...
@@ -11,7 +11,6 @@
...
@@ -11,7 +11,6 @@
* 4- test.oneshot : Test for oneshot API
* 4- test.oneshot : Test for oneshot API
*/
*/
#define REDISMODULE_EXPERIMENTAL_API
#include "redismodule.h"
#include "redismodule.h"
#include <stdlib.h>
#include <stdlib.h>
#include <unistd.h>
#include <unistd.h>
...
...
tests/modules/hooks.c
View file @
fb4e0d40
...
@@ -267,6 +267,18 @@ void swapDbCallback(RedisModuleCtx *ctx, RedisModuleEvent e, uint64_t sub, void
...
@@ -267,6 +267,18 @@ void swapDbCallback(RedisModuleCtx *ctx, RedisModuleEvent e, uint64_t sub, void
LogNumericEvent
(
ctx
,
"swapdb-second"
,
ei
->
dbnum_second
);
LogNumericEvent
(
ctx
,
"swapdb-second"
,
ei
->
dbnum_second
);
}
}
void
configChangeCallback
(
RedisModuleCtx
*
ctx
,
RedisModuleEvent
e
,
uint64_t
sub
,
void
*
data
)
{
REDISMODULE_NOT_USED
(
e
);
if
(
sub
!=
REDISMODULE_SUBEVENT_CONFIG_CHANGE
)
{
return
;
}
RedisModuleConfigChangeV1
*
ei
=
data
;
LogNumericEvent
(
ctx
,
"config-change-count"
,
ei
->
num_changes
);
LogStringEvent
(
ctx
,
"config-change-first"
,
ei
->
config_names
[
0
]);
}
/* This function must be present on each Redis module. It is used in order to
/* This function must be present on each Redis module. It is used in order to
* register the commands into the Redis server. */
* register the commands into the Redis server. */
int
RedisModule_OnLoad
(
RedisModuleCtx
*
ctx
,
RedisModuleString
**
argv
,
int
argc
)
{
int
RedisModule_OnLoad
(
RedisModuleCtx
*
ctx
,
RedisModuleString
**
argv
,
int
argc
)
{
...
@@ -317,6 +329,9 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
...
@@ -317,6 +329,9 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
RedisModule_SubscribeToServerEvent
(
ctx
,
RedisModule_SubscribeToServerEvent
(
ctx
,
RedisModuleEvent_SwapDB
,
swapDbCallback
);
RedisModuleEvent_SwapDB
,
swapDbCallback
);
RedisModule_SubscribeToServerEvent
(
ctx
,
RedisModuleEvent_Config
,
configChangeCallback
);
event_log
=
RedisModule_CreateDict
(
ctx
);
event_log
=
RedisModule_CreateDict
(
ctx
);
if
(
RedisModule_CreateCommand
(
ctx
,
"hooks.event_count"
,
cmdEventCount
,
""
,
0
,
0
,
0
)
==
REDISMODULE_ERR
)
if
(
RedisModule_CreateCommand
(
ctx
,
"hooks.event_count"
,
cmdEventCount
,
""
,
0
,
0
,
0
)
==
REDISMODULE_ERR
)
...
...
tests/modules/moduleconfigs.c
0 → 100644
View file @
fb4e0d40
#include "redismodule.h"
#include <strings.h>
int
mutable_bool_val
;
int
immutable_bool_val
;
long
long
longval
;
long
long
memval
;
RedisModuleString
*
strval
=
NULL
;
int
enumval
;
/* 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
* use names if they wanted, and store anything in privdata. */
int
getBoolConfigCommand
(
const
char
*
name
,
void
*
privdata
)
{
REDISMODULE_NOT_USED
(
name
);
return
(
*
(
int
*
)
privdata
);
}
int
setBoolConfigCommand
(
const
char
*
name
,
int
new
,
void
*
privdata
,
RedisModuleString
**
err
)
{
REDISMODULE_NOT_USED
(
name
);
REDISMODULE_NOT_USED
(
err
);
*
(
int
*
)
privdata
=
new
;
return
REDISMODULE_OK
;
}
long
long
getNumericConfigCommand
(
const
char
*
name
,
void
*
privdata
)
{
REDISMODULE_NOT_USED
(
name
);
return
(
*
(
long
long
*
)
privdata
);
}
int
setNumericConfigCommand
(
const
char
*
name
,
long
long
new
,
void
*
privdata
,
RedisModuleString
**
err
)
{
REDISMODULE_NOT_USED
(
name
);
REDISMODULE_NOT_USED
(
err
);
*
(
long
long
*
)
privdata
=
new
;
return
REDISMODULE_OK
;
}
RedisModuleString
*
getStringConfigCommand
(
const
char
*
name
,
void
*
privdata
)
{
REDISMODULE_NOT_USED
(
name
);
REDISMODULE_NOT_USED
(
privdata
);
return
strval
;
}
int
setStringConfigCommand
(
const
char
*
name
,
RedisModuleString
*
new
,
void
*
privdata
,
RedisModuleString
**
err
)
{
REDISMODULE_NOT_USED
(
name
);
REDISMODULE_NOT_USED
(
err
);
REDISMODULE_NOT_USED
(
privdata
);
size_t
len
;
if
(
!
strcasecmp
(
RedisModule_StringPtrLen
(
new
,
&
len
),
"rejectisfreed"
))
{
*
err
=
RedisModule_CreateString
(
NULL
,
"Cannot set string to 'rejectisfreed'"
,
36
);
return
REDISMODULE_ERR
;
}
if
(
strval
)
RedisModule_FreeString
(
NULL
,
strval
);
RedisModule_RetainString
(
NULL
,
new
);
strval
=
new
;
return
REDISMODULE_OK
;
}
int
getEnumConfigCommand
(
const
char
*
name
,
void
*
privdata
)
{
REDISMODULE_NOT_USED
(
name
);
REDISMODULE_NOT_USED
(
privdata
);
return
enumval
;
}
int
setEnumConfigCommand
(
const
char
*
name
,
int
val
,
void
*
privdata
,
RedisModuleString
**
err
)
{
REDISMODULE_NOT_USED
(
name
);
REDISMODULE_NOT_USED
(
err
);
REDISMODULE_NOT_USED
(
privdata
);
enumval
=
val
;
return
REDISMODULE_OK
;
}
int
boolApplyFunc
(
RedisModuleCtx
*
ctx
,
void
*
privdata
,
RedisModuleString
**
err
)
{
REDISMODULE_NOT_USED
(
ctx
);
REDISMODULE_NOT_USED
(
privdata
);
if
(
mutable_bool_val
&&
immutable_bool_val
)
{
*
err
=
RedisModule_CreateString
(
NULL
,
"Bool configs cannot both be yes."
,
32
);
return
REDISMODULE_ERR
;
}
return
REDISMODULE_OK
;
}
int
longlongApplyFunc
(
RedisModuleCtx
*
ctx
,
void
*
privdata
,
RedisModuleString
**
err
)
{
REDISMODULE_NOT_USED
(
ctx
);
REDISMODULE_NOT_USED
(
privdata
);
if
(
longval
==
memval
)
{
*
err
=
RedisModule_CreateString
(
NULL
,
"These configs cannot equal each other."
,
38
);
return
REDISMODULE_ERR
;
}
return
REDISMODULE_OK
;
}
int
RedisModule_OnLoad
(
RedisModuleCtx
*
ctx
,
RedisModuleString
**
argv
,
int
argc
)
{
REDISMODULE_NOT_USED
(
argv
);
REDISMODULE_NOT_USED
(
argc
);
if
(
RedisModule_Init
(
ctx
,
"moduleconfigs"
,
1
,
REDISMODULE_APIVER_1
)
==
REDISMODULE_ERR
)
return
REDISMODULE_ERR
;
if
(
RedisModule_RegisterBoolConfig
(
ctx
,
"mutable_bool"
,
1
,
REDISMODULE_CONFIG_DEFAULT
,
getBoolConfigCommand
,
setBoolConfigCommand
,
boolApplyFunc
,
&
mutable_bool_val
)
==
REDISMODULE_ERR
)
{
return
REDISMODULE_ERR
;
}
/* Immutable config here. */
if
(
RedisModule_RegisterBoolConfig
(
ctx
,
"immutable_bool"
,
0
,
REDISMODULE_CONFIG_IMMUTABLE
,
getBoolConfigCommand
,
setBoolConfigCommand
,
boolApplyFunc
,
&
immutable_bool_val
)
==
REDISMODULE_ERR
)
{
return
REDISMODULE_ERR
;
}
if
(
RedisModule_RegisterStringConfig
(
ctx
,
"string"
,
"secret password"
,
REDISMODULE_CONFIG_DEFAULT
,
getStringConfigCommand
,
setStringConfigCommand
,
NULL
,
NULL
)
==
REDISMODULE_ERR
)
{
return
REDISMODULE_ERR
;
}
/* 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
};
if
(
RedisModule_RegisterEnumConfig
(
ctx
,
"enum"
,
0
,
REDISMODULE_CONFIG_DEFAULT
,
enum_vals
,
int_vals
,
3
,
getEnumConfigCommand
,
setEnumConfigCommand
,
NULL
,
NULL
)
==
REDISMODULE_ERR
)
{
return
REDISMODULE_ERR
;
}
/* Memory config here. */
if
(
RedisModule_RegisterNumericConfig
(
ctx
,
"memory_numeric"
,
1024
,
REDISMODULE_CONFIG_DEFAULT
|
REDISMODULE_CONFIG_MEMORY
,
0
,
3000000
,
getNumericConfigCommand
,
setNumericConfigCommand
,
longlongApplyFunc
,
&
memval
)
==
REDISMODULE_ERR
)
{
return
REDISMODULE_ERR
;
}
if
(
RedisModule_RegisterNumericConfig
(
ctx
,
"numeric"
,
-
1
,
REDISMODULE_CONFIG_DEFAULT
,
-
5
,
2000
,
getNumericConfigCommand
,
setNumericConfigCommand
,
longlongApplyFunc
,
&
longval
)
==
REDISMODULE_ERR
)
{
return
REDISMODULE_ERR
;
}
size_t
len
;
if
(
argc
&&
!
strcasecmp
(
RedisModule_StringPtrLen
(
argv
[
0
],
&
len
),
"noload"
))
{
return
REDISMODULE_OK
;
}
else
if
(
RedisModule_LoadConfigs
(
ctx
)
==
REDISMODULE_ERR
)
{
if
(
strval
)
{
RedisModule_FreeString
(
ctx
,
strval
);
strval
=
NULL
;
}
return
REDISMODULE_ERR
;
}
return
REDISMODULE_OK
;
}
int
RedisModule_OnUnload
(
RedisModuleCtx
*
ctx
)
{
REDISMODULE_NOT_USED
(
ctx
);
if
(
strval
)
{
RedisModule_FreeString
(
ctx
,
strval
);
strval
=
NULL
;
}
return
REDISMODULE_OK
;
}
\ No newline at end of file
tests/modules/moduleconfigstwo.c
0 → 100644
View file @
fb4e0d40
#include "redismodule.h"
#include <strings.h>
/* Second module configs module, for testing.
* Need to make sure that multiple modules with configs don't interfere with each other */
int
bool_config
;
int
getBoolConfigCommand
(
const
char
*
name
,
void
*
privdata
)
{
REDISMODULE_NOT_USED
(
privdata
);
if
(
!
strcasecmp
(
name
,
"test"
))
{
return
bool_config
;
}
return
0
;
}
int
setBoolConfigCommand
(
const
char
*
name
,
int
new
,
void
*
privdata
,
RedisModuleString
**
err
)
{
REDISMODULE_NOT_USED
(
privdata
);
REDISMODULE_NOT_USED
(
err
);
if
(
!
strcasecmp
(
name
,
"test"
))
{
bool_config
=
new
;
return
REDISMODULE_OK
;
}
return
REDISMODULE_ERR
;
}
/* No arguments are expected */
int
RedisModule_OnLoad
(
RedisModuleCtx
*
ctx
,
RedisModuleString
**
argv
,
int
argc
)
{
REDISMODULE_NOT_USED
(
argv
);
REDISMODULE_NOT_USED
(
argc
);
if
(
RedisModule_Init
(
ctx
,
"configs"
,
1
,
REDISMODULE_APIVER_1
)
==
REDISMODULE_ERR
)
return
REDISMODULE_ERR
;
if
(
RedisModule_RegisterBoolConfig
(
ctx
,
"test"
,
1
,
REDISMODULE_CONFIG_DEFAULT
,
getBoolConfigCommand
,
setBoolConfigCommand
,
NULL
,
&
argc
)
==
REDISMODULE_ERR
)
{
return
REDISMODULE_ERR
;
}
if
(
RedisModule_LoadConfigs
(
ctx
)
==
REDISMODULE_ERR
)
{
return
REDISMODULE_ERR
;
}
return
REDISMODULE_OK
;
}
\ No newline at end of file
tests/sentinel/tests/03-runtime-reconf.tcl
View file @
fb4e0d40
...
@@ -2,6 +2,162 @@
...
@@ -2,6 +2,162 @@
source
"../tests/includes/init-tests.tcl"
source
"../tests/includes/init-tests.tcl"
set num_sentinels
[
llength $::sentinel_instances
]
set num_sentinels
[
llength $::sentinel_instances
]
set ::user
"testuser"
set ::password
"secret"
proc server_set_password
{}
{
foreach_redis_id id
{
assert_equal
{
OK
}
[
R $id CONFIG SET requirepass $::password
]
assert_equal
{
OK
}
[
R $id AUTH $::password
]
assert_equal
{
OK
}
[
R $id CONFIG SET masterauth $::password
]
}
}
proc server_reset_password
{}
{
foreach_redis_id id
{
assert_equal
{
OK
}
[
R $id CONFIG SET requirepass
""
]
assert_equal
{
OK
}
[
R $id CONFIG SET masterauth
""
]
}
}
proc server_set_acl
{
id
}
{
assert_equal
{
OK
}
[
R $id ACL SETUSER $::user on >$::password allchannels +@all
]
assert_equal
{
OK
}
[
R $id ACL SETUSER default off
]
R $id CLIENT KILL USER default SKIPME no
assert_equal
{
OK
}
[
R $id AUTH $::user $::password
]
assert_equal
{
OK
}
[
R $id CONFIG SET masteruser $::user
]
assert_equal
{
OK
}
[
R $id CONFIG SET masterauth $::password
]
}
proc server_reset_acl
{
id
}
{
assert_equal
{
OK
}
[
R $id ACL SETUSER default on
]
assert_equal
{
1
}
[
R $id ACL DELUSER $::user
]
assert_equal
{
OK
}
[
R $id CONFIG SET masteruser
""
]
assert_equal
{
OK
}
[
R $id CONFIG SET masterauth
""
]
}
proc verify_sentinel_connect_replicas
{
id
}
{
foreach replica
[
S $id SENTINEL REPLICAS mymaster
]
{
if
{[
string match
"*disconnected*"
[
dict get $replica flags
]]}
{
return 0
}
}
return 1
}
proc wait_for_sentinels_connect_servers
{
{
is_connect 1
}
}
{
foreach_sentinel_id id
{
wait_for_condition 1000 50
{
[
string match
"*disconnected*"
[
dict get
[
S $id SENTINEL MASTER mymaster
]
flags
]]
!= $is_connect
}
else
{
fail
"At least some sentinel can't connect to master"
}
wait_for_condition 1000 50
{
[
verify_sentinel_connect_replicas $id
]
== $is_connect
}
else
{
fail
"At least some sentinel can't connect to replica"
}
}
}
test
"Sentinels (re)connection following SENTINEL SET mymaster auth-pass"
{
# 3 types of sentinels to test:
#
(
re
)
started while master changed pwd. Manage to connect only after setting pwd
set sent2re 0
#
(
up
)
dated in advance with master new password
set sent2up 1
#
(
un
)
touched. Yet manage to maintain
(
old
)
connection
set sent2un 2
wait_for_sentinels_connect_servers
kill_instance sentinel $sent2re
server_set_password
assert_equal
{
OK
}
[
S $sent2up SENTINEL SET mymaster auth-pass $::password
]
restart_instance sentinel $sent2re
# Verify sentinel that restarted failed to connect master
if
{
!
[
string match
"*disconnected*"
[
dict get
[
S $sent2re SENTINEL MASTER mymaster
]
flags
]]}
{
fail
"Expected to be disconnected from master due to wrong password"
}
# Update restarted sentinel with master password
assert_equal
{
OK
}
[
S $sent2re SENTINEL SET mymaster auth-pass $::password
]
# All sentinels expected to connect successfully
wait_for_sentinels_connect_servers
# remove requirepass and verify sentinels manage to connect servers
server_reset_password
wait_for_sentinels_connect_servers
# Sanity check
verify_sentinel_auto_discovery
}
test
"Sentinels (re)connection following master ACL change"
{
# Three types of sentinels to test during ACL change:
# 1.
(
re
)
started Sentinel. Manage to connect only after setting new pwd
# 2.
(
up
)
dated Sentinel, get just before ACL change the new password
# 3.
(
un
)
touched Sentinel that kept old connection with master and didn't
# set new ACL password won't persist ACL pwd change
(
unlike legacy auth-pass
)
set sent2re 0
set sent2up 1
set sent2un 2
wait_for_sentinels_connect_servers
# kill sentinel 'sent2re' and restart it after ACL change
kill_instance sentinel $sent2re
# Update sentinel 'sent2up' with new user and pwd
assert_equal
{
OK
}
[
S $sent2up SENTINEL SET mymaster auth-user $::user
]
assert_equal
{
OK
}
[
S $sent2up SENTINEL SET mymaster auth-pass $::password
]
foreach_redis_id id
{
server_set_acl $id
}
restart_instance sentinel $sent2re
# Verify sentinel that restarted failed to reconnect master
wait_for_condition 100 50
{
[
string match
"*disconnected*"
[
dict get
[
S $sent2re SENTINEL MASTER mymaster
]
flags
]]
!= 0
}
else
{
fail
"Expected: Sentinel to be disconnected from master due to wrong password"
}
# Verify sentinel with updated password managed to connect
(
wait for sentinelTimer to reconnect
)
wait_for_condition 100 50
{
[
string match
"*disconnected*"
[
dict get
[
S $sent2up SENTINEL MASTER mymaster
]
flags
]]
== 0
}
else
{
fail
"Expected: Sentinel to be connected to master"
}
# Verify sentinel untouched gets failed to connect master
if
{
!
[
string match
"*disconnected*"
[
dict get
[
S $sent2un SENTINEL MASTER mymaster
]
flags
]]}
{
fail
"Expected: Sentinel to be disconnected from master due to wrong password"
}
# Now update all sentinels with new password
foreach_sentinel_id id
{
assert_equal
{
OK
}
[
S $id SENTINEL SET mymaster auth-user $::user
]
assert_equal
{
OK
}
[
S $id SENTINEL SET mymaster auth-pass $::password
]
}
# All sentinels expected to connect successfully
wait_for_sentinels_connect_servers
# remove requirepass and verify sentinels manage to connect servers
foreach_redis_id id
{
server_reset_acl $id
}
wait_for_sentinels_connect_servers
# Sanity check
verify_sentinel_auto_discovery
}
test
"Set parameters in normal case"
{
test
"Set parameters in normal case"
{
set info
[
S 0 SENTINEL master mymaster
]
set info
[
S 0 SENTINEL master mymaster
]
...
...
tests/sentinel/tests/07-down-conditions.tcl
View file @
fb4e0d40
...
@@ -24,7 +24,6 @@ proc ensure_master_up {} {
...
@@ -24,7 +24,6 @@ proc ensure_master_up {} {
}
}
}
}
proc ensure_master_down
{}
{
proc ensure_master_down
{}
{
S $::alive_sentinel sentinel debug info-period 1000
S $::alive_sentinel sentinel debug info-period 1000
S $::alive_sentinel sentinel debug ping-period 100
S $::alive_sentinel sentinel debug ping-period 100
...
@@ -45,10 +44,14 @@ test "Crash the majority of Sentinels to prevent failovers for this unit" {
...
@@ -45,10 +44,14 @@ test "Crash the majority of Sentinels to prevent failovers for this unit" {
}
}
test
"SDOWN is triggered by non-responding but not crashed instance"
{
test
"SDOWN is triggered by non-responding but not crashed instance"
{
lassign
[
S $::alive_sentinel SENTINEL GET-MASTER-ADDR-BY-NAME mymaster
]
host port
ensure_master_up
ensure_master_up
exec ../../../src/redis-cli -h $host -p $port
{*}
[
rediscli_tls_config
"../../../tests"
]
debug sleep 3 > /dev/null &
set master_addr
[
S $::alive_sentinel SENTINEL GET-MASTER-ADDR-BY-NAME mymaster
]
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
ensure_master_down
ensure_master_down
exec kill -SIGCONT $pid
ensure_master_up
ensure_master_up
}
}
...
...
tests/sentinel/tests/08-hostname-conf.tcl
View file @
fb4e0d40
source
"../tests/includes/utils.tcl"
proc set_redis_announce_ip
{
addr
}
{
proc set_redis_announce_ip
{
addr
}
{
foreach_redis_id id
{
foreach_redis_id id
{
R $id config set replica-announce-ip $addr
R $id config set replica-announce-ip $addr
...
...
Prev
1
…
3
4
5
6
7
8
9
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment