2018-06-19 15:00:15 +01:00
|
|
|
// Copyright (C) 2018 Storj Labs, Inc.
|
|
|
|
// See LICENSE for copying information.
|
|
|
|
|
|
|
|
package overlay
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"net"
|
|
|
|
"testing"
|
|
|
|
|
2018-10-19 15:05:31 +01:00
|
|
|
"github.com/golang/protobuf/proto"
|
2018-06-19 15:00:15 +01:00
|
|
|
"github.com/stretchr/testify/assert"
|
2018-09-11 05:52:14 +01:00
|
|
|
"github.com/zeebo/errs"
|
2018-06-19 15:00:15 +01:00
|
|
|
"google.golang.org/grpc"
|
|
|
|
|
2018-07-09 18:43:13 +01:00
|
|
|
"storj.io/storj/pkg/dht"
|
2018-10-08 16:09:37 +01:00
|
|
|
"storj.io/storj/pkg/node"
|
2018-09-18 05:39:06 +01:00
|
|
|
"storj.io/storj/pkg/pb"
|
2018-08-24 05:01:03 +01:00
|
|
|
"storj.io/storj/pkg/provider"
|
2018-10-19 15:05:31 +01:00
|
|
|
"storj.io/storj/storage"
|
2018-09-11 08:27:12 +01:00
|
|
|
"storj.io/storj/storage/redis/redisserver"
|
2018-06-19 15:00:15 +01:00
|
|
|
)
|
|
|
|
|
2018-07-09 18:43:13 +01:00
|
|
|
type mockNodeID struct {
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m mockNodeID) String() string {
|
|
|
|
return "foobar"
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m mockNodeID) Bytes() []byte {
|
|
|
|
return []byte("foobar")
|
|
|
|
}
|
|
|
|
|
2018-06-19 15:00:15 +01:00
|
|
|
func TestNewOverlayClient(t *testing.T) {
|
|
|
|
cases := []struct {
|
|
|
|
address string
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
address: "127.0.0.1:8080",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, v := range cases {
|
2018-11-01 15:48:43 +00:00
|
|
|
ca, err := provider.NewTestCA(ctx)
|
2018-08-24 05:01:03 +01:00
|
|
|
assert.NoError(t, err)
|
|
|
|
identity, err := ca.NewIdentity()
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
oc, err := NewOverlayClient(identity, v.address)
|
2018-06-19 15:00:15 +01:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
assert.NotNil(t, oc)
|
|
|
|
assert.NotEmpty(t, oc.client)
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestChoose(t *testing.T) {
|
|
|
|
cases := []struct {
|
2018-10-19 15:05:31 +01:00
|
|
|
limit int
|
|
|
|
space int64
|
|
|
|
allNodes []*pb.Node
|
|
|
|
excluded []dht.NodeID
|
2018-06-19 15:00:15 +01:00
|
|
|
}{
|
|
|
|
{
|
2018-10-19 15:05:31 +01:00
|
|
|
limit: 4,
|
|
|
|
space: 0,
|
|
|
|
allNodes: func() []*pb.Node {
|
|
|
|
n1 := &pb.Node{Id: "n1"}
|
|
|
|
n2 := &pb.Node{Id: "n2"}
|
|
|
|
n3 := &pb.Node{Id: "n3"}
|
|
|
|
n4 := &pb.Node{Id: "n4"}
|
|
|
|
n5 := &pb.Node{Id: "n5"}
|
|
|
|
n6 := &pb.Node{Id: "n6"}
|
|
|
|
n7 := &pb.Node{Id: "n7"}
|
|
|
|
n8 := &pb.Node{Id: "n8"}
|
|
|
|
return []*pb.Node{n1, n2, n3, n4, n5, n6, n7, n8}
|
|
|
|
}(),
|
2018-10-15 18:42:36 +01:00
|
|
|
excluded: func() []dht.NodeID {
|
|
|
|
id1 := node.IDFromString("n1")
|
|
|
|
id2 := node.IDFromString("n2")
|
|
|
|
id3 := node.IDFromString("n3")
|
|
|
|
id4 := node.IDFromString("n4")
|
2018-10-19 15:05:31 +01:00
|
|
|
return []dht.NodeID{id1, id2, id3, id4}
|
2018-10-15 18:42:36 +01:00
|
|
|
}(),
|
2018-06-19 15:00:15 +01:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, v := range cases {
|
2018-09-07 10:42:04 +01:00
|
|
|
lis, err := net.Listen("tcp", "127.0.0.1:0")
|
2018-06-19 15:00:15 +01:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2018-10-19 15:05:31 +01:00
|
|
|
var listItems []storage.ListItem
|
|
|
|
for _, n := range v.allNodes {
|
|
|
|
data, err := proto.Marshal(n)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
listItems = append(listItems, storage.ListItem{
|
|
|
|
Key: storage.Key(n.Id),
|
|
|
|
Value: data,
|
|
|
|
})
|
|
|
|
}
|
2018-06-19 15:00:15 +01:00
|
|
|
|
2018-11-01 15:48:43 +00:00
|
|
|
ca, err := provider.NewTestCA(ctx)
|
2018-08-24 05:01:03 +01:00
|
|
|
assert.NoError(t, err)
|
|
|
|
identity, err := ca.NewIdentity()
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2018-10-19 15:05:31 +01:00
|
|
|
srv := NewMockServer(listItems, func() grpc.ServerOption {
|
|
|
|
opt, err := identity.ServerOption()
|
|
|
|
assert.NoError(t, err)
|
|
|
|
return opt
|
|
|
|
}())
|
|
|
|
|
|
|
|
go func() { assert.NoError(t, srv.Serve(lis)) }()
|
|
|
|
defer srv.Stop()
|
|
|
|
|
2018-08-24 05:01:03 +01:00
|
|
|
oc, err := NewOverlayClient(identity, lis.Addr().String())
|
2018-06-19 15:00:15 +01:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
assert.NotNil(t, oc)
|
|
|
|
assert.NotEmpty(t, oc.client)
|
|
|
|
|
2018-10-19 15:05:31 +01:00
|
|
|
newNodes, err := oc.Choose(ctx, Options{Amount: v.limit, Space: v.space, Excluded: v.excluded})
|
2018-06-19 15:00:15 +01:00
|
|
|
assert.NoError(t, err)
|
2018-10-19 15:05:31 +01:00
|
|
|
for _, new := range newNodes {
|
|
|
|
for _, ex := range v.excluded {
|
|
|
|
assert.NotEqual(t, ex.String(), new.Id)
|
|
|
|
}
|
|
|
|
}
|
2018-06-19 15:00:15 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestLookup(t *testing.T) {
|
|
|
|
cases := []struct {
|
2018-07-09 18:43:13 +01:00
|
|
|
nodeID dht.NodeID
|
2018-06-19 15:00:15 +01:00
|
|
|
expectedCalls int
|
|
|
|
}{
|
|
|
|
{
|
2018-07-09 18:43:13 +01:00
|
|
|
nodeID: mockNodeID{},
|
2018-06-19 15:00:15 +01:00
|
|
|
expectedCalls: 1,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, v := range cases {
|
2018-09-07 10:42:04 +01:00
|
|
|
lis, err := net.Listen("tcp", "127.0.0.1:0")
|
2018-06-19 15:00:15 +01:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2018-08-27 18:28:16 +01:00
|
|
|
srv, mock, err := newTestServer(ctx)
|
2018-08-24 05:01:03 +01:00
|
|
|
assert.NoError(t, err)
|
2018-09-11 14:13:25 +01:00
|
|
|
go func() { assert.NoError(t, srv.Serve(lis)) }()
|
2018-06-19 15:00:15 +01:00
|
|
|
defer srv.Stop()
|
|
|
|
|
2018-11-01 15:48:43 +00:00
|
|
|
ca, err := provider.NewTestCA(ctx)
|
2018-08-24 05:01:03 +01:00
|
|
|
assert.NoError(t, err)
|
|
|
|
identity, err := ca.NewIdentity()
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
oc, err := NewOverlayClient(identity, lis.Addr().String())
|
2018-06-19 15:00:15 +01:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
assert.NotNil(t, oc)
|
|
|
|
assert.NotEmpty(t, oc.client)
|
|
|
|
|
2018-08-24 05:01:03 +01:00
|
|
|
_, err = oc.Lookup(ctx, v.nodeID)
|
2018-06-19 15:00:15 +01:00
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, mock.lookupCalled, v.expectedCalls)
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2018-09-11 05:52:14 +01:00
|
|
|
func TestBulkLookup(t *testing.T) {
|
|
|
|
cases := []struct {
|
|
|
|
nodeIDs []dht.NodeID
|
|
|
|
expectedCalls int
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
nodeIDs: []dht.NodeID{mockNodeID{}, mockNodeID{}, mockNodeID{}},
|
|
|
|
expectedCalls: 1,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
for _, v := range cases {
|
2018-09-11 08:27:12 +01:00
|
|
|
lis, err := net.Listen("tcp", "127.0.0.1:0")
|
2018-09-11 05:52:14 +01:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
srv, mock, err := newTestServer(ctx)
|
|
|
|
assert.NoError(t, err)
|
2018-09-11 14:13:25 +01:00
|
|
|
go func() { assert.NoError(t, srv.Serve(lis)) }()
|
2018-09-11 05:52:14 +01:00
|
|
|
defer srv.Stop()
|
|
|
|
|
2018-11-01 15:48:43 +00:00
|
|
|
ca, err := provider.NewTestCA(ctx)
|
2018-09-11 05:52:14 +01:00
|
|
|
assert.NoError(t, err)
|
|
|
|
identity, err := ca.NewIdentity()
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
oc, err := NewOverlayClient(identity, lis.Addr().String())
|
|
|
|
assert.NoError(t, err)
|
2018-06-19 15:00:15 +01:00
|
|
|
|
2018-09-11 05:52:14 +01:00
|
|
|
assert.NotNil(t, oc)
|
|
|
|
assert.NotEmpty(t, oc.client)
|
|
|
|
|
|
|
|
_, err = oc.BulkLookup(ctx, v.nodeIDs)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, mock.bulkLookupCalled, v.expectedCalls)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
func TestBulkLookupV2(t *testing.T) {
|
2018-09-11 08:27:12 +01:00
|
|
|
redisAddr, cleanup, err := redisserver.Start()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
defer cleanup()
|
|
|
|
|
|
|
|
lis, err := net.Listen("tcp", "127.0.0.1:0")
|
2018-09-11 05:52:14 +01:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2018-09-11 08:27:12 +01:00
|
|
|
srv, s, err := newServer(ctx, redisAddr)
|
2018-09-11 05:52:14 +01:00
|
|
|
|
|
|
|
assert.NoError(t, err)
|
2018-09-11 14:13:25 +01:00
|
|
|
go func() { assert.NoError(t, srv.Serve(lis)) }()
|
2018-09-11 05:52:14 +01:00
|
|
|
defer srv.Stop()
|
|
|
|
|
2018-11-01 15:48:43 +00:00
|
|
|
ca, err := provider.NewTestCA(ctx)
|
2018-09-11 05:52:14 +01:00
|
|
|
assert.NoError(t, err)
|
|
|
|
identity, err := ca.NewIdentity()
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
oc, err := NewOverlayClient(identity, lis.Addr().String())
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
assert.NotNil(t, oc)
|
|
|
|
assert.NotEmpty(t, oc.client)
|
2018-09-18 05:39:06 +01:00
|
|
|
n1 := &pb.Node{Id: "n1"}
|
|
|
|
n2 := &pb.Node{Id: "n2"}
|
|
|
|
n3 := &pb.Node{Id: "n3"}
|
|
|
|
nodes := []*pb.Node{n1, n2, n3}
|
2018-09-11 05:52:14 +01:00
|
|
|
for _, n := range nodes {
|
2018-09-11 14:13:25 +01:00
|
|
|
assert.NoError(t, s.cache.Put(n.Id, *n))
|
2018-09-11 05:52:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
cases := []struct {
|
|
|
|
testID string
|
|
|
|
nodeIDs []dht.NodeID
|
2018-09-18 05:39:06 +01:00
|
|
|
responses []*pb.Node
|
2018-09-11 05:52:14 +01:00
|
|
|
errors *errs.Class
|
|
|
|
}{
|
|
|
|
{testID: "empty id",
|
|
|
|
nodeIDs: []dht.NodeID{},
|
|
|
|
responses: nil,
|
|
|
|
errors: &ClientError,
|
|
|
|
},
|
|
|
|
{testID: "valid ids",
|
|
|
|
nodeIDs: func() []dht.NodeID {
|
2018-10-08 16:09:37 +01:00
|
|
|
id1 := node.IDFromString("n1")
|
|
|
|
id2 := node.IDFromString("n2")
|
|
|
|
id3 := node.IDFromString("n3")
|
2018-09-11 05:52:14 +01:00
|
|
|
return []dht.NodeID{id1, id2, id3}
|
|
|
|
}(),
|
|
|
|
responses: nodes,
|
|
|
|
errors: nil,
|
|
|
|
},
|
|
|
|
{testID: "missing ids",
|
|
|
|
nodeIDs: func() []dht.NodeID {
|
2018-10-08 16:09:37 +01:00
|
|
|
id1 := node.IDFromString("n4")
|
|
|
|
id2 := node.IDFromString("n5")
|
2018-09-11 05:52:14 +01:00
|
|
|
return []dht.NodeID{id1, id2}
|
|
|
|
}(),
|
2018-09-18 05:39:06 +01:00
|
|
|
responses: []*pb.Node{nil, nil},
|
2018-09-11 05:52:14 +01:00
|
|
|
errors: nil,
|
|
|
|
},
|
|
|
|
{testID: "random order and nil",
|
|
|
|
nodeIDs: func() []dht.NodeID {
|
2018-10-08 16:09:37 +01:00
|
|
|
id1 := node.IDFromString("n1")
|
|
|
|
id2 := node.IDFromString("n2")
|
|
|
|
id3 := node.IDFromString("n3")
|
|
|
|
id4 := node.IDFromString("n4")
|
2018-09-11 05:52:14 +01:00
|
|
|
return []dht.NodeID{id2, id1, id3, id4}
|
|
|
|
}(),
|
2018-09-18 05:39:06 +01:00
|
|
|
responses: func() []*pb.Node {
|
|
|
|
return []*pb.Node{nodes[1], nodes[0], nodes[2], nil}
|
2018-09-11 05:52:14 +01:00
|
|
|
}(),
|
|
|
|
errors: nil,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
for _, c := range cases {
|
|
|
|
t.Run(c.testID, func(t *testing.T) {
|
|
|
|
ns, err := oc.BulkLookup(ctx, c.nodeIDs)
|
|
|
|
assertErrClass(t, c.errors, err)
|
|
|
|
assert.Equal(t, c.responses, ns)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-11 08:27:12 +01:00
|
|
|
func newServer(ctx context.Context, redisAddr string) (*grpc.Server, *Server, error) {
|
2018-11-01 15:48:43 +00:00
|
|
|
ca, err := provider.NewTestCA(ctx)
|
2018-09-11 05:52:14 +01:00
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
identity, err := ca.NewIdentity()
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
identOpt, err := identity.ServerOption()
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
grpcServer := grpc.NewServer(identOpt)
|
2018-09-11 08:27:12 +01:00
|
|
|
cache, err := NewRedisOverlayCache(redisAddr, "", 1, nil)
|
2018-09-11 05:52:14 +01:00
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
s := &Server{cache: cache}
|
|
|
|
|
2018-09-18 05:39:06 +01:00
|
|
|
pb.RegisterOverlayServer(grpcServer, s)
|
2018-09-11 05:52:14 +01:00
|
|
|
|
|
|
|
return grpcServer, s, nil
|
|
|
|
}
|
2018-09-11 08:27:12 +01:00
|
|
|
|
2018-08-27 18:28:16 +01:00
|
|
|
func newTestServer(ctx context.Context) (*grpc.Server, *mockOverlayServer, error) {
|
2018-11-01 15:48:43 +00:00
|
|
|
ca, err := provider.NewTestCA(ctx)
|
2018-08-24 05:01:03 +01:00
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
identity, err := ca.NewIdentity()
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
identOpt, err := identity.ServerOption()
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
grpcServer := grpc.NewServer(identOpt)
|
2018-06-19 15:00:15 +01:00
|
|
|
mo := &mockOverlayServer{lookupCalled: 0, FindStorageNodesCalled: 0}
|
|
|
|
|
2018-09-18 05:39:06 +01:00
|
|
|
pb.RegisterOverlayServer(grpcServer, mo)
|
2018-06-19 15:00:15 +01:00
|
|
|
|
2018-08-24 05:01:03 +01:00
|
|
|
return grpcServer, mo, nil
|
2018-06-19 15:00:15 +01:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
type mockOverlayServer struct {
|
|
|
|
lookupCalled int
|
2018-09-11 05:52:14 +01:00
|
|
|
bulkLookupCalled int
|
2018-06-19 15:00:15 +01:00
|
|
|
FindStorageNodesCalled int
|
|
|
|
}
|
|
|
|
|
2018-09-18 05:39:06 +01:00
|
|
|
func (o *mockOverlayServer) Lookup(ctx context.Context, req *pb.LookupRequest) (*pb.LookupResponse, error) {
|
2018-06-19 15:00:15 +01:00
|
|
|
o.lookupCalled++
|
2018-09-18 05:39:06 +01:00
|
|
|
return &pb.LookupResponse{}, nil
|
2018-06-19 15:00:15 +01:00
|
|
|
}
|
|
|
|
|
2018-09-18 05:39:06 +01:00
|
|
|
func (o *mockOverlayServer) FindStorageNodes(ctx context.Context, req *pb.FindStorageNodesRequest) (*pb.FindStorageNodesResponse, error) {
|
2018-06-19 15:00:15 +01:00
|
|
|
o.FindStorageNodesCalled++
|
2018-09-18 05:39:06 +01:00
|
|
|
return &pb.FindStorageNodesResponse{}, nil
|
2018-06-19 15:00:15 +01:00
|
|
|
}
|
2018-09-11 05:52:14 +01:00
|
|
|
|
2018-09-18 05:39:06 +01:00
|
|
|
func (o *mockOverlayServer) BulkLookup(ctx context.Context, reqs *pb.LookupRequests) (*pb.LookupResponses, error) {
|
2018-09-11 05:52:14 +01:00
|
|
|
o.bulkLookupCalled++
|
2018-09-18 05:39:06 +01:00
|
|
|
return &pb.LookupResponses{}, nil
|
2018-09-11 05:52:14 +01:00
|
|
|
}
|