github.com/true-sqn/fabric@v2.1.1+incompatible/core/ledger/kvledger/tests/env.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package tests
     8  
     9  import (
    10  	"io/ioutil"
    11  	"os"
    12  	"path/filepath"
    13  	"testing"
    14  
    15  	"github.com/hyperledger/fabric-protos-go/common"
    16  	"github.com/hyperledger/fabric-protos-go/peer"
    17  	"github.com/hyperledger/fabric/bccsp"
    18  	"github.com/hyperledger/fabric/bccsp/sw"
    19  	"github.com/hyperledger/fabric/common/ledger/blkstorage/fsblkstorage"
    20  	"github.com/hyperledger/fabric/common/ledger/util"
    21  	"github.com/hyperledger/fabric/common/metrics/disabled"
    22  	"github.com/hyperledger/fabric/core/chaincode/lifecycle"
    23  	"github.com/hyperledger/fabric/core/common/privdata"
    24  	"github.com/hyperledger/fabric/core/container/externalbuilder"
    25  	"github.com/hyperledger/fabric/core/ledger"
    26  	"github.com/hyperledger/fabric/core/ledger/kvledger"
    27  	"github.com/hyperledger/fabric/core/ledger/ledgermgmt"
    28  	corepeer "github.com/hyperledger/fabric/core/peer"
    29  	"github.com/hyperledger/fabric/core/scc/lscc"
    30  	"github.com/hyperledger/fabric/msp"
    31  	"github.com/hyperledger/fabric/msp/mgmt"
    32  	"github.com/hyperledger/fabric/protoutil"
    33  	"github.com/stretchr/testify/assert"
    34  )
    35  
    36  type rebuildable uint8
    37  
    38  const (
    39  	rebuildableStatedb       rebuildable = 1
    40  	rebuildableBlockIndex    rebuildable = 2
    41  	rebuildableConfigHistory rebuildable = 4
    42  	rebuildableHistoryDB     rebuildable = 8
    43  	rebuildableBookkeeper    rebuildable = 16
    44  )
    45  
    46  type env struct {
    47  	assert      *assert.Assertions
    48  	initializer *ledgermgmt.Initializer
    49  	ledgerMgr   *ledgermgmt.LedgerMgr
    50  }
    51  
    52  func newEnv(t *testing.T) *env {
    53  	cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
    54  	assert.NoError(t, err)
    55  	return newEnvWithInitializer(t, &ledgermgmt.Initializer{
    56  		Hasher: cryptoProvider,
    57  		EbMetadataProvider: &externalbuilder.MetadataProvider{
    58  			DurablePath: "testdata",
    59  		},
    60  	})
    61  }
    62  
    63  func newEnvWithInitializer(t *testing.T, initializer *ledgermgmt.Initializer) *env {
    64  	populateMissingsWithTestDefaults(t, initializer)
    65  
    66  	return &env{
    67  		assert:      assert.New(t),
    68  		initializer: initializer,
    69  	}
    70  }
    71  
    72  func (e *env) cleanup() {
    73  	if e.ledgerMgr != nil {
    74  		e.ledgerMgr.Close()
    75  	}
    76  	// Ignore RemoveAll error because when a test mounts a dir to a couchdb container,
    77  	// the mounted dir cannot be deleted in CI builds. This has no impact to CI because it gets a new VM for each build.
    78  	// When running the test locally (macOS and linux VM), the mounted dirs are deleted without any error.
    79  	os.RemoveAll(e.initializer.Config.RootFSPath)
    80  }
    81  
    82  func (e *env) closeAllLedgersAndDrop(flags rebuildable) {
    83  	if e.ledgerMgr != nil {
    84  		e.ledgerMgr.Close()
    85  	}
    86  	defer e.initLedgerMgmt()
    87  
    88  	if flags&rebuildableBlockIndex == rebuildableBlockIndex {
    89  		indexPath := e.getBlockIndexDBPath()
    90  		logger.Infof("Deleting blockstore indexdb path [%s]", indexPath)
    91  		e.verifyNonEmptyDirExists(indexPath)
    92  		e.assert.NoError(os.RemoveAll(indexPath))
    93  	}
    94  
    95  	if flags&rebuildableStatedb == rebuildableStatedb {
    96  		statedbPath := e.getLevelstateDBPath()
    97  		logger.Infof("Deleting statedb path [%s]", statedbPath)
    98  		e.verifyNonEmptyDirExists(statedbPath)
    99  		e.assert.NoError(os.RemoveAll(statedbPath))
   100  	}
   101  
   102  	if flags&rebuildableConfigHistory == rebuildableConfigHistory {
   103  		configHistoryPath := e.getConfigHistoryDBPath()
   104  		logger.Infof("Deleting configHistory db path [%s]", configHistoryPath)
   105  		e.verifyNonEmptyDirExists(configHistoryPath)
   106  		e.assert.NoError(os.RemoveAll(configHistoryPath))
   107  	}
   108  
   109  	if flags&rebuildableBookkeeper == rebuildableBookkeeper {
   110  		bookkeeperPath := e.getBookkeeperDBPath()
   111  		logger.Infof("Deleting bookkeeper db path [%s]", bookkeeperPath)
   112  		e.verifyNonEmptyDirExists(bookkeeperPath)
   113  		e.assert.NoError(os.RemoveAll(bookkeeperPath))
   114  	}
   115  
   116  	if flags&rebuildableHistoryDB == rebuildableHistoryDB {
   117  		historyPath := e.getHistoryDBPath()
   118  		logger.Infof("Deleting history db path [%s]", historyPath)
   119  		e.verifyNonEmptyDirExists(historyPath)
   120  		e.assert.NoError(os.RemoveAll(historyPath))
   121  	}
   122  
   123  	e.verifyRebuilableDoesNotExist(flags)
   124  }
   125  
   126  func (e *env) verifyRebuilablesExist(flags rebuildable) {
   127  	if flags&rebuildableBlockIndex == rebuildableBlockIndex {
   128  		e.verifyNonEmptyDirExists(e.getBlockIndexDBPath())
   129  	}
   130  	if flags&rebuildableStatedb == rebuildableStatedb {
   131  		e.verifyNonEmptyDirExists(e.getLevelstateDBPath())
   132  	}
   133  	if flags&rebuildableConfigHistory == rebuildableConfigHistory {
   134  		e.verifyNonEmptyDirExists(e.getConfigHistoryDBPath())
   135  	}
   136  	if flags&rebuildableBookkeeper == rebuildableBookkeeper {
   137  		e.verifyNonEmptyDirExists(e.getBookkeeperDBPath())
   138  	}
   139  	if flags&rebuildableHistoryDB == rebuildableHistoryDB {
   140  		e.verifyNonEmptyDirExists(e.getHistoryDBPath())
   141  	}
   142  }
   143  
   144  func (e *env) verifyRebuilableDoesNotExist(flags rebuildable) {
   145  	if flags&rebuildableStatedb == rebuildableStatedb {
   146  		e.verifyDirDoesNotExist(e.getLevelstateDBPath())
   147  	}
   148  	if flags&rebuildableBlockIndex == rebuildableBlockIndex {
   149  		e.verifyDirDoesNotExist(e.getBlockIndexDBPath())
   150  	}
   151  	if flags&rebuildableConfigHistory == rebuildableConfigHistory {
   152  		e.verifyDirDoesNotExist(e.getConfigHistoryDBPath())
   153  	}
   154  	if flags&rebuildableBookkeeper == rebuildableBookkeeper {
   155  		e.verifyDirDoesNotExist(e.getBookkeeperDBPath())
   156  	}
   157  	if flags&rebuildableHistoryDB == rebuildableHistoryDB {
   158  		e.verifyDirDoesNotExist(e.getHistoryDBPath())
   159  	}
   160  }
   161  
   162  func (e *env) verifyNonEmptyDirExists(path string) {
   163  	empty, err := util.DirEmpty(path)
   164  	e.assert.NoError(err)
   165  	e.assert.False(empty)
   166  }
   167  
   168  func (e *env) verifyDirDoesNotExist(path string) {
   169  	exists, _, err := util.FileExists(path)
   170  	e.assert.NoError(err)
   171  	e.assert.False(exists)
   172  }
   173  
   174  func (e *env) initLedgerMgmt() {
   175  	e.ledgerMgr = ledgermgmt.NewLedgerMgr(e.initializer)
   176  }
   177  
   178  func (e *env) closeLedgerMgmt() {
   179  	e.ledgerMgr.Close()
   180  }
   181  
   182  func (e *env) getLedgerRootPath() string {
   183  	return e.initializer.Config.RootFSPath
   184  }
   185  
   186  func (e *env) getLevelstateDBPath() string {
   187  	return kvledger.StateDBPath(e.initializer.Config.RootFSPath)
   188  }
   189  
   190  func (e *env) getBlockIndexDBPath() string {
   191  	return filepath.Join(kvledger.BlockStorePath(e.initializer.Config.RootFSPath), fsblkstorage.IndexDir)
   192  }
   193  
   194  func (e *env) getConfigHistoryDBPath() string {
   195  	return kvledger.ConfigHistoryDBPath(e.initializer.Config.RootFSPath)
   196  }
   197  
   198  func (e *env) getHistoryDBPath() string {
   199  	return kvledger.HistoryDBPath(e.initializer.Config.RootFSPath)
   200  }
   201  
   202  func (e *env) getBookkeeperDBPath() string {
   203  	return kvledger.BookkeeperDBPath(e.initializer.Config.RootFSPath)
   204  }
   205  
   206  func populateMissingsWithTestDefaults(t *testing.T, initializer *ledgermgmt.Initializer) {
   207  	if initializer.CustomTxProcessors == nil {
   208  		initializer.CustomTxProcessors = map[common.HeaderType]ledger.CustomTxProcessor{}
   209  	}
   210  
   211  	if initializer.DeployedChaincodeInfoProvider == nil {
   212  		initializer.DeployedChaincodeInfoProvider = &lscc.DeployedCCInfoProvider{}
   213  	}
   214  
   215  	if initializer.MembershipInfoProvider == nil {
   216  		identityDeserializerFactory := func(chainID string) msp.IdentityDeserializer {
   217  			return mgmt.GetManagerForChain(chainID)
   218  		}
   219  		cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
   220  		assert.NoError(t, err)
   221  		mspID := "test-mspid"
   222  		membershipInfoProvider := privdata.NewMembershipInfoProvider(mspID, createSelfSignedData(cryptoProvider), identityDeserializerFactory)
   223  		initializer.MembershipInfoProvider = membershipInfoProvider
   224  	}
   225  
   226  	if initializer.MetricsProvider == nil {
   227  		initializer.MetricsProvider = &disabled.Provider{}
   228  	}
   229  
   230  	if initializer.Config == nil {
   231  		rootPath, err := ioutil.TempDir("/tmp", "ledgersData")
   232  		if err != nil {
   233  			t.Fatalf("Failed to create root directory: %s", err)
   234  		}
   235  
   236  		initializer.Config = &ledger.Config{
   237  			RootFSPath: rootPath,
   238  		}
   239  	}
   240  
   241  	if initializer.Config.StateDBConfig == nil {
   242  		initializer.Config.StateDBConfig = &ledger.StateDBConfig{
   243  			StateDatabase: "goleveldb",
   244  		}
   245  	}
   246  
   247  	if initializer.Config.HistoryDBConfig == nil {
   248  		initializer.Config.HistoryDBConfig = &ledger.HistoryDBConfig{
   249  			Enabled: true,
   250  		}
   251  	}
   252  
   253  	if initializer.Config.PrivateDataConfig == nil {
   254  		initializer.Config.PrivateDataConfig = &ledger.PrivateDataConfig{
   255  			MaxBatchSize:    5000,
   256  			BatchesInterval: 1000,
   257  			PurgeInterval:   100,
   258  		}
   259  	}
   260  }
   261  
   262  func createSelfSignedData(cryptoProvider bccsp.BCCSP) protoutil.SignedData {
   263  	sID := mgmt.GetLocalSigningIdentityOrPanic(cryptoProvider)
   264  	msg := make([]byte, 32)
   265  	sig, err := sID.Sign(msg)
   266  	if err != nil {
   267  		logger.Panicf("Failed creating self signed data because message signing failed: %v", err)
   268  	}
   269  	peerIdentity, err := sID.Serialize()
   270  	if err != nil {
   271  		logger.Panicf("Failed creating self signed data because peer identity couldn't be serialized: %v", err)
   272  	}
   273  	return protoutil.SignedData{
   274  		Data:      msg,
   275  		Signature: sig,
   276  		Identity:  peerIdentity,
   277  	}
   278  }
   279  
   280  // deployedCCInfoProviderWrapper is a wrapper type that overrides ChaincodeImplicitCollections
   281  type deployedCCInfoProviderWrapper struct {
   282  	*lifecycle.ValidatorCommitter
   283  	orgMSPIDs []string
   284  }
   285  
   286  // AllCollectionsConfigPkg overrides the same method in lifecycle.AllCollectionsConfigPkg.
   287  // It is basically a copy of lifecycle.AllCollectionsConfigPkg and invokes ImplicitCollections in the wrapper.
   288  // This method is called when the unit test code gets private data code path.
   289  func (dc *deployedCCInfoProviderWrapper) AllCollectionsConfigPkg(channelName, chaincodeName string, qe ledger.SimpleQueryExecutor) (*peer.CollectionConfigPackage, error) {
   290  	chaincodeInfo, err := dc.ChaincodeInfo(channelName, chaincodeName, qe)
   291  	if err != nil {
   292  		return nil, err
   293  	}
   294  	explicitCollectionConfigPkg := chaincodeInfo.ExplicitCollectionConfigPkg
   295  
   296  	implicitCollections, _ := dc.ImplicitCollections(channelName, "", nil)
   297  
   298  	var combinedColls []*peer.CollectionConfig
   299  	if explicitCollectionConfigPkg != nil {
   300  		combinedColls = append(combinedColls, explicitCollectionConfigPkg.Config...)
   301  	}
   302  	for _, implicitColl := range implicitCollections {
   303  		c := &peer.CollectionConfig{}
   304  		c.Payload = &peer.CollectionConfig_StaticCollectionConfig{StaticCollectionConfig: implicitColl}
   305  		combinedColls = append(combinedColls, c)
   306  	}
   307  	return &peer.CollectionConfigPackage{
   308  		Config: combinedColls,
   309  	}, nil
   310  }
   311  
   312  // ImplicitCollections overrides the same method in lifecycle.ValidatorCommitter.
   313  // It constructs static collection config using known mspids from the sample ledger.
   314  // This method is called when the unit test code gets collection configuration.
   315  func (dc *deployedCCInfoProviderWrapper) ImplicitCollections(channelName, chaincodeName string, qe ledger.SimpleQueryExecutor) ([]*peer.StaticCollectionConfig, error) {
   316  	collConfigs := make([]*peer.StaticCollectionConfig, 0, len(dc.orgMSPIDs))
   317  	for _, mspID := range dc.orgMSPIDs {
   318  		collConfigs = append(collConfigs, dc.ValidatorCommitter.GenerateImplicitCollectionForOrg(mspID))
   319  	}
   320  	return collConfigs, nil
   321  }
   322  
   323  func createDeployedCCInfoProvider(orgMSPIDs []string) ledger.DeployedChaincodeInfoProvider {
   324  	deployedCCInfoProvider := &lifecycle.ValidatorCommitter{
   325  		CoreConfig: &corepeer.Config{},
   326  		Resources: &lifecycle.Resources{
   327  			Serializer: &lifecycle.Serializer{},
   328  		},
   329  		LegacyDeployedCCInfoProvider: &lscc.DeployedCCInfoProvider{},
   330  	}
   331  	return &deployedCCInfoProviderWrapper{
   332  		ValidatorCommitter: deployedCCInfoProvider,
   333  		orgMSPIDs:          orgMSPIDs,
   334  	}
   335  }