github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/ledger/confighistory/mgr_test.go (about) 1 /* 2 Copyright hechain. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package confighistory 8 9 import ( 10 "crypto/sha256" 11 "fmt" 12 "hash" 13 "io/ioutil" 14 "math" 15 "os" 16 "path/filepath" 17 "testing" 18 19 "github.com/golang/protobuf/proto" 20 "github.com/hechain20/hechain/common/flogging" 21 "github.com/hechain20/hechain/common/ledger/snapshot" 22 "github.com/hechain20/hechain/core/ledger" 23 "github.com/hechain20/hechain/core/ledger/mock" 24 "github.com/hyperledger/fabric-protos-go/peer" 25 "github.com/stretchr/testify/require" 26 ) 27 28 var testNewHashFunc = func() (hash.Hash, error) { 29 return sha256.New(), nil 30 } 31 32 func TestMain(m *testing.M) { 33 flogging.ActivateSpec("confighistory=debug") 34 os.Exit(m.Run()) 35 } 36 37 func TestWithNoCollectionConfig(t *testing.T) { 38 dbPath, err := ioutil.TempDir("", "confighistory") 39 if err != nil { 40 t.Fatalf("Failed to create config history directory: %s", err) 41 } 42 defer os.RemoveAll(dbPath) 43 mockCCInfoProvider := &mock.DeployedChaincodeInfoProvider{} 44 mgr, err := NewMgr(dbPath, mockCCInfoProvider) 45 require.NoError(t, err) 46 testutilEquipMockCCInfoProviderToReturnDesiredCollConfig(mockCCInfoProvider, "chaincode1", nil) 47 err = mgr.HandleStateUpdates(&ledger.StateUpdateTrigger{ 48 LedgerID: "ledger1", 49 CommittingBlockNum: 50, 50 }, 51 ) 52 require.NoError(t, err) 53 retriever := mgr.GetRetriever("ledger1") 54 collConfig, err := retriever.MostRecentCollectionConfigBelow(90, "chaincode1") 55 require.NoError(t, err) 56 require.Nil(t, collConfig) 57 } 58 59 func TestWithEmptyCollectionConfig(t *testing.T) { 60 dbPath, err := ioutil.TempDir("", "confighistory") 61 if err != nil { 62 t.Fatalf("Failed to create config history directory: %s", err) 63 } 64 defer os.RemoveAll(dbPath) 65 mockCCInfoProvider := &mock.DeployedChaincodeInfoProvider{} 66 mgr, err := NewMgr(dbPath, mockCCInfoProvider) 67 require.NoError(t, err) 68 testutilEquipMockCCInfoProviderToReturnDesiredCollConfig( 69 mockCCInfoProvider, 70 "chaincode1", 71 &peer.CollectionConfigPackage{}, 72 ) 73 err = mgr.HandleStateUpdates(&ledger.StateUpdateTrigger{ 74 LedgerID: "ledger1", 75 CommittingBlockNum: 50, 76 }, 77 ) 78 require.NoError(t, err) 79 retriever := mgr.GetRetriever("ledger1") 80 collConfig, err := retriever.MostRecentCollectionConfigBelow(90, "chaincode1") 81 require.NoError(t, err) 82 require.Nil(t, collConfig) 83 } 84 85 func TestMgrQueries(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 require.NoError(t, err) 94 chaincodeName := "chaincode1" 95 configCommittingBlockNums := []uint64{5, 10, 15, 100} 96 ledgerIds := []string{"ledgerid1", "ledger2"} 97 98 // Populate collection config versions 99 for _, ledgerid := range ledgerIds { 100 for _, committingBlockNum := range configCommittingBlockNums { 101 // for each ledgerid and commitHeight combination, construct a unique collConfigPackage and induce a stateUpdate 102 collConfigPackage := sampleCollectionConfigPackage(ledgerid, committingBlockNum) 103 testutilEquipMockCCInfoProviderToReturnDesiredCollConfig(mockCCInfoProvider, chaincodeName, collConfigPackage) 104 err = mgr.HandleStateUpdates(&ledger.StateUpdateTrigger{ 105 LedgerID: ledgerid, 106 CommittingBlockNum: committingBlockNum, 107 }, 108 ) 109 require.NoError(t, err) 110 } 111 } 112 113 t.Run("test-api-MostRecentCollectionConfigBelow()", func(t *testing.T) { 114 // A map that contains entries such that for each of the entries of type <K, V>, 115 // we retrieve the 'MostRecentCollectionConfigBelow' for 'K' and the expected value 116 // should be configuration committed at 'V' 117 m := map[uint64]uint64{math.MaxUint64: 100, 1000: 100, 50: 15, 12: 10, 7: 5} 118 for _, ledgerid := range ledgerIds { 119 retriever := mgr.GetRetriever(ledgerid) 120 for testHeight, expectedHeight := range m { 121 retrievedConfig, err := retriever.MostRecentCollectionConfigBelow(testHeight, chaincodeName) 122 require.NoError(t, err) 123 expectedConfig := sampleCollectionConfigPackage(ledgerid, expectedHeight) 124 require.Equal(t, expectedConfig, retrievedConfig.CollectionConfig) 125 require.Equal(t, expectedHeight, retrievedConfig.CommittingBlockNum) 126 } 127 128 retrievedConfig, err := retriever.MostRecentCollectionConfigBelow(5, chaincodeName) 129 require.NoError(t, err) 130 require.Nil(t, retrievedConfig) 131 } 132 }) 133 } 134 135 func TestDrop(t *testing.T) { 136 dbPath, err := ioutil.TempDir("", "confighistory") 137 require.NoError(t, err) 138 defer os.RemoveAll(dbPath) 139 mockCCInfoProvider := &mock.DeployedChaincodeInfoProvider{} 140 mgr, err := NewMgr(dbPath, mockCCInfoProvider) 141 require.NoError(t, err) 142 chaincodeName := "chaincode1" 143 configCommittingBlockNums := []uint64{5, 10, 15, 100} 144 ledgerIds := []string{"ledger1", "ledger2"} 145 146 // Populate collection config versions 147 for _, ledgerid := range ledgerIds { 148 for _, committingBlockNum := range configCommittingBlockNums { 149 // for each ledgerid and commitHeight combination, construct a unique collConfigPackage and induce a stateUpdate 150 collConfigPackage := sampleCollectionConfigPackage(ledgerid, committingBlockNum) 151 testutilEquipMockCCInfoProviderToReturnDesiredCollConfig(mockCCInfoProvider, chaincodeName, collConfigPackage) 152 require.NoError(t, mgr.HandleStateUpdates(&ledger.StateUpdateTrigger{LedgerID: ledgerid, CommittingBlockNum: committingBlockNum})) 153 } 154 } 155 156 // remove ledger1 and verify ledger1 entries are deleted and ledger2 returns collection config as is 157 require.NoError(t, mgr.Drop("ledger1")) 158 159 retriever1 := mgr.GetRetriever("ledger1") 160 retrievedConfig, err := retriever1.MostRecentCollectionConfigBelow(math.MaxUint64, chaincodeName) 161 require.NoError(t, err) 162 require.Nil(t, retrievedConfig) 163 empty, err := retriever1.dbHandle.IsEmpty() 164 require.NoError(t, err) 165 require.True(t, empty) 166 167 retriever2 := mgr.GetRetriever("ledger2") 168 m := map[uint64]uint64{math.MaxUint64: 100, 1000: 100, 50: 15, 12: 10, 7: 5} 169 for testHeight, expectedHeight := range m { 170 retrievedConfig, err = retriever2.MostRecentCollectionConfigBelow(testHeight, chaincodeName) 171 require.NoError(t, err) 172 expectedConfig := sampleCollectionConfigPackage("ledger2", expectedHeight) 173 require.Equal(t, expectedConfig, retrievedConfig.CollectionConfig) 174 require.Equal(t, expectedHeight, retrievedConfig.CommittingBlockNum) 175 } 176 177 // drop again is not an error 178 require.NoError(t, mgr.Drop("ledger1")) 179 180 // test error path 181 mgr.Close() 182 require.EqualError(t, mgr.Drop("ledger2"), "internal leveldb error while obtaining db iterator: leveldb: closed") 183 } 184 185 func TestWithImplicitColls(t *testing.T) { 186 dbPath, err := ioutil.TempDir("", "confighistory") 187 if err != nil { 188 t.Fatalf("Failed to create config history directory: %s", err) 189 } 190 defer os.RemoveAll(dbPath) 191 collConfigPackage := testutilCreateCollConfigPkg([]string{"Explicit-coll-1", "Explicit-coll-2"}) 192 mockCCInfoProvider := &mock.DeployedChaincodeInfoProvider{} 193 mockCCInfoProvider.ImplicitCollectionsReturns( 194 []*peer.StaticCollectionConfig{ 195 { 196 Name: "Implicit-coll-1", 197 }, 198 { 199 Name: "Implicit-coll-2", 200 }, 201 }, 202 nil, 203 ) 204 p, err := newDBProvider(dbPath) 205 require.NoError(t, err) 206 207 mgr := &Mgr{ 208 ccInfoProvider: mockCCInfoProvider, 209 dbProvider: p, 210 } 211 dbHandle := mgr.dbProvider.getDB("ledger1") 212 batch := dbHandle.newBatch() 213 // add explicit collections at height 20 214 err = prepareDBBatch( 215 batch, 216 map[string]*peer.CollectionConfigPackage{ 217 "chaincode1": collConfigPackage, 218 }, 219 20, 220 ) 221 require.NoError(t, err) 222 require.NoError(t, dbHandle.writeBatch(batch, true)) 223 224 explicitAndImplicitCollections := testutilCreateCollConfigPkg( 225 []string{"Explicit-coll-1", "Explicit-coll-2"}, 226 ) 227 228 t.Run("CheckQueryExecutorCalls", func(t *testing.T) { 229 retriever := mgr.GetRetriever("ledger1") 230 // function MostRecentCollectionConfigBelow calls Done on query executor 231 _, err := retriever.MostRecentCollectionConfigBelow(50, "chaincode1") 232 require.NoError(t, err) 233 }) 234 235 t.Run("MostRecentCollectionConfigBelow50", func(t *testing.T) { 236 // explicit collections added at height 20 should be merged with the implicit collections 237 retriever := mgr.GetRetriever("ledger1") 238 retrievedConfig, err := retriever.MostRecentCollectionConfigBelow(50, "chaincode1") 239 require.NoError(t, err) 240 require.True(t, proto.Equal(retrievedConfig.CollectionConfig, explicitAndImplicitCollections)) 241 }) 242 243 t.Run("MostRecentCollectionConfigBelow10", func(t *testing.T) { 244 // No explicit collections below height 10, should return only implicit collections 245 retriever := mgr.GetRetriever("ledger1") 246 retrievedConfig, err := retriever.MostRecentCollectionConfigBelow(10, "chaincode1") 247 require.NoError(t, err) 248 require.Nil(t, retrievedConfig) 249 }) 250 } 251 252 type testEnvForSnapshot struct { 253 mgr *Mgr 254 testSnapshotDir string 255 cleanup func() 256 } 257 258 func newTestEnvForSnapshot(t *testing.T) *testEnvForSnapshot { 259 dbPath, err := ioutil.TempDir("", "confighistory") 260 require.NoError(t, err) 261 mgr, err := NewMgr(dbPath, &mock.DeployedChaincodeInfoProvider{}) 262 if err != nil { 263 os.RemoveAll(dbPath) 264 t.Fatalf("Failed to create new config history manager: %s", err) 265 } 266 267 testSnapshotDir, err := ioutil.TempDir("", "confighistorysnapshot") 268 if err != nil { 269 os.RemoveAll(dbPath) 270 t.Fatalf("Failed to create config history snapshot directory: %s", err) 271 } 272 return &testEnvForSnapshot{ 273 mgr: mgr, 274 testSnapshotDir: testSnapshotDir, 275 cleanup: func() { 276 os.RemoveAll(dbPath) 277 os.RemoveAll(testSnapshotDir) 278 }, 279 } 280 } 281 282 func TestExportAndImportConfigHistory(t *testing.T) { 283 setupWithSampleData := func(env *testEnvForSnapshot, ledgerID string) ([]*compositeKV, map[string][]*ledger.CollectionConfigInfo) { 284 cc1CollConfigPackage := testutilCreateCollConfigPkg([]string{"Explicit-cc1-coll-1", "Explicit-cc1-coll-2"}) 285 cc2CollConfigPackage := testutilCreateCollConfigPkg([]string{"Explicit-cc2-coll-1", "Explicit-cc2-coll-2"}) 286 cc3CollConfigPackage := testutilCreateCollConfigPkg([]string{"Explicit-cc3-coll-1", "Explicit-cc3-coll-2"}) 287 cc1CollConfigPackageNew := testutilCreateCollConfigPkg([]string{"Explicit-cc1-coll-1", "Explicit-cc1-coll-2", "Explicit-cc1-coll-3"}) 288 cc2CollConfigPackageNew := testutilCreateCollConfigPkg([]string{"Explicit-cc2-coll-1", "Explicit-cc2-coll-2", "Explicit-cc2-coll-3"}) 289 cc3CollConfigPackageNew := testutilCreateCollConfigPkg([]string{"Explicit-cc3-coll-1", "Explicit-cc3-coll-2", "Explicit-cc3-coll-3"}) 290 291 ccConfigInfo := map[string][]*ledger.CollectionConfigInfo{ 292 "chaincode1": { 293 { 294 CollectionConfig: cc1CollConfigPackage, 295 CommittingBlockNum: 50, 296 }, 297 { 298 CollectionConfig: cc1CollConfigPackageNew, 299 CommittingBlockNum: 100, 300 }, 301 }, 302 "chaincode2": { 303 { 304 CollectionConfig: cc2CollConfigPackage, 305 CommittingBlockNum: 50, 306 }, 307 { 308 CollectionConfig: cc2CollConfigPackageNew, 309 CommittingBlockNum: 100, 310 }, 311 }, 312 "chaincode3": { 313 { 314 CollectionConfig: cc3CollConfigPackage, 315 CommittingBlockNum: 50, 316 }, 317 { 318 CollectionConfig: cc3CollConfigPackageNew, 319 CommittingBlockNum: 100, 320 }, 321 }, 322 } 323 324 db := env.mgr.dbProvider.getDB(ledgerID) 325 batch := db.newBatch() 326 err := prepareDBBatch( 327 batch, 328 map[string]*peer.CollectionConfigPackage{ 329 "chaincode1": cc1CollConfigPackage, 330 "chaincode2": cc2CollConfigPackage, 331 "chaincode3": cc3CollConfigPackage, 332 }, 333 50, 334 ) 335 require.NoError(t, err) 336 require.NoError(t, db.writeBatch(batch, true)) 337 338 batch = db.newBatch() 339 err = prepareDBBatch( 340 batch, 341 map[string]*peer.CollectionConfigPackage{ 342 "chaincode1": cc1CollConfigPackageNew, 343 "chaincode2": cc2CollConfigPackageNew, 344 "chaincode3": cc3CollConfigPackageNew, 345 }, 346 100, 347 ) 348 require.NoError(t, err) 349 require.NoError(t, db.writeBatch(batch, true)) 350 351 cc1configBytes, err := proto.Marshal(cc1CollConfigPackage) 352 require.NoError(t, err) 353 cc2configBytes, err := proto.Marshal(cc2CollConfigPackage) 354 require.NoError(t, err) 355 cc3configBytes, err := proto.Marshal(cc3CollConfigPackage) 356 require.NoError(t, err) 357 cc1configBytesNew, err := proto.Marshal(cc1CollConfigPackageNew) 358 require.NoError(t, err) 359 cc2configBytesNew, err := proto.Marshal(cc2CollConfigPackageNew) 360 require.NoError(t, err) 361 cc3configBytesNew, err := proto.Marshal(cc3CollConfigPackageNew) 362 require.NoError(t, err) 363 364 storedKVs := []*compositeKV{ 365 {&compositeKey{ns: "lscc", key: "chaincode1~collection", blockNum: 100}, cc1configBytesNew}, 366 {&compositeKey{ns: "lscc", key: "chaincode1~collection", blockNum: 50}, cc1configBytes}, 367 {&compositeKey{ns: "lscc", key: "chaincode2~collection", blockNum: 100}, cc2configBytesNew}, 368 {&compositeKey{ns: "lscc", key: "chaincode2~collection", blockNum: 50}, cc2configBytes}, 369 {&compositeKey{ns: "lscc", key: "chaincode3~collection", blockNum: 100}, cc3configBytesNew}, 370 {&compositeKey{ns: "lscc", key: "chaincode3~collection", blockNum: 50}, cc3configBytes}, 371 } 372 return storedKVs, ccConfigInfo 373 } 374 375 t.Run("confighistory is empty", func(t *testing.T) { 376 env := newTestEnvForSnapshot(t) 377 defer env.cleanup() 378 retriever := env.mgr.GetRetriever("ledger1") 379 fileHashes, err := retriever.ExportConfigHistory(env.testSnapshotDir, testNewHashFunc) 380 require.NoError(t, err) 381 require.Empty(t, fileHashes) 382 files, err := ioutil.ReadDir(env.testSnapshotDir) 383 require.NoError(t, err) 384 require.Len(t, files, 0) 385 }) 386 387 t.Run("export confighistory", func(t *testing.T) { 388 // setup ledger1 => export ledger1 389 env := newTestEnvForSnapshot(t) 390 defer env.cleanup() 391 storedKVs, _ := setupWithSampleData(env, "ledger1") 392 retriever := env.mgr.GetRetriever("ledger1") 393 fileHashes, err := retriever.ExportConfigHistory(env.testSnapshotDir, testNewHashFunc) 394 require.NoError(t, err) 395 verifyExportedConfigHistory(t, env.testSnapshotDir, fileHashes, storedKVs) 396 }) 397 398 t.Run("import confighistory and verify queries", func(t *testing.T) { 399 // setup ledger1 => export ledger1 => import into ledger2 400 env := newTestEnvForSnapshot(t) 401 defer env.cleanup() 402 _, ccConfigInfo := setupWithSampleData(env, "ledger1") 403 retriever := env.mgr.GetRetriever("ledger1") 404 _, err := retriever.ExportConfigHistory(env.testSnapshotDir, testNewHashFunc) 405 require.NoError(t, err) 406 407 importConfigsBatchSize = 100 408 require.NoError(t, env.mgr.ImportFromSnapshot("ledger2", env.testSnapshotDir)) 409 410 retriever = env.mgr.GetRetriever("ledger2") 411 verifyImportedConfigHistory(t, retriever, ccConfigInfo) 412 }) 413 414 t.Run("export from an imported confighistory", func(t *testing.T) { 415 // setup ledger1 => export ledger1 => import into ledger2 => export ledger2 416 env := newTestEnvForSnapshot(t) 417 defer env.cleanup() 418 storedKVs, _ := setupWithSampleData(env, "ledger1") 419 retriever := env.mgr.GetRetriever("ledger1") 420 _, err := retriever.ExportConfigHistory(env.testSnapshotDir, testNewHashFunc) 421 require.NoError(t, err) 422 423 importConfigsBatchSize = 100 424 require.NoError(t, env.mgr.ImportFromSnapshot("ledger2", env.testSnapshotDir)) 425 require.NoError(t, os.RemoveAll(filepath.Join(env.testSnapshotDir, snapshotDataFileName))) 426 require.NoError(t, os.RemoveAll(filepath.Join(env.testSnapshotDir, snapshotMetadataFileName))) 427 428 retriever = env.mgr.GetRetriever("ledger2") 429 fileHashes, err := retriever.ExportConfigHistory(env.testSnapshotDir, testNewHashFunc) 430 require.NoError(t, err) 431 verifyExportedConfigHistory(t, env.testSnapshotDir, fileHashes, storedKVs) 432 }) 433 434 t.Run("import confighistory with no data and metadata files", func(t *testing.T) { 435 env := newTestEnvForSnapshot(t) 436 defer env.cleanup() 437 require.NoFileExists(t, filepath.Join(env.testSnapshotDir, snapshotDataFileName)) 438 require.NoFileExists(t, filepath.Join(env.testSnapshotDir, snapshotMetadataFileName)) 439 err := env.mgr.ImportFromSnapshot("ledger1", env.testSnapshotDir) 440 require.NoError(t, err) 441 }) 442 443 t.Run("import confighistory - ledger exists error", func(t *testing.T) { 444 env := newTestEnvForSnapshot(t) 445 defer env.cleanup() 446 setupWithSampleData(env, "ledger1") 447 dataFileWriter, err := snapshot.CreateFile(filepath.Join(env.testSnapshotDir, snapshotDataFileName), snapshotFileFormat, testNewHashFunc) 448 require.NoError(t, err) 449 defer dataFileWriter.Close() 450 err = env.mgr.ImportFromSnapshot("ledger1", env.testSnapshotDir) 451 expectedErrStr := "config history for ledger [ledger1] exists. Incremental import is not supported. Remove the existing ledger data before retry" 452 require.EqualError(t, err, expectedErrStr) 453 }) 454 455 t.Run("import confighistory - EOF error", func(t *testing.T) { 456 env := newTestEnvForSnapshot(t) 457 defer env.cleanup() 458 dataFileWriter1, err := snapshot.CreateFile(filepath.Join(env.testSnapshotDir, snapshotMetadataFileName), snapshotFileFormat, testNewHashFunc) 459 require.NoError(t, err) 460 defer dataFileWriter1.Close() 461 dataFileWriter2, err := snapshot.CreateFile(filepath.Join(env.testSnapshotDir, snapshotDataFileName), snapshotFileFormat, testNewHashFunc) 462 require.NoError(t, err) 463 defer dataFileWriter2.Close() 464 err = env.mgr.ImportFromSnapshot("ledger2", env.testSnapshotDir) 465 require.Contains(t, err.Error(), "error while reading from the snapshot file") 466 require.Contains(t, err.Error(), "confighistory.metadata: EOF") 467 468 require.NoError(t, os.RemoveAll(filepath.Join(env.testSnapshotDir, snapshotMetadataFileName))) 469 dataFileWriter3, err := snapshot.CreateFile(filepath.Join(env.testSnapshotDir, snapshotMetadataFileName), snapshotFileFormat, testNewHashFunc) 470 require.NoError(t, err) 471 defer dataFileWriter3.Close() 472 require.NoError(t, dataFileWriter3.EncodeUVarint(1)) 473 _, err = dataFileWriter3.Done() 474 require.NoError(t, err) 475 err = env.mgr.ImportFromSnapshot("ledger2", env.testSnapshotDir) 476 require.Contains(t, err.Error(), "error while reading from the snapshot file") 477 require.Contains(t, err.Error(), "confighistory.data: EOF") 478 }) 479 480 t.Run("import confighistory - leveldb iter error", func(t *testing.T) { 481 env := newTestEnvForSnapshot(t) 482 defer env.cleanup() 483 env.mgr.dbProvider.Close() 484 dataFileWriter, err := snapshot.CreateFile(filepath.Join(env.testSnapshotDir, snapshotDataFileName), snapshotFileFormat, testNewHashFunc) 485 require.NoError(t, err) 486 defer dataFileWriter.Close() 487 err = env.mgr.ImportFromSnapshot("ledger2", env.testSnapshotDir) 488 require.EqualError(t, err, "internal leveldb error while obtaining db iterator: leveldb: closed") 489 }) 490 } 491 492 func verifyExportedConfigHistory(t *testing.T, dir string, fileHashes map[string][]byte, expectedCollectionConfigs []*compositeKV) { 493 require.Len(t, fileHashes, 2) 494 require.Contains(t, fileHashes, snapshotDataFileName) 495 require.Contains(t, fileHashes, snapshotMetadataFileName) 496 497 dataFile := filepath.Join(dir, snapshotDataFileName) 498 dataFileContent, err := ioutil.ReadFile(dataFile) 499 require.NoError(t, err) 500 dataFileHash := sha256.Sum256(dataFileContent) 501 require.Equal(t, dataFileHash[:], fileHashes[snapshotDataFileName]) 502 503 metadataFile := filepath.Join(dir, snapshotMetadataFileName) 504 metadataFileContent, err := ioutil.ReadFile(metadataFile) 505 require.NoError(t, err) 506 metadataFileHash := sha256.Sum256(metadataFileContent) 507 require.Equal(t, metadataFileHash[:], fileHashes[snapshotMetadataFileName]) 508 509 metadataReader, err := snapshot.OpenFile(metadataFile, snapshotFileFormat) 510 require.NoError(t, err) 511 defer metadataReader.Close() 512 513 dataReader, err := snapshot.OpenFile(dataFile, snapshotFileFormat) 514 require.NoError(t, err) 515 defer dataReader.Close() 516 517 numCollectionConfigs, err := metadataReader.DecodeUVarInt() 518 require.NoError(t, err) 519 520 var retrievedCollectionConfigs []*compositeKV 521 for i := uint64(0); i < numCollectionConfigs; i++ { 522 key, err := dataReader.DecodeBytes() 523 require.NoError(t, err) 524 val, err := dataReader.DecodeBytes() 525 require.NoError(t, err) 526 retrievedCollectionConfigs = append(retrievedCollectionConfigs, 527 &compositeKV{decodeCompositeKey(key), val}, 528 ) 529 } 530 require.Equal(t, expectedCollectionConfigs, retrievedCollectionConfigs) 531 } 532 533 func verifyImportedConfigHistory(t *testing.T, retriever *Retriever, expectedCCConfigInfo map[string][]*ledger.CollectionConfigInfo) { 534 for chaincodeName, ccConfigInfos := range expectedCCConfigInfo { 535 for _, expectedCCConfig := range ccConfigInfos { 536 ccConfig, err := retriever.MostRecentCollectionConfigBelow(expectedCCConfig.CommittingBlockNum+1, chaincodeName) 537 require.NoError(t, err) 538 require.True(t, proto.Equal(expectedCCConfig.CollectionConfig, ccConfig.CollectionConfig)) 539 require.Equal(t, expectedCCConfig.CommittingBlockNum, ccConfig.CommittingBlockNum) 540 } 541 } 542 } 543 544 func TestExportConfigHistoryErrorCase(t *testing.T) { 545 env := newTestEnvForSnapshot(t) 546 defer env.cleanup() 547 548 db := env.mgr.dbProvider.getDB("ledger1") 549 cc1collConfigPackage := testutilCreateCollConfigPkg([]string{"Explicit-cc1-coll-1", "Explicit-cc1-coll-2"}) 550 batch := db.newBatch() 551 err := prepareDBBatch( 552 batch, 553 map[string]*peer.CollectionConfigPackage{ 554 "chaincode1": cc1collConfigPackage, 555 }, 556 50, 557 ) 558 require.NoError(t, err) 559 require.NoError(t, db.writeBatch(batch, true)) 560 561 // error during data file creation 562 dataFilePath := filepath.Join(env.testSnapshotDir, snapshotDataFileName) 563 _, err = os.Create(dataFilePath) 564 require.NoError(t, err) 565 566 retriever := env.mgr.GetRetriever("ledger1") 567 _, err = retriever.ExportConfigHistory(env.testSnapshotDir, testNewHashFunc) 568 require.Contains(t, err.Error(), "error while creating the snapshot file: "+dataFilePath) 569 os.RemoveAll(env.testSnapshotDir) 570 571 // error during metadata file creation 572 require.NoError(t, os.MkdirAll(env.testSnapshotDir, 0o700)) 573 metadataFilePath := filepath.Join(env.testSnapshotDir, snapshotMetadataFileName) 574 _, err = os.Create(metadataFilePath) 575 require.NoError(t, err) 576 _, err = retriever.ExportConfigHistory(env.testSnapshotDir, testNewHashFunc) 577 require.Contains(t, err.Error(), "error while creating the snapshot file: "+metadataFilePath) 578 os.RemoveAll(env.testSnapshotDir) 579 580 // error while reading from leveldb 581 require.NoError(t, os.MkdirAll(env.testSnapshotDir, 0o700)) 582 env.mgr.dbProvider.Close() 583 _, err = retriever.ExportConfigHistory(env.testSnapshotDir, testNewHashFunc) 584 require.EqualError(t, err, "internal leveldb error while obtaining db iterator: leveldb: closed") 585 os.RemoveAll(env.testSnapshotDir) 586 } 587 588 func sampleCollectionConfigPackage(collNamePart1 string, collNamePart2 uint64) *peer.CollectionConfigPackage { 589 collName := fmt.Sprintf("%s-%d", collNamePart1, collNamePart2) 590 return testutilCreateCollConfigPkg([]string{collName}) 591 } 592 593 func testutilEquipMockCCInfoProviderToReturnDesiredCollConfig( 594 mockCCInfoProvider *mock.DeployedChaincodeInfoProvider, 595 chaincodeName string, 596 collConfigPackage *peer.CollectionConfigPackage) { 597 mockCCInfoProvider.UpdatedChaincodesReturns( 598 []*ledger.ChaincodeLifecycleInfo{ 599 {Name: chaincodeName}, 600 }, 601 nil, 602 ) 603 mockCCInfoProvider.ChaincodeInfoReturns( 604 &ledger.DeployedChaincodeInfo{Name: chaincodeName, ExplicitCollectionConfigPkg: collConfigPackage}, 605 nil, 606 ) 607 } 608 609 func testutilCreateCollConfigPkg(collNames []string) *peer.CollectionConfigPackage { 610 pkg := &peer.CollectionConfigPackage{ 611 Config: []*peer.CollectionConfig{}, 612 } 613 for _, collName := range collNames { 614 pkg.Config = append(pkg.Config, 615 &peer.CollectionConfig{ 616 Payload: &peer.CollectionConfig_StaticCollectionConfig{ 617 StaticCollectionConfig: &peer.StaticCollectionConfig{ 618 Name: collName, 619 }, 620 }, 621 }, 622 ) 623 } 624 return pkg 625 }