github.com/yimialmonte/fabric@v2.1.1+incompatible/core/ledger/confighistory/mgr_test.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package confighistory 8 9 import ( 10 "fmt" 11 "io/ioutil" 12 "math" 13 "os" 14 "testing" 15 16 "github.com/golang/protobuf/proto" 17 "github.com/hyperledger/fabric-protos-go/common" 18 "github.com/hyperledger/fabric-protos-go/peer" 19 "github.com/hyperledger/fabric/common/flogging" 20 "github.com/hyperledger/fabric/core/ledger" 21 "github.com/hyperledger/fabric/core/ledger/mock" 22 "github.com/stretchr/testify/assert" 23 "github.com/stretchr/testify/require" 24 ) 25 26 func TestMain(m *testing.M) { 27 flogging.ActivateSpec("confighistory=debug") 28 os.Exit(m.Run()) 29 } 30 31 func TestWithNoCollectionConfig(t *testing.T) { 32 dbPath, err := ioutil.TempDir("", "confighistory") 33 if err != nil { 34 t.Fatalf("Failed to create config history directory: %s", err) 35 } 36 defer os.RemoveAll(dbPath) 37 mockCCInfoProvider := &mock.DeployedChaincodeInfoProvider{} 38 mgr, err := NewMgr(dbPath, mockCCInfoProvider) 39 assert.NoError(t, err) 40 testutilEquipMockCCInfoProviderToReturnDesiredCollConfig(mockCCInfoProvider, "chaincode1", nil) 41 err = mgr.HandleStateUpdates(&ledger.StateUpdateTrigger{ 42 LedgerID: "ledger1", 43 CommittingBlockNum: 50}, 44 ) 45 assert.NoError(t, err) 46 dummyLedgerInfoRetriever := &dummyLedgerInfoRetriever{ 47 info: &common.BlockchainInfo{Height: 100}, 48 qe: &mock.QueryExecutor{}, 49 } 50 retriever := mgr.GetRetriever("ledger1", dummyLedgerInfoRetriever) 51 collConfig, err := retriever.MostRecentCollectionConfigBelow(90, "chaincode1") 52 assert.NoError(t, err) 53 assert.Nil(t, collConfig) 54 } 55 56 func TestWithEmptyCollectionConfig(t *testing.T) { 57 dbPath, err := ioutil.TempDir("", "confighistory") 58 if err != nil { 59 t.Fatalf("Failed to create config history directory: %s", err) 60 } 61 defer os.RemoveAll(dbPath) 62 mockCCInfoProvider := &mock.DeployedChaincodeInfoProvider{} 63 mgr, err := NewMgr(dbPath, mockCCInfoProvider) 64 assert.NoError(t, err) 65 testutilEquipMockCCInfoProviderToReturnDesiredCollConfig( 66 mockCCInfoProvider, 67 "chaincode1", 68 &peer.CollectionConfigPackage{}, 69 ) 70 err = mgr.HandleStateUpdates(&ledger.StateUpdateTrigger{ 71 LedgerID: "ledger1", 72 CommittingBlockNum: 50}, 73 ) 74 assert.NoError(t, err) 75 dummyLedgerInfoRetriever := &dummyLedgerInfoRetriever{ 76 info: &common.BlockchainInfo{Height: 100}, 77 qe: &mock.QueryExecutor{}, 78 } 79 retriever := mgr.GetRetriever("ledger1", dummyLedgerInfoRetriever) 80 collConfig, err := retriever.MostRecentCollectionConfigBelow(90, "chaincode1") 81 assert.NoError(t, err) 82 assert.Nil(t, collConfig) 83 } 84 85 func TestMgr(t *testing.T) { 86 dbPath, err := ioutil.TempDir("", "confighistory") 87 if err != nil { 88 t.Fatalf("Failed to create config history directory: %s", err) 89 } 90 defer os.RemoveAll(dbPath) 91 mockCCInfoProvider := &mock.DeployedChaincodeInfoProvider{} 92 mgr, err := NewMgr(dbPath, mockCCInfoProvider) 93 assert.NoError(t, err) 94 chaincodeName := "chaincode1" 95 maxBlockNumberInLedger := uint64(2000) 96 dummyLedgerInfoRetriever := &dummyLedgerInfoRetriever{ 97 info: &common.BlockchainInfo{Height: maxBlockNumberInLedger + 1}, 98 qe: &mock.QueryExecutor{}, 99 } 100 configCommittingBlockNums := []uint64{5, 10, 15, 100} 101 ledgerIds := []string{"ledgerid1", "ledger2"} 102 103 // Populate collection config versions 104 for _, ledgerid := range ledgerIds { 105 for _, committingBlockNum := range configCommittingBlockNums { 106 // for each ledgerid and commitHeight combination, construct a unique collConfigPackage and induce a stateUpdate 107 collConfigPackage := sampleCollectionConfigPackage(ledgerid, committingBlockNum) 108 testutilEquipMockCCInfoProviderToReturnDesiredCollConfig(mockCCInfoProvider, chaincodeName, collConfigPackage) 109 mgr.HandleStateUpdates(&ledger.StateUpdateTrigger{ 110 LedgerID: ledgerid, 111 CommittingBlockNum: committingBlockNum}, 112 ) 113 } 114 } 115 116 t.Run("test-api-MostRecentCollectionConfigBelow()", func(t *testing.T) { 117 // A map that contains entries such that for each of the entries of type <K, V>, 118 // we retrieve the 'MostRecentCollectionConfigBelow' for 'K' and the expected value 119 // should be configuration committed at 'V' 120 m := map[uint64]uint64{math.MaxUint64: 100, 1000: 100, 50: 15, 12: 10, 7: 5} 121 for _, ledgerid := range ledgerIds { 122 retriever := mgr.GetRetriever(ledgerid, dummyLedgerInfoRetriever) 123 for testHeight, expectedHeight := range m { 124 retrievedConfig, err := retriever.MostRecentCollectionConfigBelow(testHeight, chaincodeName) 125 assert.NoError(t, err) 126 expectedConfig := sampleCollectionConfigPackage(ledgerid, expectedHeight) 127 assert.Equal(t, expectedConfig, retrievedConfig.CollectionConfig) 128 assert.Equal(t, expectedHeight, retrievedConfig.CommittingBlockNum) 129 } 130 131 retrievedConfig, err := retriever.MostRecentCollectionConfigBelow(5, chaincodeName) 132 assert.NoError(t, err) 133 assert.Nil(t, retrievedConfig) 134 } 135 }) 136 137 t.Run("test-api-CollectionConfigAt()", func(t *testing.T) { 138 for _, ledgerid := range ledgerIds { 139 retriever := mgr.GetRetriever(ledgerid, dummyLedgerInfoRetriever) 140 for _, commitHeight := range configCommittingBlockNums { 141 retrievedConfig, err := retriever.CollectionConfigAt(commitHeight, chaincodeName) 142 assert.NoError(t, err) 143 expectedConfig := sampleCollectionConfigPackage(ledgerid, commitHeight) 144 assert.Equal(t, expectedConfig, retrievedConfig.CollectionConfig) 145 assert.Equal(t, commitHeight, retrievedConfig.CommittingBlockNum) 146 } 147 } 148 }) 149 150 t.Run("test-api-CollectionConfigAt-BoundaryCases()", func(t *testing.T) { 151 retriever := mgr.GetRetriever("ledgerid1", dummyLedgerInfoRetriever) 152 retrievedConfig, err := retriever.CollectionConfigAt(4, chaincodeName) 153 assert.NoError(t, err) 154 assert.Nil(t, retrievedConfig) 155 156 retrievedConfig, err = retriever.CollectionConfigAt(5000, chaincodeName) 157 typedErr, ok := err.(*ledger.ErrCollectionConfigNotYetAvailable) 158 assert.True(t, ok) 159 assert.Equal(t, maxBlockNumberInLedger, typedErr.MaxBlockNumCommitted) 160 }) 161 } 162 163 func TestWithImplicitColls(t *testing.T) { 164 dbPath, err := ioutil.TempDir("", "confighistory") 165 if err != nil { 166 t.Fatalf("Failed to create config history directory: %s", err) 167 } 168 defer os.RemoveAll(dbPath) 169 collConfigPackage := testutilCreateCollConfigPkg([]string{"Explicit-coll-1", "Explicit-coll-2"}) 170 mockCCInfoProvider := &mock.DeployedChaincodeInfoProvider{} 171 mockCCInfoProvider.ImplicitCollectionsReturns( 172 []*peer.StaticCollectionConfig{ 173 { 174 Name: "Implicit-coll-1", 175 }, 176 { 177 Name: "Implicit-coll-2", 178 }, 179 }, 180 nil, 181 ) 182 p, err := newDBProvider(dbPath) 183 require.NoError(t, err) 184 185 mgr := &mgr{ 186 ccInfoProvider: mockCCInfoProvider, 187 dbProvider: p, 188 } 189 190 // add explicit collections at height 20 191 batch, err := prepareDBBatch( 192 map[string]*peer.CollectionConfigPackage{ 193 "chaincode1": collConfigPackage, 194 }, 195 20, 196 ) 197 assert.NoError(t, err) 198 dbHandle := mgr.dbProvider.getDB("ledger1") 199 assert.NoError(t, dbHandle.writeBatch(batch, true)) 200 201 onlyImplicitCollections := testutilCreateCollConfigPkg( 202 []string{"Implicit-coll-1", "Implicit-coll-2"}, 203 ) 204 205 explicitAndImplicitCollections := testutilCreateCollConfigPkg( 206 []string{"Explicit-coll-1", "Explicit-coll-2", "Implicit-coll-1", "Implicit-coll-2"}, 207 ) 208 209 dummyLedgerInfoRetriever := &dummyLedgerInfoRetriever{ 210 info: &common.BlockchainInfo{Height: 1000}, 211 qe: &mock.QueryExecutor{}, 212 } 213 214 t.Run("CheckQueryExecutorCalls", func(t *testing.T) { 215 retriever := mgr.GetRetriever("ledger1", dummyLedgerInfoRetriever) 216 // function MostRecentCollectionConfigBelow calls Done on query executor 217 _, err := retriever.MostRecentCollectionConfigBelow(50, "chaincode1") 218 assert.NoError(t, err) 219 assert.Equal(t, 1, dummyLedgerInfoRetriever.qe.DoneCallCount()) 220 // function CollectionConfigAt calls Done on query executor 221 _, err = retriever.CollectionConfigAt(50, "chaincode1") 222 assert.NoError(t, err) 223 assert.Equal(t, 2, dummyLedgerInfoRetriever.qe.DoneCallCount()) 224 }) 225 226 t.Run("MostRecentCollectionConfigBelow50", func(t *testing.T) { 227 // explicit collections added at height 20 should be merged with the implicit collections 228 retriever := mgr.GetRetriever("ledger1", dummyLedgerInfoRetriever) 229 retrievedConfig, err := retriever.MostRecentCollectionConfigBelow(50, "chaincode1") 230 assert.NoError(t, err) 231 assert.True(t, proto.Equal(retrievedConfig.CollectionConfig, explicitAndImplicitCollections)) 232 }) 233 234 t.Run("MostRecentCollectionConfigBelow10", func(t *testing.T) { 235 // No explicit collections below height 10, should return only implicit collections 236 retriever := mgr.GetRetriever("ledger1", dummyLedgerInfoRetriever) 237 retrievedConfig, err := retriever.MostRecentCollectionConfigBelow(10, "chaincode1") 238 assert.NoError(t, err) 239 assert.True(t, proto.Equal(retrievedConfig.CollectionConfig, onlyImplicitCollections)) 240 }) 241 242 t.Run("CollectionConfigAt50", func(t *testing.T) { 243 // No explicit collections at height 50, should return only implicit collections 244 retriever := mgr.GetRetriever("ledger1", dummyLedgerInfoRetriever) 245 retrievedConfig, err := retriever.CollectionConfigAt(50, "chaincode1") 246 assert.NoError(t, err) 247 assert.True(t, proto.Equal(retrievedConfig.CollectionConfig, onlyImplicitCollections)) 248 }) 249 250 t.Run("CollectionConfigAt20", func(t *testing.T) { 251 // Explicit collections at height 20, should be merged with implicit collections 252 retriever := mgr.GetRetriever("ledger1", dummyLedgerInfoRetriever) 253 retrievedConfig, err := retriever.CollectionConfigAt(20, "chaincode1") 254 assert.NoError(t, err) 255 assert.True(t, proto.Equal(retrievedConfig.CollectionConfig, explicitAndImplicitCollections)) 256 }) 257 258 } 259 260 func sampleCollectionConfigPackage(collNamePart1 string, collNamePart2 uint64) *peer.CollectionConfigPackage { 261 collName := fmt.Sprintf("%s-%d", collNamePart1, collNamePart2) 262 return testutilCreateCollConfigPkg([]string{collName}) 263 } 264 265 func testutilEquipMockCCInfoProviderToReturnDesiredCollConfig( 266 mockCCInfoProvider *mock.DeployedChaincodeInfoProvider, 267 chaincodeName string, 268 collConfigPackage *peer.CollectionConfigPackage) { 269 mockCCInfoProvider.UpdatedChaincodesReturns( 270 []*ledger.ChaincodeLifecycleInfo{ 271 {Name: chaincodeName}, 272 }, 273 nil, 274 ) 275 mockCCInfoProvider.ChaincodeInfoReturns( 276 &ledger.DeployedChaincodeInfo{Name: chaincodeName, ExplicitCollectionConfigPkg: collConfigPackage}, 277 nil, 278 ) 279 } 280 281 func testutilCreateCollConfigPkg(collNames []string) *peer.CollectionConfigPackage { 282 pkg := &peer.CollectionConfigPackage{ 283 Config: []*peer.CollectionConfig{}, 284 } 285 for _, collName := range collNames { 286 pkg.Config = append(pkg.Config, 287 &peer.CollectionConfig{ 288 Payload: &peer.CollectionConfig_StaticCollectionConfig{ 289 StaticCollectionConfig: &peer.StaticCollectionConfig{ 290 Name: collName, 291 }, 292 }, 293 }, 294 ) 295 } 296 return pkg 297 } 298 299 type dummyLedgerInfoRetriever struct { 300 info *common.BlockchainInfo 301 qe *mock.QueryExecutor 302 } 303 304 func (d *dummyLedgerInfoRetriever) GetBlockchainInfo() (*common.BlockchainInfo, error) { 305 return d.info, nil 306 } 307 308 func (d *dummyLedgerInfoRetriever) NewQueryExecutor() (ledger.QueryExecutor, error) { 309 return d.qe, nil 310 }