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