5470d94416
In previous implementation placement traverser processed incorrectly with local placement build. Also entity incorrectly traversed the placement vectors for fixed number read operations until success. The erroneous behavior was due to the use of a vector number of successes instead of a scalar number in these scenarios. Signed-off-by: Leonard Lyubich <leonard@nspcc.ru>
205 lines
4.2 KiB
Go
205 lines
4.2 KiB
Go
package placement
|
|
|
|
import (
|
|
"strconv"
|
|
"testing"
|
|
|
|
"github.com/nspcc-dev/neofs-api-go/pkg/container"
|
|
"github.com/nspcc-dev/neofs-api-go/pkg/netmap"
|
|
"github.com/nspcc-dev/neofs-api-go/pkg/object"
|
|
"github.com/nspcc-dev/neofs-node/pkg/network"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
type testBuilder struct {
|
|
vectors []netmap.Nodes
|
|
}
|
|
|
|
func (b testBuilder) BuildPlacement(*object.Address, *netmap.PlacementPolicy) ([]netmap.Nodes, error) {
|
|
return b.vectors, nil
|
|
}
|
|
|
|
func testNode(v uint32) (n netmap.NodeInfo) {
|
|
n.SetAddress("/ip4/0.0.0.0/tcp/" + strconv.Itoa(int(v)))
|
|
|
|
return n
|
|
}
|
|
|
|
func flattenVectors(vs []netmap.Nodes) netmap.Nodes {
|
|
v := make(netmap.Nodes, 0)
|
|
|
|
for i := range vs {
|
|
v = append(v, vs[i]...)
|
|
}
|
|
|
|
return v
|
|
}
|
|
|
|
func copyVectors(v []netmap.Nodes) []netmap.Nodes {
|
|
vc := make([]netmap.Nodes, 0, len(v))
|
|
|
|
for i := range v {
|
|
ns := make(netmap.Nodes, len(v[i]))
|
|
copy(ns, v[i])
|
|
|
|
vc = append(vc, ns)
|
|
}
|
|
|
|
return vc
|
|
}
|
|
|
|
func testPlacement(t *testing.T, ss, rs []int) ([]netmap.Nodes, *container.Container) {
|
|
nodes := make([]netmap.Nodes, 0, len(rs))
|
|
replicas := make([]*netmap.Replica, 0, len(rs))
|
|
num := uint32(0)
|
|
|
|
for i := range ss {
|
|
ns := make([]netmap.NodeInfo, 0, ss[i])
|
|
|
|
for j := 0; j < ss[i]; j++ {
|
|
ns = append(ns, testNode(num))
|
|
num++
|
|
}
|
|
|
|
nodes = append(nodes, netmap.NodesFromInfo(ns))
|
|
|
|
s := new(netmap.Replica)
|
|
s.SetCount(uint32(rs[i]))
|
|
|
|
replicas = append(replicas, s)
|
|
}
|
|
|
|
policy := new(netmap.PlacementPolicy)
|
|
policy.SetReplicas(replicas...)
|
|
|
|
return nodes, container.New(container.WithPolicy(policy))
|
|
}
|
|
|
|
func TestTraverserObjectScenarios(t *testing.T) {
|
|
t.Run("search scenario", func(t *testing.T) {
|
|
selectors := []int{2, 3}
|
|
replicas := []int{1, 2}
|
|
|
|
nodes, cnr := testPlacement(t, selectors, replicas)
|
|
|
|
nodesCopy := copyVectors(nodes)
|
|
|
|
tr, err := NewTraverser(
|
|
ForContainer(cnr),
|
|
UseBuilder(&testBuilder{vectors: nodesCopy}),
|
|
WithoutSuccessTracking(),
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
for i := range selectors {
|
|
addrs := tr.Next()
|
|
|
|
require.Len(t, addrs, len(nodes[i]))
|
|
|
|
for j, n := range nodes[i] {
|
|
require.Equal(t, n.Address(), addrs[j].String())
|
|
}
|
|
}
|
|
|
|
require.Empty(t, tr.Next())
|
|
require.True(t, tr.Success())
|
|
})
|
|
|
|
t.Run("read scenario", func(t *testing.T) {
|
|
selectors := []int{5, 3}
|
|
replicas := []int{2, 2}
|
|
|
|
nodes, cnr := testPlacement(t, selectors, replicas)
|
|
|
|
nodesCopy := copyVectors(nodes)
|
|
|
|
tr, err := NewTraverser(
|
|
ForContainer(cnr),
|
|
UseBuilder(&testBuilder{
|
|
vectors: nodesCopy,
|
|
}),
|
|
SuccessAfter(1),
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
for i := 0; i < len(nodes[0]); i++ {
|
|
require.NotNil(t, tr.Next())
|
|
}
|
|
|
|
n, err := network.AddressFromString(nodes[1][0].Address())
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, []*network.Address{n}, tr.Next())
|
|
})
|
|
|
|
t.Run("put scenario", func(t *testing.T) {
|
|
selectors := []int{5, 3}
|
|
replicas := []int{2, 2}
|
|
|
|
nodes, cnr := testPlacement(t, selectors, replicas)
|
|
|
|
nodesCopy := copyVectors(nodes)
|
|
|
|
tr, err := NewTraverser(
|
|
ForContainer(cnr),
|
|
UseBuilder(&testBuilder{vectors: nodesCopy}),
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
fn := func(curVector int) {
|
|
for i := 0; i+replicas[curVector] < selectors[curVector]; i += replicas[curVector] {
|
|
addrs := tr.Next()
|
|
require.Len(t, addrs, replicas[curVector])
|
|
|
|
for j := range addrs {
|
|
require.Equal(t, nodes[curVector][i+j].Address(), addrs[j].String())
|
|
}
|
|
}
|
|
|
|
require.Empty(t, tr.Next())
|
|
require.False(t, tr.Success())
|
|
|
|
for i := 0; i < replicas[curVector]; i++ {
|
|
tr.SubmitSuccess()
|
|
}
|
|
}
|
|
|
|
for i := range selectors {
|
|
fn(i)
|
|
|
|
if i < len(selectors)-1 {
|
|
require.False(t, tr.Success())
|
|
} else {
|
|
require.True(t, tr.Success())
|
|
}
|
|
}
|
|
})
|
|
|
|
t.Run("local operation scenario", func(t *testing.T) {
|
|
selectors := []int{2, 3}
|
|
replicas := []int{1, 2}
|
|
|
|
nodes, cnr := testPlacement(t, selectors, replicas)
|
|
|
|
tr, err := NewTraverser(
|
|
ForContainer(cnr),
|
|
UseBuilder(&testBuilder{
|
|
vectors: []netmap.Nodes{{nodes[1][1]}}, // single node (local)
|
|
}),
|
|
SuccessAfter(1),
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
require.NotEmpty(t, tr.Next())
|
|
require.False(t, tr.Success())
|
|
|
|
// add 1 OK
|
|
tr.SubmitSuccess()
|
|
|
|
// nothing more to do
|
|
require.Empty(t, tr.Next())
|
|
|
|
// common success
|
|
require.True(t, tr.Success())
|
|
})
|
|
}
|