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

     1  /*
     2  Copyright hechain. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package statecouchdb
     8  
     9  import (
    10  	"errors"
    11  	"fmt"
    12  	"io/ioutil"
    13  	"os"
    14  	"strings"
    15  	"testing"
    16  	"time"
    17  	"unicode/utf8"
    18  
    19  	"github.com/hechain20/hechain/common/flogging"
    20  	"github.com/hechain20/hechain/common/ledger/dataformat"
    21  	"github.com/hechain20/hechain/common/metrics/disabled"
    22  	"github.com/hechain20/hechain/core/ledger"
    23  	"github.com/hechain20/hechain/core/ledger/internal/version"
    24  	"github.com/hechain20/hechain/core/ledger/kvledger/txmgmt/statedb"
    25  	"github.com/hechain20/hechain/core/ledger/kvledger/txmgmt/statedb/commontests"
    26  	"github.com/hechain20/hechain/core/ledger/kvledger/txmgmt/statedb/mock"
    27  	"github.com/stretchr/testify/require"
    28  )
    29  
    30  // testVDBEnv provides a couch db backed versioned db for testing
    31  type testVDBEnv struct {
    32  	t             *testing.T
    33  	DBProvider    statedb.VersionedDBProvider
    34  	config        *ledger.CouchDBConfig
    35  	cache         *cache
    36  	sysNamespaces []string
    37  	couchDBEnv    *testCouchDBEnv
    38  }
    39  
    40  func (env *testVDBEnv) init(t *testing.T, sysNamespaces []string) {
    41  	t.Logf("Initializing TestVDBEnv")
    42  
    43  	if env.couchDBEnv == nil {
    44  		couchDBEnv := &testCouchDBEnv{}
    45  		couchDBEnv.startCouchDB(t)
    46  		env.couchDBEnv = couchDBEnv
    47  	}
    48  
    49  	redoPath, err := ioutil.TempDir("", "cvdbenv")
    50  	if err != nil {
    51  		t.Fatalf("Failed to create redo log directory: %s", err)
    52  	}
    53  	config := &ledger.CouchDBConfig{
    54  		Address:             env.couchDBEnv.couchAddress,
    55  		Username:            "admin",
    56  		Password:            "adminpw",
    57  		InternalQueryLimit:  1000,
    58  		MaxBatchUpdateSize:  1000,
    59  		MaxRetries:          3,
    60  		MaxRetriesOnStartup: 20,
    61  		RequestTimeout:      35 * time.Second,
    62  		RedoLogPath:         redoPath,
    63  		UserCacheSizeMBs:    8,
    64  	}
    65  
    66  	disableKeepAlive = true
    67  	dbProvider, err := NewVersionedDBProvider(config, &disabled.Provider{}, sysNamespaces)
    68  	if err != nil {
    69  		t.Fatalf("Error creating CouchDB Provider: %s", err)
    70  	}
    71  
    72  	env.t = t
    73  	env.config = config
    74  	env.DBProvider = dbProvider
    75  	env.config = config
    76  	env.cache = dbProvider.cache
    77  	env.sysNamespaces = sysNamespaces
    78  }
    79  
    80  func (env *testVDBEnv) closeAndReopen() {
    81  	env.DBProvider.Close()
    82  	dbProvider, _ := NewVersionedDBProvider(env.config, &disabled.Provider{}, env.sysNamespaces)
    83  	env.DBProvider = dbProvider
    84  	env.cache = dbProvider.cache
    85  }
    86  
    87  // Cleanup drops the test couch databases and closes the db provider
    88  func (env *testVDBEnv) cleanup() {
    89  	env.t.Logf("Cleaningup TestVDBEnv")
    90  	if env.DBProvider != nil {
    91  		env.DBProvider.Close()
    92  	}
    93  	env.couchDBEnv.cleanup(env.config)
    94  	require.NoError(env.t, os.RemoveAll(env.config.RedoLogPath))
    95  }
    96  
    97  // testVDBEnv provides a couch db for testing
    98  type testCouchDBEnv struct {
    99  	t              *testing.T
   100  	couchAddress   string
   101  	cleanupCouchDB func()
   102  }
   103  
   104  // startCouchDB starts external couchDB resources for testCouchDBEnv.
   105  func (env *testCouchDBEnv) startCouchDB(t *testing.T) {
   106  	if env.couchAddress != "" {
   107  		return
   108  	}
   109  	env.t = t
   110  	env.couchAddress, env.cleanupCouchDB = StartCouchDB(t, nil)
   111  }
   112  
   113  // stopCouchDB stops external couchDB resources.
   114  func (env *testCouchDBEnv) stopCouchDB() {
   115  	if env.couchAddress != "" {
   116  		env.cleanupCouchDB()
   117  	}
   118  }
   119  
   120  func (env *testCouchDBEnv) cleanup(config *ledger.CouchDBConfig) {
   121  	err := DropApplicationDBs(config)
   122  	require.NoError(env.t, err)
   123  }
   124  
   125  // we create two CouchDB instances/containers---one is used to test the
   126  // functionality of the versionedDB and another for testing the CouchDB
   127  // util functions.
   128  var (
   129  	vdbEnv     = &testVDBEnv{}
   130  	couchDBEnv = &testCouchDBEnv{}
   131  )
   132  
   133  func TestMain(m *testing.M) {
   134  	flogging.ActivateSpec("statecouchdb=debug")
   135  
   136  	rc := m.Run()
   137  	if vdbEnv.couchDBEnv != nil {
   138  		vdbEnv.couchDBEnv.stopCouchDB()
   139  	}
   140  	couchDBEnv.stopCouchDB()
   141  	os.Exit(rc)
   142  }
   143  
   144  func TestBasicRW(t *testing.T) {
   145  	vdbEnv.init(t, nil)
   146  	defer vdbEnv.cleanup()
   147  
   148  	commontests.TestBasicRW(t, vdbEnv.DBProvider)
   149  }
   150  
   151  // TestGetStateFromCache checks cache hits, cache misses, and cache
   152  // updates during GetState call.
   153  func TestGetStateFromCache(t *testing.T) {
   154  	vdbEnv.init(t, []string{"lscc", "_lifecycle"})
   155  	defer vdbEnv.cleanup()
   156  
   157  	chainID := "testgetstatefromcache"
   158  	db, err := vdbEnv.DBProvider.GetDBHandle(chainID, nil)
   159  	require.NoError(t, err)
   160  
   161  	// scenario 1: get state would receives a
   162  	// cache miss as the given key does not exist.
   163  	// As the key does not exist in the
   164  	// db also, get state call would not update
   165  	// the cache.
   166  	vv, err := db.GetState("ns", "key1")
   167  	require.NoError(t, err)
   168  	require.Nil(t, vv)
   169  	testDoesNotExistInCache(t, vdbEnv.cache, chainID, "ns", "key1")
   170  
   171  	// scenario 2: get state would receive a cache hit.
   172  	// directly store an entry in the cache
   173  	cacheValue := &CacheValue{
   174  		Value:          []byte("value1"),
   175  		Metadata:       []byte("meta1"),
   176  		Version:        version.NewHeight(1, 1).ToBytes(),
   177  		AdditionalInfo: []byte("rev1"),
   178  	}
   179  	require.NoError(t, vdbEnv.cache.putState(chainID, "ns", "key1", cacheValue))
   180  
   181  	vv, err = db.GetState("ns", "key1")
   182  	require.NoError(t, err)
   183  	expectedVV, err := constructVersionedValue(cacheValue)
   184  	require.NoError(t, err)
   185  	require.Equal(t, expectedVV, vv)
   186  
   187  	// scenario 3: get state would receives a
   188  	// cache miss as the given key does not present.
   189  	// The value associated with the key would be
   190  	// fetched from the database and the cache would
   191  	// be updated accordingly.
   192  
   193  	// store an entry in the db
   194  	batch := statedb.NewUpdateBatch()
   195  	vv2 := &statedb.VersionedValue{Value: []byte("value2"), Metadata: []byte("meta2"), Version: version.NewHeight(1, 2)}
   196  	batch.PutValAndMetadata("lscc", "key1", vv2.Value, vv2.Metadata, vv2.Version)
   197  	savePoint := version.NewHeight(1, 2)
   198  	require.NoError(t, db.ApplyUpdates(batch, savePoint))
   199  	// Note that the ApplyUpdates() updates only the existing entry in the cache. Currently, the
   200  	// cache has only ns, key1 but we are storing lscc, key1. Hence, no changes would happen in the cache.
   201  	testDoesNotExistInCache(t, vdbEnv.cache, chainID, "lscc", "key1")
   202  
   203  	// calling GetState() would update the cache
   204  	vv, err = db.GetState("lscc", "key1")
   205  	require.NoError(t, err)
   206  	require.Equal(t, vv2, vv)
   207  
   208  	// cache should have been updated with lscc, key1
   209  	nsdb, err := db.(*VersionedDB).getNamespaceDBHandle("lscc")
   210  	require.NoError(t, err)
   211  	testExistInCache(t, nsdb, vdbEnv.cache, chainID, "lscc", "key1", vv2)
   212  }
   213  
   214  // TestGetVersionFromCache checks cache hits, cache misses, and
   215  // updates during GetVersion call.
   216  func TestGetVersionFromCache(t *testing.T) {
   217  	vdbEnv.init(t, []string{"lscc", "_lifecycle"})
   218  	defer vdbEnv.cleanup()
   219  
   220  	chainID := "testgetstatefromcache"
   221  	db, err := vdbEnv.DBProvider.GetDBHandle(chainID, nil)
   222  	require.NoError(t, err)
   223  
   224  	// scenario 1: get version would receives a
   225  	// cache miss as the given key does not exist.
   226  	// As the key does not exist in the
   227  	// db also, get version call would not update
   228  	// the cache.
   229  	ver, err := db.GetVersion("ns", "key1")
   230  	require.Nil(t, err)
   231  	require.Nil(t, ver)
   232  	testDoesNotExistInCache(t, vdbEnv.cache, chainID, "ns", "key1")
   233  
   234  	// scenario 2: get version would receive a cache hit.
   235  	// directly store an entry in the cache
   236  	cacheValue := &CacheValue{
   237  		Value:          []byte("value1"),
   238  		Metadata:       []byte("meta1"),
   239  		Version:        version.NewHeight(1, 1).ToBytes(),
   240  		AdditionalInfo: []byte("rev1"),
   241  	}
   242  	require.NoError(t, vdbEnv.cache.putState(chainID, "ns", "key1", cacheValue))
   243  
   244  	ver, err = db.GetVersion("ns", "key1")
   245  	require.NoError(t, err)
   246  	expectedVer, _, err := version.NewHeightFromBytes(cacheValue.Version)
   247  	require.NoError(t, err)
   248  	require.Equal(t, expectedVer, ver)
   249  
   250  	// scenario 3: get version would receives a
   251  	// cache miss as the given key does not present.
   252  	// The value associated with the key would be
   253  	// fetched from the database and the cache would
   254  	// be updated accordingly.
   255  
   256  	// store an entry in the db
   257  	batch := statedb.NewUpdateBatch()
   258  	vv2 := &statedb.VersionedValue{Value: []byte("value2"), Metadata: []byte("meta2"), Version: version.NewHeight(1, 2)}
   259  	batch.PutValAndMetadata("lscc", "key1", vv2.Value, vv2.Metadata, vv2.Version)
   260  	savePoint := version.NewHeight(1, 2)
   261  	require.NoError(t, db.ApplyUpdates(batch, savePoint))
   262  	// Note that the ApplyUpdates() updates only the existing entry in the cache. Currently, the
   263  	// cache has only ns, key1 but we are storing lscc, key1. Hence, no changes would happen in the cache.
   264  	testDoesNotExistInCache(t, vdbEnv.cache, chainID, "lscc", "key1")
   265  
   266  	// calling GetVersion() would update the cache
   267  	ver, err = db.GetVersion("lscc", "key1")
   268  	require.NoError(t, err)
   269  	require.Equal(t, vv2.Version, ver)
   270  
   271  	// cache should have been updated with lscc, key1
   272  	nsdb, err := db.(*VersionedDB).getNamespaceDBHandle("lscc")
   273  	require.NoError(t, err)
   274  	testExistInCache(t, nsdb, vdbEnv.cache, chainID, "lscc", "key1", vv2)
   275  }
   276  
   277  // TestGetMultipleStatesFromCache checks cache hits, cache misses,
   278  // and updates during GetStateMultipleKeys call.
   279  func TestGetMultipleStatesFromCache(t *testing.T) {
   280  	vdbEnv.init(t, []string{"lscc", "_lifecycle"})
   281  	defer vdbEnv.cleanup()
   282  
   283  	chainID := "testgetmultiplestatesfromcache"
   284  	db, err := vdbEnv.DBProvider.GetDBHandle(chainID, nil)
   285  	require.NoError(t, err)
   286  
   287  	// scenario: given 5 keys, get multiple states find
   288  	// 2 keys in the cache. The remaining 2 keys would be fetched
   289  	// from the database and the cache would be updated. The last
   290  	// key is not present in the db and hence it won't be sent to
   291  	// the cache.
   292  
   293  	// key1 and key2 exist only in the cache
   294  	cacheValue1 := &CacheValue{
   295  		Value:          []byte("value1"),
   296  		Metadata:       []byte("meta1"),
   297  		Version:        version.NewHeight(1, 1).ToBytes(),
   298  		AdditionalInfo: []byte("rev1"),
   299  	}
   300  	require.NoError(t, vdbEnv.cache.putState(chainID, "ns", "key1", cacheValue1))
   301  	cacheValue2 := &CacheValue{
   302  		Value:          []byte("value2"),
   303  		Metadata:       []byte("meta2"),
   304  		Version:        version.NewHeight(1, 1).ToBytes(),
   305  		AdditionalInfo: []byte("rev2"),
   306  	}
   307  	require.NoError(t, vdbEnv.cache.putState(chainID, "ns", "key2", cacheValue2))
   308  
   309  	// key3 and key4 exist only in the db
   310  	batch := statedb.NewUpdateBatch()
   311  	vv3 := &statedb.VersionedValue{Value: []byte("value3"), Metadata: []byte("meta3"), Version: version.NewHeight(1, 1)}
   312  	batch.PutValAndMetadata("ns", "key3", vv3.Value, vv3.Metadata, vv3.Version)
   313  	vv4 := &statedb.VersionedValue{Value: []byte("value4"), Metadata: []byte("meta4"), Version: version.NewHeight(1, 1)}
   314  	batch.PutValAndMetadata("ns", "key4", vv4.Value, vv4.Metadata, vv4.Version)
   315  	savePoint := version.NewHeight(1, 2)
   316  	require.NoError(t, db.ApplyUpdates(batch, savePoint))
   317  
   318  	testDoesNotExistInCache(t, vdbEnv.cache, chainID, "ns", "key3")
   319  	testDoesNotExistInCache(t, vdbEnv.cache, chainID, "ns", "key4")
   320  
   321  	// key5 does not exist at all while key3 and key4 does not exist in the cache
   322  	vvalues, err := db.GetStateMultipleKeys("ns", []string{"key1", "key2", "key3", "key4", "key5"})
   323  	require.Nil(t, err)
   324  	vv1, err := constructVersionedValue(cacheValue1)
   325  	require.NoError(t, err)
   326  	vv2, err := constructVersionedValue(cacheValue2)
   327  	require.NoError(t, err)
   328  	require.Equal(t, []*statedb.VersionedValue{vv1, vv2, vv3, vv4, nil}, vvalues)
   329  
   330  	// cache should have been updated with key3 and key4
   331  	nsdb, err := db.(*VersionedDB).getNamespaceDBHandle("ns")
   332  	require.NoError(t, err)
   333  	testExistInCache(t, nsdb, vdbEnv.cache, chainID, "ns", "key3", vv3)
   334  	testExistInCache(t, nsdb, vdbEnv.cache, chainID, "ns", "key4", vv4)
   335  }
   336  
   337  // TestCacheUpdatesAfterCommit checks whether the cache is updated
   338  // after a commit of a update batch.
   339  func TestCacheUpdatesAfterCommit(t *testing.T) {
   340  	vdbEnv.init(t, []string{"lscc", "_lifecycle"})
   341  	defer vdbEnv.cleanup()
   342  
   343  	chainID := "testcacheupdatesaftercommit"
   344  	db, err := vdbEnv.DBProvider.GetDBHandle(chainID, nil)
   345  	require.NoError(t, err)
   346  
   347  	// scenario: cache has 4 keys while the commit operation
   348  	// updates 2 of those keys, delete the remaining 2 keys, and
   349  	// adds a new key. At the end of the commit operation, only
   350  	// those 2 keys should be present with the recent value
   351  	// in the cache and the new key should not be present in the cache.
   352  
   353  	// store 4 keys in the db
   354  	batch := statedb.NewUpdateBatch()
   355  	vv1 := &statedb.VersionedValue{Value: []byte("value1"), Metadata: []byte("meta1"), Version: version.NewHeight(1, 2)}
   356  	vv2 := &statedb.VersionedValue{Value: []byte("value2"), Metadata: []byte("meta2"), Version: version.NewHeight(1, 2)}
   357  	vv3 := &statedb.VersionedValue{Value: []byte("value3"), Metadata: []byte("meta3"), Version: version.NewHeight(1, 2)}
   358  	vv4 := &statedb.VersionedValue{Value: []byte("value4"), Metadata: []byte("meta4"), Version: version.NewHeight(1, 2)}
   359  
   360  	batch.PutValAndMetadata("ns1", "key1", vv1.Value, vv1.Metadata, vv1.Version)
   361  	batch.PutValAndMetadata("ns1", "key2", vv2.Value, vv2.Metadata, vv2.Version)
   362  	batch.PutValAndMetadata("ns2", "key1", vv3.Value, vv3.Metadata, vv3.Version)
   363  	batch.PutValAndMetadata("ns2", "key2", vv4.Value, vv4.Metadata, vv4.Version)
   364  	savePoint := version.NewHeight(1, 5)
   365  	require.NoError(t, db.ApplyUpdates(batch, savePoint))
   366  
   367  	// key1, key2 in ns1 and ns2 would not be in cache
   368  	testDoesNotExistInCache(t, vdbEnv.cache, chainID, "ns1", "key1")
   369  	testDoesNotExistInCache(t, vdbEnv.cache, chainID, "ns1", "key2")
   370  	testDoesNotExistInCache(t, vdbEnv.cache, chainID, "ns2", "key1")
   371  	testDoesNotExistInCache(t, vdbEnv.cache, chainID, "ns2", "key2")
   372  
   373  	// add key1 and key2 from ns1 to the cache
   374  	_, err = db.GetState("ns1", "key1")
   375  	require.NoError(t, err)
   376  	_, err = db.GetState("ns1", "key2")
   377  	require.NoError(t, err)
   378  	// add key1 and key2 from ns2 to the cache
   379  	_, err = db.GetState("ns2", "key1")
   380  	require.NoError(t, err)
   381  	_, err = db.GetState("ns2", "key2")
   382  	require.NoError(t, err)
   383  
   384  	v, err := vdbEnv.cache.getState(chainID, "ns1", "key1")
   385  	require.NoError(t, err)
   386  	ns1key1rev := string(v.AdditionalInfo)
   387  
   388  	v, err = vdbEnv.cache.getState(chainID, "ns1", "key2")
   389  	require.NoError(t, err)
   390  	ns1key2rev := string(v.AdditionalInfo)
   391  
   392  	// update key1 and key2 in ns1. delete key1 and key2 in ns2. add a new key3 in ns2.
   393  	batch = statedb.NewUpdateBatch()
   394  	vv1Update := &statedb.VersionedValue{Value: []byte("new-value1"), Metadata: []byte("meta1"), Version: version.NewHeight(2, 2)}
   395  	vv2Update := &statedb.VersionedValue{Value: []byte("new-value2"), Metadata: []byte("meta2"), Version: version.NewHeight(2, 2)}
   396  	vv3Update := &statedb.VersionedValue{Version: version.NewHeight(2, 4)}
   397  	vv4Update := &statedb.VersionedValue{Version: version.NewHeight(2, 5)}
   398  	vv5 := &statedb.VersionedValue{Value: []byte("value5"), Metadata: []byte("meta5"), Version: version.NewHeight(1, 2)}
   399  
   400  	batch.PutValAndMetadata("ns1", "key1", vv1Update.Value, vv1Update.Metadata, vv1Update.Version)
   401  	batch.PutValAndMetadata("ns1", "key2", vv2Update.Value, vv2Update.Metadata, vv2Update.Version)
   402  	batch.Delete("ns2", "key1", vv3Update.Version)
   403  	batch.Delete("ns2", "key2", vv4Update.Version)
   404  	batch.PutValAndMetadata("ns2", "key3", vv5.Value, vv5.Metadata, vv5.Version)
   405  	savePoint = version.NewHeight(2, 5)
   406  	require.NoError(t, db.ApplyUpdates(batch, savePoint))
   407  
   408  	// cache should have only the update key1 and key2 in ns1
   409  	cacheValue, err := vdbEnv.cache.getState(chainID, "ns1", "key1")
   410  	require.NoError(t, err)
   411  	vv, err := constructVersionedValue(cacheValue)
   412  	require.NoError(t, err)
   413  	require.Equal(t, vv1Update, vv)
   414  	require.NotEqual(t, ns1key1rev, string(cacheValue.AdditionalInfo))
   415  
   416  	cacheValue, err = vdbEnv.cache.getState(chainID, "ns1", "key2")
   417  	require.NoError(t, err)
   418  	vv, err = constructVersionedValue(cacheValue)
   419  	require.NoError(t, err)
   420  	require.Equal(t, vv2Update, vv)
   421  	require.NotEqual(t, ns1key2rev, string(cacheValue.AdditionalInfo))
   422  
   423  	testDoesNotExistInCache(t, vdbEnv.cache, chainID, "ns2", "key1")
   424  	testDoesNotExistInCache(t, vdbEnv.cache, chainID, "ns2", "key2")
   425  	testDoesNotExistInCache(t, vdbEnv.cache, chainID, "ns2", "key3")
   426  }
   427  
   428  func TestMultiDBBasicRW(t *testing.T) {
   429  	vdbEnv.init(t, nil)
   430  	defer vdbEnv.cleanup()
   431  
   432  	commontests.TestMultiDBBasicRW(t, vdbEnv.DBProvider)
   433  }
   434  
   435  func TestDeletes(t *testing.T) {
   436  	vdbEnv.init(t, nil)
   437  	defer vdbEnv.cleanup()
   438  
   439  	commontests.TestDeletes(t, vdbEnv.DBProvider)
   440  }
   441  
   442  func TestIterator(t *testing.T) {
   443  	vdbEnv.init(t, nil)
   444  	defer vdbEnv.cleanup()
   445  
   446  	commontests.TestIterator(t, vdbEnv.DBProvider)
   447  }
   448  
   449  // The following tests are unique to couchdb, they are not used in leveldb
   450  //  query test
   451  func TestQuery(t *testing.T) {
   452  	vdbEnv.init(t, nil)
   453  	defer vdbEnv.cleanup()
   454  
   455  	commontests.TestQuery(t, vdbEnv.DBProvider)
   456  }
   457  
   458  func TestGetStateMultipleKeys(t *testing.T) {
   459  	vdbEnv.init(t, nil)
   460  	defer vdbEnv.cleanup()
   461  
   462  	commontests.TestGetStateMultipleKeys(t, vdbEnv.DBProvider)
   463  }
   464  
   465  func TestGetVersion(t *testing.T) {
   466  	vdbEnv.init(t, nil)
   467  	defer vdbEnv.cleanup()
   468  
   469  	commontests.TestGetVersion(t, vdbEnv.DBProvider)
   470  }
   471  
   472  func TestSmallBatchSize(t *testing.T) {
   473  	vdbEnv.init(t, nil)
   474  	defer vdbEnv.cleanup()
   475  
   476  	commontests.TestSmallBatchSize(t, vdbEnv.DBProvider)
   477  }
   478  
   479  func TestBatchRetry(t *testing.T) {
   480  	vdbEnv.init(t, nil)
   481  	defer vdbEnv.cleanup()
   482  
   483  	commontests.TestBatchWithIndividualRetry(t, vdbEnv.DBProvider)
   484  }
   485  
   486  func TestValueAndMetadataWrites(t *testing.T) {
   487  	vdbEnv.init(t, nil)
   488  	defer vdbEnv.cleanup()
   489  
   490  	commontests.TestValueAndMetadataWrites(t, vdbEnv.DBProvider)
   491  }
   492  
   493  func TestPaginatedRangeQuery(t *testing.T) {
   494  	vdbEnv.init(t, nil)
   495  	defer vdbEnv.cleanup()
   496  
   497  	commontests.TestPaginatedRangeQuery(t, vdbEnv.DBProvider)
   498  }
   499  
   500  func TestRangeQuerySpecialCharacters(t *testing.T) {
   501  	vdbEnv.init(t, nil)
   502  	defer vdbEnv.cleanup()
   503  
   504  	commontests.TestRangeQuerySpecialCharacters(t, vdbEnv.DBProvider)
   505  }
   506  
   507  // TestUtilityFunctions tests utility functions
   508  func TestUtilityFunctions(t *testing.T) {
   509  	vdbEnv.init(t, nil)
   510  	defer vdbEnv.cleanup()
   511  
   512  	db, err := vdbEnv.DBProvider.GetDBHandle("testutilityfunctions", nil)
   513  	require.NoError(t, err)
   514  
   515  	require.False(t, vdbEnv.DBProvider.BytesKeySupported())
   516  	require.False(t, db.BytesKeySupported())
   517  
   518  	// ValidateKeyValue should return nil for a valid key and value
   519  	err = db.ValidateKeyValue("testKey", []byte("Some random bytes"))
   520  	require.Nil(t, err)
   521  
   522  	// ValidateKeyValue should return an error for a key that is not a utf-8 valid string
   523  	err = db.ValidateKeyValue(string([]byte{0xff, 0xfe, 0xfd}), []byte("Some random bytes"))
   524  	require.Error(t, err, "ValidateKey should have thrown an error for an invalid utf-8 string")
   525  
   526  	// ValidateKeyValue should return an error for a key that is an empty string
   527  	require.EqualError(t, db.ValidateKeyValue("", []byte("validValue")),
   528  		"invalid key. Empty string is not supported as a key by couchdb")
   529  
   530  	reservedFields := []string{"~version", "_id", "_test"}
   531  
   532  	// ValidateKeyValue should return an error for a json value that contains one of the reserved fields
   533  	// at the top level
   534  	for _, reservedField := range reservedFields {
   535  		testVal := fmt.Sprintf(`{"%s":"dummyVal"}`, reservedField)
   536  		err = db.ValidateKeyValue("testKey", []byte(testVal))
   537  		require.Error(t, err, fmt.Sprintf(
   538  			"ValidateKey should have thrown an error for a json value %s, as contains one of the reserved fields", testVal))
   539  	}
   540  
   541  	// ValidateKeyValue should not return an error for a json value that contains one of the reserved fields
   542  	// if not at the top level
   543  	for _, reservedField := range reservedFields {
   544  		testVal := fmt.Sprintf(`{"data.%s":"dummyVal"}`, reservedField)
   545  		err = db.ValidateKeyValue("testKey", []byte(testVal))
   546  		require.NoError(t, err, fmt.Sprintf(
   547  			"ValidateKey should not have thrown an error the json value %s since the reserved field was not at the top level", testVal))
   548  	}
   549  
   550  	// ValidateKeyValue should return an error for a key that begins with an underscore
   551  	err = db.ValidateKeyValue("_testKey", []byte("testValue"))
   552  	require.Error(t, err, "ValidateKey should have thrown an error for a key that begins with an underscore")
   553  }
   554  
   555  // TestInvalidJSONFields tests for invalid JSON fields
   556  func TestInvalidJSONFields(t *testing.T) {
   557  	vdbEnv.init(t, nil)
   558  	defer vdbEnv.cleanup()
   559  
   560  	db, err := vdbEnv.DBProvider.GetDBHandle("testinvalidfields", nil)
   561  	require.NoError(t, err)
   562  
   563  	require.NoError(t, db.Open())
   564  	defer db.Close()
   565  
   566  	batch := statedb.NewUpdateBatch()
   567  	jsonValue1 := `{"_id":"key1","asset_name":"marble1","color":"blue","size":1,"owner":"tom"}`
   568  	batch.Put("ns1", "key1", []byte(jsonValue1), version.NewHeight(1, 1))
   569  
   570  	savePoint := version.NewHeight(1, 2)
   571  	err = db.ApplyUpdates(batch, savePoint)
   572  	require.Error(t, err, "Invalid field _id should have thrown an error")
   573  
   574  	batch = statedb.NewUpdateBatch()
   575  	jsonValue1 = `{"_rev":"rev1","asset_name":"marble1","color":"blue","size":1,"owner":"tom"}`
   576  	batch.Put("ns1", "key1", []byte(jsonValue1), version.NewHeight(1, 1))
   577  
   578  	savePoint = version.NewHeight(1, 2)
   579  	err = db.ApplyUpdates(batch, savePoint)
   580  	require.Error(t, err, "Invalid field _rev should have thrown an error")
   581  
   582  	batch = statedb.NewUpdateBatch()
   583  	jsonValue1 = `{"_deleted":"true","asset_name":"marble1","color":"blue","size":1,"owner":"tom"}`
   584  	batch.Put("ns1", "key1", []byte(jsonValue1), version.NewHeight(1, 1))
   585  
   586  	savePoint = version.NewHeight(1, 2)
   587  	err = db.ApplyUpdates(batch, savePoint)
   588  	require.Error(t, err, "Invalid field _deleted should have thrown an error")
   589  
   590  	batch = statedb.NewUpdateBatch()
   591  	jsonValue1 = `{"~version":"v1","asset_name":"marble1","color":"blue","size":1,"owner":"tom"}`
   592  	batch.Put("ns1", "key1", []byte(jsonValue1), version.NewHeight(1, 1))
   593  
   594  	savePoint = version.NewHeight(1, 2)
   595  	err = db.ApplyUpdates(batch, savePoint)
   596  	require.Error(t, err, "Invalid field ~version should have thrown an error")
   597  }
   598  
   599  func TestDebugFunctions(t *testing.T) {
   600  	// Test printCompositeKeys
   601  	// initialize a key list
   602  	loadKeys := []*statedb.CompositeKey{}
   603  	// create a composite key and add to the key list
   604  	compositeKey3 := statedb.CompositeKey{Namespace: "ns", Key: "key3"}
   605  	loadKeys = append(loadKeys, &compositeKey3)
   606  	compositeKey4 := statedb.CompositeKey{Namespace: "ns", Key: "key4"}
   607  	loadKeys = append(loadKeys, &compositeKey4)
   608  	require.Equal(t, "[ns,key3],[ns,key4]", printCompositeKeys(loadKeys))
   609  }
   610  
   611  func TestHandleChaincodeDeploy(t *testing.T) {
   612  	vdbEnv.init(t, nil)
   613  	defer vdbEnv.cleanup()
   614  
   615  	db, err := vdbEnv.DBProvider.GetDBHandle("testinit", nil)
   616  	require.NoError(t, err)
   617  	require.NoError(t, db.Open())
   618  	defer db.Close()
   619  	batch := statedb.NewUpdateBatch()
   620  
   621  	jsonValue1 := `{"asset_name": "marble1","color": "blue","size": 1,"owner": "tom"}`
   622  	batch.Put("ns1", "key1", []byte(jsonValue1), version.NewHeight(1, 1))
   623  	jsonValue2 := `{"asset_name": "marble2","color": "blue","size": 2,"owner": "jerry"}`
   624  	batch.Put("ns1", "key2", []byte(jsonValue2), version.NewHeight(1, 2))
   625  	jsonValue3 := `{"asset_name": "marble3","color": "blue","size": 3,"owner": "fred"}`
   626  	batch.Put("ns1", "key3", []byte(jsonValue3), version.NewHeight(1, 3))
   627  	jsonValue4 := `{"asset_name": "marble4","color": "blue","size": 4,"owner": "martha"}`
   628  	batch.Put("ns1", "key4", []byte(jsonValue4), version.NewHeight(1, 4))
   629  	jsonValue5 := `{"asset_name": "marble5","color": "blue","size": 5,"owner": "fred"}`
   630  	batch.Put("ns1", "key5", []byte(jsonValue5), version.NewHeight(1, 5))
   631  	jsonValue6 := `{"asset_name": "marble6","color": "blue","size": 6,"owner": "elaine"}`
   632  	batch.Put("ns1", "key6", []byte(jsonValue6), version.NewHeight(1, 6))
   633  	jsonValue7 := `{"asset_name": "marble7","color": "blue","size": 7,"owner": "fred"}`
   634  	batch.Put("ns1", "key7", []byte(jsonValue7), version.NewHeight(1, 7))
   635  	jsonValue8 := `{"asset_name": "marble8","color": "blue","size": 8,"owner": "elaine"}`
   636  	batch.Put("ns1", "key8", []byte(jsonValue8), version.NewHeight(1, 8))
   637  	jsonValue9 := `{"asset_name": "marble9","color": "green","size": 9,"owner": "fred"}`
   638  	batch.Put("ns1", "key9", []byte(jsonValue9), version.NewHeight(1, 9))
   639  	jsonValue10 := `{"asset_name": "marble10","color": "green","size": 10,"owner": "mary"}`
   640  	batch.Put("ns1", "key10", []byte(jsonValue10), version.NewHeight(1, 10))
   641  	jsonValue11 := `{"asset_name": "marble11","color": "cyan","size": 1000007,"owner": "joe"}`
   642  	batch.Put("ns1", "key11", []byte(jsonValue11), version.NewHeight(1, 11))
   643  
   644  	// add keys for a separate namespace
   645  	batch.Put("ns2", "key1", []byte(jsonValue1), version.NewHeight(1, 12))
   646  	batch.Put("ns2", "key2", []byte(jsonValue2), version.NewHeight(1, 13))
   647  	batch.Put("ns2", "key3", []byte(jsonValue3), version.NewHeight(1, 14))
   648  	batch.Put("ns2", "key4", []byte(jsonValue4), version.NewHeight(1, 15))
   649  	batch.Put("ns2", "key5", []byte(jsonValue5), version.NewHeight(1, 16))
   650  	batch.Put("ns2", "key6", []byte(jsonValue6), version.NewHeight(1, 17))
   651  	batch.Put("ns2", "key7", []byte(jsonValue7), version.NewHeight(1, 18))
   652  	batch.Put("ns2", "key8", []byte(jsonValue8), version.NewHeight(1, 19))
   653  	batch.Put("ns2", "key9", []byte(jsonValue9), version.NewHeight(1, 20))
   654  	batch.Put("ns2", "key10", []byte(jsonValue10), version.NewHeight(1, 21))
   655  
   656  	savePoint := version.NewHeight(2, 22)
   657  	require.NoError(t, db.ApplyUpdates(batch, savePoint))
   658  
   659  	indexData := map[string][]byte{
   660  		"META-INF/statedb/couchdb/indexes/indexColorSortName.json":                                               []byte(`{"index":{"fields":[{"color":"desc"}]},"ddoc":"indexColorSortName","name":"indexColorSortName","type":"json"}`),
   661  		"META-INF/statedb/couchdb/indexes/indexSizeSortName.json":                                                []byte(`{"index":{"fields":[{"size":"desc"}]},"ddoc":"indexSizeSortName","name":"indexSizeSortName","type":"json"}`),
   662  		"META-INF/statedb/couchdb/collections/collectionMarbles/indexes/indexCollMarbles.json":                   []byte(`{"index":{"fields":["docType","owner"]},"ddoc":"indexCollectionMarbles", "name":"indexCollectionMarbles","type":"json"}`),
   663  		"META-INF/statedb/couchdb/collections/collectionMarblesPrivateDetails/indexes/indexCollPrivDetails.json": []byte(`{"index":{"fields":["docType","price"]},"ddoc":"indexPrivateDetails", "name":"indexPrivateDetails","type":"json"}`),
   664  	}
   665  
   666  	// Create a query
   667  	queryString := `{"selector":{"owner":"fred"}}`
   668  
   669  	_, err = db.ExecuteQuery("ns1", queryString)
   670  	require.NoError(t, err)
   671  
   672  	// Create a query with a sort
   673  	queryString = `{"selector":{"owner":"fred"}, "sort": [{"size": "desc"}]}`
   674  
   675  	_, err = db.ExecuteQuery("ns1", queryString)
   676  	require.Error(t, err, "Error should have been thrown for a missing index")
   677  
   678  	indexCapable, ok := db.(statedb.IndexCapable)
   679  	if !ok {
   680  		t.Fatalf("Couchdb state impl is expected to implement interface `statedb.IndexCapable`")
   681  	}
   682  	require.NoError(t, indexCapable.ProcessIndexesForChaincodeDeploy("ns1", indexData))
   683  
   684  	queryString = `{"selector":{"owner":"fred"}, "sort": [{"size": "desc"}]}`
   685  	queryUsingIndex := func() bool {
   686  		_, err = db.ExecuteQuery("ns1", queryString)
   687  		return err == nil
   688  	}
   689  	require.Eventually(t, queryUsingIndex, 2*time.Second, 100*time.Millisecond, "error executing query with sort")
   690  
   691  	// Query namespace "ns2", index is only created in "ns1".  This should return an error.
   692  	_, err = db.ExecuteQuery("ns2", queryString)
   693  	require.Error(t, err, "Error should have been thrown for a missing index")
   694  }
   695  
   696  func TestTryCastingToJSON(t *testing.T) {
   697  	sampleJSON := []byte(`{"a":"A", "b":"B"}`)
   698  	isJSON, jsonVal := tryCastingToJSON(sampleJSON)
   699  	require.True(t, isJSON)
   700  	require.Equal(t, "A", jsonVal["a"])
   701  	require.Equal(t, "B", jsonVal["b"])
   702  
   703  	sampleNonJSON := []byte(`This is not a json`)
   704  	isJSON, _ = tryCastingToJSON(sampleNonJSON)
   705  	require.False(t, isJSON)
   706  }
   707  
   708  func TestIndexDeploymentWithOrderAndBadSyntax(t *testing.T) {
   709  	channelName := "ch1"
   710  	vdbEnv.init(t, nil)
   711  	defer vdbEnv.cleanup()
   712  	db, err := vdbEnv.DBProvider.GetDBHandle(channelName, nil)
   713  	require.NoError(t, err)
   714  	require.NoError(t, db.Open())
   715  	defer db.Close()
   716  
   717  	batch := statedb.NewUpdateBatch()
   718  	batch.Put("ns1", "key1", []byte(`{"asset_name": "marble1","color": "blue","size": 1,"owner": "tom"}`), version.NewHeight(1, 1))
   719  	batch.Put("ns1", "key2", []byte(`{"asset_name": "marble2","color": "blue","size": 2,"owner": "jerry"}`), version.NewHeight(1, 2))
   720  
   721  	indexCapable, ok := db.(statedb.IndexCapable)
   722  	if !ok {
   723  		t.Fatalf("Couchdb state impl is expected to implement interface `statedb.IndexCapable`")
   724  	}
   725  
   726  	badSyntaxFileContent := `{"index":{"fields": This is a bad json}`
   727  	indexData := map[string][]byte{
   728  		"META-INF/statedb/couchdb/indexes/indexColorSortName.json":                             []byte(`{"index":{"fields":[{"color":"desc"}]},"ddoc":"indexSizeSortName","name":"indexSizeSortName","type":"json"}`),
   729  		"META-INF/statedb/couchdb/indexes/indexSizeSortName.json":                              []byte(`{"index":{"fields":[{"size":"desc"}]},"ddoc":"indexSizeSortName","name":"indexSizeSortName","type":"json"}`),
   730  		"META-INF/statedb/couchdb/indexes/badSyntax.json":                                      []byte(badSyntaxFileContent),
   731  		"META-INF/statedb/couchdb/collections/collectionMarbles/indexes/indexCollMarbles.json": []byte(`{"index":{"fields":["docType","owner"]},"ddoc":"indexCollectionMarbles", "name":"indexCollectionMarbles","type":"json"}`),
   732  	}
   733  
   734  	// as the indexes are sorted by file names, the order of index processing would be
   735  	// (1) indexCollMarbles.json, (2) badSyntax.json, (3) indexColorSortName, (4) indexSizeSortName.
   736  	// As the indexColorSortName.json and indexSizeSortName has the same index name but different
   737  	// index fields, the later would replace the former, i.e., index would be created on size field
   738  	// rather than the color field. Further, the index with a bad syntax would not stop the processing
   739  	// of other valid indexes.
   740  	require.NoError(t, indexCapable.ProcessIndexesForChaincodeDeploy("ns1", indexData))
   741  
   742  	queryString := `{"selector":{"owner":"fred"}, "sort": [{"docType": "desc"}]}`
   743  	queryUsingIndex := func() bool {
   744  		_, err = db.ExecuteQuery("ns1", queryString)
   745  		return err == nil
   746  	}
   747  	require.Eventually(t, queryUsingIndex, 2*time.Second, 100*time.Millisecond, "error executing query with sort")
   748  
   749  	queryString = `{"selector":{"owner":"fred"}, "sort": [{"size": "desc"}]}`
   750  	queryUsingIndex = func() bool {
   751  		_, err = db.ExecuteQuery("ns1", queryString)
   752  		return err == nil
   753  	}
   754  	require.Eventually(t, queryUsingIndex, 2*time.Second, 100*time.Millisecond, "error executing query with sort")
   755  
   756  	// though the indexColorSortName.json is processed before indexSizeSortName.json as per the order,
   757  	// the later would replace the former as the index names are the same. Hence, a query using the color
   758  	// field in sort should fail.
   759  	queryString = `{"selector":{"owner":"fred"}, "sort": [{"color": "desc"}]}`
   760  	queryUsingIndex = func() bool {
   761  		_, err = db.ExecuteQuery("ns1", queryString)
   762  		return err == nil
   763  	}
   764  	require.Never(t, queryUsingIndex, 2*time.Second, 100*time.Millisecond, "error should have occurred as there is no index on color field")
   765  }
   766  
   767  func TestIsBulkOptimizable(t *testing.T) {
   768  	var db statedb.VersionedDB = &VersionedDB{}
   769  	_, ok := db.(statedb.BulkOptimizable)
   770  	if !ok {
   771  		t.Fatal("state couch db is expected to implement interface statedb.BulkOptimizable")
   772  	}
   773  }
   774  
   775  func printCompositeKeys(keys []*statedb.CompositeKey) string {
   776  	compositeKeyString := []string{}
   777  	for _, key := range keys {
   778  		compositeKeyString = append(compositeKeyString, "["+key.Namespace+","+key.Key+"]")
   779  	}
   780  	return strings.Join(compositeKeyString, ",")
   781  }
   782  
   783  // TestPaginatedQuery tests queries with pagination
   784  func TestPaginatedQuery(t *testing.T) {
   785  	vdbEnv.init(t, nil)
   786  	defer vdbEnv.cleanup()
   787  
   788  	db, err := vdbEnv.DBProvider.GetDBHandle("testpaginatedquery", nil)
   789  	require.NoError(t, err)
   790  	require.NoError(t, db.Open())
   791  	defer db.Close()
   792  
   793  	batch := statedb.NewUpdateBatch()
   794  	jsonValue1 := `{"asset_name": "marble1","color": "blue","size": 1,"owner": "tom"}`
   795  	batch.Put("ns1", "key1", []byte(jsonValue1), version.NewHeight(1, 1))
   796  	jsonValue2 := `{"asset_name": "marble2","color": "red","size": 2,"owner": "jerry"}`
   797  	batch.Put("ns1", "key2", []byte(jsonValue2), version.NewHeight(1, 2))
   798  	jsonValue3 := `{"asset_name": "marble3","color": "red","size": 3,"owner": "fred"}`
   799  	batch.Put("ns1", "key3", []byte(jsonValue3), version.NewHeight(1, 3))
   800  	jsonValue4 := `{"asset_name": "marble4","color": "red","size": 4,"owner": "martha"}`
   801  	batch.Put("ns1", "key4", []byte(jsonValue4), version.NewHeight(1, 4))
   802  	jsonValue5 := `{"asset_name": "marble5","color": "blue","size": 5,"owner": "fred"}`
   803  	batch.Put("ns1", "key5", []byte(jsonValue5), version.NewHeight(1, 5))
   804  	jsonValue6 := `{"asset_name": "marble6","color": "red","size": 6,"owner": "elaine"}`
   805  	batch.Put("ns1", "key6", []byte(jsonValue6), version.NewHeight(1, 6))
   806  	jsonValue7 := `{"asset_name": "marble7","color": "blue","size": 7,"owner": "fred"}`
   807  	batch.Put("ns1", "key7", []byte(jsonValue7), version.NewHeight(1, 7))
   808  	jsonValue8 := `{"asset_name": "marble8","color": "red","size": 8,"owner": "elaine"}`
   809  	batch.Put("ns1", "key8", []byte(jsonValue8), version.NewHeight(1, 8))
   810  	jsonValue9 := `{"asset_name": "marble9","color": "green","size": 9,"owner": "fred"}`
   811  	batch.Put("ns1", "key9", []byte(jsonValue9), version.NewHeight(1, 9))
   812  	jsonValue10 := `{"asset_name": "marble10","color": "green","size": 10,"owner": "mary"}`
   813  	batch.Put("ns1", "key10", []byte(jsonValue10), version.NewHeight(1, 10))
   814  
   815  	jsonValue11 := `{"asset_name": "marble11","color": "cyan","size": 11,"owner": "joe"}`
   816  	batch.Put("ns1", "key11", []byte(jsonValue11), version.NewHeight(1, 11))
   817  	jsonValue12 := `{"asset_name": "marble12","color": "red","size": 12,"owner": "martha"}`
   818  	batch.Put("ns1", "key12", []byte(jsonValue12), version.NewHeight(1, 4))
   819  	jsonValue13 := `{"asset_name": "marble13","color": "red","size": 13,"owner": "james"}`
   820  	batch.Put("ns1", "key13", []byte(jsonValue13), version.NewHeight(1, 4))
   821  	jsonValue14 := `{"asset_name": "marble14","color": "red","size": 14,"owner": "fred"}`
   822  	batch.Put("ns1", "key14", []byte(jsonValue14), version.NewHeight(1, 4))
   823  	jsonValue15 := `{"asset_name": "marble15","color": "red","size": 15,"owner": "mary"}`
   824  	batch.Put("ns1", "key15", []byte(jsonValue15), version.NewHeight(1, 4))
   825  	jsonValue16 := `{"asset_name": "marble16","color": "red","size": 16,"owner": "robert"}`
   826  	batch.Put("ns1", "key16", []byte(jsonValue16), version.NewHeight(1, 4))
   827  	jsonValue17 := `{"asset_name": "marble17","color": "red","size": 17,"owner": "alan"}`
   828  	batch.Put("ns1", "key17", []byte(jsonValue17), version.NewHeight(1, 4))
   829  	jsonValue18 := `{"asset_name": "marble18","color": "red","size": 18,"owner": "elaine"}`
   830  	batch.Put("ns1", "key18", []byte(jsonValue18), version.NewHeight(1, 4))
   831  	jsonValue19 := `{"asset_name": "marble19","color": "red","size": 19,"owner": "alan"}`
   832  	batch.Put("ns1", "key19", []byte(jsonValue19), version.NewHeight(1, 4))
   833  	jsonValue20 := `{"asset_name": "marble20","color": "red","size": 20,"owner": "elaine"}`
   834  	batch.Put("ns1", "key20", []byte(jsonValue20), version.NewHeight(1, 4))
   835  
   836  	jsonValue21 := `{"asset_name": "marble21","color": "cyan","size": 21,"owner": "joe"}`
   837  	batch.Put("ns1", "key21", []byte(jsonValue21), version.NewHeight(1, 11))
   838  	jsonValue22 := `{"asset_name": "marble22","color": "red","size": 22,"owner": "martha"}`
   839  	batch.Put("ns1", "key22", []byte(jsonValue22), version.NewHeight(1, 4))
   840  	jsonValue23 := `{"asset_name": "marble23","color": "blue","size": 23,"owner": "james"}`
   841  	batch.Put("ns1", "key23", []byte(jsonValue23), version.NewHeight(1, 4))
   842  	jsonValue24 := `{"asset_name": "marble24","color": "red","size": 24,"owner": "fred"}`
   843  	batch.Put("ns1", "key24", []byte(jsonValue24), version.NewHeight(1, 4))
   844  	jsonValue25 := `{"asset_name": "marble25","color": "red","size": 25,"owner": "mary"}`
   845  	batch.Put("ns1", "key25", []byte(jsonValue25), version.NewHeight(1, 4))
   846  	jsonValue26 := `{"asset_name": "marble26","color": "red","size": 26,"owner": "robert"}`
   847  	batch.Put("ns1", "key26", []byte(jsonValue26), version.NewHeight(1, 4))
   848  	jsonValue27 := `{"asset_name": "marble27","color": "green","size": 27,"owner": "alan"}`
   849  	batch.Put("ns1", "key27", []byte(jsonValue27), version.NewHeight(1, 4))
   850  	jsonValue28 := `{"asset_name": "marble28","color": "red","size": 28,"owner": "elaine"}`
   851  	batch.Put("ns1", "key28", []byte(jsonValue28), version.NewHeight(1, 4))
   852  	jsonValue29 := `{"asset_name": "marble29","color": "red","size": 29,"owner": "alan"}`
   853  	batch.Put("ns1", "key29", []byte(jsonValue29), version.NewHeight(1, 4))
   854  	jsonValue30 := `{"asset_name": "marble30","color": "red","size": 30,"owner": "elaine"}`
   855  	batch.Put("ns1", "key30", []byte(jsonValue30), version.NewHeight(1, 4))
   856  
   857  	jsonValue31 := `{"asset_name": "marble31","color": "cyan","size": 31,"owner": "joe"}`
   858  	batch.Put("ns1", "key31", []byte(jsonValue31), version.NewHeight(1, 11))
   859  	jsonValue32 := `{"asset_name": "marble32","color": "red","size": 32,"owner": "martha"}`
   860  	batch.Put("ns1", "key32", []byte(jsonValue32), version.NewHeight(1, 4))
   861  	jsonValue33 := `{"asset_name": "marble33","color": "red","size": 33,"owner": "james"}`
   862  	batch.Put("ns1", "key33", []byte(jsonValue33), version.NewHeight(1, 4))
   863  	jsonValue34 := `{"asset_name": "marble34","color": "red","size": 34,"owner": "fred"}`
   864  	batch.Put("ns1", "key34", []byte(jsonValue34), version.NewHeight(1, 4))
   865  	jsonValue35 := `{"asset_name": "marble35","color": "red","size": 35,"owner": "mary"}`
   866  	batch.Put("ns1", "key35", []byte(jsonValue35), version.NewHeight(1, 4))
   867  	jsonValue36 := `{"asset_name": "marble36","color": "orange","size": 36,"owner": "robert"}`
   868  	batch.Put("ns1", "key36", []byte(jsonValue36), version.NewHeight(1, 4))
   869  	jsonValue37 := `{"asset_name": "marble37","color": "red","size": 37,"owner": "alan"}`
   870  	batch.Put("ns1", "key37", []byte(jsonValue37), version.NewHeight(1, 4))
   871  	jsonValue38 := `{"asset_name": "marble38","color": "yellow","size": 38,"owner": "elaine"}`
   872  	batch.Put("ns1", "key38", []byte(jsonValue38), version.NewHeight(1, 4))
   873  	jsonValue39 := `{"asset_name": "marble39","color": "red","size": 39,"owner": "alan"}`
   874  	batch.Put("ns1", "key39", []byte(jsonValue39), version.NewHeight(1, 4))
   875  	jsonValue40 := `{"asset_name": "marble40","color": "red","size": 40,"owner": "elaine"}`
   876  	batch.Put("ns1", "key40", []byte(jsonValue40), version.NewHeight(1, 4))
   877  
   878  	savePoint := version.NewHeight(2, 22)
   879  	require.NoError(t, db.ApplyUpdates(batch, savePoint))
   880  
   881  	indexData := map[string][]byte{
   882  		"META-INF/statedb/couchdb/indexes/indexSizeSortName.json": []byte(`{"index":{"fields":[{"size":"desc"}]},"ddoc":"indexSizeSortName","name":"indexSizeSortName","type":"json"}`),
   883  	}
   884  
   885  	// Create a query
   886  	queryString := `{"selector":{"color":"red"}}`
   887  
   888  	_, err = db.ExecuteQuery("ns1", queryString)
   889  	require.NoError(t, err)
   890  
   891  	indexCapable, ok := db.(statedb.IndexCapable)
   892  	if !ok {
   893  		t.Fatalf("Couchdb state impl is expected to implement interface `statedb.IndexCapable`")
   894  	}
   895  
   896  	require.NoError(t, indexCapable.ProcessIndexesForChaincodeDeploy("ns1", indexData))
   897  	// Sleep to allow time for index creation
   898  	time.Sleep(100 * time.Millisecond)
   899  	// Create a query with a sort
   900  	queryString = `{"selector":{"color":"red"}, "sort": [{"size": "asc"}]}`
   901  
   902  	// Query should complete without error
   903  	_, err = db.ExecuteQuery("ns1", queryString)
   904  	require.NoError(t, err)
   905  
   906  	// Test explicit paging
   907  	// Execute 3 page queries, there are 28 records with color red, use page size 10
   908  	returnKeys := []string{"key2", "key3", "key4", "key6", "key8", "key12", "key13", "key14", "key15", "key16"}
   909  	bookmark, err := executeQuery(t, db, "ns1", queryString, "", int32(10), returnKeys)
   910  	require.NoError(t, err)
   911  	returnKeys = []string{"key17", "key18", "key19", "key20", "key22", "key24", "key25", "key26", "key28", "key29"}
   912  	bookmark, err = executeQuery(t, db, "ns1", queryString, bookmark, int32(10), returnKeys)
   913  	require.NoError(t, err)
   914  
   915  	returnKeys = []string{"key30", "key32", "key33", "key34", "key35", "key37", "key39", "key40"}
   916  	_, err = executeQuery(t, db, "ns1", queryString, bookmark, int32(10), returnKeys)
   917  	require.NoError(t, err)
   918  
   919  	// Test explicit paging
   920  	// Increase pagesize to 50,  should return all values
   921  	returnKeys = []string{
   922  		"key2", "key3", "key4", "key6", "key8", "key12", "key13", "key14", "key15",
   923  		"key16", "key17", "key18", "key19", "key20", "key22", "key24", "key25", "key26", "key28", "key29",
   924  		"key30", "key32", "key33", "key34", "key35", "key37", "key39", "key40",
   925  	}
   926  	_, err = executeQuery(t, db, "ns1", queryString, "", int32(50), returnKeys)
   927  	require.NoError(t, err)
   928  
   929  	// Test explicit paging
   930  	// Pagesize is 10, so all 28 records should be return in 3 "pages"
   931  	returnKeys = []string{"key2", "key3", "key4", "key6", "key8", "key12", "key13", "key14", "key15", "key16"}
   932  	bookmark, err = executeQuery(t, db, "ns1", queryString, "", int32(10), returnKeys)
   933  	require.NoError(t, err)
   934  	returnKeys = []string{"key17", "key18", "key19", "key20", "key22", "key24", "key25", "key26", "key28", "key29"}
   935  	bookmark, err = executeQuery(t, db, "ns1", queryString, bookmark, int32(10), returnKeys)
   936  	require.NoError(t, err)
   937  	returnKeys = []string{"key30", "key32", "key33", "key34", "key35", "key37", "key39", "key40"}
   938  	_, err = executeQuery(t, db, "ns1", queryString, bookmark, int32(10), returnKeys)
   939  	require.NoError(t, err)
   940  
   941  	// Test implicit paging
   942  	returnKeys = []string{
   943  		"key2", "key3", "key4", "key6", "key8", "key12", "key13", "key14", "key15",
   944  		"key16", "key17", "key18", "key19", "key20", "key22", "key24", "key25", "key26", "key28", "key29",
   945  		"key30", "key32", "key33", "key34", "key35", "key37", "key39", "key40",
   946  	}
   947  	_, err = executeQuery(t, db, "ns1", queryString, "", int32(0), returnKeys)
   948  	require.NoError(t, err)
   949  
   950  	// pagesize greater than querysize will execute with implicit paging
   951  	returnKeys = []string{"key2", "key3", "key4", "key6", "key8", "key12", "key13", "key14", "key15", "key16"}
   952  	_, err = executeQuery(t, db, "ns1", queryString, "", int32(10), returnKeys)
   953  	require.NoError(t, err)
   954  }
   955  
   956  func executeQuery(t *testing.T, db statedb.VersionedDB, namespace, query, bookmark string, pageSize int32, returnKeys []string) (string, error) {
   957  	var itr statedb.ResultsIterator
   958  	var err error
   959  
   960  	if pageSize == int32(0) && bookmark == "" {
   961  		itr, err = db.ExecuteQuery(namespace, query)
   962  		if err != nil {
   963  			return "", err
   964  		}
   965  	} else {
   966  		itr, err = db.ExecuteQueryWithPagination(namespace, query, bookmark, pageSize)
   967  		if err != nil {
   968  			return "", err
   969  		}
   970  	}
   971  
   972  	// Verify the keys returned
   973  	commontests.TestItrWithoutClose(t, itr, returnKeys)
   974  
   975  	returnBookmark := ""
   976  	if queryResultItr, ok := itr.(statedb.QueryResultsIterator); ok {
   977  		returnBookmark = queryResultItr.GetBookmarkAndClose()
   978  	}
   979  
   980  	return returnBookmark, nil
   981  }
   982  
   983  func TestApplyUpdatesWithNilHeight(t *testing.T) {
   984  	vdbEnv.init(t, nil)
   985  	defer vdbEnv.cleanup()
   986  	commontests.TestApplyUpdatesWithNilHeight(t, vdbEnv.DBProvider)
   987  }
   988  
   989  func TestRangeScanWithCouchInternalDocsPresent(t *testing.T) {
   990  	vdbEnv.init(t, nil)
   991  	defer vdbEnv.cleanup()
   992  	db, err := vdbEnv.DBProvider.GetDBHandle("testrangescanfiltercouchinternaldocs", nil)
   993  	require.NoError(t, err)
   994  	couchDatabse, err := db.(*VersionedDB).getNamespaceDBHandle("ns")
   995  	require.NoError(t, err)
   996  	require.NoError(t, db.Open())
   997  	defer db.Close()
   998  	_, err = couchDatabse.createIndex(`{
   999  		"index" : {"fields" : ["asset_name"]},
  1000  			"ddoc" : "indexAssetName",
  1001  			"name" : "indexAssetName",
  1002  			"type" : "json"
  1003  		}`)
  1004  	require.NoError(t, err)
  1005  
  1006  	_, err = couchDatabse.createIndex(`{
  1007  		"index" : {"fields" : ["assetValue"]},
  1008  			"ddoc" : "indexAssetValue",
  1009  			"name" : "indexAssetValue",
  1010  			"type" : "json"
  1011  		}`)
  1012  	require.NoError(t, err)
  1013  
  1014  	batch := statedb.NewUpdateBatch()
  1015  	for i := 1; i <= 3; i++ {
  1016  		keySmallerThanDesignDoc := fmt.Sprintf("Key-%d", i)
  1017  		keyGreaterThanDesignDoc := fmt.Sprintf("key-%d", i)
  1018  		jsonValue := fmt.Sprintf(`{"asset_name": "marble-%d"}`, i)
  1019  		batch.Put("ns", keySmallerThanDesignDoc, []byte(jsonValue), version.NewHeight(1, uint64(i)))
  1020  		batch.Put("ns", keyGreaterThanDesignDoc, []byte(jsonValue), version.NewHeight(1, uint64(i)))
  1021  	}
  1022  	require.NoError(t, db.ApplyUpdates(batch, version.NewHeight(2, 2)))
  1023  	require.NoError(t, err)
  1024  
  1025  	// The Keys in db are in this order
  1026  	// Key-1, Key-2, Key-3,_design/indexAssetNam, _design/indexAssetValue, key-1, key-2, key-3
  1027  	// query different ranges and verify results
  1028  	s, err := newQueryScanner("ns", couchDatabse, "", 3, 3, "", "", "")
  1029  	require.NoError(t, err)
  1030  	assertQueryResults(t, s.resultsInfo.results, []string{"Key-1", "Key-2", "Key-3"})
  1031  	require.Equal(t, "key-1", s.queryDefinition.startKey)
  1032  
  1033  	s, err = newQueryScanner("ns", couchDatabse, "", 4, 4, "", "", "")
  1034  	require.NoError(t, err)
  1035  	assertQueryResults(t, s.resultsInfo.results, []string{"Key-1", "Key-2", "Key-3", "key-1"})
  1036  	require.Equal(t, "key-2", s.queryDefinition.startKey)
  1037  
  1038  	s, err = newQueryScanner("ns", couchDatabse, "", 2, 2, "", "", "")
  1039  	require.NoError(t, err)
  1040  	assertQueryResults(t, s.resultsInfo.results, []string{"Key-1", "Key-2"})
  1041  	require.Equal(t, "Key-3", s.queryDefinition.startKey)
  1042  	require.NoError(t, s.getNextStateRangeScanResults())
  1043  	assertQueryResults(t, s.resultsInfo.results, []string{"Key-3", "key-1"})
  1044  	require.Equal(t, "key-2", s.queryDefinition.startKey)
  1045  
  1046  	s, err = newQueryScanner("ns", couchDatabse, "", 2, 2, "", "_", "")
  1047  	require.NoError(t, err)
  1048  	assertQueryResults(t, s.resultsInfo.results, []string{"key-1", "key-2"})
  1049  	require.Equal(t, "key-3", s.queryDefinition.startKey)
  1050  }
  1051  
  1052  func assertQueryResults(t *testing.T, results []*queryResult, expectedIds []string) {
  1053  	var actualIds []string
  1054  	for _, res := range results {
  1055  		actualIds = append(actualIds, res.id)
  1056  	}
  1057  	require.Equal(t, expectedIds, actualIds)
  1058  }
  1059  
  1060  func TestFormatCheck(t *testing.T) {
  1061  	testCases := []struct {
  1062  		dataFormat     string                        // precondition
  1063  		dataExists     bool                          // precondition
  1064  		expectedFormat string                        // postcondition
  1065  		expectedErr    *dataformat.ErrFormatMismatch // postcondition
  1066  	}{
  1067  		{
  1068  			dataFormat: "",
  1069  			dataExists: true,
  1070  			expectedErr: &dataformat.ErrFormatMismatch{
  1071  				DBInfo:         "CouchDB for state database",
  1072  				Format:         "",
  1073  				ExpectedFormat: "2.0",
  1074  			},
  1075  			expectedFormat: "does not matter as the test should not reach to check this",
  1076  		},
  1077  
  1078  		{
  1079  			dataFormat:     "",
  1080  			dataExists:     false,
  1081  			expectedErr:    nil,
  1082  			expectedFormat: dataformat.CurrentFormat,
  1083  		},
  1084  
  1085  		{
  1086  			dataFormat:     dataformat.CurrentFormat,
  1087  			dataExists:     false,
  1088  			expectedFormat: dataformat.CurrentFormat,
  1089  			expectedErr:    nil,
  1090  		},
  1091  
  1092  		{
  1093  			dataFormat:     dataformat.CurrentFormat,
  1094  			dataExists:     true,
  1095  			expectedFormat: dataformat.CurrentFormat,
  1096  			expectedErr:    nil,
  1097  		},
  1098  
  1099  		{
  1100  			dataFormat: "3.0",
  1101  			dataExists: true,
  1102  			expectedErr: &dataformat.ErrFormatMismatch{
  1103  				DBInfo:         "CouchDB for state database",
  1104  				Format:         "3.0",
  1105  				ExpectedFormat: dataformat.CurrentFormat,
  1106  			},
  1107  			expectedFormat: "does not matter as the test should not reach to check this",
  1108  		},
  1109  	}
  1110  
  1111  	vdbEnv.init(t, nil)
  1112  	for i, testCase := range testCases {
  1113  		t.Run(
  1114  			fmt.Sprintf("testCase %d", i),
  1115  			func(t *testing.T) {
  1116  				testFormatCheck(t, testCase.dataFormat, testCase.dataExists, testCase.expectedErr, testCase.expectedFormat, vdbEnv)
  1117  			})
  1118  	}
  1119  }
  1120  
  1121  func testFormatCheck(t *testing.T, dataFormat string, dataExists bool, expectedErr *dataformat.ErrFormatMismatch, expectedFormat string, vdbEnv *testVDBEnv) {
  1122  	redoPath, err := ioutil.TempDir("", "redoPath")
  1123  	require.NoError(t, err)
  1124  	defer os.RemoveAll(redoPath)
  1125  	config := &ledger.CouchDBConfig{
  1126  		Address:             vdbEnv.couchDBEnv.couchAddress,
  1127  		Username:            "admin",
  1128  		Password:            "adminpw",
  1129  		MaxRetries:          3,
  1130  		MaxRetriesOnStartup: 20,
  1131  		RequestTimeout:      35 * time.Second,
  1132  		RedoLogPath:         redoPath,
  1133  	}
  1134  	dbProvider, err := NewVersionedDBProvider(config, &disabled.Provider{}, nil)
  1135  	require.NoError(t, err)
  1136  
  1137  	// create preconditions for test
  1138  	if dataExists {
  1139  		db, err := dbProvider.GetDBHandle("testns", nil)
  1140  		require.NoError(t, err)
  1141  		batch := statedb.NewUpdateBatch()
  1142  		batch.Put("testns", "testkey", []byte("testVal"), version.NewHeight(1, 1))
  1143  		require.NoError(t, db.ApplyUpdates(batch, version.NewHeight(1, 1)))
  1144  	}
  1145  	if dataFormat == "" {
  1146  		err := dropDB(dbProvider.couchInstance, fabricInternalDBName)
  1147  		require.NoError(t, err)
  1148  	} else {
  1149  		require.NoError(t, writeDataFormatVersion(dbProvider.couchInstance, dataFormat))
  1150  	}
  1151  	dbProvider.Close()
  1152  	defer func() {
  1153  		require.NoError(t, DropApplicationDBs(vdbEnv.config))
  1154  	}()
  1155  
  1156  	// close and reopen with preconditions set and check the expected behavior
  1157  	dbProvider, err = NewVersionedDBProvider(config, &disabled.Provider{}, nil)
  1158  	if expectedErr != nil {
  1159  		require.Equal(t, expectedErr, err)
  1160  		return
  1161  	}
  1162  	require.NoError(t, err)
  1163  	defer func() {
  1164  		if dbProvider != nil {
  1165  			dbProvider.Close()
  1166  		}
  1167  	}()
  1168  	format, err := readDataformatVersion(dbProvider.couchInstance)
  1169  	require.NoError(t, err)
  1170  	require.Equal(t, expectedFormat, format)
  1171  }
  1172  
  1173  func testDoesNotExistInCache(t *testing.T, cache *cache, chainID, ns, key string) {
  1174  	cacheValue, err := cache.getState(chainID, ns, key)
  1175  	require.NoError(t, err)
  1176  	require.Nil(t, cacheValue)
  1177  }
  1178  
  1179  func testExistInCache(t *testing.T, db *couchDatabase, cache *cache, chainID, ns, key string, expectedVV *statedb.VersionedValue) {
  1180  	cacheValue, err := cache.getState(chainID, ns, key)
  1181  	require.NoError(t, err)
  1182  	vv, err := constructVersionedValue(cacheValue)
  1183  	require.NoError(t, err)
  1184  	require.Equal(t, expectedVV, vv)
  1185  	metadata, err := retrieveNsMetadata(db, []string{key})
  1186  	require.NoError(t, err)
  1187  	require.Equal(t, metadata[0].Rev, string(cacheValue.AdditionalInfo))
  1188  }
  1189  
  1190  func TestLoadCommittedVersion(t *testing.T) {
  1191  	vdbEnv.init(t, []string{"lscc", "_lifecycle"})
  1192  	defer vdbEnv.cleanup()
  1193  
  1194  	chainID := "testloadcommittedversion"
  1195  	db, err := vdbEnv.DBProvider.GetDBHandle(chainID, nil)
  1196  	require.NoError(t, err)
  1197  
  1198  	// scenario: state cache has (ns1, key1), (ns1, key2),
  1199  	// and (ns2, key1) but misses (ns2, key2). The
  1200  	// LoadCommittedVersions will fetch the first
  1201  	// three keys from the state cache and the remaining one from
  1202  	// the db. To ensure that, the db contains only
  1203  	// the missing key (ns2, key2).
  1204  
  1205  	// store (ns1, key1), (ns1, key2), (ns2, key1) in the state cache
  1206  	cacheValue := &CacheValue{
  1207  		Value:          []byte("value1"),
  1208  		Metadata:       []byte("meta1"),
  1209  		Version:        version.NewHeight(1, 1).ToBytes(),
  1210  		AdditionalInfo: []byte("rev1"),
  1211  	}
  1212  	require.NoError(t, vdbEnv.cache.putState(chainID, "ns1", "key1", cacheValue))
  1213  
  1214  	cacheValue = &CacheValue{
  1215  		Value:          []byte("value2"),
  1216  		Metadata:       []byte("meta2"),
  1217  		Version:        version.NewHeight(1, 2).ToBytes(),
  1218  		AdditionalInfo: []byte("rev2"),
  1219  	}
  1220  	require.NoError(t, vdbEnv.cache.putState(chainID, "ns1", "key2", cacheValue))
  1221  
  1222  	cacheValue = &CacheValue{
  1223  		Value:          []byte("value3"),
  1224  		Metadata:       []byte("meta3"),
  1225  		Version:        version.NewHeight(1, 3).ToBytes(),
  1226  		AdditionalInfo: []byte("rev3"),
  1227  	}
  1228  	require.NoError(t, vdbEnv.cache.putState(chainID, "ns2", "key1", cacheValue))
  1229  
  1230  	// store (ns2, key2) in the db
  1231  	batch := statedb.NewUpdateBatch()
  1232  	vv := &statedb.VersionedValue{Value: []byte("value4"), Metadata: []byte("meta4"), Version: version.NewHeight(1, 4)}
  1233  	batch.PutValAndMetadata("ns2", "key2", vv.Value, vv.Metadata, vv.Version)
  1234  	savePoint := version.NewHeight(2, 2)
  1235  	require.NoError(t, db.ApplyUpdates(batch, savePoint))
  1236  
  1237  	// version cache should be empty
  1238  	ver, ok := db.(*VersionedDB).GetCachedVersion("ns1", "key1")
  1239  	require.Nil(t, ver)
  1240  	require.False(t, ok)
  1241  	ver, ok = db.(*VersionedDB).GetCachedVersion("ns1", "key2")
  1242  	require.Nil(t, ver)
  1243  	require.False(t, ok)
  1244  	ver, ok = db.(*VersionedDB).GetCachedVersion("ns2", "key1")
  1245  	require.Nil(t, ver)
  1246  	require.False(t, ok)
  1247  	ver, ok = db.(*VersionedDB).GetCachedVersion("ns2", "key2")
  1248  	require.Nil(t, ver)
  1249  	require.False(t, ok)
  1250  
  1251  	keys := []*statedb.CompositeKey{
  1252  		{
  1253  			Namespace: "ns1",
  1254  			Key:       "key1",
  1255  		},
  1256  		{
  1257  			Namespace: "ns1",
  1258  			Key:       "key2",
  1259  		},
  1260  		{
  1261  			Namespace: "ns2",
  1262  			Key:       "key1",
  1263  		},
  1264  		{
  1265  			Namespace: "ns2",
  1266  			Key:       "key2",
  1267  		},
  1268  	}
  1269  
  1270  	require.NoError(t, db.(*VersionedDB).LoadCommittedVersions(keys))
  1271  
  1272  	ver, ok = db.(*VersionedDB).GetCachedVersion("ns1", "key1")
  1273  	require.Equal(t, version.NewHeight(1, 1), ver)
  1274  	require.True(t, ok)
  1275  	ver, ok = db.(*VersionedDB).GetCachedVersion("ns1", "key2")
  1276  	require.Equal(t, version.NewHeight(1, 2), ver)
  1277  	require.True(t, ok)
  1278  	ver, ok = db.(*VersionedDB).GetCachedVersion("ns2", "key1")
  1279  	require.Equal(t, version.NewHeight(1, 3), ver)
  1280  	require.True(t, ok)
  1281  	ver, ok = db.(*VersionedDB).GetCachedVersion("ns2", "key2")
  1282  	require.Equal(t, version.NewHeight(1, 4), ver)
  1283  	require.True(t, ok)
  1284  }
  1285  
  1286  func TestMissingRevisionRetrievalFromDB(t *testing.T) {
  1287  	vdbEnv.init(t, nil)
  1288  	defer vdbEnv.cleanup()
  1289  	chainID := "testmissingrevisionfromdb"
  1290  	db, err := vdbEnv.DBProvider.GetDBHandle(chainID, nil)
  1291  	require.NoError(t, err)
  1292  
  1293  	// store key1, key2, key3 to the DB
  1294  	batch := statedb.NewUpdateBatch()
  1295  	vv1 := statedb.VersionedValue{Value: []byte("value1"), Version: version.NewHeight(1, 1)}
  1296  	vv2 := statedb.VersionedValue{Value: []byte("value2"), Version: version.NewHeight(1, 2)}
  1297  	vv3 := statedb.VersionedValue{Value: []byte("value3"), Version: version.NewHeight(1, 3)}
  1298  	batch.Put("ns1", "key1", vv1.Value, vv1.Version)
  1299  	batch.Put("ns1", "key2", vv2.Value, vv2.Version)
  1300  	batch.Put("ns1", "key3", vv3.Value, vv3.Version)
  1301  	savePoint := version.NewHeight(2, 5)
  1302  	require.NoError(t, db.ApplyUpdates(batch, savePoint))
  1303  
  1304  	// retrieve the versions of key1, key2, and key3
  1305  	revisions := make(map[string]string)
  1306  	require.NoError(t, db.(*VersionedDB).addMissingRevisionsFromDB("ns1", []string{"key1", "key2", "key3"}, revisions))
  1307  	require.Equal(t, 3, len(revisions))
  1308  
  1309  	// update key1 and key2 but not key3
  1310  	batch = statedb.NewUpdateBatch()
  1311  	vv4 := statedb.VersionedValue{Value: []byte("value1"), Version: version.NewHeight(1, 1)}
  1312  	vv5 := statedb.VersionedValue{Value: []byte("value2"), Version: version.NewHeight(1, 2)}
  1313  	batch.Put("ns1", "key1", vv4.Value, vv4.Version)
  1314  	batch.Put("ns1", "key2", vv5.Value, vv5.Version)
  1315  	savePoint = version.NewHeight(3, 5)
  1316  	require.NoError(t, db.ApplyUpdates(batch, savePoint))
  1317  
  1318  	// for key3, the revision should be the same but not for key1 and key2
  1319  	newRevisions := make(map[string]string)
  1320  	require.NoError(t, db.(*VersionedDB).addMissingRevisionsFromDB("ns1", []string{"key1", "key2", "key3"}, newRevisions))
  1321  	require.Equal(t, 3, len(newRevisions))
  1322  	require.NotEqual(t, revisions["key1"], newRevisions["key1"])
  1323  	require.NotEqual(t, revisions["key2"], newRevisions["key2"])
  1324  	require.Equal(t, revisions["key3"], newRevisions["key3"])
  1325  }
  1326  
  1327  func TestMissingRevisionRetrievalFromCache(t *testing.T) {
  1328  	vdbEnv.init(t, []string{"lscc", "_lifecycle"})
  1329  	defer vdbEnv.cleanup()
  1330  
  1331  	chainID := "testmissingrevisionfromcache"
  1332  	db, err := vdbEnv.DBProvider.GetDBHandle(chainID, nil)
  1333  	require.NoError(t, err)
  1334  
  1335  	// scenario 1: missing from cache.
  1336  	revisions := make(map[string]string)
  1337  	stillMissingKeys, err := db.(*VersionedDB).addMissingRevisionsFromCache("ns1", []string{"key1", "key2"}, revisions)
  1338  	require.NoError(t, err)
  1339  	require.Equal(t, []string{"key1", "key2"}, stillMissingKeys)
  1340  	require.Empty(t, revisions)
  1341  
  1342  	// scenario 2: key1 is available in the cache
  1343  	require.NoError(t, vdbEnv.cache.putState(chainID, "ns1", "key1", &CacheValue{AdditionalInfo: []byte("rev1")}))
  1344  	revisions = make(map[string]string)
  1345  	stillMissingKeys, err = db.(*VersionedDB).addMissingRevisionsFromCache("ns1", []string{"key1", "key2"}, revisions)
  1346  	require.NoError(t, err)
  1347  	require.Equal(t, []string{"key2"}, stillMissingKeys)
  1348  	require.Equal(t, "rev1", revisions["key1"])
  1349  
  1350  	// scenario 3: both key1 and key2 are available in the cache
  1351  	require.NoError(t, vdbEnv.cache.putState(chainID, "ns1", "key2", &CacheValue{AdditionalInfo: []byte("rev2")}))
  1352  	revisions = make(map[string]string)
  1353  	stillMissingKeys, err = db.(*VersionedDB).addMissingRevisionsFromCache("ns1", []string{"key1", "key2"}, revisions)
  1354  	require.NoError(t, err)
  1355  	require.Empty(t, stillMissingKeys)
  1356  	require.Equal(t, "rev1", revisions["key1"])
  1357  	require.Equal(t, "rev2", revisions["key2"])
  1358  }
  1359  
  1360  func TestChannelMetadata(t *testing.T) {
  1361  	vdbEnv.init(t, sysNamespaces)
  1362  	defer vdbEnv.cleanup()
  1363  	channelName := "testchannelmetadata"
  1364  
  1365  	db, err := vdbEnv.DBProvider.GetDBHandle(channelName, nil)
  1366  	require.NoError(t, err)
  1367  	vdb := db.(*VersionedDB)
  1368  	expectedChannelMetadata := &channelMetadata{
  1369  		ChannelName:      channelName,
  1370  		NamespaceDBsInfo: make(map[string]*namespaceDBInfo),
  1371  	}
  1372  	savedChannelMetadata, err := vdb.readChannelMetadata()
  1373  	require.NoError(t, err)
  1374  	require.Equal(t, expectedChannelMetadata, savedChannelMetadata)
  1375  	require.Equal(t, expectedChannelMetadata, vdb.channelMetadata)
  1376  
  1377  	// call getNamespaceDBHandle for new dbs, verify that new db names are added to dbMetadataMapping
  1378  	namepsaces := make([]string, 10)
  1379  	for i := 0; i < 10; i++ {
  1380  		ns := fmt.Sprintf("nsname_%d", i)
  1381  		_, err := vdb.getNamespaceDBHandle(ns)
  1382  		require.NoError(t, err)
  1383  		namepsaces[i] = ns
  1384  		expectedChannelMetadata.NamespaceDBsInfo[ns] = &namespaceDBInfo{
  1385  			Namespace: ns,
  1386  			DBName:    constructNamespaceDBName(channelName, ns),
  1387  		}
  1388  	}
  1389  
  1390  	savedChannelMetadata, err = vdb.readChannelMetadata()
  1391  	require.NoError(t, err)
  1392  	require.Equal(t, expectedChannelMetadata, savedChannelMetadata)
  1393  	require.Equal(t, expectedChannelMetadata, vdb.channelMetadata)
  1394  
  1395  	// call getNamespaceDBHandle for existing dbs, verify that no new db names are added to dbMetadataMapping
  1396  	for _, ns := range namepsaces {
  1397  		_, err := vdb.getNamespaceDBHandle(ns)
  1398  		require.NoError(t, err)
  1399  	}
  1400  
  1401  	savedChannelMetadata, err = vdb.readChannelMetadata()
  1402  	require.NoError(t, err)
  1403  	require.Equal(t, expectedChannelMetadata, savedChannelMetadata)
  1404  	require.Equal(t, expectedChannelMetadata, vdb.channelMetadata)
  1405  }
  1406  
  1407  func TestChannelMetadata_NegativeTests(t *testing.T) {
  1408  	vdbEnv.init(t, sysNamespaces)
  1409  	defer vdbEnv.cleanup()
  1410  
  1411  	channelName := "testchannelmetadata-errorpropagation"
  1412  	origCouchAddress := vdbEnv.config.Address
  1413  	vdbEnv.config.MaxRetries = 1
  1414  	vdbEnv.config.MaxRetriesOnStartup = 1
  1415  	vdbEnv.config.RequestTimeout = 1 * time.Second
  1416  
  1417  	// simulate db connection error by setting an invalid address before GetDBHandle, verify error is propagated
  1418  	vdbEnv.config.Address = "127.0.0.1:1"
  1419  	expectedErrMsg := fmt.Sprintf("http error calling couchdb: Get \"http://%s/testchannelmetadata-errorpropagation_\": dial tcp %s: connect: connection refused",
  1420  		vdbEnv.config.Address, vdbEnv.config.Address)
  1421  	_, err := vdbEnv.DBProvider.GetDBHandle(channelName, nil)
  1422  	require.EqualError(t, err, expectedErrMsg)
  1423  	vdbEnv.config.Address = origCouchAddress
  1424  
  1425  	// simulate db connection error by setting an invalid address before getNamespaceDBHandle, verify error is propagated
  1426  	db, err := vdbEnv.DBProvider.GetDBHandle(channelName, nil)
  1427  	require.NoError(t, err)
  1428  	vdb := db.(*VersionedDB)
  1429  	vdbEnv.config.Address = "127.0.0.1:1"
  1430  	expectedErrMsg = fmt.Sprintf("http error calling couchdb: Put \"http://%s/testchannelmetadata-errorpropagation_/channel_metadata\": dial tcp %s: connect: connection refused",
  1431  		vdbEnv.config.Address, vdbEnv.config.Address)
  1432  	_, err = vdb.getNamespaceDBHandle("testnamepsace1")
  1433  	require.EqualError(t, err, expectedErrMsg)
  1434  	vdb.couchInstance.conf.Address = origCouchAddress
  1435  
  1436  	// call createCouchDatabase to simulate peer crashes after metadataDB is created but before channelMetadata is updated
  1437  	// then call DBProvider.GetDBHandle and verify channelMetadata is correctly generated
  1438  	channelName = "testchannelmetadata-simulatefailure-in-between"
  1439  	couchInstance, err := createCouchInstance(vdbEnv.config, &disabled.Provider{})
  1440  	require.NoError(t, err)
  1441  	metadatadbName := constructMetadataDBName(channelName)
  1442  	metadataDB, err := createCouchDatabase(couchInstance, metadatadbName)
  1443  	require.NoError(t, err)
  1444  	vdb = &VersionedDB{
  1445  		metadataDB: metadataDB,
  1446  	}
  1447  	savedChannelMetadata, err := vdb.readChannelMetadata()
  1448  	require.NoError(t, err)
  1449  	require.Nil(t, savedChannelMetadata)
  1450  
  1451  	db, err = vdbEnv.DBProvider.GetDBHandle(channelName, nil)
  1452  	require.NoError(t, err)
  1453  	vdb = db.(*VersionedDB)
  1454  	expectedChannelMetadata := &channelMetadata{
  1455  		ChannelName:      channelName,
  1456  		NamespaceDBsInfo: make(map[string]*namespaceDBInfo),
  1457  	}
  1458  	savedChannelMetadata, err = vdb.readChannelMetadata()
  1459  	require.NoError(t, err)
  1460  	require.Equal(t, expectedChannelMetadata, savedChannelMetadata)
  1461  	require.Equal(t, expectedChannelMetadata, vdb.channelMetadata)
  1462  
  1463  	// call writeChannelMetadata to simulate peer crashes after channelMetada is saved but before namespace DB is created
  1464  	// then call vdb.getNamespaceDBHandle and verify namespaceDB is created and channelMetadata is correct
  1465  	namespace := "testnamepsace2"
  1466  	namespaceDBName := constructNamespaceDBName(channelName, namespace)
  1467  	vdb.channelMetadata.NamespaceDBsInfo[namespace] = &namespaceDBInfo{Namespace: namespace, DBName: namespaceDBName}
  1468  	err = vdb.writeChannelMetadata()
  1469  	require.NoError(t, err)
  1470  	expectedChannelMetadata.NamespaceDBsInfo = map[string]*namespaceDBInfo{
  1471  		namespace: {Namespace: namespace, DBName: namespaceDBName},
  1472  	}
  1473  	savedChannelMetadata, err = vdb.readChannelMetadata()
  1474  	require.NoError(t, err)
  1475  	require.Equal(t, expectedChannelMetadata, savedChannelMetadata)
  1476  	require.Equal(t, expectedChannelMetadata, vdb.channelMetadata)
  1477  
  1478  	_, err = vdb.getNamespaceDBHandle(namespace)
  1479  	require.NoError(t, err)
  1480  	savedChannelMetadata, err = vdb.readChannelMetadata()
  1481  	require.NoError(t, err)
  1482  	require.Equal(t, expectedChannelMetadata, savedChannelMetadata)
  1483  	require.Equal(t, expectedChannelMetadata, vdb.channelMetadata)
  1484  }
  1485  
  1486  func TestInitChannelMetadta(t *testing.T) {
  1487  	vdbEnv.init(t, sysNamespaces)
  1488  	defer vdbEnv.cleanup()
  1489  	channelName1 := "testinithannelmetadata"
  1490  	channelName2 := "testinithannelmetadata_anotherchannel"
  1491  
  1492  	// create versioned DBs for channelName1 and channelName2
  1493  	db, err := vdbEnv.DBProvider.GetDBHandle(channelName1, nil)
  1494  	require.NoError(t, err)
  1495  	vdb := db.(*VersionedDB)
  1496  	db2, err := vdbEnv.DBProvider.GetDBHandle(channelName2, nil)
  1497  	require.NoError(t, err)
  1498  	vdb2 := db2.(*VersionedDB)
  1499  
  1500  	// prepare test data:
  1501  	// create dbs for channelName1: "ns1" and "ns3", which should match channelName1 namespaces
  1502  	// create dbs for channelName2: "ns2" and "ns4", which should not match any channelName1 namespaces
  1503  	_, err = vdb.getNamespaceDBHandle("ns1")
  1504  	require.NoError(t, err)
  1505  	_, err = vdb.getNamespaceDBHandle("ns3")
  1506  	require.NoError(t, err)
  1507  	_, err = vdb2.getNamespaceDBHandle("ns2")
  1508  	require.NoError(t, err)
  1509  	_, err = vdb2.getNamespaceDBHandle("ns4")
  1510  	require.NoError(t, err)
  1511  
  1512  	namespaces := []string{"ns1", "ns2", "ns3", "ns4"}
  1513  	fakeNsProvider := &mock.NamespaceProvider{}
  1514  	fakeNsProvider.PossibleNamespacesReturns(namespaces, nil)
  1515  	expectedDBsInfo := map[string]*namespaceDBInfo{
  1516  		"ns1": {Namespace: "ns1", DBName: constructNamespaceDBName(channelName1, "ns1")},
  1517  		"ns3": {Namespace: "ns3", DBName: constructNamespaceDBName(channelName1, "ns3")},
  1518  	}
  1519  	expectedChannelMetadata := &channelMetadata{
  1520  		ChannelName:      channelName1,
  1521  		NamespaceDBsInfo: expectedDBsInfo,
  1522  	}
  1523  
  1524  	// test an existing DB with channelMetadata, namespace provider should not be called
  1525  	require.NoError(t, vdb.initChannelMetadata(false, fakeNsProvider))
  1526  	require.Equal(t, expectedChannelMetadata, vdb.channelMetadata)
  1527  	require.Equal(t, 0, fakeNsProvider.PossibleNamespacesCallCount())
  1528  
  1529  	// test an existing DB with no channelMetadata by deleting channelMetadata, namespace provider should be called
  1530  	require.NoError(t, vdb.metadataDB.deleteDoc(channelMetadataDocID, ""))
  1531  	require.NoError(t, vdb.initChannelMetadata(false, fakeNsProvider))
  1532  	require.Equal(t, expectedChannelMetadata, vdb.channelMetadata)
  1533  	require.Equal(t, 1, fakeNsProvider.PossibleNamespacesCallCount())
  1534  	savedChannelMetadata, err := vdb.readChannelMetadata()
  1535  	require.NoError(t, err)
  1536  	require.Equal(t, expectedChannelMetadata, savedChannelMetadata)
  1537  
  1538  	// test namespaceProvider error
  1539  	fakeNsProvider.PossibleNamespacesReturns(nil, errors.New("fake-namespaceprivder-error"))
  1540  	require.NoError(t, vdb.metadataDB.deleteDoc(channelMetadataDocID, ""))
  1541  	err = vdb.initChannelMetadata(false, fakeNsProvider)
  1542  	require.EqualError(t, err, "fake-namespaceprivder-error")
  1543  
  1544  	// test db error
  1545  	origCouchAddress := vdbEnv.config.Address
  1546  	vdbEnv.config.Address = "127.0.0.1:1"
  1547  	vdbEnv.config.MaxRetries = 1
  1548  	vdbEnv.config.MaxRetriesOnStartup = 1
  1549  	expectedErrMsg := fmt.Sprintf("http error calling couchdb: Get \"http://%s/testinithannelmetadata_/channel_metadata?attachments=true\": dial tcp %s: connect: connection refused",
  1550  		vdbEnv.config.Address, vdbEnv.config.Address)
  1551  	vdb.channelMetadata = nil
  1552  	err = vdb.initChannelMetadata(false, fakeNsProvider)
  1553  	require.EqualError(t, err, expectedErrMsg)
  1554  	vdbEnv.config.Address = origCouchAddress
  1555  }
  1556  
  1557  func TestRangeQueryWithInternalLimitAndPageSize(t *testing.T) {
  1558  	// generateSampleData returns a slice of KVs. The returned value contains 12 KVs for a namespace ns1
  1559  	generateSampleData := func() []*statedb.VersionedKV {
  1560  		sampleData := []*statedb.VersionedKV{}
  1561  		ver := version.NewHeight(1, 1)
  1562  		sampleKV := &statedb.VersionedKV{
  1563  			CompositeKey:   &statedb.CompositeKey{Namespace: "ns1", Key: string('\u0000')},
  1564  			VersionedValue: &statedb.VersionedValue{Value: []byte("v0"), Version: ver, Metadata: []byte("m0")},
  1565  		}
  1566  		sampleData = append(sampleData, sampleKV)
  1567  		for i := 0; i < 10; i++ {
  1568  			sampleKV = &statedb.VersionedKV{
  1569  				CompositeKey: &statedb.CompositeKey{
  1570  					Namespace: "ns1",
  1571  					Key:       fmt.Sprintf("key-%d", i),
  1572  				},
  1573  				VersionedValue: &statedb.VersionedValue{
  1574  					Value:    []byte(fmt.Sprintf("value-for-key-%d-for-ns1", i)),
  1575  					Version:  ver,
  1576  					Metadata: []byte(fmt.Sprintf("metadata-for-key-%d-for-ns1", i)),
  1577  				},
  1578  			}
  1579  			sampleData = append(sampleData, sampleKV)
  1580  		}
  1581  		sampleKV = &statedb.VersionedKV{
  1582  			CompositeKey: &statedb.CompositeKey{
  1583  				Namespace: "ns1",
  1584  				Key:       string(utf8.MaxRune),
  1585  			},
  1586  			VersionedValue: &statedb.VersionedValue{
  1587  				Value:    []byte("v1"),
  1588  				Version:  ver,
  1589  				Metadata: []byte("m1"),
  1590  			},
  1591  		}
  1592  		sampleData = append(sampleData, sampleKV)
  1593  		return sampleData
  1594  	}
  1595  
  1596  	vdbEnv.init(t, nil)
  1597  	defer vdbEnv.cleanup()
  1598  	channelName := "ch1"
  1599  	vdb, err := vdbEnv.DBProvider.GetDBHandle(channelName, nil)
  1600  	require.NoError(t, err)
  1601  	db := vdb.(*VersionedDB)
  1602  
  1603  	sampleData := generateSampleData()
  1604  	batch := statedb.NewUpdateBatch()
  1605  	for _, d := range sampleData {
  1606  		batch.PutValAndMetadata(d.Namespace, d.Key, d.Value, d.Metadata, d.Version)
  1607  	}
  1608  	require.NoError(t, db.ApplyUpdates(batch, version.NewHeight(1, 1)))
  1609  
  1610  	defaultLimit := vdbEnv.config.InternalQueryLimit
  1611  
  1612  	// Scenario 1: We try to fetch either 11 records or all 12 records. We pass various internalQueryLimits.
  1613  	// key utf8.MaxRune would not be included as inclusive_end is always set to false
  1614  	testRangeQueryWithInternalLimit(t, "ns1", db, 2, string('\u0000'), string(utf8.MaxRune), sampleData[:len(sampleData)-1])
  1615  	testRangeQueryWithInternalLimit(t, "ns1", db, 5, string('\u0000'), string(utf8.MaxRune), sampleData[:len(sampleData)-1])
  1616  	testRangeQueryWithInternalLimit(t, "ns1", db, 2, string('\u0000'), "", sampleData)
  1617  	testRangeQueryWithInternalLimit(t, "ns1", db, 5, string('\u0000'), "", sampleData)
  1618  	testRangeQueryWithInternalLimit(t, "ns1", db, 2, "", string(utf8.MaxRune), sampleData[:len(sampleData)-1])
  1619  	testRangeQueryWithInternalLimit(t, "ns1", db, 5, "", string(utf8.MaxRune), sampleData[:len(sampleData)-1])
  1620  	testRangeQueryWithInternalLimit(t, "ns1", db, 2, "", "", sampleData)
  1621  	testRangeQueryWithInternalLimit(t, "ns1", db, 5, "", "", sampleData)
  1622  
  1623  	// Scenario 2: We try to fetch either 11 records or all 12 records using pagination. We pass various page sizes while
  1624  	// keeping the internalQueryLimit as the default one, i.e., 1000.
  1625  	vdbEnv.config.InternalQueryLimit = defaultLimit
  1626  	testRangeQueryWithPageSize(t, "ns1", db, 2, string('\u0000'), string(utf8.MaxRune), sampleData[:len(sampleData)-1])
  1627  	testRangeQueryWithPageSize(t, "ns1", db, 15, string('\u0000'), string(utf8.MaxRune), sampleData[:len(sampleData)-1])
  1628  	testRangeQueryWithPageSize(t, "ns1", db, 2, string('\u0000'), "", sampleData)
  1629  	testRangeQueryWithPageSize(t, "ns1", db, 15, string('\u0000'), "", sampleData)
  1630  	testRangeQueryWithPageSize(t, "ns1", db, 2, "", string(utf8.MaxRune), sampleData[:len(sampleData)-1])
  1631  	testRangeQueryWithPageSize(t, "ns1", db, 15, "", string(utf8.MaxRune), sampleData[:len(sampleData)-1])
  1632  	testRangeQueryWithPageSize(t, "ns1", db, 2, "", "", sampleData)
  1633  	testRangeQueryWithPageSize(t, "ns1", db, 15, "", "", sampleData)
  1634  
  1635  	// Scenario 3: We try to fetch either 11 records or all 12 records using pagination. We pass various page sizes while
  1636  	// keeping the internalQueryLimit to 1.
  1637  	vdbEnv.config.InternalQueryLimit = 1
  1638  	testRangeQueryWithPageSize(t, "ns1", db, 2, string('\u0000'), string(utf8.MaxRune), sampleData[:len(sampleData)-1])
  1639  	testRangeQueryWithPageSize(t, "ns1", db, 15, string('\u0000'), string(utf8.MaxRune), sampleData[:len(sampleData)-1])
  1640  	testRangeQueryWithPageSize(t, "ns1", db, 2, string('\u0000'), "", sampleData)
  1641  	testRangeQueryWithPageSize(t, "ns1", db, 15, string('\u0000'), "", sampleData)
  1642  	testRangeQueryWithPageSize(t, "ns1", db, 2, "", string(utf8.MaxRune), sampleData[:len(sampleData)-1])
  1643  	testRangeQueryWithPageSize(t, "ns1", db, 15, "", string(utf8.MaxRune), sampleData[:len(sampleData)-1])
  1644  	testRangeQueryWithPageSize(t, "ns1", db, 2, "", "", sampleData)
  1645  	testRangeQueryWithPageSize(t, "ns1", db, 15, "", "", sampleData)
  1646  }
  1647  
  1648  func testRangeQueryWithInternalLimit(
  1649  	t *testing.T,
  1650  	ns string,
  1651  	db *VersionedDB,
  1652  	limit int,
  1653  	startKey, endKey string,
  1654  	expectedResults []*statedb.VersionedKV,
  1655  ) {
  1656  	vdbEnv.config.InternalQueryLimit = limit
  1657  	require.Equal(t, int32(limit), db.couchInstance.internalQueryLimit())
  1658  	itr, err := db.GetStateRangeScanIterator(ns, startKey, endKey)
  1659  	require.NoError(t, err)
  1660  	require.Equal(t, int32(limit), itr.(*queryScanner).queryDefinition.internalQueryLimit)
  1661  	results := []*statedb.VersionedKV{}
  1662  	for {
  1663  		result, err := itr.Next()
  1664  		require.NoError(t, err)
  1665  		if result == nil {
  1666  			itr.Close()
  1667  			break
  1668  		}
  1669  		results = append(results, result)
  1670  	}
  1671  	require.Equal(t, expectedResults, results)
  1672  }
  1673  
  1674  func testRangeQueryWithPageSize(
  1675  	t *testing.T,
  1676  	ns string,
  1677  	db *VersionedDB,
  1678  	pageSize int,
  1679  	startKey, endKey string,
  1680  	expectedResults []*statedb.VersionedKV,
  1681  ) {
  1682  	itr, err := db.GetStateRangeScanIteratorWithPagination(ns, startKey, endKey, int32(pageSize))
  1683  	require.NoError(t, err)
  1684  	results := []*statedb.VersionedKV{}
  1685  	for {
  1686  		result, err := itr.Next()
  1687  		require.NoError(t, err)
  1688  		if result != nil {
  1689  			results = append(results, result)
  1690  			continue
  1691  		}
  1692  		nextStartKey := itr.GetBookmarkAndClose()
  1693  		if nextStartKey == endKey {
  1694  			break
  1695  		}
  1696  		itr, err = db.GetStateRangeScanIteratorWithPagination(ns, nextStartKey, endKey, int32(pageSize))
  1697  		require.NoError(t, err)
  1698  		continue
  1699  	}
  1700  	require.Equal(t, expectedResults, results)
  1701  }
  1702  
  1703  func TestDataExportImport(t *testing.T) {
  1704  	t.Run("export-import", func(t *testing.T) {
  1705  		vdbEnv.init(t, nil)
  1706  		defer vdbEnv.cleanup()
  1707  
  1708  		for _, size := range []int{10, 2 * 1024 * 1024} {
  1709  			maxDataImportBatchMemorySize = size
  1710  			commontests.TestDataExportImport(t, vdbEnv.DBProvider)
  1711  		}
  1712  	})
  1713  
  1714  	t.Run("nil-iterator", func(t *testing.T) {
  1715  		vdbEnv.init(t, nil)
  1716  		defer vdbEnv.cleanup()
  1717  
  1718  		require.NoError(
  1719  			t,
  1720  			vdbEnv.DBProvider.ImportFromSnapshot("testdb", nil, nil),
  1721  		)
  1722  	})
  1723  
  1724  	t.Run("error-couchdb-connection", func(t *testing.T) {
  1725  		vdbEnv.init(t, nil)
  1726  		configBackup := *vdbEnv.config
  1727  		defer func() {
  1728  			vdbEnv.config = &configBackup
  1729  			vdbEnv.cleanup()
  1730  		}()
  1731  
  1732  		vdbEnv.config.MaxRetries = 1
  1733  		vdbEnv.config.MaxRetriesOnStartup = 1
  1734  		vdbEnv.config.RequestTimeout = 1 * time.Second
  1735  		vdbEnv.config.Address = "127.0.0.1:1"
  1736  		require.Contains(
  1737  			t,
  1738  			vdbEnv.DBProvider.ImportFromSnapshot("testdb", nil, nil).Error(),
  1739  			"error while creating the metadata database for channel testdb: http error calling couchdb",
  1740  		)
  1741  	})
  1742  
  1743  	t.Run("error-reading-from-iter", func(t *testing.T) {
  1744  		vdbEnv.init(t, nil)
  1745  		defer vdbEnv.cleanup()
  1746  
  1747  		itr := &dummyFullScanIter{
  1748  			err: errors.New("error while reading from source"),
  1749  		}
  1750  		require.EqualError(
  1751  			t,
  1752  			vdbEnv.DBProvider.ImportFromSnapshot("testdb", nil, itr),
  1753  			"error while reading from source",
  1754  		)
  1755  	})
  1756  
  1757  	t.Run("error-creating-database", func(t *testing.T) {
  1758  		vdbEnv.init(t, nil)
  1759  		configBackup := *vdbEnv.config
  1760  		defer func() {
  1761  			vdbEnv.config = &configBackup
  1762  			vdbEnv.cleanup()
  1763  		}()
  1764  
  1765  		vdb, err := vdbEnv.DBProvider.GetDBHandle("testdb", nil)
  1766  		require.NoError(t, err)
  1767  		nsDB, err := vdb.(*VersionedDB).getNamespaceDBHandle("ns")
  1768  		require.NoError(t, err)
  1769  
  1770  		vdbEnv.config.MaxRetries = 1
  1771  		vdbEnv.config.MaxRetriesOnStartup = 1
  1772  		vdbEnv.config.RequestTimeout = 1 * time.Second
  1773  		vdbEnv.config.Address = "127.0.0.1:1"
  1774  
  1775  		// creating database for the first encountered namespace
  1776  		s := &snapshotImporter{
  1777  			vdb: vdb.(*VersionedDB),
  1778  			itr: &dummyFullScanIter{
  1779  				kv: &statedb.VersionedKV{
  1780  					CompositeKey: &statedb.CompositeKey{
  1781  						Namespace: "ns1",
  1782  					},
  1783  				},
  1784  			},
  1785  		}
  1786  		require.Contains(
  1787  			t,
  1788  			s.importState().Error(),
  1789  			"error while creating database for the namespace ns1",
  1790  		)
  1791  
  1792  		// creating database as next namespace
  1793  		// does not match the current namespace
  1794  		s = &snapshotImporter{
  1795  			vdb: vdb.(*VersionedDB),
  1796  			itr: &dummyFullScanIter{
  1797  				kv: &statedb.VersionedKV{
  1798  					CompositeKey: &statedb.CompositeKey{
  1799  						Namespace: "ns2",
  1800  					},
  1801  				},
  1802  			},
  1803  			currentNsDB: nsDB,
  1804  			currentNs:   "ns",
  1805  		}
  1806  		require.Contains(
  1807  			t,
  1808  			s.importState().Error(),
  1809  			"error while creating database for the namespace ns2",
  1810  		)
  1811  	})
  1812  
  1813  	t.Run("error-while-storing", func(t *testing.T) {
  1814  		vdbEnv.init(t, nil)
  1815  		configBackup := *vdbEnv.config
  1816  		defer func() {
  1817  			vdbEnv.config = &configBackup
  1818  			vdbEnv.cleanup()
  1819  		}()
  1820  
  1821  		vdb, err := vdbEnv.DBProvider.GetDBHandle("testdb", nil)
  1822  		require.NoError(t, err)
  1823  		ns1DB, err := vdb.(*VersionedDB).getNamespaceDBHandle("ns1")
  1824  		require.NoError(t, err)
  1825  
  1826  		vdbEnv.config.MaxRetries = 1
  1827  		vdbEnv.config.MaxRetriesOnStartup = 1
  1828  		vdbEnv.config.RequestTimeout = 1 * time.Second
  1829  		vdbEnv.config.Address = "127.0.0.1:1"
  1830  
  1831  		// same namespace but the pending doc limit reached
  1832  		s := &snapshotImporter{
  1833  			vdb: vdb.(*VersionedDB),
  1834  			itr: &dummyFullScanIter{
  1835  				kv: &statedb.VersionedKV{
  1836  					CompositeKey: &statedb.CompositeKey{
  1837  						Namespace: "ns1",
  1838  					},
  1839  					VersionedValue: &statedb.VersionedValue{
  1840  						Value:   []byte("random"),
  1841  						Version: version.NewHeight(1, 1),
  1842  					},
  1843  				},
  1844  			},
  1845  			currentNsDB:      ns1DB,
  1846  			currentNs:        "ns1",
  1847  			pendingDocsBatch: []*couchDoc{{}, {}},
  1848  			batchMemorySize:  4 * 1024 * 1024,
  1849  		}
  1850  		require.Contains(
  1851  			t,
  1852  			s.importState().Error(),
  1853  			"error while storing 3 states associated with namespace ns1",
  1854  		)
  1855  
  1856  		// next namespace does not match the current namespace
  1857  		s = &snapshotImporter{
  1858  			vdb: vdb.(*VersionedDB),
  1859  			itr: &dummyFullScanIter{
  1860  				kv: &statedb.VersionedKV{
  1861  					CompositeKey: &statedb.CompositeKey{
  1862  						Namespace: "ns2",
  1863  					},
  1864  					VersionedValue: &statedb.VersionedValue{
  1865  						Value:   []byte("random"),
  1866  						Version: version.NewHeight(1, 1),
  1867  					},
  1868  				},
  1869  			},
  1870  			currentNsDB:      ns1DB,
  1871  			currentNs:        "ns1",
  1872  			pendingDocsBatch: []*couchDoc{{}, {}},
  1873  		}
  1874  		require.Contains(
  1875  			t,
  1876  			s.importState().Error(),
  1877  			"error while storing 2 states associated with namespace ns1",
  1878  		)
  1879  	})
  1880  }
  1881  
  1882  func TestFullScanIteratorDeterministicJSONOutput(t *testing.T) {
  1883  	generateSampleData := func(ns string, sortedJSON bool) []*statedb.VersionedKV {
  1884  		sampleData := []*statedb.VersionedKV{}
  1885  		ver := version.NewHeight(1, 1)
  1886  		for i := 0; i < 10; i++ {
  1887  			sampleKV := &statedb.VersionedKV{
  1888  				CompositeKey: &statedb.CompositeKey{
  1889  					Namespace: ns,
  1890  					Key:       fmt.Sprintf("key-%d", i),
  1891  				},
  1892  				VersionedValue: &statedb.VersionedValue{
  1893  					Version:  ver,
  1894  					Metadata: []byte(fmt.Sprintf("metadata-for-key-%d-for-ns1", i)),
  1895  				},
  1896  			}
  1897  			if sortedJSON {
  1898  				sampleKV.Value = []byte(fmt.Sprintf(`{"a":0,"b":0,"c":%d}`, i))
  1899  			} else {
  1900  				sampleKV.Value = []byte(fmt.Sprintf(`{"c":%d,"b":0,"a":0}`, i))
  1901  			}
  1902  			sampleData = append(sampleData, sampleKV)
  1903  		}
  1904  		return sampleData
  1905  	}
  1906  
  1907  	vdbEnv.init(t, nil)
  1908  	defer vdbEnv.cleanup()
  1909  	channelName := "ch1"
  1910  	vdb, err := vdbEnv.DBProvider.GetDBHandle(channelName, nil)
  1911  	require.NoError(t, err)
  1912  	db := vdb.(*VersionedDB)
  1913  
  1914  	// creating and storing JSON value with sorted keys
  1915  	sampleDataWithSortedJSON := generateSampleData("ns1", true)
  1916  	batch := statedb.NewUpdateBatch()
  1917  	for _, d := range sampleDataWithSortedJSON {
  1918  		batch.PutValAndMetadata(d.Namespace, d.Key, d.Value, d.Metadata, d.Version)
  1919  	}
  1920  	require.NoError(t, db.ApplyUpdates(batch, version.NewHeight(1, 1)))
  1921  
  1922  	retrieveOnlyNs1 := func(ns string) bool {
  1923  		return ns != "ns1"
  1924  	}
  1925  	dbItr, err := db.GetFullScanIterator(retrieveOnlyNs1)
  1926  	require.NoError(t, err)
  1927  	require.NotNil(t, dbItr)
  1928  	verifyFullScanIterator(t, dbItr, sampleDataWithSortedJSON)
  1929  
  1930  	// creating and storing JSON value with unsorted JSON-keys
  1931  	sampleDataWithUnsortedJSON := generateSampleData("ns2", false)
  1932  	batch = statedb.NewUpdateBatch()
  1933  	for _, d := range sampleDataWithUnsortedJSON {
  1934  		batch.PutValAndMetadata(d.Namespace, d.Key, d.Value, d.Metadata, d.Version)
  1935  	}
  1936  	require.NoError(t, db.ApplyUpdates(batch, version.NewHeight(1, 1)))
  1937  
  1938  	retrieveOnlyNs2 := func(ns string) bool {
  1939  		return ns != "ns2"
  1940  	}
  1941  	sampleDataWithSortedJSON = generateSampleData("ns2", true)
  1942  	dbItr, err = db.GetFullScanIterator(retrieveOnlyNs2)
  1943  	require.NoError(t, err)
  1944  	require.NotNil(t, dbItr)
  1945  	verifyFullScanIterator(t, dbItr, sampleDataWithSortedJSON)
  1946  }
  1947  
  1948  func TestFullScanIteratorSkipInternalKeys(t *testing.T) {
  1949  	generateSampleData := func(ns string, keys []string) []*statedb.VersionedKV {
  1950  		sampleData := []*statedb.VersionedKV{}
  1951  		ver := version.NewHeight(1, 1)
  1952  		for i := 0; i < len(keys); i++ {
  1953  			sampleKV := &statedb.VersionedKV{
  1954  				CompositeKey: &statedb.CompositeKey{
  1955  					Namespace: ns,
  1956  					Key:       keys[i],
  1957  				},
  1958  				VersionedValue: &statedb.VersionedValue{
  1959  					Value:    []byte(fmt.Sprintf("value-for-%s-for-ns1", keys[i])),
  1960  					Version:  ver,
  1961  					Metadata: []byte(fmt.Sprintf("metadata-for-%s-for-ns1", keys[i])),
  1962  				},
  1963  			}
  1964  			sampleData = append(sampleData, sampleKV)
  1965  		}
  1966  		return sampleData
  1967  	}
  1968  
  1969  	vdbEnv.init(t, nil)
  1970  	defer vdbEnv.cleanup()
  1971  	channelName := "ch1"
  1972  	vdb, err := vdbEnv.DBProvider.GetDBHandle(channelName, nil)
  1973  	require.NoError(t, err)
  1974  	db := vdb.(*VersionedDB)
  1975  
  1976  	keys := []string{channelMetadataDocID, "key-1", "key-2", "key-3", "key-4", "key-5", savepointDocID}
  1977  	sampleData := generateSampleData("ns1", keys)
  1978  	batch := statedb.NewUpdateBatch()
  1979  	for _, d := range sampleData {
  1980  		batch.PutValAndMetadata(d.Namespace, d.Key, d.Value, d.Metadata, d.Version)
  1981  	}
  1982  	require.NoError(t, db.ApplyUpdates(batch, version.NewHeight(1, 1)))
  1983  
  1984  	retrieveOnlyNs1 := func(ns string) bool {
  1985  		return ns != "ns1"
  1986  	}
  1987  	dbItr, err := db.GetFullScanIterator(retrieveOnlyNs1)
  1988  	require.NoError(t, err)
  1989  	require.NotNil(t, dbItr)
  1990  	verifyFullScanIterator(t, dbItr, sampleData)
  1991  
  1992  	sampleData = generateSampleData("", keys)
  1993  	batch = statedb.NewUpdateBatch()
  1994  	for _, d := range sampleData {
  1995  		batch.PutValAndMetadata(d.Namespace, d.Key, d.Value, d.Metadata, d.Version)
  1996  	}
  1997  	require.NoError(t, db.ApplyUpdates(batch, version.NewHeight(1, 1)))
  1998  
  1999  	retrieveOnlyEmptyNs := func(ns string) bool {
  2000  		return ns != ""
  2001  	}
  2002  	// remove internal keys such as savepointDocID and channelMetadataDocID
  2003  	// as it is an empty namespace
  2004  	keys = []string{"key-1", "key-2", "key-3", "key-4", "key-5"}
  2005  	sampleData = generateSampleData("", keys)
  2006  	dbItr, err = db.GetFullScanIterator(retrieveOnlyEmptyNs)
  2007  	require.NoError(t, err)
  2008  	require.NotNil(t, dbItr)
  2009  	verifyFullScanIterator(t, dbItr, sampleData)
  2010  }
  2011  
  2012  func verifyFullScanIterator(
  2013  	t *testing.T,
  2014  	dbIter statedb.FullScanIterator,
  2015  	expectedResult []*statedb.VersionedKV,
  2016  ) {
  2017  	results := []*statedb.VersionedKV{}
  2018  	for {
  2019  		kv, err := dbIter.Next()
  2020  		require.NoError(t, err)
  2021  		if kv == nil {
  2022  			break
  2023  		}
  2024  		require.NoError(t, err)
  2025  		results = append(results, kv)
  2026  	}
  2027  	require.Equal(t, expectedResult, results)
  2028  }
  2029  
  2030  func TestDrop(t *testing.T) {
  2031  	vdbEnv.init(t, nil)
  2032  	defer vdbEnv.cleanup()
  2033  
  2034  	checkDBsAfterDropFunc := func(channelName string) {
  2035  		appDBNames := RetrieveApplicationDBNames(t, vdbEnv.config)
  2036  		for _, dbName := range appDBNames {
  2037  			require.NotContains(t, dbName, channelName+"_")
  2038  		}
  2039  	}
  2040  
  2041  	commontests.TestDrop(t, vdbEnv.DBProvider, checkDBsAfterDropFunc)
  2042  }
  2043  
  2044  func TestDropErrorPath(t *testing.T) {
  2045  	vdbEnv.init(t, nil)
  2046  	defer vdbEnv.cleanup()
  2047  	channelName := "testdroperror"
  2048  
  2049  	_, err := vdbEnv.DBProvider.GetDBHandle(channelName, nil)
  2050  	require.NoError(t, err)
  2051  
  2052  	vdbEnv.config.MaxRetries = 1
  2053  	vdbEnv.config.MaxRetriesOnStartup = 1
  2054  	vdbEnv.config.RequestTimeout = 1 * time.Second
  2055  	origAddress := vdbEnv.config.Address
  2056  	vdbEnv.config.Address = "127.0.0.1:1"
  2057  	err = vdbEnv.DBProvider.Drop(channelName)
  2058  	require.Contains(t, err.Error(), "connection refused")
  2059  	vdbEnv.config.Address = origAddress
  2060  
  2061  	vdbEnv.DBProvider.Close()
  2062  	require.EqualError(t, vdbEnv.DBProvider.Drop(channelName), "internal leveldb error while obtaining db iterator: leveldb: closed")
  2063  }
  2064  
  2065  func TestReadFromDBInvalidKey(t *testing.T) {
  2066  	vdbEnv.init(t, sysNamespaces)
  2067  	defer vdbEnv.cleanup()
  2068  	channelName := "test_getstate_invalidkey"
  2069  	db, err := vdbEnv.DBProvider.GetDBHandle(channelName, nil)
  2070  	require.NoError(t, err)
  2071  	vdb := db.(*VersionedDB)
  2072  
  2073  	testcase := []struct {
  2074  		key              string
  2075  		expectedErrorMsg string
  2076  	}{
  2077  		{
  2078  			key:              string([]byte{0xff, 0xfe, 0xfd}),
  2079  			expectedErrorMsg: "invalid key [fffefd], must be a UTF-8 string",
  2080  		},
  2081  		{
  2082  			key:              "",
  2083  			expectedErrorMsg: "invalid key. Empty string is not supported as a key by couchdb",
  2084  		},
  2085  		{
  2086  			key:              "_key_starting_with_an_underscore",
  2087  			expectedErrorMsg: `invalid key [_key_starting_with_an_underscore], cannot begin with "_"`,
  2088  		},
  2089  	}
  2090  
  2091  	for i, tc := range testcase {
  2092  		t.Run(fmt.Sprintf("testcase-%d", i), func(t *testing.T) {
  2093  			_, err = vdb.readFromDB("ns", tc.key)
  2094  			require.EqualError(t, err, tc.expectedErrorMsg)
  2095  		})
  2096  	}
  2097  }
  2098  
  2099  type dummyFullScanIter struct {
  2100  	err error
  2101  	kv  *statedb.VersionedKV
  2102  }
  2103  
  2104  func (d *dummyFullScanIter) Next() (*statedb.VersionedKV, error) {
  2105  	return d.kv, d.err
  2106  }
  2107  
  2108  func (d *dummyFullScanIter) Close() {
  2109  }