2019-01-24 20:15:10 +00:00
|
|
|
// Copyright (C) 2019 Storj Labs, Inc.
|
2018-11-19 20:39:25 +00:00
|
|
|
// See LICENSE for copying information.
|
|
|
|
|
|
|
|
package overlay_test
|
|
|
|
|
|
|
|
import (
|
2019-01-29 19:42:43 +00:00
|
|
|
"strconv"
|
2018-11-19 20:39:25 +00:00
|
|
|
"testing"
|
2018-11-20 16:54:52 +00:00
|
|
|
"time"
|
2018-11-19 20:39:25 +00:00
|
|
|
|
|
|
|
"github.com/stretchr/testify/assert"
|
2019-01-15 16:08:45 +00:00
|
|
|
"github.com/stretchr/testify/require"
|
2019-01-29 19:42:43 +00:00
|
|
|
"google.golang.org/grpc/codes"
|
|
|
|
"google.golang.org/grpc/status"
|
2018-11-19 20:39:25 +00:00
|
|
|
|
|
|
|
"storj.io/storj/internal/testcontext"
|
|
|
|
"storj.io/storj/internal/testplanet"
|
2019-01-29 19:42:43 +00:00
|
|
|
"storj.io/storj/pkg/overlay"
|
2018-11-19 20:39:25 +00:00
|
|
|
"storj.io/storj/pkg/pb"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestServer(t *testing.T) {
|
|
|
|
ctx := testcontext.New(t)
|
|
|
|
defer ctx.Cleanup()
|
|
|
|
|
|
|
|
planet, err := testplanet.New(t, 1, 4, 1)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
defer ctx.Check(planet.Shutdown)
|
|
|
|
|
|
|
|
planet.Start(ctx)
|
2018-11-20 16:54:52 +00:00
|
|
|
// we wait a second for all the nodes to complete bootstrapping off the satellite
|
|
|
|
time.Sleep(2 * time.Second)
|
2018-11-19 20:39:25 +00:00
|
|
|
|
|
|
|
satellite := planet.Satellites[0]
|
2019-01-18 13:54:08 +00:00
|
|
|
server := satellite.Overlay.Endpoint
|
2018-11-19 20:39:25 +00:00
|
|
|
// TODO: handle cleanup
|
|
|
|
|
|
|
|
{ // Lookup
|
2019-01-15 16:08:45 +00:00
|
|
|
result, err := server.Lookup(ctx, &pb.LookupRequest{
|
|
|
|
NodeId: planet.StorageNodes[0].ID(),
|
|
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, result)
|
|
|
|
assert.Equal(t, result.Node.Address.Address, planet.StorageNodes[0].Addr())
|
2018-11-19 20:39:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
{ // BulkLookup
|
|
|
|
result, err := server.BulkLookup(ctx, &pb.LookupRequests{
|
2018-11-24 02:46:53 +00:00
|
|
|
LookupRequest: []*pb.LookupRequest{
|
2018-11-29 18:39:27 +00:00
|
|
|
{NodeId: planet.StorageNodes[0].ID()},
|
|
|
|
{NodeId: planet.StorageNodes[1].ID()},
|
|
|
|
{NodeId: planet.StorageNodes[2].ID()},
|
2018-11-19 20:39:25 +00:00
|
|
|
},
|
|
|
|
})
|
|
|
|
|
2019-01-15 16:08:45 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, result)
|
|
|
|
require.Len(t, result.LookupResponse, 3)
|
|
|
|
|
|
|
|
for i, resp := range result.LookupResponse {
|
|
|
|
if assert.NotNil(t, resp.Node) {
|
|
|
|
assert.Equal(t, resp.Node.Address.Address, planet.StorageNodes[i].Addr())
|
2018-11-19 20:39:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-01-29 19:42:43 +00:00
|
|
|
|
|
|
|
func TestNewNodeFiltering(t *testing.T) {
|
|
|
|
ctx := testcontext.New(t)
|
|
|
|
defer ctx.Cleanup()
|
|
|
|
|
|
|
|
var totalNodes int
|
|
|
|
totalNodes = 10
|
|
|
|
|
|
|
|
planet, err := testplanet.New(t, 1, totalNodes, 1)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
planet.Start(ctx)
|
|
|
|
|
|
|
|
defer ctx.Check(planet.Shutdown)
|
|
|
|
|
|
|
|
// we wait a second for all the nodes to complete bootstrapping off the satellite
|
|
|
|
time.Sleep(5 * time.Second)
|
|
|
|
|
|
|
|
satellite := planet.Satellites[0]
|
|
|
|
|
|
|
|
// This sets a reputable audit count for a certain number of nodes.
|
|
|
|
for i, node := range planet.StorageNodes {
|
|
|
|
for j := 0; j < i; j++ {
|
|
|
|
_, err := satellite.DB.StatDB().UpdateAuditSuccess(ctx, node.ID(), true)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, tt := range []struct {
|
|
|
|
name string
|
|
|
|
newNodeAuditThreshold int64
|
|
|
|
newNodePercentage float64
|
|
|
|
requestedNodeAmt int64
|
|
|
|
expectedResultLength int
|
|
|
|
excludedAmt int
|
|
|
|
notEnoughRepNodes bool
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
name: "case: all reputable nodes, only reputable nodes requested",
|
|
|
|
newNodeAuditThreshold: 0,
|
|
|
|
newNodePercentage: 0,
|
|
|
|
requestedNodeAmt: 5,
|
|
|
|
expectedResultLength: 5,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "case: all reputable nodes, reputable and new nodes requested",
|
|
|
|
newNodeAuditThreshold: 0,
|
|
|
|
newNodePercentage: 1,
|
|
|
|
requestedNodeAmt: 5,
|
|
|
|
expectedResultLength: 5,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "case: all reputable nodes except one, reputable and new nodes requested",
|
|
|
|
newNodeAuditThreshold: 1,
|
|
|
|
newNodePercentage: 1,
|
|
|
|
requestedNodeAmt: 5,
|
|
|
|
expectedResultLength: 6,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "case: 50-50 reputable and new nodes, reputable and new nodes requested (new node % 1)",
|
|
|
|
newNodeAuditThreshold: 5,
|
|
|
|
newNodePercentage: 1,
|
|
|
|
requestedNodeAmt: 2,
|
|
|
|
expectedResultLength: 4,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "case: 50-50 reputable and new nodes, reputable and new nodes requested (new node % .5)",
|
|
|
|
newNodeAuditThreshold: 5,
|
|
|
|
newNodePercentage: 0.5,
|
|
|
|
requestedNodeAmt: 4,
|
|
|
|
expectedResultLength: 6,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "case: all new nodes except one, reputable and new nodes requested (happy path)",
|
|
|
|
newNodeAuditThreshold: 8,
|
|
|
|
newNodePercentage: 1,
|
|
|
|
requestedNodeAmt: 1,
|
|
|
|
expectedResultLength: 2,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "case: all new nodes except one, reputable and new nodes requested (not happy path)",
|
|
|
|
newNodeAuditThreshold: 9,
|
|
|
|
newNodePercentage: 1,
|
|
|
|
requestedNodeAmt: 2,
|
|
|
|
expectedResultLength: 3,
|
|
|
|
notEnoughRepNodes: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "case: all new nodes, reputable and new nodes requested",
|
|
|
|
newNodeAuditThreshold: 50,
|
|
|
|
newNodePercentage: 1,
|
|
|
|
requestedNodeAmt: 2,
|
|
|
|
expectedResultLength: 2,
|
|
|
|
notEnoughRepNodes: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "case: audit threshold edge case (1)",
|
|
|
|
newNodeAuditThreshold: 9,
|
|
|
|
newNodePercentage: 0,
|
|
|
|
requestedNodeAmt: 1,
|
|
|
|
expectedResultLength: 1,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "case: audit threshold edge case (2)",
|
|
|
|
newNodeAuditThreshold: 0,
|
|
|
|
newNodePercentage: 1,
|
|
|
|
requestedNodeAmt: 1,
|
|
|
|
expectedResultLength: 1,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "case: excluded node ids being excluded",
|
|
|
|
excludedAmt: 7,
|
|
|
|
newNodeAuditThreshold: 5,
|
|
|
|
newNodePercentage: 0,
|
|
|
|
requestedNodeAmt: 5,
|
|
|
|
expectedResultLength: 3,
|
|
|
|
notEnoughRepNodes: true,
|
|
|
|
},
|
|
|
|
} {
|
|
|
|
|
|
|
|
nodeSelectionConfig := &overlay.NodeSelectionConfig{
|
|
|
|
UptimeCount: 0,
|
|
|
|
UptimeRatio: 0,
|
|
|
|
AuditSuccessRatio: 0,
|
|
|
|
AuditCount: 0,
|
|
|
|
NewNodeAuditThreshold: tt.newNodeAuditThreshold,
|
|
|
|
NewNodePercentage: tt.newNodePercentage,
|
|
|
|
}
|
|
|
|
|
|
|
|
server := overlay.NewServer(satellite.Log.Named("overlay"), satellite.Overlay.Service, nodeSelectionConfig)
|
|
|
|
|
|
|
|
var excludedNodes []pb.NodeID
|
|
|
|
|
|
|
|
for i := range planet.StorageNodes {
|
|
|
|
address := "127.0.0.1:555" + strconv.Itoa(i)
|
|
|
|
|
|
|
|
n := &pb.Node{
|
|
|
|
Id: planet.StorageNodes[i].ID(),
|
|
|
|
Address: &pb.NodeAddress{Address: address},
|
|
|
|
}
|
|
|
|
|
|
|
|
if tt.excludedAmt != 0 && i < tt.excludedAmt {
|
|
|
|
excludedNodes = append(excludedNodes, n.Id)
|
|
|
|
}
|
|
|
|
|
|
|
|
err = satellite.Overlay.Service.Put(ctx, n.Id, *n)
|
|
|
|
assert.NoError(t, err, tt.name)
|
|
|
|
}
|
|
|
|
|
|
|
|
result, err := server.FindStorageNodes(ctx,
|
|
|
|
&pb.FindStorageNodesRequest{
|
|
|
|
Opts: &pb.OverlayOptions{
|
|
|
|
Restrictions: &pb.NodeRestrictions{
|
|
|
|
FreeBandwidth: 0,
|
|
|
|
FreeDisk: 0,
|
|
|
|
},
|
|
|
|
Amount: tt.requestedNodeAmt,
|
|
|
|
ExcludedNodes: excludedNodes,
|
|
|
|
},
|
|
|
|
})
|
|
|
|
|
|
|
|
if tt.notEnoughRepNodes {
|
|
|
|
stat, ok := status.FromError(err)
|
|
|
|
assert.Equal(t, true, ok, tt.name)
|
|
|
|
assert.Equal(t, codes.ResourceExhausted, stat.Code(), tt.name)
|
|
|
|
} else {
|
|
|
|
assert.NoError(t, err, tt.name)
|
|
|
|
}
|
|
|
|
|
|
|
|
assert.Equal(t, tt.expectedResultLength, len(result.GetNodes()), tt.name)
|
|
|
|
}
|
|
|
|
}
|