github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/common/ledger/blkstorage/blockfile_helper_test.go (about)

     1  /*
     2  Copyright hechain. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package blkstorage
     8  
     9  import (
    10  	"fmt"
    11  	"io/ioutil"
    12  	"os"
    13  	"path/filepath"
    14  	"testing"
    15  
    16  	"github.com/golang/protobuf/proto"
    17  	"github.com/hechain20/hechain/common/ledger/testutil"
    18  	"github.com/stretchr/testify/require"
    19  )
    20  
    21  func TestConstructBlockfilesInfo(t *testing.T) {
    22  	ledgerid := "testLedger"
    23  	conf := NewConf(testPath(), 0)
    24  	blkStoreDir := conf.getLedgerBlockDir(ledgerid)
    25  	env := newTestEnv(t, conf)
    26  	require.NoError(t, os.MkdirAll(blkStoreDir, 0o755))
    27  	defer env.Cleanup()
    28  
    29  	// constructBlockfilesInfo on an empty block folder should return blockfileInfo with noBlockFiles: true
    30  	blkfilesInfo, err := constructBlockfilesInfo(blkStoreDir)
    31  	require.NoError(t, err)
    32  	require.Equal(t,
    33  		&blockfilesInfo{
    34  			noBlockFiles:       true,
    35  			lastPersistedBlock: 0,
    36  			latestFileSize:     0,
    37  			latestFileNumber:   0,
    38  		},
    39  		blkfilesInfo,
    40  	)
    41  
    42  	w := newTestBlockfileWrapper(env, ledgerid)
    43  	defer w.close()
    44  	blockfileMgr := w.blockfileMgr
    45  	bg, gb := testutil.NewBlockGenerator(t, ledgerid, false)
    46  
    47  	// Add a few blocks and verify that blockfilesInfo derived from filesystem should be same as from the blockfile manager
    48  	blockfileMgr.addBlock(gb)
    49  	for _, blk := range bg.NextTestBlocks(3) {
    50  		blockfileMgr.addBlock(blk)
    51  	}
    52  	checkBlockfilesInfoFromFS(t, blkStoreDir, blockfileMgr.blockfilesInfo)
    53  
    54  	// Move the chain to new file and check blockfilesInfo derived from file system
    55  	blockfileMgr.moveToNextFile()
    56  	checkBlockfilesInfoFromFS(t, blkStoreDir, blockfileMgr.blockfilesInfo)
    57  
    58  	// Add a few blocks that would go to new file and verify that blockfilesInfo derived from filesystem should be same as from the blockfile manager
    59  	for _, blk := range bg.NextTestBlocks(3) {
    60  		blockfileMgr.addBlock(blk)
    61  	}
    62  	checkBlockfilesInfoFromFS(t, blkStoreDir, blockfileMgr.blockfilesInfo)
    63  
    64  	// Write a partial block (to simulate a crash) and verify that blockfilesInfo derived from filesystem should be same as from the blockfile manager
    65  	lastTestBlk := bg.NextTestBlocks(1)[0]
    66  	blockBytes, _, err := serializeBlock(lastTestBlk)
    67  	require.NoError(t, err)
    68  	partialByte := append(proto.EncodeVarint(uint64(len(blockBytes))), blockBytes[len(blockBytes)/2:]...)
    69  	blockfileMgr.currentFileWriter.append(partialByte, true)
    70  	checkBlockfilesInfoFromFS(t, blkStoreDir, blockfileMgr.blockfilesInfo)
    71  
    72  	// Close the block storage, drop the index and restart and verify
    73  	blkfilesInfoBeforeClose := blockfileMgr.blockfilesInfo
    74  	w.close()
    75  	env.provider.Close()
    76  	indexFolder := conf.getIndexDir()
    77  	require.NoError(t, os.RemoveAll(indexFolder))
    78  
    79  	env = newTestEnv(t, conf)
    80  	w = newTestBlockfileWrapper(env, ledgerid)
    81  	blockfileMgr = w.blockfileMgr
    82  	require.Equal(t, blkfilesInfoBeforeClose, blockfileMgr.blockfilesInfo)
    83  
    84  	lastBlkIndexed, err := blockfileMgr.index.getLastBlockIndexed()
    85  	require.NoError(t, err)
    86  	require.Equal(t, uint64(6), lastBlkIndexed)
    87  
    88  	// Add the last block again after start and check blockfilesInfo again
    89  	require.NoError(t, blockfileMgr.addBlock(lastTestBlk))
    90  	checkBlockfilesInfoFromFS(t, blkStoreDir, blockfileMgr.blockfilesInfo)
    91  }
    92  
    93  func TestBinarySearchBlockFileNum(t *testing.T) {
    94  	blockStoreRootDir := testPath()
    95  	blocks := testutil.ConstructTestBlocks(t, 100)
    96  	maxFileSie := int(0.1 * float64(testutilEstimateTotalSizeOnDisk(t, blocks)))
    97  	env := newTestEnv(t, NewConf(blockStoreRootDir, maxFileSie))
    98  	defer env.Cleanup()
    99  	blkfileMgrWrapper := newTestBlockfileWrapper(env, "testLedger")
   100  	blkfileMgr := blkfileMgrWrapper.blockfileMgr
   101  
   102  	blkfileMgrWrapper.addBlocks(blocks)
   103  
   104  	ledgerDir := (&Conf{blockStorageDir: blockStoreRootDir}).getLedgerBlockDir("testLedger")
   105  	files, err := ioutil.ReadDir(ledgerDir)
   106  	require.NoError(t, err)
   107  	require.Len(t, files, 11)
   108  
   109  	for i := uint64(0); i < 100; i++ {
   110  		fileNum, err := binarySearchFileNumForBlock(ledgerDir, i)
   111  		require.NoError(t, err)
   112  		locFromIndex, err := blkfileMgr.index.getBlockLocByBlockNum(i)
   113  		require.NoError(t, err)
   114  		expectedFileNum := locFromIndex.fileSuffixNum
   115  		require.Equal(t, expectedFileNum, fileNum)
   116  	}
   117  }
   118  
   119  func TestIsBootstrappedFromSnapshot(t *testing.T) {
   120  	testDir, err := ioutil.TempDir("", "isbootstrappedfromsnapshot")
   121  	require.NoError(t, err)
   122  	defer os.RemoveAll(testDir)
   123  
   124  	t.Run("no_bootstrapping_snapshot_info_file", func(t *testing.T) {
   125  		// create chains directory for the ledger without bootstrappingSnapshotInfoFile
   126  		ledgerid := "testnosnapshotinfofile"
   127  		require.NoError(t, os.MkdirAll(filepath.Join(testDir, ChainsDir, ledgerid), 0o755))
   128  		isFromSnapshot, err := IsBootstrappedFromSnapshot(testDir, ledgerid)
   129  		require.NoError(t, err)
   130  		require.False(t, isFromSnapshot)
   131  	})
   132  
   133  	t.Run("with_bootstrapping_snapshot_info_file", func(t *testing.T) {
   134  		// create chains directory for the ledger with bootstrappingSnapshotInfoFile
   135  		ledgerid := "testwithsnapshotinfofile"
   136  		ledgerChainDir := filepath.Join(testDir, ChainsDir, ledgerid)
   137  		require.NoError(t, os.MkdirAll(ledgerChainDir, 0o755))
   138  		file, err := os.Create(filepath.Join(ledgerChainDir, bootstrappingSnapshotInfoFile))
   139  		require.NoError(t, err)
   140  		defer file.Close()
   141  		isFromSnapshot, err := IsBootstrappedFromSnapshot(testDir, ledgerid)
   142  		require.NoError(t, err)
   143  		require.True(t, isFromSnapshot)
   144  	})
   145  }
   146  
   147  func TestGetLedgersBootstrappedFromSnapshot(t *testing.T) {
   148  	t.Run("no_bootstrapping_snapshot_info_file", func(t *testing.T) {
   149  		testDir, err := ioutil.TempDir("", "getledgersfromsnapshot_nosnapshot_info")
   150  		require.NoError(t, err)
   151  		defer os.RemoveAll(testDir)
   152  
   153  		// create chains directories for ledgers without bootstrappingSnapshotInfoFile
   154  		for i := 0; i < 5; i++ {
   155  			require.NoError(t, os.MkdirAll(filepath.Join(testDir, ChainsDir, fmt.Sprintf("ledger_%d", i)), 0o755))
   156  		}
   157  
   158  		ledgersFromSnapshot, err := GetLedgersBootstrappedFromSnapshot(testDir)
   159  		require.NoError(t, err)
   160  		require.Equal(t, 0, len(ledgersFromSnapshot))
   161  	})
   162  
   163  	t.Run("with_bootstrapping_snapshot_info_file", func(t *testing.T) {
   164  		testDir, err := ioutil.TempDir("", "getledgersfromsnapshot_snapshot_info")
   165  		require.NoError(t, err)
   166  		defer os.RemoveAll(testDir)
   167  
   168  		// create chains directories for ledgers
   169  		// also create bootstrappingSnapshotInfoFile for ledger_0 and ledger_1
   170  		for i := 0; i < 5; i++ {
   171  			ledgerChainDir := filepath.Join(testDir, ChainsDir, fmt.Sprintf("ledger_%d", i))
   172  			require.NoError(t, os.MkdirAll(ledgerChainDir, 0o755))
   173  			if i < 2 {
   174  				file, err := os.Create(filepath.Join(ledgerChainDir, bootstrappingSnapshotInfoFile))
   175  				require.NoError(t, err)
   176  				defer file.Close()
   177  			}
   178  		}
   179  
   180  		ledgersFromSnapshot, err := GetLedgersBootstrappedFromSnapshot(testDir)
   181  		require.NoError(t, err)
   182  		require.ElementsMatch(t, ledgersFromSnapshot, []string{"ledger_0", "ledger_1"})
   183  	})
   184  }
   185  
   186  func checkBlockfilesInfoFromFS(t *testing.T, blkStoreDir string, expected *blockfilesInfo) {
   187  	blkfilesInfo, err := constructBlockfilesInfo(blkStoreDir)
   188  	require.NoError(t, err)
   189  	require.Equal(t, expected, blkfilesInfo)
   190  }