2018-11-05 15:23:54 +00:00
|
|
|
// Copyright (C) 2018 Storj Labs, Inc.
|
|
|
|
// See LICENSE for copying information.
|
|
|
|
|
|
|
|
package bwagreement
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"crypto"
|
|
|
|
"crypto/ecdsa"
|
2018-11-15 19:06:09 +00:00
|
|
|
"crypto/x509"
|
2018-11-08 13:20:23 +00:00
|
|
|
"flag"
|
2018-11-05 15:23:54 +00:00
|
|
|
"log"
|
|
|
|
"net"
|
2018-11-08 13:20:23 +00:00
|
|
|
"os"
|
2018-11-05 15:23:54 +00:00
|
|
|
"testing"
|
2018-11-15 19:06:09 +00:00
|
|
|
"time"
|
2018-11-05 15:23:54 +00:00
|
|
|
|
2018-11-15 19:06:09 +00:00
|
|
|
"github.com/gogo/protobuf/proto"
|
2018-11-12 21:59:30 +00:00
|
|
|
"github.com/gtank/cryptopasta"
|
2018-11-15 19:06:09 +00:00
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
"github.com/zeebo/errs"
|
|
|
|
|
2018-11-05 15:23:54 +00:00
|
|
|
"go.uber.org/zap"
|
|
|
|
"google.golang.org/grpc"
|
|
|
|
|
2018-11-15 19:06:09 +00:00
|
|
|
"storj.io/storj/pkg/bwagreement/database-manager"
|
2018-11-05 15:23:54 +00:00
|
|
|
"storj.io/storj/pkg/pb"
|
|
|
|
"storj.io/storj/pkg/provider"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
ctx = context.Background()
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestBandwidthAgreements(t *testing.T) {
|
|
|
|
TS := NewTestServer(t)
|
|
|
|
defer TS.Stop()
|
|
|
|
|
2018-11-15 19:06:09 +00:00
|
|
|
pba, err := generatePayerBandwidthAllocation(pb.PayerBandwidthAllocation_GET, TS.k)
|
|
|
|
assert.NoError(t, err)
|
2018-11-05 15:23:54 +00:00
|
|
|
|
2018-11-15 19:06:09 +00:00
|
|
|
rba, err := generateRenterBandwidthAllocation(pba, TS.k)
|
2018-11-12 21:59:30 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2018-11-05 15:23:54 +00:00
|
|
|
/* emulate sending the bwagreement stream from piecestore node */
|
2018-11-15 19:06:09 +00:00
|
|
|
_, err = TS.c.BandwidthAgreements(ctx, rba)
|
2018-11-05 15:23:54 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
type TestServer struct {
|
|
|
|
s *Server
|
|
|
|
grpcs *grpc.Server
|
|
|
|
conn *grpc.ClientConn
|
|
|
|
c pb.BandwidthClient
|
|
|
|
k crypto.PrivateKey
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewTestServer(t *testing.T) *TestServer {
|
|
|
|
check := func(e error) {
|
|
|
|
if !assert.NoError(t, e) {
|
|
|
|
t.Fail()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
caS, err := provider.NewTestCA(context.Background())
|
|
|
|
check(err)
|
|
|
|
fiS, err := caS.NewIdentity()
|
|
|
|
check(err)
|
|
|
|
so, err := fiS.ServerOption()
|
|
|
|
check(err)
|
|
|
|
|
|
|
|
caC, err := provider.NewTestCA(context.Background())
|
|
|
|
check(err)
|
|
|
|
fiC, err := caC.NewIdentity()
|
|
|
|
check(err)
|
2018-11-09 22:08:33 +00:00
|
|
|
co, err := fiC.DialOption("")
|
2018-11-05 15:23:54 +00:00
|
|
|
check(err)
|
|
|
|
|
2018-11-15 19:06:09 +00:00
|
|
|
s := newTestServerStruct(t, fiC.Key)
|
2018-11-05 15:23:54 +00:00
|
|
|
grpcs := grpc.NewServer(so)
|
|
|
|
|
|
|
|
k, ok := fiC.Key.(*ecdsa.PrivateKey)
|
|
|
|
assert.True(t, ok)
|
|
|
|
ts := &TestServer{s: s, grpcs: grpcs, k: k}
|
|
|
|
addr := ts.start()
|
|
|
|
ts.c, ts.conn = connect(addr, co)
|
|
|
|
|
|
|
|
return ts
|
|
|
|
}
|
|
|
|
|
2018-11-08 13:20:23 +00:00
|
|
|
const (
|
|
|
|
// this connstring is expected to work under the storj-test docker-compose instance
|
2018-11-15 18:36:57 +00:00
|
|
|
defaultPostgresConn = "postgres://storj:storj-pass@test-postgres/teststorj?sslmode=disable"
|
2018-11-08 13:20:23 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
// for travis build support
|
2018-11-15 18:36:57 +00:00
|
|
|
testPostgres = flag.String("postgres-test-db", os.Getenv("STORJ_POSTGRES_TEST"), "PostgreSQL test database connection string")
|
2018-11-08 13:20:23 +00:00
|
|
|
)
|
|
|
|
|
2018-11-15 19:06:09 +00:00
|
|
|
func newTestServerStruct(t *testing.T, k crypto.PrivateKey) *Server {
|
2018-11-08 13:20:23 +00:00
|
|
|
if *testPostgres == "" {
|
|
|
|
t.Skipf("postgres flag missing, example:\n-postgres-test-db=%s", defaultPostgresConn)
|
|
|
|
}
|
|
|
|
|
2018-11-15 19:06:09 +00:00
|
|
|
dbm, err := dbmanager.NewDBManager("postgres", *testPostgres)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Failed to initialize dbmanager when creating test server: %+v", err)
|
|
|
|
}
|
2018-11-12 21:59:30 +00:00
|
|
|
|
|
|
|
p, _ := k.(*ecdsa.PrivateKey)
|
2018-11-15 19:06:09 +00:00
|
|
|
server, err := NewServer(dbm, zap.NewNop(), &p.PublicKey)
|
2018-11-09 22:15:35 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
return server
|
2018-11-05 15:23:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (TS *TestServer) start() (addr string) {
|
|
|
|
lis, err := net.Listen("tcp", "127.0.0.1:0")
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("failed to listen: %v", err)
|
|
|
|
}
|
|
|
|
pb.RegisterBandwidthServer(TS.grpcs, TS.s)
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
if err := TS.grpcs.Serve(lis); err != nil {
|
|
|
|
log.Fatalf("failed to serve: %v", err)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
return lis.Addr().String()
|
|
|
|
}
|
|
|
|
|
|
|
|
func connect(addr string, o ...grpc.DialOption) (pb.BandwidthClient, *grpc.ClientConn) {
|
|
|
|
conn, err := grpc.Dial(addr, o...)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("did not connect: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
c := pb.NewBandwidthClient(conn)
|
|
|
|
|
|
|
|
return c, conn
|
|
|
|
}
|
|
|
|
|
2018-11-15 19:06:09 +00:00
|
|
|
func generatePayerBandwidthAllocation(action pb.PayerBandwidthAllocation_Action, satelliteKey crypto.PrivateKey) (*pb.PayerBandwidthAllocation, error) {
|
|
|
|
satelliteKeyEcdsa, ok := satelliteKey.(*ecdsa.PrivateKey)
|
|
|
|
if !ok {
|
|
|
|
return nil, errs.New("Satellite Private Key is not a valid *ecdsa.PrivateKey")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Generate PayerBandwidthAllocation_Data
|
|
|
|
data, _ := proto.Marshal(
|
|
|
|
&pb.PayerBandwidthAllocation_Data{
|
|
|
|
SatelliteId: []byte("SatelliteID"),
|
|
|
|
UplinkId: []byte("UplinkID"),
|
|
|
|
ExpirationUnixSec: time.Now().Add(time.Hour * 24 * 10).Unix(),
|
|
|
|
SerialNumber: "SerialNumber",
|
|
|
|
Action: action,
|
|
|
|
CreatedUnixSec: time.Now().Unix(),
|
|
|
|
},
|
|
|
|
)
|
|
|
|
|
|
|
|
// Sign the PayerBandwidthAllocation_Data with the "Satellite" Private Key
|
|
|
|
s, err := cryptopasta.Sign(data, satelliteKeyEcdsa)
|
|
|
|
if err != nil {
|
|
|
|
return nil, errs.New("Failed to sign PayerBandwidthAllocation_Data with satellite Private Key: %+v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Combine Signature and Data for PayerBandwidthAllocation
|
|
|
|
return &pb.PayerBandwidthAllocation{
|
|
|
|
Data: data,
|
|
|
|
Signature: s,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func generateRenterBandwidthAllocation(pba *pb.PayerBandwidthAllocation, uplinkKey crypto.PrivateKey) (*pb.RenterBandwidthAllocation, error) {
|
|
|
|
// get "Uplink" Public Key
|
|
|
|
uplinkKeyEcdsa, ok := uplinkKey.(*ecdsa.PrivateKey)
|
|
|
|
if !ok {
|
|
|
|
return nil, errs.New("Uplink Private Key is not a valid *ecdsa.PrivateKey")
|
|
|
|
}
|
|
|
|
|
|
|
|
pubbytes, err := x509.MarshalPKIXPublicKey(&uplinkKeyEcdsa.PublicKey)
|
|
|
|
if err != nil {
|
|
|
|
return nil, errs.New("Could not generate byte array from Uplink Public key: %+v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Generate RenterBandwidthAllocation_Data
|
|
|
|
data, _ := proto.Marshal(
|
|
|
|
&pb.RenterBandwidthAllocation_Data{
|
|
|
|
PayerAllocation: pba,
|
|
|
|
PubKey: pubbytes, // TODO: Take this out. It will be kept in a database on the satellite
|
|
|
|
StorageNodeId: []byte("StorageNodeID"),
|
|
|
|
Total: int64(666),
|
|
|
|
},
|
|
|
|
)
|
|
|
|
|
|
|
|
// Sign the PayerBandwidthAllocation_Data with the "Uplink" Private Key
|
|
|
|
s, err := cryptopasta.Sign(data, uplinkKeyEcdsa)
|
|
|
|
if err != nil {
|
|
|
|
return nil, errs.New("Failed to sign RenterBandwidthAllocation_Data with uplink Private Key: %+v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Combine Signature and Data for RenterBandwidthAllocation
|
|
|
|
return &pb.RenterBandwidthAllocation{
|
|
|
|
Signature: s,
|
|
|
|
Data: data,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
2018-11-05 15:23:54 +00:00
|
|
|
func (TS *TestServer) Stop() {
|
|
|
|
if err := TS.conn.Close(); err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
TS.grpcs.Stop()
|
|
|
|
}
|