storj/pkg/audit/verifier_test.go

258 lines
5.9 KiB
Go
Raw Normal View History

2019-01-24 20:15:10 +00:00
// Copyright (C) 2019 Storj Labs, Inc.
2018-10-09 22:10:37 +01:00
// See LICENSE for copying information.
2019-01-23 19:58:44 +00:00
// +build ignore
package audit_test
2018-10-09 22:10:37 +01:00
import (
"context"
"crypto/rand"
"strconv"
"testing"
"github.com/stretchr/testify/assert"
"github.com/vivint/infectious"
"storj.io/storj/internal/teststorj"
2019-01-23 19:58:44 +00:00
"storj.io/storj/pkg/audit"
2018-10-09 22:10:37 +01:00
"storj.io/storj/pkg/pb"
)
type mockDownloader struct {
2019-01-23 19:58:44 +00:00
shares map[int]audit.Share
2018-10-09 22:10:37 +01:00
}
func TestPassingAudit(t *testing.T) {
ctx := context.Background()
2019-01-23 19:58:44 +00:00
mockShares := make(map[int]audit.Share)
2018-10-09 22:10:37 +01:00
for _, tt := range []struct {
nodeAmt int
shareAmt int
required int
total int
err error
}{
{nodeAmt: 30, shareAmt: 30, required: 20, total: 40, err: nil},
} {
someData := randData(32 * 1024)
for i := 0; i < tt.shareAmt; i++ {
2019-01-23 19:58:44 +00:00
mockShares[i] = audit.Share{
2018-10-09 22:10:37 +01:00
Error: tt.err,
PieceNumber: i,
Data: someData,
}
}
md := mockDownloader{shares: mockShares}
2019-01-23 19:58:44 +00:00
verifier := &audit.Verifier{downloader: &md}
2018-10-09 22:10:37 +01:00
pointer := makePointer(tt.nodeAmt)
2019-01-23 19:58:44 +00:00
verifiedNodes, err := verifier.Verify(ctx, &audit.Stripe{Index: 6, Segment: pointer, PBA: nil, Authorization: nil})
2018-10-09 22:10:37 +01:00
if err != nil {
t.Fatal(err)
}
if len(verifiedNodes.SuccessNodeIDs) == 0 {
t.Fatal("expected there to be passing nodes")
2018-10-09 22:10:37 +01:00
}
}
}
func TestSomeNodesPassAudit(t *testing.T) {
ctx := context.Background()
mockShares := make(map[int]share)
for _, tt := range []struct {
nodeAmt int
shareAmt int
required int
total int
err0 error
err1 error
}{
{nodeAmt: 30, shareAmt: 30, required: 20, total: 40, err0: Error.New("unable to get node"), err1: nil},
} {
someData := randData(32 * 1024)
for i := 0; i < 10; i++ {
mockShares[i] = share{
Error: tt.err0,
PieceNumber: i,
Data: someData,
}
}
for i := 10; i < tt.shareAmt; i++ {
mockShares[i] = share{
Error: tt.err1,
PieceNumber: i,
Data: someData,
}
}
md := mockDownloader{shares: mockShares}
2019-01-23 19:58:44 +00:00
verifier := &audit.Verifier{downloader: &md}
pointer := makePointer(tt.nodeAmt)
2019-01-23 19:58:44 +00:00
verifiedNodes, err := verifier.verify(ctx, &audit.Stripe{Index: 6, Segment: pointer, PBA: nil, Authorization: nil})
if err != nil {
t.Fatal(err)
}
assert.Equal(t, len(verifiedNodes.OfflineNodeIDs), 10)
}
}
2018-10-09 22:10:37 +01:00
func TestFailingAudit(t *testing.T) {
const (
required = 8
total = 14
)
f, err := infectious.NewFEC(required, total)
if err != nil {
panic(err)
}
shares := make([]infectious.Share, total)
output := func(s infectious.Share) {
shares[s.Number] = s.DeepCopy()
}
// the data to encode must be padded to a multiple of required, hence the
// underscores.
err = f.Encode([]byte("hello, world! __"), output)
if err != nil {
panic(err)
}
modifiedShares := make([]infectious.Share, len(shares))
for i := range shares {
modifiedShares[i] = shares[i].DeepCopy()
}
modifiedShares[0].Data[1] = '!'
modifiedShares[2].Data[0] = '#'
modifiedShares[3].Data[1] = '!'
modifiedShares[4].Data[0] = 'b'
badPieceNums := []int{0, 2, 3, 4}
ctx := context.Background()
2019-01-23 19:58:44 +00:00
auditPkgShares := make(map[int]audit.Share, len(modifiedShares))
2018-10-09 22:10:37 +01:00
for i := range modifiedShares {
2019-01-23 19:58:44 +00:00
auditPkgShares[modifiedShares[i].Number] = audit.Share{
2018-11-28 07:33:17 +00:00
PieceNumber: modifiedShares[i].Number,
Data: append([]byte(nil), modifiedShares[i].Data...),
}
2018-10-09 22:10:37 +01:00
}
pieceNums, err := auditShares(ctx, 8, 14, auditPkgShares)
if err != nil {
panic(err)
}
for i, num := range pieceNums {
if num != badPieceNums[i] {
t.Fatal("expected nums in pieceNums to be same as in badPieceNums")
}
}
}
func TestNotEnoughShares(t *testing.T) {
const (
required = 8
total = 14
)
f, err := infectious.NewFEC(required, total)
if err != nil {
panic(err)
}
shares := make([]infectious.Share, total)
output := func(s infectious.Share) {
shares[s.Number] = s.DeepCopy()
}
// the data to encode must be padded to a multiple of required, hence the
// underscores.
err = f.Encode([]byte("hello, world! __"), output)
if err != nil {
panic(err)
}
ctx := context.Background()
2018-11-28 07:33:17 +00:00
auditPkgShares := make(map[int]share, len(shares))
2018-10-09 22:10:37 +01:00
for i := range shares {
2018-11-28 07:33:17 +00:00
auditPkgShares[shares[i].Number] = share{
PieceNumber: shares[i].Number,
Data: append([]byte(nil), shares[i].Data...),
}
2018-10-09 22:10:37 +01:00
}
_, err = auditShares(ctx, 20, 40, auditPkgShares)
assert.Contains(t, err.Error(), "infectious: must specify at least the number of required shares")
}
func TestCalcPadded(t *testing.T) {
for _, tt := range []struct {
segSize int64
blockSize int
paddedSize int64
}{
{segSize: int64(5 * 1024), blockSize: 1024, paddedSize: int64(5120)},
{segSize: int64(5 * 1023), blockSize: 1024, paddedSize: int64(5120)},
} {
result := calcPadded(tt.segSize, tt.blockSize)
assert.Equal(t, result, tt.paddedSize)
}
}
func (m *mockDownloader) DownloadShares(ctx context.Context, pointer *pb.Pointer, stripeIndex int,
pba *pb.PayerBandwidthAllocation, authorization *pb.SignedMessage) (shares map[int]share, nodes map[int]*pb.Node, err error) {
2018-11-28 07:33:17 +00:00
nodes = make(map[int]*pb.Node, 30)
2018-10-09 22:10:37 +01:00
for i := 0; i < 30; i++ {
2018-11-28 07:33:17 +00:00
nodes[i] = &pb.Node{
Id: teststorj.NodeIDFromString(strconv.Itoa(i)),
Type: pb.NodeType_STORAGE,
Address: &pb.NodeAddress{
Address: strconv.Itoa(i),
},
2018-10-09 22:10:37 +01:00
}
}
2018-11-28 07:33:17 +00:00
return m.shares, nodes, nil
2018-10-09 22:10:37 +01:00
}
func makePointer(nodeAmt int) *pb.Pointer {
var rps []*pb.RemotePiece
for i := 0; i < nodeAmt; i++ {
rps = append(rps, &pb.RemotePiece{
PieceNum: int32(i),
NodeId: teststorj.NodeIDFromString("test" + strconv.Itoa(i)),
2018-10-09 22:10:37 +01:00
})
}
pr := &pb.Pointer{
Type: pb.Pointer_REMOTE,
Remote: &pb.RemoteSegment{
Redundancy: &pb.RedundancyScheme{
Type: pb.RedundancyScheme_RS,
MinReq: 20,
Total: 40,
RepairThreshold: 2,
SuccessThreshold: 3,
ErasureShareSize: 4,
},
PieceId: "testId",
RemotePieces: rps,
},
SegmentSize: int64(1),
2018-10-09 22:10:37 +01:00
}
return pr
}
func randData(amount int) []byte {
buf := make([]byte, amount)
_, err := rand.Read(buf)
if err != nil {
panic(err)
}
return buf
}