frostfs-sdk-go/pool/sampler_test.go
Leonard Lyubich 737e690482 [#299] pool: Do not use pointers to the resulting values
In previous implementation `pool` package provided access to resulting
values as pointers to them. This caused clients to handle nil
cases even when the field presence in the response is required.

Avoid returning pointers to values in result getters. This also reduces
reference counter load and allows values from `client.Client` to be
forwarded directly without additional assignment.

Signed-off-by: Leonard Lyubich <leonard@nspcc.ru>
2022-08-16 15:31:57 +04:00

149 lines
3.4 KiB
Go

package pool
import (
"context"
"fmt"
"math/rand"
"testing"
"github.com/nspcc-dev/neofs-sdk-go/netmap"
"github.com/stretchr/testify/require"
)
func TestSamplerStability(t *testing.T) {
const COUNT = 100000
cases := []struct {
probabilities []float64
expected []int
}{
{
probabilities: []float64{1, 0},
expected: []int{COUNT, 0},
},
{
probabilities: []float64{0.1, 0.2, 0.7},
expected: []int{10138, 19813, 70049},
},
{
probabilities: []float64{0.2, 0.2, 0.4, 0.1, 0.1, 0},
expected: []int{19824, 20169, 39900, 10243, 9864, 0},
},
}
for _, tc := range cases {
sampler := newSampler(tc.probabilities, rand.NewSource(0))
res := make([]int, len(tc.probabilities))
for i := 0; i < COUNT; i++ {
res[sampler.Next()]++
}
require.Equal(t, tc.expected, res, "probabilities: %v", tc.probabilities)
}
}
type clientMock struct {
clientWrapper
name string
err error
}
func (c *clientMock) endpointInfo(context.Context, prmEndpointInfo) (netmap.NodeInfo, error) {
return netmap.NodeInfo{}, nil
}
func (c *clientMock) networkInfo(context.Context, prmNetworkInfo) (netmap.NetworkInfo, error) {
return netmap.NetworkInfo{}, nil
}
func newNetmapMock(name string, needErr bool) *clientMock {
var err error
if needErr {
err = fmt.Errorf("not available")
}
return &clientMock{
clientWrapper: clientWrapper{
clientStatusMonitor: newClientStatusMonitor("", 10),
},
name: name,
err: err,
}
}
func TestHealthyReweight(t *testing.T) {
var (
weights = []float64{0.9, 0.1}
names = []string{"node0", "node1"}
buffer = make([]float64, len(weights))
)
cache, err := newCache()
require.NoError(t, err)
inner := &innerPool{
sampler: newSampler(weights, rand.NewSource(0)),
clients: []client{
newNetmapMock(names[0], true),
newNetmapMock(names[1], false),
},
}
p := &Pool{
innerPools: []*innerPool{inner},
cache: cache,
key: newPrivateKey(t),
rebalanceParams: rebalanceParameters{nodesParams: []*nodesParam{{weights: weights}}},
}
// check getting first node connection before rebalance happened
connection0, err := p.connection()
require.NoError(t, err)
mock0 := connection0.(*clientMock)
require.Equal(t, names[0], mock0.name)
p.updateInnerNodesHealth(context.TODO(), 0, buffer)
connection1, err := p.connection()
require.NoError(t, err)
mock1 := connection1.(*clientMock)
require.Equal(t, names[1], mock1.name)
// enabled first node again
inner.lock.Lock()
inner.clients[0] = newNetmapMock(names[0], false)
inner.lock.Unlock()
p.updateInnerNodesHealth(context.TODO(), 0, buffer)
inner.sampler = newSampler(weights, rand.NewSource(0))
connection0, err = p.connection()
require.NoError(t, err)
mock0 = connection0.(*clientMock)
require.Equal(t, names[0], mock0.name)
}
func TestHealthyNoReweight(t *testing.T) {
var (
weights = []float64{0.9, 0.1}
names = []string{"node0", "node1"}
buffer = make([]float64, len(weights))
)
sampl := newSampler(weights, rand.NewSource(0))
inner := &innerPool{
sampler: sampl,
clients: []client{
newNetmapMock(names[0], false),
newNetmapMock(names[1], false),
},
}
p := &Pool{
innerPools: []*innerPool{inner},
rebalanceParams: rebalanceParameters{nodesParams: []*nodesParam{{weights: weights}}},
}
p.updateInnerNodesHealth(context.TODO(), 0, buffer)
inner.lock.RLock()
defer inner.lock.RUnlock()
require.Equal(t, inner.sampler, sampl)
}