storj/pkg/overlay/client_test.go

351 lines
8.1 KiB
Go
Raw Normal View History

// Copyright (C) 2018 Storj Labs, Inc.
// See LICENSE for copying information.
package overlay
import (
"context"
"net"
"testing"
"github.com/gogo/protobuf/proto"
"github.com/stretchr/testify/assert"
"google.golang.org/grpc"
"storj.io/storj/internal/identity"
2018-11-16 16:31:14 +00:00
"storj.io/storj/internal/testcontext"
"storj.io/storj/internal/teststorj"
"storj.io/storj/pkg/pb"
"storj.io/storj/pkg/storj"
"storj.io/storj/storage"
2018-11-16 16:31:14 +00:00
"storj.io/storj/storage/teststore"
)
var fooID = teststorj.NodeIDFromString("foo")
Transport security (#63) * wip initial transport security * wip: transport security (add tests / refactor) * wip tests * refactoring - still wip * refactor, improve tests * wip tls testing * fix typo * wip testing * wip testing * wip * tls_test passing * code-style improvemente / refactor; service and tls tests passing! * code-style auto-format * add TestNewServer_LoadTLS * refactor; test improvements * refactor * add client cert * port changes * Merge remote-tracking branch 'upstream/master' * Merge remote-tracking branch 'upstream/master' * Merge remote-tracking branch 'upstream/master' * files created * Merge remote-tracking branch 'upstream/master' into coyle/kad-tests * wip * add separate `Process` tests for bolt and redis-backed overlay * more testing * fix gitignore * fix linter error * goimports goimports GOIMPORTS GoImPortS!!!! * wip * fix port madness * forgot to add * add `mux` as handler and shorten context timeouts * gofreakingimports * fix comments * refactor test & add logger/monkit registry * debugging travis * add comment * Set redisAddress to empty string for bolt-test * Merge remote-tracking branch 'upstream/master' into coyle/kad-tests * Merge branch 'tls' into tls-upstream * tls: add client cert refactor refactor; test improvements add TestNewServer_LoadTLS code-style auto-format code-style improvemente / refactor; service and tls tests passing! tls_test passing wip wip testing wip testing fix typo wip tls testing refactor, improve tests refactoring - still wip wip tests wip: transport security (add tests / refactor) wip initial transport security * fixing linter things * wip * remove bkad dependencie from tests * wip * wip * wip * wip * wip * updated coyle/kademlia * wip * cleanup * ports * overlay upgraded * linter fixes * piecestore kademlia newID * Merge branch 'master' into tls-upstream * master: Add error to the return values of Ranger.Range method (#90) udp-forwarding: demo week work! (#84) * Merge branch 'kad-tests' into tls-upstream * kad-tests: piecestore kademlia newID linter fixes overlay upgraded ports cleanup wip updated coyle/kademlia wip wip wip wip wip remove bkad dependencie from tests wip wip files created port changes * wip * finish merging service tests * add test for different client/server certs * wip * Merge branch 'master' into tls-upstream * master: Add context to Ranger.Range method (#99) Coyle/kad client (#91) * wip * wip; refactoring/cleanup * wip * Merge branch 'master' into tls * master: Bolt backed overlay cache (#94) internal/test: switch errors to error classes (#96) * wip - test passing * cleanup * remove port.go * cleanup * Merge branch 'master' into tls * master: hardcode version (#111) Coyle/docker fix (#109) pkg/kademlia tests and restructuring (#97) Use continue instead of return in table tests (#106) prepend storjlabs to docker tag (#108) Automatically build, tag and push docker images on merge to master (#103) * more belated merging * more belated merging * more belated merging * add copyrights * cleanup * goimports * refactoring * wip * wip * implement `TLSFileOptions#loadTLS`, refactoring: `peertls.TestNewClient_LoadTLS` is the failing holdout; Still trying to figure out why I'm getting ECDSA verification is failing. * not sure if actually working: Tests are now passing (no more "ECDSA verification failed"); however, `len(*tls.Certificates.Certificate) == 1` which I don't think should be the case if the root and leaf are being created correctly. * Experimenting/bugfixing?: I think leaf certs should be properly signed by the parent now but not entirely certain. It's also unclear to me why in `VerifyPeerCertificate`, `len(rawCerts) == 1` when the certs should contain both the root and leaf afaik. * Properly write/read certificate chain (root/leaf): I think I'm now properly reading and writing the root and leaf certificate chain such that they're both being received by `VerifyPeerCertificate`. The next step is to parse the certificates with `x509.ParseCertificate` (or similar) and verify that the public keys and signatures match. * Add tls certificate chain signature veification (spike): + `VerifyPeerCertificate` verifies signatures of certificates using the key of it's parent if there is one; otherwise, it verifies the certificate is self-signed + TODO: refactor + TODO: test * refactoring `VerifyPeerCertificate` * cleanup * refactor * Merge branch 'master' into tls * master: Remove some structural folders we don't seem to be using. (#125) license code with agplv3 (#126) Update .clabot (#124) added team memebers (#123) clabot file added (#121) ECClient (#110) docker image issue fixed (#118) Piecestore Farmer CLI (#92) Define Path type (#101) adds netstate pagination (#95) Transport Client (#89) Implement psclient interface (#107) pkg/process: start replacing pkg/process with cobra helpers (#98) protos/netstate: remove stuff we're not using (#100) adding coveralls / code coverage (#112) * responding to review feedback / cleanup / add copywrite headers * suggestions * realitive * Merge pull request #1 from coyle/coyle/tls suggestions * remove unnecessary `_`s * Merge branch 'tls' of github.com:bryanchriswhite/storj into tls * 'tls' of github.com:bryanchriswhite/storj: realitive suggestions * Responding to review feedback: + refactor `VerifyPeerCertificate` * remove tls expiration * remove "hosts" and "clien option" from tls options * goimports * linter fixes
2018-07-09 18:43:13 +01:00
func TestNewOverlayClient(t *testing.T) {
2018-11-16 16:31:14 +00:00
ctx := testcontext.New(t)
defer ctx.Cleanup()
cases := []struct {
address string
}{
{
address: "127.0.0.1:8080",
},
}
for _, v := range cases {
ca, err := testidentity.NewTestCA(ctx)
assert.NoError(t, err)
identity, err := ca.NewIdentity()
assert.NoError(t, err)
oc, err := NewOverlayClient(identity, v.address)
assert.NoError(t, err)
assert.NotNil(t, oc)
overlay, ok := oc.(*Overlay)
assert.True(t, ok)
assert.NotEmpty(t, overlay.client)
}
}
func TestChoose(t *testing.T) {
2018-11-16 16:31:14 +00:00
ctx := testcontext.New(t)
defer ctx.Cleanup()
cases := []struct {
limit int
space int64
allNodes []*pb.Node
excluded storj.NodeIDList
}{
{
limit: 4,
space: 0,
allNodes: func() []*pb.Node {
n1 := teststorj.MockNode("n1")
n2 := teststorj.MockNode("n2")
n3 := teststorj.MockNode("n3")
n4 := teststorj.MockNode("n4")
n5 := teststorj.MockNode("n5")
n6 := teststorj.MockNode("n6")
n7 := teststorj.MockNode("n7")
n8 := teststorj.MockNode("n8")
nodes := []*pb.Node{n1, n2, n3, n4, n5, n6, n7, n8}
for _, n := range nodes {
n.Type = pb.NodeType_STORAGE
}
return nodes
}(),
excluded: func() storj.NodeIDList {
id1 := teststorj.NodeIDFromString("n1")
id2 := teststorj.NodeIDFromString("n2")
id3 := teststorj.NodeIDFromString("n3")
id4 := teststorj.NodeIDFromString("n4")
return storj.NodeIDList{id1, id2, id3, id4}
}(),
},
}
for _, v := range cases {
lis, err := net.Listen("tcp", "127.0.0.1:0")
assert.NoError(t, err)
var listItems []storage.ListItem
for _, n := range v.allNodes {
data, err := proto.Marshal(n)
assert.NoError(t, err)
listItems = append(listItems, storage.ListItem{
Key: n.Id.Bytes(),
Value: data,
})
}
ca, err := testidentity.NewTestCA(ctx)
assert.NoError(t, err)
identity, err := ca.NewIdentity()
assert.NoError(t, err)
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()
oc, err := NewOverlayClient(identity, lis.Addr().String())
assert.NoError(t, err)
assert.NotNil(t, oc)
overlay, ok := oc.(*Overlay)
assert.True(t, ok)
assert.NotEmpty(t, overlay.client)
newNodes, err := oc.Choose(ctx, Options{Amount: v.limit, Space: v.space, Excluded: v.excluded})
assert.NoError(t, err)
for _, new := range newNodes {
for _, ex := range v.excluded {
assert.NotEqual(t, ex.String(), new.Id)
}
}
}
}
func TestLookup(t *testing.T) {
2018-11-16 16:31:14 +00:00
ctx := testcontext.New(t)
defer ctx.Cleanup()
cases := []struct {
nodeID storj.NodeID
expectedCalls int
}{
{
nodeID: fooID,
expectedCalls: 1,
},
}
for _, v := range cases {
lis, err := net.Listen("tcp", "127.0.0.1:0")
assert.NoError(t, err)
srv, mock, err := newTestServer(ctx)
assert.NoError(t, err)
go func() { assert.NoError(t, srv.Serve(lis)) }()
defer srv.Stop()
ca, err := testidentity.NewTestCA(ctx)
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)
overlay, ok := oc.(*Overlay)
assert.True(t, ok)
assert.NotEmpty(t, overlay.client)
_, err = oc.Lookup(ctx, v.nodeID)
assert.NoError(t, err)
assert.Equal(t, mock.lookupCalled, v.expectedCalls)
}
}
2018-11-16 16:31:14 +00:00
func TestBulkLookup(t *testing.T) {
2018-11-16 16:31:14 +00:00
ctx := testcontext.New(t)
defer ctx.Cleanup()
cases := []struct {
nodeIDs storj.NodeIDList
expectedCalls int
}{
{
nodeIDs: storj.NodeIDList{fooID, fooID, fooID},
expectedCalls: 1,
},
}
for _, v := range cases {
lis, err := net.Listen("tcp", "127.0.0.1:0")
assert.NoError(t, err)
srv, mock, err := newTestServer(ctx)
assert.NoError(t, err)
go func() { assert.NoError(t, srv.Serve(lis)) }()
defer srv.Stop()
ca, err := testidentity.NewTestCA(ctx)
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)
overlay, ok := oc.(*Overlay)
assert.True(t, ok)
assert.NotEmpty(t, overlay.client)
_, err = oc.BulkLookup(ctx, v.nodeIDs)
assert.NoError(t, err)
assert.Equal(t, mock.bulkLookupCalled, v.expectedCalls)
}
}
2018-11-16 16:31:14 +00:00
func TestBulkLookupV2(t *testing.T) {
2018-11-16 16:31:14 +00:00
ctx := testcontext.New(t)
defer ctx.Cleanup()
lis, err := net.Listen("tcp", "127.0.0.1:0")
assert.NoError(t, err)
2018-11-16 16:31:14 +00:00
srv, s, err := newServer(ctx)
assert.NoError(t, err)
go func() { assert.NoError(t, srv.Serve(lis)) }()
defer srv.Stop()
ca, err := testidentity.NewTestCA(ctx)
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)
overlay, ok := oc.(*Overlay)
assert.True(t, ok)
assert.NotEmpty(t, overlay.client)
n1 := teststorj.MockNode("n1")
n2 := teststorj.MockNode("n2")
n3 := teststorj.MockNode("n3")
nodes := []*pb.Node{n1, n2, n3}
for _, n := range nodes {
assert.NoError(t, s.cache.Put(n.Id, *n))
}
nid1 := teststorj.NodeIDFromString("n1")
nid2 := teststorj.NodeIDFromString("n2")
nid3 := teststorj.NodeIDFromString("n3")
nid4 := teststorj.NodeIDFromString("n4")
nid5 := teststorj.NodeIDFromString("n5")
2018-11-16 16:31:14 +00:00
{ // empty id
_, err := oc.BulkLookup(ctx, storj.NodeIDList{})
2018-11-16 16:31:14 +00:00
assert.Error(t, err)
}
{ // valid ids
ns, err := oc.BulkLookup(ctx, storj.NodeIDList{nid1, nid2, nid3})
2018-11-16 16:31:14 +00:00
assert.NoError(t, err)
assert.Equal(t, nodes, ns)
}
2018-11-16 16:31:14 +00:00
{ // missing ids
ns, err := oc.BulkLookup(ctx, storj.NodeIDList{nid4, nid5})
2018-11-16 16:31:14 +00:00
assert.NoError(t, err)
assert.Equal(t, []*pb.Node{nil, nil}, ns)
}
{ // different order and missing
ns, err := oc.BulkLookup(ctx, storj.NodeIDList{nid3, nid4, nid1, nid2, nid5})
2018-11-16 16:31:14 +00:00
assert.NoError(t, err)
assert.Equal(t, []*pb.Node{n3, nil, n1, n2, nil}, ns)
}
}
2018-11-16 16:31:14 +00:00
func newServer(ctx context.Context) (*grpc.Server, *Server, error) {
ca, err := testidentity.NewTestCA(ctx)
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)
s := &Server{cache: NewOverlayCache(teststore.New(), nil, nil)}
pb.RegisterOverlayServer(grpcServer, s)
return grpcServer, s, nil
}
func newTestServer(ctx context.Context) (*grpc.Server, *mockOverlayServer, error) {
ca, err := testidentity.NewTestCA(ctx)
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)
mo := &mockOverlayServer{lookupCalled: 0, FindStorageNodesCalled: 0}
pb.RegisterOverlayServer(grpcServer, mo)
return grpcServer, mo, nil
}
type mockOverlayServer struct {
lookupCalled int
bulkLookupCalled int
FindStorageNodesCalled int
}
func (o *mockOverlayServer) Lookup(ctx context.Context, req *pb.LookupRequest) (*pb.LookupResponse, error) {
o.lookupCalled++
return &pb.LookupResponse{}, nil
}
func (o *mockOverlayServer) FindStorageNodes(ctx context.Context, req *pb.FindStorageNodesRequest) (*pb.FindStorageNodesResponse, error) {
o.FindStorageNodesCalled++
return &pb.FindStorageNodesResponse{}, nil
}
func (o *mockOverlayServer) BulkLookup(ctx context.Context, reqs *pb.LookupRequests) (*pb.LookupResponses, error) {
o.bulkLookupCalled++
return &pb.LookupResponses{}, nil
}