Beispiel #1
0
func TestRandom(t *testing.T) {
	p := loadbalancer.NewStaticPublisher([]endpoint.Endpoint{})
	defer p.Stop()

	lb := loadbalancer.Random(p)
	if _, err := lb.Get(); err == nil {
		t.Error("want error, got none")
	}

	counts := []int{0, 0, 0}
	p.Replace([]endpoint.Endpoint{
		func(context.Context, interface{}) (interface{}, error) { counts[0]++; return struct{}{}, nil },
		func(context.Context, interface{}) (interface{}, error) { counts[1]++; return struct{}{}, nil },
		func(context.Context, interface{}) (interface{}, error) { counts[2]++; return struct{}{}, nil },
	})
	assertLoadBalancerNotEmpty(t, lb)

	n := 10000
	for i := 0; i < n; i++ {
		e, _ := lb.Get()
		e(context.Background(), struct{}{})
	}

	want := float64(n) / float64(len(counts))
	tolerance := (want / 100.0) * 5 // 5%
	for _, have := range counts {
		if math.Abs(want-float64(have)) > tolerance {
			t.Errorf("want %.0f, have %d", want, have)
		}
	}
}
Beispiel #2
0
func TestRoundRobin(t *testing.T) {
	p := loadbalancer.NewStaticPublisher([]endpoint.Endpoint{})
	defer p.Stop()

	lb := loadbalancer.RoundRobin(p)
	if _, err := lb.Get(); err == nil {
		t.Error("want error, got none")
	}

	counts := []int{0, 0, 0}
	p.Replace([]endpoint.Endpoint{
		func(context.Context, interface{}) (interface{}, error) { counts[0]++; return struct{}{}, nil },
		func(context.Context, interface{}) (interface{}, error) { counts[1]++; return struct{}{}, nil },
		func(context.Context, interface{}) (interface{}, error) { counts[2]++; return struct{}{}, nil },
	})
	runtime.Gosched()

	for i, want := range [][]int{
		{1, 0, 0},
		{1, 1, 0},
		{1, 1, 1},
		{2, 1, 1},
		{2, 2, 1},
		{2, 2, 2},
		{3, 2, 2},
	} {
		e, _ := lb.Get()
		e(context.Background(), struct{}{})
		if have := counts; !reflect.DeepEqual(want, have) {
			t.Errorf("%d: want %v, have %v", i+1, want, have)
		}
	}
}
Beispiel #3
0
func TestRetryMax(t *testing.T) {
	var (
		endpoints = []endpoint.Endpoint{}
		p         = loadbalancer.NewStaticPublisher(endpoints)
		lb        = loadbalancer.RoundRobin(p)
	)

	if _, err := loadbalancer.Retry(999, time.Second, lb)(context.Background(), struct{}{}); err == nil {
		t.Errorf("expected error, got none")
	}

	endpoints = []endpoint.Endpoint{
		func(context.Context, interface{}) (interface{}, error) { return nil, errors.New("error one") },
		func(context.Context, interface{}) (interface{}, error) { return nil, errors.New("error two") },
		func(context.Context, interface{}) (interface{}, error) { return struct{}{}, nil /* OK */ },
	}
	p.Replace(endpoints)
	runtime.Gosched()

	if _, err := loadbalancer.Retry(len(endpoints)-1, time.Second, lb)(context.Background(), struct{}{}); err == nil {
		t.Errorf("expected error, got none")
	}

	if _, err := loadbalancer.Retry(len(endpoints), time.Second, lb)(context.Background(), struct{}{}); err != nil {
		t.Error(err)
	}
}
Beispiel #4
0
func TestStaticPublisher(t *testing.T) {
	endpoints := []endpoint.Endpoint{
		func(context.Context, interface{}) (interface{}, error) { return struct{}{}, nil },
	}
	p := loadbalancer.NewStaticPublisher(endpoints)
	defer p.Stop()

	c := make(chan []endpoint.Endpoint, 1)
	p.Subscribe(c)
	if want, have := len(endpoints), len(<-c); want != have {
		t.Errorf("want %d, have %d", want, have)
	}

	endpoints = []endpoint.Endpoint{}
	p.Replace(endpoints)
	if want, have := len(endpoints), len(<-c); want != have {
		t.Errorf("want %d, have %d", want, have)
	}
}
Beispiel #5
0
func TestRetryTimeout(t *testing.T) {
	var (
		step    = make(chan struct{})
		e       = func(context.Context, interface{}) (interface{}, error) { <-step; return struct{}{}, nil }
		timeout = time.Millisecond
		retry   = loadbalancer.Retry(999, timeout, loadbalancer.RoundRobin(loadbalancer.NewStaticPublisher([]endpoint.Endpoint{e})))
		errs    = make(chan error)
		invoke  = func() { _, err := retry(context.Background(), struct{}{}); errs <- err }
	)

	go invoke()                    // invoke the endpoint
	step <- struct{}{}             // tell the endpoint to return
	if err := <-errs; err != nil { // that should succeed
		t.Error(err)
	}

	go invoke()                                         // invoke the endpoint
	time.Sleep(2 * timeout)                             // wait
	step <- struct{}{}                                  // tell the endpoint to return
	if err := <-errs; err != context.DeadlineExceeded { // that should not succeed
		t.Errorf("wanted error, got none")
	}
}