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 }