github.com/fufuok/balancer@v1.0.0/hash_test.go (about)

     1  package balancer
     2  
     3  import (
     4  	"strings"
     5  	"sync"
     6  	"sync/atomic"
     7  	"testing"
     8  )
     9  
    10  func TestConsistentHash(t *testing.T) {
    11  	lb := NewConsistentHash()
    12  	item := lb.Select()
    13  	if item != "" {
    14  		t.Fatalf("hash expected empty, actual %s", item)
    15  	}
    16  
    17  	lb.Add("A")
    18  	item = lb.Select()
    19  	if item != "A" {
    20  		t.Fatalf("hash expected A, actual %s", item)
    21  	}
    22  
    23  	nodes := []string{"A", "B", "C", "D"}
    24  	lb = NewConsistentHash(nodes)
    25  	item = lb.Select()
    26  	if item != "B" {
    27  		t.Fatalf("hash expected B, actual %s", item)
    28  	}
    29  	item = lb.Select()
    30  	if item != "B" {
    31  		t.Fatalf("hash expected B, actual %s", item)
    32  	}
    33  	item = lb.Select("192.168.1.100")
    34  	if item != "A" {
    35  		t.Fatalf("hash expected A, actual %s", item)
    36  	}
    37  	item = lb.Select("192.168.1.101")
    38  	if item != "C" {
    39  		t.Fatalf("hash expected C, actual %s", item)
    40  	}
    41  	item = lb.Select("192.168.1.102")
    42  	if item != "D" {
    43  		t.Fatalf("hash expected D, actual %s", item)
    44  	}
    45  	item = lb.Select("192.168.1.100")
    46  	if item != "A" {
    47  		t.Fatalf("hash expected A, actual %s", item)
    48  	}
    49  	item = lb.Select("2400:da00::6666")
    50  	if item != "C" {
    51  		t.Fatalf("hash expected C, actual %s", item)
    52  	}
    53  
    54  	for i := 0; i < 2000; i++ {
    55  		item := lb.Select("192.168.1.100")
    56  		if item != "A" {
    57  			t.Fatalf("hash expected A, actual %s", item)
    58  		}
    59  	}
    60  
    61  	lb.Add("E")
    62  	lb.Add("C")
    63  	lb.Add("E")
    64  	lb.Remove("B")
    65  	item = lb.Select("192.168.1.100")
    66  	if item != "A" {
    67  		t.Fatalf("hash expected A, actual %s", item)
    68  	}
    69  
    70  	all := lb.All().([]string)
    71  	if strings.Join(all, "") != "ACDECE" {
    72  		t.Fatalf("hash all() wrong")
    73  	}
    74  
    75  	lb.Remove("E")
    76  	all = lb.All().([]string)
    77  	if strings.Join(all, "") != "ACDCE" {
    78  		t.Fatalf("hash all() wrong")
    79  	}
    80  
    81  	lb.Remove("C", true)
    82  	all = lb.All().([]string)
    83  	if strings.Join(all, "") != "ADE" {
    84  		t.Fatalf("hash all() wrong")
    85  	}
    86  
    87  	lb.RemoveAll()
    88  	lb.Add("F", 1)
    89  	all, ok := lb.All().([]string)
    90  	if !ok || len(all) != 1 {
    91  		t.Fatal("hash all() wrong")
    92  	}
    93  
    94  	ok = lb.Update([]string{
    95  		"X",
    96  		"Y",
    97  	})
    98  	if ok != true {
    99  		t.Fatal("hash update wrong")
   100  	}
   101  	item = lb.Select()
   102  	if item != "Y" {
   103  		t.Fatal("hash update wrong")
   104  	}
   105  	item = lb.Select()
   106  	if item != "Y" {
   107  		t.Fatal("hash update wrong")
   108  	}
   109  }
   110  
   111  func TestConsistentHash_C(t *testing.T) {
   112  	var c int64
   113  	nodes := []string{"A", "B", "C", "D"}
   114  	lb := NewConsistentHash(nodes)
   115  
   116  	var wg sync.WaitGroup
   117  	for i := 0; i < 500; i++ {
   118  		wg.Add(1)
   119  		go func() {
   120  			defer wg.Done()
   121  			for j := 0; j < 2000; j++ {
   122  				switch lb.Select("192.168.1.7") {
   123  				case "C":
   124  					atomic.AddInt64(&c, 1)
   125  				default:
   126  				}
   127  			}
   128  		}()
   129  	}
   130  	wg.Wait()
   131  
   132  	if atomic.LoadInt64(&c) != 1000000 {
   133  		t.Fatalf("hash expected C == 1000000, actual C == %d, item: %s", atomic.LoadInt64(&c), lb.Select("192.168.1.7"))
   134  	}
   135  }