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