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