github.com/uber/kraken@v0.1.4/core/metainfo_test.go (about) 1 // Copyright (c) 2016-2019 Uber Technologies, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 package core 15 16 import ( 17 "math/rand" 18 "testing" 19 20 "github.com/stretchr/testify/require" 21 22 "github.com/uber/kraken/utils/memsize" 23 ) 24 25 func TestMetaInfoGetPieceLength(t *testing.T) { 26 tests := []struct { 27 desc string 28 size uint64 29 pieceLength uint64 30 i int 31 expected int64 32 }{ 33 {"first piece", 10, 3, 0, 3}, 34 {"smaller last piece", 10, 3, 3, 1}, 35 {"same size last piece", 8, 2, 3, 2}, 36 {"middle piece", 10, 3, 1, 3}, 37 {"outside bounds", 10, 3, 4, 0}, 38 {"negative", 10, 3, -1, 0}, 39 } 40 for _, test := range tests { 41 t.Run(test.desc, func(t *testing.T) { 42 blob := SizedBlobFixture(test.size, test.pieceLength) 43 require.Equal(t, test.expected, blob.MetaInfo.GetPieceLength(test.i)) 44 }) 45 } 46 } 47 48 func TestMetaInfoSerialization(t *testing.T) { 49 require := require.New(t) 50 51 blob := NewBlobFixture() 52 53 b, err := blob.MetaInfo.Serialize() 54 require.NoError(err) 55 result, err := DeserializeMetaInfo(b) 56 require.NoError(err) 57 require.Equal(blob.Digest, result.Digest()) 58 require.Equal(blob.MetaInfo.InfoHash(), result.InfoHash()) 59 } 60 61 func TestMetaInfoBackwardsCompatibility(t *testing.T) { 62 require := require.New(t) 63 64 // This metainfo / hash pair was taken from a production agent. It should 65 // be deserializable by the new logic and produce the same info hash. 66 // TODO(codyg): This test can be removed once this change is fully rolled 67 // out. 68 rawMetaInfo := `{"Info":{"PieceLength":4194304,"PieceSums":[2131691452],"Name":"289314c356bc2a19802c3e31505506db30ea81a0bcaea4ec3e079524c8ac3cf5","Length":236},"Announce":"","AnnounceList":null,"CreationDate":0,"Comment":"","CreatedBy":""}` 69 70 expectedInfoHash, err := NewInfoHashFromHex("85b978c4377625b3963df406d0dd3a1da5a7d9c3") 71 require.NoError(err) 72 73 result, err := DeserializeMetaInfo([]byte(rawMetaInfo)) 74 require.NoError(err) 75 require.Equal(expectedInfoHash, result.InfoHash()) 76 } 77 78 func TestMetaInfoSerializationLimit(t *testing.T) { 79 80 // MetaInfo is stored as raw bytes as a Redis value, and should stay 81 // within the limits of the value. Because the number of pieces in a 82 // torrent is variable, this test serves as a sanity check that reasonable 83 // blob size / piece length combinations can be safely serialized. 84 var redisValueLimit = 512 * memsize.MB 85 86 tests := []struct { 87 description string 88 blobSize uint64 89 pieceLength uint64 90 }{ 91 {"reasonable default", 2 * memsize.GB, 2 * memsize.MB}, 92 {"large file", 100 * memsize.GB, 2 * memsize.MB}, 93 {"tiny pieces", 2 * memsize.GB, 4 * memsize.KB}, 94 } 95 for _, test := range tests { 96 t.Run(test.description, func(t *testing.T) { 97 require := require.New(t) 98 99 numPieces := test.blobSize / test.pieceLength 100 pieceSums := make([]uint32, numPieces) 101 for i := range pieceSums { 102 pieceSums[i] = rand.Uint32() 103 } 104 105 mi := MetaInfo{ 106 info: info{ 107 PieceLength: int64(test.pieceLength), 108 PieceSums: pieceSums, 109 Name: "6422b52513a39399598494bdb7471211890cd13c271fb5c11c5ba6538ed7578c", 110 Length: int64(test.blobSize), 111 }, 112 } 113 b, err := mi.Serialize() 114 require.NoError(err) 115 size := uint64(len(b)) 116 require.True(size < redisValueLimit, 117 "%d piece serialization %d bytes too large", numPieces, size-redisValueLimit) 118 }) 119 } 120 }