github.com/sl1pm4t/consul@v1.4.5-0.20190325224627-74c31c540f9c/agent/router/manager_test.go (about) 1 package router_test 2 3 import ( 4 "fmt" 5 "log" 6 "math/rand" 7 "net" 8 "os" 9 "strings" 10 "testing" 11 12 "github.com/hashicorp/consul/agent/metadata" 13 "github.com/hashicorp/consul/agent/router" 14 ) 15 16 type fauxAddr struct { 17 addr string 18 } 19 20 func (a *fauxAddr) Network() string { 21 return "faux" 22 } 23 24 func (a *fauxAddr) String() string { 25 return a.addr 26 } 27 28 type fauxConnPool struct { 29 // failPct between 0.0 and 1.0 == pct of time a Ping should fail. 30 failPct float64 31 32 // failAddr fail whenever we see this address. 33 failAddr net.Addr 34 } 35 36 func (cp *fauxConnPool) Ping(dc string, addr net.Addr, version int, useTLS bool) (bool, error) { 37 var success bool 38 39 successProb := rand.Float64() 40 if successProb > cp.failPct { 41 success = true 42 } 43 44 if cp.failAddr != nil && addr.String() == cp.failAddr.String() { 45 success = false 46 } 47 48 return success, nil 49 } 50 51 type fauxSerf struct { 52 } 53 54 func (s *fauxSerf) NumNodes() int { 55 return 16384 56 } 57 58 func testManager() (m *router.Manager) { 59 logger := log.New(os.Stderr, "", log.LstdFlags) 60 shutdownCh := make(chan struct{}) 61 m = router.New(logger, shutdownCh, &fauxSerf{}, &fauxConnPool{}) 62 return m 63 } 64 65 func testManagerFailProb(failPct float64) (m *router.Manager) { 66 logger := log.New(os.Stderr, "", log.LstdFlags) 67 shutdownCh := make(chan struct{}) 68 m = router.New(logger, shutdownCh, &fauxSerf{}, &fauxConnPool{failPct: failPct}) 69 return m 70 } 71 72 func testManagerFailAddr(failAddr net.Addr) (m *router.Manager) { 73 logger := log.New(os.Stderr, "", log.LstdFlags) 74 shutdownCh := make(chan struct{}) 75 m = router.New(logger, shutdownCh, &fauxSerf{}, &fauxConnPool{failAddr: failAddr}) 76 return m 77 } 78 79 // func (m *Manager) AddServer(server *metadata.Server) { 80 func TestServers_AddServer(t *testing.T) { 81 m := testManager() 82 var num int 83 num = m.NumServers() 84 if num != 0 { 85 t.Fatalf("Expected zero servers to start") 86 } 87 88 s1 := &metadata.Server{Name: "s1"} 89 m.AddServer(s1) 90 num = m.NumServers() 91 if num != 1 { 92 t.Fatalf("Expected one server") 93 } 94 95 m.AddServer(s1) 96 num = m.NumServers() 97 if num != 1 { 98 t.Fatalf("Expected one server (still)") 99 } 100 101 s2 := &metadata.Server{Name: "s2"} 102 m.AddServer(s2) 103 num = m.NumServers() 104 if num != 2 { 105 t.Fatalf("Expected two servers") 106 } 107 } 108 109 // func (m *Manager) IsOffline() bool { 110 func TestServers_IsOffline(t *testing.T) { 111 m := testManager() 112 if !m.IsOffline() { 113 t.Fatalf("bad") 114 } 115 116 s1 := &metadata.Server{Name: "s1"} 117 m.AddServer(s1) 118 if m.IsOffline() { 119 t.Fatalf("bad") 120 } 121 m.RebalanceServers() 122 if m.IsOffline() { 123 t.Fatalf("bad") 124 } 125 m.RemoveServer(s1) 126 m.RebalanceServers() 127 if !m.IsOffline() { 128 t.Fatalf("bad") 129 } 130 131 const failPct = 0.5 132 m = testManagerFailProb(failPct) 133 m.AddServer(s1) 134 var on, off int 135 for i := 0; i < 100; i++ { 136 m.RebalanceServers() 137 if m.IsOffline() { 138 off++ 139 } else { 140 on++ 141 } 142 } 143 if on == 0 || off == 0 { 144 t.Fatalf("bad: %d %d", on, off) 145 } 146 } 147 148 // func (m *Manager) FindServer() (server *metadata.Server) { 149 func TestServers_FindServer(t *testing.T) { 150 m := testManager() 151 152 if m.FindServer() != nil { 153 t.Fatalf("Expected nil return") 154 } 155 156 m.AddServer(&metadata.Server{Name: "s1"}) 157 if m.NumServers() != 1 { 158 t.Fatalf("Expected one server") 159 } 160 161 s1 := m.FindServer() 162 if s1 == nil { 163 t.Fatalf("Expected non-nil server") 164 } 165 if s1.Name != "s1" { 166 t.Fatalf("Expected s1 server") 167 } 168 169 s1 = m.FindServer() 170 if s1 == nil || s1.Name != "s1" { 171 t.Fatalf("Expected s1 server (still)") 172 } 173 174 m.AddServer(&metadata.Server{Name: "s2"}) 175 if m.NumServers() != 2 { 176 t.Fatalf("Expected two servers") 177 } 178 s1 = m.FindServer() 179 if s1 == nil || s1.Name != "s1" { 180 t.Fatalf("Expected s1 server (still)") 181 } 182 183 m.NotifyFailedServer(s1) 184 s2 := m.FindServer() 185 if s2 == nil || s2.Name != "s2" { 186 t.Fatalf("Expected s2 server") 187 } 188 189 m.NotifyFailedServer(s2) 190 s1 = m.FindServer() 191 if s1 == nil || s1.Name != "s1" { 192 t.Fatalf("Expected s1 server") 193 } 194 } 195 196 // func New(logger *log.Logger, shutdownCh chan struct{}) (m *Manager) { 197 func TestServers_New(t *testing.T) { 198 logger := log.New(os.Stderr, "", log.LstdFlags) 199 shutdownCh := make(chan struct{}) 200 m := router.New(logger, shutdownCh, &fauxSerf{}, &fauxConnPool{}) 201 if m == nil { 202 t.Fatalf("Manager nil") 203 } 204 } 205 206 // func (m *Manager) NotifyFailedServer(server *metadata.Server) { 207 func TestServers_NotifyFailedServer(t *testing.T) { 208 m := testManager() 209 210 if m.NumServers() != 0 { 211 t.Fatalf("Expected zero servers to start") 212 } 213 214 s1 := &metadata.Server{Name: "s1"} 215 s2 := &metadata.Server{Name: "s2"} 216 217 // Try notifying for a server that is not managed by Manager 218 m.NotifyFailedServer(s1) 219 if m.NumServers() != 0 { 220 t.Fatalf("Expected zero servers to start") 221 } 222 m.AddServer(s1) 223 224 // Test again w/ a server not in the list 225 m.NotifyFailedServer(s2) 226 if m.NumServers() != 1 { 227 t.Fatalf("Expected one server") 228 } 229 230 m.AddServer(s2) 231 if m.NumServers() != 2 { 232 t.Fatalf("Expected two servers") 233 } 234 235 s1 = m.FindServer() 236 if s1 == nil || s1.Name != "s1" { 237 t.Fatalf("Expected s1 server") 238 } 239 240 m.NotifyFailedServer(s2) 241 s1 = m.FindServer() 242 if s1 == nil || s1.Name != "s1" { 243 t.Fatalf("Expected s1 server (still)") 244 } 245 246 m.NotifyFailedServer(s1) 247 s2 = m.FindServer() 248 if s2 == nil || s2.Name != "s2" { 249 t.Fatalf("Expected s2 server") 250 } 251 252 m.NotifyFailedServer(s2) 253 s1 = m.FindServer() 254 if s1 == nil || s1.Name != "s1" { 255 t.Fatalf("Expected s1 server") 256 } 257 } 258 259 // func (m *Manager) NumServers() (numServers int) { 260 func TestServers_NumServers(t *testing.T) { 261 m := testManager() 262 var num int 263 num = m.NumServers() 264 if num != 0 { 265 t.Fatalf("Expected zero servers to start") 266 } 267 268 s := &metadata.Server{} 269 m.AddServer(s) 270 num = m.NumServers() 271 if num != 1 { 272 t.Fatalf("Expected one server after AddServer") 273 } 274 } 275 276 // func (m *Manager) RebalanceServers() { 277 func TestServers_RebalanceServers(t *testing.T) { 278 const failPct = 0.5 279 m := testManagerFailProb(failPct) 280 const maxServers = 100 281 const numShuffleTests = 100 282 const uniquePassRate = 0.5 283 284 // Make a huge list of nodes. 285 for i := 0; i < maxServers; i++ { 286 nodeName := fmt.Sprintf("s%02d", i) 287 m.AddServer(&metadata.Server{Name: nodeName}) 288 } 289 290 // Keep track of how many unique shuffles we get. 291 uniques := make(map[string]struct{}, maxServers) 292 for i := 0; i < numShuffleTests; i++ { 293 m.RebalanceServers() 294 295 var names []string 296 for j := 0; j < maxServers; j++ { 297 server := m.FindServer() 298 m.NotifyFailedServer(server) 299 names = append(names, server.Name) 300 } 301 key := strings.Join(names, "|") 302 uniques[key] = struct{}{} 303 } 304 305 // We have to allow for the fact that there won't always be a unique 306 // shuffle each pass, so we just look for smell here without the test 307 // being flaky. 308 if len(uniques) < int(maxServers*uniquePassRate) { 309 t.Fatalf("unique shuffle ratio too low: %d/%d", len(uniques), maxServers) 310 } 311 } 312 313 func TestServers_RebalanceServers_AvoidFailed(t *testing.T) { 314 // Do a large number of rebalances with one failed server in the 315 // list and make sure we never have that one selected afterwards. 316 // This was added when fixing #3463, when we were just doing the 317 // shuffle and not actually cycling servers. We do a large number 318 // of trials with a small number of servers to try to make sure 319 // the shuffle alone won't give the right answer. 320 servers := []*metadata.Server{ 321 &metadata.Server{Name: "s1", Addr: &fauxAddr{"s1"}}, 322 &metadata.Server{Name: "s2", Addr: &fauxAddr{"s2"}}, 323 &metadata.Server{Name: "s3", Addr: &fauxAddr{"s3"}}, 324 } 325 for i := 0; i < 100; i++ { 326 m := testManagerFailAddr(&fauxAddr{"s2"}) 327 for _, s := range servers { 328 m.AddServer(s) 329 } 330 331 m.RebalanceServers() 332 if front := m.FindServer().Name; front == "s2" { 333 t.Fatalf("should have avoided the failed server") 334 } 335 } 336 } 337 338 // func (m *Manager) RemoveServer(server *metadata.Server) { 339 func TestManager_RemoveServer(t *testing.T) { 340 const nodeNameFmt = "s%02d" 341 m := testManager() 342 343 if m.NumServers() != 0 { 344 t.Fatalf("Expected zero servers to start") 345 } 346 347 // Test removing server before its added 348 nodeName := fmt.Sprintf(nodeNameFmt, 1) 349 s1 := &metadata.Server{Name: nodeName} 350 m.RemoveServer(s1) 351 m.AddServer(s1) 352 353 nodeName = fmt.Sprintf(nodeNameFmt, 2) 354 s2 := &metadata.Server{Name: nodeName} 355 m.RemoveServer(s2) 356 m.AddServer(s2) 357 358 const maxServers = 19 359 servers := make([]*metadata.Server, maxServers) 360 // Already added two servers above 361 for i := maxServers; i > 2; i-- { 362 nodeName := fmt.Sprintf(nodeNameFmt, i) 363 server := &metadata.Server{Name: nodeName} 364 servers = append(servers, server) 365 m.AddServer(server) 366 } 367 if m.NumServers() != maxServers { 368 t.Fatalf("Expected %d servers, received %d", maxServers, m.NumServers()) 369 } 370 371 m.RebalanceServers() 372 373 if m.NumServers() != maxServers { 374 t.Fatalf("Expected %d servers, received %d", maxServers, m.NumServers()) 375 } 376 377 findServer := func(server *metadata.Server) bool { 378 for i := m.NumServers(); i > 0; i-- { 379 s := m.FindServer() 380 if s == server { 381 return true 382 } 383 } 384 return false 385 } 386 387 expectedNumServers := maxServers 388 removedServers := make([]*metadata.Server, 0, maxServers) 389 390 // Remove servers from the front of the list 391 for i := 3; i > 0; i-- { 392 server := m.FindServer() 393 if server == nil { 394 t.Fatalf("FindServer returned nil") 395 } 396 m.RemoveServer(server) 397 expectedNumServers-- 398 if m.NumServers() != expectedNumServers { 399 t.Fatalf("Expected %d servers (got %d)", expectedNumServers, m.NumServers()) 400 } 401 if findServer(server) == true { 402 t.Fatalf("Did not expect to find server %s after removal from the front", server.Name) 403 } 404 removedServers = append(removedServers, server) 405 } 406 407 // Remove server from the end of the list 408 for i := 3; i > 0; i-- { 409 server := m.FindServer() 410 m.NotifyFailedServer(server) 411 m.RemoveServer(server) 412 expectedNumServers-- 413 if m.NumServers() != expectedNumServers { 414 t.Fatalf("Expected %d servers (got %d)", expectedNumServers, m.NumServers()) 415 } 416 if findServer(server) == true { 417 t.Fatalf("Did not expect to find server %s", server.Name) 418 } 419 removedServers = append(removedServers, server) 420 } 421 422 // Remove server from the middle of the list 423 for i := 3; i > 0; i-- { 424 server := m.FindServer() 425 m.NotifyFailedServer(server) 426 server2 := m.FindServer() 427 m.NotifyFailedServer(server2) // server2 now at end of the list 428 429 m.RemoveServer(server) 430 expectedNumServers-- 431 if m.NumServers() != expectedNumServers { 432 t.Fatalf("Expected %d servers (got %d)", expectedNumServers, m.NumServers()) 433 } 434 if findServer(server) == true { 435 t.Fatalf("Did not expect to find server %s", server.Name) 436 } 437 removedServers = append(removedServers, server) 438 } 439 440 if m.NumServers()+len(removedServers) != maxServers { 441 t.Fatalf("Expected %d+%d=%d servers", m.NumServers(), len(removedServers), maxServers) 442 } 443 444 // Drain the remaining servers from the middle 445 for i := m.NumServers(); i > 0; i-- { 446 server := m.FindServer() 447 m.NotifyFailedServer(server) 448 server2 := m.FindServer() 449 m.NotifyFailedServer(server2) // server2 now at end of the list 450 m.RemoveServer(server) 451 removedServers = append(removedServers, server) 452 } 453 454 if m.NumServers() != 0 { 455 t.Fatalf("Expected an empty server list") 456 } 457 if len(removedServers) != maxServers { 458 t.Fatalf("Expected all servers to be in removed server list") 459 } 460 } 461 462 // func (m *Manager) Start() {