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