github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/ledger/kvledger/tests/env.go (about)

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