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 }