github.com/yous1230/fabric@v2.0.0-beta.0.20191224111736-74345bee6ac2+incompatible/core/ledger/kvledger/tests/v1x_test.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  	"fmt"
    11  	"os"
    12  	"path"
    13  	"path/filepath"
    14  	"testing"
    15  	"time"
    16  
    17  	protopeer "github.com/hyperledger/fabric-protos-go/peer"
    18  	"github.com/hyperledger/fabric/common/ledger/testutil"
    19  	"github.com/hyperledger/fabric/core/ledger/kvledger"
    20  	"github.com/hyperledger/fabric/core/ledger/mock"
    21  	"github.com/hyperledger/fabric/core/ledger/util/couchdb"
    22  	"github.com/hyperledger/fabric/core/ledger/util/couchdbtest"
    23  	"github.com/stretchr/testify/require"
    24  )
    25  
    26  // TestV11 tests that a ledgersData folder created by v1.1 can be used with future releases in a backward compatible way
    27  // The test data was generated by v1.1 code https://github.com/hyperledger/fabric/blob/release-1.1/core/ledger/kvledger/tests/v11_generate_test.go#L22
    28  func TestV11(t *testing.T) {
    29  	env := newEnv(t)
    30  	defer env.cleanup()
    31  
    32  	ledgerFSRoot := env.initializer.Config.RootFSPath
    33  	// pass false so that 'ledgersData' directory will not be created when unzipped to ledgerFSRoot
    34  	require.NoError(t, testutil.Unzip("testdata/v11/sample_ledgers/ledgersData.zip", ledgerFSRoot, false))
    35  
    36  	// verify init ledger panic and drop the corresponding db after each panic
    37  	checkInitLedgerPanicAndDropDBs(t, env, ledgerFSRoot, nil)
    38  
    39  	t.Logf("All stores are reformatted/dropped, now ledgermgmt initialization should not panic")
    40  	env.initLedgerMgmt()
    41  
    42  	h1, h2 := env.newTestHelperOpenLgr("ledger1", t), env.newTestHelperOpenLgr("ledger2", t)
    43  	dataHelper := &v1xSampleDataHelper{sampleDataVersion: "v1.1", t: t}
    44  
    45  	dataHelper.verify(h1)
    46  	dataHelper.verify(h2)
    47  
    48  	env.closeAllLedgersAndDrop(rebuildableStatedb + rebuildableBlockIndex + rebuildableConfigHistory + rebuildableHistoryDB)
    49  	h1, h2 = env.newTestHelperOpenLgr("ledger1", t), env.newTestHelperOpenLgr("ledger2", t)
    50  	dataHelper.verify(h1)
    51  	dataHelper.verify(h2)
    52  }
    53  
    54  // TestV13WithStateCouchdb tests that a ledgersData folder and couchdb data created by v1.3 can be read by latest fabric version in a backward compatible way
    55  // The test data was generated by v1.3 code https://gerrit.hyperledger.org/r/#/c/fabric/+/34078/3/core/ledger/kvledger/tests/v13_generate_test.go@60
    56  func TestV13WithStateCouchdb(t *testing.T) {
    57  	env := newEnv(t)
    58  	defer env.cleanup()
    59  
    60  	ledgerFSRoot := env.initializer.Config.RootFSPath
    61  	// pass false so that 'ledgersData' directory will not be created when unzipped to ledgerFSRoot
    62  	require.NoError(t, testutil.Unzip("testdata/v13_statecouchdb/sample_ledgers/ledgersData.zip", ledgerFSRoot, false))
    63  
    64  	// unzip couchdb data to prepare the mount dir
    65  	couchdbDataUnzipDir := filepath.Join(ledgerFSRoot, "couchdbData")
    66  	require.NoError(t, os.Mkdir(couchdbDataUnzipDir, os.ModePerm))
    67  	require.NoError(t, testutil.Unzip("testdata/v13_statecouchdb/sample_ledgers/couchdbData.zip", couchdbDataUnzipDir, false))
    68  
    69  	// prepare the local.d mount dir to overwrite the number of shards and nodes so that they match the couchdb data generated from v1.3
    70  	localdHostDir := filepath.Join(ledgerFSRoot, "local.d")
    71  	require.NoError(t, os.MkdirAll(localdHostDir, os.ModePerm))
    72  	testutil.CopyDir("testdata/v13_statecouchdb/couchdb_etc/local.d", localdHostDir, true)
    73  
    74  	// start couchdb using couchdbDataUnzipDir and localdHostDir as mount dirs
    75  	couchAddress, cleanup := couchdbtest.CouchDBSetup(couchdbDataUnzipDir, localdHostDir)
    76  	defer cleanup()
    77  
    78  	// set required config data to use state couchdb
    79  	couchdbConfig := &couchdb.Config{
    80  		Address:             couchAddress,
    81  		Username:            "",
    82  		Password:            "",
    83  		MaxRetries:          3,
    84  		MaxRetriesOnStartup: 3,
    85  		RequestTimeout:      10 * time.Second,
    86  		RedoLogPath:         filepath.Join(ledgerFSRoot, "couchdbRedoLogs"),
    87  	}
    88  	env.initializer.Config.StateDBConfig.StateDatabase = "CouchDB"
    89  	env.initializer.Config.StateDBConfig.CouchDB = couchdbConfig
    90  	env.initializer.HealthCheckRegistry = &mock.HealthCheckRegistry{}
    91  	env.initializer.ChaincodeLifecycleEventProvider = &mock.ChaincodeLifecycleEventProvider{}
    92  
    93  	// verify init ledger panic and drop the corresponding db after each panic
    94  	checkInitLedgerPanicAndDropDBs(t, env, ledgerFSRoot, couchdbConfig)
    95  
    96  	t.Logf("All stores are reformatted/dropped, now ledgermgmt initialization should not panic")
    97  	env.initLedgerMgmt()
    98  
    99  	h1, h2 := env.newTestHelperOpenLgr("ledger1", t), env.newTestHelperOpenLgr("ledger2", t)
   100  	dataHelper := &v1xSampleDataHelper{sampleDataVersion: "v1.3", t: t}
   101  
   102  	dataHelper.verify(h1)
   103  	dataHelper.verify(h2)
   104  
   105  	// drop couchDB and other rebuildable dbs to test db rebuild
   106  	dropCouchDBs(t, couchdbConfig)
   107  	env.closeAllLedgersAndDrop(rebuildableBlockIndex + rebuildableConfigHistory + rebuildableHistoryDB)
   108  	h1, h2 = env.newTestHelperOpenLgr("ledger1", t), env.newTestHelperOpenLgr("ledger2", t)
   109  	dataHelper.verify(h1)
   110  	dataHelper.verify(h2)
   111  }
   112  
   113  func checkInitLedgerPanicAndDropDBs(t *testing.T, env *env, ledgerFSRoot string, couchdbConfig *couchdb.Config) {
   114  	t.Logf("verifying that a panic occurs because idStore has old format and then reformat the idstore to proceed")
   115  	idStorePath := kvledger.LedgerProviderPath(ledgerFSRoot)
   116  	require.PanicsWithValue(
   117  		t,
   118  		fmt.Sprintf("Error in instantiating ledger provider: unexpected format. db info = [leveldb for channel-IDs at [%s]], data format = [], expected format = [2.0]",
   119  			idStorePath),
   120  		func() { env.initLedgerMgmt() },
   121  		"A panic should occur because idstore is in format 1.x",
   122  	)
   123  	require.NoError(t, kvledger.UpgradeIDStoreFormat(ledgerFSRoot))
   124  
   125  	t.Logf("verifying that a panic occurs because blockstore index has old format and then drop the idstore to proceed")
   126  	blkIndexPath := path.Join(kvledger.BlockStorePath(ledgerFSRoot), "index")
   127  	require.PanicsWithValue(
   128  		t,
   129  		fmt.Sprintf("Error in instantiating ledger provider: unexpected format. db info = [leveldb at [%s]], data format = [], expected format = [2.0]",
   130  			blkIndexPath),
   131  		func() { env.initLedgerMgmt() },
   132  		"A panic should occur because block store index is in format 1.x",
   133  	)
   134  	require.NoError(t, os.RemoveAll(blkIndexPath))
   135  
   136  	t.Logf("verifying that a panic occurs because historydb has old format and then drop the historydb to proceed")
   137  	historyDBPath := kvledger.HistoryDBPath(ledgerFSRoot)
   138  	require.PanicsWithValue(
   139  		t,
   140  		fmt.Sprintf("Error in instantiating ledger provider: unexpected format. db info = [leveldb at [%s]], data format = [], expected format = [2.0]",
   141  			historyDBPath),
   142  		func() { env.initLedgerMgmt() },
   143  		"A panic should occur because history is in format 1.x",
   144  	)
   145  	require.NoError(t, os.RemoveAll(historyDBPath))
   146  
   147  	if couchdbConfig == nil {
   148  		t.Logf("verifying that a panic occurs because stateleveldb has old format and then drop the statedb to proceed")
   149  		stateLevelDBPath := kvledger.StateDBPath(ledgerFSRoot)
   150  		require.PanicsWithValue(
   151  			t,
   152  			fmt.Sprintf(
   153  				"Error in instantiating ledger provider: unexpected format. db info = [leveldb at [%s]], data format = [], expected format = [2.0]",
   154  				stateLevelDBPath,
   155  			),
   156  			func() { env.initLedgerMgmt() },
   157  			"A panic should occur because statedb is in format 1.x",
   158  		)
   159  		require.NoError(t, os.RemoveAll(stateLevelDBPath))
   160  	} else {
   161  		t.Logf("verifying that a panic occurs because statecouchdb has old format and then drop the statedb to proceed")
   162  		require.PanicsWithValue(
   163  			t,
   164  			fmt.Sprintf(
   165  				"Error in instantiating ledger provider: unexpected format. db info = [CouchDB for state database], data format = [], expected format = [2.0]"),
   166  			func() { env.initLedgerMgmt() },
   167  			"A panic should occur because statedb is in format 1.x",
   168  		)
   169  		dropCouchDBs(t, couchdbConfig)
   170  	}
   171  }
   172  
   173  // v1xSampleDataHelper provides a set of functions to verify the ledger (after upgraded to latest data format).
   174  // It verifies the ledger under the assumption that the ledger was generated by the specific generation code from v1.1 or v1.3.
   175  // For v1.1, the sample ledger data was generated by https://github.com/hyperledger/fabric/blob/release-1.1/core/ledger/kvledger/tests/v11_generate_test.go#L22
   176  // This generate function constructed two ledgers and populateed the ledgers using this code
   177  // (https://github.com/hyperledger/fabric/blob/release-1.1/core/ledger/kvledger/tests/sample_data_helper.go#L55)
   178  // For v1.3, the sample ledger data was generated by CR (https://gerrit.hyperledger.org/r/#/c/fabric/+/34078/3/core/ledger/kvledger/tests/v13_generate_test.go@60).
   179  // This generate function constructed two ledgers and populated the ledgers using this code
   180  // (https://github.com/hyperledger/fabric/blob/release-1.3/core/ledger/kvledger/tests/sample_data_helper.go#L55)
   181  type v1xSampleDataHelper struct {
   182  	sampleDataVersion string
   183  	t                 *testing.T
   184  }
   185  
   186  func (d *v1xSampleDataHelper) verify(h *testhelper) {
   187  	d.verifyState(h)
   188  	d.verifyBlockAndPvtdata(h)
   189  	d.verifyGetTransactionByID(h)
   190  	d.verifyConfigHistory(h)
   191  	d.verifyHistory(h)
   192  }
   193  
   194  func (d *v1xSampleDataHelper) verifyState(h *testhelper) {
   195  	lgrid := h.lgrid
   196  	h.verifyPubState("cc1", "key1", d.sampleVal("value13", lgrid))
   197  	h.verifyPubState("cc1", "key2", "")
   198  	h.verifyPvtState("cc1", "coll1", "key3", d.sampleVal("value14", lgrid))
   199  	h.verifyPvtState("cc1", "coll1", "key4", "")
   200  	h.verifyPvtState("cc1", "coll2", "key3", d.sampleVal("value09", lgrid))
   201  	h.verifyPvtState("cc1", "coll2", "key4", d.sampleVal("value10", lgrid))
   202  
   203  	h.verifyPubState("cc2", "key1", d.sampleVal("value03", lgrid))
   204  	h.verifyPubState("cc2", "key2", d.sampleVal("value04", lgrid))
   205  	h.verifyPvtState("cc2", "coll1", "key3", d.sampleVal("value07", lgrid))
   206  	h.verifyPvtState("cc2", "coll1", "key4", d.sampleVal("value08", lgrid))
   207  	h.verifyPvtState("cc2", "coll2", "key3", d.sampleVal("value11", lgrid))
   208  	h.verifyPvtState("cc2", "coll2", "key4", d.sampleVal("value12", lgrid))
   209  }
   210  
   211  func (d *v1xSampleDataHelper) verifyHistory(h *testhelper) {
   212  	lgrid := h.lgrid
   213  	expectedHistoryCC1Key1 := []string{
   214  		d.sampleVal("value13", lgrid),
   215  		d.sampleVal("value01", lgrid),
   216  	}
   217  	h.verifyHistory("cc1", "key1", expectedHistoryCC1Key1)
   218  }
   219  
   220  func (d *v1xSampleDataHelper) verifyConfigHistory(h *testhelper) {
   221  	lgrid := h.lgrid
   222  	h.verifyMostRecentCollectionConfigBelow(10, "cc1",
   223  		&expectedCollConfInfo{5, d.sampleCollConf2(lgrid, "cc1")})
   224  
   225  	h.verifyMostRecentCollectionConfigBelow(5, "cc1",
   226  		&expectedCollConfInfo{3, d.sampleCollConf1(lgrid, "cc1")})
   227  
   228  	h.verifyMostRecentCollectionConfigBelow(10, "cc2",
   229  		&expectedCollConfInfo{5, d.sampleCollConf2(lgrid, "cc2")})
   230  
   231  	h.verifyMostRecentCollectionConfigBelow(5, "cc2",
   232  		&expectedCollConfInfo{3, d.sampleCollConf1(lgrid, "cc2")})
   233  }
   234  
   235  func (d *v1xSampleDataHelper) verifyConfigHistoryDoesNotExist(h *testhelper) {
   236  	h.verifyMostRecentCollectionConfigBelow(10, "cc1", nil)
   237  	h.verifyMostRecentCollectionConfigBelow(10, "cc2", nil)
   238  }
   239  
   240  func (d *v1xSampleDataHelper) verifyBlockAndPvtdata(h *testhelper) {
   241  	lgrid := h.lgrid
   242  	h.verifyBlockAndPvtData(2, nil, func(r *retrievedBlockAndPvtdata) {
   243  		r.hasNumTx(2)
   244  		r.hasNoPvtdata()
   245  	})
   246  
   247  	h.verifyBlockAndPvtData(4, nil, func(r *retrievedBlockAndPvtdata) {
   248  		r.hasNumTx(2)
   249  		r.pvtdataShouldContain(0, "cc1", "coll1", "key3", d.sampleVal("value05", lgrid))
   250  		r.pvtdataShouldContain(1, "cc2", "coll1", "key3", d.sampleVal("value07", lgrid))
   251  	})
   252  }
   253  
   254  func (d *v1xSampleDataHelper) verifyGetTransactionByID(h *testhelper) {
   255  	h.verifyTxValidationCode("txid7", protopeer.TxValidationCode_VALID)
   256  	h.verifyTxValidationCode("txid8", protopeer.TxValidationCode_MVCC_READ_CONFLICT)
   257  }
   258  
   259  func (d *v1xSampleDataHelper) sampleVal(val, ledgerid string) string {
   260  	return fmt.Sprintf("%s:%s", val, ledgerid)
   261  }
   262  
   263  func (d *v1xSampleDataHelper) sampleCollConf1(ledgerid, ccName string) []*collConf {
   264  	switch d.sampleDataVersion {
   265  	case "v1.1":
   266  		return []*collConf{
   267  			{name: "coll1", members: []string{"org1", "org2"}},
   268  			{name: ledgerid, members: []string{"org1", "org2"}},
   269  			{name: ccName, members: []string{"org1", "org2"}},
   270  		}
   271  	case "v1.3":
   272  		return []*collConf{
   273  			{name: "coll1"},
   274  			{name: ledgerid},
   275  			{name: ccName},
   276  		}
   277  	default:
   278  		// should not happen
   279  		require.Failf(d.t, "sample data version %s is wrong", d.sampleDataVersion)
   280  		return nil
   281  	}
   282  }
   283  
   284  func (d *v1xSampleDataHelper) sampleCollConf2(ledgerid string, ccName string) []*collConf {
   285  	switch d.sampleDataVersion {
   286  	case "v1.1":
   287  		return []*collConf{
   288  			{name: "coll1", members: []string{"org1", "org2"}},
   289  			{name: "coll2", members: []string{"org1", "org2"}},
   290  			{name: ledgerid, members: []string{"org1", "org2"}},
   291  			{name: ccName, members: []string{"org1", "org2"}},
   292  		}
   293  	case "v1.3":
   294  		return []*collConf{
   295  			{name: "coll1"},
   296  			{name: "coll2"},
   297  			{name: ledgerid},
   298  			{name: ccName},
   299  		}
   300  	default:
   301  		// should not happen
   302  		require.Failf(d.t, "sample data version %s is wrong", d.sampleDataVersion)
   303  		return nil
   304  	}
   305  }