storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/cmd/erasure_test.go (about) 1 /* 2 * MinIO Cloud Storage, (C) 2016-2020 MinIO, Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package cmd 18 19 import ( 20 "bytes" 21 "context" 22 "crypto/rand" 23 "io" 24 "os" 25 "testing" 26 ) 27 28 var erasureEncodeDecodeTests = []struct { 29 dataBlocks, parityBlocks int 30 missingData, missingParity int 31 reconstructParity bool 32 shouldFail bool 33 }{ 34 {dataBlocks: 2, parityBlocks: 2, missingData: 0, missingParity: 0, reconstructParity: true, shouldFail: false}, 35 {dataBlocks: 3, parityBlocks: 3, missingData: 1, missingParity: 0, reconstructParity: true, shouldFail: false}, 36 {dataBlocks: 4, parityBlocks: 4, missingData: 2, missingParity: 0, reconstructParity: false, shouldFail: false}, 37 {dataBlocks: 5, parityBlocks: 5, missingData: 0, missingParity: 1, reconstructParity: true, shouldFail: false}, 38 {dataBlocks: 6, parityBlocks: 6, missingData: 0, missingParity: 2, reconstructParity: true, shouldFail: false}, 39 {dataBlocks: 7, parityBlocks: 7, missingData: 1, missingParity: 1, reconstructParity: false, shouldFail: false}, 40 {dataBlocks: 8, parityBlocks: 8, missingData: 3, missingParity: 2, reconstructParity: false, shouldFail: false}, 41 {dataBlocks: 2, parityBlocks: 2, missingData: 2, missingParity: 1, reconstructParity: true, shouldFail: true}, 42 {dataBlocks: 4, parityBlocks: 2, missingData: 2, missingParity: 2, reconstructParity: false, shouldFail: true}, 43 {dataBlocks: 8, parityBlocks: 4, missingData: 2, missingParity: 2, reconstructParity: false, shouldFail: false}, 44 } 45 46 func TestErasureEncodeDecode(t *testing.T) { 47 data := make([]byte, 256) 48 if _, err := io.ReadFull(rand.Reader, data); err != nil { 49 t.Fatalf("Failed to read random data: %v", err) 50 } 51 for i, test := range erasureEncodeDecodeTests { 52 buffer := make([]byte, len(data), 2*len(data)) 53 copy(buffer, data) 54 55 erasure, err := NewErasure(context.Background(), test.dataBlocks, test.parityBlocks, blockSizeV2) 56 if err != nil { 57 t.Fatalf("Test %d: failed to create erasure: %v", i, err) 58 } 59 encoded, err := erasure.EncodeData(context.Background(), buffer) 60 if err != nil { 61 t.Fatalf("Test %d: failed to encode data: %v", i, err) 62 } 63 64 for j := range encoded[:test.missingData] { 65 encoded[j] = nil 66 } 67 for j := test.dataBlocks; j < test.dataBlocks+test.missingParity; j++ { 68 encoded[j] = nil 69 } 70 71 if test.reconstructParity { 72 err = erasure.DecodeDataAndParityBlocks(context.Background(), encoded) 73 } else { 74 err = erasure.DecodeDataBlocks(encoded) 75 } 76 77 if err == nil && test.shouldFail { 78 t.Errorf("Test %d: test should fail but it passed", i) 79 } 80 if err != nil && !test.shouldFail { 81 t.Errorf("Test %d: test should pass but it failed: %v", i, err) 82 } 83 84 decoded := encoded 85 if !test.shouldFail { 86 if test.reconstructParity { 87 for j := range decoded { 88 if decoded[j] == nil { 89 t.Errorf("Test %d: failed to reconstruct shard %d", i, j) 90 } 91 } 92 } else { 93 for j := range decoded[:test.dataBlocks] { 94 if decoded[j] == nil { 95 t.Errorf("Test %d: failed to reconstruct data shard %d", i, j) 96 } 97 } 98 } 99 100 decodedData := new(bytes.Buffer) 101 if _, err = writeDataBlocks(context.Background(), decodedData, decoded, test.dataBlocks, 0, int64(len(data))); err != nil { 102 t.Errorf("Test %d: failed to write data blocks: %v", i, err) 103 } 104 if !bytes.Equal(decodedData.Bytes(), data) { 105 t.Errorf("Test %d: Decoded data does not match original data: got: %v want: %v", i, decodedData.Bytes(), data) 106 } 107 } 108 } 109 } 110 111 // Setup for erasureCreateFile and erasureReadFile tests. 112 type erasureTestSetup struct { 113 dataBlocks int 114 parityBlocks int 115 blockSize int64 116 diskPaths []string 117 disks []StorageAPI 118 } 119 120 // Removes the temporary disk directories. 121 func (e erasureTestSetup) Remove() { 122 for _, path := range e.diskPaths { 123 os.RemoveAll(path) 124 } 125 } 126 127 // Returns an initialized setup for erasure tests. 128 func newErasureTestSetup(dataBlocks int, parityBlocks int, blockSize int64) (*erasureTestSetup, error) { 129 diskPaths := make([]string, dataBlocks+parityBlocks) 130 disks := make([]StorageAPI, len(diskPaths)) 131 var err error 132 for i := range diskPaths { 133 disks[i], diskPaths[i], err = newXLStorageTestSetup() 134 if err != nil { 135 return nil, err 136 } 137 err = disks[i].MakeVol(context.Background(), "testbucket") 138 if err != nil { 139 return nil, err 140 } 141 } 142 return &erasureTestSetup{dataBlocks, parityBlocks, blockSize, diskPaths, disks}, nil 143 }