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 }