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