github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/common/ledger/blockledger/fileledger/factory_test.go (about)

     1  /*
     2  Copyright hechain. 2022 All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package fileledger
     8  
     9  import (
    10  	"errors"
    11  	"fmt"
    12  	"io/ioutil"
    13  	"os"
    14  	"path/filepath"
    15  	"testing"
    16  
    17  	"github.com/hechain20/hechain/common/ledger/blockledger/fileledger/mock"
    18  	"github.com/hechain20/hechain/common/metrics/disabled"
    19  	"github.com/hechain20/hechain/orderer/common/filerepo"
    20  	"github.com/stretchr/testify/require"
    21  )
    22  
    23  //go:generate counterfeiter -o mock/file_ledger_block_store.go --fake-name FileLedgerBlockStore . fileLedgerBlockStore
    24  
    25  type fileLedgerBlockStore interface {
    26  	FileLedgerBlockStore
    27  }
    28  
    29  func TestBlockStoreProviderErrors(t *testing.T) {
    30  	setup := func(fileRepo *filerepo.Repo) (*fileLedgerFactory, *mock.BlockStoreProvider) {
    31  		m := &mock.BlockStoreProvider{}
    32  
    33  		f := &fileLedgerFactory{
    34  			blkstorageProvider: m,
    35  			ledgers:            map[string]*FileLedger{},
    36  			removeFileRepo:     fileRepo,
    37  		}
    38  		return f, m
    39  	}
    40  
    41  	t.Run("list", func(t *testing.T) {
    42  		f, mockBlockStoreProvider := setup(nil)
    43  		mockBlockStoreProvider.ListReturns(nil, errors.New("boogie"))
    44  		require.PanicsWithValue(
    45  			t,
    46  			"boogie",
    47  			func() { f.ChannelIDs() },
    48  			"Expected ChannelIDs to panic if storage provider cannot list channel IDs",
    49  		)
    50  	})
    51  
    52  	t.Run("open", func(t *testing.T) {
    53  		f, mockBlockStoreProvider := setup(nil)
    54  		mockBlockStoreProvider.OpenReturns(nil, errors.New("woogie"))
    55  		_, err := f.GetOrCreate("foo")
    56  		require.EqualError(t, err, "woogie")
    57  		require.Empty(t, f.ledgers, "Expected no new ledger is created")
    58  	})
    59  
    60  	t.Run("remove", func(t *testing.T) {
    61  		dir, err := ioutil.TempDir("", "fileledger")
    62  		require.NoError(t, err, "Error creating temp dir: %s", err)
    63  		defer os.RemoveAll(dir)
    64  		fileRepo, err := filerepo.New(filepath.Join(dir, "pendingops"), "remove")
    65  		require.NoError(t, err, "Error creating temp file repo: %s", err)
    66  
    67  		t.Run("ledger doesn't exist", func(t *testing.T) {
    68  			f, mockBlockStoreProvider := setup(fileRepo)
    69  			err := f.Remove("foo")
    70  			require.NoError(t, err)
    71  			require.Equal(t, 1, mockBlockStoreProvider.DropCallCount())
    72  			channelID := mockBlockStoreProvider.DropArgsForCall(0)
    73  			require.Equal(t, "foo", channelID)
    74  		})
    75  
    76  		t.Run("dropping the blockstore fails", func(t *testing.T) {
    77  			f, mockBlockStoreProvider := setup(fileRepo)
    78  			mockBlockStore := &mock.FileLedgerBlockStore{}
    79  			f.ledgers["bar"] = &FileLedger{blockStore: mockBlockStore}
    80  			mockBlockStoreProvider.DropReturns(errors.New("oogie"))
    81  
    82  			err := f.Remove("bar")
    83  			require.EqualError(t, err, "oogie")
    84  			require.Equal(t, 1, mockBlockStore.ShutdownCallCount())
    85  			require.Equal(t, 1, mockBlockStoreProvider.DropCallCount())
    86  			channelID := mockBlockStoreProvider.DropArgsForCall(0)
    87  			require.Equal(t, "bar", channelID)
    88  		})
    89  	})
    90  }
    91  
    92  func TestMultiReinitialization(t *testing.T) {
    93  	metricsProvider := &disabled.Provider{}
    94  
    95  	dir, err := ioutil.TempDir("", "fileledger")
    96  	require.NoError(t, err, "Error creating temp dir: %s", err)
    97  	defer os.RemoveAll(dir)
    98  
    99  	f, err := New(dir, metricsProvider)
   100  	require.NoError(t, err)
   101  	_, err = f.GetOrCreate("testchannelid")
   102  	require.NoError(t, err, "Error GetOrCreate channel")
   103  	require.Equal(t, 1, len(f.ChannelIDs()), "Expected 1 channel")
   104  	f.Close()
   105  
   106  	f, err = New(dir, metricsProvider)
   107  	require.NoError(t, err)
   108  	_, err = f.GetOrCreate("foo")
   109  	require.NoError(t, err, "Error creating channel")
   110  	require.Equal(t, 2, len(f.ChannelIDs()), "Expected channel to be recovered")
   111  	f.Close()
   112  
   113  	f, err = New(dir, metricsProvider)
   114  	require.NoError(t, err)
   115  	_, err = f.GetOrCreate("bar")
   116  	require.NoError(t, err, "Error creating channel")
   117  	require.Equal(t, 3, len(f.ChannelIDs()), "Expected channel to be recovered")
   118  	f.Close()
   119  
   120  	bar2FileRepoDir := filepath.Join(dir, "pendingops", "remove", "bar2.remove")
   121  	_, err = os.Create(bar2FileRepoDir)
   122  	require.NoError(t, err, "Error creating temp file: %s", err)
   123  
   124  	bar2ChainsDir := filepath.Join(dir, "chains", "bar2")
   125  	err = os.MkdirAll(bar2ChainsDir, 0o700)
   126  	require.NoError(t, err, "Error creating temp dir: %s", err)
   127  	_, err = os.Create(filepath.Join(bar2ChainsDir, "blockfile_000000"))
   128  	require.NoError(t, err, "Error creating temp file: %s", err)
   129  
   130  	f, err = New(dir, metricsProvider)
   131  	require.NoError(t, err)
   132  
   133  	err = f.Remove("bar")
   134  	require.NoError(t, err, "Error removing channel")
   135  	require.Equal(t, 2, len(f.ChannelIDs()))
   136  	err = f.Remove("this-isnt-an-existing-channel")
   137  	require.NoError(t, err, "Error removing channel")
   138  	require.Equal(t, 2, len(f.ChannelIDs()))
   139  
   140  	_, err = os.Stat(bar2ChainsDir)
   141  	require.EqualError(t, err, fmt.Sprintf("stat %s: no such file or directory", bar2ChainsDir))
   142  
   143  	_, err = os.Stat(bar2FileRepoDir)
   144  	require.EqualError(t, err, fmt.Sprintf("stat %s: no such file or directory", bar2FileRepoDir))
   145  	f.Close()
   146  }
   147  
   148  func TestNewErrors(t *testing.T) {
   149  	metricsProvider := &disabled.Provider{}
   150  
   151  	t.Run("creation of filerepo fails", func(t *testing.T) {
   152  		dir, err := ioutil.TempDir("", "fileledger")
   153  		require.NoError(t, err, "Error creating temp dir: %s", err)
   154  		defer os.RemoveAll(dir)
   155  
   156  		fileRepoDir := filepath.Join(dir, "pendingops", "remove")
   157  		err = os.MkdirAll(fileRepoDir, 0o700)
   158  		require.NoError(t, err, "Error creating temp dir: %s", err)
   159  		removeFile := filepath.Join(fileRepoDir, "rojo.remove")
   160  		_, err = os.Create(removeFile)
   161  		require.NoError(t, err, "Error creating temp file: %s", err)
   162  		err = os.Chmod(removeFile, 0o444)
   163  		require.NoError(t, err, "Error changing permissions of temp file: %s", err)
   164  		err = os.Chmod(filepath.Join(dir, "pendingops", "remove"), 0o444)
   165  		require.NoError(t, err, "Error changing permissions of temp file: %s", err)
   166  
   167  		_, err = New(dir, metricsProvider)
   168  		require.EqualError(t, err, fmt.Sprintf("error checking if dir [%s] is empty: lstat %s: permission denied", fileRepoDir, removeFile))
   169  	})
   170  
   171  	t.Run("removal fails", func(t *testing.T) {
   172  		dir, err := ioutil.TempDir("", "fileledger")
   173  		require.NoError(t, err, "Error creating temp dir: %s", err)
   174  		defer os.RemoveAll(dir)
   175  
   176  		fileRepoDir := filepath.Join(dir, "pendingops", "remove")
   177  		err = os.MkdirAll(fileRepoDir, 0o777)
   178  		require.NoError(t, err, "Error creating temp dir: %s", err)
   179  		removeFile := filepath.Join(fileRepoDir, "rojo.remove")
   180  		_, err = os.Create(removeFile)
   181  		require.NoError(t, err, "Error creating temp file: %s", err)
   182  		err = os.Chmod(removeFile, 0o444)
   183  		require.NoError(t, err, "Error changing permissions of temp file: %s", err)
   184  		err = os.Chmod(filepath.Join(dir, "pendingops", "remove"), 0o544)
   185  		require.NoError(t, err, "Error changing permissions of temp file: %s", err)
   186  
   187  		_, err = New(dir, metricsProvider)
   188  		require.EqualError(t, err, fmt.Sprintf("unlinkat %s: permission denied", removeFile))
   189  	})
   190  }
   191  
   192  func TestRemove(t *testing.T) {
   193  	mockBlockStore := &mock.BlockStoreProvider{}
   194  	dir, err := ioutil.TempDir("", "fileledger")
   195  	require.NoError(t, err, "Error creating temp dir: %s", err)
   196  	defer os.RemoveAll(dir)
   197  
   198  	fileRepo, err := filerepo.New(filepath.Join(dir, "pendingops"), "remove")
   199  	require.NoError(t, err, "Error creating temp file repo: %s", err)
   200  	f := &fileLedgerFactory{
   201  		blkstorageProvider: mockBlockStore,
   202  		ledgers:            map[string]*FileLedger{},
   203  		removeFileRepo:     fileRepo,
   204  	}
   205  	defer f.Close()
   206  
   207  	t.Run("success", func(t *testing.T) {
   208  		dest := filepath.Join(dir, "pendingops", "remove", "foo.remove")
   209  		mockBlockStore.DropCalls(func(string) error {
   210  			_, err = os.Stat(dest)
   211  			require.NoError(t, err, "Expected foo.remove to exist")
   212  			return nil
   213  		})
   214  		err = f.Remove("foo")
   215  		require.NoError(t, err, "Error removing channel")
   216  		require.Equal(t, 1, mockBlockStore.DropCallCount(), "Expected 1 Drop() calls")
   217  
   218  		_, err = os.Stat(dest)
   219  		require.EqualError(t, err, fmt.Sprintf("stat %s: no such file or directory", dest))
   220  	})
   221  
   222  	t.Run("drop fails", func(t *testing.T) {
   223  		mockBlockStore.DropReturns(errors.New("oogie"))
   224  		err = f.Remove("foo")
   225  		require.EqualError(t, err, "oogie")
   226  
   227  		dest := filepath.Join(dir, "pendingops", "remove", "foo.remove")
   228  		_, err = os.Stat(dest)
   229  		require.NoError(t, err, "Expected foo.remove to exist")
   230  	})
   231  
   232  	t.Run("saving to pending ops fails", func(t *testing.T) {
   233  		os.RemoveAll(dir)
   234  		mockBlockStore.DropReturns(nil)
   235  		err = f.Remove("foo")
   236  		require.EqualError(t, err, fmt.Sprintf("error while creating file:%s/pendingops/remove/foo.remove~: open %s/pendingops/remove/foo.remove~: no such file or directory", dir, dir))
   237  	})
   238  }