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 }