aboutsummaryrefslogtreecommitdiff
path: root/examples/redis-unstable/tests/support/cluster_util.tcl
diff options
context:
space:
mode:
authorMitja Felicijan <mitja.felicijan@gmail.com>2026-01-21 22:52:54 +0100
committerMitja Felicijan <mitja.felicijan@gmail.com>2026-01-21 22:52:54 +0100
commitdcacc00e3750300617ba6e16eb346713f91a783a (patch)
tree38e2d4fb5ed9d119711d4295c6eda4b014af73fd /examples/redis-unstable/tests/support/cluster_util.tcl
parent58dac10aeb8f5a041c46bddbeaf4c7966a99b998 (diff)
downloadcrep-dcacc00e3750300617ba6e16eb346713f91a783a.tar.gz
Remove testing data
Diffstat (limited to 'examples/redis-unstable/tests/support/cluster_util.tcl')
-rw-r--r--examples/redis-unstable/tests/support/cluster_util.tcl264
1 files changed, 0 insertions, 264 deletions
diff --git a/examples/redis-unstable/tests/support/cluster_util.tcl b/examples/redis-unstable/tests/support/cluster_util.tcl
deleted file mode 100644
index 6b7f423..0000000
--- a/examples/redis-unstable/tests/support/cluster_util.tcl
+++ /dev/null
@@ -1,264 +0,0 @@
1#
2# Copyright (c) 2009-Present, Redis Ltd.
3# All rights reserved.
4#
5# Copyright (c) 2024-present, Valkey contributors.
6# All rights reserved.
7#
8# Licensed under your choice of (a) the Redis Source Available License 2.0
9# (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the
10# GNU Affero General Public License v3 (AGPLv3).
11#
12# Portions of this file are available under BSD3 terms; see REDISCONTRIBUTIONS for more information.
13#
14
15# Cluster helper functions
16# Normalize cluster slots configuration by sorting replicas by node ID
17proc normalize_cluster_slots {slots_config} {
18 set normalized {}
19 foreach slot_range $slots_config {
20 if {[llength $slot_range] <= 3} {
21 lappend normalized $slot_range
22 } else {
23 # Sort replicas (index 3+) by node ID, keep start/end/master unchanged
24 set replicas [lrange $slot_range 3 end]
25 set sorted_replicas [lsort -index 2 $replicas]
26 lappend normalized [concat [lrange $slot_range 0 2] $sorted_replicas]
27 }
28 }
29 return $normalized
30}
31
32# Check if cluster configuration is consistent.
33proc cluster_config_consistent {} {
34 for {set j 0} {$j < [llength $::servers]} {incr j} {
35 if {$j == 0} {
36 set base_cfg [R $j cluster slots]
37 set base_secret [R $j debug internal_secret]
38 set normalized_base_cfg [normalize_cluster_slots $base_cfg]
39 } else {
40 set cfg [R $j cluster slots]
41 set secret [R $j debug internal_secret]
42 set normalized_cfg [normalize_cluster_slots $cfg]
43 if {$normalized_cfg != $normalized_base_cfg || $secret != $base_secret} {
44 return 0
45 }
46 }
47 }
48
49 return 1
50}
51
52# Check if cluster size is consistent.
53proc cluster_size_consistent {cluster_size} {
54 for {set j 0} {$j < $cluster_size} {incr j} {
55 if {[CI $j cluster_known_nodes] ne $cluster_size} {
56 return 0
57 }
58 }
59 return 1
60}
61
62# Wait for cluster configuration to propagate and be consistent across nodes.
63proc wait_for_cluster_propagation {} {
64 wait_for_condition 50 100 {
65 [cluster_config_consistent] eq 1
66 } else {
67 fail "cluster config did not reach a consistent state"
68 }
69}
70
71# Wait for cluster size to be consistent across nodes.
72proc wait_for_cluster_size {cluster_size} {
73 wait_for_condition 1000 50 {
74 [cluster_size_consistent $cluster_size] eq 1
75 } else {
76 fail "cluster size did not reach a consistent size $cluster_size"
77 }
78}
79
80# Check that cluster nodes agree about "state", or raise an error.
81proc wait_for_cluster_state {state} {
82 for {set j 0} {$j < [llength $::servers]} {incr j} {
83 wait_for_condition 100 50 {
84 [CI $j cluster_state] eq $state
85 } else {
86 fail "Cluster node $j cluster_state:[CI $j cluster_state]"
87 }
88 }
89}
90
91# Default slot allocation for clusters, each master has a continuous block
92# and approximately equal number of slots.
93proc continuous_slot_allocation {masters} {
94 set avg [expr double(16384) / $masters]
95 set slot_start 0
96 for {set j 0} {$j < $masters} {incr j} {
97 set slot_end [expr int(ceil(($j + 1) * $avg) - 1)]
98 R $j cluster addslotsrange $slot_start $slot_end
99 set slot_start [expr $slot_end + 1]
100 }
101}
102
103# Setup method to be executed to configure the cluster before the
104# tests run.
105proc cluster_setup {masters node_count slot_allocator code} {
106 # Have all nodes meet
107 if {$::tls} {
108 set tls_cluster [lindex [R 0 CONFIG GET tls-cluster] 1]
109 }
110 if {$::tls && !$tls_cluster} {
111 for {set i 1} {$i < $node_count} {incr i} {
112 R 0 CLUSTER MEET [srv -$i host] [srv -$i pport]
113 }
114 } else {
115 for {set i 1} {$i < $node_count} {incr i} {
116 R 0 CLUSTER MEET [srv -$i host] [srv -$i port]
117 }
118 }
119
120 $slot_allocator $masters
121
122 wait_for_cluster_propagation
123
124 # Setup master/replica relationships
125 for {set i 0} {$i < $masters} {incr i} {
126 set nodeid [R $i CLUSTER MYID]
127 for {set j [expr $i + $masters]} {$j < $node_count} {incr j $masters} {
128 R $j CLUSTER REPLICATE $nodeid
129 }
130 }
131
132 wait_for_cluster_propagation
133 wait_for_cluster_state "ok"
134
135 uplevel 1 $code
136}
137
138# Start a cluster with the given number of masters and replicas. Replicas
139# will be allocated to masters by round robin.
140proc start_cluster {masters replicas options code {slot_allocator continuous_slot_allocation}} {
141 set ::cluster_master_nodes $masters
142 set ::cluster_replica_nodes $replicas
143 set node_count [expr $masters + $replicas]
144
145 # Set the final code to be the tests + cluster setup
146 set code [list cluster_setup $masters $node_count $slot_allocator $code]
147
148 # Configure the starting of multiple servers. Set cluster node timeout
149 # aggressively since many tests depend on ping/pong messages.
150 set cluster_options [list overrides [list cluster-enabled yes cluster-ping-interval 100 cluster-node-timeout 3000 cluster-slot-stats-enabled yes]]
151 set options [concat $cluster_options $options]
152
153 # Cluster mode only supports a single database, so before executing the tests
154 # it needs to be configured correctly and needs to be reset after the tests.
155 set old_singledb $::singledb
156 set ::singledb 1
157 start_multiple_servers $node_count $options $code
158 set ::singledb $old_singledb
159}
160
161# Test node for flag.
162proc cluster_has_flag {node flag} {
163 expr {[lsearch -exact [dict get $node flags] $flag] != -1}
164}
165
166# Returns the parsed "myself" node entry as a dictionary.
167proc cluster_get_myself id {
168 set nodes [get_cluster_nodes $id]
169 foreach n $nodes {
170 if {[cluster_has_flag $n myself]} {return $n}
171 }
172 return {}
173}
174
175# Returns a parsed CLUSTER NODES output as a list of dictionaries.
176proc get_cluster_nodes id {
177 set lines [split [R $id cluster nodes] "\r\n"]
178 set nodes {}
179 foreach l $lines {
180 set l [string trim $l]
181 if {$l eq {}} continue
182 set args [split $l]
183 set node [dict create \
184 id [lindex $args 0] \
185 addr [lindex $args 1] \
186 flags [split [lindex $args 2] ,] \
187 slaveof [lindex $args 3] \
188 ping_sent [lindex $args 4] \
189 pong_recv [lindex $args 5] \
190 config_epoch [lindex $args 6] \
191 linkstate [lindex $args 7] \
192 slots [lrange $args 8 end] \
193 ]
194 lappend nodes $node
195 }
196 return $nodes
197}
198
199# Returns 1 if no node knows node_id, 0 if any node knows it.
200proc node_is_forgotten {node_id} {
201 for {set j 0} {$j < [llength $::servers]} {incr j} {
202 set cluster_nodes [R $j CLUSTER NODES]
203 if { [string match "*$node_id*" $cluster_nodes] } {
204 return 0
205 }
206 }
207 return 1
208}
209
210# Isolate a node from the cluster and give it a new nodeid
211proc isolate_node {id} {
212 set node_id [R $id CLUSTER MYID]
213 R $id CLUSTER RESET HARD
214 # Here we additionally test that CLUSTER FORGET propagates to all nodes.
215 set other_id [expr $id == 0 ? 1 : 0]
216 R $other_id CLUSTER FORGET $node_id
217 wait_for_condition 50 100 {
218 [node_is_forgotten $node_id]
219 } else {
220 fail "CLUSTER FORGET was not propagated to all nodes"
221 }
222}
223
224# Check if cluster's view of hostnames is consistent
225proc are_hostnames_propagated {match_string} {
226 for {set j 0} {$j < [llength $::servers]} {incr j} {
227 set cfg [R $j cluster slots]
228 foreach node $cfg {
229 for {set i 2} {$i < [llength $node]} {incr i} {
230 if {! [string match $match_string [lindex [lindex [lindex $node $i] 3] 1]] } {
231 return 0
232 }
233 }
234 }
235 }
236 return 1
237}
238
239proc wait_node_marked_fail {ref_node_index instance_id_to_check} {
240 wait_for_condition 1000 50 {
241 [check_cluster_node_mark fail $ref_node_index $instance_id_to_check]
242 } else {
243 fail "Replica node never marked as FAIL ('fail')"
244 }
245}
246
247proc wait_node_marked_pfail {ref_node_index instance_id_to_check} {
248 wait_for_condition 1000 50 {
249 [check_cluster_node_mark fail\? $ref_node_index $instance_id_to_check]
250 } else {
251 fail "Replica node never marked as PFAIL ('fail?')"
252 }
253}
254
255proc check_cluster_node_mark {flag ref_node_index instance_id_to_check} {
256 set nodes [get_cluster_nodes $ref_node_index]
257
258 foreach n $nodes {
259 if {[dict get $n id] eq $instance_id_to_check} {
260 return [cluster_has_flag $n $flag]
261 }
262 }
263 fail "Unable to find instance id in cluster nodes. ID: $instance_id_to_check"
264}