github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/ledger/kvledger/txmgmt/privacyenabledstate/db_test.go (about)

     1  /*
     2  Copyright hechain. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package privacyenabledstate
     8  
     9  import (
    10  	"crypto/rand"
    11  	"encoding/hex"
    12  	"fmt"
    13  	"io"
    14  	"testing"
    15  
    16  	"github.com/hechain20/hechain/common/ledger/testutil"
    17  	"github.com/hechain20/hechain/core/common/ccprovider"
    18  	"github.com/hechain20/hechain/core/ledger/cceventmgmt"
    19  	"github.com/hechain20/hechain/core/ledger/internal/version"
    20  	testmock "github.com/hechain20/hechain/core/ledger/kvledger/txmgmt/privacyenabledstate/mock"
    21  	"github.com/hechain20/hechain/core/ledger/kvledger/txmgmt/statedb"
    22  	"github.com/hechain20/hechain/core/ledger/kvledger/txmgmt/statedb/statecouchdb"
    23  	"github.com/hechain20/hechain/core/ledger/kvledger/txmgmt/statedb/stateleveldb"
    24  	"github.com/hechain20/hechain/core/ledger/mock"
    25  	"github.com/hechain20/hechain/core/ledger/util"
    26  	"github.com/hyperledger/fabric-protos-go/peer"
    27  	"github.com/stretchr/testify/require"
    28  )
    29  
    30  func TestHealthCheckRegister(t *testing.T) {
    31  	fakeHealthCheckRegistry := &mock.HealthCheckRegistry{}
    32  	dbProvider := &DBProvider{
    33  		VersionedDBProvider: &stateleveldb.VersionedDBProvider{},
    34  		HealthCheckRegistry: fakeHealthCheckRegistry,
    35  	}
    36  
    37  	err := dbProvider.RegisterHealthChecker()
    38  	require.NoError(t, err)
    39  	require.Equal(t, 0, fakeHealthCheckRegistry.RegisterCheckerCallCount())
    40  
    41  	dbProvider.VersionedDBProvider = &statecouchdb.VersionedDBProvider{}
    42  	err = dbProvider.RegisterHealthChecker()
    43  	require.NoError(t, err)
    44  	require.Equal(t, 1, fakeHealthCheckRegistry.RegisterCheckerCallCount())
    45  
    46  	arg1, arg2 := fakeHealthCheckRegistry.RegisterCheckerArgsForCall(0)
    47  	require.Equal(t, "couchdb", arg1)
    48  	require.NotNil(t, arg2)
    49  }
    50  
    51  func TestGetIndexInfo(t *testing.T) {
    52  	chaincodeIndexPath := "META-INF/statedb/couchdb/indexes"
    53  	actualIndexInfo := getIndexInfo(chaincodeIndexPath)
    54  	expectedIndexInfo := &indexInfo{
    55  		hasIndexForChaincode:  true,
    56  		hasIndexForCollection: false,
    57  		collectionName:        "",
    58  	}
    59  	require.Equal(t, expectedIndexInfo, actualIndexInfo)
    60  
    61  	collectionIndexPath := "META-INF/statedb/couchdb/collections/collectionMarbles/indexes"
    62  	actualIndexInfo = getIndexInfo(collectionIndexPath)
    63  	expectedIndexInfo = &indexInfo{
    64  		hasIndexForChaincode:  false,
    65  		hasIndexForCollection: true,
    66  		collectionName:        "collectionMarbles",
    67  	}
    68  	require.Equal(t, expectedIndexInfo, actualIndexInfo)
    69  
    70  	incorrectChaincodeIndexPath := "META-INF/statedb/couchdb"
    71  	actualIndexInfo = getIndexInfo(incorrectChaincodeIndexPath)
    72  	expectedIndexInfo = &indexInfo{
    73  		hasIndexForChaincode:  false,
    74  		hasIndexForCollection: false,
    75  		collectionName:        "",
    76  	}
    77  	require.Equal(t, expectedIndexInfo, actualIndexInfo)
    78  
    79  	incorrectCollectionIndexPath := "META-INF/statedb/couchdb/collections/indexes"
    80  	actualIndexInfo = getIndexInfo(incorrectCollectionIndexPath)
    81  	require.Equal(t, expectedIndexInfo, actualIndexInfo)
    82  
    83  	incorrectCollectionIndexPath = "META-INF/statedb/couchdb/collections"
    84  	actualIndexInfo = getIndexInfo(incorrectCollectionIndexPath)
    85  	require.Equal(t, expectedIndexInfo, actualIndexInfo)
    86  
    87  	incorrectIndexPath := "META-INF/statedb"
    88  	actualIndexInfo = getIndexInfo(incorrectIndexPath)
    89  	require.Equal(t, expectedIndexInfo, actualIndexInfo)
    90  }
    91  
    92  func TestDB(t *testing.T) {
    93  	for _, env := range testEnvs {
    94  		t.Run(env.GetName(), func(t *testing.T) {
    95  			testDB(t, env)
    96  		})
    97  	}
    98  }
    99  
   100  func testDB(t *testing.T, env TestEnv) {
   101  	env.Init(t)
   102  	defer env.Cleanup()
   103  	db := env.GetDBHandle(generateLedgerID(t))
   104  
   105  	updates := NewUpdateBatch()
   106  
   107  	updates.PubUpdates.Put("ns1", "key1", []byte("value1"), version.NewHeight(1, 1))
   108  	updates.PubUpdates.Put("ns1", "key2", []byte("value2"), version.NewHeight(1, 2))
   109  	updates.PubUpdates.Put("ns2", "key3", []byte("value3"), version.NewHeight(1, 3))
   110  
   111  	putPvtUpdates(t, updates, "ns1", "coll1", "key1", []byte("pvt_value1"), version.NewHeight(1, 4))
   112  	putPvtUpdates(t, updates, "ns1", "coll1", "key2", []byte("pvt_value2"), version.NewHeight(1, 5))
   113  	putPvtUpdates(t, updates, "ns2", "coll1", "key3", []byte("pvt_value3"), version.NewHeight(1, 6))
   114  	require.NoError(t, db.ApplyPrivacyAwareUpdates(updates, version.NewHeight(2, 6)))
   115  	bulkOptimizable, ok := db.VersionedDB.(statedb.BulkOptimizable)
   116  	if ok {
   117  		bulkOptimizable.ClearCachedVersions()
   118  	}
   119  
   120  	vv, err := db.GetState("ns1", "key1")
   121  	require.NoError(t, err)
   122  	require.Equal(t, &statedb.VersionedValue{Value: []byte("value1"), Version: version.NewHeight(1, 1)}, vv)
   123  
   124  	vv, err = db.GetPrivateData("ns1", "coll1", "key1")
   125  	require.NoError(t, err)
   126  	require.Equal(t, &statedb.VersionedValue{Value: []byte("pvt_value1"), Version: version.NewHeight(1, 4)}, vv)
   127  
   128  	vv, err = db.GetPrivateDataHash("ns1", "coll1", "key1")
   129  	require.NoError(t, err)
   130  	require.Equal(t, &statedb.VersionedValue{Value: util.ComputeStringHash("pvt_value1"), Version: version.NewHeight(1, 4)}, vv)
   131  
   132  	vv, err = db.GetValueHash("ns1", "coll1", util.ComputeStringHash("key1"))
   133  	require.NoError(t, err)
   134  	require.Equal(t, &statedb.VersionedValue{Value: util.ComputeStringHash("pvt_value1"), Version: version.NewHeight(1, 4)}, vv)
   135  
   136  	committedVersion, err := db.GetKeyHashVersion("ns1", "coll1", util.ComputeStringHash("key1"))
   137  	require.NoError(t, err)
   138  	require.Equal(t, version.NewHeight(1, 4), committedVersion)
   139  
   140  	updates = NewUpdateBatch()
   141  	updates.PubUpdates.Delete("ns1", "key1", version.NewHeight(2, 7))
   142  	deletePvtUpdates(t, updates, "ns1", "coll1", "key1", version.NewHeight(2, 7))
   143  	require.NoError(t, db.ApplyPrivacyAwareUpdates(updates, version.NewHeight(2, 7)))
   144  
   145  	vv, err = db.GetState("ns1", "key1")
   146  	require.NoError(t, err)
   147  	require.Nil(t, vv)
   148  
   149  	vv, err = db.GetPrivateData("ns1", "coll1", "key1")
   150  	require.NoError(t, err)
   151  	require.Nil(t, vv)
   152  
   153  	vv, err = db.GetValueHash("ns1", "coll1", util.ComputeStringHash("key1"))
   154  	require.NoError(t, err)
   155  	require.Nil(t, vv)
   156  }
   157  
   158  func TestGetStateMultipleKeys(t *testing.T) {
   159  	for _, env := range testEnvs {
   160  		t.Run(env.GetName(), func(t *testing.T) {
   161  			testGetStateMultipleKeys(t, env)
   162  		})
   163  	}
   164  }
   165  
   166  func testGetStateMultipleKeys(t *testing.T, env TestEnv) {
   167  	env.Init(t)
   168  	defer env.Cleanup()
   169  	db := env.GetDBHandle(generateLedgerID(t))
   170  
   171  	updates := NewUpdateBatch()
   172  
   173  	updates.PubUpdates.Put("ns1", "key1", []byte("value1"), version.NewHeight(1, 1))
   174  	updates.PubUpdates.Put("ns1", "key2", []byte("value2"), version.NewHeight(1, 2))
   175  	updates.PubUpdates.Put("ns1", "key3", []byte("value3"), version.NewHeight(1, 3))
   176  
   177  	putPvtUpdates(t, updates, "ns1", "coll1", "key1", []byte("pvt_value1"), version.NewHeight(1, 4))
   178  	putPvtUpdates(t, updates, "ns1", "coll1", "key2", []byte("pvt_value2"), version.NewHeight(1, 5))
   179  	putPvtUpdates(t, updates, "ns1", "coll1", "key3", []byte("pvt_value3"), version.NewHeight(1, 6))
   180  	require.NoError(t, db.ApplyPrivacyAwareUpdates(updates, version.NewHeight(2, 6)))
   181  
   182  	versionedVals, err := db.GetStateMultipleKeys("ns1", []string{"key1", "key3"})
   183  	require.NoError(t, err)
   184  	require.Equal(t,
   185  		[]*statedb.VersionedValue{
   186  			{Value: []byte("value1"), Version: version.NewHeight(1, 1)},
   187  			{Value: []byte("value3"), Version: version.NewHeight(1, 3)},
   188  		},
   189  		versionedVals)
   190  
   191  	pvtVersionedVals, err := db.GetPrivateDataMultipleKeys("ns1", "coll1", []string{"key1", "key3"})
   192  	require.NoError(t, err)
   193  	require.Equal(t,
   194  		[]*statedb.VersionedValue{
   195  			{Value: []byte("pvt_value1"), Version: version.NewHeight(1, 4)},
   196  			{Value: []byte("pvt_value3"), Version: version.NewHeight(1, 6)},
   197  		},
   198  		pvtVersionedVals)
   199  }
   200  
   201  func TestGetStateRangeScanIterator(t *testing.T) {
   202  	for _, env := range testEnvs {
   203  		t.Run(env.GetName(), func(t *testing.T) {
   204  			testGetStateRangeScanIterator(t, env)
   205  		})
   206  	}
   207  }
   208  
   209  func testGetStateRangeScanIterator(t *testing.T, env TestEnv) {
   210  	env.Init(t)
   211  	defer env.Cleanup()
   212  	db := env.GetDBHandle(generateLedgerID(t))
   213  
   214  	updates := NewUpdateBatch()
   215  
   216  	updates.PubUpdates.Put("ns1", "key1", []byte("value1"), version.NewHeight(1, 1))
   217  	updates.PubUpdates.Put("ns1", "key2", []byte("value2"), version.NewHeight(1, 2))
   218  	updates.PubUpdates.Put("ns1", "key3", []byte("value3"), version.NewHeight(1, 3))
   219  	updates.PubUpdates.Put("ns1", "key4", []byte("value4"), version.NewHeight(1, 4))
   220  	updates.PubUpdates.Put("ns2", "key5", []byte("value5"), version.NewHeight(1, 5))
   221  	updates.PubUpdates.Put("ns2", "key6", []byte("value6"), version.NewHeight(1, 6))
   222  	updates.PubUpdates.Put("ns3", "key7", []byte("value7"), version.NewHeight(1, 7))
   223  
   224  	putPvtUpdates(t, updates, "ns1", "coll1", "key1", []byte("pvt_value1"), version.NewHeight(1, 1))
   225  	putPvtUpdates(t, updates, "ns1", "coll1", "key2", []byte("pvt_value2"), version.NewHeight(1, 2))
   226  	putPvtUpdates(t, updates, "ns1", "coll1", "key3", []byte("pvt_value3"), version.NewHeight(1, 3))
   227  	putPvtUpdates(t, updates, "ns1", "coll1", "key4", []byte("pvt_value4"), version.NewHeight(1, 4))
   228  	putPvtUpdates(t, updates, "ns2", "coll1", "key5", []byte("pvt_value5"), version.NewHeight(1, 5))
   229  	putPvtUpdates(t, updates, "ns2", "coll1", "key6", []byte("pvt_value6"), version.NewHeight(1, 6))
   230  	putPvtUpdates(t, updates, "ns3", "coll1", "key7", []byte("pvt_value7"), version.NewHeight(1, 7))
   231  	require.NoError(t, db.ApplyPrivacyAwareUpdates(updates, version.NewHeight(2, 7)))
   232  
   233  	itr1, _ := db.GetStateRangeScanIterator("ns1", "key1", "")
   234  	testItr(t, itr1, []string{"key1", "key2", "key3", "key4"})
   235  
   236  	itr2, _ := db.GetStateRangeScanIterator("ns1", "key2", "key3")
   237  	testItr(t, itr2, []string{"key2"})
   238  
   239  	itr3, _ := db.GetStateRangeScanIterator("ns1", "", "")
   240  	testItr(t, itr3, []string{"key1", "key2", "key3", "key4"})
   241  
   242  	itr4, _ := db.GetStateRangeScanIterator("ns2", "", "")
   243  	testItr(t, itr4, []string{"key5", "key6"})
   244  
   245  	pvtItr1, _ := db.GetPrivateDataRangeScanIterator("ns1", "coll1", "key1", "")
   246  	testItr(t, pvtItr1, []string{"key1", "key2", "key3", "key4"})
   247  
   248  	pvtItr2, _ := db.GetPrivateDataRangeScanIterator("ns1", "coll1", "key2", "key3")
   249  	testItr(t, pvtItr2, []string{"key2"})
   250  
   251  	pvtItr3, _ := db.GetPrivateDataRangeScanIterator("ns1", "coll1", "", "")
   252  	testItr(t, pvtItr3, []string{"key1", "key2", "key3", "key4"})
   253  
   254  	pvtItr4, _ := db.GetPrivateDataRangeScanIterator("ns2", "coll1", "", "")
   255  	testItr(t, pvtItr4, []string{"key5", "key6"})
   256  }
   257  
   258  func TestQueryOnCouchDB(t *testing.T) {
   259  	for _, env := range testEnvs {
   260  		_, ok := env.(*CouchDBTestEnv)
   261  		if !ok {
   262  			continue
   263  		}
   264  		t.Run(env.GetName(), func(t *testing.T) {
   265  			testQueryOnCouchDB(t, env)
   266  		})
   267  	}
   268  }
   269  
   270  func testQueryOnCouchDB(t *testing.T, env TestEnv) {
   271  	env.Init(t)
   272  	defer env.Cleanup()
   273  	db := env.GetDBHandle(generateLedgerID(t))
   274  	updates := NewUpdateBatch()
   275  
   276  	jsonValues := []string{
   277  		`{"asset_name": "marble1", "color": "blue", "size": 1, "owner": "tom"}`,
   278  		`{"asset_name": "marble2","color": "blue","size": 2,"owner": "jerry"}`,
   279  		`{"asset_name": "marble3","color": "blue","size": 3,"owner": "fred"}`,
   280  		`{"asset_name": "marble4","color": "blue","size": 4,"owner": "martha"}`,
   281  		`{"asset_name": "marble5","color": "blue","size": 5,"owner": "fred"}`,
   282  		`{"asset_name": "marble6","color": "blue","size": 6,"owner": "elaine"}`,
   283  		`{"asset_name": "marble7","color": "blue","size": 7,"owner": "fred"}`,
   284  		`{"asset_name": "marble8","color": "blue","size": 8,"owner": "elaine"}`,
   285  		`{"asset_name": "marble9","color": "green","size": 9,"owner": "fred"}`,
   286  		`{"asset_name": "marble10","color": "green","size": 10,"owner": "mary"}`,
   287  		`{"asset_name": "marble11","color": "cyan","size": 1000007,"owner": "joe"}`,
   288  	}
   289  
   290  	for i, jsonValue := range jsonValues {
   291  		updates.PubUpdates.Put("ns1", testKey(i), []byte(jsonValue), version.NewHeight(1, uint64(i)))
   292  		updates.PubUpdates.Put("ns2", testKey(i), []byte(jsonValue), version.NewHeight(1, uint64(i)))
   293  		putPvtUpdates(t, updates, "ns1", "coll1", testKey(i), []byte(jsonValue), version.NewHeight(1, uint64(i)))
   294  		putPvtUpdates(t, updates, "ns2", "coll1", testKey(i), []byte(jsonValue), version.NewHeight(1, uint64(i)))
   295  	}
   296  	require.NoError(t, db.ApplyPrivacyAwareUpdates(updates, version.NewHeight(1, 11)))
   297  
   298  	// query for owner=jerry, use namespace "ns1"
   299  	itr, err := db.ExecuteQuery("ns1", `{"selector":{"owner":"jerry"}}`)
   300  	require.NoError(t, err)
   301  	testQueryItr(t, itr, []string{testKey(1)}, []string{"jerry"})
   302  
   303  	// query for owner=jerry, use namespace "ns2"
   304  	itr, err = db.ExecuteQuery("ns2", `{"selector":{"owner":"jerry"}}`)
   305  	require.NoError(t, err)
   306  	testQueryItr(t, itr, []string{testKey(1)}, []string{"jerry"})
   307  
   308  	// query for pvt data owner=jerry, use namespace "ns1"
   309  	itr, err = db.ExecuteQueryOnPrivateData("ns1", "coll1", `{"selector":{"owner":"jerry"}}`)
   310  	require.NoError(t, err)
   311  	testQueryItr(t, itr, []string{testKey(1)}, []string{"jerry"})
   312  
   313  	// query for pvt data owner=jerry, use namespace "ns2"
   314  	itr, err = db.ExecuteQueryOnPrivateData("ns2", "coll1", `{"selector":{"owner":"jerry"}}`)
   315  	require.NoError(t, err)
   316  	testQueryItr(t, itr, []string{testKey(1)}, []string{"jerry"})
   317  
   318  	// query using bad query string
   319  	_, err = db.ExecuteQueryOnPrivateData("ns1", "coll1", "this is an invalid query string")
   320  	require.Error(t, err, "Should have received an error for invalid query string")
   321  
   322  	// query returns 0 records
   323  	itr, err = db.ExecuteQueryOnPrivateData("ns1", "coll1", `{"selector":{"owner":"not_a_valid_name"}}`)
   324  	require.NoError(t, err)
   325  	testQueryItr(t, itr, []string{}, []string{})
   326  
   327  	// query with embedded implicit "AND" and explicit "OR", namespace "ns1"
   328  	itr, err = db.ExecuteQueryOnPrivateData("ns1", "coll1", `{"selector":{"color":"green","$or":[{"owner":"fred"},{"owner":"mary"}]}}`)
   329  	require.NoError(t, err)
   330  	testQueryItr(t, itr, []string{testKey(8), testKey(9)}, []string{"green"}, []string{"green"})
   331  
   332  	// query with integer with digit-count equals 7 and response received is also received
   333  	// with same digit-count and there is no float transformation
   334  	itr, err = db.ExecuteQueryOnPrivateData("ns2", "coll1", `{"selector":{"$and":[{"size":{"$eq": 1000007}}]}}`)
   335  	require.NoError(t, err)
   336  	testQueryItr(t, itr, []string{testKey(10)}, []string{"joe", "1000007"})
   337  }
   338  
   339  func TestLongDBNameOnCouchDB(t *testing.T) {
   340  	for _, env := range testEnvs {
   341  		_, ok := env.(*CouchDBTestEnv)
   342  		if !ok {
   343  			continue
   344  		}
   345  		t.Run(env.GetName(), func(t *testing.T) {
   346  			testLongDBNameOnCouchDB(t, env)
   347  		})
   348  	}
   349  }
   350  
   351  func testLongDBNameOnCouchDB(t *testing.T, env TestEnv) {
   352  	env.Init(t)
   353  	defer env.Cleanup()
   354  
   355  	// Creates metadataDB (i.e., chainDB)
   356  	// Allowed pattern for chainName: [a-z][a-z0-9.-]
   357  	db := env.GetDBHandle("w1coaii9ck3l8red6a5cf3rwbe1b4wvbzcrrfl7samu7px8b9gf-4hft7wrgdmzzjj9ure4cbffucaj78nbj9ej.kvl3bus1iq1qir9xlhb8a1wipuksgs3g621elzy1prr658087exwrhp-y4j55o9cld242v--oeh3br1g7m8d6l8jobn.y42cgjt1.u1ik8qxnv4ohh9kr2w2zc8hqir5u4ev23s7jygrg....s7.ohp-5bcxari8nji")
   358  
   359  	updates := NewUpdateBatch()
   360  
   361  	// Allowed pattern for namespace and collection: [a-zA-Z0-9_-]
   362  	ns := "wMCnSXiV9YoIqNQyNvFVTdM8XnUtvrOFFIWsKelmP5NEszmNLl8YhtOKbFu3P_NgwgsYF8PsfwjYCD8f1XRpANQLoErDHwLlweryqXeJ6vzT2x0pS_GwSx0m6tBI0zOmHQOq_2De8A87x6zUOPwufC2T6dkidFxiuq8Sey2-5vUo_iNKCij3WTeCnKx78PUIg_U1gp4_0KTvYVtRBRvH0kz5usizBxPaiFu3TPhB9XLviScvdUVSbSYJ0Z"
   363  	coll := "vWjtfSTXVK8WJus5s6zWoMIciXd7qHRZIusF9SkOS6m8XuHCiJDE9cCRuVerq22Na8qBL2ywDGFpVMIuzfyEXLjeJb0mMuH4cwewT6r1INOTOSYwrikwOLlT_fl0V1L7IQEwUBB8WCvRqSdj6j5-E5aGul_pv_0UeCdwWiyA_GrZmP7ocLzfj2vP8btigrajqdH-irLO2ydEjQUAvf8fiuxru9la402KmKRy457GgI98UHoUdqV3f3FCdR"
   364  
   365  	updates.PubUpdates.Put(ns, "key1", []byte("value1"), version.NewHeight(1, 1))
   366  	updates.PvtUpdates.Put(ns, coll, "key1", []byte("pvt_value"), version.NewHeight(1, 2))
   367  	updates.HashUpdates.Put(ns, coll, util.ComputeStringHash("key1"), util.ComputeHash([]byte("pvt_value")), version.NewHeight(1, 2))
   368  
   369  	require.NoError(t, db.ApplyPrivacyAwareUpdates(updates, version.NewHeight(2, 6)))
   370  
   371  	vv, err := db.GetState(ns, "key1")
   372  	require.NoError(t, err)
   373  	require.Equal(t, &statedb.VersionedValue{Value: []byte("value1"), Version: version.NewHeight(1, 1)}, vv)
   374  
   375  	vv, err = db.GetPrivateData(ns, coll, "key1")
   376  	require.NoError(t, err)
   377  	require.Equal(t, &statedb.VersionedValue{Value: []byte("pvt_value"), Version: version.NewHeight(1, 2)}, vv)
   378  }
   379  
   380  func testItr(t *testing.T, itr statedb.ResultsIterator, expectedKeys []string) {
   381  	defer itr.Close()
   382  	for _, expectedKey := range expectedKeys {
   383  		queryResult, err := itr.Next()
   384  		require.NoError(t, err)
   385  		require.Equal(t, expectedKey, queryResult.Key)
   386  	}
   387  	last, err := itr.Next()
   388  	require.NoError(t, err)
   389  	require.Nil(t, last)
   390  }
   391  
   392  func testQueryItr(t *testing.T, itr statedb.ResultsIterator, expectedKeys []string, expectedValStrs ...[]string) {
   393  	defer itr.Close()
   394  	for i, expectedKey := range expectedKeys {
   395  		queryResult, err := itr.Next()
   396  		require.NoError(t, err)
   397  		valStr := string(queryResult.Value)
   398  		require.Equal(t, expectedKey, queryResult.Key)
   399  		for _, expectedValStr := range expectedValStrs[i] {
   400  			require.Contains(t, valStr, expectedValStr)
   401  		}
   402  	}
   403  	last, err := itr.Next()
   404  	require.NoError(t, err)
   405  	require.Nil(t, last)
   406  }
   407  
   408  func testKey(i int) string {
   409  	return fmt.Sprintf("key%d", i)
   410  }
   411  
   412  func TestHandleChainCodeDeployOnCouchDB(t *testing.T) {
   413  	for _, env := range testEnvs {
   414  		_, ok := env.(*CouchDBTestEnv)
   415  		if !ok {
   416  			continue
   417  		}
   418  		t.Run(env.GetName(), func(t *testing.T) {
   419  			testHandleChainCodeDeploy(t, env)
   420  		})
   421  	}
   422  }
   423  
   424  func createCollectionConfig(collectionName string) *peer.CollectionConfig {
   425  	return &peer.CollectionConfig{
   426  		Payload: &peer.CollectionConfig_StaticCollectionConfig{
   427  			StaticCollectionConfig: &peer.StaticCollectionConfig{
   428  				Name:              collectionName,
   429  				MemberOrgsPolicy:  nil,
   430  				RequiredPeerCount: 0,
   431  				MaximumPeerCount:  0,
   432  				BlockToLive:       0,
   433  			},
   434  		},
   435  	}
   436  }
   437  
   438  func testHandleChainCodeDeploy(t *testing.T, env TestEnv) {
   439  	env.Init(t)
   440  	defer env.Cleanup()
   441  	db := env.GetDBHandle(generateLedgerID(t))
   442  
   443  	coll1 := createCollectionConfig("collectionMarbles")
   444  	ccp := &peer.CollectionConfigPackage{Config: []*peer.CollectionConfig{coll1}}
   445  	chaincodeDef := &cceventmgmt.ChaincodeDefinition{Name: "ns1", Hash: nil, Version: "", CollectionConfigs: ccp}
   446  
   447  	// Test indexes for side databases
   448  	dbArtifactsTarBytes := testutil.CreateTarBytesForTest(
   449  		[]*testutil.TarFileEntry{
   450  			{Name: "META-INF/statedb/couchdb/indexes/indexColorSortName.json", Body: `{"index":{"fields":[{"color":"desc"}]},"ddoc":"indexColorSortName","name":"indexColorSortName","type":"json"}`},
   451  			{Name: "META-INF/statedb/couchdb/indexes/indexSizeSortName.json", Body: `{"index":{"fields":[{"size":"desc"}]},"ddoc":"indexSizeSortName","name":"indexSizeSortName","type":"json"}`},
   452  			{Name: "META-INF/statedb/couchdb/collections/collectionMarbles/indexes/indexCollMarbles.json", Body: `{"index":{"fields":["docType","owner"]},"ddoc":"indexCollectionMarbles", "name":"indexCollectionMarbles","type":"json"}`},
   453  			{Name: "META-INF/statedb/couchdb/collections/collectionMarblesPrivateDetails/indexes/indexCollPrivDetails.json", Body: `{"index":{"fields":["docType","price"]},"ddoc":"indexPrivateDetails", "name":"indexPrivateDetails","type":"json"}`},
   454  		},
   455  	)
   456  
   457  	// Test the retrieveIndexArtifacts method
   458  	fileEntries, err := ccprovider.ExtractFileEntries(dbArtifactsTarBytes, "couchdb")
   459  	require.NoError(t, err)
   460  
   461  	// There should be 3 entries
   462  	require.Len(t, fileEntries, 3)
   463  
   464  	// There should be 2 entries for main
   465  	require.Len(t, fileEntries["META-INF/statedb/couchdb/indexes"], 2)
   466  
   467  	// There should be 1 entry for collectionMarbles
   468  	require.Len(t, fileEntries["META-INF/statedb/couchdb/collections/collectionMarbles/indexes"], 1)
   469  
   470  	// Verify the content of the array item
   471  	expectedJSON := []byte(`{"index":{"fields":["docType","owner"]},"ddoc":"indexCollectionMarbles", "name":"indexCollectionMarbles","type":"json"}`)
   472  	actualJSON := fileEntries["META-INF/statedb/couchdb/collections/collectionMarbles/indexes"][0].FileContent
   473  	require.Equal(t, expectedJSON, actualJSON)
   474  
   475  	// The collection config is added to the chaincodeDef but missing collectionMarblesPrivateDetails.
   476  	// Hence, the index on collectionMarblesPrivateDetails cannot be created
   477  	err = db.HandleChaincodeDeploy(chaincodeDef, dbArtifactsTarBytes)
   478  	require.NoError(t, err)
   479  
   480  	coll2 := createCollectionConfig("collectionMarblesPrivateDetails")
   481  	ccp = &peer.CollectionConfigPackage{Config: []*peer.CollectionConfig{coll1, coll2}}
   482  	chaincodeDef = &cceventmgmt.ChaincodeDefinition{Name: "ns1", Hash: nil, Version: "", CollectionConfigs: ccp}
   483  
   484  	// The collection config is added to the chaincodeDef and it contains all collections
   485  	// including collectionMarblesPrivateDetails which was missing earlier.
   486  	// Hence, the existing indexes must be updated and the new index must be created for
   487  	// collectionMarblesPrivateDetails
   488  	err = db.HandleChaincodeDeploy(chaincodeDef, dbArtifactsTarBytes)
   489  	require.NoError(t, err)
   490  
   491  	chaincodeDef = &cceventmgmt.ChaincodeDefinition{Name: "ns1", Hash: nil, Version: "", CollectionConfigs: nil}
   492  
   493  	// The collection config is not added to the chaincodeDef. In this case, the index creation
   494  	// process reads the collection config from state db. However, the state db does not contain
   495  	// any collection config for this chaincode. Hence, index creation/update on all collections
   496  	// should fail
   497  	err = db.HandleChaincodeDeploy(chaincodeDef, dbArtifactsTarBytes)
   498  	require.NoError(t, err)
   499  
   500  	// Test HandleChaincodeDefinition with a nil tar file
   501  	err = db.HandleChaincodeDeploy(chaincodeDef, nil)
   502  	require.NoError(t, err)
   503  
   504  	// Test HandleChaincodeDefinition with a bad tar file
   505  	err = db.HandleChaincodeDeploy(chaincodeDef, []byte(`This is a really bad tar file`))
   506  	require.NoError(t, err, "Error should not have been thrown for a bad tar file")
   507  
   508  	// Test HandleChaincodeDefinition with a nil chaincodeDef
   509  	err = db.HandleChaincodeDeploy(nil, dbArtifactsTarBytes)
   510  	require.Error(t, err, "Error should have been thrown for a nil chaincodeDefinition")
   511  
   512  	// Create a tar file for test with 2 index definitions - one of them being errorneous
   513  	badSyntaxFileContent := `{"index":{"fields": This is a bad json}`
   514  	dbArtifactsTarBytes = testutil.CreateTarBytesForTest(
   515  		[]*testutil.TarFileEntry{
   516  			{Name: "META-INF/statedb/couchdb/indexes/indexSizeSortName.json", Body: `{"index":{"fields":[{"size":"desc"}]},"ddoc":"indexSizeSortName","name":"indexSizeSortName","type":"json"}`},
   517  			{Name: "META-INF/statedb/couchdb/indexes/badSyntax.json", Body: badSyntaxFileContent},
   518  		},
   519  	)
   520  
   521  	// Test the retrieveIndexArtifacts method
   522  	fileEntries, err = ccprovider.ExtractFileEntries(dbArtifactsTarBytes, "couchdb")
   523  	require.NoError(t, err)
   524  
   525  	// There should be 1 entry
   526  	require.Len(t, fileEntries, 1)
   527  
   528  	err = db.HandleChaincodeDeploy(chaincodeDef, dbArtifactsTarBytes)
   529  	require.NoError(t, err)
   530  }
   531  
   532  func TestMetadataRetrieval(t *testing.T) {
   533  	for _, env := range testEnvs {
   534  		t.Run(env.GetName(), func(t *testing.T) {
   535  			testMetadataRetrieval(t, env)
   536  		})
   537  	}
   538  }
   539  
   540  func testMetadataRetrieval(t *testing.T, env TestEnv) {
   541  	env.Init(t)
   542  	defer env.Cleanup()
   543  	db := env.GetDBHandle(generateLedgerID(t))
   544  
   545  	updates := NewUpdateBatch()
   546  	updates.PubUpdates.PutValAndMetadata("ns1", "key1", []byte("value1"), []byte("metadata1"), version.NewHeight(1, 1))
   547  	updates.PubUpdates.PutValAndMetadata("ns1", "key2", []byte("value2"), nil, version.NewHeight(1, 2))
   548  	updates.PubUpdates.PutValAndMetadata("ns2", "key3", []byte("value3"), nil, version.NewHeight(1, 3))
   549  
   550  	putPvtUpdatesWithMetadata(t, updates, "ns1", "coll1", "key1", []byte("pvt_value1"), []byte("metadata1"), version.NewHeight(1, 4))
   551  	putPvtUpdatesWithMetadata(t, updates, "ns1", "coll1", "key2", []byte("pvt_value2"), nil, version.NewHeight(1, 5))
   552  	putPvtUpdatesWithMetadata(t, updates, "ns2", "coll1", "key3", []byte("pvt_value3"), nil, version.NewHeight(1, 6))
   553  	require.NoError(t, db.ApplyPrivacyAwareUpdates(updates, version.NewHeight(2, 6)))
   554  
   555  	vm, _ := db.GetStateMetadata("ns1", "key1")
   556  	require.Equal(t, vm, []byte("metadata1"))
   557  	vm, _ = db.GetStateMetadata("ns1", "key2")
   558  	require.Nil(t, vm)
   559  	vm, _ = db.GetStateMetadata("ns2", "key3")
   560  	require.Nil(t, vm)
   561  
   562  	vm, _ = db.GetPrivateDataMetadataByHash("ns1", "coll1", util.ComputeStringHash("key1"))
   563  	require.Equal(t, vm, []byte("metadata1"))
   564  	vm, _ = db.GetPrivateDataMetadataByHash("ns1", "coll1", util.ComputeStringHash("key2"))
   565  	require.Nil(t, vm)
   566  	vm, _ = db.GetPrivateDataMetadataByHash("ns2", "coll1", util.ComputeStringHash("key3"))
   567  	require.Nil(t, vm)
   568  }
   569  
   570  func putPvtUpdates(t *testing.T, updates *UpdateBatch, ns, coll, key string, value []byte, ver *version.Height) {
   571  	updates.PvtUpdates.Put(ns, coll, key, value, ver)
   572  	updates.HashUpdates.Put(ns, coll, util.ComputeStringHash(key), util.ComputeHash(value), ver)
   573  }
   574  
   575  func putPvtUpdatesWithMetadata(t *testing.T, updates *UpdateBatch, ns, coll, key string, value []byte, metadata []byte, ver *version.Height) {
   576  	updates.PvtUpdates.Put(ns, coll, key, value, ver)
   577  	updates.HashUpdates.PutValHashAndMetadata(ns, coll, util.ComputeStringHash(key), util.ComputeHash(value), metadata, ver)
   578  }
   579  
   580  func deletePvtUpdates(t *testing.T, updates *UpdateBatch, ns, coll, key string, ver *version.Height) {
   581  	updates.PvtUpdates.Delete(ns, coll, key, ver)
   582  	updates.HashUpdates.Delete(ns, coll, util.ComputeStringHash(key), ver)
   583  }
   584  
   585  func generateLedgerID(t *testing.T) string {
   586  	bytes := make([]byte, 8)
   587  	_, err := io.ReadFull(rand.Reader, bytes)
   588  	require.NoError(t, err)
   589  	return fmt.Sprintf("x%s", hex.EncodeToString(bytes))
   590  }
   591  
   592  func TestDrop(t *testing.T) {
   593  	for _, env := range testEnvs {
   594  		t.Run(env.GetName(), func(t *testing.T) {
   595  			testDrop(t, env)
   596  		})
   597  
   598  		t.Run("test-drop-error-propagation", func(t *testing.T) {
   599  			env.Init(t)
   600  			defer env.Cleanup()
   601  			ledgerid := generateLedgerID(t)
   602  			env.GetDBHandle(ledgerid)
   603  			env.GetProvider().Close()
   604  			require.EqualError(t, env.GetProvider().Drop(ledgerid), "internal leveldb error while obtaining db iterator: leveldb: closed")
   605  		})
   606  	}
   607  }
   608  
   609  func testDrop(t *testing.T, env TestEnv) {
   610  	env.Init(t)
   611  	defer env.Cleanup()
   612  	ledgerid := generateLedgerID(t)
   613  	db := env.GetDBHandle(ledgerid)
   614  
   615  	updates := NewUpdateBatch()
   616  	updates.PubUpdates.Put("ns1", "key1", []byte("value1"), version.NewHeight(1, 1))
   617  	putPvtUpdates(t, updates, "ns1", "coll1", "key1", []byte("pvt_value1"), version.NewHeight(1, 2))
   618  	require.NoError(t, db.ApplyPrivacyAwareUpdates(updates, version.NewHeight(2, 2)))
   619  
   620  	vv, err := db.GetState("ns1", "key1")
   621  	require.NoError(t, err)
   622  	require.Equal(t, &statedb.VersionedValue{Value: []byte("value1"), Version: version.NewHeight(1, 1)}, vv)
   623  
   624  	vv, err = db.GetPrivateData("ns1", "coll1", "key1")
   625  	require.NoError(t, err)
   626  	require.Equal(t, &statedb.VersionedValue{Value: []byte("pvt_value1"), Version: version.NewHeight(1, 2)}, vv)
   627  
   628  	vv, err = db.GetPrivateDataHash("ns1", "coll1", "key1")
   629  	require.NoError(t, err)
   630  	require.Equal(t, &statedb.VersionedValue{Value: util.ComputeStringHash("pvt_value1"), Version: version.NewHeight(1, 2)}, vv)
   631  
   632  	require.NoError(t, env.GetProvider().Drop(ledgerid))
   633  
   634  	vv, err = db.GetState("ns1", "key1")
   635  	require.NoError(t, err)
   636  	require.Nil(t, vv)
   637  
   638  	vv, err = db.GetPrivateData("ns1", "coll1", "key1")
   639  	require.NoError(t, err)
   640  	require.Nil(t, vv)
   641  
   642  	vv, err = db.GetPrivateDataHash("ns1", "coll1", "key1")
   643  	require.NoError(t, err)
   644  	require.Nil(t, vv)
   645  }
   646  
   647  //go:generate counterfeiter -o mock/channelinfo_provider.go -fake-name ChannelInfoProvider . channelInfoProvider
   648  
   649  func TestPossibleNamespaces(t *testing.T) {
   650  	namespacesAndCollections := map[string][]string{
   651  		"cc1":        {"_implicit_org_Org1MSP", "_implicit_org_Org2MSP", "collectionA", "collectionB"},
   652  		"cc2":        {"_implicit_org_Org1MSP", "_implicit_org_Org2MSP"},
   653  		"_lifecycle": {"_implicit_org_Org1MSP", "_implicit_org_Org2MSP"},
   654  		"lscc":       {},
   655  		"":           {},
   656  	}
   657  	expectedNamespaces := []string{
   658  		"cc1",
   659  		"cc1$$p_implicit_org_Org1MSP",
   660  		"cc1$$h_implicit_org_Org1MSP",
   661  		"cc1$$p_implicit_org_Org2MSP",
   662  		"cc1$$h_implicit_org_Org2MSP",
   663  		"cc1$$pcollectionA",
   664  		"cc1$$hcollectionA",
   665  		"cc1$$pcollectionB",
   666  		"cc1$$hcollectionB",
   667  		"cc2",
   668  		"cc2$$p_implicit_org_Org1MSP",
   669  		"cc2$$h_implicit_org_Org1MSP",
   670  		"cc2$$p_implicit_org_Org2MSP",
   671  		"cc2$$h_implicit_org_Org2MSP",
   672  		"_lifecycle",
   673  		"_lifecycle$$p_implicit_org_Org1MSP",
   674  		"_lifecycle$$h_implicit_org_Org1MSP",
   675  		"_lifecycle$$p_implicit_org_Org2MSP",
   676  		"_lifecycle$$h_implicit_org_Org2MSP",
   677  		"lscc",
   678  		"",
   679  	}
   680  
   681  	fakeChannelInfoProvider := &testmock.ChannelInfoProvider{}
   682  	fakeChannelInfoProvider.NamespacesAndCollectionsReturns(namespacesAndCollections, nil)
   683  	nsProvider := &namespaceProvider{fakeChannelInfoProvider}
   684  	namespaces, err := nsProvider.PossibleNamespaces(&statecouchdb.VersionedDB{})
   685  	require.NoError(t, err)
   686  	require.ElementsMatch(t, expectedNamespaces, namespaces)
   687  }