1// Copyright (C) 2019 Storj Labs, Inc. 2// See LICENSE for copying information. 3 4package audit 5 6import ( 7 "context" 8 "math/rand" 9 "testing" 10 11 "github.com/stretchr/testify/assert" 12 "github.com/stretchr/testify/require" 13 "github.com/vivint/infectious" 14 15 "storj.io/common/pkcrypto" 16 "storj.io/common/storj" 17 "storj.io/common/testrand" 18 "storj.io/storj/satellite/metabase" 19) 20 21func TestFailingAudit(t *testing.T) { 22 const ( 23 required = 8 24 total = 14 25 ) 26 27 f, err := infectious.NewFEC(required, total) 28 require.NoError(t, err) 29 30 shares := make([]infectious.Share, total) 31 output := func(s infectious.Share) { 32 shares[s.Number] = s.DeepCopy() 33 } 34 35 // the data to encode must be padded to a multiple of required, hence the 36 // underscores. 37 err = f.Encode([]byte("hello, world! __"), output) 38 require.NoError(t, err) 39 40 modifiedShares := make([]infectious.Share, len(shares)) 41 for i := range shares { 42 modifiedShares[i] = shares[i].DeepCopy() 43 } 44 45 modifiedShares[0].Data[1] = '!' 46 modifiedShares[2].Data[0] = '#' 47 modifiedShares[3].Data[1] = '!' 48 modifiedShares[4].Data[0] = 'b' 49 50 badPieceNums := []int{0, 2, 3, 4} 51 52 ctx := context.Background() 53 auditPkgShares := make(map[int]Share, len(modifiedShares)) 54 for i := range modifiedShares { 55 auditPkgShares[modifiedShares[i].Number] = Share{ 56 PieceNum: modifiedShares[i].Number, 57 Data: append([]byte(nil), modifiedShares[i].Data...), 58 } 59 } 60 61 pieceNums, correctedShares, err := auditShares(ctx, 8, 14, auditPkgShares) 62 if err != nil { 63 panic(err) 64 } 65 66 for i, num := range pieceNums { 67 if num != badPieceNums[i] { 68 t.Fatal("expected nums in pieceNums to be same as in badPieceNums") 69 } 70 } 71 72 require.Equal(t, shares, correctedShares) 73} 74 75func TestNotEnoughShares(t *testing.T) { 76 const ( 77 required = 8 78 total = 14 79 ) 80 81 f, err := infectious.NewFEC(required, total) 82 require.NoError(t, err) 83 84 shares := make([]infectious.Share, total) 85 output := func(s infectious.Share) { 86 shares[s.Number] = s.DeepCopy() 87 } 88 89 // the data to encode must be padded to a multiple of required, hence the 90 // underscores. 91 err = f.Encode([]byte("hello, world! __"), output) 92 require.NoError(t, err) 93 94 ctx := context.Background() 95 auditPkgShares := make(map[int]Share, len(shares)) 96 for i := range shares { 97 auditPkgShares[shares[i].Number] = Share{ 98 PieceNum: shares[i].Number, 99 Data: append([]byte(nil), shares[i].Data...), 100 } 101 } 102 _, _, err = auditShares(ctx, 20, 40, auditPkgShares) 103 require.NotNil(t, err) 104 require.Contains(t, err.Error(), "must specify at least the number of required shares") 105} 106 107func TestCreatePendingAudits(t *testing.T) { 108 const ( 109 required = 8 110 total = 14 111 ) 112 113 f, err := infectious.NewFEC(required, total) 114 require.NoError(t, err) 115 116 shares := make([]infectious.Share, total) 117 output := func(s infectious.Share) { 118 shares[s.Number] = s.DeepCopy() 119 } 120 121 // The data to encode must be padded to a multiple of required, hence the 122 // underscores. 123 err = f.Encode([]byte("hello, world! __"), output) 124 require.NoError(t, err) 125 126 testNodeID := testrand.NodeID() 127 128 ctx := context.Background() 129 contained := make(map[int]storj.NodeID) 130 contained[1] = testNodeID 131 132 segment := testSegment() 133 segmentInfo := metabase.Segment{ 134 StreamID: segment.StreamID, 135 RootPieceID: testrand.PieceID(), 136 Redundancy: storj.RedundancyScheme{ 137 Algorithm: storj.ReedSolomon, 138 RequiredShares: required, 139 TotalShares: total, 140 ShareSize: int32(len(shares[0].Data)), 141 }, 142 } 143 randomIndex := rand.Int31n(10) 144 145 pending, err := createPendingAudits(ctx, contained, shares, segment, segmentInfo, randomIndex) 146 require.NoError(t, err) 147 require.Equal(t, 1, len(pending)) 148 assert.Equal(t, testNodeID, pending[0].NodeID) 149 assert.Equal(t, segmentInfo.RootPieceID, pending[0].PieceID) 150 assert.Equal(t, randomIndex, pending[0].StripeIndex) 151 assert.Equal(t, segmentInfo.Redundancy.ShareSize, pending[0].ShareSize) 152 assert.Equal(t, pkcrypto.SHA256Hash(shares[1].Data), pending[0].ExpectedShareHash) 153 assert.EqualValues(t, 0, pending[0].ReverifyCount) 154} 155