diff options
| author | Mitja Felicijan <mitja.felicijan@gmail.com> | 2026-01-21 22:52:54 +0100 |
|---|---|---|
| committer | Mitja Felicijan <mitja.felicijan@gmail.com> | 2026-01-21 22:52:54 +0100 |
| commit | dcacc00e3750300617ba6e16eb346713f91a783a (patch) | |
| tree | 38e2d4fb5ed9d119711d4295c6eda4b014af73fd /examples/redis-unstable/tests/support/cluster_util.tcl | |
| parent | 58dac10aeb8f5a041c46bddbeaf4c7966a99b998 (diff) | |
| download | crep-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.tcl | 264 |
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 | ||
| 17 | proc 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. | ||
| 33 | proc 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. | ||
| 53 | proc 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. | ||
| 63 | proc 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. | ||
| 72 | proc 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. | ||
| 81 | proc 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. | ||
| 93 | proc 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. | ||
| 105 | proc 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. | ||
| 140 | proc 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. | ||
| 162 | proc 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. | ||
| 167 | proc 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. | ||
| 176 | proc 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. | ||
| 200 | proc 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 | ||
| 211 | proc 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 | ||
| 225 | proc 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 | |||
| 239 | proc 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 | |||
| 247 | proc 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 | |||
| 255 | proc 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 | } | ||
