github.com/osdi23p228/fabric@v0.0.0-20221218062954-77808885f5db/core/ledger/kvledger/txmgmt/statedb/statecouchdb/statecouchdb_test.go (about)

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