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  }