github.com/unionj-cloud/go-doudou/v2@v2.3.5/toolkit/memberlist/util_test.go (about) 1 package memberlist 2 3 import ( 4 "fmt" 5 "reflect" 6 "testing" 7 "time" 8 9 "github.com/stretchr/testify/require" 10 ) 11 12 func TestUtil_PortFunctions(t *testing.T) { 13 tests := []struct { 14 addr string 15 hasPort bool 16 ensurePort string 17 }{ 18 {"1.2.3.4", false, "1.2.3.4:8301"}, 19 {"1.2.3.4:1234", true, "1.2.3.4:1234"}, 20 {"2600:1f14:e22:1501:f9a:2e0c:a167:67e8", false, "[2600:1f14:e22:1501:f9a:2e0c:a167:67e8]:8301"}, 21 {"[2600:1f14:e22:1501:f9a:2e0c:a167:67e8]", false, "[2600:1f14:e22:1501:f9a:2e0c:a167:67e8]:8301"}, 22 {"[2600:1f14:e22:1501:f9a:2e0c:a167:67e8]:1234", true, "[2600:1f14:e22:1501:f9a:2e0c:a167:67e8]:1234"}, 23 {"localhost", false, "localhost:8301"}, 24 {"localhost:1234", true, "localhost:1234"}, 25 {"hashicorp.com", false, "hashicorp.com:8301"}, 26 {"hashicorp.com:1234", true, "hashicorp.com:1234"}, 27 } 28 for _, tt := range tests { 29 t.Run(tt.addr, func(t *testing.T) { 30 if got, want := hasPort(tt.addr), tt.hasPort; got != want { 31 t.Fatalf("got %v want %v", got, want) 32 } 33 if got, want := ensurePort(tt.addr, 8301), tt.ensurePort; got != want { 34 t.Fatalf("got %v want %v", got, want) 35 } 36 }) 37 } 38 } 39 40 func TestEncodeDecode(t *testing.T) { 41 msg := &ping{SeqNo: 100} 42 buf, err := encode(pingMsg, msg) 43 if err != nil { 44 t.Fatalf("unexpected err: %s", err) 45 } 46 var out ping 47 if err := decode(buf.Bytes()[1:], &out); err != nil { 48 t.Fatalf("unexpected err: %s", err) 49 } 50 if msg.SeqNo != out.SeqNo { 51 t.Fatalf("bad sequence no") 52 } 53 } 54 55 func TestRandomOffset(t *testing.T) { 56 vals := make(map[int]struct{}) 57 for i := 0; i < 100; i++ { 58 offset := randomOffset(2 << 30) 59 if _, ok := vals[offset]; ok { 60 t.Fatalf("got collision") 61 } 62 vals[offset] = struct{}{} 63 } 64 } 65 66 func TestRandomOffset_Zero(t *testing.T) { 67 offset := randomOffset(0) 68 if offset != 0 { 69 t.Fatalf("bad offset") 70 } 71 } 72 73 func TestSuspicionTimeout(t *testing.T) { 74 timeouts := map[int]time.Duration{ 75 5: 1000 * time.Millisecond, 76 10: 1000 * time.Millisecond, 77 50: 1698 * time.Millisecond, 78 100: 2000 * time.Millisecond, 79 500: 2698 * time.Millisecond, 80 1000: 3000 * time.Millisecond, 81 } 82 for n, expected := range timeouts { 83 timeout := suspicionTimeout(3, n, time.Second) / 3 84 if timeout != expected { 85 t.Fatalf("bad: %v, %v", expected, timeout) 86 } 87 } 88 } 89 90 func TestSuspicionTimeout2(t *testing.T) { 91 timeout := suspicionTimeout(6, 6, 5*time.Second) 92 fmt.Println(timeout) 93 } 94 95 func TestRetransmitLimit(t *testing.T) { 96 lim := retransmitLimit(3, 0) 97 if lim != 0 { 98 t.Fatalf("bad val %v", lim) 99 } 100 lim = retransmitLimit(3, 1) 101 if lim != 3 { 102 t.Fatalf("bad val %v", lim) 103 } 104 lim = retransmitLimit(3, 99) 105 if lim != 6 { 106 t.Fatalf("bad val %v", lim) 107 } 108 lim = retransmitLimit(4, 15) 109 if lim != 8 { 110 t.Fatalf("bad val %v", lim) 111 } 112 } 113 114 func TestShuffleNodes(t *testing.T) { 115 orig := []*nodeState{ 116 &nodeState{ 117 State: StateDead, 118 }, 119 &nodeState{ 120 State: StateAlive, 121 }, 122 &nodeState{ 123 State: StateAlive, 124 }, 125 &nodeState{ 126 State: StateDead, 127 }, 128 &nodeState{ 129 State: StateAlive, 130 }, 131 &nodeState{ 132 State: StateAlive, 133 }, 134 &nodeState{ 135 State: StateDead, 136 }, 137 &nodeState{ 138 State: StateAlive, 139 }, 140 } 141 nodes := make([]*nodeState, len(orig)) 142 copy(nodes[:], orig[:]) 143 144 if !reflect.DeepEqual(nodes, orig) { 145 t.Fatalf("should match") 146 } 147 148 shuffleNodes(nodes) 149 } 150 151 func TestPushPullScale(t *testing.T) { 152 sec := time.Second 153 for i := 0; i <= 32; i++ { 154 if s := pushPullScale(sec, i); s != sec { 155 t.Fatalf("Bad time scale: %v", s) 156 } 157 } 158 for i := 33; i <= 64; i++ { 159 if s := pushPullScale(sec, i); s != 2*sec { 160 t.Fatalf("Bad time scale: %v", s) 161 } 162 } 163 for i := 65; i <= 128; i++ { 164 if s := pushPullScale(sec, i); s != 3*sec { 165 t.Fatalf("Bad time scale: %v", s) 166 } 167 } 168 } 169 170 func TestMoveDeadNodes(t *testing.T) { 171 nodes := []*nodeState{ 172 &nodeState{ 173 State: StateDead, 174 StateChange: time.Now().Add(-20 * time.Second), 175 }, 176 &nodeState{ 177 State: StateAlive, 178 StateChange: time.Now().Add(-20 * time.Second), 179 }, 180 // This dead node should not be moved, as its state changed 181 // less than the specified GossipToTheDead time ago 182 &nodeState{ 183 State: StateDead, 184 StateChange: time.Now().Add(-10 * time.Second), 185 }, 186 &nodeState{ 187 State: StateAlive, 188 StateChange: time.Now().Add(-20 * time.Second), 189 }, 190 &nodeState{ 191 State: StateDead, 192 StateChange: time.Now().Add(-20 * time.Second), 193 }, 194 &nodeState{ 195 State: StateAlive, 196 StateChange: time.Now().Add(-20 * time.Second), 197 }, 198 } 199 200 idx := moveDeadNodes(nodes, (15 * time.Second)) 201 if idx != 4 { 202 t.Fatalf("bad index") 203 } 204 for i := 0; i < idx; i++ { 205 switch i { 206 case 2: 207 // Recently dead node remains at index 2, 208 // since nodes are swapped out to move to end. 209 if nodes[i].State != StateDead { 210 t.Fatalf("Bad state %d", i) 211 } 212 default: 213 if nodes[i].State != StateAlive { 214 t.Fatalf("Bad state %d", i) 215 } 216 } 217 } 218 for i := idx; i < len(nodes); i++ { 219 if nodes[i].State != StateDead { 220 t.Fatalf("Bad state %d", i) 221 } 222 } 223 } 224 225 func TestKRandomNodes(t *testing.T) { 226 nodes := []*nodeState{} 227 for i := 0; i < 90; i++ { 228 // Half the nodes are in a bad state 229 state := StateAlive 230 switch i % 3 { 231 case 0: 232 state = StateAlive 233 case 1: 234 state = StateSuspect 235 case 2: 236 state = StateDead 237 } 238 nodes = append(nodes, &nodeState{ 239 Node: Node{ 240 Name: fmt.Sprintf("test%d", i), 241 }, 242 State: state, 243 }) 244 } 245 246 filterFunc := func(n *nodeState) bool { 247 if n.Name == "test0" || n.State != StateAlive { 248 return true 249 } 250 return false 251 } 252 253 s1 := kRandomNodes(3, nodes, filterFunc) 254 s2 := kRandomNodes(3, nodes, filterFunc) 255 s3 := kRandomNodes(3, nodes, filterFunc) 256 257 if reflect.DeepEqual(s1, s2) { 258 t.Fatalf("unexpected equal") 259 } 260 if reflect.DeepEqual(s1, s3) { 261 t.Fatalf("unexpected equal") 262 } 263 if reflect.DeepEqual(s2, s3) { 264 t.Fatalf("unexpected equal") 265 } 266 267 for _, s := range [][]Node{s1, s2, s3} { 268 if len(s) != 3 { 269 t.Fatalf("bad len") 270 } 271 for _, n := range s { 272 if n.Name == "test0" { 273 t.Fatalf("Bad name") 274 } 275 if n.State != StateAlive { 276 t.Fatalf("Bad state") 277 } 278 } 279 } 280 } 281 282 func TestMakeCompoundMessage(t *testing.T) { 283 msg := &ping{SeqNo: 100} 284 buf, err := encode(pingMsg, msg) 285 if err != nil { 286 t.Fatalf("unexpected err: %s", err) 287 } 288 289 msgs := [][]byte{buf.Bytes(), buf.Bytes(), buf.Bytes()} 290 compound := makeCompoundMessage(msgs) 291 292 if compound.Len() != 3*buf.Len()+3*compoundOverhead+compoundHeaderOverhead { 293 t.Fatalf("bad len") 294 } 295 } 296 297 func TestDecodeCompoundMessage(t *testing.T) { 298 msg := &ping{SeqNo: 100} 299 buf, err := encode(pingMsg, msg) 300 if err != nil { 301 t.Fatalf("unexpected err: %s", err) 302 } 303 304 msgs := [][]byte{buf.Bytes(), buf.Bytes(), buf.Bytes()} 305 compound := makeCompoundMessage(msgs) 306 307 trunc, parts, err := decodeCompoundMessage(compound.Bytes()[1:]) 308 if err != nil { 309 t.Fatalf("unexpected err: %s", err) 310 } 311 if trunc != 0 { 312 t.Fatalf("should not truncate") 313 } 314 if len(parts) != 3 { 315 t.Fatalf("bad parts") 316 } 317 for _, p := range parts { 318 if len(p) != buf.Len() { 319 t.Fatalf("bad part len") 320 } 321 } 322 } 323 324 func TestDecodeCompoundMessage_NumberOfPartsOverflow(t *testing.T) { 325 buf := []byte{0x80} 326 _, _, err := decodeCompoundMessage(buf) 327 require.Error(t, err) 328 require.Equal(t, err.Error(), "truncated len slice") 329 } 330 331 func TestDecodeCompoundMessage_Trunc(t *testing.T) { 332 msg := &ping{SeqNo: 100} 333 buf, err := encode(pingMsg, msg) 334 if err != nil { 335 t.Fatalf("unexpected err: %s", err) 336 } 337 338 msgs := [][]byte{buf.Bytes(), buf.Bytes(), buf.Bytes()} 339 compound := makeCompoundMessage(msgs) 340 341 trunc, parts, err := decodeCompoundMessage(compound.Bytes()[1:38]) 342 if err != nil { 343 t.Fatalf("unexpected err: %s", err) 344 } 345 if trunc != 1 { 346 t.Fatalf("truncate: %d", trunc) 347 } 348 if len(parts) != 2 { 349 t.Fatalf("bad parts") 350 } 351 for _, p := range parts { 352 if len(p) != buf.Len() { 353 t.Fatalf("bad part len") 354 } 355 } 356 } 357 358 func TestCompressDecompressPayload(t *testing.T) { 359 buf, err := compressPayload([]byte("testing")) 360 if err != nil { 361 t.Fatalf("unexpected err: %s", err) 362 } 363 364 decomp, err := decompressPayload(buf.Bytes()[1:]) 365 if err != nil { 366 t.Fatalf("unexpected err: %s", err) 367 } 368 369 if !reflect.DeepEqual(decomp, []byte("testing")) { 370 t.Fatalf("bad payload: %v", decomp) 371 } 372 }