github.com/osdi23p228/fabric@v0.0.0-20221218062954-77808885f5db/common/ledger/snapshot/file_test.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package snapshot 8 9 import ( 10 "bufio" 11 "crypto/sha256" 12 "errors" 13 "hash" 14 "io/ioutil" 15 "os" 16 "path" 17 "testing" 18 19 "github.com/golang/protobuf/proto" 20 "github.com/hyperledger/fabric-protos-go/common" 21 "github.com/stretchr/testify/require" 22 ) 23 24 var ( 25 testNewHashFunc = func() (hash.Hash, error) { 26 return sha256.New(), nil 27 } 28 ) 29 30 func TestFileCreateAndRead(t *testing.T) { 31 testDir := testPath(t) 32 defer os.RemoveAll(testDir) 33 34 // create file and encode some data 35 fileCreator, err := CreateFile(path.Join(testDir, "dataFile"), byte(5), testNewHashFunc) 36 require.NoError(t, err) 37 defer fileCreator.Close() 38 39 require.NoError(t, fileCreator.EncodeString("Hi there")) 40 require.NoError(t, fileCreator.EncodeString("How are you?")) 41 require.NoError(t, fileCreator.EncodeString("")) // zreo length string 42 require.NoError(t, fileCreator.EncodeUVarint(uint64(25))) 43 require.NoError(t, fileCreator.EncodeProtoMessage( 44 &common.BlockchainInfo{ 45 Height: 30, 46 CurrentBlockHash: []byte("Current-Block-Hash"), 47 PreviousBlockHash: []byte("Previous-Block-Hash"), 48 }, 49 )) 50 require.NoError(t, fileCreator.EncodeBytes([]byte("some junk bytes"))) 51 require.NoError(t, fileCreator.EncodeBytes([]byte{})) // zreo length slice 52 53 // Done and verify the returned hash 54 dataHash, err := fileCreator.Done() 55 require.NoError(t, err) 56 require.Equal( 57 t, 58 dataHash, 59 computeSha256(t, path.Join(testDir, "dataFile")), 60 ) 61 62 // open the file and verify the reads 63 fileReader, err := OpenFile(path.Join(testDir, "dataFile"), byte(5)) 64 require.NoError(t, err) 65 defer fileReader.Close() 66 67 str, err := fileReader.DecodeString() 68 require.NoError(t, err) 69 require.Equal(t, "Hi there", str) 70 71 str, err = fileReader.DecodeString() 72 require.NoError(t, err) 73 require.Equal(t, "How are you?", str) 74 75 str, err = fileReader.DecodeString() 76 require.NoError(t, err) 77 require.Equal(t, "", str) 78 79 number, err := fileReader.DecodeUVarInt() 80 require.NoError(t, err) 81 require.Equal(t, uint64(25), number) 82 83 retrievedBlockchainInfo := &common.BlockchainInfo{} 84 require.NoError(t, fileReader.DecodeProtoMessage(retrievedBlockchainInfo)) 85 require.True(t, proto.Equal( 86 &common.BlockchainInfo{ 87 Height: 30, 88 CurrentBlockHash: []byte("Current-Block-Hash"), 89 PreviousBlockHash: []byte("Previous-Block-Hash"), 90 }, 91 retrievedBlockchainInfo, 92 )) 93 94 b, err := fileReader.DecodeBytes() 95 require.NoError(t, err) 96 require.Equal(t, []byte("some junk bytes"), b) 97 98 b, err = fileReader.DecodeBytes() 99 require.NoError(t, err) 100 require.Equal(t, []byte{}, b) 101 } 102 103 func TestFileCreatorErrorPropagation(t *testing.T) { 104 testPath := testPath(t) 105 defer os.RemoveAll(testPath) 106 107 // error propagation from CreateFile function when file already exists 108 existingFilePath := path.Join(testPath, "an-existing-file") 109 file, err := os.Create(existingFilePath) 110 require.NoError(t, err) 111 require.NoError(t, file.Close()) 112 _, err = CreateFile(existingFilePath, byte(1), testNewHashFunc) 113 require.Contains(t, err.Error(), "error while creating the snapshot file: "+existingFilePath) 114 115 // error propagation from Encode functions. 116 // Mimic the errors by setting the writer to an error returning writer 117 dataFilePath := path.Join(testPath, "data-file") 118 fileCreator, err := CreateFile(dataFilePath, byte(1), testNewHashFunc) 119 require.NoError(t, err) 120 defer fileCreator.Close() 121 122 fileCreator.multiWriter = &errorCausingWriter{err: errors.New("error-from-EncodeUVarint")} 123 require.EqualError(t, fileCreator.EncodeUVarint(9), "error while writing data to the snapshot file: "+dataFilePath+": error-from-EncodeUVarint") 124 125 fileCreator.multiWriter = &errorCausingWriter{err: errors.New("error-from-EncodeBytes")} 126 require.EqualError(t, fileCreator.EncodeBytes([]byte("junk")), "error while writing data to the snapshot file: "+dataFilePath+": error-from-EncodeBytes") 127 128 fileCreator.multiWriter = &errorCausingWriter{err: errors.New("error-from-EncodeProtoMessage")} 129 require.EqualError(t, fileCreator.EncodeProtoMessage(&common.BlockchainInfo{}), "error while writing data to the snapshot file: "+dataFilePath+": error-from-EncodeProtoMessage") 130 require.EqualError(t, fileCreator.EncodeProtoMessage(nil), "error marshalling proto message to write to the snapshot file: "+dataFilePath+": proto: Marshal called with nil") 131 132 fileCreator.multiWriter = &errorCausingWriter{err: errors.New("error-from-EncodeString")} 133 require.EqualError(t, fileCreator.EncodeString("junk"), "error while writing data to the snapshot file: "+dataFilePath+": error-from-EncodeString") 134 135 // error propagation from Done function 136 fileCreator.file.Close() 137 _, err = fileCreator.Done() 138 require.Contains(t, err.Error(), "error while flushing to the snapshot file: "+dataFilePath) 139 140 // error propagation from Close function 141 require.Contains(t, fileCreator.Close().Error(), "error while closing the snapshot file: "+dataFilePath) 142 } 143 144 func TestFileReaderErrorPropagation(t *testing.T) { 145 testPath := testPath(t) 146 defer os.RemoveAll(testPath) 147 148 // non-existent-file cuases an error 149 nonExistentFile := path.Join(testPath, "non-existent-file") 150 _, err := OpenFile(nonExistentFile, byte(1)) 151 require.Contains(t, err.Error(), "error while opening the snapshot file: "+nonExistentFile) 152 153 // an empty-file causes an error 154 emptyFile := path.Join(testPath, "empty-file") 155 f, err := os.Create(emptyFile) 156 require.NoError(t, err) 157 f.Close() 158 emptyFileReader, err := OpenFile(emptyFile, byte(1)) 159 require.Contains(t, err.Error(), "error while reading from the snapshot file: "+emptyFile) 160 defer emptyFileReader.Close() 161 162 // a file with mismatched format info causes an error 163 unexpectedFormatFile := path.Join(testPath, "wrong-data-format-file") 164 fw, err := CreateFile(unexpectedFormatFile, byte(1), testNewHashFunc) 165 require.NoError(t, err) 166 require.NoError(t, fw.EncodeString("Hello there")) 167 _, err = fw.Done() 168 require.NoError(t, err) 169 unexpectedFormatFileReader, err := OpenFile(unexpectedFormatFile, byte(2)) 170 require.EqualError(t, err, "unexpected data format: 1") 171 defer unexpectedFormatFileReader.Close() 172 173 // decodeMethodsErrors - mimic errors by closing the underlying file 174 closedFile := path.Join(testPath, "closed-file") 175 f, err = os.Create(closedFile) 176 require.NoError(t, err) 177 require.NoError(t, f.Close()) 178 179 closedFileReader := &FileReader{ 180 file: f, 181 bufReader: bufio.NewReader(f), 182 } 183 _, err = closedFileReader.DecodeUVarInt() 184 require.Contains(t, err.Error(), "error while reading from snapshot file: "+closedFile) 185 _, err = closedFileReader.DecodeBytes() 186 require.Contains(t, err.Error(), "error while reading from snapshot file: "+closedFile) 187 _, err = closedFileReader.DecodeString() 188 require.Contains(t, err.Error(), "error while reading from snapshot file: "+closedFile) 189 err = closedFileReader.DecodeProtoMessage(&common.BlockchainInfo{}) 190 require.Contains(t, err.Error(), "error while reading from snapshot file: "+closedFile) 191 err = closedFileReader.Close() 192 require.Contains(t, err.Error(), "error while closing the snapshot file: "+closedFile) 193 } 194 195 func computeSha256(t *testing.T, file string) []byte { 196 data, err := ioutil.ReadFile(file) 197 require.NoError(t, err) 198 sha := sha256.Sum256(data) 199 return sha[:] 200 } 201 202 func testPath(t *testing.T) string { 203 path, err := ioutil.TempDir("", "test-file-encoder-") 204 require.NoError(t, err) 205 return path 206 } 207 208 type errorCausingWriter struct { 209 err error 210 } 211 212 func (w *errorCausingWriter) Write(p []byte) (n int, err error) { return 0, w.err }