github.com/searKing/golang/go@v1.2.117/container/hashring/hashring_test.go (about) 1 // Copyright 2020 The searKing Author. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package hashring 6 7 import ( 8 "runtime" 9 "sort" 10 "strconv" 11 "testing" 12 "testing/quick" 13 ) 14 15 func TestNew(t *testing.T) { 16 numReps := 160 17 x := New(WithNumberNodeRepetitions(numReps)) 18 if x == nil { 19 t.Errorf("expected obj") 20 return 21 } 22 23 if x.numReps != numReps { 24 t.Errorf("got %d, want %d", x.numReps, numReps) 25 } 26 } 27 28 func TestAdd(t *testing.T) { 29 numReps := 160 30 x := New(WithNumberNodeRepetitions(numReps)) 31 x.AddNodes(StringNode("abcdefg")) 32 33 if len(x.nodeByKey) != numReps { 34 t.Errorf("got %d, want %d", len(x.nodeByKey), numReps) 35 } 36 if len(x.sortedKeys) != numReps { 37 t.Errorf("got %d, want %d", len(x.sortedKeys), numReps) 38 } 39 if sort.IsSorted(x.sortedKeys) == false { 40 t.Errorf("expected sorted hashes to be sorted") 41 } 42 x.AddNodes(StringNode("qwer")) 43 44 if len(x.nodeByKey) != 2*numReps { 45 t.Errorf("got %d, want %d", len(x.nodeByKey), 2*numReps) 46 } 47 if len(x.sortedKeys) != 2*numReps { 48 t.Errorf("got %d, want %d", len(x.nodeByKey), 2*numReps) 49 } 50 if sort.IsSorted(x.sortedKeys) == false { 51 t.Errorf("expected sorted hashes to be sorted") 52 } 53 } 54 55 func TestRemove(t *testing.T) { 56 numReps := 160 57 x := New(WithNumberNodeRepetitions(numReps)) 58 x.AddNodes(StringNode("abcdefg")) 59 x.RemoveNodes(StringNode("abcdefg")) 60 if len(x.nodeByKey) != 0 { 61 t.Errorf("got %d, want %d", len(x.nodeByKey), 0) 62 } 63 if len(x.sortedKeys) != 0 { 64 t.Errorf("got %d, want %d", len(x.nodeByKey), 0) 65 } 66 } 67 68 func TestRemoveNonExisting(t *testing.T) { 69 numReps := 160 70 x := New(WithNumberNodeRepetitions(numReps)) 71 x.AddNodes(StringNode("abcdefg")) 72 x.RemoveNodes(StringNode("abcdefghijk")) 73 if len(x.nodeByKey) != numReps { 74 t.Errorf("got %d, want %d", len(x.nodeByKey), numReps) 75 } 76 } 77 78 func TestGetEmpty(t *testing.T) { 79 numReps := 160 80 x := New(WithNumberNodeRepetitions(numReps)) 81 _, has := x.Get("asdfsadfsadf") 82 if has { 83 t.Errorf("expected error") 84 } 85 } 86 87 func TestGetSingle(t *testing.T) { 88 numReps := 160 89 x := New(WithNumberNodeRepetitions(numReps)) 90 x.AddNodes(StringNode("abcdefg")) 91 f := func(s string) bool { 92 y, has := x.Get(s) 93 if !has { 94 return false 95 } 96 // t.Logf("s = %q, y = %q", s, y) 97 return y.String() == "abcdefg" 98 } 99 if err := quick.Check(f, nil); err != nil { 100 t.Logf("missing nodes") 101 } 102 } 103 104 type gtest struct { 105 in string 106 out string 107 } 108 109 var gmtests = []gtest{ 110 {"ggg", "abcdefg"}, 111 {"hhh", "opqrstu"}, 112 {"iii", "hijklmn"}, 113 } 114 115 func TestGetMultiple(t *testing.T) { 116 x := New() 117 x.AddNodes(StringNode("abcdefg")) 118 x.AddNodes(StringNode("hijklmn")) 119 x.AddNodes(StringNode("opqrstu")) 120 for i, v := range gmtests { 121 result, has := x.Get(v.in) 122 if !has { 123 t.Fatal() 124 } 125 if result.String() != v.out { 126 t.Errorf("%d. got %q, expected %q", i, result, v.out) 127 } 128 } 129 } 130 131 func TestGetMultipleQuick(t *testing.T) { 132 x := New() 133 x.AddNodes(StringNode("abcdefg")) 134 x.AddNodes(StringNode("hijklmn")) 135 x.AddNodes(StringNode("opqrstu")) 136 f := func(s string) bool { 137 y, has := x.Get(s) 138 if !has { 139 return false 140 } 141 // t.Logf("s = %q, y = %q", s, y) 142 return y.String() == "abcdefg" || 143 y.String() == "hijklmn" || 144 y.String() == "opqrstu" 145 } 146 if err := quick.Check(f, nil); err != nil { 147 t.Logf("missing nodes") 148 } 149 } 150 151 var rtestsBefore = []gtest{ 152 {"ggg", "abcdefg"}, 153 {"hhh", "opqrstu"}, 154 {"iii", "hijklmn"}, 155 } 156 157 var rtestsAfter = []gtest{ 158 {"ggg", "abcdefg"}, 159 {"hhh", "opqrstu"}, 160 {"iii", "abcdefg"}, 161 } 162 163 func TestGetMultipleRemove(t *testing.T) { 164 x := New() 165 x.AddNodes(StringNode("abcdefg")) 166 x.AddNodes(StringNode("hijklmn")) 167 x.AddNodes(StringNode("opqrstu")) 168 for i, v := range rtestsBefore { 169 result, has := x.Get(v.in) 170 if !has { 171 t.Fatal() 172 } 173 if result.String() != v.out { 174 t.Errorf("%d. got %q, expected %q before rm", i, result, v.out) 175 } 176 } 177 x.RemoveNodes(StringNode("hijklmn")) 178 for i, v := range rtestsAfter { 179 result, has := x.Get(v.in) 180 if !has { 181 t.Fatal() 182 } 183 if result.String() != v.out { 184 t.Errorf("%d. got %q, expected %q after rm", i, result, v.out) 185 } 186 } 187 } 188 189 func TestGetMultipleRemoveQuick(t *testing.T) { 190 x := New() 191 x.AddNodes(StringNode("abcdefg")) 192 x.AddNodes(StringNode("hijklmn")) 193 x.AddNodes(StringNode("opqrstu")) 194 x.RemoveNodes(StringNode("opqrstu")) 195 f := func(s string) bool { 196 y, has := x.Get(s) 197 if !has { 198 t.Logf("missing node") 199 return false 200 } 201 //t.Logf("s = %q, y = %q", s, y) 202 return y.String() == "abcdefg" || y.String() == "hijklmn" 203 } 204 if err := quick.Check(f, nil); err != nil { 205 t.Logf("missing nodes") 206 } 207 } 208 209 func TestGetTwo(t *testing.T) { 210 x := New() 211 x.AddNodes(StringNode("abcdefg")) 212 x.AddNodes(StringNode("hijklmn")) 213 x.AddNodes(StringNode("opqrstu")) 214 a, b, has := x.GetTwo("99999999") 215 if !has { 216 t.Fatal("missing nodes") 217 } 218 if a == b { 219 t.Errorf("a shouldn't equal b") 220 } 221 if a.String() != "opqrstu" { 222 t.Errorf("wrong a: %q", a) 223 } 224 if b.String() != "hijklmn" { 225 t.Errorf("wrong b: %q", b) 226 } 227 } 228 229 func TestGetTwoQuick(t *testing.T) { 230 x := New() 231 x.AddNodes(StringNode("abcdefg")) 232 x.AddNodes(StringNode("hijklmn")) 233 x.AddNodes(StringNode("opqrstu")) 234 f := func(s string) bool { 235 a, b, has := x.GetTwo(s) 236 if !has { 237 t.Logf("missing nodes") 238 return false 239 } 240 if a == b { 241 t.Logf("a == b") 242 return false 243 } 244 if a.String() != "abcdefg" && 245 a.String() != "hijklmn" && 246 a.String() != "opqrstu" { 247 t.Logf("invalid a: %q", a) 248 return false 249 } 250 251 if b.String() != "abcdefg" && 252 b.String() != "hijklmn" && 253 b.String() != "opqrstu" { 254 t.Logf("invalid b: %q", b) 255 return false 256 } 257 return true 258 } 259 if err := quick.Check(f, nil); err != nil { 260 t.Logf("missing nodes") 261 } 262 } 263 264 func TestGetTwoOnlyTwoQuick(t *testing.T) { 265 x := New() 266 x.AddNodes(StringNode("abcdefg")) 267 x.AddNodes(StringNode("hijklmn")) 268 f := func(s string) bool { 269 a, b, has := x.GetTwo(s) 270 if !has { 271 t.Logf("missing nodes") 272 return false 273 } 274 if a == b { 275 t.Logf("a == b") 276 return false 277 } 278 if a.String() != "abcdefg" && a.String() != "hijklmn" { 279 t.Logf("invalid a: %q", a) 280 return false 281 } 282 283 if b.String() != "abcdefg" && b.String() != "hijklmn" { 284 t.Logf("invalid b: %q", b) 285 return false 286 } 287 return true 288 } 289 if err := quick.Check(f, nil); err != nil { 290 t.Logf("missing nodes") 291 } 292 } 293 294 func TestGetTwoOnlyOneInCircle(t *testing.T) { 295 x := New() 296 297 x.AddNodes(StringNode("abcdefg")) 298 a, b, has := x.GetTwo("99999999") 299 if !has { 300 t.Logf("missing nodes") 301 } 302 if a == b { 303 t.Errorf("a shouldn't equal b") 304 } 305 if a.String() != "abcdefg" { 306 t.Errorf("wrong a: %q", a) 307 } 308 if b != nil { 309 t.Errorf("wrong b: %q", b) 310 } 311 } 312 313 func TestGetN(t *testing.T) { 314 x := New() 315 x.AddNodes(StringNode("abcdefg")) 316 x.AddNodes(StringNode("hijklmn")) 317 x.AddNodes(StringNode("opqrstu")) 318 members, has := x.GetN("9999999", 3) 319 if !has { 320 t.Logf("missing nodes") 321 } 322 if len(members) != 3 { 323 t.Errorf("expected 3 allNodes instead of %d", len(members)) 324 } 325 if members[0].String() != "abcdefg" { 326 t.Errorf("wrong allNodes[0]: %q", members[0]) 327 } 328 if members[1].String() != "opqrstu" { 329 t.Errorf("wrong allNodes[1]: %q", members[1]) 330 } 331 if members[2].String() != "hijklmn" { 332 t.Errorf("wrong allNodes[2]: %q", members[2]) 333 } 334 } 335 336 func TestGetNLess(t *testing.T) { 337 x := New() 338 x.AddNodes(StringNode("abcdefg")) 339 x.AddNodes(StringNode("hijklmn")) 340 x.AddNodes(StringNode("opqrstu")) 341 members, has := x.GetN("99999999", 2) 342 if !has { 343 t.Logf("missing nodes") 344 } 345 if len(members) != 2 { 346 t.Errorf("expected 2 allNodes instead of %d", len(members)) 347 } 348 if members[0].String() != "opqrstu" { 349 t.Errorf("wrong allNodes[0]: %q", members[0]) 350 } 351 if members[1].String() != "hijklmn" { 352 t.Errorf("wrong allNodes[1]: %q", members[1]) 353 } 354 } 355 356 func TestGetNMore(t *testing.T) { 357 x := New() 358 x.AddNodes(StringNode("abcdefg")) 359 x.AddNodes(StringNode("hijklmn")) 360 x.AddNodes(StringNode("opqrstu")) 361 members, has := x.GetN("9999999", 5) 362 if !has { 363 t.Logf("missing nodes") 364 } 365 if len(members) != 3 { 366 t.Errorf("expected 3 allNodes instead of %d", len(members)) 367 } 368 if members[0].String() != "abcdefg" { 369 t.Errorf("wrong allNodes[0]: %q", members[0]) 370 } 371 if members[1].String() != "opqrstu" { 372 t.Errorf("wrong allNodes[1]: %q", members[1]) 373 } 374 if members[2].String() != "hijklmn" { 375 t.Errorf("wrong allNodes[2]: %q", members[2]) 376 } 377 } 378 379 func TestGetNQuick(t *testing.T) { 380 x := New() 381 x.AddNodes(StringNode("abcdefg")) 382 x.AddNodes(StringNode("hijklmn")) 383 x.AddNodes(StringNode("opqrstu")) 384 f := func(s string) bool { 385 members, has := x.GetN(s, 3) 386 if !has { 387 t.Logf("missing nodes") 388 return false 389 } 390 if len(members) != 3 { 391 t.Logf("expected 3 allNodes instead of %d", len(members)) 392 return false 393 } 394 set := make(map[string]bool, 4) 395 for _, member := range members { 396 if set[member.String()] { 397 t.Logf("duplicate error") 398 return false 399 } 400 set[member.String()] = true 401 if member.String() != "abcdefg" && 402 member.String() != "hijklmn" && 403 member.String() != "opqrstu" { 404 t.Logf("invalid member: %q", member) 405 return false 406 } 407 } 408 return true 409 } 410 if err := quick.Check(f, nil); err != nil { 411 t.Logf("missing nodes") 412 } 413 } 414 415 func TestGetNLessQuick(t *testing.T) { 416 x := New() 417 x.AddNodes(StringNode("abcdefg")) 418 x.AddNodes(StringNode("hijklmn")) 419 x.AddNodes(StringNode("opqrstu")) 420 f := func(s string) bool { 421 members, has := x.GetN(s, 2) 422 if !has { 423 t.Logf("missing nodes") 424 return false 425 } 426 if len(members) != 2 { 427 t.Logf("expected 2 allNodes instead of %d", len(members)) 428 return false 429 } 430 set := make(map[string]bool, 4) 431 for _, member := range members { 432 if set[member.String()] { 433 t.Logf("duplicate error") 434 return false 435 } 436 set[member.String()] = true 437 if member.String() != "abcdefg" && 438 member.String() != "hijklmn" && 439 member.String() != "opqrstu" { 440 t.Logf("invalid member: %q", member) 441 return false 442 } 443 } 444 return true 445 } 446 if err := quick.Check(f, nil); err != nil { 447 t.Logf("missing nodes") 448 } 449 } 450 451 func TestGetNMoreQuick(t *testing.T) { 452 x := New() 453 x.AddNodes(StringNode("abcdefg")) 454 x.AddNodes(StringNode("hijklmn")) 455 x.AddNodes(StringNode("opqrstu")) 456 f := func(s string) bool { 457 // t.Log("check", s) 458 members, has := x.GetN(s, 5) 459 if !has { 460 t.Logf("missing nodes") 461 return false 462 } 463 if len(members) != 3 { 464 t.Logf("expected 3 allNodes instead of %d", len(members)) 465 return false 466 } 467 set := make(map[string]bool, 4) 468 for _, member := range members { 469 if set[member.String()] { 470 t.Logf("duplicate error") 471 return false 472 } 473 set[member.String()] = true 474 if member.String() != "abcdefg" && member.String() != "hijklmn" && member.String() != "opqrstu" { 475 t.Logf("invalid member: %q", member) 476 return false 477 } 478 } 479 return true 480 } 481 if err := quick.Check(f, nil); err != nil { 482 t.Logf("missing nodes") 483 } 484 } 485 486 func TestSet(t *testing.T) { 487 x := New() 488 x.AddNodes(StringNode("abc")) 489 x.AddNodes(StringNode("def")) 490 x.AddNodes(StringNode("ghi")) 491 x.SetNodes(StringNode("jkl"), StringNode("mno")) 492 if len(x.allNodes) != 2 { 493 t.Errorf("expected 2 elts, got %d", len(x.allNodes)) 494 } 495 a, b, has := x.GetTwo("qwerqwerwqer") 496 if !has { 497 t.Fatal() 498 } 499 if a.String() != "jkl" && a.String() != "mno" { 500 t.Errorf("expected jkl or mno, got %s", a) 501 } 502 if b.String() != "jkl" && b.String() != "mno" { 503 t.Errorf("expected jkl or mno, got %s", b) 504 } 505 if a == b { 506 t.Errorf("expected a != b, they were both %s", a) 507 } 508 x.SetNodes(StringNode("jkl"), StringNode("mno")) 509 if len(x.allNodes) != 2 { 510 t.Errorf("expected 2 elts, got %d", len(x.allNodes)) 511 } 512 a, b, has = x.GetTwo("qwerqwerwqer") 513 if !has { 514 t.Fatal() 515 } 516 if a.String() != "jkl" && a.String() != "mno" { 517 t.Errorf("expected jkl or mno, got %s", a) 518 } 519 if b.String() != "jkl" && b.String() != "mno" { 520 t.Errorf("expected jkl or mno, got %s", b) 521 } 522 if a == b { 523 t.Errorf("expected a != b, they were both %s", a) 524 } 525 x.SetNodes(StringNode("pqr"), StringNode("mno")) 526 if len(x.allNodes) != 2 { 527 t.Errorf("expected 2 elts, got %d", len(x.allNodes)) 528 } 529 a, b, has = x.GetTwo("qwerqwerwqer") 530 if !has { 531 t.Fatal() 532 } 533 if a.String() != "pqr" && a.String() != "mno" { 534 t.Errorf("expected jkl or mno, got %s", a) 535 } 536 if b.String() != "pqr" && b.String() != "mno" { 537 t.Errorf("expected jkl or mno, got %s", b) 538 } 539 if a == b { 540 t.Errorf("expected a != b, they were both %s", a) 541 } 542 } 543 544 // allocBytes returns the number of bytes allocated by invoking f. 545 func allocBytes(f func()) uint64 { 546 var stats runtime.MemStats 547 runtime.ReadMemStats(&stats) 548 t := stats.TotalAlloc 549 f() 550 runtime.ReadMemStats(&stats) 551 return stats.TotalAlloc - t 552 } 553 554 func mallocNum(f func()) uint64 { 555 var stats runtime.MemStats 556 runtime.ReadMemStats(&stats) 557 t := stats.Mallocs 558 f() 559 runtime.ReadMemStats(&stats) 560 return stats.Mallocs - t 561 } 562 563 func BenchmarkAllocations(b *testing.B) { 564 x := New() 565 x.AddNodes(StringNode("stays")) 566 b.ResetTimer() 567 allocSize := allocBytes(func() { 568 for i := 0; i < b.N; i++ { 569 x.AddNodes(StringNode("Foo")) 570 x.RemoveNodes(StringNode("Foo")) 571 } 572 }) 573 b.Logf("%d: Allocated %d bytes (%.2fx)", b.N, allocSize, float64(allocSize)/float64(b.N)) 574 } 575 576 func BenchmarkMalloc(b *testing.B) { 577 x := New() 578 x.AddNodes(StringNode("stays")) 579 b.ResetTimer() 580 mallocs := mallocNum(func() { 581 for i := 0; i < b.N; i++ { 582 x.AddNodes(StringNode("Foo")) 583 x.RemoveNodes(StringNode("Foo")) 584 } 585 }) 586 b.Logf("%d: Mallocd %d times (%.2fx)", b.N, mallocs, float64(mallocs)/float64(b.N)) 587 } 588 589 func BenchmarkCycle(b *testing.B) { 590 x := New() 591 x.AddNodes(StringNode("nothing")) 592 b.ResetTimer() 593 for i := 0; i < b.N; i++ { 594 x.AddNodes(StringNode("foo" + strconv.Itoa(i))) 595 x.RemoveNodes(StringNode("foo" + strconv.Itoa(i))) 596 } 597 } 598 599 func BenchmarkCycleLarge(b *testing.B) { 600 x := New() 601 for i := 0; i < 10; i++ { 602 x.AddNodes(StringNode("start" + strconv.Itoa(i))) 603 } 604 b.ResetTimer() 605 for i := 0; i < b.N; i++ { 606 x.AddNodes(StringNode("foo" + strconv.Itoa(i))) 607 x.RemoveNodes(StringNode("foo" + strconv.Itoa(i))) 608 } 609 } 610 611 func BenchmarkGet(b *testing.B) { 612 x := New() 613 x.AddNodes(StringNode("nothing")) 614 b.ResetTimer() 615 for i := 0; i < b.N; i++ { 616 x.Get("nothing") 617 } 618 } 619 620 func BenchmarkGetLarge(b *testing.B) { 621 x := New() 622 for i := 0; i < 10; i++ { 623 x.AddNodes(StringNode("start" + strconv.Itoa(i))) 624 } 625 b.ResetTimer() 626 for i := 0; i < b.N; i++ { 627 x.Get("nothing") 628 } 629 } 630 631 func BenchmarkGetN(b *testing.B) { 632 x := New() 633 x.AddNodes(StringNode("nothing")) 634 b.ResetTimer() 635 for i := 0; i < b.N; i++ { 636 x.GetN("nothing", 3) 637 } 638 } 639 640 func BenchmarkGetNLarge(b *testing.B) { 641 x := New() 642 for i := 0; i < 10; i++ { 643 x.AddNodes(StringNode("start" + strconv.Itoa(i))) 644 } 645 b.ResetTimer() 646 for i := 0; i < b.N; i++ { 647 x.GetN("nothing", 3) 648 } 649 } 650 651 func BenchmarkGetTwo(b *testing.B) { 652 x := New() 653 x.AddNodes(StringNode("nothing")) 654 b.ResetTimer() 655 for i := 0; i < b.N; i++ { 656 x.GetTwo("nothing") 657 } 658 } 659 660 func BenchmarkGetTwoLarge(b *testing.B) { 661 x := New() 662 for i := 0; i < 10; i++ { 663 x.AddNodes(StringNode("start" + strconv.Itoa(i))) 664 } 665 b.ResetTimer() 666 for i := 0; i < b.N; i++ { 667 x.GetTwo("nothing") 668 } 669 } 670 671 // from @edsrzf on github: 672 func TestAddCollision(t *testing.T) { 673 // These two strings produce several crc32 collisions after "|i" is 674 // appended added by NodeLocator.virtualNode. 675 const s1 = "abear" 676 const s2 = "solidiform" 677 x := New() 678 x.AddNodes(StringNode(s1)) 679 x.AddNodes(StringNode(s2)) 680 elt1, has := x.Get("abear") 681 if !has { 682 t.Fatal("missing node") 683 } 684 685 y := New() 686 // add elements in opposite order 687 y.AddNodes(StringNode(s2)) 688 y.AddNodes(StringNode(s1)) 689 elt2, has := y.Get(s1) 690 if !has { 691 t.Fatal("missing node") 692 } 693 694 if elt1 != elt2 { 695 t.Error(elt1, "and", elt2, "should be equal") 696 } 697 }