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 }