1// Copyright (C) 2019 Storj Labs, Inc. 2// See LICENSE for copying information. 3 4package nodetally_test 5 6import ( 7 "testing" 8 "time" 9 10 "github.com/stretchr/testify/assert" 11 "github.com/stretchr/testify/require" 12 13 "storj.io/common/encryption" 14 "storj.io/common/memory" 15 "storj.io/common/storj" 16 "storj.io/common/testcontext" 17 "storj.io/common/testrand" 18 "storj.io/storj/private/testplanet" 19 "storj.io/storj/satellite/accounting/nodetally" 20) 21 22func TestCalculateNodeAtRestData(t *testing.T) { 23 testplanet.Run(t, testplanet.Config{ 24 SatelliteCount: 1, StorageNodeCount: 4, UplinkCount: 1, 25 }, func(t *testing.T, ctx *testcontext.Context, planet *testplanet.Planet) { 26 tallySvc := planet.Satellites[0].Accounting.NodeTally 27 tallySvc.Loop.Pause() 28 uplink := planet.Uplinks[0] 29 30 // Setup: create 50KiB of data for the uplink to upload 31 expectedData := testrand.Bytes(50 * memory.KiB) 32 33 // TODO uplink currently hardcode block size so we need to use the same value in test 34 encryptionParameters := storj.EncryptionParameters{ 35 CipherSuite: storj.EncAESGCM, 36 BlockSize: 29 * 256 * memory.B.Int32(), 37 } 38 expectedTotalBytes, err := encryption.CalcEncryptedSize(int64(len(expectedData)), encryptionParameters) 39 require.NoError(t, err) 40 41 // Execute test: upload a file, then calculate at rest data 42 expectedBucketName := "testbucket" 43 err = uplink.Upload(ctx, planet.Satellites[0], expectedBucketName, "test/path", expectedData) 44 require.NoError(t, err) 45 46 obs := nodetally.NewObserver(planet.Satellites[0].Log.Named("observer"), time.Now()) 47 err = planet.Satellites[0].Metabase.SegmentLoop.Join(ctx, obs) 48 require.NoError(t, err) 49 50 // Confirm the correct number of shares were stored 51 rs := satelliteRS(t, planet.Satellites[0]) 52 if !correctRedundencyScheme(len(obs.Node), rs) { 53 t.Fatalf("expected between: %d and %d, actual: %d", rs.RepairShares, rs.TotalShares, len(obs.Node)) 54 } 55 56 // Confirm the correct number of bytes were stored on each node 57 for _, actualTotalBytes := range obs.Node { 58 assert.Equal(t, expectedTotalBytes, int64(actualTotalBytes)) 59 } 60 }) 61} 62 63func correctRedundencyScheme(shareCount int, uplinkRS storj.RedundancyScheme) bool { 64 // The shareCount should be a value between RequiredShares and TotalShares where 65 // RequiredShares is the min number of shares required to recover a segment and 66 // TotalShares is the number of shares to encode 67 return int(uplinkRS.RepairShares) <= shareCount && shareCount <= int(uplinkRS.TotalShares) 68} 69 70func satelliteRS(t *testing.T, satellite *testplanet.Satellite) storj.RedundancyScheme { 71 rs := satellite.Config.Metainfo.RS 72 73 return storj.RedundancyScheme{ 74 RequiredShares: int16(rs.Min), 75 RepairShares: int16(rs.Repair), 76 OptimalShares: int16(rs.Success), 77 TotalShares: int16(rs.Total), 78 ShareSize: rs.ErasureShareSize.Int32(), 79 } 80} 81