github.com/m3db/m3@v1.5.0/src/cluster/placement/selector/mirrored_test.go (about) 1 // Copyright (c) 2017 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 package selector 22 23 import ( 24 "testing" 25 26 "github.com/m3db/m3/src/cluster/placement" 27 "github.com/m3db/m3/src/cluster/shard" 28 29 "github.com/stretchr/testify/assert" 30 "github.com/stretchr/testify/require" 31 ) 32 33 func TestSelectInitialInstancesForMirror(t *testing.T) { 34 h1p1 := placement.NewInstance(). 35 SetID("h1p1"). 36 SetHostname("h1"). 37 SetPort(1). 38 SetIsolationGroup("r1"). 39 SetZone("z1"). 40 SetEndpoint("h1p1e"). 41 SetWeight(1) 42 h1p2 := placement.NewInstance(). 43 SetID("h1p2"). 44 SetHostname("h1"). 45 SetPort(2). 46 SetIsolationGroup("r1"). 47 SetZone("z1"). 48 SetEndpoint("h1p2e"). 49 SetWeight(1) 50 h2p1 := placement.NewInstance(). 51 SetID("h2p1"). 52 SetHostname("h2"). 53 SetPort(1). 54 SetIsolationGroup("r2"). 55 SetZone("z1"). 56 SetEndpoint("h2p1e"). 57 SetWeight(1) 58 h2p2 := placement.NewInstance(). 59 SetID("h2p2"). 60 SetHostname("h2"). 61 SetPort(2). 62 SetIsolationGroup("r2"). 63 SetZone("z1"). 64 SetEndpoint("h2p2e"). 65 SetWeight(1) 66 h3p1 := placement.NewInstance(). 67 SetID("h3p1"). 68 SetHostname("h3"). 69 SetPort(1). 70 SetIsolationGroup("r1"). 71 SetZone("z1"). 72 SetEndpoint("h3p1e"). 73 SetWeight(1) 74 h3p2 := placement.NewInstance(). 75 SetID("h3p2"). 76 SetHostname("h3"). 77 SetPort(2). 78 SetIsolationGroup("r1"). 79 SetZone("z1"). 80 SetEndpoint("h3p2e"). 81 SetWeight(1) 82 h4p1 := placement.NewInstance(). 83 SetID("h4p1"). 84 SetHostname("h4"). 85 SetPort(1). 86 SetIsolationGroup("r3"). 87 SetZone("z1"). 88 SetEndpoint("h4p1e"). 89 SetWeight(1) 90 h4p2 := placement.NewInstance(). 91 SetID("h4p2"). 92 SetHostname("h4"). 93 SetPort(2). 94 SetIsolationGroup("r3"). 95 SetZone("z1"). 96 SetEndpoint("h4p2e"). 97 SetWeight(1) 98 99 selector := NewPortMirroredSelector(placement.NewOptions().SetValidZone("z1")) 100 res, err := selector.SelectInitialInstances( 101 []placement.Instance{ 102 h1p1.SetShardSetID(0), 103 h1p2.SetShardSetID(0), 104 h2p1.SetShardSetID(0), 105 h2p2.SetShardSetID(0), 106 h3p1.SetShardSetID(0), 107 h3p2.SetShardSetID(0), 108 h4p1.SetShardSetID(0), 109 h4p2.SetShardSetID(0), 110 }, 111 2, 112 ) 113 require.NoError(t, err) 114 require.Equal(t, 8, len(res)) 115 116 ssIDs := make(map[uint32]int) 117 for i := 1; i <= 4; i++ { 118 ssIDs[uint32(i)] = 2 119 } 120 121 for _, instance := range res { 122 ssIDs[instance.ShardSetID()] = ssIDs[instance.ShardSetID()] - 1 123 } 124 125 for _, count := range ssIDs { 126 require.Equal(t, 0, count) 127 } 128 } 129 130 func TestSelectInitialInstancesForMirrorRF2(t *testing.T) { 131 h1p1 := placement.NewInstance(). 132 SetID("h1p1"). 133 SetHostname("h1"). 134 SetPort(1). 135 SetIsolationGroup("r1"). 136 SetZone("z1"). 137 SetEndpoint("h1p1e"). 138 SetWeight(1) 139 h1p2 := placement.NewInstance(). 140 SetID("h1p2"). 141 SetHostname("h1"). 142 SetPort(2). 143 SetIsolationGroup("r1"). 144 SetZone("z1"). 145 SetEndpoint("h1p2e"). 146 SetWeight(1) 147 h1p3 := placement.NewInstance(). 148 SetID("h1p3"). 149 SetHostname("h1"). 150 SetPort(3). 151 SetIsolationGroup("r1"). 152 SetZone("z1"). 153 SetEndpoint("h1p3e"). 154 SetWeight(1) 155 h2p1 := placement.NewInstance(). 156 SetID("h2p1"). 157 SetHostname("h2"). 158 SetPort(1). 159 SetIsolationGroup("r2"). 160 SetZone("z1"). 161 SetEndpoint("h2p1e"). 162 SetWeight(1) 163 h2p2 := placement.NewInstance(). 164 SetID("h2p2"). 165 SetHostname("h2"). 166 SetPort(2). 167 SetIsolationGroup("r2"). 168 SetZone("z1"). 169 SetEndpoint("h2p2e"). 170 SetWeight(1) 171 h2p3 := placement.NewInstance(). 172 SetID("h2p3"). 173 SetHostname("h2"). 174 SetPort(3). 175 SetIsolationGroup("r2"). 176 SetZone("z1"). 177 SetEndpoint("h2p3e"). 178 SetWeight(1) 179 h3p1 := placement.NewInstance(). 180 SetID("h3p1"). 181 SetHostname("h3"). 182 SetPort(1). 183 SetIsolationGroup("r1"). 184 SetZone("z1"). 185 SetEndpoint("h3p1e"). 186 SetWeight(2) 187 h3p2 := placement.NewInstance(). 188 SetID("h3p2"). 189 SetHostname("h3"). 190 SetPort(2). 191 SetIsolationGroup("r1"). 192 SetZone("z1"). 193 SetEndpoint("h3p2e"). 194 SetWeight(2) 195 h3p3 := placement.NewInstance(). 196 SetID("h3p3"). 197 SetHostname("h3"). 198 SetPort(3). 199 SetIsolationGroup("r1"). 200 SetZone("z1"). 201 SetEndpoint("h3p3e"). 202 SetWeight(2) 203 204 selector := NewPortMirroredSelector(placement.NewOptions().SetValidZone("z1")) 205 res, err := selector.SelectInitialInstances( 206 []placement.Instance{h1p1, h1p2, h1p3, h2p1, h2p2, h2p3, h3p1, h3p2, h3p3}, 207 2, 208 ) 209 require.NoError(t, err) 210 require.Equal(t, 6, len(res)) 211 require.Equal(t, h1p1.ShardSetID(), h2p1.ShardSetID()) 212 require.Equal(t, h1p2.ShardSetID(), h2p2.ShardSetID()) 213 require.Equal(t, h1p3.ShardSetID(), h2p3.ShardSetID()) 214 ssIDs := make(map[uint32]int) 215 for i := 1; i <= 3; i++ { 216 ssIDs[uint32(i)] = 2 217 } 218 219 for _, instance := range res { 220 ssIDs[instance.ShardSetID()] = ssIDs[instance.ShardSetID()] - 1 221 } 222 223 for _, count := range ssIDs { 224 require.Equal(t, 0, count) 225 } 226 227 require.Equal(t, h3p1.ShardSetID(), h3p2.ShardSetID()) 228 require.Empty(t, h3p1.ShardSetID()) 229 230 h4p1 := placement.NewInstance(). 231 SetID("h4p1"). 232 SetHostname("h4"). 233 SetPort(1). 234 SetIsolationGroup("r3"). 235 SetZone("z1"). 236 SetEndpoint("h4p1e"). 237 SetWeight(2) 238 h4p2 := placement.NewInstance(). 239 SetID("h4p2"). 240 SetHostname("h4"). 241 SetPort(2). 242 SetIsolationGroup("r3"). 243 SetZone("z1"). 244 SetEndpoint("h4p2e"). 245 SetWeight(2) 246 h4p3 := placement.NewInstance(). 247 SetID("h4p3"). 248 SetHostname("h4"). 249 SetPort(3). 250 SetIsolationGroup("r3"). 251 SetZone("z1"). 252 SetEndpoint("h4p3e"). 253 SetWeight(2) 254 255 res, err = selector.SelectInitialInstances( 256 []placement.Instance{ 257 h1p1.SetShardSetID(0), 258 h1p2.SetShardSetID(0), 259 h1p3.SetShardSetID(0), 260 h2p1.SetShardSetID(0), 261 h2p2.SetShardSetID(0), 262 h2p3.SetShardSetID(0), 263 h3p1.SetShardSetID(0), 264 h3p2.SetShardSetID(0), 265 h3p3.SetShardSetID(0), 266 h4p1.SetShardSetID(0), 267 h4p2.SetShardSetID(0), 268 h4p3.SetShardSetID(0), 269 }, 270 2, 271 ) 272 require.NoError(t, err) 273 require.Equal(t, 12, len(res)) 274 require.Equal(t, h1p1.ShardSetID(), h2p1.ShardSetID()) 275 require.Equal(t, h1p2.ShardSetID(), h2p2.ShardSetID()) 276 require.Equal(t, h1p3.ShardSetID(), h2p3.ShardSetID()) 277 require.Equal(t, h3p1.ShardSetID(), h4p1.ShardSetID()) 278 require.Equal(t, h3p2.ShardSetID(), h4p2.ShardSetID()) 279 require.Equal(t, h3p3.ShardSetID(), h4p3.ShardSetID()) 280 281 ssIDs = make(map[uint32]int) 282 for i := 1; i <= 6; i++ { 283 ssIDs[uint32(i)] = 2 284 } 285 286 for _, instance := range res { 287 ssIDs[instance.ShardSetID()] = ssIDs[instance.ShardSetID()] - 1 288 } 289 290 for _, count := range ssIDs { 291 require.Equal(t, 0, count) 292 } 293 } 294 295 func TestSelectInitialInstancesForMirrorRF3(t *testing.T) { 296 h1p1 := placement.NewInstance(). 297 SetID("h1p1"). 298 SetHostname("h1"). 299 SetPort(1). 300 SetIsolationGroup("r1"). 301 SetZone("z1"). 302 SetEndpoint("h1p1e"). 303 SetWeight(1) 304 h1p2 := placement.NewInstance(). 305 SetID("h1p2"). 306 SetHostname("h1"). 307 SetPort(2). 308 SetIsolationGroup("r1"). 309 SetZone("z1"). 310 SetEndpoint("h1p2e"). 311 SetWeight(1) 312 h1p3 := placement.NewInstance(). 313 SetID("h1p3"). 314 SetHostname("h1"). 315 SetPort(3). 316 SetIsolationGroup("r1"). 317 SetZone("z1"). 318 SetEndpoint("h1p3e"). 319 SetWeight(1) 320 h2p1 := placement.NewInstance(). 321 SetID("h2p1"). 322 SetHostname("h2"). 323 SetPort(1). 324 SetIsolationGroup("r2"). 325 SetZone("z1"). 326 SetEndpoint("h2p1e"). 327 SetWeight(1) 328 h2p2 := placement.NewInstance(). 329 SetID("h2p2"). 330 SetHostname("h2"). 331 SetPort(2). 332 SetIsolationGroup("r2"). 333 SetZone("z1"). 334 SetEndpoint("h2p2e"). 335 SetWeight(1) 336 h2p3 := placement.NewInstance(). 337 SetID("h2p3"). 338 SetHostname("h2"). 339 SetPort(3). 340 SetIsolationGroup("r2"). 341 SetZone("z1"). 342 SetEndpoint("h2p3e"). 343 SetWeight(1) 344 h3p1 := placement.NewInstance(). 345 SetID("h3p1"). 346 SetHostname("h3"). 347 SetPort(1). 348 SetIsolationGroup("r3"). 349 SetZone("z1"). 350 SetEndpoint("h3p1e"). 351 SetWeight(1) 352 h3p2 := placement.NewInstance(). 353 SetID("h3p2"). 354 SetHostname("h3"). 355 SetPort(2). 356 SetIsolationGroup("r3"). 357 SetZone("z1"). 358 SetEndpoint("h3p2e"). 359 SetWeight(1) 360 h3p3 := placement.NewInstance(). 361 SetID("h3p3"). 362 SetHostname("h3"). 363 SetPort(3). 364 SetIsolationGroup("r3"). 365 SetZone("z1"). 366 SetEndpoint("h3p3e"). 367 SetWeight(1) 368 369 selector := NewPortMirroredSelector(placement.NewOptions().SetValidZone("z1")) 370 res, err := selector.SelectInitialInstances( 371 []placement.Instance{h1p1, h1p2, h1p3, h2p1, h2p2, h2p3, h3p1, h3p2, h3p3}, 372 3, 373 ) 374 require.NoError(t, err) 375 require.Equal(t, 9, len(res)) 376 require.Equal(t, h1p1.ShardSetID(), h2p1.ShardSetID()) 377 require.Equal(t, h1p1.ShardSetID(), h3p1.ShardSetID()) 378 require.Equal(t, h1p2.ShardSetID(), h2p2.ShardSetID()) 379 require.Equal(t, h1p2.ShardSetID(), h3p2.ShardSetID()) 380 require.Equal(t, h1p3.ShardSetID(), h2p3.ShardSetID()) 381 require.Equal(t, h1p3.ShardSetID(), h3p3.ShardSetID()) 382 383 ssIDs := make(map[uint32]int) 384 for i := 1; i <= 3; i++ { 385 ssIDs[uint32(i)] = 3 386 } 387 388 for _, instance := range res { 389 ssIDs[instance.ShardSetID()] = ssIDs[instance.ShardSetID()] - 1 390 } 391 392 for _, count := range ssIDs { 393 require.Equal(t, 0, count) 394 } 395 } 396 397 func TestSelectReplaceInstanceForMirror(t *testing.T) { 398 h1p1 := placement.NewInstance(). 399 SetID("h1p1"). 400 SetHostname("h1"). 401 SetPort(1). 402 SetIsolationGroup("r1"). 403 SetZone("z1"). 404 SetEndpoint("h1p1e"). 405 SetWeight(1). 406 SetShardSetID(1) 407 h1p2 := placement.NewInstance(). 408 SetID("h1p2"). 409 SetHostname("h1"). 410 SetPort(2). 411 SetIsolationGroup("r1"). 412 SetZone("z1"). 413 SetEndpoint("h1p2e"). 414 SetWeight(1). 415 SetShardSetID(2) 416 h2p1 := placement.NewInstance(). 417 SetID("h2p1"). 418 SetHostname("h2"). 419 SetPort(1). 420 SetIsolationGroup("r2"). 421 SetZone("z1"). 422 SetEndpoint("h2p1e"). 423 SetWeight(1). 424 SetShardSetID(1) 425 h2p2 := placement.NewInstance(). 426 SetID("h2p2"). 427 SetHostname("h2"). 428 SetPort(2). 429 SetIsolationGroup("r2"). 430 SetZone("z1"). 431 SetEndpoint("h2p2e"). 432 SetWeight(1). 433 SetShardSetID(2) 434 435 p := placement.NewPlacement(). 436 SetInstances([]placement.Instance{h1p1, h1p2, h2p1, h2p2}). 437 SetIsMirrored(true). 438 SetIsSharded(true). 439 SetReplicaFactor(2) 440 441 h3p1 := placement.NewInstance(). 442 SetID("h3p1"). 443 SetHostname("h3"). 444 SetPort(1). 445 SetIsolationGroup("r1"). 446 SetZone("z1"). 447 SetEndpoint("h3p1e"). 448 SetWeight(1) 449 h3p2 := placement.NewInstance(). 450 SetID("h3p2"). 451 SetHostname("h3"). 452 SetPort(2). 453 SetIsolationGroup("r1"). 454 SetZone("z1"). 455 SetEndpoint("h3p2e"). 456 SetWeight(1) 457 458 selector := NewPortMirroredSelector(placement.NewOptions().SetValidZone("z1")) 459 res, err := selector.SelectReplaceInstances( 460 []placement.Instance{h3p1, h3p2}, 461 []string{h1p1.ID(), h1p2.ID()}, 462 p, 463 ) 464 require.NoError(t, err) 465 require.Equal(t, 2, len(res)) 466 require.Equal(t, h3p1.ShardSetID(), res[0].ShardSetID()) 467 require.Equal(t, h3p2.ShardSetID(), res[1].ShardSetID()) 468 469 // Isolation group conflict. 470 _, err = selector.SelectReplaceInstances( 471 []placement.Instance{h3p1, h3p2}, 472 []string{h2p1.ID(), h2p2.ID()}, 473 p, 474 ) 475 require.Error(t, err) 476 477 // More than 1 host. 478 _, err = selector.SelectReplaceInstances( 479 []placement.Instance{h3p1, h3p2}, 480 []string{h1p1.ID(), h2p1.ID()}, 481 p, 482 ) 483 require.Error(t, err) 484 485 // No matching weight. 486 h3p1.SetWeight(2) 487 h3p2.SetWeight(2) 488 489 _, err = selector.SelectReplaceInstances( 490 []placement.Instance{h3p1, h3p2}, 491 []string{h1p1.ID(), h1p2.ID()}, 492 p, 493 ) 494 require.Error(t, err) 495 } 496 497 func TestSelectReplaceInstancesWithLeaving(t *testing.T) { 498 s1 := shard.NewShard(1).SetState(shard.Leaving) 499 h1p1 := placement.NewInstance(). 500 SetID("h1p1"). 501 SetHostname("h1"). 502 SetPort(1). 503 SetIsolationGroup("r1"). 504 SetZone("z1"). 505 SetEndpoint("h1p1e"). 506 SetWeight(1). 507 SetShardSetID(1). 508 SetShards(shard.NewShards([]shard.Shard{s1})) 509 s2 := shard.NewShard(1).SetState(shard.Initializing) 510 h2p1 := placement.NewInstance(). 511 SetID("h2p1"). 512 SetHostname("h2"). 513 SetPort(1). 514 SetIsolationGroup("r2"). 515 SetZone("z1"). 516 SetEndpoint("h2p1e"). 517 SetWeight(1). 518 SetShardSetID(1). 519 SetShards(shard.NewShards([]shard.Shard{s2})) 520 521 p := placement.NewPlacement(). 522 SetInstances([]placement.Instance{h1p1, h2p1}). 523 SetIsMirrored(true). 524 SetIsSharded(true). 525 SetReplicaFactor(1) 526 527 selector := NewPortMirroredSelector(placement.NewOptions().SetValidZone("z1")) 528 res, err := selector.SelectReplaceInstances( 529 []placement.Instance{h1p1, h2p1}, 530 []string{h2p1.ID()}, 531 p, 532 ) 533 require.NoError(t, err) 534 require.Equal(t, 1, len(res)) 535 require.Equal(t, h1p1, res[0]) 536 } 537 538 func TestSelectAddingInstanceForMirror(t *testing.T) { 539 h1p1 := placement.NewInstance(). 540 SetID("h1p1"). 541 SetHostname("h1"). 542 SetPort(1). 543 SetIsolationGroup("r1"). 544 SetZone("z1"). 545 SetEndpoint("h1p1e"). 546 SetWeight(1). 547 SetShardSetID(1) 548 h1p2 := placement.NewInstance(). 549 SetID("h1p2"). 550 SetHostname("h1"). 551 SetPort(2). 552 SetIsolationGroup("r1"). 553 SetZone("z1"). 554 SetEndpoint("h1p2e"). 555 SetWeight(1). 556 SetShardSetID(2) 557 h2p1 := placement.NewInstance(). 558 SetID("h2p1"). 559 SetHostname("h2"). 560 SetPort(1). 561 SetIsolationGroup("r2"). 562 SetZone("z1"). 563 SetEndpoint("h2p1e"). 564 SetWeight(1). 565 SetShardSetID(1) 566 h2p2 := placement.NewInstance(). 567 SetID("h2p2"). 568 SetHostname("h2"). 569 SetPort(2). 570 SetIsolationGroup("r2"). 571 SetZone("z1"). 572 SetEndpoint("h2p2e"). 573 SetWeight(1). 574 SetShardSetID(2) 575 576 p := placement.NewPlacement(). 577 SetInstances([]placement.Instance{h1p1, h1p2, h2p1, h2p2}). 578 SetIsMirrored(true). 579 SetIsSharded(true). 580 SetReplicaFactor(2). 581 SetMaxShardSetID(2) 582 583 h3p1 := placement.NewInstance(). 584 SetID("h3p1"). 585 SetHostname("h3"). 586 SetPort(1). 587 SetIsolationGroup("r1"). 588 SetZone("z1"). 589 SetEndpoint("h3p1e"). 590 SetWeight(1) 591 h3p2 := placement.NewInstance(). 592 SetID("h3p2"). 593 SetHostname("h3"). 594 SetPort(2). 595 SetIsolationGroup("r1"). 596 SetZone("z1"). 597 SetEndpoint("h3p2e"). 598 SetWeight(1) 599 h4p1 := placement.NewInstance(). 600 SetID("h4p1"). 601 SetHostname("h4"). 602 SetPort(1). 603 SetIsolationGroup("r3"). 604 SetZone("z1"). 605 SetEndpoint("h4p1e"). 606 SetWeight(1) 607 h4p2 := placement.NewInstance(). 608 SetID("h4p2"). 609 SetHostname("h4"). 610 SetPort(2). 611 SetIsolationGroup("r3"). 612 SetZone("z1"). 613 SetEndpoint("h4p2e"). 614 SetWeight(1) 615 616 selector := NewPortMirroredSelector(placement.NewOptions().SetValidZone("z1")) 617 res, err := selector.SelectAddingInstances( 618 []placement.Instance{h3p1, h3p2, h4p1, h4p2}, 619 p, 620 ) 621 require.NoError(t, err) 622 require.Equal(t, 4, len(res)) 623 624 // Make sure leaving nodes are eligible for adding. 625 h1p1.SetShards(shard.NewShards([]shard.Shard{shard.NewShard(0).SetState(shard.Leaving)})) 626 h2p1.SetShards(shard.NewShards([]shard.Shard{shard.NewShard(0).SetState(shard.Leaving)})) 627 628 require.Equal(t, h1p1.ShardSetID(), h2p1.ShardSetID()) 629 require.Equal(t, uint32(1), h1p1.ShardSetID()) 630 res, err = selector.SelectAddingInstances( 631 []placement.Instance{h1p1, h2p1}, 632 p, 633 ) 634 require.NoError(t, err) 635 require.Equal(t, 2, len(res)) 636 for _, instance := range res { 637 require.Equal(t, uint32(1), instance.ShardSetID()) 638 } 639 640 res, err = selector.SelectAddingInstances( 641 []placement.Instance{h1p1, h4p1}, 642 p, 643 ) 644 require.NoError(t, err) 645 require.Equal(t, 2, len(res)) 646 for _, instance := range res { 647 require.Equal(t, uint32(3), instance.ShardSetID()) 648 } 649 650 _, err = selector.SelectAddingInstances( 651 []placement.Instance{h3p2, h4p1}, 652 p, 653 ) 654 require.Error(t, err) 655 656 _, err = selector.SelectAddingInstances( 657 []placement.Instance{h3p1, h3p2}, 658 p, 659 ) 660 require.Error(t, err) 661 662 // No matching weight. 663 h3p1.SetWeight(2) 664 h3p2.SetWeight(2) 665 666 _, err = selector.SelectAddingInstances( 667 []placement.Instance{h3p1, h3p2, h4p1, h4p2}, 668 p, 669 ) 670 require.Error(t, err) 671 } 672 673 func TestSelectAddingInstanceForMirrorWithAddAllCandidates(t *testing.T) { 674 h1p1 := placement.NewInstance(). 675 SetID("h1p1"). 676 SetHostname("h1"). 677 SetPort(1). 678 SetIsolationGroup("r1"). 679 SetZone("z1"). 680 SetEndpoint("h1p1e"). 681 SetWeight(1). 682 SetShardSetID(1) 683 h1p2 := placement.NewInstance(). 684 SetID("h1p2"). 685 SetHostname("h1"). 686 SetPort(2). 687 SetIsolationGroup("r1"). 688 SetZone("z1"). 689 SetEndpoint("h1p2e"). 690 SetWeight(1). 691 SetShardSetID(2) 692 h2p1 := placement.NewInstance(). 693 SetID("h2p1"). 694 SetHostname("h2"). 695 SetPort(1). 696 SetIsolationGroup("r2"). 697 SetZone("z1"). 698 SetEndpoint("h2p1e"). 699 SetWeight(1). 700 SetShardSetID(1) 701 h2p2 := placement.NewInstance(). 702 SetID("h2p2"). 703 SetHostname("h2"). 704 SetPort(2). 705 SetIsolationGroup("r2"). 706 SetZone("z1"). 707 SetEndpoint("h2p2e"). 708 SetWeight(1). 709 SetShardSetID(2) 710 711 p := placement.NewPlacement(). 712 SetInstances([]placement.Instance{h1p1, h1p2, h2p1, h2p2}). 713 SetIsMirrored(true). 714 SetIsSharded(true). 715 SetReplicaFactor(2). 716 SetMaxShardSetID(2) 717 718 h3p1 := placement.NewInstance(). 719 SetID("h3p1"). 720 SetHostname("h3"). 721 SetPort(1). 722 SetIsolationGroup("r1"). 723 SetZone("z1"). 724 SetEndpoint("h3p1e"). 725 SetWeight(1) 726 h3p2 := placement.NewInstance(). 727 SetID("h3p2"). 728 SetHostname("h3"). 729 SetPort(2). 730 SetIsolationGroup("r1"). 731 SetZone("z1"). 732 SetEndpoint("h3p2e"). 733 SetWeight(1) 734 h4p1 := placement.NewInstance(). 735 SetID("h4p1"). 736 SetHostname("h4"). 737 SetPort(1). 738 SetIsolationGroup("r3"). 739 SetZone("z1"). 740 SetEndpoint("h4p1e"). 741 SetWeight(1) 742 h4p2 := placement.NewInstance(). 743 SetID("h4p2"). 744 SetHostname("h4"). 745 SetPort(2). 746 SetIsolationGroup("r3"). 747 SetZone("z1"). 748 SetEndpoint("h4p2e"). 749 SetWeight(1) 750 h5p1 := placement.NewInstance(). 751 SetID("h5p1"). 752 SetHostname("h5"). 753 SetPort(1). 754 SetIsolationGroup("r1"). 755 SetZone("z1"). 756 SetEndpoint("h5p1e"). 757 SetWeight(1) 758 h5p2 := placement.NewInstance(). 759 SetID("h5p2"). 760 SetHostname("h5"). 761 SetPort(2). 762 SetIsolationGroup("r1"). 763 SetZone("z1"). 764 SetEndpoint("h5p2e"). 765 SetWeight(1) 766 h6p1 := placement.NewInstance(). 767 SetID("h6p1"). 768 SetHostname("h6"). 769 SetPort(1). 770 SetIsolationGroup("r3"). 771 SetZone("z1"). 772 SetEndpoint("h6p1e"). 773 SetWeight(1) 774 h6p2 := placement.NewInstance(). 775 SetID("h6p2"). 776 SetHostname("h6"). 777 SetPort(2). 778 SetIsolationGroup("r3"). 779 SetZone("z1"). 780 SetEndpoint("h6p2e"). 781 SetWeight(1) 782 783 selector := NewPortMirroredSelector(placement.NewOptions().SetValidZone("z1").SetAddAllCandidates(true)) 784 res, err := selector.SelectAddingInstances( 785 []placement.Instance{h3p1, h3p2, h4p1, h4p2, h5p1, h5p2, h6p1, h6p2}, 786 p, 787 ) 788 require.NoError(t, err) 789 require.Equal(t, 8, len(res)) 790 require.Equal(t, h3p1.ShardSetID(), h4p1.ShardSetID()) 791 require.Equal(t, h3p2.ShardSetID(), h4p2.ShardSetID()) 792 require.Equal(t, h5p1.ShardSetID(), h6p1.ShardSetID()) 793 require.Equal(t, h5p1.ShardSetID(), h6p1.ShardSetID()) 794 } 795 796 func TestGroupInstancesByHostPort(t *testing.T) { 797 t.Run("maintains host order with 2 instances", func(t *testing.T) { 798 port := uint32(5) 799 i1 := newInstanceWithID("i1").SetPort(port).SetHostname("h1") 800 i2 := newInstanceWithID("i2").SetPort(port).SetHostname("h2") 801 802 hosts := [][]host{{{ 803 name: "h1", 804 isolationGroup: "g1", 805 portToInstance: map[uint32]placement.Instance{ 806 port: i1, 807 }, 808 }, { 809 name: "h2", 810 isolationGroup: "g2", 811 portToInstance: map[uint32]placement.Instance{ 812 port: i2, 813 }, 814 }}} 815 816 groups, err := groupInstancesByHostPort(hosts, false) 817 require.NoError(t, err) 818 819 assert.Equal(t, [][]placement.Instance{{i1, i2}}, groups) 820 }) 821 822 t.Run("maintains host order with 2 instances with different ports", func(t *testing.T) { 823 port1 := uint32(5) 824 i1 := newInstanceWithID("i1").SetPort(port1).SetHostname("h1") 825 port2 := uint32(15) 826 i2 := newInstanceWithID("i2").SetPort(port2).SetHostname("h2") 827 828 hosts := [][]host{{{ 829 name: "h1", 830 isolationGroup: "g1", 831 portToInstance: map[uint32]placement.Instance{ 832 port1: i1, 833 }, 834 }, { 835 name: "h2", 836 isolationGroup: "g2", 837 portToInstance: map[uint32]placement.Instance{ 838 port2: i2, 839 }, 840 }}} 841 842 groups, err := groupInstancesByHostPort(hosts, true) 843 require.NoError(t, err) 844 assert.Equal(t, [][]placement.Instance{{i1, i2}}, groups) 845 846 _, err = groupInstancesByHostPort(hosts, false) 847 require.NotNil(t, err) 848 }) 849 }