Moved to google.golang.org/genproto/googleapis/api/annotations
Fixes #52
This commit is contained in:
		
							
								
								
									
										15
									
								
								vendor/github.com/go-kit/kit/sd/lb/balancer.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								vendor/github.com/go-kit/kit/sd/lb/balancer.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
			
		||||
package lb
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
 | 
			
		||||
	"github.com/go-kit/kit/endpoint"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Balancer yields endpoints according to some heuristic.
 | 
			
		||||
type Balancer interface {
 | 
			
		||||
	Endpoint() (endpoint.Endpoint, error)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ErrNoEndpoints is returned when no qualifying endpoints are available.
 | 
			
		||||
var ErrNoEndpoints = errors.New("no endpoints available")
 | 
			
		||||
							
								
								
									
										4
									
								
								vendor/github.com/go-kit/kit/sd/lb/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/go-kit/kit/sd/lb/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,4 @@
 | 
			
		||||
// Package lb implements the client-side load balancer pattern. When combined
 | 
			
		||||
// with a service discovery system of record, it enables a more decentralized
 | 
			
		||||
// architecture, removing the need for separate load balancers like HAProxy.
 | 
			
		||||
package lb
 | 
			
		||||
							
								
								
									
										32
									
								
								vendor/github.com/go-kit/kit/sd/lb/random.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								vendor/github.com/go-kit/kit/sd/lb/random.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,32 @@
 | 
			
		||||
package lb
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"math/rand"
 | 
			
		||||
 | 
			
		||||
	"github.com/go-kit/kit/endpoint"
 | 
			
		||||
	"github.com/go-kit/kit/sd"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// NewRandom returns a load balancer that selects services randomly.
 | 
			
		||||
func NewRandom(s sd.Subscriber, seed int64) Balancer {
 | 
			
		||||
	return &random{
 | 
			
		||||
		s: s,
 | 
			
		||||
		r: rand.New(rand.NewSource(seed)),
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type random struct {
 | 
			
		||||
	s sd.Subscriber
 | 
			
		||||
	r *rand.Rand
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *random) Endpoint() (endpoint.Endpoint, error) {
 | 
			
		||||
	endpoints, err := r.s.Endpoints()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	if len(endpoints) <= 0 {
 | 
			
		||||
		return nil, ErrNoEndpoints
 | 
			
		||||
	}
 | 
			
		||||
	return endpoints[r.r.Intn(len(endpoints))], nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										52
									
								
								vendor/github.com/go-kit/kit/sd/lb/random_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								vendor/github.com/go-kit/kit/sd/lb/random_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,52 @@
 | 
			
		||||
package lb
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"math"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"github.com/go-kit/kit/endpoint"
 | 
			
		||||
	"github.com/go-kit/kit/sd"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestRandom(t *testing.T) {
 | 
			
		||||
	var (
 | 
			
		||||
		n          = 7
 | 
			
		||||
		endpoints  = make([]endpoint.Endpoint, n)
 | 
			
		||||
		counts     = make([]int, n)
 | 
			
		||||
		seed       = int64(12345)
 | 
			
		||||
		iterations = 1000000
 | 
			
		||||
		want       = iterations / n
 | 
			
		||||
		tolerance  = want / 100 // 1%
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	for i := 0; i < n; i++ {
 | 
			
		||||
		i0 := i
 | 
			
		||||
		endpoints[i] = func(context.Context, interface{}) (interface{}, error) { counts[i0]++; return struct{}{}, nil }
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	subscriber := sd.FixedSubscriber(endpoints)
 | 
			
		||||
	balancer := NewRandom(subscriber, seed)
 | 
			
		||||
 | 
			
		||||
	for i := 0; i < iterations; i++ {
 | 
			
		||||
		endpoint, _ := balancer.Endpoint()
 | 
			
		||||
		endpoint(context.Background(), struct{}{})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for i, have := range counts {
 | 
			
		||||
		delta := int(math.Abs(float64(want - have)))
 | 
			
		||||
		if delta > tolerance {
 | 
			
		||||
			t.Errorf("%d: want %d, have %d, delta %d > %d tolerance", i, want, have, delta, tolerance)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestRandomNoEndpoints(t *testing.T) {
 | 
			
		||||
	subscriber := sd.FixedSubscriber{}
 | 
			
		||||
	balancer := NewRandom(subscriber, 1415926)
 | 
			
		||||
	_, err := balancer.Endpoint()
 | 
			
		||||
	if want, have := ErrNoEndpoints, err; want != have {
 | 
			
		||||
		t.Errorf("want %v, have %v", want, have)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										117
									
								
								vendor/github.com/go-kit/kit/sd/lb/retry.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								vendor/github.com/go-kit/kit/sd/lb/retry.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,117 @@
 | 
			
		||||
package lb
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/go-kit/kit/endpoint"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// RetryError is an error wrapper that is used by the retry mechanism. All
 | 
			
		||||
// errors returned by the retry mechanism via its endpoint will be RetryErrors.
 | 
			
		||||
type RetryError struct {
 | 
			
		||||
	RawErrors []error // all errors encountered from endpoints directly
 | 
			
		||||
	Final     error   // the final, terminating error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e RetryError) Error() string {
 | 
			
		||||
	var suffix string
 | 
			
		||||
	if len(e.RawErrors) > 1 {
 | 
			
		||||
		a := make([]string, len(e.RawErrors)-1)
 | 
			
		||||
		for i := 0; i < len(e.RawErrors)-1; i++ { // last one is Final
 | 
			
		||||
			a[i] = e.RawErrors[i].Error()
 | 
			
		||||
		}
 | 
			
		||||
		suffix = fmt.Sprintf(" (previously: %s)", strings.Join(a, "; "))
 | 
			
		||||
	}
 | 
			
		||||
	return fmt.Sprintf("%v%s", e.Final, suffix)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Callback is a function that is given the current attempt count and the error
 | 
			
		||||
// received from the underlying endpoint. It should return whether the Retry
 | 
			
		||||
// function should continue trying to get a working endpoint, and a custom error
 | 
			
		||||
// if desired. The error message may be nil, but a true/false is always
 | 
			
		||||
// expected. In all cases, if the replacement error is supplied, the received
 | 
			
		||||
// error will be replaced in the calling context.
 | 
			
		||||
type Callback func(n int, received error) (keepTrying bool, replacement error)
 | 
			
		||||
 | 
			
		||||
// Retry wraps a service load balancer and returns an endpoint oriented load
 | 
			
		||||
// balancer for the specified service method. Requests to the endpoint will be
 | 
			
		||||
// automatically load balanced via the load balancer. Requests that return
 | 
			
		||||
// errors will be retried until they succeed, up to max times, or until the
 | 
			
		||||
// timeout is elapsed, whichever comes first.
 | 
			
		||||
func Retry(max int, timeout time.Duration, b Balancer) endpoint.Endpoint {
 | 
			
		||||
	return RetryWithCallback(timeout, b, maxRetries(max))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func maxRetries(max int) Callback {
 | 
			
		||||
	return func(n int, err error) (keepTrying bool, replacement error) {
 | 
			
		||||
		return n < max, nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func alwaysRetry(int, error) (keepTrying bool, replacement error) {
 | 
			
		||||
	return true, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RetryWithCallback wraps a service load balancer and returns an endpoint
 | 
			
		||||
// oriented load balancer for the specified service method. Requests to the
 | 
			
		||||
// endpoint will be automatically load balanced via the load balancer. Requests
 | 
			
		||||
// that return errors will be retried until they succeed, up to max times, until
 | 
			
		||||
// the callback returns false, or until the timeout is elapsed, whichever comes
 | 
			
		||||
// first.
 | 
			
		||||
func RetryWithCallback(timeout time.Duration, b Balancer, cb Callback) endpoint.Endpoint {
 | 
			
		||||
	if cb == nil {
 | 
			
		||||
		cb = alwaysRetry
 | 
			
		||||
	}
 | 
			
		||||
	if b == nil {
 | 
			
		||||
		panic("nil Balancer")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return func(ctx context.Context, request interface{}) (response interface{}, err error) {
 | 
			
		||||
		var (
 | 
			
		||||
			newctx, cancel = context.WithTimeout(ctx, timeout)
 | 
			
		||||
			responses      = make(chan interface{}, 1)
 | 
			
		||||
			errs           = make(chan error, 1)
 | 
			
		||||
			final          RetryError
 | 
			
		||||
		)
 | 
			
		||||
		defer cancel()
 | 
			
		||||
 | 
			
		||||
		for i := 1; ; i++ {
 | 
			
		||||
			go func() {
 | 
			
		||||
				e, err := b.Endpoint()
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					errs <- err
 | 
			
		||||
					return
 | 
			
		||||
				}
 | 
			
		||||
				response, err := e(newctx, request)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					errs <- err
 | 
			
		||||
					return
 | 
			
		||||
				}
 | 
			
		||||
				responses <- response
 | 
			
		||||
			}()
 | 
			
		||||
 | 
			
		||||
			select {
 | 
			
		||||
			case <-newctx.Done():
 | 
			
		||||
				return nil, newctx.Err()
 | 
			
		||||
 | 
			
		||||
			case response := <-responses:
 | 
			
		||||
				return response, nil
 | 
			
		||||
 | 
			
		||||
			case err := <-errs:
 | 
			
		||||
				final.RawErrors = append(final.RawErrors, err)
 | 
			
		||||
				keepTrying, replacement := cb(i, err)
 | 
			
		||||
				if replacement != nil {
 | 
			
		||||
					err = replacement
 | 
			
		||||
				}
 | 
			
		||||
				if !keepTrying {
 | 
			
		||||
					final.Final = err
 | 
			
		||||
					return nil, final
 | 
			
		||||
				}
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										141
									
								
								vendor/github.com/go-kit/kit/sd/lb/retry_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										141
									
								
								vendor/github.com/go-kit/kit/sd/lb/retry_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,141 @@
 | 
			
		||||
package lb_test
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"testing"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/go-kit/kit/endpoint"
 | 
			
		||||
	"github.com/go-kit/kit/sd"
 | 
			
		||||
	"github.com/go-kit/kit/sd/lb"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestRetryMaxTotalFail(t *testing.T) {
 | 
			
		||||
	var (
 | 
			
		||||
		endpoints = sd.FixedSubscriber{} // no endpoints
 | 
			
		||||
		rr        = lb.NewRoundRobin(endpoints)
 | 
			
		||||
		retry     = lb.Retry(999, time.Second, rr) // lots of retries
 | 
			
		||||
		ctx       = context.Background()
 | 
			
		||||
	)
 | 
			
		||||
	if _, err := retry(ctx, struct{}{}); err == nil {
 | 
			
		||||
		t.Errorf("expected error, got none") // should fail
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestRetryMaxPartialFail(t *testing.T) {
 | 
			
		||||
	var (
 | 
			
		||||
		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 */ },
 | 
			
		||||
		}
 | 
			
		||||
		subscriber = sd.FixedSubscriber{
 | 
			
		||||
			0: endpoints[0],
 | 
			
		||||
			1: endpoints[1],
 | 
			
		||||
			2: endpoints[2],
 | 
			
		||||
		}
 | 
			
		||||
		retries = len(endpoints) - 1 // not quite enough retries
 | 
			
		||||
		rr      = lb.NewRoundRobin(subscriber)
 | 
			
		||||
		ctx     = context.Background()
 | 
			
		||||
	)
 | 
			
		||||
	if _, err := lb.Retry(retries, time.Second, rr)(ctx, struct{}{}); err == nil {
 | 
			
		||||
		t.Errorf("expected error two, got none")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestRetryMaxSuccess(t *testing.T) {
 | 
			
		||||
	var (
 | 
			
		||||
		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 */ },
 | 
			
		||||
		}
 | 
			
		||||
		subscriber = sd.FixedSubscriber{
 | 
			
		||||
			0: endpoints[0],
 | 
			
		||||
			1: endpoints[1],
 | 
			
		||||
			2: endpoints[2],
 | 
			
		||||
		}
 | 
			
		||||
		retries = len(endpoints) // exactly enough retries
 | 
			
		||||
		rr      = lb.NewRoundRobin(subscriber)
 | 
			
		||||
		ctx     = context.Background()
 | 
			
		||||
	)
 | 
			
		||||
	if _, err := lb.Retry(retries, time.Second, rr)(ctx, struct{}{}); err != nil {
 | 
			
		||||
		t.Error(err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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   = lb.Retry(999, timeout, lb.NewRoundRobin(sd.FixedSubscriber{0: e}))
 | 
			
		||||
		errs    = make(chan error, 1)
 | 
			
		||||
		invoke  = func() { _, err := retry(context.Background(), struct{}{}); errs <- err }
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	go func() { step <- struct{}{} }() // queue up a flush of the endpoint
 | 
			
		||||
	invoke()                           // invoke the endpoint and trigger the flush
 | 
			
		||||
	if err := <-errs; err != nil {     // that should succeed
 | 
			
		||||
		t.Error(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	go func() { time.Sleep(10 * timeout); step <- struct{}{} }() // a delayed flush
 | 
			
		||||
	invoke()                                                     // invoke the endpoint
 | 
			
		||||
	if err := <-errs; err != context.DeadlineExceeded {          // that should not succeed
 | 
			
		||||
		t.Errorf("wanted %v, got none", context.DeadlineExceeded)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestAbortEarlyCustomMessage(t *testing.T) {
 | 
			
		||||
	var (
 | 
			
		||||
		myErr     = errors.New("aborting early")
 | 
			
		||||
		cb        = func(int, error) (bool, error) { return false, myErr }
 | 
			
		||||
		endpoints = sd.FixedSubscriber{} // no endpoints
 | 
			
		||||
		rr        = lb.NewRoundRobin(endpoints)
 | 
			
		||||
		retry     = lb.RetryWithCallback(time.Second, rr, cb) // lots of retries
 | 
			
		||||
		ctx       = context.Background()
 | 
			
		||||
	)
 | 
			
		||||
	_, err := retry(ctx, struct{}{})
 | 
			
		||||
	if want, have := myErr, err.(lb.RetryError).Final; want != have {
 | 
			
		||||
		t.Errorf("want %v, have %v", want, have)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestErrorPassedUnchangedToCallback(t *testing.T) {
 | 
			
		||||
	var (
 | 
			
		||||
		myErr = errors.New("my custom error")
 | 
			
		||||
		cb    = func(_ int, err error) (bool, error) {
 | 
			
		||||
			if want, have := myErr, err; want != have {
 | 
			
		||||
				t.Errorf("want %v, have %v", want, have)
 | 
			
		||||
			}
 | 
			
		||||
			return false, nil
 | 
			
		||||
		}
 | 
			
		||||
		endpoint = func(ctx context.Context, request interface{}) (interface{}, error) {
 | 
			
		||||
			return nil, myErr
 | 
			
		||||
		}
 | 
			
		||||
		endpoints = sd.FixedSubscriber{endpoint} // no endpoints
 | 
			
		||||
		rr        = lb.NewRoundRobin(endpoints)
 | 
			
		||||
		retry     = lb.RetryWithCallback(time.Second, rr, cb) // lots of retries
 | 
			
		||||
		ctx       = context.Background()
 | 
			
		||||
	)
 | 
			
		||||
	_, err := retry(ctx, struct{}{})
 | 
			
		||||
	if want, have := myErr, err.(lb.RetryError).Final; want != have {
 | 
			
		||||
		t.Errorf("want %v, have %v", want, have)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestHandleNilCallback(t *testing.T) {
 | 
			
		||||
	var (
 | 
			
		||||
		subscriber = sd.FixedSubscriber{
 | 
			
		||||
			func(context.Context, interface{}) (interface{}, error) { return struct{}{}, nil /* OK */ },
 | 
			
		||||
		}
 | 
			
		||||
		rr  = lb.NewRoundRobin(subscriber)
 | 
			
		||||
		ctx = context.Background()
 | 
			
		||||
	)
 | 
			
		||||
	retry := lb.RetryWithCallback(time.Second, rr, nil)
 | 
			
		||||
	if _, err := retry(ctx, struct{}{}); err != nil {
 | 
			
		||||
		t.Error(err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										34
									
								
								vendor/github.com/go-kit/kit/sd/lb/round_robin.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								vendor/github.com/go-kit/kit/sd/lb/round_robin.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,34 @@
 | 
			
		||||
package lb
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"sync/atomic"
 | 
			
		||||
 | 
			
		||||
	"github.com/go-kit/kit/endpoint"
 | 
			
		||||
	"github.com/go-kit/kit/sd"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// NewRoundRobin returns a load balancer that returns services in sequence.
 | 
			
		||||
func NewRoundRobin(s sd.Subscriber) Balancer {
 | 
			
		||||
	return &roundRobin{
 | 
			
		||||
		s: s,
 | 
			
		||||
		c: 0,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type roundRobin struct {
 | 
			
		||||
	s sd.Subscriber
 | 
			
		||||
	c uint64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (rr *roundRobin) Endpoint() (endpoint.Endpoint, error) {
 | 
			
		||||
	endpoints, err := rr.s.Endpoints()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	if len(endpoints) <= 0 {
 | 
			
		||||
		return nil, ErrNoEndpoints
 | 
			
		||||
	}
 | 
			
		||||
	old := atomic.AddUint64(&rr.c, 1) - 1
 | 
			
		||||
	idx := old % uint64(len(endpoints))
 | 
			
		||||
	return endpoints[idx], nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										95
									
								
								vendor/github.com/go-kit/kit/sd/lb/round_robin_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								vendor/github.com/go-kit/kit/sd/lb/round_robin_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,95 @@
 | 
			
		||||
package lb
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"sync"
 | 
			
		||||
	"sync/atomic"
 | 
			
		||||
	"testing"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/go-kit/kit/endpoint"
 | 
			
		||||
	"github.com/go-kit/kit/sd"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestRoundRobin(t *testing.T) {
 | 
			
		||||
	var (
 | 
			
		||||
		counts    = []int{0, 0, 0}
 | 
			
		||||
		endpoints = []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 },
 | 
			
		||||
		}
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	subscriber := sd.FixedSubscriber(endpoints)
 | 
			
		||||
	balancer := NewRoundRobin(subscriber)
 | 
			
		||||
 | 
			
		||||
	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},
 | 
			
		||||
	} {
 | 
			
		||||
		endpoint, err := balancer.Endpoint()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			t.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
		endpoint(context.Background(), struct{}{})
 | 
			
		||||
		if have := counts; !reflect.DeepEqual(want, have) {
 | 
			
		||||
			t.Fatalf("%d: want %v, have %v", i, want, have)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestRoundRobinNoEndpoints(t *testing.T) {
 | 
			
		||||
	subscriber := sd.FixedSubscriber{}
 | 
			
		||||
	balancer := NewRoundRobin(subscriber)
 | 
			
		||||
	_, err := balancer.Endpoint()
 | 
			
		||||
	if want, have := ErrNoEndpoints, err; want != have {
 | 
			
		||||
		t.Errorf("want %v, have %v", want, have)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestRoundRobinNoRace(t *testing.T) {
 | 
			
		||||
	balancer := NewRoundRobin(sd.FixedSubscriber([]endpoint.Endpoint{
 | 
			
		||||
		endpoint.Nop,
 | 
			
		||||
		endpoint.Nop,
 | 
			
		||||
		endpoint.Nop,
 | 
			
		||||
		endpoint.Nop,
 | 
			
		||||
		endpoint.Nop,
 | 
			
		||||
	}))
 | 
			
		||||
 | 
			
		||||
	var (
 | 
			
		||||
		n     = 100
 | 
			
		||||
		done  = make(chan struct{})
 | 
			
		||||
		wg    sync.WaitGroup
 | 
			
		||||
		count uint64
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	wg.Add(n)
 | 
			
		||||
 | 
			
		||||
	for i := 0; i < n; i++ {
 | 
			
		||||
		go func() {
 | 
			
		||||
			defer wg.Done()
 | 
			
		||||
			for {
 | 
			
		||||
				select {
 | 
			
		||||
				case <-done:
 | 
			
		||||
					return
 | 
			
		||||
				default:
 | 
			
		||||
					_, _ = balancer.Endpoint()
 | 
			
		||||
					atomic.AddUint64(&count, 1)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	time.Sleep(time.Second)
 | 
			
		||||
	close(done)
 | 
			
		||||
	wg.Wait()
 | 
			
		||||
 | 
			
		||||
	t.Logf("made %d calls", atomic.LoadUint64(&count))
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user