go_study/fabric-main/common/ledger/blockledger/fileledger/factory_test.go

236 lines
7.8 KiB
Go

/*
Copyright IBM Corp. 2016 All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package fileledger
import (
"errors"
"fmt"
"os"
"path/filepath"
"testing"
"github.com/hyperledger/fabric/common/ledger/blockledger/fileledger/mock"
"github.com/hyperledger/fabric/common/metrics/disabled"
"github.com/hyperledger/fabric/orderer/common/filerepo"
"github.com/stretchr/testify/require"
)
//go:generate counterfeiter -o mock/file_ledger_block_store.go --fake-name FileLedgerBlockStore . fileLedgerBlockStore
type fileLedgerBlockStore interface {
FileLedgerBlockStore
}
func TestBlockStoreProviderErrors(t *testing.T) {
setup := func(fileRepo *filerepo.Repo) (*fileLedgerFactory, *mock.BlockStoreProvider) {
m := &mock.BlockStoreProvider{}
f := &fileLedgerFactory{
blkstorageProvider: m,
ledgers: map[string]*FileLedger{},
removeFileRepo: fileRepo,
}
return f, m
}
t.Run("list", func(t *testing.T) {
f, mockBlockStoreProvider := setup(nil)
mockBlockStoreProvider.ListReturns(nil, errors.New("boogie"))
require.PanicsWithValue(
t,
"boogie",
func() { f.ChannelIDs() },
"Expected ChannelIDs to panic if storage provider cannot list channel IDs",
)
})
t.Run("open", func(t *testing.T) {
f, mockBlockStoreProvider := setup(nil)
mockBlockStoreProvider.OpenReturns(nil, errors.New("woogie"))
_, err := f.GetOrCreate("foo")
require.EqualError(t, err, "woogie")
require.Empty(t, f.ledgers, "Expected no new ledger is created")
})
t.Run("remove", func(t *testing.T) {
dir := t.TempDir()
fileRepo, err := filerepo.New(filepath.Join(dir, "pendingops"), "remove")
require.NoError(t, err, "Error creating temp file repo: %s", err)
t.Run("ledger doesn't exist", func(t *testing.T) {
f, mockBlockStoreProvider := setup(fileRepo)
err := f.Remove("foo")
require.NoError(t, err)
require.Equal(t, 1, mockBlockStoreProvider.DropCallCount())
channelID := mockBlockStoreProvider.DropArgsForCall(0)
require.Equal(t, "foo", channelID)
})
t.Run("dropping the blockstore fails", func(t *testing.T) {
f, mockBlockStoreProvider := setup(fileRepo)
mockBlockStore := &mock.FileLedgerBlockStore{}
f.ledgers["bar"] = &FileLedger{blockStore: mockBlockStore}
mockBlockStoreProvider.DropReturns(errors.New("oogie"))
err := f.Remove("bar")
require.EqualError(t, err, "oogie")
require.Equal(t, 1, mockBlockStore.ShutdownCallCount())
require.Equal(t, 1, mockBlockStoreProvider.DropCallCount())
channelID := mockBlockStoreProvider.DropArgsForCall(0)
require.Equal(t, "bar", channelID)
})
})
}
func TestMultiReinitialization(t *testing.T) {
metricsProvider := &disabled.Provider{}
dir := t.TempDir()
f, err := New(dir, metricsProvider)
require.NoError(t, err)
_, err = f.GetOrCreate("testchannelid")
require.NoError(t, err, "Error GetOrCreate channel")
require.Equal(t, 1, len(f.ChannelIDs()), "Expected 1 channel")
f.Close()
f, err = New(dir, metricsProvider)
require.NoError(t, err)
_, err = f.GetOrCreate("foo")
require.NoError(t, err, "Error creating channel")
require.Equal(t, 2, len(f.ChannelIDs()), "Expected channel to be recovered")
f.Close()
f, err = New(dir, metricsProvider)
require.NoError(t, err)
_, err = f.GetOrCreate("bar")
require.NoError(t, err, "Error creating channel")
require.Equal(t, 3, len(f.ChannelIDs()), "Expected channel to be recovered")
f.Close()
bar2FileRepoDir := filepath.Join(dir, "pendingops", "remove", "bar2.remove")
_, err = os.Create(bar2FileRepoDir)
require.NoError(t, err, "Error creating temp file: %s", err)
bar2ChainsDir := filepath.Join(dir, "chains", "bar2")
err = os.MkdirAll(bar2ChainsDir, 0o700)
require.NoError(t, err, "Error creating temp dir: %s", err)
_, err = os.Create(filepath.Join(bar2ChainsDir, "blockfile_000000"))
require.NoError(t, err, "Error creating temp file: %s", err)
f, err = New(dir, metricsProvider)
require.NoError(t, err)
err = f.Remove("bar")
require.NoError(t, err, "Error removing channel")
require.Equal(t, 2, len(f.ChannelIDs()))
err = f.Remove("this-isnt-an-existing-channel")
require.NoError(t, err, "Error removing channel")
require.Equal(t, 2, len(f.ChannelIDs()))
_, err = os.Stat(bar2ChainsDir)
require.EqualError(t, err, fmt.Sprintf("stat %s: no such file or directory", bar2ChainsDir))
_, err = os.Stat(bar2FileRepoDir)
require.EqualError(t, err, fmt.Sprintf("stat %s: no such file or directory", bar2FileRepoDir))
f.Close()
}
func TestNewErrors(t *testing.T) {
metricsProvider := &disabled.Provider{}
t.Run("creation of filerepo fails", func(t *testing.T) {
dir := t.TempDir()
fileRepoDir := filepath.Join(dir, "pendingops", "remove")
err := os.MkdirAll(fileRepoDir, 0o700)
require.NoError(t, err, "Error creating temp dir: %s", err)
removeFile := filepath.Join(fileRepoDir, "rojo.remove")
_, err = os.Create(removeFile)
require.NoError(t, err, "Error creating temp file: %s", err)
err = os.Chmod(removeFile, 0o444)
require.NoError(t, err, "Error changing permissions of temp file: %s", err)
err = os.Chmod(filepath.Join(dir, "pendingops", "remove"), 0o444)
require.NoError(t, err, "Error changing permissions of temp file: %s", err)
t.Cleanup(func() {
require.NoError(t, os.Chmod(filepath.Join(dir, "pendingops", "remove"), 0o777))
})
_, err = New(dir, metricsProvider)
require.EqualError(t, err, fmt.Sprintf("error checking if dir [%s] is empty: lstat %s: permission denied", fileRepoDir, removeFile))
})
t.Run("removal fails", func(t *testing.T) {
dir := t.TempDir()
fileRepoDir := filepath.Join(dir, "pendingops", "remove")
err := os.MkdirAll(fileRepoDir, 0o777)
require.NoError(t, err, "Error creating temp dir: %s", err)
removeFile := filepath.Join(fileRepoDir, "rojo.remove")
_, err = os.Create(removeFile)
require.NoError(t, err, "Error creating temp file: %s", err)
err = os.Chmod(removeFile, 0o444)
require.NoError(t, err, "Error changing permissions of temp file: %s", err)
err = os.Chmod(filepath.Join(dir, "pendingops", "remove"), 0o544)
require.NoError(t, err, "Error changing permissions of temp file: %s", err)
t.Cleanup(func() {
require.NoError(t, os.Chmod(filepath.Join(dir, "pendingops", "remove"), 0o777))
})
_, err = New(dir, metricsProvider)
require.EqualError(t, err, fmt.Sprintf("unlinkat %s: permission denied", removeFile))
})
}
func TestRemove(t *testing.T) {
mockBlockStore := &mock.BlockStoreProvider{}
dir := t.TempDir()
fileRepo, err := filerepo.New(filepath.Join(dir, "pendingops"), "remove")
require.NoError(t, err, "Error creating temp file repo: %s", err)
f := &fileLedgerFactory{
blkstorageProvider: mockBlockStore,
ledgers: map[string]*FileLedger{},
removeFileRepo: fileRepo,
}
defer f.Close()
t.Run("success", func(t *testing.T) {
dest := filepath.Join(dir, "pendingops", "remove", "foo.remove")
mockBlockStore.DropCalls(func(string) error {
_, err = os.Stat(dest)
require.NoError(t, err, "Expected foo.remove to exist")
return nil
})
err = f.Remove("foo")
require.NoError(t, err, "Error removing channel")
require.Equal(t, 1, mockBlockStore.DropCallCount(), "Expected 1 Drop() calls")
_, err = os.Stat(dest)
require.EqualError(t, err, fmt.Sprintf("stat %s: no such file or directory", dest))
})
t.Run("drop fails", func(t *testing.T) {
mockBlockStore.DropReturns(errors.New("oogie"))
err = f.Remove("foo")
require.EqualError(t, err, "oogie")
dest := filepath.Join(dir, "pendingops", "remove", "foo.remove")
_, err = os.Stat(dest)
require.NoError(t, err, "Expected foo.remove to exist")
})
t.Run("saving to pending ops fails", func(t *testing.T) {
os.RemoveAll(dir)
mockBlockStore.DropReturns(nil)
err = f.Remove("foo")
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))
})
}