github.com/jfrazelle/docker@v1.1.2-0.20210712172922-bf78e25fe508/libnetwork/networkdb/networkdb_test.go (about) 1 package networkdb 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "log" 7 "net" 8 "os" 9 "strconv" 10 "sync/atomic" 11 "testing" 12 "time" 13 14 "github.com/docker/docker/pkg/stringid" 15 "github.com/docker/go-events" 16 "github.com/hashicorp/memberlist" 17 "github.com/sirupsen/logrus" 18 "gotest.tools/v3/assert" 19 is "gotest.tools/v3/assert/cmp" 20 "gotest.tools/v3/poll" 21 22 // this takes care of the incontainer flag 23 _ "github.com/docker/docker/libnetwork/testutils" 24 ) 25 26 var dbPort int32 = 10000 27 28 func TestMain(m *testing.M) { 29 ioutil.WriteFile("/proc/sys/net/ipv6/conf/lo/disable_ipv6", []byte{'0', '\n'}, 0644) 30 logrus.SetLevel(logrus.ErrorLevel) 31 os.Exit(m.Run()) 32 } 33 34 func launchNode(t *testing.T, conf Config) *NetworkDB { 35 t.Helper() 36 db, err := New(&conf) 37 assert.NilError(t, err) 38 return db 39 } 40 41 func createNetworkDBInstances(t *testing.T, num int, namePrefix string, conf *Config) []*NetworkDB { 42 t.Helper() 43 var dbs []*NetworkDB 44 for i := 0; i < num; i++ { 45 localConfig := *conf 46 localConfig.Hostname = fmt.Sprintf("%s%d", namePrefix, i+1) 47 localConfig.NodeID = stringid.TruncateID(stringid.GenerateRandomID()) 48 localConfig.BindPort = int(atomic.AddInt32(&dbPort, 1)) 49 db := launchNode(t, localConfig) 50 if i != 0 { 51 assert.Check(t, db.Join([]string{fmt.Sprintf("localhost:%d", db.config.BindPort-1)})) 52 } 53 54 dbs = append(dbs, db) 55 } 56 57 // Wait till the cluster creation is successful 58 check := func(t poll.LogT) poll.Result { 59 // Check that the cluster is properly created 60 for i := 0; i < num; i++ { 61 if num != len(dbs[i].ClusterPeers()) { 62 return poll.Continue("%s:Waiting for cluser peers to be established", dbs[i].config.Hostname) 63 } 64 } 65 return poll.Success() 66 } 67 poll.WaitOn(t, check, poll.WithDelay(2*time.Second), poll.WithTimeout(20*time.Second)) 68 69 return dbs 70 } 71 72 func closeNetworkDBInstances(t *testing.T, dbs []*NetworkDB) { 73 t.Helper() 74 log.Print("Closing DB instances...") 75 for _, db := range dbs { 76 db.Close() 77 } 78 } 79 80 func (db *NetworkDB) verifyNodeExistence(t *testing.T, node string, present bool) { 81 t.Helper() 82 for i := 0; i < 80; i++ { 83 db.RLock() 84 _, ok := db.nodes[node] 85 db.RUnlock() 86 if present && ok { 87 return 88 } 89 90 if !present && !ok { 91 return 92 } 93 94 time.Sleep(50 * time.Millisecond) 95 } 96 97 t.Errorf("%v(%v): Node existence verification for node %s failed", db.config.Hostname, db.config.NodeID, node) 98 } 99 100 func (db *NetworkDB) verifyNetworkExistence(t *testing.T, node string, id string, present bool) { 101 t.Helper() 102 for i := 0; i < 80; i++ { 103 db.RLock() 104 nn, nnok := db.networks[node] 105 db.RUnlock() 106 if nnok { 107 n, ok := nn[id] 108 if present && ok { 109 return 110 } 111 112 if !present && 113 ((ok && n.leaving) || 114 !ok) { 115 return 116 } 117 } 118 119 time.Sleep(50 * time.Millisecond) 120 } 121 122 t.Error("Network existence verification failed") 123 } 124 125 func (db *NetworkDB) verifyEntryExistence(t *testing.T, tname, nid, key, value string, present bool) { 126 t.Helper() 127 n := 80 128 for i := 0; i < n; i++ { 129 entry, err := db.getEntry(tname, nid, key) 130 if present && err == nil && string(entry.value) == value { 131 return 132 } 133 134 if !present && 135 ((err == nil && entry.deleting) || 136 (err != nil)) { 137 return 138 } 139 140 if i == n-1 && !present && err != nil { 141 return 142 } 143 144 time.Sleep(50 * time.Millisecond) 145 } 146 147 t.Errorf("Entry existence verification test failed for %v(%v)", db.config.Hostname, db.config.NodeID) 148 } 149 150 func testWatch(t *testing.T, ch chan events.Event, ev interface{}, tname, nid, key, value string) { 151 t.Helper() 152 select { 153 case rcvdEv := <-ch: 154 assert.Check(t, is.Equal(fmt.Sprintf("%T", rcvdEv), fmt.Sprintf("%T", ev))) 155 switch typ := rcvdEv.(type) { 156 case CreateEvent: 157 assert.Check(t, is.Equal(tname, typ.Table)) 158 assert.Check(t, is.Equal(nid, typ.NetworkID)) 159 assert.Check(t, is.Equal(key, typ.Key)) 160 assert.Check(t, is.Equal(value, string(typ.Value))) 161 case UpdateEvent: 162 assert.Check(t, is.Equal(tname, typ.Table)) 163 assert.Check(t, is.Equal(nid, typ.NetworkID)) 164 assert.Check(t, is.Equal(key, typ.Key)) 165 assert.Check(t, is.Equal(value, string(typ.Value))) 166 case DeleteEvent: 167 assert.Check(t, is.Equal(tname, typ.Table)) 168 assert.Check(t, is.Equal(nid, typ.NetworkID)) 169 assert.Check(t, is.Equal(key, typ.Key)) 170 } 171 case <-time.After(time.Second): 172 t.Fail() 173 return 174 } 175 } 176 177 func TestNetworkDBSimple(t *testing.T) { 178 dbs := createNetworkDBInstances(t, 2, "node", DefaultConfig()) 179 closeNetworkDBInstances(t, dbs) 180 } 181 182 func TestNetworkDBJoinLeaveNetwork(t *testing.T) { 183 dbs := createNetworkDBInstances(t, 2, "node", DefaultConfig()) 184 185 err := dbs[0].JoinNetwork("network1") 186 assert.NilError(t, err) 187 188 dbs[1].verifyNetworkExistence(t, dbs[0].config.NodeID, "network1", true) 189 190 err = dbs[0].LeaveNetwork("network1") 191 assert.NilError(t, err) 192 193 dbs[1].verifyNetworkExistence(t, dbs[0].config.NodeID, "network1", false) 194 closeNetworkDBInstances(t, dbs) 195 } 196 197 func TestNetworkDBJoinLeaveNetworks(t *testing.T) { 198 dbs := createNetworkDBInstances(t, 2, "node", DefaultConfig()) 199 200 n := 10 201 for i := 1; i <= n; i++ { 202 err := dbs[0].JoinNetwork(fmt.Sprintf("network0%d", i)) 203 assert.NilError(t, err) 204 } 205 206 for i := 1; i <= n; i++ { 207 err := dbs[1].JoinNetwork(fmt.Sprintf("network1%d", i)) 208 assert.NilError(t, err) 209 } 210 211 for i := 1; i <= n; i++ { 212 dbs[1].verifyNetworkExistence(t, dbs[0].config.NodeID, fmt.Sprintf("network0%d", i), true) 213 } 214 215 for i := 1; i <= n; i++ { 216 dbs[0].verifyNetworkExistence(t, dbs[1].config.NodeID, fmt.Sprintf("network1%d", i), true) 217 } 218 219 for i := 1; i <= n; i++ { 220 err := dbs[0].LeaveNetwork(fmt.Sprintf("network0%d", i)) 221 assert.NilError(t, err) 222 } 223 224 for i := 1; i <= n; i++ { 225 err := dbs[1].LeaveNetwork(fmt.Sprintf("network1%d", i)) 226 assert.NilError(t, err) 227 } 228 229 for i := 1; i <= n; i++ { 230 dbs[1].verifyNetworkExistence(t, dbs[0].config.NodeID, fmt.Sprintf("network0%d", i), false) 231 } 232 233 for i := 1; i <= n; i++ { 234 dbs[0].verifyNetworkExistence(t, dbs[1].config.NodeID, fmt.Sprintf("network1%d", i), false) 235 } 236 237 closeNetworkDBInstances(t, dbs) 238 } 239 240 func TestNetworkDBCRUDTableEntry(t *testing.T) { 241 dbs := createNetworkDBInstances(t, 3, "node", DefaultConfig()) 242 243 err := dbs[0].JoinNetwork("network1") 244 assert.NilError(t, err) 245 246 dbs[1].verifyNetworkExistence(t, dbs[0].config.NodeID, "network1", true) 247 248 err = dbs[1].JoinNetwork("network1") 249 assert.NilError(t, err) 250 251 err = dbs[0].CreateEntry("test_table", "network1", "test_key", []byte("test_value")) 252 assert.NilError(t, err) 253 254 dbs[1].verifyEntryExistence(t, "test_table", "network1", "test_key", "test_value", true) 255 dbs[2].verifyEntryExistence(t, "test_table", "network1", "test_key", "test_value", false) 256 257 err = dbs[0].UpdateEntry("test_table", "network1", "test_key", []byte("test_updated_value")) 258 assert.NilError(t, err) 259 260 dbs[1].verifyEntryExistence(t, "test_table", "network1", "test_key", "test_updated_value", true) 261 262 err = dbs[0].DeleteEntry("test_table", "network1", "test_key") 263 assert.NilError(t, err) 264 265 dbs[1].verifyEntryExistence(t, "test_table", "network1", "test_key", "", false) 266 267 closeNetworkDBInstances(t, dbs) 268 } 269 270 func TestNetworkDBCRUDTableEntries(t *testing.T) { 271 dbs := createNetworkDBInstances(t, 2, "node", DefaultConfig()) 272 273 err := dbs[0].JoinNetwork("network1") 274 assert.NilError(t, err) 275 276 dbs[1].verifyNetworkExistence(t, dbs[0].config.NodeID, "network1", true) 277 278 err = dbs[1].JoinNetwork("network1") 279 assert.NilError(t, err) 280 281 n := 10 282 for i := 1; i <= n; i++ { 283 err = dbs[0].CreateEntry("test_table", "network1", 284 fmt.Sprintf("test_key0%d", i), 285 []byte(fmt.Sprintf("test_value0%d", i))) 286 assert.NilError(t, err) 287 } 288 289 for i := 1; i <= n; i++ { 290 err = dbs[1].CreateEntry("test_table", "network1", 291 fmt.Sprintf("test_key1%d", i), 292 []byte(fmt.Sprintf("test_value1%d", i))) 293 assert.NilError(t, err) 294 } 295 296 for i := 1; i <= n; i++ { 297 dbs[0].verifyEntryExistence(t, "test_table", "network1", 298 fmt.Sprintf("test_key1%d", i), 299 fmt.Sprintf("test_value1%d", i), true) 300 assert.NilError(t, err) 301 } 302 303 for i := 1; i <= n; i++ { 304 dbs[1].verifyEntryExistence(t, "test_table", "network1", 305 fmt.Sprintf("test_key0%d", i), 306 fmt.Sprintf("test_value0%d", i), true) 307 assert.NilError(t, err) 308 } 309 310 // Verify deletes 311 for i := 1; i <= n; i++ { 312 err = dbs[0].DeleteEntry("test_table", "network1", 313 fmt.Sprintf("test_key0%d", i)) 314 assert.NilError(t, err) 315 } 316 317 for i := 1; i <= n; i++ { 318 err = dbs[1].DeleteEntry("test_table", "network1", 319 fmt.Sprintf("test_key1%d", i)) 320 assert.NilError(t, err) 321 } 322 323 for i := 1; i <= n; i++ { 324 dbs[0].verifyEntryExistence(t, "test_table", "network1", 325 fmt.Sprintf("test_key1%d", i), "", false) 326 assert.NilError(t, err) 327 } 328 329 for i := 1; i <= n; i++ { 330 dbs[1].verifyEntryExistence(t, "test_table", "network1", 331 fmt.Sprintf("test_key0%d", i), "", false) 332 assert.NilError(t, err) 333 } 334 335 closeNetworkDBInstances(t, dbs) 336 } 337 338 func TestNetworkDBNodeLeave(t *testing.T) { 339 dbs := createNetworkDBInstances(t, 2, "node", DefaultConfig()) 340 341 err := dbs[0].JoinNetwork("network1") 342 assert.NilError(t, err) 343 344 err = dbs[1].JoinNetwork("network1") 345 assert.NilError(t, err) 346 347 err = dbs[0].CreateEntry("test_table", "network1", "test_key", []byte("test_value")) 348 assert.NilError(t, err) 349 350 dbs[1].verifyEntryExistence(t, "test_table", "network1", "test_key", "test_value", true) 351 352 dbs[0].Close() 353 dbs[1].verifyEntryExistence(t, "test_table", "network1", "test_key", "test_value", false) 354 dbs[1].Close() 355 } 356 357 func TestNetworkDBWatch(t *testing.T) { 358 dbs := createNetworkDBInstances(t, 2, "node", DefaultConfig()) 359 err := dbs[0].JoinNetwork("network1") 360 assert.NilError(t, err) 361 362 err = dbs[1].JoinNetwork("network1") 363 assert.NilError(t, err) 364 365 ch, cancel := dbs[1].Watch("", "", "") 366 367 err = dbs[0].CreateEntry("test_table", "network1", "test_key", []byte("test_value")) 368 assert.NilError(t, err) 369 370 testWatch(t, ch.C, CreateEvent{}, "test_table", "network1", "test_key", "test_value") 371 372 err = dbs[0].UpdateEntry("test_table", "network1", "test_key", []byte("test_updated_value")) 373 assert.NilError(t, err) 374 375 testWatch(t, ch.C, UpdateEvent{}, "test_table", "network1", "test_key", "test_updated_value") 376 377 err = dbs[0].DeleteEntry("test_table", "network1", "test_key") 378 assert.NilError(t, err) 379 380 testWatch(t, ch.C, DeleteEvent{}, "test_table", "network1", "test_key", "") 381 382 cancel() 383 closeNetworkDBInstances(t, dbs) 384 } 385 386 func TestNetworkDBBulkSync(t *testing.T) { 387 dbs := createNetworkDBInstances(t, 2, "node", DefaultConfig()) 388 389 err := dbs[0].JoinNetwork("network1") 390 assert.NilError(t, err) 391 392 dbs[1].verifyNetworkExistence(t, dbs[0].config.NodeID, "network1", true) 393 394 n := 1000 395 for i := 1; i <= n; i++ { 396 err = dbs[0].CreateEntry("test_table", "network1", 397 fmt.Sprintf("test_key0%d", i), 398 []byte(fmt.Sprintf("test_value0%d", i))) 399 assert.NilError(t, err) 400 } 401 402 err = dbs[1].JoinNetwork("network1") 403 assert.NilError(t, err) 404 405 dbs[0].verifyNetworkExistence(t, dbs[1].config.NodeID, "network1", true) 406 407 for i := 1; i <= n; i++ { 408 dbs[1].verifyEntryExistence(t, "test_table", "network1", 409 fmt.Sprintf("test_key0%d", i), 410 fmt.Sprintf("test_value0%d", i), true) 411 assert.NilError(t, err) 412 } 413 414 closeNetworkDBInstances(t, dbs) 415 } 416 417 func TestNetworkDBCRUDMediumCluster(t *testing.T) { 418 n := 5 419 420 dbs := createNetworkDBInstances(t, n, "node", DefaultConfig()) 421 422 for i := 0; i < n; i++ { 423 for j := 0; j < n; j++ { 424 if i == j { 425 continue 426 } 427 428 dbs[i].verifyNodeExistence(t, dbs[j].config.NodeID, true) 429 } 430 } 431 432 for i := 0; i < n; i++ { 433 err := dbs[i].JoinNetwork("network1") 434 assert.NilError(t, err) 435 } 436 437 for i := 0; i < n; i++ { 438 for j := 0; j < n; j++ { 439 dbs[i].verifyNetworkExistence(t, dbs[j].config.NodeID, "network1", true) 440 } 441 } 442 443 err := dbs[0].CreateEntry("test_table", "network1", "test_key", []byte("test_value")) 444 assert.NilError(t, err) 445 446 for i := 1; i < n; i++ { 447 dbs[i].verifyEntryExistence(t, "test_table", "network1", "test_key", "test_value", true) 448 } 449 450 err = dbs[0].UpdateEntry("test_table", "network1", "test_key", []byte("test_updated_value")) 451 assert.NilError(t, err) 452 453 for i := 1; i < n; i++ { 454 dbs[i].verifyEntryExistence(t, "test_table", "network1", "test_key", "test_updated_value", true) 455 } 456 457 err = dbs[0].DeleteEntry("test_table", "network1", "test_key") 458 assert.NilError(t, err) 459 460 for i := 1; i < n; i++ { 461 dbs[i].verifyEntryExistence(t, "test_table", "network1", "test_key", "", false) 462 } 463 464 for i := 1; i < n; i++ { 465 _, err = dbs[i].GetEntry("test_table", "network1", "test_key") 466 assert.Check(t, is.ErrorContains(err, "")) 467 assert.Check(t, is.Contains(err.Error(), "deleted and pending garbage collection"), err) 468 } 469 470 closeNetworkDBInstances(t, dbs) 471 } 472 473 func TestNetworkDBNodeJoinLeaveIteration(t *testing.T) { 474 maxRetry := 5 475 dbs := createNetworkDBInstances(t, 2, "node", DefaultConfig()) 476 477 // Single node Join/Leave 478 err := dbs[0].JoinNetwork("network1") 479 assert.NilError(t, err) 480 481 if len(dbs[0].networkNodes["network1"]) != 1 { 482 t.Fatalf("The networkNodes list has to have be 1 instead of %d", len(dbs[0].networkNodes["network1"])) 483 } 484 485 err = dbs[0].LeaveNetwork("network1") 486 assert.NilError(t, err) 487 488 if len(dbs[0].networkNodes["network1"]) != 0 { 489 t.Fatalf("The networkNodes list has to have be 0 instead of %d", len(dbs[0].networkNodes["network1"])) 490 } 491 492 // Multiple nodes Join/Leave 493 err = dbs[0].JoinNetwork("network1") 494 assert.NilError(t, err) 495 496 err = dbs[1].JoinNetwork("network1") 497 assert.NilError(t, err) 498 499 // Wait for the propagation on db[0] 500 for i := 0; i < maxRetry; i++ { 501 if len(dbs[0].networkNodes["network1"]) == 2 { 502 break 503 } 504 time.Sleep(1 * time.Second) 505 } 506 if len(dbs[0].networkNodes["network1"]) != 2 { 507 t.Fatalf("The networkNodes list has to have be 2 instead of %d - %v", len(dbs[0].networkNodes["network1"]), dbs[0].networkNodes["network1"]) 508 } 509 if n, ok := dbs[0].networks[dbs[0].config.NodeID]["network1"]; !ok || n.leaving { 510 t.Fatalf("The network should not be marked as leaving:%t", n.leaving) 511 } 512 513 // Wait for the propagation on db[1] 514 for i := 0; i < maxRetry; i++ { 515 if len(dbs[1].networkNodes["network1"]) == 2 { 516 break 517 } 518 time.Sleep(1 * time.Second) 519 } 520 if len(dbs[1].networkNodes["network1"]) != 2 { 521 t.Fatalf("The networkNodes list has to have be 2 instead of %d - %v", len(dbs[1].networkNodes["network1"]), dbs[1].networkNodes["network1"]) 522 } 523 if n, ok := dbs[1].networks[dbs[1].config.NodeID]["network1"]; !ok || n.leaving { 524 t.Fatalf("The network should not be marked as leaving:%t", n.leaving) 525 } 526 527 // Try a quick leave/join 528 err = dbs[0].LeaveNetwork("network1") 529 assert.NilError(t, err) 530 err = dbs[0].JoinNetwork("network1") 531 assert.NilError(t, err) 532 533 for i := 0; i < maxRetry; i++ { 534 if len(dbs[0].networkNodes["network1"]) == 2 { 535 break 536 } 537 time.Sleep(1 * time.Second) 538 } 539 if len(dbs[0].networkNodes["network1"]) != 2 { 540 t.Fatalf("The networkNodes list has to have be 2 instead of %d - %v", len(dbs[0].networkNodes["network1"]), dbs[0].networkNodes["network1"]) 541 } 542 543 for i := 0; i < maxRetry; i++ { 544 if len(dbs[1].networkNodes["network1"]) == 2 { 545 break 546 } 547 time.Sleep(1 * time.Second) 548 } 549 if len(dbs[1].networkNodes["network1"]) != 2 { 550 t.Fatalf("The networkNodes list has to have be 2 instead of %d - %v", len(dbs[1].networkNodes["network1"]), dbs[1].networkNodes["network1"]) 551 } 552 553 closeNetworkDBInstances(t, dbs) 554 } 555 556 func TestNetworkDBGarbageCollection(t *testing.T) { 557 keysWriteDelete := 5 558 config := DefaultConfig() 559 config.reapEntryInterval = 30 * time.Second 560 config.StatsPrintPeriod = 15 * time.Second 561 562 dbs := createNetworkDBInstances(t, 3, "node", config) 563 564 // 2 Nodes join network 565 err := dbs[0].JoinNetwork("network1") 566 assert.NilError(t, err) 567 568 err = dbs[1].JoinNetwork("network1") 569 assert.NilError(t, err) 570 571 for i := 0; i < keysWriteDelete; i++ { 572 err = dbs[i%2].CreateEntry("testTable", "network1", "key-"+strconv.Itoa(i), []byte("value")) 573 assert.NilError(t, err) 574 } 575 time.Sleep(time.Second) 576 for i := 0; i < keysWriteDelete; i++ { 577 err = dbs[i%2].DeleteEntry("testTable", "network1", "key-"+strconv.Itoa(i)) 578 assert.NilError(t, err) 579 } 580 for i := 0; i < 2; i++ { 581 assert.Check(t, is.Equal(keysWriteDelete, dbs[i].networks[dbs[i].config.NodeID]["network1"].entriesNumber), "entries number should match") 582 } 583 584 // from this point the timer for the garbage collection started, wait 5 seconds and then join a new node 585 time.Sleep(5 * time.Second) 586 587 err = dbs[2].JoinNetwork("network1") 588 assert.NilError(t, err) 589 for i := 0; i < 3; i++ { 590 assert.Check(t, is.Equal(keysWriteDelete, dbs[i].networks[dbs[i].config.NodeID]["network1"].entriesNumber), "entries number should match") 591 } 592 // at this point the entries should had been all deleted 593 time.Sleep(30 * time.Second) 594 for i := 0; i < 3; i++ { 595 assert.Check(t, is.Equal(0, dbs[i].networks[dbs[i].config.NodeID]["network1"].entriesNumber), "entries should had been garbage collected") 596 } 597 598 // make sure that entries are not coming back 599 time.Sleep(15 * time.Second) 600 for i := 0; i < 3; i++ { 601 assert.Check(t, is.Equal(0, dbs[i].networks[dbs[i].config.NodeID]["network1"].entriesNumber), "entries should had been garbage collected") 602 } 603 604 closeNetworkDBInstances(t, dbs) 605 } 606 607 func TestFindNode(t *testing.T) { 608 dbs := createNetworkDBInstances(t, 1, "node", DefaultConfig()) 609 610 dbs[0].nodes["active"] = &node{Node: memberlist.Node{Name: "active"}} 611 dbs[0].failedNodes["failed"] = &node{Node: memberlist.Node{Name: "failed"}} 612 dbs[0].leftNodes["left"] = &node{Node: memberlist.Node{Name: "left"}} 613 614 // active nodes is 2 because the testing node is in the list 615 assert.Check(t, is.Len(dbs[0].nodes, 2)) 616 assert.Check(t, is.Len(dbs[0].failedNodes, 1)) 617 assert.Check(t, is.Len(dbs[0].leftNodes, 1)) 618 619 n, currState, m := dbs[0].findNode("active") 620 assert.Check(t, n != nil) 621 assert.Check(t, is.Equal("active", n.Name)) 622 assert.Check(t, is.Equal(nodeActiveState, currState)) 623 assert.Check(t, m != nil) 624 // delete the entry manually 625 delete(m, "active") 626 627 // test if can be still find 628 n, currState, m = dbs[0].findNode("active") 629 assert.Check(t, is.Nil(n)) 630 assert.Check(t, is.Equal(nodeNotFound, currState)) 631 assert.Check(t, is.Nil(m)) 632 633 n, currState, m = dbs[0].findNode("failed") 634 assert.Check(t, n != nil) 635 assert.Check(t, is.Equal("failed", n.Name)) 636 assert.Check(t, is.Equal(nodeFailedState, currState)) 637 assert.Check(t, m != nil) 638 639 // find and remove 640 n, currState, m = dbs[0].findNode("left") 641 assert.Check(t, n != nil) 642 assert.Check(t, is.Equal("left", n.Name)) 643 assert.Check(t, is.Equal(nodeLeftState, currState)) 644 assert.Check(t, m != nil) 645 delete(m, "left") 646 647 n, currState, m = dbs[0].findNode("left") 648 assert.Check(t, is.Nil(n)) 649 assert.Check(t, is.Equal(nodeNotFound, currState)) 650 assert.Check(t, is.Nil(m)) 651 652 closeNetworkDBInstances(t, dbs) 653 } 654 655 func TestChangeNodeState(t *testing.T) { 656 dbs := createNetworkDBInstances(t, 1, "node", DefaultConfig()) 657 658 dbs[0].nodes["node1"] = &node{Node: memberlist.Node{Name: "node1"}} 659 dbs[0].nodes["node2"] = &node{Node: memberlist.Node{Name: "node2"}} 660 dbs[0].nodes["node3"] = &node{Node: memberlist.Node{Name: "node3"}} 661 662 // active nodes is 4 because the testing node is in the list 663 assert.Check(t, is.Len(dbs[0].nodes, 4)) 664 665 n, currState, m := dbs[0].findNode("node1") 666 assert.Check(t, n != nil) 667 assert.Check(t, is.Equal(nodeActiveState, currState)) 668 assert.Check(t, is.Equal("node1", n.Name)) 669 assert.Check(t, m != nil) 670 671 // node1 to failed 672 dbs[0].changeNodeState("node1", nodeFailedState) 673 674 n, currState, m = dbs[0].findNode("node1") 675 assert.Check(t, n != nil) 676 assert.Check(t, is.Equal(nodeFailedState, currState)) 677 assert.Check(t, is.Equal("node1", n.Name)) 678 assert.Check(t, m != nil) 679 assert.Check(t, time.Duration(0) != n.reapTime) 680 681 // node1 back to active 682 dbs[0].changeNodeState("node1", nodeActiveState) 683 684 n, currState, m = dbs[0].findNode("node1") 685 assert.Check(t, n != nil) 686 assert.Check(t, is.Equal(nodeActiveState, currState)) 687 assert.Check(t, is.Equal("node1", n.Name)) 688 assert.Check(t, m != nil) 689 assert.Check(t, is.Equal(time.Duration(0), n.reapTime)) 690 691 // node1 to left 692 dbs[0].changeNodeState("node1", nodeLeftState) 693 dbs[0].changeNodeState("node2", nodeLeftState) 694 dbs[0].changeNodeState("node3", nodeLeftState) 695 696 n, currState, m = dbs[0].findNode("node1") 697 assert.Check(t, n != nil) 698 assert.Check(t, is.Equal(nodeLeftState, currState)) 699 assert.Check(t, is.Equal("node1", n.Name)) 700 assert.Check(t, m != nil) 701 assert.Check(t, time.Duration(0) != n.reapTime) 702 703 n, currState, m = dbs[0].findNode("node2") 704 assert.Check(t, n != nil) 705 assert.Check(t, is.Equal(nodeLeftState, currState)) 706 assert.Check(t, is.Equal("node2", n.Name)) 707 assert.Check(t, m != nil) 708 assert.Check(t, time.Duration(0) != n.reapTime) 709 710 n, currState, m = dbs[0].findNode("node3") 711 assert.Check(t, n != nil) 712 assert.Check(t, is.Equal(nodeLeftState, currState)) 713 assert.Check(t, is.Equal("node3", n.Name)) 714 assert.Check(t, m != nil) 715 assert.Check(t, time.Duration(0) != n.reapTime) 716 717 // active nodes is 1 because the testing node is in the list 718 assert.Check(t, is.Len(dbs[0].nodes, 1)) 719 assert.Check(t, is.Len(dbs[0].failedNodes, 0)) 720 assert.Check(t, is.Len(dbs[0].leftNodes, 3)) 721 722 closeNetworkDBInstances(t, dbs) 723 } 724 725 func TestNodeReincarnation(t *testing.T) { 726 dbs := createNetworkDBInstances(t, 1, "node", DefaultConfig()) 727 728 dbs[0].nodes["node1"] = &node{Node: memberlist.Node{Name: "node1", Addr: net.ParseIP("192.168.1.1")}} 729 dbs[0].leftNodes["node2"] = &node{Node: memberlist.Node{Name: "node2", Addr: net.ParseIP("192.168.1.2")}} 730 dbs[0].failedNodes["node3"] = &node{Node: memberlist.Node{Name: "node3", Addr: net.ParseIP("192.168.1.3")}} 731 732 // active nodes is 2 because the testing node is in the list 733 assert.Check(t, is.Len(dbs[0].nodes, 2)) 734 assert.Check(t, is.Len(dbs[0].failedNodes, 1)) 735 assert.Check(t, is.Len(dbs[0].leftNodes, 1)) 736 737 b := dbs[0].purgeReincarnation(&memberlist.Node{Name: "node4", Addr: net.ParseIP("192.168.1.1")}) 738 assert.Check(t, b) 739 dbs[0].nodes["node4"] = &node{Node: memberlist.Node{Name: "node4", Addr: net.ParseIP("192.168.1.1")}} 740 741 b = dbs[0].purgeReincarnation(&memberlist.Node{Name: "node5", Addr: net.ParseIP("192.168.1.2")}) 742 assert.Check(t, b) 743 dbs[0].nodes["node5"] = &node{Node: memberlist.Node{Name: "node5", Addr: net.ParseIP("192.168.1.1")}} 744 745 b = dbs[0].purgeReincarnation(&memberlist.Node{Name: "node6", Addr: net.ParseIP("192.168.1.3")}) 746 assert.Check(t, b) 747 dbs[0].nodes["node6"] = &node{Node: memberlist.Node{Name: "node6", Addr: net.ParseIP("192.168.1.1")}} 748 749 b = dbs[0].purgeReincarnation(&memberlist.Node{Name: "node6", Addr: net.ParseIP("192.168.1.10")}) 750 assert.Check(t, !b) 751 752 // active nodes is 1 because the testing node is in the list 753 assert.Check(t, is.Len(dbs[0].nodes, 4)) 754 assert.Check(t, is.Len(dbs[0].failedNodes, 0)) 755 assert.Check(t, is.Len(dbs[0].leftNodes, 3)) 756 757 closeNetworkDBInstances(t, dbs) 758 } 759 760 func TestParallelCreate(t *testing.T) { 761 dbs := createNetworkDBInstances(t, 1, "node", DefaultConfig()) 762 763 startCh := make(chan int) 764 doneCh := make(chan error) 765 var success int32 766 for i := 0; i < 20; i++ { 767 go func() { 768 <-startCh 769 err := dbs[0].CreateEntry("testTable", "testNetwork", "key", []byte("value")) 770 if err == nil { 771 atomic.AddInt32(&success, 1) 772 } 773 doneCh <- err 774 }() 775 } 776 777 close(startCh) 778 779 for i := 0; i < 20; i++ { 780 <-doneCh 781 } 782 close(doneCh) 783 // Only 1 write should have succeeded 784 assert.Check(t, is.Equal(int32(1), success)) 785 786 closeNetworkDBInstances(t, dbs) 787 } 788 789 func TestParallelDelete(t *testing.T) { 790 dbs := createNetworkDBInstances(t, 1, "node", DefaultConfig()) 791 792 err := dbs[0].CreateEntry("testTable", "testNetwork", "key", []byte("value")) 793 assert.NilError(t, err) 794 795 startCh := make(chan int) 796 doneCh := make(chan error) 797 var success int32 798 for i := 0; i < 20; i++ { 799 go func() { 800 <-startCh 801 err := dbs[0].DeleteEntry("testTable", "testNetwork", "key") 802 if err == nil { 803 atomic.AddInt32(&success, 1) 804 } 805 doneCh <- err 806 }() 807 } 808 809 close(startCh) 810 811 for i := 0; i < 20; i++ { 812 <-doneCh 813 } 814 close(doneCh) 815 // Only 1 write should have succeeded 816 assert.Check(t, is.Equal(int32(1), success)) 817 818 closeNetworkDBInstances(t, dbs) 819 } 820 821 func TestNetworkDBIslands(t *testing.T) { 822 logrus.SetLevel(logrus.DebugLevel) 823 dbs := createNetworkDBInstances(t, 5, "node", DefaultConfig()) 824 825 // Get the node IP used currently 826 node := dbs[0].nodes[dbs[0].config.NodeID] 827 baseIPStr := node.Addr.String() 828 // Node 0,1,2 are going to be the 3 bootstrap nodes 829 members := []string{fmt.Sprintf("%s:%d", baseIPStr, dbs[0].config.BindPort), 830 fmt.Sprintf("%s:%d", baseIPStr, dbs[1].config.BindPort), 831 fmt.Sprintf("%s:%d", baseIPStr, dbs[2].config.BindPort)} 832 // Rejoining will update the list of the bootstrap members 833 for i := 3; i < 5; i++ { 834 t.Logf("Re-joining: %d", i) 835 assert.Check(t, dbs[i].Join(members)) 836 } 837 838 // Now the 3 bootstrap nodes will cleanly leave, and will be properly removed from the other 2 nodes 839 for i := 0; i < 3; i++ { 840 logrus.Infof("node %d leaving", i) 841 dbs[i].Close() 842 } 843 844 checkDBs := make(map[string]*NetworkDB) 845 for i := 3; i < 5; i++ { 846 db := dbs[i] 847 checkDBs[db.config.Hostname] = db 848 } 849 850 // Give some time to let the system propagate the messages and free up the ports 851 check := func(t poll.LogT) poll.Result { 852 // Verify that the nodes are actually all gone and marked appropiately 853 for name, db := range checkDBs { 854 db.RLock() 855 if (len(db.leftNodes) != 3) || (len(db.failedNodes) != 0) { 856 for name := range db.leftNodes { 857 t.Logf("%s: Node %s left", db.config.Hostname, name) 858 } 859 for name := range db.failedNodes { 860 t.Logf("%s: Node %s failed", db.config.Hostname, name) 861 } 862 db.RUnlock() 863 return poll.Continue("%s:Waiting for all nodes to cleanly leave, left: %d, failed nodes: %d", name, len(db.leftNodes), len(db.failedNodes)) 864 } 865 db.RUnlock() 866 t.Logf("%s: OK", name) 867 delete(checkDBs, name) 868 } 869 return poll.Success() 870 } 871 poll.WaitOn(t, check, poll.WithDelay(time.Second), poll.WithTimeout(120*time.Second)) 872 873 // Spawn again the first 3 nodes with different names but same IP:port 874 for i := 0; i < 3; i++ { 875 logrus.Infof("node %d coming back", i) 876 dbs[i].config.NodeID = stringid.TruncateID(stringid.GenerateRandomID()) 877 dbs[i] = launchNode(t, *dbs[i].config) 878 } 879 880 // Give some time for the reconnect routine to run, it runs every 60s 881 check = func(t poll.LogT) poll.Result { 882 // Verify that the cluster is again all connected. Note that the 3 previous node did not do any join 883 for i := 0; i < 5; i++ { 884 db := dbs[i] 885 db.RLock() 886 if len(db.nodes) != 5 { 887 db.RUnlock() 888 return poll.Continue("%s:Waiting to connect to all nodes", dbs[i].config.Hostname) 889 } 890 if len(db.failedNodes) != 0 { 891 db.RUnlock() 892 return poll.Continue("%s:Waiting for 0 failedNodes", dbs[i].config.Hostname) 893 } 894 if i < 3 { 895 // nodes from 0 to 3 has no left nodes 896 if len(db.leftNodes) != 0 { 897 db.RUnlock() 898 return poll.Continue("%s:Waiting to have no leftNodes", dbs[i].config.Hostname) 899 } 900 } else { 901 // nodes from 4 to 5 has the 3 previous left nodes 902 if len(db.leftNodes) != 3 { 903 db.RUnlock() 904 return poll.Continue("%s:Waiting to have 3 leftNodes", dbs[i].config.Hostname) 905 } 906 } 907 db.RUnlock() 908 } 909 return poll.Success() 910 } 911 poll.WaitOn(t, check, poll.WithDelay(10*time.Second), poll.WithTimeout(120*time.Second)) 912 closeNetworkDBInstances(t, dbs) 913 }